Zynq-PL中创建AXI Master接口IP及AXI4-Lite总线主从读写时序测试

转载:原文  http://www.eefocus.com/antaur/blog/17-08/423751_6cc0d.html

0. 引言

通过之前的学习,可以在PL端创建从机模式的AXI接口IP核。但是从机模式是被动接收数据,而不能主动的去获取数据,因此计划研究一下AXI Master接口的IP核的构建方法。 

1. 利用向导创建AXI Lite Master测试用例

 

 

image001.png

image003.png

 

image005.png

 

image007.png

image009.png

在这一步,AXI类型为Lite型的,可选参数如下所示:

image011.png

在这里,重点是Interface Mode,前面的实验中采用的是默认配置Slave,即设计的IP接口为从机。本实验中,要将其设置为Master。

下面的三个参数跟Sl**e模式下可配置的参数类型是相同的。具体的说明如下所示:

image013.png

Data Width:为数据总线的位宽,单位为bits

image015.png

Memory Size:只有在IP类型为AXI FULL Slave模式下才有效,目前不讨论。

image017.png

Number of Registers:只有在IP接口类型为AXI Lite Slave模式下才有效,可以参看之前的实验说明。

 

image019.png

 

 

至此,利用向导工具创建一个AXI Lite Master类型的IP接口配置完毕。

 

2. 源码分析

2.1 顶层源码解析

系统会自动生成一个该IP的工程,可以查看生成的源代码,并在此基础上进行修改。

 

 

image021.png

 

 

从上图可以看出,向导工具就生成了两个模块。直接综合后,查看RTL级图的操作入口如下所示:

image023.png

显示结果如下:

image025.png

可以看出顶层模块只是做了简单的直连封装,内部没有任何逻辑设计,查看代码(附录1)也是如此,唯一有用的操作配置了内层模块实例的参数。

具体配置测参数如下所示:

image027.png

 

 

可以看到配置了5个参数,其中:

C_M00_AXI_ADDR_WIDTH表示地址总线的位宽,这里配置为32bits,由于涉及到总线的协议,建议不要动这个参数。

C_M00_AXI_DATA_WIDTH表示数据总线的位宽,这里配置为32bits,同样的原因,建议不要动这个参数。

其余的三个参数是根据测试用例的用户逻辑相关的,具体意义在底层模块的源码分析(附录2)中会详细解释,这里简单说明一下:

C_M00_AXI_TARGET_SLAVE BASE_ADDR表示本IP作为主机欲访问的从机内存的基地址。

C_M00_AXI_START_DATA_VALUE表示对从机寄存器进行写入操作的测试数据

C_M00_AXI_TRANSACTIONS_NUM表示测试的次数

具体逻辑及各参数的意义见下文对底层模块的解析。

 

image029.png

2.2 底层源码解析

向导自动生成的示例程序中底层模块为AzIP_AXI_Master_Ex1_v1_0_M00_AXI,该模块并不是一个Master型的IO标准接口,而只是一个用户测试用例的逻辑操作。而Master的Write和Read读写逻辑并没有很完毕的封装,需要仔细分析示例代码进行拆分。

具体的代码解析详见后面附录2的注释说明,这里给出的仅是本人对此分析得到的笔记。

  1. 测试业务逻辑

 

测试业务逻辑的本质如下图所示,就是一个典型的内存读写操作的测试流程。

image032.gif

 

 

代码编写时采用状态机的方式。

image033.png

 

其中:

 

【地址操作分析】:

从机寄存器的初始地址有变量C_M00_AXI_TARGET_SLAVE_BASE_ADDR定义,在构建集成系统时,对应从机的内存映射必须于配置相同。

AXI总线上写操作地址总线绑定如下,C_M00_AXI_TARGET_SLAVE_BASE_ADDR为基地址,而axi_awaddr定义地址偏移量。

image035.png

image037.png

段内地址偏移量初始化值为0,每次写入成功后,地址偏移量+4,这是因为地址定义的单位是字节Byte,而数据总线为32bits,即4个字节,因此没写入32bits,会用掉从机4个地址的存储空间。

 

image039.png

 

关于读取操作指定寄存器的地址定义及处理过程是类似的。

【数据操作分析】:

写操作使用的数据总线绑定到一个内部寄存器上。

 

image041.png 

初始化时,测试数据寄存器被设置为参数配置的数值,之后每次加1。 

image043.png

 

image045.png

测试数据向从机写入之后,内部备份保存一份,存在寄存器expected_rdata中,代码如下:

image047.png

可以看到代码逻辑完全相同,但是整个代码架构真的不敢苟同。

 

数据比较段的代码如下:

image049.png

相应的逻辑应该是一旦有一次出错,read_mismatch就置为1,如果下次对了,该状态寄存器仍然保持数据为1,直到复位操作。

 

(2)AXI4-Lite总线接口定义

在进行AXI4-Lite总线读写时序操作时,首先要明确总线的读写操作接口。

查看相关技术文档,这里主要用到以下两个技术文档:

  • ARM公司发布的《ARM AMBA AXI Protocol v2.0 Specification》
  • Xilinx公司发布的《Vivado Design Suite : AXI Reference Guide》UG1037(v3.0)2015

    image051.png

    可以看到,无论是AXI4总线还是精简版的AXI4-Lite总线接口分成5大类,这5大类又分别****于Write操作核Read操作。

     

    Write操作

    1. 写地址:主机-->从机
    2. 写数据:主机-->从机
    3. 写应答:从机-->主机

    Read操作

    1. 读地址:主机-->从机
    2. 读数据:从机-->主机
     

下面重点研究一下AXI4-Lite总线具体是如何定义的,它与AXI4总线协议有什么不同?

首先看一下AXI4总线协议的官方定义:

image053.png

再看一下AXI4-Lite总线协议的官方定义:

 

image055.png

 

不支持突发(burst)传输模式,及burst length=1

数据总线宽度只能为32bit或则64bits

不支持独家访问(exclusive accesses)

image057.png

即AXI4-Lite不支持突发(burst)传输模式。

【说明】关于突发(burst)传输模式是否采用将在后面分析读写时序时重点讨论。这里先铺垫一下。

image059.png

AXI4总线,由于读写通道是分离的,可以提供实时双向的数据传输。

采用突发(burst)传输模式,可以在发送1个地址之后,最多支持突发256words的数据。(Words??2字节吗??)

 

下面看一下AXI4-Lite总线协议的物理接口Port的定义:

image061.png

可以看出除了时钟和复位信号后,也是前文介绍的5类信号通道。

但是作为一个简化的总线协议,其物理接口应该比完整版的AXI4总线要少,具体精简掉了哪些?详见下表。

 

image063.png

 

学习完原理性的基础知识之后,我们来看一下示例程序代码是否符合官方标准。

分析AXI Master示例IP源代码的Port定义,代码即注释说明如下所示:

【AXI4-Lite Write Address Channel】

image065.png

 

 

image067.png

image069.png

 

 

在示例程序中,AXI Master模块的M_AXI_AWPROT管脚始终输出为:3’b000

【AXI4-Lite Write data Channel】

 

image071.png

 

 

其中端口M_AXI_ARPROT,参见【AXI4-Lite Write Address Channel】中的M_AXI_AWPROT

 

【AXI4-Lite Read Data Channel】

 

 

image071.png

 

 

image079.png

image075.png

在示例程序中,AXI Master模块由于数据总线位宽为32bit,因此M_AXI_WSTRB管脚始终输出为:4’b1111


【AXI4-Lite Write response Channel】

image077.png

image079.png

image081.png

 

 

【AXI4-Lite Read Address Channel】

 

 

image083.png

 

其中端口M_AXI_ARPROT,参见【AXI4-Lite Write Address Channel】中的M_AXI_AWPROT

 

【AXI4-Lite Read Data Channel】

 

image083.png

其中端口M_AXI_RRESP,参见【AXI4-Lite Write response Channel】中的M_AXI_BRESP 

image085.png

其中端口M_AXI_RRESP,参见【AXI4-Lite Write response Channel】中的M_AXI_BRESP

 

(3)AXI4-Lite总线读写时序分析1--写入操作时序

研究总线协议的交互时序,必须依赖协议标准,但是能够查到的官方协议标准均没有对AXI4-Lite总线的读写时序进行独立的时序设定。

Xilinx公司发布的文档,引用的还是ARM公司发布的文档,对于总线写入时序逻辑示意图如下:

image087.png

表示,主机需要先写地址,然后写入一系列数据,为什么是四个暂时不确定,从机处理完毕后回复一个应答响应。

 

ARM公司发布的文档《ARM AMBA AXI Protocol v2.0 Specification》中没有AXI4-Lits的写入时序逻辑,只有Write brust的时序示意图。如下所示

 

image089.png

 

经过前面的研究,知道AXI4-Lite是brust length=1的Write brust,因此我自行简化上述时序图如下:

 image091.png

如果主机连续发送两次数据写入操作,我猜测的时序逻辑图应该如下所示: 

image093.png

分析示例程序中,AXI Master模块的源代码,绘制相应的主机向从机写入数据的时序逻辑如下图所示:

 

image096.gif

查看代码,分析得到的时序与个人分析得到的原理时序并不完全匹配。这里先铺垫一下,后文将会对示例源码的时序进行仿真分析,得到对应可用的时序,用于将来自行编写接口时使用。记得看下文。

(4) AXI4-Lite总线读写时序分析2--读取操作时序

同样先学习一下官方协议。 

image097.png

以及来自官方文档的读取操作时序图。

image099.png

同样自行分析对于brust length=1的AXI4-Lite总线,读取操作的时序图如下所示 

image101.png

示例代码的操作时序这里就不在画处理流程图了。下文会通过时序仿真给出示例中采用的时序关系。

(5) 示例工程的时序分析

【工程创建的原始出发点】:

根据上述对AXI4-Lite总线接口的分析,其实就是主机和从机之间的数据通信。联想到之间创建的AXI4-Lite Sl**e示例IP核,是否能创建一个顶层模块直接将AXI4-Lite Sl**e示例IP核与AXI4-Lite Sl**e示例IP核直接相连,完成AXI4-Lite总线读写操作?

为了验证上述想法,首先再创建一个AXI4-Lite Sl**e示例IP核,参数要与AXI4-Lite Master示例IP核的参数向对应,下面将端口定义对比如下:

 

image103.png

从上图的对比中,可以看出AXI4-Lite主从机的接口其实是一一匹配的。

创建一个顶层文件Top_AXI4_Lite_Interfce_Demo,将生成的主从示例直接对连。代码见附录3.相应的层级结构如下图所示。

 

image105.png

综合完的RTL级连接图如下所示。

 

image107.png

对该顶层文件创建仿真驱动,代码如下所示:

`timescale 1ns / 1ps

 

module Sim_AXI4_Lite_Interface();

 

  reg axi_ACLK;    // AXI总线时钟

  reg axi_ARESETn;   // 系统复位信号,低电平有效

 

  reg r_app_txn;    // 应用级复位信号,负脉冲,上升沿复位

  wire w_err;       // 状态指示,异常

  wire w_txn_done;  // 状态指示,发送完毕

 

  Top_AXI4_Lite_Interfce_Demo Ut1 (

      .axi_ACLK(axi_ACLK),

      .axi_ARESETn(axi_ARESETn),

      .app_TXn(r_app_txn),

      .state_err(w_err),

      .state_done(w_txn_done)

      );

 

  parameter PERIOD = 2;

  always begin

    #(PERIOD/2);

    axi_ACLK = ~axi_ACLK;

  end

 

  initial begin

    axi_ACLK    = 1'b0;

    axi_ARESETn = 1'b1;

    r_app_txn   = 1'b1;

 

    #(10*PERIOD);

    axi_ARESETn = 1'b0;

    #(5*PERIOD);

    r_app_txn = 1'b0;

    #(2*PERIOD);

    axi_ARESETn = 1'b1;

    #(4*PERIOD);

    r_app_txn = 1'b1;

  end

 

endmodule

 

运行后的仿真结果如下所示: 

 

仿真结果1:先写入4次,然后读取4次的时序仿真结果

 

image109.png

仿真结果2:先写入1次,然后读取1次的时序仿真结果

image111.png

仿真结果3:仅写入1次时序仿真结果

image113.png

                                              仿真结果4:仅读取1次时序仿真结果

 

image115.png

仿真结果5:先写入2次,再读取2次时序仿真结果

image117.png

  • 对比仿真得到的写入操作时序和从官网文档分析得到的时序

 

image119.png

【个人心得】

可以看出,AXI4中设定的5类通道都是相互独立的,示例仿真中,应为AWVALID和WVALID是同时给从机的,从机就同时采样AWADDR总线和WDATA总线数据,并同时给出了应答AWREADY和WREADY。

从机在匹配完Address和Data后,给出应答BVALID。

而官方文档上的时序时先发地址后发数据,正常的从机也是能够正确响应的。

结论,自行编写接口时,每个通道要独立处理,不要耦合到一起。

  • 对比仿真得到的读取操作时序和从官网文档分析得到的时序

 

image121.png

【个人心得】

由于没有经过总线控制器,而是直连的,因此时序仿真结果图中从机的响应速度很快,而原理图中有个响应处理延时。

 

2. 总结

通过本学习笔记,详细分析了AXI4-Lite总线主机端的交互处理时序,以后就可以自行编写主从机的接口了。



附录1:顶层模块源代码:

 `timescale 1ns / 1ps


module Top_AXI4_Lite_Interfce_Demo
#(
parameter  C_AXI_START_DATA_VALUE  = 32'hAA000000,


parameter  C_AXI_TARGET_SLAVE_BASE_ADDR  = 32'h40000000,


parameter integer C_AXI_ADDR_WIDTH  = 32,


parameter integer C_AXI_DATA_WIDTH  = 32,


parameter integer C_AXI_TRANSACTIONS_NUM  = 4


)
(


    input axi_ACLK,


    input axi_ARESETn,


    input app_TXn,


    output state_err,


    output state_done


    );


   


    wire w_err;       // 状态指示,异常


    wire w_txn_done;  // 状态指示,发送完毕


   


    assign state_err  = w_err;


    assign state_done = w_txn_done;


   


    wire [C_AXI_ADDR_WIDTH-1 : 0]   axi_AWADDR;   // AXI总线信号:AWADDR


    wire [2 : 0]                    axi_AWPROT;   // AXI总线信号:AWPROT


    wire                            axi_AWVALID;  // AXI总线信号:AWVALID


    wire                            axi_AWREADY;  // AXI总线信号:AWREADY


 


    wire [C_AXI_DATA_WIDTH-1   : 0] axi_WDATA;    // AXI总线信号:WDATA


    wire [C_AXI_DATA_WIDTH/8-1 : 0]  axi_WSTRB;    // AXI总线信号:WSTRB


    wire                            axi_WVALID;   // AXI总线信号:WVALID


    wire                            axi_WREADY;   // AXI总线信号:WREADY


  


    wire [1 : 0]                       axi_BRESP;    // AXI总线信号:BRESP


    wire                            axi_BVALID;   // AXI总线信号:BVALID


    wire                            axi_BREADY;   // AXI总线信号:BREADY


 


 


    wire [C_AXI_ADDR_WIDTH-1 : 0]   axi_ARADDR;   // AXI总线信号:ARADDR


    wire [2 : 0]                    axi_ARPROT;   // AXI总线信号:ARPROT


    wire                            axi_ARVALID;  // AXI总线信号:ARVALID


    wire                            axi_ARREADY;  // AXI总线信号:ARREADY


   


    wire [C_AXI_DATA_WIDTH-1 : 0]   axi_RDATA;    // AXI总线信号:RDATA


    wire [1 : 0]                    axi_RRESP;    // AXI总线信号:RRESP


    wire                            axi_RVAILD;   // AXI总线信号:RVAILD


    wire                            axi_RREADY;   // AXI总线信号:RREADY


   


    axi_ip_master_v1_0  #


    (


       .C_M00_AXI_START_DATA_VALUE(C_AXI_START_DATA_VALUE),


       .C_M00_AXI_TARGET_SLAVE_BASE_ADDR(C_AXI_TARGET_SLAVE_BASE_ADDR),


       .C_M00_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),


       .C_M00_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),


       .C_M00_AXI_TRANSACTIONS_NUM(C_AXI_TRANSACTIONS_NUM)


     ) Ut1 (


      //-- AXI4-Lite Global ----------------------------------------------


      .m00_axi_aclk(axi_ACLK),


      .m00_axi_aresetn(axi_ARESETn),


      //------------------------------------------------------------------


      .m00_axi_init_axi_txn(app_TXn),


      .m00_axi_error(w_err),


      .m00_axi_txn_done(w_txn_done),


      //--- AXI4-Lite Write Address Channel ------------------------------


      .m00_axi_awaddr(axi_AWADDR),


      .m00_axi_awprot(axi_AWPROT),


      .m00_axi_awvalid(axi_AWVALID),


      .m00_axi_awready(axi_AWREADY),


      //--- AXI4-Lite Write data Channel ------------------------------


      .m00_axi_wdata(axi_WDATA),


      .m00_axi_wstrb(axi_WSTRB),


      .m00_axi_wvalid(axi_WVALID),


      .m00_axi_wready(axi_WREADY),


      //--- AXI4-Lite Write response Channel ------------------------------


      .m00_axi_bresp(axi_BRESP),


      .m00_axi_bvalid(axi_BVALID),


      .m00_axi_bready(axi_BREADY),


      //--- AXI4-Lite Read Address Channel ------------------------------


      .m00_axi_araddr(axi_ARADDR),


      .m00_axi_arprot(axi_ARPROT),


      .m00_axi_arvalid(axi_ARVALID),


      .m00_axi_arready(axi_ARREADY),


      //--- AXI4-Lite Read Data Channel ------------------------------


      .m00_axi_rdata(axi_RDATA),


      .m00_axi_rresp(axi_RRESP),


      .m00_axi_rvalid(axi_RVAILD),


      .m00_axi_rready(axi_RREADY)


    );


 


    axi_ip_slave_v1_0 #


    (


      .C_S00_AXI_DATA_WIDTH(C_AXI_ADDR_WIDTH),


      .C_S00_AXI_ADDR_WIDTH(7)


    ) Ut2 (


      //-- AXI4-Lite Global ----------------------------------------------


      .s00_axi_aclk(axi_ACLK),


      .s00_axi_aresetn(axi_ARESETn),


      //--- AXI4-Lite Write Address Channel ------------------------------


      .s00_axi_awaddr(axi_AWADDR[6:0]), //注意:只有段地址!!!!!,做的axi_slave_ip的地址位宽为7,寄存器个数为32


      .s00_axi_awprot(axi_AWPROT),


      .s00_axi_awvalid(axi_AWVALID),


      .s00_axi_awready(axi_AWREADY),


      //--- AXI4-Lite Write data Channel --------------------------------


      .s00_axi_wdata(axi_WDATA),


      .s00_axi_wstrb(axi_WSTRB),


      .s00_axi_wvalid(axi_WVALID),


      .s00_axi_wready(axi_WREADY),


      //--- AXI4-Lite Write response Channel ------------------------------


      .s00_axi_bresp(axi_BRESP),


      .s00_axi_bvalid(axi_BVALID),


      .s00_axi_bready(axi_BREADY),


      //--- AXI4-Lite Read Address Channel ------------------------------


      .s00_axi_araddr(axi_ARADDR),


      .s00_axi_arprot(axi_ARPROT),


      .s00_axi_arvalid(axi_ARVALID),


      .s00_axi_arready(axi_ARREADY),


      //--- AXI4-Lite Read Data Channel ------------------------------


      .s00_axi_rdata(axi_RDATA),


      .s00_axi_rresp(axi_RRESP),


      .s00_axi_rvalid(axi_RVAILD),


      .s00_axi_rready(axi_RREADY)


    );


   


endmodule

 

附录2:底层模块MASTER 顶层源代码:



`timescale 1 ns / 1 ps


module axi_ip_master_v1_0 #
(
// Users to add parameters here


// User parameters ends
// Do not modify the parameters beyond this line




// Parameters of Axi Master Bus Interface M00_AXI
parameter  C_M00_AXI_START_DATA_VALUE = 32'hAA000000,
parameter  C_M00_AXI_TARGET_SLAVE_BASE_ADDR = 32'h40000000,
parameter integer C_M00_AXI_ADDR_WIDTH = 32,
parameter integer C_M00_AXI_DATA_WIDTH = 32,
parameter integer C_M00_AXI_TRANSACTIONS_NUM = 4
)
(
// Users to add ports here


// User ports ends
// Do not modify the ports beyond this line




// Ports of Axi Master Bus Interface M00_AXI
input wire  m00_axi_init_axi_txn,
output wire  m00_axi_error,
output wire  m00_axi_txn_done,
input wire  m00_axi_aclk,
input wire  m00_axi_aresetn,
output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_awaddr,
output wire [2 : 0] m00_axi_awprot,
output wire  m00_axi_awvalid,
input wire  m00_axi_awready,
output wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_wdata,
output wire [C_M00_AXI_DATA_WIDTH/8-1 : 0] m00_axi_wstrb,
output wire  m00_axi_wvalid,
input wire  m00_axi_wready,
input wire [1 : 0] m00_axi_bresp,
input wire  m00_axi_bvalid,
output wire  m00_axi_bready,
output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_araddr,
output wire [2 : 0] m00_axi_arprot,
output wire  m00_axi_arvalid,
input wire  m00_axi_arready,
input wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_rdata,
input wire [1 : 0] m00_axi_rresp,
input wire  m00_axi_rvalid,
output wire  m00_axi_rready
);
// Instantiation of Axi Bus Interface M00_AXI
axi_ip_master_v1_0_M00_AXI # ( 
.C_M_START_DATA_VALUE(C_M00_AXI_START_DATA_VALUE),
.C_M_TARGET_SLAVE_BASE_ADDR(C_M00_AXI_TARGET_SLAVE_BASE_ADDR),
.C_M_AXI_ADDR_WIDTH(C_M00_AXI_ADDR_WIDTH),
.C_M_AXI_DATA_WIDTH(C_M00_AXI_DATA_WIDTH),
.C_M_TRANSACTIONS_NUM(C_M00_AXI_TRANSACTIONS_NUM)
) axi_ip_master_v1_0_M00_AXI_inst (
.INIT_AXI_TXN(m00_axi_init_axi_txn),
.ERROR(m00_axi_error),
.TXN_DONE(m00_axi_txn_done),
.M_AXI_ACLK(m00_axi_aclk),
.M_AXI_ARESETN(m00_axi_aresetn),
.M_AXI_AWADDR(m00_axi_awaddr),
.M_AXI_AWPROT(m00_axi_awprot),
.M_AXI_AWVALID(m00_axi_awvalid),
.M_AXI_AWREADY(m00_axi_awready),
.M_AXI_WDATA(m00_axi_wdata),
.M_AXI_WSTRB(m00_axi_wstrb),
.M_AXI_WVALID(m00_axi_wvalid),
.M_AXI_WREADY(m00_axi_wready),
.M_AXI_BRESP(m00_axi_bresp),
.M_AXI_BVALID(m00_axi_bvalid),
.M_AXI_BREADY(m00_axi_bready),
.M_AXI_ARADDR(m00_axi_araddr),
.M_AXI_ARPROT(m00_axi_arprot),
.M_AXI_ARVALID(m00_axi_arvalid),
.M_AXI_ARREADY(m00_axi_arready),
.M_AXI_RDATA(m00_axi_rdata),
.M_AXI_RRESP(m00_axi_rresp),
.M_AXI_RVALID(m00_axi_rvalid),
.M_AXI_RREADY(m00_axi_rready)
);


// Add user logic here


// User logic ends


endmodule

附录3:底层模块MASTER 底层源代码:



`timescale 1 ns / 1 ps


module axi_ip_master_v1_0_M00_AXI #
(
// Users to add parameters here


// User parameters ends
// Do not modify the parameters beyond this line


// The master will start generating data from the C_M_START_DATA_VALUE value
parameter  C_M_START_DATA_VALUE = 32'hAA000000,
// The master requires a target slave base address.
    // The master will initiate read and write transactions on the slave with base address specified here as a parameter.
parameter  C_M_TARGET_SLAVE_BASE_ADDR = 32'h40000000,
// Width of M_AXI address bus. 
    // The master generates the read and write addresses of width specified as C_M_AXI_ADDR_WIDTH.
parameter integer C_M_AXI_ADDR_WIDTH = 32,
// Width of M_AXI data bus. 
    // The master issues write data and accept read data where the width of the data bus is C_M_AXI_DATA_WIDTH
parameter integer C_M_AXI_DATA_WIDTH = 32,
// Transaction number is the number of write 
    // and read transactions the master will perform as a part of this example memory test.
parameter integer C_M_TRANSACTIONS_NUM = 4
)
(
// Users to add ports here


// User ports ends
// Do not modify the ports beyond this line


// Initiate AXI transactions
input wire  INIT_AXI_TXN,
// Asserts when ERROR is detected
output reg  ERROR,
// Asserts when AXI transactions is complete
output wire  TXN_DONE,
// AXI clock signal
input wire  M_AXI_ACLK,
// AXI active low reset signal
input wire  M_AXI_ARESETN,
// Master Interface Write Address Channel ports. Write address (issued by master)
output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_AWADDR,
// Write channel Protection type.
    // This signal indicates the privilege and security level of the transaction,
    // and whether the transaction is a data access or an instruction access.
output wire [2 : 0] M_AXI_AWPROT,
// Write address valid. 
    // This signal indicates that the master signaling valid write address and control information.
output wire  M_AXI_AWVALID,
// Write address ready. 
    // This signal indicates that the slave is ready to accept an address and associated control signals.
input wire  M_AXI_AWREADY,
// Master Interface Write Data Channel ports. Write data (issued by master)
output wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA,
// Write strobes. 
    // This signal indicates which byte lanes hold valid data.
    // There is one write strobe bit for each eight bits of the write data bus.
output wire [C_M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB,
// Write valid. This signal indicates that valid write data and strobes are available.
output wire  M_AXI_WVALID,
// Write ready. This signal indicates that the slave can accept the write data.
input wire  M_AXI_WREADY,
// Master Interface Write Response Channel ports. 
    // This signal indicates the status of the write transaction.
input wire [1 : 0] M_AXI_BRESP,
// Write response valid. 
    // This signal indicates that the channel is signaling a valid write response
input wire  M_AXI_BVALID,
// Response ready. This signal indicates that the master can accept a write response.
output wire  M_AXI_BREADY,
// Master Interface Read Address Channel ports. Read address (issued by master)
output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_ARADDR,
// Protection type. 
    // This signal indicates the privilege and security level of the transaction, 
    // and whether the transaction is a data access or an instruction access.
output wire [2 : 0] M_AXI_ARPROT,
// Read address valid. 
    // This signal indicates that the channel is signaling valid read address and control information.
output wire  M_AXI_ARVALID,
// Read address ready. 
    // This signal indicates that the slave is ready to accept an address and associated control signals.
input wire  M_AXI_ARREADY,
// Master Interface Read Data Channel ports. Read data (issued by slave)
input wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA,
// Read response. This signal indicates the status of the read transfer.
input wire [1 : 0] M_AXI_RRESP,
// Read valid. This signal indicates that the channel is signaling the required read data.
input wire  M_AXI_RVALID,
// Read ready. This signal indicates that the master can accept the read data and response information.
output wire  M_AXI_RREADY
);


// function called clogb2 that returns an integer which has the
// value of the ceiling of the log base 2


function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction


// TRANS_NUM_BITS is the width of the index counter for 
// number of write or read transaction.
localparam integer TRANS_NUM_BITS = clogb2(C_M_TRANSACTIONS_NUM-1);


// Example State machine to initialize counter, initialize write transactions, 
// initialize read transactions and comparison of read data with the 
// written data words.
parameter [1:0] IDLE = 2'b00, // This state initiates AXI4Lite transaction 
// after the state machine changes state to INIT_WRITE   
// when there is 0 to 1 transition on INIT_AXI_TXN
INIT_WRITE   = 2'b01, // This state initializes write transaction,
// once writes are done, the state machine 
// changes state to INIT_READ 
INIT_READ = 2'b10, // This state initializes read transaction
// once reads are done, the state machine 
// changes state to INIT_COMPARE 
INIT_COMPARE = 2'b11; // This state issues the status of comparison 
// of the written data with the read data


reg [1:0] mst_exec_state;


// AXI4LITE signals
//write address valid
reg  axi_awvalid;
//write data valid
reg  axi_wvalid;
//read address valid
reg  axi_arvalid;
//read data acceptance
reg  axi_rready;
//write response acceptance
reg  axi_bready;
//write address
reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;
//write data
reg [C_M_AXI_DATA_WIDTH-1 : 0] axi_wdata;
//read addresss
reg [C_M_AXI_ADDR_WIDTH-1 : 0] axi_araddr;
//Asserts when there is a write response error
wire  write_resp_error;
//Asserts when there is a read response error
wire  read_resp_error;
//A pulse to initiate a write transaction
reg  start_single_write;
//A pulse to initiate a read transaction
reg  start_single_read;
//Asserts when a single beat write transaction is issued and remains asserted till the completion of write trasaction.
reg  write_issued;
//Asserts when a single beat read transaction is issued and remains asserted till the completion of read trasaction.
reg  read_issued;
//flag that marks the completion of write trasactions. The number of write transaction is user selected by the parameter C_M_TRANSACTIONS_NUM.
reg  writes_done;
//flag that marks the completion of read trasactions. The number of read transaction is user selected by the parameter C_M_TRANSACTIONS_NUM
reg  reads_done;
//The error register is asserted when any of the write response error, read response error or the data mismatch flags are asserted.
reg  error_reg;
//index counter to track the number of write transaction issued
reg [TRANS_NUM_BITS : 0] write_index;
//index counter to track the number of read transaction issued
reg [TRANS_NUM_BITS : 0] read_index;
//Expected read data used to compare with the read data.
reg [C_M_AXI_DATA_WIDTH-1 : 0] expected_rdata;
//Flag marks the completion of comparison of the read data with the expected read data
reg  compare_done;
//This flag is asserted when there is a mismatch of the read data with the expected read data.
reg  read_mismatch;
//Flag is asserted when the write index reaches the last write transction number
reg  last_write;
//Flag is asserted when the read index reaches the last read transction number
reg  last_read;
reg  init_txn_ff;
reg  init_txn_ff2;
reg  init_txn_edge;
wire  init_txn_pulse;




// I/O Connections assignments


//Adding the offset address to the base addr of the slave
assign M_AXI_AWADDR = C_M_TARGET_SLAVE_BASE_ADDR + axi_awaddr;
//AXI 4 write data
assign M_AXI_WDATA = axi_wdata;
assign M_AXI_AWPROT = 3'b000;
assign M_AXI_AWVALID = axi_awvalid;
//Write Data(W)
assign M_AXI_WVALID = axi_wvalid;
//Set all byte strobes in this example
assign M_AXI_WSTRB = 4'b1111;
//Write Response (B)
assign M_AXI_BREADY = axi_bready;
//Read Address (AR)
assign M_AXI_ARADDR = C_M_TARGET_SLAVE_BASE_ADDR + axi_araddr;
assign M_AXI_ARVALID = axi_arvalid;
assign M_AXI_ARPROT = 3'b001;
//Read and Read Response (R)
assign M_AXI_RREADY = axi_rready;
//Example design I/O
assign TXN_DONE = compare_done;
assign init_txn_pulse = (!init_txn_ff2) && init_txn_ff;




//Generate a pulse to initiate AXI transaction.
always @(posedge M_AXI_ACLK)       
  begin                                                                        
    // Initiates AXI transaction delay    
    if (M_AXI_ARESETN == 0 )                                                   
      begin                                                                    
        init_txn_ff <= 1'b0;                                                   
        init_txn_ff2 <= 1'b0;                                                   
      end                                                                               
    else                                                                       
      begin  
        init_txn_ff <= INIT_AXI_TXN;
        init_txn_ff2 <= init_txn_ff;                                                                 
      end                                                                      
  end     




//--------------------
//Write Address Channel
//--------------------


// The purpose of the write address channel is to request the address and 
// command information for the entire transaction.  It is a single beat
// of information.


// Note for this example the axi_awvalid/axi_wvalid are asserted at the same
// time, and then each is deasserted independent from each other.
// This is a lower-performance, but simplier control scheme.


// AXI VALID signals must be held active until accepted by the partner.


// A data transfer is accepted by the slave when a master has
// VALID data and the slave acknoledges it is also READY. While the master
// is allowed to generated multiple, back-to-back requests by not 
// deasserting VALID, this design will add rest cycle for
// simplicity.


// Since only one outstanding transaction is issued by the user design,
// there will not be a collision between a new request and an accepted
// request on the same clock cycle. 


  always @(posedge M_AXI_ACLK)       
  begin                                                                        
    //Only VALID signals must be deasserted during reset per AXI spec          
    //Consider inverting then registering active-low reset for higher fmax     
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                   
      begin                                                                    
        axi_awvalid <= 1'b0;                                                   
      end                                                                      
      //Signal a new address/data command is available by user logic           
    else                                                                       
      begin                                                                    
        if (start_single_write)                                                
          begin                                                                
            axi_awvalid <= 1'b1;                                               
          end                                                                  
     //Address accepted by interconnect/slave (issue of M_AXI_AWREADY by slave)
        else if (M_AXI_AWREADY && axi_awvalid)                                 
          begin                                                                
            axi_awvalid <= 1'b0;                                               
          end                                                                  
      end                                                                      
  end                                                                          
                                                                               
                                                                               
  // start_single_write triggers a new write                                   
  // transaction. write_index is a counter to                                  
  // keep track with number of write transaction                               
  // issued/initiated                                                          
  always @(posedge M_AXI_ACLK)                                                 
  begin                                                                        
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                   
      begin                                                                    
        write_index <= 0;                                                      
      end                                                                      
      // Signals a new write address/ write data is                            
      // available by user logic                                               
    else if (start_single_write)                                               
      begin                                                                    
        write_index <= write_index + 1;                                        
      end                                                                      
  end                                                                          




//--------------------
//Write Data Channel
//--------------------


//The write data channel is for transfering the actual data.
//The data generation is speific to the example design, and 
//so only the WVALID/WREADY handshake is shown here


   always @(posedge M_AXI_ACLK)                                        
   begin                                                                         
     if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                    
       begin                                                                     
         axi_wvalid <= 1'b0;                                                     
       end                                                                       
     //Signal a new address/data command is available by user logic              
     else if (start_single_write)                                                
       begin                                                                     
         axi_wvalid <= 1'b1;                                                     
       end                                                                       
     //Data accepted by interconnect/slave (issue of M_AXI_WREADY by slave)      
     else if (M_AXI_WREADY && axi_wvalid)                                        
       begin                                                                     
        axi_wvalid <= 1'b0;                                                      
       end                                                                       
   end                                                                           




//----------------------------
//Write Response (B) Channel
//----------------------------


//The write response channel provides feedback that the write has committed
//to memory. BREADY will occur after both the data and the write address
//has arrived and been accepted by the slave, and can guarantee that no
//other accesses launched afterwards will be able to be reordered before it.


//The BRESP bit [1] is used indicate any errors from the interconnect or
//slave for the entire write burst. This example will capture the error.


//While not necessary per spec, it is advisable to reset READY signals in
//case of differing reset latencies between master/slave.


  always @(posedge M_AXI_ACLK)                                    
  begin                                                                
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                           
      begin                                                            
        axi_bready <= 1'b0;                                            
      end                                                              
    // accept/acknowledge bresp with axi_bready by the master          
    // when M_AXI_BVALID is asserted by slave                          
    else if (M_AXI_BVALID && ~axi_bready)                              
      begin                                                            
        axi_bready <= 1'b1;                                            
      end                                                              
    // deassert after one clock cycle                                  
    else if (axi_bready)                                               
      begin                                                            
        axi_bready <= 1'b0;                                            
      end                                                              
    // retain the previous value                                       
    else                                                               
      axi_bready <= axi_bready;                                        
  end                                                                  
                                                                       
//Flag write errors                                                    
assign write_resp_error = (axi_bready & M_AXI_BVALID & M_AXI_BRESP[1]);




//----------------------------
//Read Address Channel
//----------------------------


//start_single_read triggers a new read transaction. read_index is a counter to
//keep track with number of read transaction issued/initiated


  always @(posedge M_AXI_ACLK)                                                     
  begin                                                                            
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                       
      begin                                                                        
        read_index <= 0;                                                           
      end                                                                          
    // Signals a new read address is                                               
    // available by user logic                                                     
    else if (start_single_read)                                                    
      begin                                                                        
        read_index <= read_index + 1;                                              
      end                                                                          
  end                                                                              
                                                                                   
  // A new axi_arvalid is asserted when there is a valid read address              
  // available by the master. start_single_read triggers a new read                
  // transaction                                                                   
  always @(posedge M_AXI_ACLK)                                                     
  begin                                                                            
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                       
      begin                                                                        
        axi_arvalid <= 1'b0;                                                       
      end                                                                          
    //Signal a new read address command is available by user logic                 
    else if (start_single_read)                                                    
      begin                                                                        
        axi_arvalid <= 1'b1;                                                       
      end                                                                          
    //RAddress accepted by interconnect/slave (issue of M_AXI_ARREADY by slave)    
    else if (M_AXI_ARREADY && axi_arvalid)                                         
      begin                                                                        
        axi_arvalid <= 1'b0;                                                       
      end                                                                          
    // retain the previous value                                                   
  end                                                                              




//--------------------------------
//Read Data (and Response) Channel
//--------------------------------


//The Read Data channel returns the results of the read request 
//The master will accept the read data by asserting axi_rready
//when there is a valid read data available.
//While not necessary per spec, it is advisable to reset READY signals in
//case of differing reset latencies between master/slave.


  always @(posedge M_AXI_ACLK)                                    
  begin                                                                 
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                            
      begin                                                             
        axi_rready <= 1'b0;                                             
      end                                                               
    // accept/acknowledge rdata/rresp with axi_rready by the master     
    // when M_AXI_RVALID is asserted by slave                           
    else if (M_AXI_RVALID && ~axi_rready)                               
      begin                                                             
        axi_rready <= 1'b1;                                             
      end                                                               
    // deassert after one clock cycle                                   
    else if (axi_rready)                                                
      begin                                                             
        axi_rready <= 1'b0;                                             
      end                                                               
    // retain the previous value                                        
  end                                                                   
                                                                        
//Flag write errors                                                     
assign read_resp_error = (axi_rready & M_AXI_RVALID & M_AXI_RRESP[1]);  




//--------------------------------
//User Logic
//--------------------------------


//Address/Data Stimulus


//Address/data pairs for this example. The read and write values should
//match.
//Modify these as desired for different address patterns.


  //Write Addresses                                        
  always @(posedge M_AXI_ACLK)                                  
      begin                                                     
        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
          begin                                                 
            axi_awaddr <= 0;                                    
          end                                                   
          // Signals a new write address/ write data is         
          // available by user logic                            
        else if (M_AXI_AWREADY && axi_awvalid)                  
          begin                                                 
            axi_awaddr <= axi_awaddr + 32'h00000004;            
                                                                
          end                                                   
      end                                                       
                                                                
  // Write data generation                                      
  always @(posedge M_AXI_ACLK)                                  
      begin                                                     
        if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1 )                                
          begin                                                 
            axi_wdata <= C_M_START_DATA_VALUE;                  
          end                                                   
        // Signals a new write address/ write data is           
        // available by user logic                              
        else if (M_AXI_WREADY && axi_wvalid)                    
          begin                                                 
            axi_wdata <= C_M_START_DATA_VALUE + write_index;    
          end                                                   
        end                                                 
                                                                
  //Read Addresses                                              
  always @(posedge M_AXI_ACLK)                                  
      begin                                                     
        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
          begin                                                 
            axi_araddr <= 0;                                    
          end                                                   
          // Signals a new write address/ write data is         
          // available by user logic                            
        else if (M_AXI_ARREADY && axi_arvalid)                  
          begin                                                 
            axi_araddr <= axi_araddr + 32'h00000004;            
          end                                                   
      end                                                       
                                                                
                                                                
                                                                
  always @(posedge M_AXI_ACLK)                                  
      begin                                                     
        if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                
          begin                                                 
            expected_rdata <= C_M_START_DATA_VALUE;             
          end                                                   
          // Signals a new write address/ write data is         
          // available by user logic                            
        else if (M_AXI_RVALID && axi_rready)                    
          begin                                                 
            expected_rdata <= C_M_START_DATA_VALUE + read_index;
          end                                                   
      end                                                       
  //implement master command interface state machine                         
  always @ ( posedge M_AXI_ACLK)                                                    
  begin                                                                             
    if (M_AXI_ARESETN == 1'b0)                                                     
      begin                                                                         
      // reset condition                                                            
      // All the signals are assigned default values under reset condition          
        mst_exec_state  <= IDLE;                                            
        start_single_write <= 1'b0;                                                 
        write_issued  <= 1'b0;                                                      
        start_single_read  <= 1'b0;                                                 
        read_issued   <= 1'b0;                                                      
        compare_done  <= 1'b0;                                                      
        ERROR <= 1'b0;
      end                                                                           
    else                                                                            
      begin                                                                         
       // state transition                                                          
        case (mst_exec_state)                                                       
                                                                                    
          IDLE:                                                             
          // This state is responsible to initiate 
          // AXI transaction when init_txn_pulse is asserted 
            if ( init_txn_pulse == 1'b1 )                                     
              begin                                                                 
                mst_exec_state  <= INIT_WRITE;                                      
                ERROR <= 1'b0;
                compare_done <= 1'b0;
              end                                                                   
            else                                                                    
              begin                                                                 
                mst_exec_state  <= IDLE;                                    
              end                                                                   
                                                                                    
          INIT_WRITE:                                                               
            // This state is responsible to issue start_single_write pulse to       
            // initiate a write transaction. Write transactions will be             
            // issued until last_write signal is asserted.                          
            // write controller                                                     
            if (writes_done)                                                        
              begin                                                                 
                mst_exec_state <= INIT_READ;//                                      
              end                                                                   
            else                                                                    
              begin                                                                 
                mst_exec_state  <= INIT_WRITE;                                      
                                                                                    
                  if (~axi_awvalid && ~axi_wvalid && ~M_AXI_BVALID && ~last_write && ~start_single_write && ~write_issued)
                    begin                                                           
                      start_single_write <= 1'b1;                                   
                      write_issued  <= 1'b1;                                        
                    end                                                             
                  else if (axi_bready)                                              
                    begin                                                           
                      write_issued  <= 1'b0;                                        
                    end                                                             
                  else                                                              
                    begin                                                           
                      start_single_write <= 1'b0; //Negate to generate a pulse      
                    end                                                             
              end                                                                   
                                                                                    
          INIT_READ:                                                                
            // This state is responsible to issue start_single_read pulse to        
            // initiate a read transaction. Read transactions will be               
            // issued until last_read signal is asserted.                           
             // read controller                                                     
             if (reads_done)                                                        
               begin                                                                
                 mst_exec_state <= INIT_COMPARE;                                    
               end                                                                  
             else                                                                   
               begin                                                                
                 mst_exec_state  <= INIT_READ;                                      
                                                                                    
                 if (~axi_arvalid && ~M_AXI_RVALID && ~last_read && ~start_single_read && ~read_issued)
                   begin                                                            
                     start_single_read <= 1'b1;                                     
                     read_issued  <= 1'b1;                                          
                   end                                                              
                 else if (axi_rready)                                               
                   begin                                                            
                     read_issued  <= 1'b0;                                          
                   end                                                              
                 else                                                               
                   begin                                                            
                     start_single_read <= 1'b0; //Negate to generate a pulse        
                   end                                                              
               end                                                                  
                                                                                    
           INIT_COMPARE:                                                            
             begin
                 // This state is responsible to issue the state of comparison          
                 // of written data with the read data. If no error flags are set,      
                 // compare_done signal will be asseted to indicate success.            
                 ERROR <= error_reg; 
                 mst_exec_state <= IDLE;                                    
                 compare_done <= 1'b1;                                              
             end                                                                  
           default :                                                                
             begin                                                                  
               mst_exec_state  <= IDLE;                                     
             end                                                                    
        endcase                                                                     
    end                                                                             
  end //MASTER_EXECUTION_PROC                                                       
                                                                                    
  //Terminal write count                                                            
                                                                                    
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
      last_write <= 1'b0;                                                           
                                                                                    
    //The last write should be associated with a write address ready response       
    else if ((write_index == C_M_TRANSACTIONS_NUM) && M_AXI_AWREADY)                
      last_write <= 1'b1;                                                           
    else                                                                            
      last_write <= last_write;                                                     
  end                                                                               
                                                                                    
  //Check for last write completion.                                                
                                                                                    
  //This logic is to qualify the last write count with the final write              
  //response. This demonstrates how to confirm that a write has been                
  //committed.                                                                      
                                                                                    
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
      writes_done <= 1'b0;                                                          
                                                                                    
      //The writes_done should be associated with a bready response                 
    else if (last_write && M_AXI_BVALID && axi_bready)                              
      writes_done <= 1'b1;                                                          
    else                                                                            
      writes_done <= writes_done;                                                   
  end                                                                               
                                                                                    
//------------------                                                                
//Read example                                                                      
//------------------                                                                
                                                                                    
//Terminal Read Count                                                               
                                                                                    
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
      last_read <= 1'b0;                                                            
                                                                                    
    //The last read should be associated with a read address ready response         
    else if ((read_index == C_M_TRANSACTIONS_NUM) && (M_AXI_ARREADY) )              
      last_read <= 1'b1;                                                            
    else                                                                            
      last_read <= last_read;                                                       
  end                                                                               
                                                                                    
/*                                                                                  
Check for last read completion.                                                    
                                                                                    
This logic is to qualify the last read count with the final read                   
response/data.                                                                     
*/                                                                                 
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0 || init_txn_pulse == 1'b1)                                                         
      reads_done <= 1'b0;                                                           
                                                                                    
    //The reads_done should be associated with a read ready response                
    else if (last_read && M_AXI_RVALID && axi_rready)                               
      reads_done <= 1'b1;                                                           
    else                                                                            
      reads_done <= reads_done;                                                     
    end                                                                             
                                                                                    
//-----------------------------                                                     
//Example design error register                                                     
//-----------------------------                                                     
                                                                                    
//Data Comparison                                                                   
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                         
    read_mismatch <= 1'b0;                                                          
                                                                                    
    //The read data when available (on axi_rready) is compared with the expected data
    else if ((M_AXI_RVALID && axi_rready) && (M_AXI_RDATA != expected_rdata))         
      read_mismatch <= 1'b1;                                                        
    else                                                                            
      read_mismatch <= read_mismatch;                                               
  end                                                                               
                                                                                    
// Register and hold any data mismatches, or read/write interface errors            
  always @(posedge M_AXI_ACLK)                                                      
  begin                                                                             
    if (M_AXI_ARESETN == 0  || init_txn_pulse == 1'b1)                                                         
      error_reg <= 1'b0;                                                            
                                                                                    
    //Capture any error types                                                       
    else if (read_mismatch || write_resp_error || read_resp_error)                  
      error_reg <= 1'b1;                                                            
    else                                                                            
      error_reg <= error_reg;                                                       
  end                                                                               
// Add user logic here


// User logic ends


endmodule

附录4:底层模块Slave 顶层源代码:



`timescale 1 ns / 1 ps


module axi_ip_slave_v1_0 #
(
// Users to add parameters here


// User parameters ends
// Do not modify the parameters beyond this line




// Parameters of Axi Slave Bus Interface S00_AXI
parameter integer C_S00_AXI_DATA_WIDTH = 32,
parameter integer C_S00_AXI_ADDR_WIDTH = 7
)
(
// Users to add ports here


// User ports ends
// Do not modify the ports beyond this line




// Ports of Axi Slave Bus Interface S00_AXI
input wire  s00_axi_aclk,
input wire  s00_axi_aresetn,
input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr,
input wire [2 : 0] s00_axi_awprot,
input wire  s00_axi_awvalid,
output wire  s00_axi_awready,
input wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata,
input wire [(C_S00_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb,
input wire  s00_axi_wvalid,
output wire  s00_axi_wready,
output wire [1 : 0] s00_axi_bresp,
output wire  s00_axi_bvalid,
input wire  s00_axi_bready,
input wire [C_S00_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr,
input wire [2 : 0] s00_axi_arprot,
input wire  s00_axi_arvalid,
output wire  s00_axi_arready,
output wire [C_S00_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata,
output wire [1 : 0] s00_axi_rresp,
output wire  s00_axi_rvalid,
input wire  s00_axi_rready
);
// Instantiation of Axi Bus Interface S00_AXI
axi_ip_slave_v1_0_S00_AXI # ( 
.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),
.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)
) axi_ip_slave_v1_0_S00_AXI_inst (
.S_AXI_ACLK(s00_axi_aclk),
.S_AXI_ARESETN(s00_axi_aresetn),
.S_AXI_AWADDR(s00_axi_awaddr),
.S_AXI_AWPROT(s00_axi_awprot),
.S_AXI_AWVALID(s00_axi_awvalid),
.S_AXI_AWREADY(s00_axi_awready),
.S_AXI_WDATA(s00_axi_wdata),
.S_AXI_WSTRB(s00_axi_wstrb),
.S_AXI_WVALID(s00_axi_wvalid),
.S_AXI_WREADY(s00_axi_wready),
.S_AXI_BRESP(s00_axi_bresp),
.S_AXI_BVALID(s00_axi_bvalid),
.S_AXI_BREADY(s00_axi_bready),
.S_AXI_ARADDR(s00_axi_araddr),
.S_AXI_ARPROT(s00_axi_arprot),
.S_AXI_ARVALID(s00_axi_arvalid),
.S_AXI_ARREADY(s00_axi_arready),
.S_AXI_RDATA(s00_axi_rdata),
.S_AXI_RRESP(s00_axi_rresp),
.S_AXI_RVALID(s00_axi_rvalid),
.S_AXI_RREADY(s00_axi_rready)
);


// Add user logic here


// User logic ends


endmodule


附录5:底层模块Slave 底层源代码:

////////此处需要说明一下:做的slave核时,寄存器个数为32,生成核后,地址宽度为7,为什么呢?因为一个寄存器为32位,4个字节,所以一个寄存器占用4个地址。2^7=128个地址,一个寄存器占4个。

`timescale 1 ns / 1 ps


module axi_ip_slave_v1_0_S00_AXI #
(
// Users to add parameters here


// User parameters ends
// Do not modify the parameters beyond this line


// Width of S_AXI data bus
parameter integer C_S_AXI_DATA_WIDTH = 32,
// Width of S_AXI address bus
parameter integer C_S_AXI_ADDR_WIDTH = 7
)
(
// Users to add ports here


// User ports ends
// Do not modify the ports beyond this line


// Global Clock Signal
input wire  S_AXI_ACLK,
// Global Reset Signal. This Signal is Active LOW
input wire  S_AXI_ARESETN,
// Write address (issued by master, acceped by Slave)
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
// Write channel Protection type. This signal indicates the
    // privilege and security level of the transaction, and whether
    // the transaction is a data access or an instruction access.
input wire [2 : 0] S_AXI_AWPROT,
// Write address valid. This signal indicates that the master signaling
    // valid write address and control information.
input wire  S_AXI_AWVALID,
// Write address ready. This signal indicates that the slave is ready
    // to accept an address and associated control signals.
output wire  S_AXI_AWREADY,
// Write data (issued by master, acceped by Slave) 
input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
// Write strobes. This signal indicates which byte lanes hold
    // valid data. There is one write strobe bit for each eight
    // bits of the write data bus.    
input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
// Write valid. This signal indicates that valid write
    // data and strobes are available.
input wire  S_AXI_WVALID,
// Write ready. This signal indicates that the slave
    // can accept the write data.
output wire  S_AXI_WREADY,
// Write response. This signal indicates the status
    // of the write transaction.
output wire [1 : 0] S_AXI_BRESP,
// Write response valid. This signal indicates that the channel
    // is signaling a valid write response.
output wire  S_AXI_BVALID,
// Response ready. This signal indicates that the master
    // can accept a write response.
input wire  S_AXI_BREADY,
// Read address (issued by master, acceped by Slave)
input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
// Protection type. This signal indicates the privilege
    // and security level of the transaction, and whether the
    // transaction is a data access or an instruction access.
input wire [2 : 0] S_AXI_ARPROT,
// Read address valid. This signal indicates that the channel
    // is signaling valid read address and control information.
input wire  S_AXI_ARVALID,
// Read address ready. This signal indicates that the slave is
    // ready to accept an address and associated control signals.
output wire  S_AXI_ARREADY,
// Read data (issued by slave)
output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
// Read response. This signal indicates the status of the
    // read transfer.
output wire [1 : 0] S_AXI_RRESP,
// Read valid. This signal indicates that the channel is
    // signaling the required read data.
output wire  S_AXI_RVALID,
// Read ready. This signal indicates that the master can
    // accept the read data and response information.
input wire  S_AXI_RREADY
);


// AXI4LITE signals
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;
reg  axi_awready;
reg  axi_wready;
reg [1 : 0] axi_bresp;
reg  axi_bvalid;
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr;
reg  axi_arready;
reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata;
reg [1 : 0] axi_rresp;
reg  axi_rvalid;


// Example-specific design signals
// local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
// ADDR_LSB is used for addressing 32/64 bit registers/memories
// ADDR_LSB = 2 for 32 bits (n downto 2)
// ADDR_LSB = 3 for 64 bits (n downto 3)
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
localparam integer OPT_MEM_ADDR_BITS = 4;
//----------------------------------------------
//-- Signals for user logic register space example
//------------------------------------------------
//-- Number of Slave Registers 32
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg4;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg5;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg6;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg7;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg8;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg9;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg10;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg11;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg12;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg13;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg14;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg15;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg16;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg17;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg18;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg19;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg20;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg21;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg22;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg23;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg24;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg25;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg26;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg27;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg28;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg29;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg30;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg31;
wire slv_reg_rden;
wire slv_reg_wren;
reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out;
integer byte_index;


// I/O Connections assignments


assign S_AXI_AWREADY = axi_awready;
assign S_AXI_WREADY = axi_wready;
assign S_AXI_BRESP = axi_bresp;
assign S_AXI_BVALID = axi_bvalid;
assign S_AXI_ARREADY = axi_arready;
assign S_AXI_RDATA = axi_rdata;
assign S_AXI_RRESP = axi_rresp;
assign S_AXI_RVALID = axi_rvalid;
// Implement axi_awready generation
// axi_awready is asserted for one S_AXI_ACLK clock cycle when both
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is
// de-asserted when reset is low.


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_awready <= 1'b0;
    end 
  else
    begin    
      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
        begin
          // slave is ready to accept write address when 
          // there is a valid write address and write data
          // on the write address and data bus. This design 
          // expects no outstanding transactions. 
          axi_awready <= 1'b1;
        end
      else           
        begin
          axi_awready <= 1'b0;
        end
    end 
end       


// Implement axi_awaddr latching
// This process is used to latch the address when both 
// S_AXI_AWVALID and S_AXI_WVALID are valid. 


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_awaddr <= 0;
    end 
  else
    begin    
      if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID)
        begin
          // Write Address latching 
          axi_awaddr <= S_AXI_AWADDR;
        end
    end 
end       


// Implement axi_wready generation
// axi_wready is asserted for one S_AXI_ACLK clock cycle when both
// S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is 
// de-asserted when reset is low. 


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_wready <= 1'b0;
    end 
  else
    begin    
      if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID)
        begin
          // slave is ready to accept write data when 
          // there is a valid write address and write data
          // on the write address and data bus. This design 
          // expects no outstanding transactions. 
          axi_wready <= 1'b1;
        end
      else
        begin
          axi_wready <= 1'b0;
        end
    end 
end       


// Implement memory mapped register select and write logic generation
// The write data is accepted and written to memory mapped registers when
// axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
// select byte enables of slave registers while writing.
// These registers are cleared when reset (active low) is applied.
// Slave register write enable is asserted when valid address and data are available
// and the slave is ready to accept the write address and write data.
assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      slv_reg0 <= 0;
      slv_reg1 <= 0;
      slv_reg2 <= 0;
      slv_reg3 <= 0;
      slv_reg4 <= 0;
      slv_reg5 <= 0;
      slv_reg6 <= 0;
      slv_reg7 <= 0;
      slv_reg8 <= 0;
      slv_reg9 <= 0;
      slv_reg10 <= 0;
      slv_reg11 <= 0;
      slv_reg12 <= 0;
      slv_reg13 <= 0;
      slv_reg14 <= 0;
      slv_reg15 <= 0;
      slv_reg16 <= 0;
      slv_reg17 <= 0;
      slv_reg18 <= 0;
      slv_reg19 <= 0;
      slv_reg20 <= 0;
      slv_reg21 <= 0;
      slv_reg22 <= 0;
      slv_reg23 <= 0;
      slv_reg24 <= 0;
      slv_reg25 <= 0;
      slv_reg26 <= 0;
      slv_reg27 <= 0;
      slv_reg28 <= 0;
      slv_reg29 <= 0;
      slv_reg30 <= 0;
      slv_reg31 <= 0;
    end 
  else begin
    if (slv_reg_wren)
      begin
        case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
          5'h00:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 0
                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h01:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 1
                slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h02:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 2
                slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h03:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 3
                slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h04:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 4
                slv_reg4[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h05:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 5
                slv_reg5[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h06:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 6
                slv_reg6[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h07:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 7
                slv_reg7[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h08:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 8
                slv_reg8[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h09:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 9
                slv_reg9[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0A:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 10
                slv_reg10[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0B:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 11
                slv_reg11[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0C:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 12
                slv_reg12[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0D:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 13
                slv_reg13[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0E:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 14
                slv_reg14[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h0F:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 15
                slv_reg15[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h10:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 16
                slv_reg16[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h11:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 17
                slv_reg17[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h12:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 18
                slv_reg18[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h13:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 19
                slv_reg19[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h14:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 20
                slv_reg20[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h15:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 21
                slv_reg21[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h16:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 22
                slv_reg22[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h17:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 23
                slv_reg23[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h18:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 24
                slv_reg24[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h19:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 25
                slv_reg25[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1A:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 26
                slv_reg26[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1B:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 27
                slv_reg27[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1C:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 28
                slv_reg28[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1D:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 29
                slv_reg29[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1E:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 30
                slv_reg30[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          5'h1F:
            for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )
              if ( S_AXI_WSTRB[byte_index] == 1 ) begin
                // Respective byte enables are asserted as per write strobes 
                // Slave register 31
                slv_reg31[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
              end  
          default : begin
                      slv_reg0 <= slv_reg0;
                      slv_reg1 <= slv_reg1;
                      slv_reg2 <= slv_reg2;
                      slv_reg3 <= slv_reg3;
                      slv_reg4 <= slv_reg4;
                      slv_reg5 <= slv_reg5;
                      slv_reg6 <= slv_reg6;
                      slv_reg7 <= slv_reg7;
                      slv_reg8 <= slv_reg8;
                      slv_reg9 <= slv_reg9;
                      slv_reg10 <= slv_reg10;
                      slv_reg11 <= slv_reg11;
                      slv_reg12 <= slv_reg12;
                      slv_reg13 <= slv_reg13;
                      slv_reg14 <= slv_reg14;
                      slv_reg15 <= slv_reg15;
                      slv_reg16 <= slv_reg16;
                      slv_reg17 <= slv_reg17;
                      slv_reg18 <= slv_reg18;
                      slv_reg19 <= slv_reg19;
                      slv_reg20 <= slv_reg20;
                      slv_reg21 <= slv_reg21;
                      slv_reg22 <= slv_reg22;
                      slv_reg23 <= slv_reg23;
                      slv_reg24 <= slv_reg24;
                      slv_reg25 <= slv_reg25;
                      slv_reg26 <= slv_reg26;
                      slv_reg27 <= slv_reg27;
                      slv_reg28 <= slv_reg28;
                      slv_reg29 <= slv_reg29;
                      slv_reg30 <= slv_reg30;
                      slv_reg31 <= slv_reg31;
                    end
        endcase
      end
  end
end    


// Implement write response logic generation
// The write response and response valid signals are asserted by the slave 
// when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.  
// This marks the acceptance of address and indicates the status of 
// write transaction.


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_bvalid  <= 0;
      axi_bresp   <= 2'b0;
    end 
  else
    begin    
      if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)
        begin
          // indicates a valid write response is available
          axi_bvalid <= 1'b1;
          axi_bresp  <= 2'b0; // 'OKAY' response 
        end                   // work error responses in future
      else
        begin
          if (S_AXI_BREADY && axi_bvalid) 
            //check if bready is asserted while bvalid is high) 
            //(there is a possibility that bready is always asserted high)   
            begin
              axi_bvalid <= 1'b0; 
            end  
        end
    end
end   


// Implement axi_arready generation
// axi_arready is asserted for one S_AXI_ACLK clock cycle when
// S_AXI_ARVALID is asserted. axi_awready is 
// de-asserted when reset (active low) is asserted. 
// The read address is also latched when S_AXI_ARVALID is 
// asserted. axi_araddr is reset to zero on reset assertion.


always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_arready <= 1'b0;
      axi_araddr  <= 32'b0;
    end 
  else
    begin    
      if (~axi_arready && S_AXI_ARVALID)
        begin
          // indicates that the slave has acceped the valid read address
          axi_arready <= 1'b1;
          // Read address latching
          axi_araddr  <= S_AXI_ARADDR;
        end
      else
        begin
          axi_arready <= 1'b0;
        end
    end 
end       


// Implement axi_arvalid generation
// axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both 
// S_AXI_ARVALID and axi_arready are asserted. The slave registers 
// data are available on the axi_rdata bus at this instance. The 
// assertion of axi_rvalid marks the validity of read data on the 
// bus and axi_rresp indicates the status of read transaction.axi_rvalid 
// is deasserted on reset (active low). axi_rresp and axi_rdata are 
// cleared to zero on reset (active low).  
always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_rvalid <= 0;
      axi_rresp  <= 0;
    end 
  else
    begin    
      if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)
        begin
          // Valid read data is available at the read data bus
          axi_rvalid <= 1'b1;
          axi_rresp  <= 2'b0; // 'OKAY' response
        end   
      else if (axi_rvalid && S_AXI_RREADY)
        begin
          // Read data is accepted by the master
          axi_rvalid <= 1'b0;
        end                
    end
end    


// Implement memory mapped register select and read logic generation
// Slave register read enable is asserted when valid address is available
// and the slave is ready to accept the read address.
assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;
always @(*)
begin
      // Address decoding for reading registers
      case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )
        5'h00   : reg_data_out <= slv_reg0;
        5'h01   : reg_data_out <= slv_reg1;
        5'h02   : reg_data_out <= slv_reg2;
        5'h03   : reg_data_out <= slv_reg3;
        5'h04   : reg_data_out <= slv_reg4;
        5'h05   : reg_data_out <= slv_reg5;
        5'h06   : reg_data_out <= slv_reg6;
        5'h07   : reg_data_out <= slv_reg7;
        5'h08   : reg_data_out <= slv_reg8;
        5'h09   : reg_data_out <= slv_reg9;
        5'h0A   : reg_data_out <= slv_reg10;
        5'h0B   : reg_data_out <= slv_reg11;
        5'h0C   : reg_data_out <= slv_reg12;
        5'h0D   : reg_data_out <= slv_reg13;
        5'h0E   : reg_data_out <= slv_reg14;
        5'h0F   : reg_data_out <= slv_reg15;
        5'h10   : reg_data_out <= slv_reg16;
        5'h11   : reg_data_out <= slv_reg17;
        5'h12   : reg_data_out <= slv_reg18;
        5'h13   : reg_data_out <= slv_reg19;
        5'h14   : reg_data_out <= slv_reg20;
        5'h15   : reg_data_out <= slv_reg21;
        5'h16   : reg_data_out <= slv_reg22;
        5'h17   : reg_data_out <= slv_reg23;
        5'h18   : reg_data_out <= slv_reg24;
        5'h19   : reg_data_out <= slv_reg25;
        5'h1A   : reg_data_out <= slv_reg26;
        5'h1B   : reg_data_out <= slv_reg27;
        5'h1C   : reg_data_out <= slv_reg28;
        5'h1D   : reg_data_out <= slv_reg29;
        5'h1E   : reg_data_out <= slv_reg30;
        5'h1F   : reg_data_out <= slv_reg31;
        default : reg_data_out <= 0;
      endcase
end


// Output register or memory read data
always @( posedge S_AXI_ACLK )
begin
  if ( S_AXI_ARESETN == 1'b0 )
    begin
      axi_rdata  <= 0;
    end 
  else
    begin    
      // When there is a valid read address (S_AXI_ARVALID) with 
      // acceptance of read address by the slave (axi_arready), 
      // output the read dada 
      if (slv_reg_rden)
        begin
          axi_rdata <= reg_data_out;     // register read data
        end   
    end
end    


// Add user logic here


// User logic ends


endmodule

猜你喜欢

转载自blog.csdn.net/ningjinghai11/article/details/80596338
今日推荐