FIFO間の転送では順次処理

この一ヶ月間、データが出力されないことに悩んでいました。原因はFIFO間の転送にありました。always文を使わずassign文を書くことが多い人は気をつけてください。

原因: はFIFO間がwireで直接つながっていたこと


次のようにFIFO1からFIFO2に転送します。

FIFO1 (読み出し150MHz)

FIFO2 (書き込み150MHz)

問題だったのは次のコードでした。自分はタイミングについて無知で、ワイヤ間など一瞬で転送されると思っていたのですが、実際には、クロック周波数が高い場合、ワイヤ間のdriveや転送にかかる時間、遅延が無視できなくなります。
assign pass = !empty1 && !full2;
assign rd_en1 = pass;
assign wr_en2 = pass;

解決策: データをいったんレジスタに格納する

これは次のように直すことで解決されました。150MHzが450,000クロック動き、見たところエラーゼロでした。rd_enからwr_enまでの立ち上がりは4クロック離れています。FIFO間のデータは一旦regに格納した方がよいと聞いているので。非同期間の通信にも使えるように、二段FlipFlopにしました。

FIFO1

reg data_middle1

reg data_middle2

FIFO2


    reg [7:0] data8_middle1,data8_middle2;
    reg [2:0] sreg;
    assign re32to8 = SiTCP_READY && !empty32to8;
    always @(posedge clk150) begin
        sreg <= {sreg[1:0], re32to8};
        SiTCP_WE <= sreg[2];
        data8_middle1 <= data8_out;
        data8_middle2<= data8_middle1;
        data8_in <= data8_middle2[3:0];
    end
 

ただし、上記のコードでは、FIFOはStandard FIFOにしてIP生成してください。FWFTとStandardはempty時の読み出しデータやフラッグのタイミングが異なります。FWFTはデータが入ると、rd_enを立ち上げなくても、最初のデータがdoutから常に出され、rd_en<=1にすると次のデータに切り替わります。Standardはempty時は0を出力します。自分は最初、FWFTのFIFOを生成したのに、Standardのタイミングチャートを見て設計して失敗し、原因に気がつくのに手間取りました。

FIFO Generator v12.0 (P.95-101) はFIFOの読み書きのタイミングを考えるのに必須です。
http://www.xilinx.com/support/documentation/ip_documentation/fifo_generator/v12_0/pg057-fifo-generator.pdf

wireとregの違い

単にそれらがwireと記憶処理だと聞いていましたが、どう使い分けるかは難しいものでした。たとえば、次の2つの処理は、当初、1クロック遅れるかどうかの違いしか生まないと思っていました。

assign y = c ? x : 1'b0;

always @(posedge clk) y <= c ? x : 1'b0;

また、always文だからといって順次回路だとも限りません。いずれも、yのブロッキング代入の右辺にはyがないので、以前のyの値を使っていないのですから、組み合わせ回路として論理合成されると聞きました

基本的にはalways文を使って書き、インスタンシエートされたモジュールのinput, outputをつなぐのにwireを用いるのがよさそうです。

コメント

人気の投稿