FC2カウンター FPGAの部屋 Write側とRead側のデータ幅の異なるFIFOのシミュレーション
FC2ブログ

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

FPGAの部屋

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

Write側とRead側のデータ幅の異なるFIFOのシミュレーション

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路3(FIFOの深度)”でFIFOの深度を考察した際に、Write側とRead側のデータ幅の異なるFIFOを使用することにした。実は前回も使っているのだが、単体でシミュレーションしたことがないため、シミュレーションをやってみることにした。(ISE12.1)

Writeのデータ幅が32ビットで深度64、Readのデータ幅が16ビットで深度128の非同期FIFO、fifo32_16をCORE Generator のFIFO Generatorで生成した。下に生成した時の図を示す。
def_width_fifo_1_100716.png

def_width_fifo_2_100716.png

def_width_fifo_3_100716.png

def_width_fifo_4_100716.png

def_width_fifo_5_100716.png

def_width_fifo_6_100716.png

次にテストベンチfifo32_16_tb.v をVerilogで書いた。下にVerilog ソースを示す。

`timescale 10ps / 1ps
`default_nettype none

module fifo32_16_tb;

    // Inputs
    reg rst;
    reg wr_clk = 0'b0;
    reg rd_clk = 0'b0;
    reg [31:0] din;
    reg wr_en;
    reg rd_en;

    // Outputs
    wire [15:0] dout;
    wire full;
    wire overflow;
    wire empty;
    wire underflow;
    wire [5:0] wr_data_count;
    
    parameter WR_CLK_PERIOD = 750; // 7.5nsec
    parameter RD_CLK_PERIOD = 4000; // 40nsec

    // Instantiate the Unit Under Test (UUT)
    fifo32_16 uut (
        .rst(rst), 
        .wr_clk(wr_clk), 
        .rd_clk(rd_clk), 
        .din(din), 
        .wr_en(wr_en), 
        .rd_en(rd_en), 
        .dout(dout), 
        .full(full), 
        .overflow(overflow), 
        .empty(empty), 
        .underflow(underflow), 
        .wr_data_count(wr_data_count)
    );
    
    // wr_clk
    always begin
       #(WR_CLK_PERIOD/2)    wr_clk = 1'b1 ;
       #(WR_CLK_PERIOD/2)    wr_clk = 1'b0 ;
    end
    
    // rd_clk
    always begin
       #(RD_CLK_PERIOD/2)    rd_clk = 1'b1 ;
       #(RD_CLK_PERIOD/2)    rd_clk = 1'b0 ;
    end
    
    always @(posedge wr_clk, posedge rst) begin
        if (rst)
            din <= 32'd0;
        else
            din <= din + 32'd1;
    end
    
    // wr_clk domain
    initial begin
        // Initialize Inputs
        rst = 1'b1;
        wr_en = 0;

        // Wait 100 ns for global reset to finish
        #10000;
      rst = 1'b0;  
        // Add stimulus here
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        wr_en = 1'b1;
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
//        wr_en = 1'b1;
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        @(posedge wr_clk); #100; // 次のクロックの後1nsec wait
        wr_en = 1'b0;
    end
    
    // rd_clk domain
   initial begin
        rd_en = 0;
        #10000; // rstの分をwait
        @(negedge empty); #100; // emptyがデアサートされるまで待つ
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        rd_en = 1'b1;
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        @(posedge rd_clk); #100; // 次のクロックの後1nsec wait
        rd_en = 1'b0;
    end
endmodule
`default_nettype wire



ここで時間がなくなったので、また帰ってきてから書きます。衝撃の事実が。。。ご期待ください???
(大げさすぎですね。。。)書いてみたかったので。。。

続きです。いよいよ衝撃の事実が明らかに。(ネタです。本気にしないでください。)

Project NavigatorのDesignウインドウでSimulationモードにしてISE Simulatorでシミュレーションをしてみた。
シミュレーションが出来ました。(ここから文体をですます調に変更)あれ?なんかoverflowが立っている???なんででしょうか?
def_width_fifo_7_100716.png

その部分を拡大してみます。
def_width_fifo_8_100716.png

非同期リセットのrstを1にしてもfullは1のままで、rstを0にした次のwr_clkの立ち上がり(黄色いカーソルのところ)でwr_enがサンプルされて、overflowが1になってしまっています。なぜfullはリセットしても0にならないのでしょうか?wr_data_countはリセットされて初期値は00ですので、fullを見ていないと最初はoverflowしてしまうことになります。これが衝撃の事実です。本当かな?

rstが1の長さを1usecにしてみましたが同様でした。
今度はどうなっているか見るために、wr_en = 1'b1;にするところをコメントアウトしている位置に移動して、従来のwr_en = 1'b1;はコメントアウトしました。
def_width_fifo_9_100716.png

今度は大丈夫です。問題の部分を拡大してみましょう。
def_width_fifo_10_100716.png

rstが0になってから、fullが3クロックかかって0になっています。どうしてでしょうか?
気になって、Veritakでもシミュレーションしてみたが同様の結果でした。なぜ?(シミュレーションを中止させるために、$stopをソースに追加しました)
def_width_fifo_11_100716.png

その時にワーニングに気がついた。(ですます調が苦痛になってきたので、である調に戻します)

WARNING: Behavioral models for independent clock FIFO configurations are not cycle-accurate. You may wish to choose the structural simulation model instead of the behavioral model. This will ensure accurate behavior and latencies during simulation. You can enable this from CORE Generator by selecting Project -> Project Options -> Generation tab -> Structural Simulation. See the FIFO Generator User Guide for more information.


あれ?behavioral modelからstructural simulation modelにしろって?早速アンサーをサーチ。これだろうか?

20414 - LogiCORE 非同期 FIFO および FIFO Generator - ビヘイビア モデルの限界


非同期FIFOだから、シミュレーションと実際の動作に違いが出るのは、よく分かるが、それでリセットでfullが落ちない理由になるのかな?
Project NavigatorからCORE Generatorを立ち上げて、早速、structural simulation modelにモデル生成を切り替えたんだけど、やはり結果は同じだった。
def_width_fifo_12_100716.png

もう少しFIFOの構成をいじってやってみよう。

(追記)この動作は正常だそうです。

AR #23659 - FIFO Generator - Why is there a latency in the deassertion of the FULL, ALMOST_FULL, and PROG_FULL signals after the release of RST?


内部は同期ロジックなので、FULL関連の信号をディアサートするのに時間がかかるとのことでした。知りませんでした。以前からそうでしたか?まずいっすね。カウントだけで制御しているものはなかったかな?
”FULLは絶対見ること”という教訓を心に誓います。。。
#結局、ネタになってしまった。。。

(2012/04/02:追記)
非同期FIFOでFWFTモードの場合は、Use Extra Logic For More Accurate Data Countsのチェックボックスにチェックを入れる必要があるそうです。詳しくは”FWFTモードのBlock RAM使用した非同期FIFOのrd_data_countについて”を参照してください。
  1. 2010年07月16日 05:49 |
  2. Core Generator
  3. | トラックバック:0
  4. | コメント:4

コメント

プチつっこみ

いつも楽しく閲覧させて頂いております。

細かいつっこみを・・・

if (rst)
din <= 32'd0;
else
din <= din + 32'd1;

ですね。

あとのウェイトはfor文にするとスマートになりますね。

for( i=0; i<10; i=i+1 ) begin
@(posedge wr_clk); #100; // 次のクロックの後1nsec wait
end

こんな感じでどうでしょう?(コンパイル通りますかね?)
  1. 2010/07/16(金) 09:27:32 |
  2. URL |
  3. vlog #-
  4. [ 編集 ]

vlogさん、こんにちは。
ツッコミありがとうございます。データ幅間違っていました。修正します。
waitは、衝撃に事実に関係があるので、却下です。(そんなたいしたことはありませんが、ネタです)
  1. 2010/07/16(金) 10:17:05 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

衝撃の事実、楽しみにしております。
  1. 2010/07/16(金) 10:21:11 |
  2. URL |
  3. vlog #-
  4. [ 編集 ]

あまり楽しみにしないでください。がっくりしますよ。ネタということで。。。
  1. 2010/07/16(金) 13:22:06 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


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

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