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总线信号:AWREAD 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

 

 

转载于:https://www.cnblogs.com/limanjihe/p/9889262.html

你可能感兴趣的:(Zynq-PL中创建AXI Master接口IP及AXI4-Lite总线主从读写时序测试(转))