AXI协议详解及FPGA仿真

发布于:2025-02-27 ⋅ 阅读:(5) ⋅ 点赞:(0)

AXI协议详解及FPGA仿真

1 摘要

AMBA AXI 协议是以高性能,高频系统设计为目标,提供了很多适合高速亚微型系统互连的特征。为相邻存储器连续进行数据传输提供的一种高频率,高带宽,低延迟的总线协议,是一种突发传输协议,即总线描述了主从设备之间的数据传输方式。

2 各类型及优势

其协议主要包括三种类型AXI4_lite、AXI4_full、AXI4_stream。
1)AXI4_full:可称为AXI4,支持突发传输,突发长度为1~256。支持存储器映射型和串流型接口;为通信、视频、嵌入式以及 DSP 功能提供统一化 IP 接口;简便易用,并具有自动流水线例程化等特性,可帮助用户轻松实现既定性能目标;
2)AXI4-Lite:不支持突发传输,一般用于小数据量的IP初始化和嵌入式设备数据传输。简单、低吞吐量的内存映射通信(例如,与控制寄存器和状态寄存器之间的通信);
3)AXI4_stream:流数据,丢弃了地址项,用于高速数据传输。AXI4-stream跟AXI4_full的区别在于AXI4-Stream没有地址接口,只有简单的发送与接收,减少了延时,允许无限制的数据突发传输规模。AXI4-stream的核心思想在于流式处理数据,是用来传输数据流的,如图像输入,高速AD等,这种数据流的处理一般是和DMA一并使用的。

3 AXI协议详解

3.1 通道定义

AXI协议总共有5个独立的通道:
①写数据地址通道;
②写数据通道;
③写应答通道;
④读数据地址通道;
⑤读数据通道;
5个独立的通道都包含一组标记信息的信号,并且使用双向的 VALID 和READY信号实现握手机制。当通道上的有效数据或控制信息可用时,发送信息的源设备将使能 VALID 信号。当目的设备接收到数据时,使能READY 信号.当一次交易中最后数据传输完成时,读数据通道和写数据通道都会发出一个LAST 信号。

(1)读地址和写地址通道
读交易和写交易都有各自的地址通道,相应的地址通道承载了一次交易中所有需要的地址和控制信息。AXI 协议支持以下机制:
•可变长度猝发,每次猝发完成1-16次数据传输
•支持8-1024字节的传输块猝发
• 地址卷回、地址递增和地址固定的猝发
• 通过独占交易和锁定交易实现原子操作
• 系统级的缓存和缓冲控制
• 安全访问和特权访问

(2)读数据通道
读数据通道用于传输从设备返回给主设备的数据和读响应信息。读数据通道包含:
• 8,16,32,64,128,256,512 或1024位宽的数据总线
• 读响应标志了读交易完成的状态

(3)写数据通道
写数据通道主要传输从主设备向从设备写数据信息,其包含:
• 数据总线,宽度可以为 8,16,32,64,128,256,512 或1024字节
• 每 8 个比特一个字节选通字节,标志总线上的哪个字节可用
写数据通道的信息总是放入缓存中,当前一个写交易从设备没有做出响应的情况下,以便于主设备进行写交易。

(4)写响应通道
写响应通道是从设备对写交易作出响应的通道。所有写交易使用完成信号。不是猝发中每个独立数据传输都返回一个完成信号,而是每个猝发完成后一起返回一个完成信号。

3.2 通道信号

AXI协议中使用的信号主要含以下几个部分:
•全局信号

信号 信号描述
ACLK 时钟源 全局时钟,所有信号在时钟源上升沿采样
ARESTN 复位源 全局复位,低电平有效

•写地址通道信号

信号 信号描述
AWID 写地址ID,用于写地址信号组标记
AWADDR 写地址,给出一次写突发传输的写地址
AWLEN AWLEN决定写传输的突发长度
AWSIZE 写突发大小,给出每次突发传输的字节数支持1、2、4、8、16、32、64、128
AWBURST 突发类型: 2'b00 FIXED:突发传输过程中地址固定,用于FIFO访问 2'b01 INCR :增量突发,传输过程中,地址递增。增加量取决AxSIZE的值。 2'b10 WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN) 2'b11 Reserved
AWLOCK 总线锁信号,可提供操作的原子性
AWCACHE 内存类型,该信号表示可缓存,写通过、写回和分配交易属性
AWPROT 保护类型,表明一次传输的特权级及安全等级
AWQOS 质量服务QoS
AWREGION 区域标志,能实现单一物理接口对应的多个逻辑接口
AWUSER 用户自定义信号
AWVALID 有效信号,表明此通道的地址控制信号有效
AWREADY 表明从机可以接收地址和对应的控制信号

•写数据通道信号

信号 信号描述
WID 一次写传输的ID
WDATA 写数据,数据宽度可以是8,16,32,64,128,256,512或1024位宽
WSTRB WSTRB[n:0]对应于对应的写字节,WSTRB[n]对应WDATA[8n+7:8n]。WVALID为低时,WSTRB可以为任意值,WVALID为高时,WSTRB为高的字节线必须指示有效的数据。
WLAST 表明此次传输是最后一个突发传输
WUSER 用户自定义信号
WVALID 写有效,表明此次写有效
WREADY 表明从机可以接收写数据
•写响应通道信号
信号 信号描述
BID 写响应ID
BRESP 写响应,表明写传输交易状态
BUSER 用户自定义
BVALID 写响应有效
BREADY 表明主机能够接收写响应

•读地址通道信号

信号 信号描述
ARID 读地址ID,用来标志一组写信号
ARADDR 读地址,给出一次读突发传输的读地址
ARLEN ARLEN[7:0]决定读传输的突发长度。AXI4扩展突发长度支持INCR突发类型为1~256次传输,对于其他的传输类型依然保持1-16次突发传输(Burst_Length=AxLEN[7:0]+1)。wraping burst ,burst长度必须是2,4,8,16burst不能跨4KB边界不支持提前终止burst传输
ARSIZE 读突发大小,给出每次突发传输的字节数支持1、2、4、8、16、32、64、128
ARBURST 突发类型: 2'b00 FIXED:突发传输过程中地址固定,用于FIFO访问 2'b01 INCR :增量突发,传输过程中,地址递增。增加量取决AxSIZE的值。 2'b10 WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN) 2'b11 Reserved
ARLOCK 总线锁信号,可提供操作的原子性
ARCACHE 内存类型,表明一次传输是怎样通过系统的
ARPROT 保护类型,表明一次传输的特权级及安全等级
ARQOS 质量服务QoS
ARREGION 区域标志,能实现单一物理接口对应的多个逻辑接口
ARREGION 区域标志,能实现单一物理接口对应的多个逻辑接口
ARUSER 户自定义信号
ARVALID 有效信号,表明此通道的地址控制信号有效
ARREADY 表明"从"可以接收地址和对应的控制信号

•读数据通道信号

信号 信号描述
RID 一次读传输的ID
RDATA 读数据
RRESP 读响应,表明读传输的状态
RLAST 表明此次传输是最后一个突发传输
RUSER 用户自定义信号
RVALID 读有效,表明数据总线上数据有效
RREADY 表明主机准备好可以接收数据

•低功耗接口信号

信号 信号描述
CSYSREQ 时钟控制器 系统低功耗请求
CSYSACK 外设 低功耗响应信号
CACTIVE 外设 时钟活动,表示外设是否有要求它的时钟信号

3.3 通道结构

(1)读事务使用读地址和读数据通道,主机在读地址通道上给出要读取的数据的地址和控制信息(当突发读取多个数据时,给出数据存储的首地址和突发长度),从机收到后在将数据通过读数据通道发送给主机。
在这里插入图片描述
(2)写数据和写响应通道的方式,主机首先向发送写控制,然后发送要写入的数据,从机在收完本次写事务的数据后给出写响应信号代表接收完成。
在这里插入图片描述

3.4 握手过程

所有五个通道使用相同的 VALID/READY 握手来传输数据和控制信息。这种双向的流控制机制使得主设备和从设备都可以控制数据和控制信息的传输速率。源设备产生VALID 信号标志当前的数据和控制信息有效。目的设备产生READY 信号标志着可以接收主设备发来的数据和控制信息。传输发生在 VALID 和 READY 信号同时为高的时候。VALID 和 READY 信号的出现有三种关系。
1) VALID 先变高 READY 后变高。时序图如下
在这里插入图片描述
(2) READY 先变高 VALID 后变高。时序图如下
在这里插入图片描述
(3) VALID 和 READY 信号同时变高。时序图如下
在这里插入图片描述

3.5 通道之间的关系

(1)主机不必等待设备先给出 AWREADY 或 WREADY 信号信号后再给出信号 AWVALID 或 WVLAID。
(2)设备可以等待信号 AWVALID 或 WVALID 信号有效或者两个都有效之后再给出 AWREADY 信号。
(3)设备可以等待 AWVALID 或 WVALID 信号有效或者两个信号都有效之后再给出 WREADY 信号。
(4)设备必须等待 WVALID 和 WREADY 信号同时有效了,才能给出 BVALID 信号有效。

在这里插入图片描述

4 AXI-FULL协议仿真

这里仿真AXI4协议向从机存入1到32共32个数据(突发长度为16),起始地址为20。然后将32个数据从从机中以突发的形式全部读出。

4.1仿真顶层文件核心代码

`timescale 1ns / 1ps
module AXI_full_tb;
    reg         M_AXI_ACLK      ;
    reg         M_AXI_ARESETN   ;
    reg         WR_START        ;

    parameter   T = 20;
    initial begin
        M_AXI_ACLK      =   1'b0;    
        M_AXI_ARESETN   =   1'b0;
        WR_START        =   1'b0;
        #(2*T);
        M_AXI_ARESETN   =   1'b1;
        #(10*T);
        WR_START        =   1'b1;
        #(T);
        WR_START        =   1'b0;
		#(30*T);
        WR_START        =   1'b1;
        #(T);
        WR_START        =   1'b0;
    end

    always#(T/2) M_AXI_ACLK = !M_AXI_ACLK;
    AXI_full_top u_AXI_full_top(
        .M_AXI_ACLK             (M_AXI_ACLK      ),      
        .M_AXI_ARESETN          (M_AXI_ARESETN   ),
        .WR_START               (WR_START        )
    );
endmodule

4.2仿真axi-master文件核心代码

`timescale 1ns / 1ps
module AXI_full_M
    #(
		//parameter           C_M_TARGET_SLAVE_BASE_ADDR	= 32'h4000_0000 ,
		parameter integer   C_M_AXI_BURST_LEN	        = 31           ,
		parameter integer   C_M_AXI_ID_WIDTH	        = 1             ,
		parameter integer   C_M_AXI_ADDR_WIDTH	        = 32            ,
		parameter integer   C_M_AXI_DATA_WIDTH	        = 32            ,
		parameter integer   C_M_AXI_AWUSER_WIDTH	    = 0             ,
		parameter integer   C_M_AXI_ARUSER_WIDTH	    = 0             ,
		parameter integer   C_M_AXI_WUSER_WIDTH	        = 0             ,
		parameter integer   C_M_AXI_RUSER_WIDTH	        = 0             ,
		parameter integer   C_M_AXI_BUSER_WIDTH	        = 0
    )
    (
    	input   wire                                    INIT_AXI_TXN    ,
		output  wire                                    TXN_DONE        ,
		output  reg                                     ERROR           ,
		input   wire                                    M_AXI_ACLK      ,
		input   wire                                    M_AXI_ARESETN   ,
		//写地址信号
		output  wire    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_AWID      ,	//写地址ID,一半不用
		output  wire    [C_M_AXI_ADDR_WIDTH-1 : 0]      M_AXI_AWADDR    ,	//写数据的地址
		output  wire    [7 : 0]                         M_AXI_AWLEN     ,	//突发长度
		output  wire    [2 : 0]                         M_AXI_AWSIZE    ,	//数据宽度
		output  wire    [1 : 0]                         M_AXI_AWBURST   ,	//突发模式选择,00为固定地址,01为自增地址突发
		output  wire                                    M_AXI_AWLOCK    ,	//锁信号一般不用,保持为0
		output  wire    [3 : 0]                         M_AXI_AWCACHE   ,	//缓存模式,有多种,这里使用无缓存模式
		output  wire    [2 : 0]                         M_AXI_AWPROT    ,	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		output  wire    [3 : 0]                         M_AXI_AWQOS     ,	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		output 	wire	[3 : 0]							M_AXI_AWREGION	,
		output  wire    [C_M_AXI_AWUSER_WIDTH-1 : 0]    M_AXI_AWUSER    ,	//区域标识符,这里没用,默认0值
		output  wire                                    M_AXI_AWVALID   ,	//写地址有效信号
		input   wire                                    M_AXI_AWREADY   ,	//应答信号是从机输入的不需要控制
		//写数据通道
		output  wire    [C_M_AXI_DATA_WIDTH-1 : 0]      M_AXI_WDATA     ,	//写的数据
		output  wire    [C_M_AXI_DATA_WIDTH/8-1 : 0]    M_AXI_WSTRB     ,	//掩码信号,每8位数据就对应一位掩码信号,掩码信号为高时,数据才能正常传输
		output  wire                                    M_AXI_WLAST     ,	//写数据最后一个数据标志信号
		output  wire    [C_M_AXI_WUSER_WIDTH-1 : 0]     M_AXI_WUSER     ,	//用户自定义信号
		output  wire                                    M_AXI_WVALID    ,	//写数据有效信号
		input   wire                                    M_AXI_WREADY    ,	//从机准备好信号是从从机输入的
		//写响应通道
		input   wire    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_BID       ,
		input   wire    [1 : 0]                         M_AXI_BRESP     ,
		input   wire    [C_M_AXI_BUSER_WIDTH-1 : 0]     M_AXI_BUSER     ,
		input   wire                                    M_AXI_BVALID    ,
		output  wire                                    M_AXI_BREADY    ,	//写响应信号,主机给从机的响应准备好信号
		//读地址通道
		output  wire    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_ARID      ,	//读地址ID,一半不用
		output  wire    [C_M_AXI_ADDR_WIDTH-1 : 0]      M_AXI_ARADDR    ,	//读数据的地址
		output  wire    [7 : 0]                         M_AXI_ARLEN     ,	//突发长度
		output  wire    [2 : 0]                         M_AXI_ARSIZE    ,	//数据宽度
		output  wire    [1 : 0]                         M_AXI_ARBURST   ,	//突发模式选择,00为固定地址,01为自增地址突发
		output  wire                                    M_AXI_ARLOCK    ,	//锁信号一般不用,保持为0
		output  wire    [3 : 0]                         M_AXI_ARCACHE   ,	//缓存模式,有多种,这里使用无缓存模式
		output  wire    [2 : 0]                         M_AXI_ARPROT    ,	//保护编码,指示特权访问/安全访问/指明数据访问还是指令访问,这里设置全0
		output  wire    [3 : 0]                         M_AXI_ARQOS     ,	//Qos信号,此协议的Qos信号不起作用,默认0值即可
		output	wire	[3 : 0]							M_AXI_ARREGION	,	//REGION,一般不用,赋4'b0000
		output  wire    [C_M_AXI_ARUSER_WIDTH-1 : 0]    M_AXI_ARUSER    ,	//区域标识符,这里没用,默认0值
		output  wire                                    M_AXI_ARVALID   ,	//读地址有效信号
		input   wire                                    M_AXI_ARREADY   ,	//应答信号是从机输入的不需要控制
		//读数据通道
		input   wire    [C_M_AXI_ID_WIDTH-1 : 0]        M_AXI_RID       ,
		input   wire    [C_M_AXI_DATA_WIDTH-1 : 0]      M_AXI_RDATA     ,	//读入数据
		input   wire    [1 : 0]                         M_AXI_RRESP     ,
		input   wire                                    M_AXI_RLAST     ,	//从机数据的读数据LAST信号
		input   wire    [C_M_AXI_RUSER_WIDTH-1 : 0]     M_AXI_RUSER     ,
		input   wire                                    M_AXI_RVALID    ,	//从机输入的读数据准备好信号
		output  wire                                    M_AXI_RREADY	,	//读数据通道主机准备好信号
		//读写数据控制端口
		input	wire 									write_flag		,	//写操作标志信号	
		input	wire 									read_flag		,	//读操作标志信号
		input	wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_AWADDR_r	,	//写数据地址寄存
		input 	wire	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r	,	//写数据赋值寄存器
		input   wire	[C_M_AXI_DATA_WIDTH - 1 : 0]	M_AXI_ARADDR_r		//读数据地址寄存
	);
	
    /***************计算输入数据的二进制位宽***************/
    function integer bit_wide;
        input integer data_in;
        for(bit_wide = 0;data_in > 0;bit_wide = bit_wide + 1'b1)
              data_in = data_in >> 1;      
    endfunction

	/*********************寄存器信号*********************/
	//
	//写地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_AWADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_AWVALID_r				;	//写地址有效标志寄存
	//写数据操作
	//reg 	[C_M_AXI_DATA_WIDTH - 1 : 0] 	M_AXI_WDATA_r				;	//写数据赋值寄存器
	reg 									M_AXI_WLAST_r 				;	//写数据最后一位标志寄存器
	reg 									M_AXI_WVALID_r				;	//写数据有效标志
	//读地址操作
	//reg 	[C_M_AXI_ADDR_WIDTH - 1 : 0] 	M_AXI_ARADDR_r				;	//写地址赋值寄存
	reg 								 	M_AXI_ARVALID_r				;	//写地址有效标志寄存
	//读数据操作
	reg 									M_AXI_RREADY_r				;	//主机读数据准备好信号

    /************************参数************************/
	//写地址参数的常量
	assign 	M_AXI_AWID			=	'd0									;	//写地址ID,一半不用,设为0
	assign 	M_AXI_AWLEN  		=   C_M_AXI_BURST_LEN					;	//突发长度,连续写数据的个数
	assign 	M_AXI_AWSIZE		=	bit_wide((C_M_AXI_DATA_WIDTH/8)-1)	;   //数据位宽,多少个字节												
	assign 	M_AXI_AWBURST   	=	2'b01								;	//自增模式突发
	assign	M_AXI_AWLOCK		=   1'b0								;   //锁信号无效
	assign 	M_AXI_AWCACHE		=   4'b0010								;   //无缓存模式
	assign  M_AXI_AWPROT    	= 	3'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign 	M_AXI_AWQOS			= 	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign	M_AXI_AWREGION		=	4'b0000								;	//Axi4协议的REGION一般没用,默认4位0值
	assign 	M_AXI_AWUSER		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)    
	//写地址参数需要控制的量    
	//assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;	//写地址赋值,输出的地址=数据写地址+基址;
	assign	M_AXI_AWADDR 		= 	M_AXI_AWADDR_r						;	//写地址赋值
	assign	M_AXI_AWVALID   	=	M_AXI_AWVALID_r						;	//写地址有效标志赋值

	//写数据参数的常量   
	assign 	M_AXI_WSTRB			= 	{(C_M_AXI_DATA_WIDTH/8){1'b1}}		;	//每8位数据一位掩码,拉高所有掩码,数据有效传输
	assign	M_AXI_WUSER			= 	'd0									;	//没有用户自定义信号,设为全0
   	//写数据需要控制的信号
	assign	M_AXI_WDATA 		= 	M_AXI_WDATA_r 						;	//写数据赋值
	assign	M_AXI_WLAST 		= 	M_AXI_WLAST_r & M_AXI_WREADY		; 	//最后一个写数据标志信号赋值
	assign	M_AXI_WVALID		= 	M_AXI_WVALID_r						; 	//写数据有效标志赋值

	//写响应参数的常量
	assign	M_AXI_BREADY		= 	1'b1								;	//直接拉高,表示主机一直准备接收从机的写响应信号
	
	//读地址通道参数的常量
	assign	M_AXI_ARID  		=	'd0									;   //读地址ID,一半不用,设为0
	assign	M_AXI_ARLEN    		=	C_M_AXI_BURST_LEN					;	//突发长度,连续读数据的个数
	assign	M_AXI_ARSIZE   		=	bit_wide((C_M_AXI_DATA_WIDTH/8)-1)	;	//数据位宽,多少个字节								
	assign	M_AXI_ARBURST  		=	2'b01								;	//自增模式突发
	assign	M_AXI_ARLOCK   		=	1'b0								;	//锁信号无效
	assign	M_AXI_ARCACHE  		=	4'b0010								;	//无缓存模式
	assign	M_AXI_ARPROT   		=	3'b000								;	//默认保护编码:非特权访问,安全访问,数据存取
	assign	M_AXI_ARQOS    		=	4'b0000								;	//Axi4协议的Qos信号没用,默认4位0值	     
	assign 	M_AXI_ARREGION		= 	4'b0000								;	//Axi4协议的REGION信号没用,默认4位0值	 
	assign	M_AXI_ARUSER   		=	'd0									;	//区域标识符,未用,设置全0,(位宽不定,设置0即可)
	//读地址参数需要控制的量  
	//assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r + C_M_TARGET_SLAVE_BASE_ADDR	;  	//读地址赋值,输出的地址=数据读取地址+基址;
	assign 	M_AXI_ARADDR  		=	M_AXI_ARADDR_r						;	//读地址赋值
	assign 	M_AXI_ARVALID 		=	M_AXI_ARVALID_r						; 	//读地址有效标志赋值

	//读数据通道
	assign	M_AXI_RREADY		= 	M_AXI_RREADY_r						;	//主机准备好从从机读入数据
	//写地址通道:写地址有效标志,写地址
	//写地址有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_AWVALID_r <= 1'b0;
		else if(write_flag)
			M_AXI_AWVALID_r <= 1'b1;
		else if(M_AXI_AWVALID_r&&M_AXI_AWREADY)
			M_AXI_AWVALID_r <= 1'b0;
		else
			M_AXI_AWVALID_r <=M_AXI_AWVALID_r;
	end
	
	//写数据通道:写数据有效标志,写数据,最后一个写数据标志信号
	//写数据有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WVALID_r <= 1'b0;
		else if(M_AXI_AWVALID_r && M_AXI_AWREADY)
			M_AXI_WVALID_r <= 1'b1;
		else if(M_AXI_WLAST_r)
			M_AXI_WVALID_r <= 1'b0;
		else
			M_AXI_WVALID_r <=M_AXI_WVALID_r;
	end
	// //写的数据
	// always@(posedge M_AXI_ACLK)begin
	// 	if(!M_AXI_ARESETN)
	// 		M_AXI_WDATA_r <= 'd0;
	// 	else if(M_AXI_AWVALID_r && M_AXI_AWREADY)	//给第一个数据
	// 		M_AXI_WDATA_r <= 'd11;
	// 	else if((M_AXI_WVALID_r && M_AXI_WREADY) && (!M_AXI_WLAST_r))
	// 		M_AXI_WDATA_r <= M_AXI_WDATA_r+1'b1;
	// 	else 
	// 		M_AXI_WDATA_r <= 'd0;
	// end
	//LAST信号产生计数器
	reg [7:0]	W_LAST_cnt;
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			W_LAST_cnt <= 'd0;
		else if(M_AXI_WVALID_r && M_AXI_WREADY)
			if(W_LAST_cnt == C_M_AXI_BURST_LEN)
				W_LAST_cnt <= 'd0;
			else
				W_LAST_cnt <= W_LAST_cnt + 1'b1;
		else 
			W_LAST_cnt <= W_LAST_cnt;
	end

	//试配所有突发长度的写LAST信号
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WLAST_r <= 1'b0;
		else begin
			if(C_M_AXI_BURST_LEN == 0)					//突发长度为0+1=1,只写一个数据,跟随写数据地址有效且从机写数据地址准备好信号(因为突发长度只能是2的幂次方)
				M_AXI_WLAST_r <= M_AXI_WVALID;
			else if(C_M_AXI_BURST_LEN == 1)				//突发长度为1+1=2,只写2个数据,即写数据有效且从机写数据地址准备好信号
				M_AXI_WLAST_r <= M_AXI_WVALID_r & M_AXI_WREADY;
			else if(W_LAST_cnt == C_M_AXI_BURST_LEN - 1)
				M_AXI_WLAST_r <= 1'b1;
			else
				M_AXI_WLAST_r <= 1'b0;
		end
	end
	//读地址通道:读数据地址有效标志,读数据地址
	//读地址有效标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_ARVALID_r <= 1'b0;
		else if(read_flag)
			M_AXI_ARVALID_r <= 1'b1;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_ARVALID_r <= 1'b0;
		else
			M_AXI_ARVALID_r <=M_AXI_ARVALID_r;
	end
	
	//读数据通道
	//读数据准备好标志
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_RREADY_r <= 1'b0;
		else if(M_AXI_ARVALID_r&&M_AXI_ARREADY)
			M_AXI_RREADY_r <= 1'b1;
		else if(M_AXI_RLAST)
			M_AXI_RREADY_r <= 1'b0;
		else
			M_AXI_RREADY_r <=M_AXI_RREADY_r;
	end

endmodule


4.3仿真axi-slave文件核心代码

`timescale 1 ns / 1 ps

	module AXI_full_slave #
	(
		// Users to add parameters here

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

		// Width of ID for for write address, write data, read address and read data
		parameter integer C_S_AXI_ID_WIDTH	= 1,
		// 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	= 6,
		// Width of optional user defined signal in write address channel
		parameter integer C_S_AXI_AWUSER_WIDTH	= 0,
		// Width of optional user defined signal in read address channel
		parameter integer C_S_AXI_ARUSER_WIDTH	= 0,
		// Width of optional user defined signal in write data channel
		parameter integer C_S_AXI_WUSER_WIDTH	= 0,
		// Width of optional user defined signal in read data channel
		parameter integer C_S_AXI_RUSER_WIDTH	= 0,
		// Width of optional user defined signal in write response channel
		parameter integer C_S_AXI_BUSER_WIDTH	= 0
	)
	(
		// 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 ID
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
		// Write address
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_AWLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_AWSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_AWBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_AWLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_AWCACHE,
		// 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,
		// Quality of Service, QoS identifier sent for each
    // write transaction.
		input wire [3 : 0] S_AXI_AWQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_AWREGION,
		// Optional User-defined signal in the write address channel.
		input wire [C_S_AXI_AWUSER_WIDTH-1 : 0] S_AXI_AWUSER,
		// Write address valid. This signal indicates that
    // the channel is 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
		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 last. This signal indicates the last transfer
    // in a write burst.
		input wire  S_AXI_WLAST,
		// Optional User-defined signal in the write data channel.
		input wire [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
		// 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,
		// Response ID tag. This signal is the ID tag of the
    // write response.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
		// Write response. This signal indicates the status
    // of the write transaction.
		output wire [1 : 0] S_AXI_BRESP,
		// Optional User-defined signal in the write response channel.
		output wire [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
		// 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 ID. This signal is the identification
    // tag for the read address group of signals.
		input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
		// Read address. This signal indicates the initial
    // address of a read burst transaction.
		input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
		// Burst length. The burst length gives the exact number of transfers in a burst
		input wire [7 : 0] S_AXI_ARLEN,
		// Burst size. This signal indicates the size of each transfer in the burst
		input wire [2 : 0] S_AXI_ARSIZE,
		// Burst type. The burst type and the size information, 
    // determine how the address for each transfer within the burst is calculated.
		input wire [1 : 0] S_AXI_ARBURST,
		// Lock type. Provides additional information about the
    // atomic characteristics of the transfer.
		input wire  S_AXI_ARLOCK,
		// Memory type. This signal indicates how transactions
    // are required to progress through a system.
		input wire [3 : 0] S_AXI_ARCACHE,
		// 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,
		// Quality of Service, QoS identifier sent for each
    // read transaction.
		input wire [3 : 0] S_AXI_ARQOS,
		// Region identifier. Permits a single physical interface
    // on a slave to be used for multiple logical interfaces.
		input wire [3 : 0] S_AXI_ARREGION,
		// Optional User-defined signal in the read address channel.
		input wire [C_S_AXI_ARUSER_WIDTH-1 : 0] S_AXI_ARUSER,
		// Write 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 ID tag. This signal is the identification tag
    // for the read data group of signals generated by the slave.
		output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
		// Read Data
		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 last. This signal indicates the last transfer
    // in a read burst.
		output wire  S_AXI_RLAST,
		// Optional User-defined signal in the read address channel.
		output wire [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
		// 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
	);

	// AXI4FULL signals
	reg [C_S_AXI_ADDR_WIDTH-1 : 0] 	axi_awaddr;
	reg  	axi_awready;
	reg  	axi_wready;
	reg [1 : 0] 	axi_bresp;
	reg [C_S_AXI_BUSER_WIDTH-1 : 0] 	axi_buser;
	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_rlast;
	reg [C_S_AXI_RUSER_WIDTH-1 : 0] 	axi_ruser;
	reg  	axi_rvalid;
	// aw_wrap_en determines wrap boundary and enables wrapping
	wire aw_wrap_en;
	// ar_wrap_en determines wrap boundary and enables wrapping
	wire ar_wrap_en;
	// aw_wrap_size is the size of the write transfer, the
	// write address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  aw_wrap_size ; 
	// ar_wrap_size is the size of the read transfer, the
	// read address wraps to a lower address if upper address
	// limit is reached
	wire [31:0]  ar_wrap_size ; 
	// The axi_awv_awr_flag flag marks the presence of write address valid
	reg axi_awv_awr_flag;
	//The axi_arv_arr_flag flag marks the presence of read address valid
	reg axi_arv_arr_flag; 
	// The axi_awlen_cntr internal write address counter to keep track of beats in a burst transaction
	reg [7:0] axi_awlen_cntr;
	//The axi_arlen_cntr internal read address counter to keep track of beats in a burst transaction
	reg [7:0] axi_arlen_cntr;
	reg [1:0] axi_arburst;
	reg [1:0] axi_awburst;
	reg [7:0] axi_arlen;
	reg [7:0] axi_awlen;
	//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 42 bits (n downto 3)

	localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32)+ 1;
	localparam integer OPT_MEM_ADDR_BITS = 3;
	localparam integer USER_NUM_MEM = 1;
	//----------------------------------------------
	//-- Signals for user logic memory space example
	//------------------------------------------------
	wire [OPT_MEM_ADDR_BITS:0] mem_address;
	wire [USER_NUM_MEM-1:0] mem_select;
	reg [C_S_AXI_DATA_WIDTH-1:0] mem_data_out[0 : USER_NUM_MEM-1];

	genvar i;
	genvar j;
	genvar mem_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_BUSER	= axi_buser;
	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_RLAST	= axi_rlast;
	assign S_AXI_RUSER	= axi_ruser;
	assign S_AXI_RVALID	= axi_rvalid;
	assign S_AXI_BID = S_AXI_AWID;
	assign S_AXI_RID = S_AXI_ARID;
	assign  aw_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_awlen)); 
	assign  ar_wrap_size = (C_S_AXI_DATA_WIDTH/8 * (axi_arlen)); 
	assign  aw_wrap_en = ((axi_awaddr & aw_wrap_size) == aw_wrap_size)? 1'b1: 1'b0;
	assign  ar_wrap_en = ((axi_araddr & ar_wrap_size) == ar_wrap_size)? 1'b1: 1'b0;

	// 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;
	      axi_awv_awr_flag <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
	        begin
	          // slave is ready to accept an address and
	          // associated control signals
	          axi_awready <= 1'b1;
	          axi_awv_awr_flag  <= 1'b1; 
	          // used for generation of bresp() and bvalid
	        end
	      else if (S_AXI_WLAST && axi_wready)          
	      // preparing to accept next address after current write burst tx completion
	        begin
	          axi_awv_awr_flag  <= 1'b0;
	        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;
	      axi_awlen_cntr <= 0;
	      axi_awburst <= 0;
	      axi_awlen <= 0;
	    end 
	  else
	    begin    
	      if (~axi_awready && S_AXI_AWVALID && ~axi_awv_awr_flag)
	        begin
	          // address latching 
	          axi_awaddr <= S_AXI_AWADDR[C_S_AXI_ADDR_WIDTH - 1:0];  
	           axi_awburst <= S_AXI_AWBURST; 
	           axi_awlen <= S_AXI_AWLEN;     
	          // start address of transfer
	          axi_awlen_cntr <= 0;
	        end   
	      else if((axi_awlen_cntr <= axi_awlen) && axi_wready && S_AXI_WVALID)        
	        begin

	          axi_awlen_cntr <= axi_awlen_cntr + 1;

	          case (axi_awburst)
	            2'b00: // fixed burst
	            // The write address for all the beats in the transaction are fixed
	              begin
	                axi_awaddr <= axi_awaddr;          
	                //for awsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst
	            // The write address for all the beats in the transaction are increments by awsize
	              begin
	                axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //awaddr aligned to 4 byte boundary
	                axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst
	            // The write address wraps when the address reaches wrap boundary 
	              if (aw_wrap_en)
	                begin
	                  axi_awaddr <= (axi_awaddr - aw_wrap_size); 
	                end
	              else 
	                begin
	                  axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                  axi_awaddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}}; 
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_awaddr <= axi_awaddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1;
	                //for awsize = 4 bytes (010)
	              end
	          endcase              
	        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 && axi_awv_awr_flag)
	        begin
	          // slave can accept the write data
	          axi_wready <= 1'b1;
	        end
	      //else if (~axi_awv_awr_flag)
	      else if (S_AXI_WLAST && axi_wready)
	        begin
	          axi_wready <= 1'b0;
	        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;
	      axi_buser <= 0;
	    end 
	  else
	    begin    
	      if (axi_awv_awr_flag && axi_wready && S_AXI_WVALID && ~axi_bvalid && S_AXI_WLAST )
	        begin
	          axi_bvalid <= 1'b1;
	          axi_bresp  <= 2'b0; 
	          // 'OKAY' response 
	        end                   
	      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_arv_arr_flag <= 1'b0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_awv_awr_flag && ~axi_arv_arr_flag)
	        begin
	          axi_arready <= 1'b1;
	          axi_arv_arr_flag <= 1'b1;
	        end
	      else if (axi_rvalid && S_AXI_RREADY && axi_arlen_cntr == axi_arlen)
	      // preparing to accept next address after current read completion
	        begin
	          axi_arv_arr_flag  <= 1'b0;
	        end
	      else        
	        begin
	          axi_arready <= 1'b0;
	        end
	    end 
	end       
	// Implement axi_araddr latching

	//This process is used to latch the address when both 
	//S_AXI_ARVALID and S_AXI_RVALID are valid. 
	always @( posedge S_AXI_ACLK )
	begin
	  if ( S_AXI_ARESETN == 1'b0 )
	    begin
	      axi_araddr <= 0;
	      axi_arlen_cntr <= 0;
	      axi_arburst <= 0;
	      axi_arlen <= 0;
	      axi_rlast <= 1'b0;
	      axi_ruser <= 0;
	    end 
	  else
	    begin    
	      if (~axi_arready && S_AXI_ARVALID && ~axi_arv_arr_flag)
	        begin
	          // address latching 
	          axi_araddr <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH - 1:0]; 
	          axi_arburst <= S_AXI_ARBURST; 
	          axi_arlen <= S_AXI_ARLEN;     
	          // start address of transfer
	          axi_arlen_cntr <= 0;
	          axi_rlast <= 1'b0;
	        end   
	      else if((axi_arlen_cntr <= axi_arlen) && axi_rvalid && S_AXI_RREADY)        
	        begin
	         
	          axi_arlen_cntr <= axi_arlen_cntr + 1;
	          axi_rlast <= 1'b0;
	        
	          case (axi_arburst)
	            2'b00: // fixed burst
	             // The read address for all the beats in the transaction are fixed
	              begin
	                axi_araddr       <= axi_araddr;        
	                //for arsize = 4 bytes (010)
	              end   
	            2'b01: //incremental burst
	            // The read address for all the beats in the transaction are increments by awsize
	              begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                //for awsize = 4 bytes (010)
	              end   
	            2'b10: //Wrapping burst
	            // The read address wraps when the address reaches wrap boundary 
	              if (ar_wrap_en) 
	                begin
	                  axi_araddr <= (axi_araddr - ar_wrap_size); 
	                end
	              else 
	                begin
	                axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB] + 1; 
	                //araddr aligned to 4 byte boundary
	                axi_araddr[ADDR_LSB-1:0]  <= {ADDR_LSB{1'b0}};   
	                end                      
	            default: //reserved (incremental burst for example)
	              begin
	                axi_araddr <= axi_araddr[C_S_AXI_ADDR_WIDTH - 1:ADDR_LSB]+1;
	                //for arsize = 4 bytes (010)
	              end
	          endcase              
	        end
	      else if((axi_arlen_cntr == axi_arlen) && ~axi_rlast && axi_arv_arr_flag )   
	        begin
	          axi_rlast <= 1'b1;
	        end          
	      else if (S_AXI_RREADY)   
	        begin
	          axi_rlast <= 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_arv_arr_flag && ~axi_rvalid)
	        begin
	          axi_rvalid <= 1'b1;
	          axi_rresp  <= 2'b0; 
	          // 'OKAY' response
	        end   
	      else if (axi_rvalid && S_AXI_RREADY)
	        begin
	          axi_rvalid <= 1'b0;
	        end            
	    end
	end    
	// ------------------------------------------
	// -- Example code to access user logic memory region
	// ------------------------------------------

	generate
	  if (USER_NUM_MEM >= 1)
	    begin
	      assign mem_select  = 1;
	      assign mem_address = (axi_arv_arr_flag? axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:(axi_awv_awr_flag? axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB]:0));
	    end
	endgenerate
	     
	// implement Block RAM(s)
	generate 
	  for(i=0; i<= USER_NUM_MEM-1; i=i+1)
	    begin:BRAM_GEN
	      wire mem_rden;
	      wire mem_wren;
	
	      assign mem_wren = axi_wready && S_AXI_WVALID ;
	
	      assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
	     
	      for(mem_byte_index=0; mem_byte_index<= (C_S_AXI_DATA_WIDTH/8-1); mem_byte_index=mem_byte_index+1)
	      begin:BYTE_BRAM_GEN
	        wire [8-1:0] data_in ;
	        wire [8-1:0] data_out;
	        reg  [8-1:0] byte_ram [0 : 15];
	        integer  j;
	     
	        //assigning 8 bit data
	        assign data_in  = S_AXI_WDATA[(mem_byte_index*8+7) -: 8];
	        assign data_out = byte_ram[mem_address];
	     
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_wren && S_AXI_WSTRB[mem_byte_index])
	            begin
	              byte_ram[mem_address] <= data_in;
	            end   
	        end    
	      
	        always @( posedge S_AXI_ACLK )
	        begin
	          if (mem_rden)
	            begin
	              mem_data_out[i][(mem_byte_index*8+7) -: 8] <= data_out;
	            end   
	        end    
	               
	    end
	  end       
	endgenerate
	//Output register or memory read data

	always @( mem_data_out, axi_rvalid)
	begin
	  if (axi_rvalid) 
	    begin
	      // Read address mux
	      axi_rdata <= mem_data_out[0];
	    end   
	  else
	    begin
	      axi_rdata <= 32'h00000000;
	    end       
	end    

	// Add user logic here

	// User logic ends

	endmodule


4.4 读写逻辑

/读写数据控制模块:写数据产生模块,读数据接收模块
module write_read_data
    #(
        parameter integer   C_M_AXI_BURST_LEN	        = 16            ,           //突发长度
        parameter integer   C_M_AXI_ADDR_WIDTH	        = 32            ,           //数据地址位宽
		parameter integer   C_M_AXI_DATA_WIDTH	        = 32                        //数据位宽
    )
    (
        input                                           M_AXI_ACLK      ,
        input                                           M_AXI_ARESETN   ,
        //读写总开始标志信号
        input   wire                                    WR_START        ,  
        //写数据地址端口
        output  reg                                     write_flag      ,           //写数据开始标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_AWADDR_r  ,           //写的数据首地址
        input                                           M_AXI_AWVALID   ,           //主机写数据地址有效标志
        input                                           M_AXI_AWREADY   ,           //从机写数据地址准备好信号
        //写数据端口
        input                                           M_AXI_WVALID    ,           //主机写数据有效信号       
        input                                           M_AXI_WREADY    ,           //从机写数据准备好信号
        input                                           M_AXI_WLAST     ,           //主机写数据最后一个标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_WDATA_r   ,
        //读数据地址端口
        output  reg                                     read_flag       ,            //读数据开始标志信号
        output  reg [C_M_AXI_DATA_WIDTH - 1 : 0]        M_AXI_ARADDR_r  ,            //读的数据首地址     
        //读数据端口
        input   wire                                    M_AXI_RLAST
    );
    //有限状态机状态
    parameter   STATE_IDLE  =   3'b001;
    parameter   STATE_WRITE =   3'b010;
    parameter   STATE_READ  =   3'b100;
    reg     [2 : 0]   current_state ;
    reg     [2 : 0]   next_state    ;

    //第一段:时序always过程块,格式化地将次态赋值当前状态
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            current_state <= STATE_IDLE;
        else
            current_state <= next_state;
    end
    //第二段:组合always过程块,状态转移条件判断
    always@(*)begin
        case(current_state)
            STATE_IDLE  :begin 
                if(WR_START)
                    next_state = STATE_WRITE;
                else
                    next_state = STATE_IDLE;
            end
            STATE_WRITE :begin
                if(M_AXI_WLAST)
                    next_state = STATE_READ;
                else
                    next_state = STATE_WRITE;
            end
            STATE_READ  :begin
                if(M_AXI_RLAST)
                    next_state = STATE_IDLE;
                else
                    next_state = STATE_READ;
            end
            default:
                next_state = STATE_IDLE;
        endcase
    end
    //第三段:赋值,产生写数据和读数据使能信号
    //写/读操作开始标志
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            write_flag <= 1'b0;
        else if(WR_START)
            write_flag <= 1'b1;
        else
            write_flag <= 1'b0;
    end
    always@(posedge M_AXI_ACLK)begin
        if(!M_AXI_ARESETN)
            read_flag <= 1'b0;
        else if(M_AXI_WLAST)
            read_flag <= 1'b1;
        else
            read_flag <= 1'b0;
    end

    /******************读写操作数据及首地址产生******************/
    //写数据地址:产生首地址
	/*
			实现的功能是向20地址写入数据11~20,起始地址为20
	*/
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_AWADDR_r <= 'd0;
		else if(write_flag)
			M_AXI_AWADDR_r <= 'd20;
		else
			M_AXI_AWADDR_r <= M_AXI_AWADDR_r;
	end
    //写数据产生:
	always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_WDATA_r <= 'd0;
		else if(M_AXI_AWVALID && M_AXI_AWREADY)	//给第一个数据
			M_AXI_WDATA_r <= 'd1;
		else if((M_AXI_WVALID && M_AXI_WREADY) && (!M_AXI_WLAST))
			M_AXI_WDATA_r <= M_AXI_WDATA_r+1'b1;
		else 
			M_AXI_WDATA_r <= M_AXI_WDATA_r;
	end
    //读数据地址:产生首地址
    always@(posedge M_AXI_ACLK)begin
		if(!M_AXI_ARESETN)
			M_AXI_ARADDR_r <= 'd0;
		else if(read_flag)
			M_AXI_ARADDR_r <= 'd20;
		else
			M_AXI_ARADDR_r <= M_AXI_ARADDR_r;
	end

endmodule

4.5 仿真结果

Master写数据时序
在这里插入图片描述
Slave读数据时序
在这里插入图片描述

5 总结

本文详细介绍了AXI总线中的一些信号的定义,写地址通道、读数据通道、写反应通道、读地址通道、读数据通道、以及低功耗接口等所用到信号、通道握手的整个过程,以及猝发式传输机制。通过FPGA上的仿真实现了主-从读写过程验证。为理解AXI总线协议提供了理论和实践结合实例,开发不易珍惜每一分原创和劳动成果,同时注意平时开发过程中的经验积累总结。