FC2カウンター FPGAの部屋 キャラクタROMをAXI4 Lite Slave として実装する6(シミュレーション)
FC2ブログ

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

FPGAの部屋

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

キャラクタROMをAXI4 Lite Slave として実装する6(シミュレーション)

キャラクタROMをAXI4 Lite Slave として実装する5(インプリメント)”の続き。
(2012/06/18:修正)char_rom_axi_lite.v を32ビット幅データバスのアドレスに変更しました。

前回でインプリメントは終了したが、まだchar_rom_axi_lite の単体テストを行ってなかった。今回はchar_rom_axi_lite の単体でのシミュレーションを行う。

・まずは、ISEのプロジェクトを作成して、char_rom_axi_lite.v とchar_gen_rom.v をプロジェクトに加えた。
AXI_Lite_Slave_30_120616.png

・New Source... を使って、char_rom_axi_lite.v のテストベンチchar_rom_axi_lite_tb.v のテンプレートを作成した。

・char_rom_axi_lite_tb.v にVerilog コードを書き足して、テストベンチを完成させた。char_rom_axi_lite_tb.v を下に示す。

`timescale 100ps / 1ps
`default_nettype wire

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   18:53:35 06/14/2012
// Design Name:   char_rom_axi_lite
// Module Name:   H:/HDL/FndtnISEWork/Spartan6/Atlys/test/Atlys_EDK_test_PA/Atlys_EDK_test_PA.srcs/sources_1/edk/system/pcores/char_rom_axi_lite_v1_00_a/char_rom_axi_lite/char_rom_axi_lite_tb.v
// Project Name:  char_rom_axi_lite
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: char_rom_axi_lite
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module char_rom_axi_lite_tb;

    // Inputs
    wire ACLK;
    wire ARESETN;
    reg [31:0] S_AXI_AWADDR = 0;
    reg [2:0] S_AXI_AWPROT = 0;
    reg S_AXI_AWVALID = 0;
    reg [31:0] S_AXI_WDATA = 0;
    reg [3:0] S_AXI_WSTRB = 0;
    reg S_AXI_WVALID = 0;
    reg S_AXI_BREADY = 0;
    reg [31:0] S_AXI_ARADDR = 0;
    reg [2:0] S_AXI_ARPROT = 0;
    reg S_AXI_ARVALID = 0;
    reg S_AXI_RREADY = 0;

    // Outputs
    wire S_AXI_AWREADY;
    wire S_AXI_WREADY;
    wire [1:0] S_AXI_BRESP;
    wire S_AXI_BVALID;
    wire S_AXI_ARREADY;
    wire [31:0] S_AXI_RDATA;
    wire [1:0] S_AXI_RRESP;
    wire S_AXI_RVALID;

    parameter    DELAY = 10;
    
    // Instantiate the Unit Under Test (UUT)
    char_rom_axi_lite uut (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY), 
        .S_AXI_BRESP(S_AXI_BRESP), 
        .S_AXI_BVALID(S_AXI_BVALID), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY), 
        .S_AXI_RDATA(S_AXI_RDATA), 
        .S_AXI_RRESP(S_AXI_RRESP), 
        .S_AXI_RVALID(S_AXI_RVALID), 
        .S_AXI_RREADY(S_AXI_RREADY)
    );

    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
     
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );
     
    initial begin
        // Initialize Inputs
        S_AXI_AWADDR = 0;
        S_AXI_AWPROT = 0;
        S_AXI_AWVALID = 0;
        S_AXI_WDATA = 0;
        S_AXI_WSTRB = 0;
        S_AXI_WVALID = 0;
        S_AXI_BREADY = 0;
        S_AXI_ARADDR = 0;
        S_AXI_ARPROT = 0;
        S_AXI_ARVALID = 0;
        S_AXI_RREADY = 0;

        // Wait Reset rising edge
        @(posedge ARESETN);
        
        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RAC(32'h0000_0100);
        AXI_MASTER_RDC;
        #DELAY;
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_RAC(32'h0000_0180);
        AXI_MASTER_RDC;
        #DELAY;
        AXI_MASTER_RAC(32'h0000_0181);
        @(posedge ACLK);    // 次のクロックへ        
        #DELAY;
        AXI_MASTER_RDC;

    end
    
    // Read Address Channel    
    task AXI_MASTER_RAC;
        input    [31:0]    araddr;
        begin
            S_AXI_ARADDR    = araddr;
            S_AXI_ARVALID     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ

            while (~S_AXI_ARREADY) begin    // S_AXI_ARREADY が1になるまで待つ
                #DELAY;
                @(posedge ACLK);    // 次のクロックへ
            end
            
            #DELAY;
            S_AXI_ARADDR    = 0;
            S_AXI_ARVALID     = 1'b0;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end
    endtask
    
    // Read Data Channel
    task AXI_MASTER_RDC; 
        begin
            S_AXI_RREADY = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            S_AXI_RREADY = 1'b0;
        end
    endtask

endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


そう言えば、char_rom_axi_lite.v も貼ってなかったと思うので、下に示す。

`timescale 1ns/1ps

module char_rom_axi_lite #
    (
    parameter integer C_S_AXI_ADDR_WIDTH            = 32,
    parameter integer C_S_AXI_DATA_WIDTH            = 32
    )
    (
    // System Signals
    input wire ACLK,
    input wire ARESETN,

    // Slave Interface Write Address Ports
    input  wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_AWADDR,
    input  wire [3-1:0]                  S_AXI_AWPROT,
    input  wire                          S_AXI_AWVALID,
    output wire                          S_AXI_AWREADY,

    // Slave Interface Write Data Ports
    input  wire [C_S_AXI_DATA_WIDTH-1:0]   S_AXI_WDATA,
    input  wire [C_S_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
    input  wire                          S_AXI_WVALID,
    output wire                          S_AXI_WREADY,

    // Slave Interface Write Response Ports
    output wire [2-1:0]                 S_AXI_BRESP,
    output wire                         S_AXI_BVALID,
    input  wire                         S_AXI_BREADY,

    // Slave Interface Read Address Ports
    input  wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_ARADDR,
    input  wire [3-1:0]                  S_AXI_ARPROT,
    input  wire                          S_AXI_ARVALID,
    output wire                          S_AXI_ARREADY,

    // Slave Interface Read Data Ports
    output wire [C_S_AXI_DATA_WIDTH-1:0]  S_AXI_RDATA,
    output wire [2-1:0]                 S_AXI_RRESP,
    output wire                         S_AXI_RVALID,
    input  wire                         S_AXI_RREADY

    );

    // RESP の値の定義
    parameter    RESP_OKAY =        2'b00;
    parameter    RESP_EXOKAY =    2'b01;
    parameter    RESP_SLVERR =     2'b10;
    parameter    RESP_DECERR =    2'b11;
    
    parameter    IDLE_RD    =        3'b001,
                AR_DATA_WAIT =    3'b010,
                AR_DATA_VALID =    3'b100;
    reg        [2:0]    rdt_cs;
    
    wire    [7:0]    char_data;
    reg        [31:0]    char_data_1d;
    reg        rvalid;
    
    // char_gen_rom のインスタンス
    char_gen_rom char_gen_rom_inst (
        .clk(ACLK),
        .reset(~ARESETN),
        .char_addr(S_AXI_ARADDR[11:5]),
        .row_addr(S_AXI_ARADDR[4:2]),
        .dout(char_data)
    );
    
    // AXI4 LITEのReadトランザクション用ステートマシン
    always @(posedge ACLK) begin
        if (~ARESETN) begin
            rdt_cs <= IDLE_RD;
            rvalid <= 1'b0;
        end else begin
            case (rdt_cs)
                IDLE_RD :
                    if (S_AXI_ARVALID)
                        rdt_cs <= AR_DATA_WAIT;
                AR_DATA_WAIT : begin
                    rdt_cs <= AR_DATA_VALID;
                    rvalid <= 1'b1;
                end
                AR_DATA_VALID :
                    if (S_AXI_RREADY) begin
                        rdt_cs <= IDLE_RD;
                        rvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign S_AXI_RVALID = rvalid;
    
    always @(posedge ACLK) begin
        if (~ARESETN)
            char_data_1d <= 8'd0;
        else begin
            if (rdt_cs == AR_DATA_WAIT)
                char_data_1d <= {24'd0, char_data};
        end
    end
    assign S_AXI_RDATA = char_data_1d;

    assign S_AXI_ARREADY = 1'b1;
    assign S_AXI_RRESP = RESP_OKAY;
    
    // Writeポートの処理、Writeが間違ってきた時にデッドロックしないように、すべてイネーブルとした
    assign S_AXI_AWREADY = 1'b1;
    assign S_AXI_WREADY = 1'b1;
    assign S_AXI_BRESP = RESP_OKAY;
    assign S_AXI_BVALID = 1'b1;
endmodule


・ISimでシミュレーションを行った。後ろ2つのAXI4 Lite Readトランザクションを下に示す。
AXI_Lite_Slave_31_120616.png

シミュレーションはうまく行ったが、やはり最初にシミュレーションした時にはバグがあった。バグを修正した。
もう一度、PlanAheadで論理合成、インプリメントを行なって、今度はSDKでソフトウェアを作成する。
  1. 2012年06月16日 04:28 |
  2. AX4 Lite Slave IPの作製
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/2172-507e1d29
この記事にトラックバックする(FC2ブログユーザー)