AXI_FULL协议详解


前言

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。
在这里插入图片描述
读数据过程
读地址握手成功后,返回数据以及读响应
在这里插入图片描述

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顺子学不会FPGA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值