FPGAによりAXI4バスの読み書きを実現

1. AXI4 インターフェイスの説明

通路側

信号

ソース

信号の説明

グローバルシグナル

アクック

ザ・ホスト

世界時計

設定されています

ザ・ホスト

グローバル リセット、アクティブ ロー

ライトチャネルアドレスと制御信号チャネル

M_AXI_WR_awid[3:0]

ザ・ホスト

書き込み信号のセットをマークするために使用される書き込みアドレス ID

M_AXI_WR_awaddr[31:0]

ザ・ホスト

書き込みアドレス。書き込みバースト転送の書き込みアドレスを指定します。

M_AXI_WR_awlen[7:0]

ザ・ホスト

バースト長、バースト転送数を表す

M_AXI_WR_awsize[2:0]

ザ・ホスト

バースト サイズ。バーストごとに転送されるバイト数を示します。

M_AXI_WR_awburst[1:0]

ザ・ホスト

バーストタイプ

M_AXI_WR_awlock

ザ・ホスト

操作のアトミック性を提供するバス ロック信号

M_AXI_WR_awcache[3:0]

ザ・ホスト

メモリ タイプ。転送がシステムをどのように通過するかを示します。

M_AXI_WR_awprot[2:0]

ザ・ホスト

保護タイプ。送信の特権レベルとセキュリティ レベルを示します。

M_AXI_WR_awqos[3:0]

ザ・ホスト

QoS

M_AXI_WR_awvalid

ザ・ホスト

有効信号。このチャネルのアドレス制御信号が有効であることを示します。

M_AXI_WR_awready

スレーブ

「スレーブ」がアドレスと対応する制御信号を受信できることを示します

書き込みチャネル データチャネル

M_AXI_WR_wdata[63:0]

ザ・ホスト

データの書き込み

M_AXI_WR_wstrb[7:0]

ザ・ホスト

書き込みデータ有効バイト ライン。どの 8 ビット データが有効であるかを示すために使用されます。

M_AXI_WR_wlast

ザ・ホスト

この転送が最後のバースト転送であることを示します

M_AXI_WR_wvalid

ザ・ホスト

Writing is valid 書き込みが有効であることを示します

M_AXI_WR_wready

スレーブ

スレーブが書き込みデータを受信できることを示します

書き込みチャネル応答チャネル

M_AXI_WR_bid[3:0]

スレーブ

書き込み応答IDタグ

M_AXI_WR_bresp[1:0]

スレーブ

書き込み応答。書き込み転送のステータスを示します。

M_AXI_WR_b有効

スレーブ

書き込み応答有効

M_AXI_WR_bready

ザ・ホスト

ホストが書き込み応答を受信できることを示します

リードチャネルアドレスと制御信号チャネル

M_AXI_RD_arid[3:0]

ザ・ホスト

一連の書き込み信号をマークするために使用される読み取りアドレス ID

M_AXI_RD_araddr[31:0]

ザ・ホスト

読み取りアドレス。書き込みバースト転送の読み取りアドレスを指定します。

M_AXI_RD_arlen[7:0]

ザ・ホスト

バースト長、バースト転送数を表す

M_AXI_RD_arsize[2:0]

ザ・ホスト

バースト サイズ。バーストごとに転送されるバイト数を示します。

M_AXI_RD_arburst[1:0]

ザ・ホスト

バーストタイプ

M_AXI_RD_arlock[1:0]

ザ・ホスト

操作のアトミック性を提供するバス ロック信号

M_AXI_RD_arcache[3:0]

ザ・ホスト

メモリ タイプ。転送がシステムをどのように通過するかを示します。

M_AXI_RD_arprot[2:0]

ザ・ホスト

保護タイプ。送信の特権レベルとセキュリティ レベルを示します。

M_AXI_RD_arqos[3:0]

ザ・ホスト

サービス品質 QOS

M_AXI_RD_arvalid

ザ・ホスト

有効信号。このチャネルのアドレス制御信号が有効であることを示します。

M_AXI_RD_arready

スレーブ

「スレーブ」がアドレスと対応する制御信号を受信できることを示します

リードチャネル データチャネル

M_AXI_RD_rid[3:0]

スレーブ

IDタグを読み取る

M_AXI_RD_rdata[63:0]

スレーブ

読み取りデータ

M_AXI_RD_rresp[1:0]

スレーブ

読み取り転送のステータスを示す読み取り応答

M_AXI_RD_rlast

スレーブ

読み取りバーストの最後の転送を示します

M_AXI_RD_rvalid

スレーブ

チャンネル信号が有効であることを示します

M_AXI_RD_rready

ザ・ホスト

ホストが読み取りデータと応答情報を受信できることを示します

2. アドレスチャネルの制御信号とアドレス記述

1. アドレスID

AWID[3:0] および ARID[3:0]: マスター スレーブ デバイスが 1 つだけの場合、この値は任意の値に設定できます。

2. アドレス構造

AWADDR[31:0] および ARADDR[31:0]: AXI プロトコルはバースト (バースト) に基づいており、ホストはバースト送信の最初のバイトのアドレスのみを提供し、スレーブはバースト送信アドレスの後続のバイトを計算する必要があります。 。バースト送信は 4KB 境界を越えることはできません (バーストが 2 つのスレーブ間の境界を越えるのを防ぎ、またスレーブがサポートする必要があるアドレス増分の数を制限するため)

3. バースト長

AWLEN[7:0] および ARLEN[7:0]: ARLEN[7:0] は読み取り転送のバースト長を決定し、AWLEN[7:0] は書き込み転送のバースト長を決定します。AXI4 拡張バースト長は、1 ~ 256 回の送信の INCR バースト タイプをサポートします。他のタイプの送信では、1 ~ 16 回のバースト送信が維持されます (Burst_Length=AxLEN[7:0]+1)。

4. バーストサイズ

ARSIZE[2:0]、読み取りバースト転送、AWSIZE[2:0]、書き込みバースト転送。

軸サイズ[2: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、突发类型

AWBURST[1:0]与ARBURST[1:0]:

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

2、WLAST与RLAST

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

3、burst[1:0]

描述读写相应结构

burst[1: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

おすすめ

転載: blog.csdn.net/QUACK_G/article/details/125951718