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总线协议提供了理论和实践结合实例,开发不易珍惜每一分原创和劳动成果,同时注意平时开发过程中的经验积累总结。