FC2カウンター FPGAの部屋 2013年11月14日
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

AXI4 Master Interfaceモジュールの作製4(axi4_master_inf.v のHDLソース)

AXI4 Master Interfaceモジュールの作製3(シミュレーション2)”の続き。

AXI4 Masterアクセスをする汎用モジュール axi4_master_inf.v を貼っておく。 axi4_master_inf.v の仕様は”AXI4 Master Interfaceモジュールの作製1(仕様の検討)”に詳しく説明してあるので参考のこと。
テストベンチの貼ってある”AXI4 Master Interfaceモジュールの作製2(シミュレーション)”と一緒に見ると、更に動作がわかりやすいと思う。
但し、axi4_master_inf.v を実機動作させたことはないため、実際に動作するかどうかはわからない?もし使った方がいたら、動作したかどうかをコメント欄でお知らせください。よろしくお願い致します。という訳で、当然、動作の保証はありません。。。
いま、ラプラシアン・フィルタのAXI4 Master IPを自力で作っている途中なのだが、そこには、 axi4_master_inf.v を使用しているので、動作するかどうか?わかると思う。

下に、axi4_master_inf.v を貼っておく。
(2013/11/22:スペルミスのため修正)
(2013/11/26:スペルミスと write_data_empty ポートの追加のために修正)
(2013/12/17:read_adfifo の .wr_clk と .wr_rst が間違っていたので修正した)
(2013/12/19:すべてのFIFOの overflow, underflow にアサーションを追加した)
(2014/02/05 : write_rst, read_rst のリセット条件に init_done = 0 の時のリセットを追加)
(2014/08/27:wr_data_csステートマシンのバグフィックス)

`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Create Date:    03:43:28 10/30/2013
// Design Name:
// Module Name:    axi4_master_inf
// write_adffio, read_adfifo へのデータの投入は基本的に2クロックに1回とする
// 2013/11/04
// 2013/11/25 : write_fifo_empty ポートを追加
// 2013/12/18 : すべての FIFO の overflow と underflow に assertion を追加
// 2014/02/05 : write_rst, read_rst のリセット条件に init_done = 0 の時のリセットを追加
// 2014/08/04 : wr_data_csステートマシンのバグフィックス
//////////////////////////////////////////////////////////////////////////////////
module axi4_master_inf #
  (/*autoport*/
        parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8,
        parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
        parameter integer C_M_AXI_ADDR_WIDTH            = 32,
        parameter integer C_M_AXI_DATA_WIDTH            = 64,
        parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
        parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
        parameter integer C_M_AXI_WUSER_WIDTH           = 1,
        parameter integer C_M_AXI_RUSER_WIDTH           = 1,
        parameter integer C_M_AXI_BUSER_WIDTH           = 1,
        parameter [31:0]  C_M_AXI_TARGET                 = 32'h00000000,
        parameter integer C_M_AXI_BURST_LEN             = 256,
        parameter integer C_OFFSET_WIDTH                = 32,

        /* Disabling these parameters will remove any throttling.
        The resulting ERROR flag will not be useful */
        parameter integer C_M_AXI_SUPPORTS_WRITE         = 1,
        parameter integer C_M_AXI_SUPPORTS_READ         = 1
    )
    (
        // System Signals
        input wire           ACLK,
        input wire           ARESETN,

        // Master Interface Write Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_AWID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]          M_AXI_AWADDR,
        output wire [8-1:0]                         M_AXI_AWLEN,
        output wire [3-1:0]                          M_AXI_AWSIZE,
        output wire [2-1:0]                          M_AXI_AWBURST,
        output wire                                  M_AXI_AWLOCK,
        output wire [4-1:0]                          M_AXI_AWCACHE,
        output wire [3-1:0]                          M_AXI_AWPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
        output wire [4-1: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,

        // Master Interface Write Data
        // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
        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,

        // Master Interface Write Response
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_BID,
        input  wire [2-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,

        // Master Interface Read Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_ARID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]          M_AXI_ARADDR,
        output wire [8-1:0]                          M_AXI_ARLEN,
        output wire [3-1:0]                          M_AXI_ARSIZE,
        output wire [2-1:0]                          M_AXI_ARBURST,
        output wire [2-1:0]                          M_AXI_ARLOCK,
        output wire [4-1:0]                          M_AXI_ARCACHE,
        output wire [3-1:0]                          M_AXI_ARPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_ARREGION,
        output wire [4-1: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,

        // Master Interface Read Data
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_RID,
        input  wire [C_M_AXI_DATA_WIDTH-1:0]          M_AXI_RDATA,
        input  wire [2-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,

        // User Ports
        input    wire                                 write_clk,
        input    wire                                 write_rst,

        input    wire                                write_adfifo_wr_ena,
        input    wire    [C_M_AXI_ADDR_WIDTH-1:0]    write_adfifo_addr,
        input    wire    [8-1:0]                        write_adfifo_awlen,
        output    wire                                write_adfifo_full,

        input    wire                                write_fifo_wr_ena,
        input    wire    [C_M_AXI_DATA_WIDTH-1:0]    write_fifo_write_data,
        input    wire    [C_M_AXI_DATA_WIDTH/8-1:0]    write_fifo_wstrb,
        output    wire                                write_fifo_full,
        output    wire                                write_fifo_almost_full,
        output    reg                                    write_fifo_empty,

        input    wire                                 read_clk,
        input    wire                                 read_rst,

        input    wire                                read_adfifo_wr_ena,
        input    wire    [C_M_AXI_ADDR_WIDTH-1:0]    read_adfifo_addr,
        input    wire    [8-1:0]                        read_adfifo_arlen,
        output    wire                                read_adfifo_full,

        input    wire                                 read_fifo_rd_ena,
        output    wire    [C_M_AXI_DATA_WIDTH-1:0]    read_fifo_read_data,
        output    wire                                read_fifo_empty_n,
        output    wire                                read_fifo_almost_empty_n,

        output    reg                                 wr_resp_err,    // AIX4 Write Transaction error
        input    wire                                init_done
    );

    /*autodef*/
    parameter [1:0]    RESP_OKAY =        2'b00,
                    RESP_EXOKAY =    2'b01,
                    RESP_SLVERR =    2'b10,
                    RESP_DECERR =    2'b11;
    wire    wadfifo_overflow, wadfifo_underflow, wadfifo_empty;
    wire     wadfifo_rd_en;
    wire     [39:0]    wadfifo_dout;
    parameter         IDLE_WR_ADDR =         1'b0,
                    AWVALID_ASSERT =    1'b1;
    reg     wr_addr_cs;
    reg     awvalid;
    wire     [7:0]    wadf_outs_dout;
    reg     wadf_outs_wr_en;
    wire     wadf_outs_rd_en;
    wire     wadf_outs_full, wadf_outs_overflow, wadf_outs_underflow;
    wire     wadf_outs_empty;
    wire     wdfifo_rd_en;
    wire     wdfifo_overflow, wdfifo_underflow;
    wire     wdfifo_empty, wdfifo_almost_empty;
    reg     wvalid, wvalid_1d;
    wire    [71:0]    wdfifo_din;
    wire     [71:0]    wdfifo_dout;
    parameter    [1:0]    IDLE_WR_DATA =        2'b00,
                        WLAST_COUNT_LOAD =    2'b01,
                        WVALID_ASSERT =        2'b11,
                        WVALID_DEASSERT =    2'b10;
    reg     [1:0]    wr_data_cs, wr_data_cs_b;
    reg     [8:0]    wr_data_cnt;
    reg     wlast;
    reg     [4:0]    wr_resp_cnt;
    wire     bready;
    parameter    [1:0]    IDLE_WR_RESP =        2'b00,
                        WAIT_BVALID =        2'b01,
                        WR_RESP_ERROR =        2'b11;
    reg     [1:0]    wr_resp_cs;

    wire    radfifo_rd_en, radfifo_overflow, radfifo_underflow, radfifo_empty;
    wire    [39:0]    radfifo_dout;
    parameter     IDLE_RD_ADDR =        1'b0,
                ARVALID_ASSERT =    1'b1;
    reg     rd_addr_cs;
    reg     arvalid;
    reg     radf_outs_wr_en;
    wire     radf_outs_rd_en;
    wire     [7:0]    radf_outs_dout;
    wire     radf_outs_full, radf_outs_empty;
    wire     radf_outs_overflow, radf_outs_underflow;
    wire     [63:0]    rdfifo_din;
    wire    [63:0]    rdfifo_dout;
    wire     rdfifo_wr_en, rdfifo_full, rdfifo_almost_full;
    wire     rdfifo_overflow, rdfifo_underflow;
    wire     rdfifo_empty, rdfifo_almost_empty;
    parameter     IDLE_RD_DATA =    1'b0,
                RREADY_ASSERT =    1'b1;
    reg     rd_data_cs;
    reg     rready;

    reg     reset1, reset2;
    wire     reset;
    reg        write_fifo_empty_1d;
    reg     wr_rst_1d, wr_rst_2d;
    wire    wr_rst;
    reg     rd_rst_1d, rd_rst_2d;
    wire    rd_rst;

    // AXI bus Reset
    always @(posedge ACLK) begin : proc_reset
        reset1 <= ~ARESETN | ~init_done;
        reset2 <= reset1;
    end
    assign reset = reset2;

    // Write Reset
    always @(posedge write_clk) begin : proc_wr_rst
        wr_rst_1d <= write_rst | ~init_done;
        wr_rst_2d <= wr_rst_1d;
    end
    assign wr_rst = wr_rst_2d;

    // Read Reset
     always @(posedge read_clk) begin : proc_rd_rst
        rd_rst_1d <= read_rst | ~init_done;
        rd_rst_2d <= rd_rst_1d;
    end
    assign rd_rst = rd_rst_2d;

    // Write Transaction
    assign M_AXI_AWUSER = 0;
    assign M_AXI_WUSER = 0;

    // AXI4 Master Write Address Transaction
    write_adfifo wadfifo (/*autoinst*/
        .wr_clk(write_clk), // input wr_clk
        .wr_rst(wr_rst), // input wr_rst
        .rd_clk(ACLK), // input rd_clk
        .rd_rst(reset), // input rd_rst
        .din({write_adfifo_awlen, write_adfifo_addr}), // input [39 : 0] din
        .wr_en(write_adfifo_wr_ena), // input wr_en
        .rd_en(wadfifo_rd_en), // input rd_en
        .dout(wadfifo_dout), // output [39 : 0] dout
        .full(write_adfifo_full), // output full
        .overflow(wadfifo_overflow), // output overflow
        .empty(wadfifo_empty), // output empty
        .underflow(wadfifo_underflow) // output underflow
    );

    // write_adfifo assertion
    // synthesis translate_off
    always @ (posedge write_clk) begin
        if (wr_rst)
            ;
        else begin
            if (wadfifo_overflow) begin
                $display("%m: at time %t ERROR : wadfifo_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (wadfifo_underflow) begin
                $display("%m: at time %t ERROR : wadfifo_underflow is asserted.",$time);
                $stop;
            end
        end
    end
   // synthesis translate_on

    // write_adfifo にアドレス、転送長が入ってきたら、AXI4 Master Write Address Transactionを発生させる
    // アドレス転送は2クロックに1回
    // Write Address Transaction State Machine
    always @(posedge ACLK) begin : proc_axi4m_wr_addr_tran
       if(reset) begin
               wr_addr_cs <= IDLE_WR_ADDR;
               awvalid <= 1'b0;
       end else begin
               case (wr_addr_cs)
                   IDLE_WR_ADDR :
                       if (~wadfifo_empty & ~wadf_outs_full) begin
                           wr_addr_cs <= AWVALID_ASSERT;
                           awvalid <= 1'b1;
                       end
                   AWVALID_ASSERT :
                       if (M_AXI_AWREADY) begin
                           wr_addr_cs <= IDLE_WR_ADDR;
                           awvalid <= 1'b0;
                       end
                  default : /* default */;
               endcase
       end
    end
    assign M_AXI_AWVALID = awvalid;

    assign wadfifo_rd_en = (awvalid & M_AXI_AWREADY) ? 1'b1 : 1'b0;

    assign M_AXI_AWID = 0;
    assign M_AXI_AWLEN = wadfifo_dout[39:32];
    assign M_AXI_AWADDR = wadfifo_dout[31:0];
    assign M_AXI_AWSIZE = (C_M_AXI_DATA_WIDTH==64) ? 3'b011 : 3'b010; // 8 or 4
    assign M_AXI_AWBURST = 2'b01; // INCR
    assign M_AXI_AWLOCK = 1'b0;
    assign M_AXI_AWCACHE = 3'b011; // 3, Xilinxの推奨値
    assign M_AXI_AWPROT = 3'd0;
    assign M_AXI_AWQOS = 4'd0;

    // Write Outstanding Address Transaction Fifo(WOATF)
    write_adfifo_outs wadfifo_outs (
        .clk(ACLK), // input clk
        .srst(reset), // input srst
        .din(wadfifo_dout[39:32]), // input [7 : 0] din
        .wr_en(wadf_outs_wr_en), // input wr_en
        .rd_en(wadf_outs_rd_en), // input rd_enwad_outs_
        .dout(wadf_outs_dout), // output [7 : 0] dout
        .full(wadf_outs_full), // output full
        .overflow(wadf_outs_overflow), // output overflow
        .empty(wadf_outs_empty), // output empty
        .underflow(wadf_outs_underflow) // output underflow
    );

    // write_adfifo_outs assertion
    // synthesis translate_off
    always @ (posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (wadf_outs_overflow) begin
                $display("%m: at time %t ERROR : wadf_outs_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (wadf_outs_underflow) begin
                $display("%m: at time %t ERROR : wadf_outs_underflow is asserted.",$time);
                $stop;
            end
        end
    end
   // synthesis translate_on

   assign wadf_outs_rd_en = wvalid & wlast & M_AXI_WREADY;

    // wadfifo_outs のwr_en
    always @(posedge ACLK) begin
        if (reset) begin
            wadf_outs_wr_en <= 1'b0;
        end else begin
            if (wr_addr_cs==IDLE_WR_ADDR && wadfifo_empty==1'b0 && wadf_outs_full==1'b0)
                wadf_outs_wr_en <= 1'b1;
            else begin
                wadf_outs_wr_en <= 1'b0;
            end
        end
    end

    assign wdfifo_din = (C_M_AXI_DATA_WIDTH==64) ? {write_fifo_wstrb, write_fifo_write_data} : {4'd0, write_fifo_wstrb, 32'd0, write_fifo_write_data}; // Write Data Bus Width = 64 or 32

    // write_data_fifo
    write_fifo wdfifo (
        .wr_clk(write_clk), // input wr_clk
        .wr_rst(wr_rst), // input wr_rst
        .rd_clk(ACLK), // input rd_clk
        .rd_rst(reset), // input rd_rst
        .din(wdfifo_din), // input [71 : 0] din
        .wr_en(write_fifo_wr_ena), // input wr_en
        .rd_en(wdfifo_rd_en), // input rd_en
        .dout(wdfifo_dout), // output [71 : 0] dout
        .full(write_fifo_full), // output full
        .almost_full(write_fifo_almost_full), // output almost_full
        .overflow(wdfifo_overflow), // output overflow
        .empty(wdfifo_empty), // output empty
        .almost_empty(wdfifo_almost_empty), // output almost_empty
        .underflow(wdfifo_underflow) // output underflow
    );

    // write_fifo assertion
    // synthesis translate_off
    always @ (posedge write_clk) begin
        if (wr_rst)
            ;
        else begin
            if (wdfifo_overflow) begin
                $display("%m: at time %t ERROR : wdfifo_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (wdfifo_underflow) begin
                $display("%m: at time %t ERROR : wdfifo_underflow is asserted.",$time);
                $stop;
            end
        end
    end
   // synthesis translate_on

    assign wdfifo_rd_en = wvalid & M_AXI_WREADY;

    assign M_AXI_WDATA = (C_M_AXI_DATA_WIDTH == 64) ? wdfifo_dout[63:0] : wdfifo_dout[31:0]; // Write Data Bus Width = 64 or 32
    assign M_AXI_WSTRB = (C_M_AXI_DATA_WIDTH == 64) ? wdfifo_dout[71:64] : wdfifo_dout[67:64]; // Write Data Bus Width = 64 or 32

    // AXI4 Write Data Transaction State Machine
    always @(posedge ACLK) begin : proc_WrDataSM
       if(reset) begin
               wr_data_cs <= IDLE_WR_DATA;
               wvalid <= 1'b0;
       end else begin
           case (wr_data_cs)
               IDLE_WR_DATA :
                   if (~wadf_outs_empty & ~wdfifo_empty) begin
                       wvalid <= 1'b1;
                       if (wadf_outs_dout != 8'd0) begin
                           wr_data_cs <= WLAST_COUNT_LOAD;
                       end else begin
                           wr_data_cs <= WVALID_ASSERT;
                       end
                   end
               WLAST_COUNT_LOAD :
                   if (wdfifo_almost_empty) begin
                        wr_data_cs <= WVALID_DEASSERT;
                        wvalid <= 1'b0;
                   end else begin
                        wr_data_cs <= WVALID_ASSERT;
                   end
               WVALID_ASSERT :
                   if ((M_AXI_WREADY==1'b1 && wr_data_cnt==9'd1) || wr_data_cnt==9'd0) begin
                       wr_data_cs <= IDLE_WR_DATA;
                       wvalid <= 1'b0;
                   end else if (wdfifo_almost_empty) begin    // 次でWrite Data が empty(バースト中)
                       wr_data_cs <= WVALID_DEASSERT;
                       wvalid <= 1'b0;
                   end
               WVALID_DEASSERT :
                   if (~wdfifo_empty) begin    // Write Data がFIFOに入った
                       wr_data_cs <= WVALID_ASSERT;
                       wvalid <= 1'b1;
                   end
           endcase
       end
    end
    assign    M_AXI_WVALID = wvalid;

    // 1クロック前の wvalid
    always @(posedge ACLK) begin : proc_wvalid_1d
       if(~ARESETN) begin
            wvalid_1d <= 1'b0;
       end else begin
            wvalid_1d <= wvalid;
       end
    end

    // 以前の wr_data_cs ステートの値
    always @(posedge ACLK) begin : proc_wr_data_cs_b
       if(~ACLK) begin
            wr_data_cs_b <= IDLE_WR_DATA;
       end else begin
            wr_data_cs_b <= wr_data_cs;
       end
    end

    // wr_data_cnt
    always @(posedge ACLK) begin : proc_wr_data_cnt
       if(reset) begin
            wr_data_cnt <= 9'd0;
       end else begin
            if (wr_data_cs == WLAST_COUNT_LOAD) begin
                if (M_AXI_WREADY)
                    wr_data_cnt <= {1'b0, wadf_outs_dout};
                else
                    wr_data_cnt <= {1'b0, wadf_outs_dout} + 9'd1;
            end else if (wvalid) begin
                if (M_AXI_WREADY && wr_data_cnt!=9'd0)
                    wr_data_cnt <= wr_data_cnt - 9'd1;
            end else if (wr_data_cs == IDLE_WR_DATA)
                wr_data_cnt <= 9'd0;
       end
    end

    // wlast
    always @(posedge ACLK) begin : proc_wlast
       if(reset) begin
            wlast <= 1'b0;
       end else begin
            if (wr_data_cs==IDLE_WR_DATA && wadf_outs_empty==1'b0 && wadf_outs_dout==8'd0) begin // Single Transction
                wlast <= 1'b1;
            end else if (wr_data_cs==WVALID_ASSERT && M_AXI_WREADY==1'b1 && wr_data_cnt==9'd2) begin // Burst Transaction
                wlast <= 1'b1;
            end else if (wr_data_cs==WLAST_COUNT_LOAD && M_AXI_WREADY==1'b1 && wadf_outs_dout==8'd1) begin // Burst length = 2
                wlast <= 1'b1;
            end else if (wvalid==1'b1 && M_AXI_WREADY==1'b1 && (wr_data_cnt==9'd1 || wadf_outs_dout==8'd0)) begin
                wlast <= 1'b0;
            end
       end
    end
    assign M_AXI_WLAST = wlast;

    // Write Response Transaction Counter
    // Write Response Transaction の残り数をカウントする
    always @(posedge ACLK) begin : proc_WrRespTranCount
       if(reset) begin
            wr_resp_cnt <= 5'd0;
       end else begin
               if(wr_data_cs_b==IDLE_WR_DATA && (wr_data_cs==WLAST_COUNT_LOAD || wr_data_cs==WVALID_ASSERT)) begin // Write Data Transaction start
                   if (M_AXI_BVALID & bready) // Write Response Transaction が完了
                       wr_resp_cnt <= wr_resp_cnt;
                   else
                       wr_resp_cnt <= wr_resp_cnt + 5'd1;
               end else if (M_AXI_BVALID & bready) // Write Response Transaction が完了
                   wr_resp_cnt <= wr_resp_cnt - 5'd1;
       end
    end

    // Write Response Transaction State Machine
    assign bready = 1'b1;
    assign M_AXI_BREADY = bready;
    always @(posedge ACLK) begin : proc_WrRespTranSM
       if(reset) begin
            wr_resp_cs <= IDLE_WR_RESP;
            wr_resp_err <= 1'b0;
       end else begin
               case (wr_resp_cs)
                   IDLE_WR_RESP :
                       if (wr_resp_cnt > 5'd0)
                           wr_resp_cs <= WAIT_BVALID;
                   WAIT_BVALID :
                       if (M_AXI_BVALID & bready) begin
                           if (M_AXI_BRESP == RESP_OKAY)
                               wr_resp_cs <= IDLE_WR_RESP;
                           else
                               wr_resp_cs <= WR_RESP_ERROR;
                       end
                   WR_RESP_ERROR : begin
                       wr_resp_err <= 1'b1;
                       wr_resp_cs <= IDLE_WR_RESP;
                   end
               endcase
       end
    end

    // write_fifo_empty
    // write_clk に同期する
    always @(posedge write_clk) begin : proc_write_fifo_empty
       if(wr_rst) begin
            write_fifo_empty_1d <= 1'b1;
            write_fifo_empty <= 1'b1;
       end else begin
            write_fifo_empty_1d <= wdfifo_empty;
            write_fifo_empty <= write_fifo_empty_1d;
       end
    end


    // Read Transaction
    assign M_AXI_ARUSER = 0;

    // AXI4 Address Transaction read_adfifo
    read_adfifo radfifo (/*autoinst*/
        .wr_clk(read_clk), // input wr_clk
        .wr_rst(rd_rst), // input wr_rst
        .rd_clk(ACLK), // input rd_clk
        .rd_rst(reset), // input rd_rst
        .din({read_adfifo_arlen, read_adfifo_addr}), // input [39 : 0] din
        .wr_en(read_adfifo_wr_ena), // input wr_en
        .rd_en(radfifo_rd_en), // input rd_en
        .dout(radfifo_dout), // output [39 : 0] dout
        .full(read_adfifo_full), // output full
        .overflow(radfifo_overflow), // output overflow
        .empty(radfifo_empty), // output empty
        .underflow(radfifo_underflow) // output underflow
    );

    // read_adfifo assertion
    // synthesis translate_off
    always @ (posedge read_clk) begin
        if (rd_rst)
            ;
        else begin
            if (radfifo_overflow) begin
                $display("%m: at time %t ERROR : radfifo_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (radfifo_underflow) begin
                $display("%m: at time %t ERROR : radfifo_underflow is asserted.",$time);
                $stop;
            end
        end
    end
    // synthesis translate_on

    // write_adfifo にアドレス、転送長が入ってきたら、AXI4 Master Read Address Transactionを発生させる
    // アドレス転送は2クロックに1回
    // Read Address Transaction State Machine
    always @(posedge ACLK) begin
        if (reset) begin
            rd_addr_cs <= IDLE_RD_ADDR;
            arvalid <= 1'b0;
       end else begin
               case (rd_addr_cs)
                   IDLE_RD_ADDR :
                       if (~radfifo_empty & ~radf_outs_full) begin
                           rd_addr_cs <= ARVALID_ASSERT;
                           arvalid <= 1'b1;
                       end
                   ARVALID_ASSERT :
                       if (M_AXI_ARREADY) begin
                           rd_addr_cs <= IDLE_RD_ADDR;
                           arvalid <= 1'b0;
                       end
                  default : /* default */;
               endcase
       end
    end
    assign M_AXI_ARVALID = arvalid;

    assign radfifo_rd_en = (arvalid & M_AXI_ARREADY) ? 1'b1 : 1'b0;

    assign M_AXI_ARID = 0;
    assign M_AXI_ARLEN = radfifo_dout[39:32];
    assign M_AXI_ARADDR = radfifo_dout[31:0];
    assign M_AXI_ARSIZE = (C_M_AXI_DATA_WIDTH==64) ? 3'b011 : 3'b010; // 8 or 4
    assign M_AXI_ARBURST = 2'b01; // INCR
    assign M_AXI_ARLOCK = 1'b0;
    assign M_AXI_ARCACHE = 3'b011; // 3, Xilinxの推奨値
    assign M_AXI_ARPROT = 3'd0;
    assign M_AXI_ARQOS = 4'd0;

    // Read Outstanding Address Transaction Fifo(WOATF)
    read_adfifo_outs radfifo_outs (
        .clk(ACLK), // input clk
        .srst(reset), // input srst
        .din(radfifo_dout[39:32]), // input [7 : 0] din
        .wr_en(radf_outs_wr_en), // input wr_en
        .rd_en(radf_outs_rd_en), // input rd_enwad_outs_
        .dout(radf_outs_dout), // output [7 : 0] dout
        .full(radf_outs_full), // output full
        .overflow(radf_outs_overflow), // output overflow
        .empty(radf_outs_empty), // output empty
        .underflow(radf_outs_underflow) // output underflow
    );

    // read_adfifo_outs assertion
    // synthesis translate_off
    always @ (posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (radf_outs_overflow) begin
                $display("%m: at time %t ERROR : radf_outs_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (radf_outs_underflow) begin
                $display("%m: at time %t ERROR : radf_outs_underflow is asserted.",$time);
                $stop;
            end
        end
    end
    // synthesis translate_on

   assign radf_outs_rd_en = rready & M_AXI_RVALID & M_AXI_RLAST;

    // radfifo_outs のwr_en
    always @(posedge ACLK) begin
        if (reset) begin
            radf_outs_wr_en <= 1'b0;
        end else begin
            if (rd_addr_cs==IDLE_RD_ADDR && radfifo_empty==1'b0 && radf_outs_full==1'b0)
                radf_outs_wr_en <= 1'b1;
            else begin
                radf_outs_wr_en <= 1'b0;
            end
        end
    end

    // read_data_fifo
    read_fifo rdfifo (
        .wr_clk(ACLK), // input wr_clk
        .wr_rst(reset), // input wr_rst
        .rd_clk(read_clk), // input rd_clk
        .rd_rst(rd_rst), // input rd_rst
        .din(rdfifo_din), // input [63 : 0] din
        .wr_en(rdfifo_wr_en), // input wr_en
        .rd_en(read_fifo_rd_ena), // input rd_en
        .dout(rdfifo_dout), // output [63 : 0] dout
        .full(rdfifo_full), // output full
        .almost_full(rdfifo_almost_full), // output almost_full
        .overflow(rdfifo_overflow), // output overflow
        .empty(rdfifo_empty), // output empty
        .almost_empty(rdfifo_almost_empty), // output almost_empty
        .underflow(rdfifo_underflow) // output underflow
    );

    // read_fifo assertion
    // synthesis translate_off
    always @ (posedge ACLK) begin
        if (reset)
            ;
        else begin
            if (rdfifo_overflow) begin
                $display("%m: at time %t ERROR : rdfifo_overflow is asserted.",$time);
                $stop;
            end
        end
    end
    always @(posedge read_clk) begin
        if (rd_rst)
            ;
        else begin
            if (rdfifo_underflow) begin
                $display("%m: at time %t ERROR : rdfifo_underflow is asserted.",$time);
                $stop;
            end
        end
    end
    // synthesis translate_on

    assign read_fifo_empty_n = ~rdfifo_empty;
    assign read_fifo_almost_empty_n = ~rdfifo_almost_empty;
    assign rdfifo_wr_en = M_AXI_RVALID & rready;
    assign rdfifo_din = (C_M_AXI_DATA_WIDTH == 64) ? M_AXI_RDATA : {32'd0, M_AXI_RDATA}; // Read Data Bus Width = 64 or 32
    assign read_fifo_read_data = (C_M_AXI_DATA_WIDTH == 64) ? rdfifo_dout : rdfifo_dout[31:0]; // Read Data Bus Width = 64 or 32

    // AXI4 Read Data Transaction State Machine
    always @(posedge ACLK) begin : proc_RdDataSM
       if(reset) begin
            rd_data_cs <= IDLE_RD_DATA;
            rready <= 1'b0;
       end else begin
            case (rd_data_cs)
                IDLE_RD_DATA :
                    if (~radf_outs_empty) begin
                        rready <= 1'b1;
                        rd_data_cs <= RREADY_ASSERT;
                    end
                RREADY_ASSERT :
                    if (M_AXI_RVALID & M_AXI_RLAST) begin
                        rready <= 1'b0;
                        rd_data_cs <= IDLE_RD_DATA;
                    end
            endcase
       end
    end
    assign M_AXI_RREADY = rready;

endmodule

`default_nettype wire

  1. 2013年11月14日 05:26 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0