FPGA实现AXI4总线的读写_如何写axi4逻辑

FPGA实现AXI4总线的读写_如何写axi4逻辑

一、AXI4 接口描述

|--------------|-------------------------|----|----------------------------|
| 通道 | 信号 | 源 | 信号描述 |
| 全局信号 | aclk | 主机 | 全局时钟 |
| | aresetn | 主机 | 全局复位,低有效 |
| 写通道地址与控制信号通道 | M_AXI_WR_awid3:0 | 主机 | 写地址ID,用来标志一组写信号 |
| | M_AXI_WR_awaddr31:0 | 主机 | 写地址,给出一次写突发传输的写地址 |
| | M_AXI_WR_awlen7:0 | 主机 | 突发长度,给出突发传输的次数 |
| | M_AXI_WR_awsize2:0 | 主机 | 突发大小,给出每次突发传输的字节数 |
| | M_AXI_WR_awburst1:0 | 主机 | 突发类型 |
| | M_AXI_WR_awlock | 主机 | 总线锁信号,可提供操作的原子性 |
| | M_AXI_WR_awcache3:0 | 主机 | 内存类型,表明一次传输是怎样通过系统的 |
| | M_AXI_WR_awprot2:0 | 主机 | 保护类型,表明一次传输的特权级及安全等级 |
| | M_AXI_WR_awqos3:0 | 主机 | 质量服务QoS |
| | M_AXI_WR_awvalid | 主机 | 有效信号,表明此通道的地址控制信号有效 |
| | M_AXI_WR_awready | 从机 | 表明"从"可以接收地址和对应的控制信号 |
| 写通道数据通道 | M_AXI_WR_wdata63:0 | 主机 | 写数据 |
| | M_AXI_WR_wstrb7:0 | 主机 | 写数据有效的字节线,用来表明哪8bits数据是有效的 |
| | M_AXI_WR_wlast | 主机 | 表明此次传输是最后一个突发传输 |
| | M_AXI_WR_wvalid | 主机 | 写有效,表明此次写有效 |
| | M_AXI_WR_wready | 从机 | 表明从机可以接收写数据 |
| 写通道响应通道 | M_AXI_WR_bid3:0 | 从机 | 写响应ID TAG |
| | M_AXI_WR_bresp1:0 | 从机 | 写响应,表明写传输的状态 |
| | M_AXI_WR_bvalid | 从机 | 写响应有效 |
| | M_AXI_WR_bready | 主机 | 表明主机能够接收写响应 |
| 读通道地址与控制信号通道 | M_AXI_RD_arid3:0 | 主机 | 读地址ID,用来标志一组写信号 |
| | M_AXI_RD_araddr31:0 | 主机 | 读地址,给出一次写突发传输的读地址 |
| | M_AXI_RD_arlen7:0 | 主机 | 突发长度,给出突发传输的次数 |
| | M_AXI_RD_arsize2:0 | 主机 | 突发大小,给出每次突发传输的字节数 |
| | M_AXI_RD_arburst1:0 | 主机 | 突发类型 |
| | M_AXI_RD_arlock1:0 | 主机 | 总线锁信号,可提供操作的原子性 |
| | M_AXI_RD_arcache3:0 | 主机 | 内存类型,表明一次传输是怎样通过系统的 |
| | M_AXI_RD_arprot2:0 | 主机 | 保护类型,表明一次传输的特权级及安全等级 |
| | M_AXI_RD_arqos3:0 | 主机 | 质量服务QOS |
| | M_AXI_RD_arvalid | 主机 | 有效信号,表明此通道的地址控制信号有效 |
| | M_AXI_RD_arready | 从机 | 表明"从"可以接收地址和对应的控制信号 |
| 读通道数据通道 | M_AXI_RD_rid3:0 | 从机 | 读IDtag |
| | M_AXI_RD_rdata63:0 | 从机 | 读数据 |
| | M_AXI_RD_rresp1:0 | 从机 | 读响应,表明读传输的状态 |
| | M_AXI_RD_rlast | 从机 | 表明读突发的最后一次传输 |
| | M_AXI_RD_rvalid | 从机 | 表明此通道信号有效 |
| | M_AXI_RD_rready | 主机 | 表明主机能够接收读数据和响应信息 |

二、地址通道的控制信号与地址描述

1、地址ID

AWID3:0与ARID3:0:对于只有一个主机从机设备,该值可设置为任意

2、地址结构

AWADDR31:0与ARADDR31:0:AXI协议是基于burst(突发)的,主机只给出突发传输的第一个字节的地址,从机必须计算突发传输后续的地址。突发传输不能跨4KB边界(防止突发跨越两个从机的边界,也限制了从机所需支持的地址自增数

3、突发长度

AWLEN7:0与ARLEN7:0:ARLEN7:0决定读传输的突发长度,AWLEN7:0决定写传输的突发长度。AXI4扩展突发长度支持INCR突发类型为1256次传输,对于其他的传输类型依然保持116次突发传输(Burst_Length=AxLEN7:0+1)

4、突发大小

ARSIZE2:0,读突发传输;AWSIZE2:0,写突发传输。

|---------------|--------|
| AxSIZE2:0 | 传输字节大小 |
| 3'b000 | 1 |
| 3'b001 | 2 |
| 3'b010 | 4 |
| 3'b011 | 8 |
| 3'b100 | 16 |
| 3'b101 | 32 |
| 3'b110 | 64 |
| 3'b111 | 128 |

5、突发类型

AWBURST1:0与ARBURST1:0:

|----------------|----------|
| AxBURST1:0 | 突发类型 |
| 2'b00 | FIXED |
| 2'b01 | INCR |
| 2'b10 | WRAP |
| 2'b11 | Reserved |

FIXED:突发传输过程中地址固定,用于FIFO访问

INCR:增量突发,传输过程中,地址递增。增加量取决AxSIZE的值

WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN)

三、数据通道信号描述

1、WDATA与RDATA:写与读数据线信号

WSTRB:有效字节,WSTRBn:0对应于对应的写字节,WSTRBn对应WDATA8n+7:8n,也就是对于的数据宽度的字节数是否有效。WVALID为低时,WSTRB可以为任意值,WVALID为高时,WSTRB为高的字节线必须指示有效的数据。对于一般应用,将WSTRB全部置1即可,保证全部数据有效。读通道无该信号。

2、WLAST与RLAST

写与读最后一个字节,拉高表示传输最后一个字节,也意味着传输结束

3、burst1:0

描述读写相应结构

|--------------|--------|
| burst1:0 | |
| 00 | 常规访问成功 |
| 01 | 独占访问成功 |
| 10 | 从机错误 |
| 11 | 解码错误 |

四、突发写时序:

AXI4突发写可以分为7个状态,写空闲,写通道写地址等待,写通道写地址,写数据等待,写数据循环,接受写应答,写结束这7种状态。之所以划分为7个状态是为了后续写程序的状态机做准备。

7种状态

1、写空闲:等待触发突发信号

2、写通道写地址等待:准备好写地址AWADDR,然后拉高AWVALID。

3、写通道写地址:从机接受到AWVALID,发出AWREADY。

4、写数据等待:准备好数据WDATA,拉高WVALID。

5、写数据循环:从机接受WVALID,确认数据WDATA有效并且接受,发出WREADY,AXI是突发传输:循环该操作到接受到WLAST最后一个数据标志位。

6、接受写应答:接受到从机发出的BVALID,主机发出BREADY。

7、写结束:拉低未拉低的信号,进入写空闲

五、突发读时序

AXI4突发读可以分为6个状态,读空闲,读通道写地址等待,读通道写地址,读数据等待,读数据循环,读结束这6种状态。之所以划分为6个状态是为了后续写程序的状态机做准备。

6种状态

1、读空闲:等待触发突发信号。

2、读通道写地址等待:准备好写地址ARADDR,然后拉高ARVALID。

3、读通道写地址:从机接受到ARVALID,发出ARREADY。

4、读数据等待:从机准备好数据WDATA,从机拉高RVALID。

5、读数据循环:主机接受RVALID,确认数据RDATA有效并且接受,发出RREADY给从机,AXI是突发传输:循环该操作到接受到RLAST最后一个数据标志位

6、读结束:拉低未拉低的信号,进入读空闲

注:

1、读数据必须总是跟在与其数据相关联的地址之后。

2、写响应必须总是跟在与其相关联的写事务的最后出现。

六、写时序状态机

七、写时序代码

复制代码
module axi4_write(
    input               clk             ,
    input               resetn          ,
    input               enable_write    ,  //写使能
    input  [31:0]       w_addr          ,  //地址
    input  [63:0]       w_data          ,  //数据
    output reg          write_done      ,  //写完成
    output reg          write_data      ,  //表示数据写入,突发模式下可用于切换数据的指示信号
    //axi4写通道地址通道
    output  [3:0]       m_axi_awid      , //写地址ID,用来标志一组写信号
    output reg[31:0]    m_axi_awaddr    ,//写地址,给出一次写突发传输的写地址 
    output [7:0]        m_axi_awlen     , //突发长度,给出突发传输的次数 
    output [2:0]        m_axi_awsize    , //突发大小,给出每次突发传输的字节数 
    output [1:0]        m_axi_awburst   , //突发类型 
    output              m_axi_awlock    , //总线锁信号,可提供操作的原子性 
    output [3:0]        m_axi_awcache   , //内存类型,表明一次传输是怎样通过系统的
    output [2:0]        m_axi_awprot    , //保护类型,表明一次传输的特权级及安全等级 
    output [3:0]        m_axi_awqos     , //质量服务QoS
    output reg          m_axi_awvalid   , //有效信号,表明此通道的地址控制信号有效 
    input               m_axi_awready   , //表明"从"可以接收地址和对应的控制信号
    //axi4写通道数据通道
    output reg[63:0]    m_axi_wdata     , //写数据 
    output [7:0]        m_axi_wstrb     , //写数据有效的字节线 
    output reg          m_axi_wlast     , //表明此次传输是最后一个突发传输
    output reg          m_axi_wvalid    , //写有效,表明此次写有效
    input               m_axi_wready    , //表明从机可以接收写数据 
    //axi4写通道应答通道 
    input [3:0]         m_axi_bid       , //写响应ID TAG
    input [1:0]         m_axi_bresp     , //写响应,表明写传输的状态
    input               m_axi_bvalid    , //写响应有效
    output reg          m_axi_bready      //表明主机能够接收写响应
    );

//*******************参数*****************************
    localparam  W_IDLEW     = 3'b001    ; //空闲等待
    localparam  W_DRIVEW    = 3'b011    ; //准备、取地址
    localparam  W_HANDS     = 3'b010    ; //握手
    localparam  W_WSTBR     = 3'b110    ; //突发
    localparam  W_WAIT      = 3'b111    ; //等待结束的信息
    localparam  W_END       = 3'b101    ; //写数据阶段

    parameter   LEN_NUM     = 1         ;
    parameter   AWID        = 0         ;
//*********内部信号******************************
    reg  [2:0]  state ,   next_state   ;
    reg         wready_over            ;
    reg  [7:0]  len                    ;

    assign  m_axi_awid    = AWID[3:0] ;    // [3:0]  //写地址ID,用来标志一组写信号  
    assign  m_axi_awlen   = LEN_NUM-1 ;    // [7:0]  //突发长度,给出突发传输的次数  
    assign  m_axi_awsize  = 3'b011    ;    // [2:0]  //突发大小,给出每次突发传输的字节数  
    assign  m_axi_awburst = 2'b10     ;    // [1:0]  //突发类型  
    assign  m_axi_awlock  = 1'b0      ;    //        //总线锁信号,可提供操作的原子性  
    assign  m_axi_awcache = 4'b0010   ;    // [3:0]  //内存类型,表明一次传输是怎样通过系统的 
    assign  m_axi_awprot  = 3'b000    ;    // [2:0]  //保护类型,表明一次传输的特权级及安全等级 
    assign  m_axi_awqos   = 4'b0000   ;    // [3:0]  //质量服务QoS 
    assign  m_axi_wstrb   = 8'hff     ;

//状态机
    always @(*) begin
        state   =   next_state    ;
    end    


    always @(posedge clk or negedge resetn) begin
        if(!resetn) begin
            wready_over<=0;
        end
        else if(state==W_IDLEW || state==W_END )
            wready_over<=0;
        else if(m_axi_wready)
            wready_over<=1;
    end
   
    always @(posedge clk or negedge resetn) begin
        if(!resetn) begin
            next_state  <=  W_IDLEW   ;
            len <=0 ;
        end
        else case(state)
                W_IDLEW :   if(enable_write) next_state <= W_DRIVEW  ;  else next_state<=W_IDLEW    ;
                W_DRIVEW:   if(m_axi_awready) begin
                                next_state <= W_HANDS ; 
                                len<=LEN_NUM-1          ; 
                            end 
                            else next_state<=W_DRIVEW   ;
                W_HANDS :   if(wready_over && len==0)
                                next_state <= W_WAIT ;  
                            else   if(wready_over ) next_state <= W_WSTBR   ;
                            else next_state<=W_HANDS  ;
                W_WSTBR :   if(len==1)       next_state <= W_WAIT ;  
                            else begin 
                                next_state <= W_WSTBR ;
                                len <=len-1           ;
                            end
                W_WAIT  :   next_state<=W_END ;  
                W_END   :   if(m_axi_bvalid)next_state <= W_IDLEW  ;  else next_state<=W_END    ;
                default :   next_state<=W_IDLEW ;
        endcase   
    end
  // 组合逻辑输出
    always @(* ) begin
        case(state)
            W_IDLEW :   begin
                            m_axi_wlast    =   0        ;
                            m_axi_awaddr   =   0        ;
                            m_axi_awvalid  =   0        ;
                            m_axi_wdata    =   0        ;
                            m_axi_wvalid   =   0        ;
                            m_axi_bready   =   0        ;
                            write_done     =   0        ;
                            write_data     =   0        ;
                    end
            W_DRIVEW:   begin
                            m_axi_wlast    =   0       ;
                            m_axi_awaddr   =   w_addr  ;
                            m_axi_awvalid  =   1       ;
                            m_axi_wdata    =   0       ;
                            m_axi_wvalid   =   0       ;
                            m_axi_bready   =   0       ;
                            write_done     =   0       ;
                            write_data     =   0       ;
                    end
            W_HANDS :   begin
                            m_axi_wlast    =   0       ;
                            m_axi_awaddr   =   0       ;
                            m_axi_awvalid  =   0       ;
                            m_axi_wdata    =   0       ;
                            m_axi_wvalid   =   0       ;
                            m_axi_bready   =   0       ;
                            write_done     =   0       ;
                            write_data     =   0       ;
                    end
            W_WSTBR :   begin
                            m_axi_wlast    =   0       ;
                            m_axi_awaddr   =   0       ;
                            m_axi_awvalid  =   0       ;
                            m_axi_wdata    =   w_data  ;
                            m_axi_wvalid   =   1       ;
                            m_axi_bready   =   0       ;
                            write_done     =   0       ;
                            write_data     =   1       ;
                    end
            W_WAIT  :   begin
                            m_axi_wlast    =   1       ;
                            m_axi_awaddr   =   0       ;
                            m_axi_awvalid  =   0       ;
                            m_axi_wdata    =   w_data  ;
                            m_axi_wvalid   =   1       ;
                            m_axi_bready   =   0       ;
                            write_done     =   1       ;
                            write_data     =   1       ;
                    end
           
            W_END   :   begin
                            m_axi_wlast    =   0       ;
                            m_axi_awaddr   =   0       ;
                            m_axi_awvalid  =   0       ;
                            m_axi_wdata    =   0       ;
                            m_axi_wvalid   =   0       ;
                            m_axi_bready   =   1       ;
                            write_done     =   0       ;
                            write_data     =   0       ;
                    end
            default :   begin
                            m_axi_wlast    =   0   ;
                            m_axi_awaddr   =   0   ;
                            m_axi_awvalid  =   0   ;
                            m_axi_wdata    =   0   ;
                            m_axi_wvalid   =   0   ;
                            m_axi_bready   =   0   ;
                            write_done     =   0   ;
                            write_data     =   0   ;
                    end
        endcase
    end
endmodule

八、读时序状态机

九、读时序代码

复制代码
module axi4_read(
    input               resetn          ,//axi复位 
    input               clk             ,  //axi时钟 
    input               enable_read     ,
    output              read_data       ,
    output              read_done       ,
    input       [31:0]  r_addr          ,
    output  reg [63:0]  r_data          ,
    //axi读通道写地址 
     output     [3:0]   m_axi_arid      , //读地址ID,用来标志一组写信号
     output reg [31:0]  m_axi_araddr    , //读地址,给出一次写突发传输的读地址
     output     [7:0]   m_axi_arlen     , //突发长度,给出突发传输的次数
     output     [2:0]   m_axi_arsize    , //突发大小,给出每次突发传输的字节数
     output     [1:0]   m_axi_arburst   , //突发类型
     output     [1:0]   m_axi_arlock    , //总线锁信号,可提供操作的原子性
     output     [3:0]   m_axi_arcache   , //内存类型,表明一次传输是怎样通过系统的 
     output     [2:0]   m_axi_arprot    , //保护类型,表明一次传输的特权级及安全等级
     output     [3:0]   m_axi_arqos     , //质量服务QOS 
     output reg         m_axi_arvalid   , //有效信号,表明此通道的地址控制信号有效 
     input              m_axi_arready   , //表明"从"可以接收地址和对应的控制信号
     //axi读通道读数据 
     input      [3:0]   m_axi_rid       , //读ID tag 
     input      [63:0]  m_axi_rdata     , //读数据 
     input      [1:0]   m_axi_rresp     , //读响应,表明读传输的状态
     input              m_axi_rlast     , //表明读突发的最后一次传输
     input              m_axi_rvalid    , //表明此通道信号有效 
     output reg         m_axi_rready      //表明主机能够接收读数据和响应信息
    
    );
//
    localparam [2:0] R_IDLER      =  3'b001   ;
    localparam [2:0] R_WAIT       =  3'b011   ;
    localparam [2:0] R_BURST      =  3'b010   ;
    localparam [2:0] R_END        =  3'b110   ;

    parameter  ARID   = 0    ;
    parameter  RD_LEN = 1    ;
//
    reg [2:0] state , next_state    ;
    reg          rvalid_over    ;
//    
    assign m_axi_arid      = ARID[3:0]      ;//地址id 
    assign m_axi_arlen     = RD_LEN-32'd1   ;//突发长度
    assign m_axi_arsize    = 3'b011         ;//表示AXI总线每个数据宽度是8字节,64位 
    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        ;

    assign read_data       =  m_axi_rvalid  ;
    assign read_done       = m_axi_rlast    ;
//axi读状态机
    always @(*) begin
        state   =   next_state  ;
    end
    //
    always @(posedge clk  or negedge resetn) begin
        if(!resetn) begin
            rvalid_over <=0  ;
        end 
        else if(state==R_IDLER) begin
            rvalid_over <=0  ;
        end
        else if(m_axi_rvalid)begin
            rvalid_over <= 1 ;
        end
    end

    always @(posedge clk or negedge resetn) begin
        if(!resetn)
            next_state <= R_IDLER;
        else    case(state)
                    R_IDLER  :  if(enable_read) next_state <= R_WAIT ;else next_state<=R_IDLER   ; 
                    R_WAIT   :  if(m_axi_arready) next_state<=R_BURST  ;else next_state<=R_WAIT  ;  
                    R_BURST  :  if(m_axi_rlast)  next_state<=R_END    ;else next_state  <=  R_BURST ;
                    R_END    :  if(rvalid_over) next_state<=R_IDLER;else next_state<=R_END ;  
                    default  :  next_state<=R_IDLER ;
        endcase
    end
    //
    always @(*) begin
        case(state)
            R_IDLER  :  begin
                            m_axi_araddr  = 0       ;  
                            m_axi_arvalid = 0       ;  
                            m_axi_rready  = 0       ;  
                            r_data        = 0       ;  
                        end 
            R_WAIT   :  begin
                            m_axi_araddr  = r_addr      ;  
                            m_axi_arvalid = 1           ;  
                            m_axi_rready  = 0           ;  
                            r_data        = 0           ;    
                        end             
            R_BURST  :  begin
                            m_axi_araddr  = 0           ;  
                            m_axi_arvalid = 0           ;  
                            m_axi_rready  = 1           ;  
                            r_data        = m_axi_rdata ;      
                        end   
            R_END    :  begin
                            m_axi_araddr  = 0           ;  
                            m_axi_arvalid = 0           ;  
                            m_axi_rready  = 1           ;  
                            r_data        = 0           ;     
                        end 
            default  :  begin
                            m_axi_araddr  = 0           ;  
                            m_axi_arvalid = 0           ;  
                            m_axi_rready  = 0           ;  
                            r_data        = 0           ;     
                        end 
        endcase
    end

endmodule
相关推荐
Hello-FPGA17 小时前
基于RFSOC FPGA ZCU216 的CoaXPress 采集demo
fpga开发
9527华安18 小时前
FPGA基于ADV7182解码PAL视频,Video Processing Subsystem去隔行,提供6套工程源码和技术支持
fpga开发·音视频·pal·adv7182
hahaha601619 小时前
数字图像时域滤波或者3D降噪算法FPGA实现
算法·计算机视觉·fpga开发
GateWorld19 小时前
Xilinx 7系列FPGA时钟网络详解
fpga开发·时钟网络·xilinx 7系列
szxinmai主板定制专家1 天前
X86 工控机 vs RK3588 异构主控:AMR 控制器 BOM、散热、长期运维对比
运维·stm32·单片机·嵌入式硬件·fpga开发·am62x
szxinmai主板定制专家2 天前
AMR 项目落地:机器人控制器硬件定制化需求复盘
arm开发·单片机·fpga开发·系统架构·机器人·am62x
FPGA小迷弟3 天前
FPGA 与卫星:从星载硬件到在轨智能的完整技术解析
fpga开发·架构·fpga·1024程序员节·无线电
NamoAmitabha1283 天前
CPU 内部结构是什么?---deepseek
fpga开发
abc light3 天前
ARM 裸机开发(6)——时钟树与定时器
arm开发·单片机·fpga开发
156082072193 天前
JFMZQ28DR、JFMZQ68DR、RFsoc XCZU47DR、XCZU48DR 信号处理板
fpga开发·信号处理