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

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

FPGAの部屋

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

fifo8 IP の作成1

8 深度の FIFO を SystemVerilog で書いてみることにした。今回は、概要とソースコードを貼っておく。

(2024/03/09:修正)ソースコードにバグがあったので、ソースコードを修正した。詳しくは”fifo8 IP の作成3”を参照。

8 深度の汎用 FIFO を SystemVerilog で書いてみることにした。
ブロック図を示す。
fifo8_1_240307.png

8 段の FF があって、最後の FF がデータを出力する。
入力は最初の FF に入力され、7 個の FF のデータの先頭を最後の FF に MUX で入力する。
それぞれの FF には、有効なデータが入っているか?を示す Valid フラグを付けておく。
Valid フラグの状況ごとに、次の Valid フラグの状態を表にまとめた。
Valid[7:0] の振る舞いの表を示す。
fifo8_2_240307.png
fifo8_3_240307.png

8 深度の汎用 FIFO の fifo8.sv を示す。

// fifo8.sv
// 2024/02/29 by marsee
// 8 entries fifo

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(~wr_ena & 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

`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;

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

    initial begin // 一回のみ順番に実行される
        clk = 1'b0;
        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月07日 04:56 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0