前言
AXI是ARM AMBA(AdvancedMicrocontroller Bus Architecture,高级微控制器总线架构)的一部分,AXI4是2010年发行的一个AXI版本。主要有三种类型:
• AXI4: 一般用于高性能存储映射需求。
• AXI4-Lite: 一般用于简单的,低吞吐量的存储映射(例如控制与状态寄存器之间的映射)。
• AXI4-Stream: 一般用于高速的数据流。
AXI4-Lite与AXI4的总线逻辑基本是一样的,仅端口数量上有差异(AXI4端口数量更多,对应功能更多),AXI4-Stream与以上两者差别相对大一些。
一、AXI特点
本文参考分析整理总结了AMBA AXI and ACE Protocol Specification文档的AXI总线协议规范部分,错误之处欢迎指出。
AMBA AXI协议支持高性能高频的系统设计,该协议拥有以下优点:
- 适合高带宽和低延迟的设计
- 不需要复杂的桥即可提供高频操作
- 可以满足多种组件的接口需求
- 适合高初始访问延迟的存储器控制器
- 提供互联架构实现的灵活性
- 向后兼容AHB与APB接口
同时,该协议还拥有以下特点: - 分离的地址/控制和数据阶段
- 通过使用字节选通信号的方式支持非对齐数据传输
- 使用突发传输时只需要传输起始地址
- 允许地址信息提前于实际数据传输发送
- 分离的读写数据通道,这可以提供低损耗的DMA
- 支持发出多个未完成的地址
- 支持乱序传输完成
- 允许简单添加寄存器阶段以提供时序收敛
AXI协议同时包含了低功耗操作所需的信号扩展,也包含了AXI4-Lite协议,该协议是AXI4的子集,有着更简单的控制寄存器接口和组件。
二、AXI4通道
1、时钟和复位信号
- AXI的组件都使用相同的时钟信号ACLK。输入信号都在ACLK的上升沿被采样,输出信号的变化都发生在ACLK上升沿之后。
- ARESETn采用低电平复位。需要注意的是ARVALID,AWVALID,WVALID,RVALID,BVALID在复位时必须保证是处于低电平的。
1、写数据
AXI4 在进行数据读写时主要使用通道(channel)方式,这种方式保证了读写可以同步进行。
概念介绍:摘自:https://zhuanlan.zhihu.com/p/469178057
Transaction:一个 AXI Master 启动一个 Transaction 来与一个 AXI Slave 通信,一般情况下 Transaction 在多个通道上进行 Master 与 Slave 之间的信息交换,这一整套的信息交换构成了AXI Transaction。
Burst:是一种根据单个地址完成多个数据项传输的过程,每一个传输的数据项都被称为 Beat(Transfer)。由于只有一个地址传输,突发中每个 Beat (Transfer)的地址都是基于传输类型 (INCR、FIXED或WRAP) 计算得到的。
Beat(Transfer):是AXI突发中的单个数据传输。
简单来说,AXI Transaction就是传输一段数据(AXI burst)所需要的一整套操作,而AXI burst就是待传数据,AXI burst由AXI Beats组成,一个Beat就是一个transfer。
1.2、写地址信号
-
AWID: 写地址ID,给当前发起的写事务起一个标识,进行outstanding、乱序传输、仲裁时使用
-
AWADDR: 写地址,基地址,也就是突发数据的第一个数据地址。注意4KB边界问题,在内存里每4KB为一个区域,在进行突发传输时不可以跨越此边界
-
AWLEN: 突发长度,即需要连续传输多少个数据(Transfer)。
对于突发类型为INCR,即递增的突发模式下,突发长度为1-256,其它模式为1-16,WRAP类型的突发长度仅能取 2, 4, 8, 或者 16,实际突发传输长度为AWLEN+1 ,因为该信号位宽为8,范围为0-255。若要突发256个数据,则应当赋值255。 -
AWSIZE: 每个传输数据(Transfer)的字节Bytes 数。
-
AWBURST: 突发类型
FIXED:固定突发,不管突发多长,每次数据都写入同一个地址。
INCR:递增突发模式,burst 中的每一个 transfer 的地址都是在前一个传输地址的增量上增加一个 transfer 的大小。例如在一个 transfer 的 Bytes = 4 的突发中,每个 transfer 的传输的地址都是前一个地址加 4。地址是以字节为单位的。
WRAP:环绕突发模式类似于递增突发模式。不同的是,如果达到了地址上限,地址会重新回到起始地址。实际上这种方式和数据结构中的用数组构建的循环链表是很类似的。
-
AWLOCK: 原子操作,给0即可,AXI4当中用不到
-
AWCACHE: 缓存类型,针对从机而言,告诉对方当前数据应该如何进行缓存,FPGA当中不需要缓存和buffer,选0b0010,主要针对CPU而言使用
-
AWPROT: 设置访问优先级,FPGA里一般置0
-
AWQOS: 服务质量,给0即可,用不到
-
AWREGIO: 区域标识,一般给0,不太理解其作用
-
AWUSER: 用户自定义信号,一般给0即可
-
AWVALID: 主机数据有效信号
-
AWREADY: 从机准备信号
1.3、写数据过程
WID:和写地址通道含义一致
WSTRB[n:0]:用来指示总线上哪些字节的数据是有效的,WSTRB 的每一个 bit 位对应 WDATA 的每一个字节,即WSTRB[n]对应于WDATA[8n+7:8n]。
WLAST指示当前传输最后一个字节
其他信号很好理解,后续通过代码和波形图理解
1.4、写响应
BRESP[1:0]:定义了突发的类型 2’b00=>OKAY ,2’b01=>EXOKAY , 2’b10=>SLVERR,2’b11=>DECERR。
OKAY:正常访问成功,还可以指示独占访问失败。
EXOKAY:指示独占访问的部分已成功。
SLVERR:主机正常发送但是从机没有正常接收。
DECERR:主机没找到从机。
2、读数据
读数据过程与写数据过程相似,信号名也只是前缀做了更改
3、代码设计以及仿真波形
完整设计RTL代码以及TB代码连接:https://github.com/shun6-6/AXI_FULL_study
AXI主机模块,在编写AXI接口模块的代码时,记得信号名字与官方一致,这样就可以在BD里被自动识别为AXI接口进行连线。
从机模块可以通过VIVADO-tools->creat and package new ip生成
module AXI_Master_Moduel#(
parameter C_M_TARGET_SLAVE_BASE_ADDR = 32'h40000000 ,
parameter integer C_M_AXI_BURST_LEN = 16 ,
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 = 1 ,
parameter integer C_M_AXI_RUSER_WIDTH = 0 ,
parameter integer C_M_AXI_BUSER_WIDTH = 0
)
(
input wire M_AXI_ACLK ,
input wire M_AXI_ARESETN ,
output wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID ,
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 ,
output wire M_AXI_AWLOCK ,
output wire [3 : 0] M_AXI_AWCACHE ,
output wire [2 : 0] M_AXI_AWPROT ,
output wire [3 : 0] M_AXI_AWQOS ,
output wire [C_M_AXI_AWUSER_WIDTH-1 : 0] M_AXI_AWUSER ,
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 ,
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 ,
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 ,
output wire M_AXI_ARLOCK ,
output wire [3 : 0] M_AXI_ARCACHE ,
output wire [2 : 0] M_AXI_ARPROT ,
output wire [3 : 0] M_AXI_ARQOS ,
output wire [C_M_AXI_ARUSER_WIDTH-1 : 0] M_AXI_ARUSER ,
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 ,
input wire [C_M_AXI_RUSER_WIDTH-1 : 0] M_AXI_RUSER ,
input wire M_AXI_RVALID ,
output wire M_AXI_RREADY
);
/***************function**************/
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction
/***************parameter*************/
localparam P_DATA_BYTE = C_M_AXI_DATA_WIDTH/8;
localparam P_M_AXI_SIZE = clogb2((C_M_AXI_DATA_WIDTH/8) - 1);
/***************port******************/
/***************mechine***************/
reg [7 :0] r_st_current ;
reg [7 :0] r_st_next ;
reg [15:0] r_st_cnt ;
localparam P_ST_IDLE = 0 ,
P_ST_WRITE = 1 ,
P_ST_READ = 2 ,
P_ST_CHECK = 3 ,
P_ST_ERR = 4 ;
/***************reg*******************/
reg [C_M_AXI_ID_WIDTH-1 : 0] ro_M_AXI_AWID ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] ro_M_AXI_AWADDR ;
reg [7 : 0] ro_M_AXI_AWLEN ;
reg [2 : 0] ro_M_AXI_AWSIZE ;
reg [1 : 0] ro_M_AXI_AWBURST ;
reg ro_M_AXI_AWLOCK ;
reg [3 : 0] ro_M_AXI_AWCACHE ;
reg [2 : 0] ro_M_AXI_AWPROT ;
reg [3 : 0] ro_M_AXI_AWQOS ;
reg [C_M_AXI_AWUSER_WIDTH-1 : 0] ro_M_AXI_AWUSER ;
reg ro_M_AXI_AWVALID ;
reg [C_M_AXI_DATA_WIDTH-1 : 0] ro_M_AXI_WDATA ;
reg [C_M_AXI_DATA_WIDTH/8-1 : 0] ro_M_AXI_WSTRB ;
reg ro_M_AXI_WLAST ;
reg [C_M_AXI_WUSER_WIDTH-1 : 0] ro_M_AXI_WUSER ;
reg ro_M_AXI_WVALID ;
reg ro_M_AXI_BREADY ;
reg [C_M_AXI_ID_WIDTH-1 : 0] ro_M_AXI_ARID ;
reg [C_M_AXI_ADDR_WIDTH-1 : 0] ro_M_AXI_ARADDR ;
reg [7 : 0] ro_M_AXI_ARLEN ;
reg [2 : 0] ro_M_AXI_ARSIZE ;
reg [1 : 0] ro_M_AXI_ARBURST ;
reg ro_M_AXI_ARLOCK ;
reg [3 : 0] ro_M_AXI_ARCACHE ;
reg [2 : 0] ro_M_AXI_ARPROT ;
reg [3 : 0] ro_M_AXI_ARQOS ;
reg [C_M_AXI_ARUSER_WIDTH-1 : 0] ro_M_AXI_ARUSER ;
reg ro_M_AXI_ARVALID ;
reg ro_M_AXI_RREADY ;
reg [C_M_AXI_DATA_WIDTH-1 : 0] ri_M_AXI_RDATA ;
reg ri_M_AXI_RLAST ;
reg ri_M_AXI_RVALID ;
reg r_check_err ;
reg [15:0] r_write_cnt ;
reg [15:0] r_read_cnt ;
reg r_R_active_1d ;
/***************wire******************/
wire w_AW_active ;
wire w_W_active ;
wire w_B_active ;
wire w_AR_active ;
wire w_R_active ;
/***************component*************/
/***************assign****************/
assign M_AXI_AWID = ro_M_AXI_AWID ;
assign M_AXI_AWADDR = ro_M_AXI_AWADDR ;
assign M_AXI_AWLEN = ro_M_AXI_AWLEN ;
assign M_AXI_AWSIZE = ro_M_AXI_AWSIZE ;
assign M_AXI_AWBURST = ro_M_AXI_AWBURST ;
assign M_AXI_AWLOCK = ro_M_AXI_AWLOCK ;
assign M_AXI_AWCACHE = ro_M_AXI_AWCACHE ;
assign M_AXI_AWPROT = ro_M_AXI_AWPROT ;
assign M_AXI_AWQOS = ro_M_AXI_AWQOS ;
assign M_AXI_AWUSER = ro_M_AXI_AWUSER ;
assign M_AXI_AWVALID = ro_M_AXI_AWVALID ;
assign M_AXI_WDATA = ro_M_AXI_WDATA ;
assign M_AXI_WSTRB = ro_M_AXI_WSTRB ;
assign M_AXI_WLAST = ro_M_AXI_WLAST ;
assign M_AXI_WUSER = ro_M_AXI_WUSER ;
assign M_AXI_WVALID = ro_M_AXI_WVALID ;
assign M_AXI_BREADY = ro_M_AXI_BREADY ;
assign M_AXI_ARID = ro_M_AXI_ARID ;
assign M_AXI_ARADDR = ro_M_AXI_ARADDR ;
assign M_AXI_ARLEN = ro_M_AXI_ARLEN ;
assign M_AXI_ARSIZE = ro_M_AXI_ARSIZE ;
assign M_AXI_ARBURST = ro_M_AXI_ARBURST ;
assign M_AXI_ARLOCK = ro_M_AXI_ARLOCK ;
assign M_AXI_ARCACHE = ro_M_AXI_ARCACHE ;
assign M_AXI_ARPROT = ro_M_AXI_ARPROT ;
assign M_AXI_ARQOS = ro_M_AXI_ARQOS ;
assign M_AXI_ARUSER = ro_M_AXI_ARUSER ;
assign M_AXI_ARVALID = ro_M_AXI_ARVALID ;
assign M_AXI_RREADY = ro_M_AXI_RREADY ;
assign w_AW_active = M_AXI_AWVALID & M_AXI_AWREADY;
assign w_W_active = M_AXI_WVALID & M_AXI_WREADY ;
assign w_B_active = M_AXI_BVALID & M_AXI_BREADY ;
assign w_AR_active = M_AXI_ARVALID & M_AXI_ARREADY;
assign w_R_active = M_AXI_RVALID & M_AXI_RREADY ;
/***************always****************/
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_st_current <= P_ST_IDLE;
else
r_st_current <= r_st_next;
end
always@(*)
begin
case(r_st_current)
P_ST_IDLE : r_st_next = P_ST_WRITE;
P_ST_WRITE : r_st_next = w_B_active ? P_ST_READ : P_ST_WRITE ;
P_ST_READ : r_st_next = ri_M_AXI_RLAST ? P_ST_CHECK : P_ST_READ ;
P_ST_CHECK : r_st_next = r_check_err ? P_ST_ERR : P_ST_IDLE ;
P_ST_ERR : r_st_next = P_ST_ERR;
default : r_st_next = P_ST_IDLE;
endcase
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_st_cnt <= 'd0;
else if(r_st_current != r_st_next)
r_st_cnt <= 'd0;
else
r_st_cnt <= r_st_cnt + 1;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN) begin
ro_M_AXI_AWID <= 'd0;
ro_M_AXI_AWADDR <= 'd0;
ro_M_AXI_AWLEN <= 'd0;
ro_M_AXI_AWSIZE <= 'd0;
ro_M_AXI_AWBURST <= 'd0;
ro_M_AXI_AWLOCK <= 'd0;
ro_M_AXI_AWCACHE <= 'd0;
ro_M_AXI_AWPROT <= 'd0;
ro_M_AXI_AWQOS <= 'd0;
ro_M_AXI_AWUSER <= 'd0;
ro_M_AXI_AWVALID <= 'd0;
end else if(w_AW_active) begin
ro_M_AXI_AWID <= 'd0;
ro_M_AXI_AWADDR <= 'd0;
ro_M_AXI_AWLEN <= 'd0;
ro_M_AXI_AWSIZE <= 'd0;
ro_M_AXI_AWBURST <= 'd0;
ro_M_AXI_AWLOCK <= 'd0;
ro_M_AXI_AWCACHE <= 'd0;
ro_M_AXI_AWPROT <= 'd0;
ro_M_AXI_AWQOS <= 'd0;
ro_M_AXI_AWUSER <= 'd0;
ro_M_AXI_AWVALID <= 'd0;
end else if(r_st_current == P_ST_WRITE && r_st_cnt == 0) begin
ro_M_AXI_AWID <= 'd0;
ro_M_AXI_AWADDR <= C_M_TARGET_SLAVE_BASE_ADDR;
ro_M_AXI_AWLEN <= C_M_AXI_BURST_LEN - 1;
ro_M_AXI_AWSIZE <= P_M_AXI_SIZE;
ro_M_AXI_AWBURST <= 2'b01;
ro_M_AXI_AWLOCK <= 'd0;
ro_M_AXI_AWCACHE <= 4'b0010;
ro_M_AXI_AWPROT <= 'd0;
ro_M_AXI_AWQOS <= 'd0;
ro_M_AXI_AWUSER <= 'd0;
ro_M_AXI_AWVALID <= 'd1;
end else begin
ro_M_AXI_AWID <= ro_M_AXI_AWID ;
ro_M_AXI_AWADDR <= ro_M_AXI_AWADDR ;
ro_M_AXI_AWLEN <= ro_M_AXI_AWLEN ;
ro_M_AXI_AWSIZE <= ro_M_AXI_AWSIZE ;
ro_M_AXI_AWBURST <= ro_M_AXI_AWBURST;
ro_M_AXI_AWLOCK <= ro_M_AXI_AWLOCK ;
ro_M_AXI_AWCACHE <= ro_M_AXI_AWCACHE;
ro_M_AXI_AWPROT <= ro_M_AXI_AWPROT ;
ro_M_AXI_AWQOS <= ro_M_AXI_AWQOS ;
ro_M_AXI_AWUSER <= ro_M_AXI_AWUSER ;
ro_M_AXI_AWVALID <= ro_M_AXI_AWVALID;
end
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN) begin
ro_M_AXI_WDATA <= 'd0;
ro_M_AXI_WUSER <= 'd0;
end else if(ro_M_AXI_WLAST) begin
ro_M_AXI_WDATA <= 'd0;
ro_M_AXI_WUSER <= 'd0;
end else if(w_W_active) begin
ro_M_AXI_WDATA <= ro_M_AXI_WDATA + 1;
ro_M_AXI_WUSER <= 'd0;
end else begin
ro_M_AXI_WDATA <= ro_M_AXI_WDATA;
ro_M_AXI_WUSER <= ro_M_AXI_WUSER;
end
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)begin
ro_M_AXI_WVALID <= 'd0;
ro_M_AXI_WSTRB <= {P_DATA_BYTE{1'b0}};
end
else if(ro_M_AXI_WLAST)begin
ro_M_AXI_WVALID <= 'd0;
ro_M_AXI_WSTRB <= 'd0;
end
else if(w_AW_active)begin
ro_M_AXI_WVALID <= 'd1;
ro_M_AXI_WSTRB <= {P_DATA_BYTE{1'b1}};
end
else begin
ro_M_AXI_WVALID <= ro_M_AXI_WVALID;
ro_M_AXI_WSTRB <= ro_M_AXI_WSTRB;
end
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_write_cnt <= 'd0;
else if(ro_M_AXI_WLAST && w_W_active)
r_write_cnt <= 'd0;
else if(w_W_active)
r_write_cnt <= r_write_cnt + 1;
else
r_write_cnt <= r_write_cnt;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
ro_M_AXI_WLAST <= 'd0;
else if(r_write_cnt == C_M_AXI_BURST_LEN - 1 && w_W_active)
ro_M_AXI_WLAST <= 'd0;
else if(r_write_cnt == C_M_AXI_BURST_LEN - 2)
ro_M_AXI_WLAST <= 'd1;
else
ro_M_AXI_WLAST <= ro_M_AXI_WLAST;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
ro_M_AXI_BREADY <= 'd0;
else if(w_B_active)
ro_M_AXI_BREADY <= 'd0;
else if(ro_M_AXI_WLAST)
ro_M_AXI_BREADY <= 'd1;
else
ro_M_AXI_BREADY <= ro_M_AXI_BREADY;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN) begin
ro_M_AXI_ARID <= 'd0;
ro_M_AXI_ARADDR <= 'd0;
ro_M_AXI_ARLEN <= 'd0;
ro_M_AXI_ARSIZE <= 'd0;
ro_M_AXI_ARBURST <= 'd0;
ro_M_AXI_ARLOCK <= 'd0;
ro_M_AXI_ARCACHE <= 'd0;
ro_M_AXI_ARPROT <= 'd0;
ro_M_AXI_ARQOS <= 'd0;
ro_M_AXI_ARUSER <= 'd0;
ro_M_AXI_ARVALID <= 'd0;
end else if(w_AR_active) begin
ro_M_AXI_ARID <= 'd0;
ro_M_AXI_ARADDR <= 'd0;
ro_M_AXI_ARLEN <= 'd0;
ro_M_AXI_ARSIZE <= 'd0;
ro_M_AXI_ARBURST <= 'd0;
ro_M_AXI_ARLOCK <= 'd0;
ro_M_AXI_ARCACHE <= 'd0;
ro_M_AXI_ARPROT <= 'd0;
ro_M_AXI_ARQOS <= 'd0;
ro_M_AXI_ARUSER <= 'd0;
ro_M_AXI_ARVALID <= 'd0;
end else if(r_st_current == P_ST_READ && r_st_cnt == 0) begin
ro_M_AXI_ARID <= 'd0;
ro_M_AXI_ARADDR <= C_M_TARGET_SLAVE_BASE_ADDR;
ro_M_AXI_ARLEN <= C_M_AXI_BURST_LEN - 1;
ro_M_AXI_ARSIZE <= P_M_AXI_SIZE;
ro_M_AXI_ARBURST <= 2'b01;
ro_M_AXI_ARLOCK <= 'd0;
ro_M_AXI_ARCACHE <= 4'b0010;
ro_M_AXI_ARPROT <= 'd0;
ro_M_AXI_ARQOS <= 'd0;
ro_M_AXI_ARUSER <= 'd0;
ro_M_AXI_ARVALID <= 'd1;
end else begin
ro_M_AXI_ARID <= ro_M_AXI_ARID ;
ro_M_AXI_ARADDR <= ro_M_AXI_ARADDR ;
ro_M_AXI_ARLEN <= ro_M_AXI_ARLEN ;
ro_M_AXI_ARSIZE <= ro_M_AXI_ARSIZE ;
ro_M_AXI_ARBURST <= ro_M_AXI_ARBURST;
ro_M_AXI_ARLOCK <= ro_M_AXI_ARLOCK ;
ro_M_AXI_ARCACHE <= ro_M_AXI_ARCACHE;
ro_M_AXI_ARPROT <= ro_M_AXI_ARPROT ;
ro_M_AXI_ARQOS <= ro_M_AXI_ARQOS ;
ro_M_AXI_ARUSER <= ro_M_AXI_ARUSER ;
ro_M_AXI_ARVALID <= ro_M_AXI_ARVALID;
end
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
ro_M_AXI_RREADY <= 'd0;
else if(M_AXI_RLAST)
ro_M_AXI_RREADY <= 'd0;
else if(w_AR_active)
ro_M_AXI_RREADY <= 'd1;
else
ro_M_AXI_RREADY <= ro_M_AXI_RREADY;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_R_active_1d <= 'd0;
else
r_R_active_1d <= w_R_active;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_read_cnt <= 'd0;
else if(ri_M_AXI_RLAST)
r_read_cnt <= 'd0;
else if(r_R_active_1d)
r_read_cnt <= r_read_cnt + 1;
else
r_read_cnt <= r_read_cnt;
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN) begin
ri_M_AXI_RDATA <= 'd0;
ri_M_AXI_RLAST <= 'd0;
ri_M_AXI_RVALID <= 'd0;
end else if(w_R_active) begin
ri_M_AXI_RDATA <= M_AXI_RDATA;
ri_M_AXI_RLAST <= M_AXI_RLAST;
ri_M_AXI_RVALID <= M_AXI_RVALID;
end else begin
ri_M_AXI_RDATA <= 'd0;
ri_M_AXI_RLAST <= 'd0;
ri_M_AXI_RVALID <= 'd0;
end
end
always@(posedge M_AXI_ACLK,negedge M_AXI_ARESETN)
begin
if(!M_AXI_ARESETN)
r_check_err <= 'd0;
else if(ri_M_AXI_RVALID && ri_M_AXI_RDATA != r_read_cnt)
r_check_err <= 'd1;
else
r_check_err <= r_check_err;
end
endmodule
仿真波形:
写地址握手成功后开启写数据,写入0-15这16个数据
写数据结束后,响应通道返回写响应00,表示写数据OK。
读数据过程
读地址握手成功后,返回数据以及读响应