FC2カウンター FPGAの部屋 2024年03月09日
fc2ブログ

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

FPGAの部屋

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

fifo8 IP の作成3

fifo8 IP の作成2”の続き。

8 深度の FIFO を SystemVerilog で書いてみることにしたということで、前回は、Icarus Verilog でシミュレーションを行った。今回は、バグがないかどうか?不安になり、テストベンチにアサーションを入れたところ、バグが分かった。バグを修正し、シミュレーションを行った。

バグがないかどうか?不安になり、テストベンチにアサーションを入れた。
アサーションは SystemVerilog の queue 型配列で実装した。なお、”SystemVerilogで遊ぼう! - 03. queue型配列”を参照させていただいた。

    task fifo_input;
        forever begin
            @(posedge clk);
            #15;
            if(~reset & wr_ena & ~full)
                array.push_back(in_data);
        end
    endtask
     initial begin
        #10 fork
            fifo_input;
        join_none
    end
   
    task fifo_val_check;
        integer fdata;

        forever begin
            @(posedge clk);
            #15;
            if(~reset & rd_ena & ~empty) begin
                fdata = array.pop_front();
                if(out_data != fdata) begin
                    $display("time = %t, out_data = %d, array = %d", $realtime, out_data, fdata);
                end
            end
        end
    endtask
     initial begin
        #10 fork
            fifo_val_check;
        join_none
    end


それで、Icarus Verilog でシミュレーションを行ったところ、エラーが発生した。
iverilog -o fifo8 fifo8*.sv -g 2012
vvp fifo8

fifo8_25_240309.png

Valid[7:0] の振る舞いの表を修正した。
fifo8_26_240309.png
fifo8_27_240309.png
fifo8_28_240309.png

fifo8.sv と fifo8_tb.sv を修正した。

Icarus Verilog でシミュレーションを行う。
iverilog -o fifo8 fifo8*.sv -g 2012
vvp fifo8

fifo8_29_240309.png

GTKWave を起動して、VCD ファイルを開いた。
gtkwave &
なお、indata[23:0] と out_data[23:0] の Data Format は Decimal に変更してある。
fifo8_30_240309.png

値が見えないので、拡大した。
fifo8_31_240309.png
fifo8_32_240309.png

fifo8.sv を貼っておく。

// fifo8.sv
// 2024/02/29 by marsee
// 8 entries fifo
// 2024/03/09 : Added assertions and fixed bugs

module fifo8 #(
    parameter data_width = 24
)(
    input   logic   clk,
    input   logic   reset,
    input   logic   [data_width-1:0]in_data,
    input   logic   wr_ena,
    output  logic   full,
    output  logic   [data_width-1:0]out_data,
    input   logic   rd_ena,
    output  logic   empty
);
    reg [data_width-1:0] ff[7:0];
    reg [7:0] valid;
    integer valid_po;

    always_ff @(posedge clk) begin : FF_OP
        integer i;

        if(reset) begin
            for(i=7; i>0; i=i-1) begin
                ff[i] <= 0;
            end
        end else begin
            for(i=7; i>1; i=i-1) begin
                if(full==1'b0 && wr_ena==1'b1) begin
                    ff[i-1] <= ff[i];
                end
            end
            if(full==1'b0 && wr_ena==1'b1) begin
                ff[7] <= in_data;
            end
        end
    end

    always_comb begin
        if(valid == 8'd0)
            valid_po = 8;
        else if(valid == 8'h80)
            valid_po = 7;
        else if(valid == 8'h01)
            valid_po = 8;
        else if(valid == 8'h81)
            valid_po = 7;
        else if(valid == 8'hc1)
            valid_po = 6;
        else if(valid == 8'he1)
            valid_po = 5;
        else if(valid == 8'hf1)
            valid_po = 4;
        else if(valid == 8'hf9)
            valid_po = 3;
        else if(valid == 8'hfd)
            valid_po = 2;
        else if(valid == 8'hff)
            valid_po = 1;
         else
             valid_po = 8;
    end
    
    always_ff @(posedge clk) begin
        if(reset) begin
            ff[0] <= 0;
        end else if(valid_po != 8 & rd_ena) begin
            ff[0] <= ff[valid_po];
        end else if(valid == 8'h80)
            ff[0] <= ff[valid_po];
    end
    assign out_data = ff[0];
    
    always_ff @(posedge clk) begin
        integer  i;

        if(reset) begin
            for(i=7; i>=0; i=i-1) begin
                valid[i] <= 0;
            end
            full <= 1'b0;
        end else begin
            if(wr_ena & valid==8'd0) begin
                valid[7] <= 1'b1;
            end else if(valid == 8'h80) begin // valid[7]のみが1の場合
                if(~wr_ena & ~rd_ena) begin
                    valid[7] <= 1'b0;
                    valid[0] <= 1'b1;
                end else if(wr_ena & ~rd_ena)
                    valid[0] <= 1'b1;
                else if(wr_ena & rd_ena) begin
                    valid[0] <= 1'b1;
                end
            end else if(valid == 8'h01) begin // Valid[0]のみが1の場合
                if(~wr_ena & rd_ena)
                    valid[0] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[7] <= 1'b1;
                else if(wr_ena & rd_ena) begin
                    valid[7] <= 1'b1;
                    valid[0] <= 1'b0;
                end
            end else if(valid == 8'h81) begin // valid[7], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[7] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[6] <= 1'b1;
            end else if(valid == 8'hc1) begin // valid[7], valid[6], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[6] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[5] <= 1'b1;
            end else if(valid == 8'he1) begin // valid[7], valid[6], valid[5], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[5] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[4] <= 1'b1;
            end else if(valid == 8'hf1) begin // valid[7], valid[6], valid[5], valid[4], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[4] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[3] <= 1'b1;
            end else if(valid == 8'hf9) begin // valid[7], valid[6], valid[5], valid[4], valid[3], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[3] <= 1'b0;
                else if(wr_ena & ~rd_ena)
                    valid[2] <= 1'b1;
            end else if(valid == 8'hfd) begin // valid[7], valid[6], valid[5], valid[4], valid[3], valid[2], valid[0]が1の場合
                if(~wr_ena & rd_ena)
                    valid[2] <= 1'b0;
                else if(wr_ena & ~rd_ena) begin
                    valid[1] <= 1'b1;
                    full <= 1'b1;
                end
            end else if(valid == 8'hff) begin // Valid[7:0]がすべて1の場合
                if(rd_ena) begin
                    valid[1] <= 1'b0;
                    full <= 1'b0;
                end
            end
        end
    end

    assign empty = ~valid[0];

// the "macro" to dump signals
`ifdef COCOTB_SIM
initial begin
  $dumpfile ("fifo2.vcd");
  $dumpvars (0, fifo8);
  #1;
end
`endif

endmodule


テストベンチの fifo8_tb.sv を貼っておく。

// fifo8_tb.sv
// 2024/02/29 by marsee
// 2024/03/09 : Added assertions and fixed bugs

`timescale 1ns / 1ns

module fifo8_tb;
    parameter data_width = 24;

    logic   clk;
    logic   reset;
    logic   [data_width-1:0]in_data;
    logic   wr_ena;
    logic   full;
    logic   [data_width-1:0]out_data;
    logic   rd_ena;
    logic   empty;
    integer i;
    int array[$];

    task gen_clk;
        forever begin
            #10 clk = ~clk; // 10 単位時間ごとに反転
        end
    endtask
    initial begin
        #10 fork
            gen_clk;
        join_none
    end

    task fifo_input;
        forever begin
            @(posedge clk);
            #15;
            if(~reset & wr_ena & ~full)
                array.push_back(in_data);
        end
    endtask
     initial begin
        #10 fork
            fifo_input;
        join_none
    end
   
    task fifo_val_check;
        integer fdata;

        forever begin
            @(posedge clk);
            #15;
            if(~reset & rd_ena & ~empty) begin
                fdata = array.pop_front();
                if(out_data != fdata) begin
                    $display("time = %t, out_data = %d, array = %d", $realtime, out_data, fdata);
                end
            end
        end
    endtask
     initial begin
        #10 fork
            fifo_val_check;
        join_none
    end

    initial begin // 一回のみ順番に実行される
        clk = 1'b1;
        reset = 1'b1;
        wr_ena = 1'b0;
        rd_ena = 1'b0;
        in_data = 0;
        #60
        reset = 1'b0;
        wr_ena = 1'b1;
        for(i=0; i<10; i=i+1) begin
            @(posedge clk);
            #1;
            in_data = in_data + 8'd1;
        end
        #60;
        wr_ena = 1'b0;
        rd_ena = 1'b1;
        for(i=0; i<10; i=i+1) begin
            in_data = in_data + 8'd1;
            @(posedge clk);
            #1;
        end
        #60
        for(i=0; i<80; i=i+1) begin
            in_data = in_data + 8'd1;
            wr_ena = $urandom_range(1,0);
            rd_ena = $urandom_range(1,0);
            @(posedge clk);
            #1;
        end
        #60
        $finish;
    end

    fifo8 fifo8_inst(.*);

    // シミュレーション時に fifo.vcd を出力する
    initial begin
        $dumpfile("fifo8.vcd");
        $dumpvars (0, fifo8_inst);
        #1;
    end
endmodule

  1. 2024年03月09日 05:16 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0