01signal.com

FPGA FIFOsの紹介

このページは、 FIFOsに関する 5 ページからなるシリーズの最初のページです。

概要

FPGA FIFO は、シンプルなコンセプトのメモリ エレメントです。 application logic の一部は、 FIFOの片側にデータ ワードを書き込みます。 FIFOの反対側では、 application logic の別の部分がこれらの単語を同じ順序(FIFO = First In First Out) で読み取ります。

このデータは FIFO内に保存されます。 FIFOのdepthは、格納できるデータのワード数です。幅 (つまり、ワードあたりのビット数) と depth は、ユーザーが各 FIFOに対して構成するパラメーターです。

FIFOs は、おそらく FPGA designsで最も一般的に使用されている IP です。 logic の一部がデータを生成し、別の部分がそれを消費するときはいつでも、すぐに頭に浮かぶ解決策はそれらの間に FIFO を配置することです (これはもちろん、 FIFO が常に正しい解決策であると言っているわけではありません...)。

command-line インターフェース (特に UNIX / Linux) に精通している方は、コマンド間で FIFOs の使用を pipes と比較できます。 1 つのプログラムの出力が別のプログラムの入力になり、それらの間の魔法の機械が残りを処理します。

FPGA FIFO は広く使用されているため、 FPGA FIFO がどのように動作するかについて事実上の合意があります。すべての FPGA 開発ソフトウェアは、アプリケーションの designで使用する FIFO IP module を生成する方法を提供します。それだけでなく、この FIFO module には、他の FPGA FIFOと同じように動作する ports の特定のセットが含まれている可能性が非常に高くなります。

FPGAのベンダーが提供するソフトウェアを使用すると、特定のニーズに合った FIFOs を作成できます。いくつかの GUI ツール (幅、 depth 、およびその他の属性について説明します) でその属性を構成するだけで、あとはツールが処理します。あとは、 designで module の instantiation を作成するだけです。 FPGA の世界の他の多くのタスクとは異なり、このタスクは非常に単純です。

各 FPGA ベンダーが独自の FIFO IPを提示しているため、ドキュメントを細かい部分まで読むことはもちろん重要です。 FPGA ベンダーが異なれば、 FIFOsを説明するために使用する用語もわずかに異なります。 moduleの ports の名前もわずかに異なります。また、各ベンダーは、わずかに異なる追加機能と構成オプションのセットを提供しています。

そうは言っても、デフォルト設定は、私が「baseline FIFO」と呼ぶものに対応している可能性があります.その上、常に利用可能な一連の追加機能が間違いなくあります。

ただし、 logic fabric での FIFO の実装はベンダーによって異なるため、 FPGAのリソースを有効に活用するには、 FIFOの属性の意味を理解することが重要です。

全体として、 FPGA FIFOs を知り、理解することは 1 回限りの作業です。ある FPGAでそれらを使用する方法を習得したら、別の FPGAでも同じことを行うのは非常に簡単です。それ自体が遍在性の理由です。

baseline FIFO

FPGA FIFOsには文書化された標準はありませんが、 FPGA FIFOsがどのように動作するかについては広く合意されています。

すべての FIFOs には 2 つのインターフェイスがあり、1 つは単語の書き込み用、もう 1 つは単語の読み取り用です。私が「baseline FIFO」と呼ぶものの instantiation を見てみましょう。これには重要なバリエーションがありますが、これについては後で説明します。

myfifo myfifo_ins
  (
   .rst(rst),       // Asynchronous reset input

   // Write interface ports
   .wr_clk(wr_clk), // Write clock input
   .wr_en(wr_en),   // Write Enable input
   .din(din),       // Write word input 
   .full(full),     // Full output

   // Read interface ports
   .rd_clk(rd_clk), // Read Clock input
   .rd_en(rd_en),   // Read Enable input
   .dout(dout),     // Read word output
   .empty(empty)    // Empty output
);

ports の名前は Xilinxのツールで使用される名前ですが、他の FPGA ベンダーも同様の名前を使用しています。

FIFO moduleの ports は 3 つのグループに分けられます。 reset シグナル (@rst)。これについては後で説明します。そして予想通り、書き込みインターフェースと読み取りインターフェースがあり、それぞれ 4 つの portsで構成されています。

@din と @doutに関しては、これらは FIFO に出入りするデータ ワードを運ぶ 2 つの vector ports です。これらのワードの幅は、関連するソフトウェア ツールを使用して、 FIFOをセットアップするときに決定します。また、 FIFOの depth 、つまり含まれる単語の数も設定します。これら 2 つのパラメータは、 FIFO が消費する FPGAのメモリ リソースの量に影響します。

Clocks

これら 2 つのインターフェイスのそれぞれに独自の clockがあることに注意してください。 @wr_clk と @rd_clk。各インターフェイスの他の ports は、これら 2 つの clocksのそれぞれと同期しています。

FIFOs は、 clocksが 2 つあるため、ある clock domain から別の clock domain にデータを移動するためによく使用されます。 design の一部の logic が clk_Aと同期しており、別の部分が clk_Bと同期している場合、それらをどのように連携させるのですか? FPGA engineer の最初の考えは、それらの間に FIFO を配置することです。これは主に、 crossing clock domains のタスクが大きな頭痛の種であり、 FIFO を使用すると問題が簡単かつ安全に解決されるためです。

書き込みインターフェース

書き込みインターフェイスは単純です。 @wr_clk、 @wr_en 、 @din は inputs から FIFO、 @full は outputです。

@wr_clkの rising edge で @wr_en が High の場合、 @din のデータは FIFOにプッシュされます。 FIFO がフルの場合、 @full ポートは High です。

たとえば、これは FIFOに 5 ワードを書き込む waveform です。

Example waveform for writing words to a FIFO

この waveformでは、 application logic が最初に D0 と D1という単語を書き込みます。 FIFO は @full output を上げて、 D1の書き込みが成功した後に FIFO がいっぱいになったことを通知します。 application logic は、同じ clock cycleの間に @wr_en を下げることによってこれに応答します。数回の clock cyclesの後、 FIFO は @full を Low に変更して、再度書き込みが可能であることを示します。これは、反対側のアクティビティが原因である可能性が最も高いです (つまり、データが FIFOから読み取られた)。

application logic は、 @full が Low に変化した clock cycle で書き込みを開始できた可能性がありますが、わずかに遅れて開始されます (この特定の例)。 waveformに示すように、さらに 3 つの単語が書き込まれます。

@din が "Dx" 値でマークされている waveformでは、値が無視されることを意味するため、どのような値があっても問題ありません。たとえば、 D1 と D2の間の「Dx」のセグメントでは、 @din は D1にとどまるか、示されているよりも早く D2 に変更されるか、またはまったく異なるものになる可能性があります。結果は同じだったでしょう。

簡単なコーディング例として、可能な限りカウントアップする単語を FIFO に入力したいとします。

assign wr_en = !full;

always @(posedge wr_clk)
  if (wr_en)
    din <= din + 1;

これは、 @full と @wr_enの間の正しい関係を示しています。 @full が高い場合、 @wr_en は同じ clock cycleで低くなければなりません。そうでない場合はどうなりますか? @full 信号を無視するとどうなるでしょうか。この場合、 FIFO が wr_en を無視する可能性があります。したがって、 wr_en port が次のように定義されている @the_real_wr_enに接続されているかのように動作する可能性があります。

assign the_real_wr_en = wr_en && !full;

ただし、一部の FPGA ツールでは、この安全メカニズムなしで FIFO を構成できます。その場合、 FIFO がいっぱいになったときにデータを書き込もうとすると、事実上すべてが発生する可能性があります。

このように、または別の方法で、 @full を尊重する必要があります。そうしないと、データが漏洩したように見えます。上記の例を考えてみましょう: @wr_en が常に High であった場合、データが FIFO に書き込まれたかどうかに関係なく、 @din はカウントアップし続けます。そのため、反対側でデータを読み取ると、カウントアップが不連続になります。

@full は、 write cycleの結果としてのみ、つまり @wr_en がハイのときに rising clock edge の直後にローからハイに変化できることに注意してください。以下でさらに説明するように、 FIFO がリセットされた場合を除きます。

読み取りインターフェース

読み取りインターフェースはよく似ていますが、まったく同じではありません。 @rd_clk と @rd_en は inputs で、 FIFO、 @dout と @empty は outputsです。

@rd_clkの rising edge で @rd_en が High の場合、 FIFOのメモリから新しいワードが読み取られ、 rising edgeの、つまり次の clock cycleで @dout がその値で更新されます。 FIFO が空の場合、 @empty port はハイになります。

この例の waveformでは、 FIFOから 5 ワードが読み取られます。

Example waveform for reading words from a FIFO

この waveformでは、 application logic は 3 つの単語を読み取ることから始まります。 @empty が高に変化するのに応じて ( @doutに現れる D2 と共に)、 application logic は同じ clock cycleで @rd_en を低に変化させます。以前のように、 @empty が Low に変更されたのと同じ clock cycle で @rd_en を再度 High に戻しても問題ありませんでした (反対側の FIFO にデータが書き込まれているため)。代わりに、 clock cyclesを数回待ってから、さらに 2 つの単語を読み続けました。

この waveform と上の waveform を比較すると、5 つの単語が書かれ、5 つの単語が読み取られたことに気付くかもしれませんでは、なぜ D4 の出現とともに @empty が高くならなかったのでしょうか。 FIFO が空でなくても、読み取りを停止しても問題ないことを示したかったからです。したがって、この架空の例のために、 FIFOに追加のワードが書き込まれたため、 D4を読み取った後、 FIFO は空になりませんでした。

@rd_en が Low の場合、 @dout はその値を保持することに注意してください。 application logic はこれに依存する場合があります。 @dout には、常に FIFO から読み取られた最後のワードの値が含まれます ( resetの後を除く)。

さらに重要なことは、 @rd_en が High の場合、 @dout の新しい値が rising edge のに表示されることに注意してください。したがって、 FIFO は次の Verilog コードのように動作します。

always @(posedge rd_clk)
  if (rd_en && !empty)
    dout <= next_word_to_show;

この偽の Verilog コードは、同じ clock cycleで @empty が High の場合、ほとんどの FIFOs が @rd_en を無視するという事実も示しています。書き込みインターフェイスと同様に、 @empty がその clock cycleで High の場合、 @rd_en は High にしないでください。繰り返しますが、 FIFO はこの保護メカニズムを持たないように構成できる場合があるため、この規則を破らないでください。

@empty は、 read cycleの後、つまり clockの rising edge で @rd_en が High になった後にのみ、Low から High に変更できます。唯一の例外は、 FIFO がリセットされたときです。

例を挙げると、 FIFOから単語を読み取り、累積合計を計算する単純化された Verilog コード スニペット ( resetなし) を次に示します。

assign rd_en = want_to_read_now && !empty;

always @(posedge rd_clk)
  begin
    rd_en_d <= rd_en;

    if (rd_en_d)
      sum <= sum + dout; // Don't try this at home: @sum is never reset.
  end

デモンストレーションのために、 logic が読み取りを希望していることを示す @want_to_read_now 信号を追加しました。それにもかかわらず、 FIFO が空でない場合にのみ、 @rd_en はハイになります。

@rd_en_dには、 @rd_en の値が含まれており、 clock cycleが 1 遅延しています。したがって、 @rd_en_d は、 @doutに新しい有効な値があると同時にハイになります。これが、 @rd_en_d が @doutの値を消費する条件として使用される理由です。この例で示されているように、 @rd_en と @dout の間の遅延により、状況が少し難しくなります。

同期と latency

上記の waveforms の例は、書き込みと読み取りで別々に描いたので、重要な点が抜けています。 最初のワードを空の FIFO に書き込んでから @empty ポートが Low に変わるまで、数 clock cycles かかります。同様に、完全な FIFO から最初のワードを読み取ってから @full ポートが Low に変化するまで、数 clock cycles かかります。

これは、 FIFO への書き込みに関する情報が、 FIFOの反対側に到達する前に、2 つの clock domainsに伝達される必要があるためです。 clock domains を通過するために必要な logic は、数 clock cyclesの遅延を引き起こします。したがって、 @empty port の応答はわずかに遅くなります。同じ話が @full portにも当てはまります。

では、この遅延は何 clock cycles ですか?それは、特定の瞬間における 2 つの clocksの edges 間の時間関係など、多くのことに依存します。要するに、わかりにくい。

この遅延に影響を与えるものの中に synchronization stagesの数があり、これは多くの場合、 FIFOに設定できるパラメーターです。 2 つの stages を選択するのが一般的ですが、それ以上の数を選択することもできます。これは、 logicのリソースを少し多く使用することを犠牲にして、 FIFOの信頼性を向上させるのに役立ちます。また、前述のように、 @empty port および @full portの latency も増加します。

したがって、本当に FIFOを楽しみたい場合は、 synchronization stages を 3 つに増やして、完全に安全だと感じてください。

reset input

すべての FPGA FIFOs には reset 信号があります。 FIFO は 2 つの clocksを使用するため、この reset 信号はそれらのいずれとも同期していないと予想されるため、非同期です。 FIFOの内部 logic は、2 つの clock domainsのそれぞれについて reset を内部的に同期させます。

では、 reset は何をするのでしょうか?まず、 FIFO を空にし、 @empty を高く設定します。 FIFOにデータがあった場合、このデータは失われます。

@full outputに関しては、 FIFOがデータを受信する準備が整うまで (つまり、 write cyclesで)、 resetの結果として FIFOs がこの output をハイに保持することが一般的 (かつ推奨) です。ただし、この動作はオプションである可能性があるため、 FIFOのドキュメントでこのトピックを確認することをお勧めします。結局のところ、 FIFO は resetの後で実際にはいっぱいではありません。また、 reset のために @full を高に変更すると、上記のルールが破られます。 @full は、データ書き込みの結果としてのみハイに変化する必要があります。

reset 信号がアクティブになった瞬間から、 @empty port と @full port がハイに変化するまでに数 clocks cycles かかることに注意することが重要です。これは、 FIFOの synchronization logicが原因です。そのため、 resetのアクティブ化前後の clock cycles の間は少しあいまいです。 application logic が、 reset周辺の数回の clock cycles の間、 FIFO への書き込みも読み取りも試みないようにしてください。

reset 信号は非同期ですが、 FPGAの register (flip-flop) の output である必要があります。 FIFO が glitchesの結果として意図しない resets を受信する可能性があるため、 reset は combinatorial logicの output であってはなりません。

実際、多くの FPGA engineers は、事実上何でも reset port に接続できると誤って想定しています。ただし、 FPGA ベンダーは、 reset 信号に関して予期しない仕様を持っている可能性があります。たとえば、これは Xilinxの FIFO (PG057) の製品ガイドから取得したものです。

If the asynchronous reset is one slowest clock wide and the assertion happens very close to the rising edge of slowest clock, then the reset detection may not happen properly causing unexpected behavior. To avoid such situations, it is always recommended to have the asynchronous reset asserted for at least 3 [ ... ] slowest clock cycles...

(Chapter 3, "Resets")

そのため、 Xilinx は、 reset が少なくとも 3 つの clock cyclesに対してアクティブであることを推奨しています。その推奨事項を知っている人がどれだけいるかはわかりません。この reset 信号を適切に生成する方法については、ベンダーの FIFO のユーザー ガイドを必ずお読みください。

FIFO の実装方法

ベンダーのソフトウェア ツールが FIFO を適切に動作させるためにあらゆることを処理しますが、特にある種のリソースの不足を回避するために、 FPGA のどのリソースが使用されているかを認識しておくことをお勧めします。

FPGA にはそれぞれオプションがありますが、いくつかの一般的なオプションについて簡単に説明します。

これで、 FIFOsに関するこのシリーズの最初のページを終了します。次のページでは、 FIFOs の一般的なバリアントと追加機能について説明します。

このページは英語から自動翻訳されています。 不明な点は元のページを参照してください。
Copyright © 2021-2024. All rights reserved. (c3c02857)