工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

Ready/Validハンドシェイクを使用したブロックRAMベースのAXI FIFO実装

モジュール設計中にAXIインターフェースに初めて遭遇したとき、その合理化されたフロー制御アプローチに驚きました。従来のプロトコルがbusy/valid、full/valid、empty/validペアに依存するのとは異なり、AXIはreadyとvalidの2信号のみを使用します。始まりはフラストレーションでしたが、すぐに魅力に変わりました。

AXIはフロー制御をハンドシェイクに直接埋め込み、追加のステータス線を不要にします。基本ルールはシンプルですが、プロトコルをFPGAハードウェアにマッピングする際は細心の注意が必要です。このチュートリアルでは、ブロックRAM上で動作するAXI FIFOのVHDL実装を解説します。

AXIが1サイクル遅延問題を解決する

2つのクロック同期モジュールがデータ・ストリームをやり取りする際、オーバー・リードとオーバーライトの防止は一般的な課題です。核心的な問題は、各モジュールが相手の出力をクロック・サイクル1つ分遅れてしか観測できないことです。

Ready/Validハンドシェイクを使用したブロックRAMベースのAXI FIFO実装

上図は、従来の書き込みイネーブル/フルシグナリング・スキームを使用するFIFOにシーケンシャル・モジュールが書き込む様子を示しています。ライターはwr_enをアサートしてデータをFIFOにプッシュし、FIFOは空きがなくなるとfullをアサートします。問題はfullがクロックの立上がりエッジでちょうどアサートされるため、ライターが同じサイクルでそれに反応できないことです。解決策はalmost_emptyのような先読み信号を提供し、上流ロジックに先手を与えることです。

Ready/Validハンドシェイク

AXIストリーム・インターフェースは、readyとvalidの2信号ハンドシェイクでこのタイミング・ジレンマを解決します。受信側がreadyを駆動し、ハイ値は新しいデータを受け入れる準備ができていることを示します。送信側がvalidを駆動し、ハイ値はバス上のデータが安定しておりサンプリング可能であることを意味します。転送は、両信号が同じ立上がりエッジでハイのときのみ発生します。

Ready/Validハンドシェイクを使用したブロックRAMベースのAXI FIFO実装

波形は単一データ・アイテムの転送を示しています。データは従来の同期設計と同様に、立上がりクロック・エッジでサンプリングされます。

実装

AXI FIFOをVHDLで構築する方法はいくつかあります。シフト・レジスタでも動作しますが、ブロックRAMでバックアップされたリング・バッファーが最も効率的でスケーラブルな選択です。以下では、ロジックを専用プロセスに分離したモジュラー設計を提示し、明確さと合成ツール・フレンドリーさを両立させます。

エンティティ

エンティティは2つのジェネリック・パラメータ、ram_widthとram_depthを定義し、ワード幅とFIFO深度を設定します。容量は実質的にram_depth - 1です。フルFIFOと空FIFOを区別するために1スロットを予約するためです。

entity axi_fifo is generic ( ram_width : natural; ram_depth : natural ); port ( clk : in std_logic; rst : in std_logic; -- AXI入力インターフェース in_ready : out std_logic; in_valid : in std_logic; in_data : in std_logic_vector(ram_width - 1 downto 0); -- AXI出力インターフェース out_ready : in std_logic; out_valid : out std_logic; out_data : out std_logic_vector(ram_width - 1 downto 0) ); end axi_fifo; 

インターフェースはAXI規約に従います: 入力側はin_readyとin_validを使用し、出力側は方向を反転させた信号をミラーします。この対称性により、複数のFIFOをシームレスに連鎖できます。

信号宣言

まず、ジェネリック幅と深度に一致するRAM型を定義し、配列をインスタンス化します:

-- FIFOはRAMにram_depth - 1要素含むときフル type ram_type is array (0 to ram_depth - 1) of std_logic_vector(in_data'range); signal ram : ram_type; 

次に、RAM内の任意のアドレスを表現できるインデックス・サブタイプと、4つのコア信号head、tail、count、遅延コピーcount_p1を宣言します:

subtype index_type is natural range ram_type'range; signal head : index_type; signal tail : index_type; signal count : index_type; signal count_p1 : index_type; 

アーキテクチャ内でout信号を読み取らないように、readyとvalid出力の内部バージョンも保持します:

signal in_ready_i : std_logic; signal out_valid_i : std_logic; 

前サイクルで同時読み書きが発生したかを追跡するヘルパー信号。これはFIFOがほぼ空のときにout_validを正しく設定するために重要です:

signal read_while_write_p1 : std_logic; 

サブプログラム

next_index関数は、読み取りまたは書き込みハンドシェイクが完了したかどうかに基づいて次のアドレスを決定します。配列の末尾に達したらラップ・アラウンドします。

function next_index( index : index_type; ready : std_logic; valid : std_logic) return index_type is begin if ready = '1' and valid = '1' then if index = index_type'high then return index_type'low; else return index + 1; end if; end if; return index; end function; 

index_procプロシージャは、headまたはtailポインタを更新する同期ロジックをカプセル化します。これにより重複コードを避け、アーキテクチャを整頓します。

procedure index_proc( signal clk : in std_logic; signal rst : in std_logic; signal index : inout index_type; signal ready : in std_logic; signal valid : in std_logic) is begin if rising_edge(clk) then if rst = '1' then index <= index_type'low; else index <= next_index(index, ready, valid); end if; end if; end procedure; 

内部信号を出力にコピー

in_ready <= in_ready_i; out_valid <= out_valid_i; 

HeadとTailの更新

ヘルパー・プロシージャを2回インスタンス化します。1回は書き込みポインタ(head)用、もう1回は読み取りポインタ(tail)用です:

PROC_HEAD : index_proc(clk, rst, head, in_ready_i, in_valid); PROC_TAIL : index_proc(clk, rst, tail, out_ready, out_valid_i); 

ブロックRAMの推論

ほとんどのFPGAのブロックRAMは同期式です。合成ツールにRAMプリミティブを推論させるため、読み取りと書き込み操作をクロック・プロセス内に保持し、明示的なイネーブル信号を避けます:

PROC_RAM : process(clk) begin if rising_edge(clk) then ram(head) <= in_data; out_data <= ram(next_index(tail, out_ready, out_valid_i)); end if; end process; 

書き込みはin_validがハイのサイクルで無条件に発生し、読み取りデータは毎サイクル更新されるため、FIFOにデータが含まれているときはいつでもコンシューマーが有効なワードを観測できます。

FIFO内の要素数をカウント

count信号は現在の占有数を反映します。headがtailより先にある場合、カウントは単純に差分です。headがラップ・アラウンドした場合は総深度を加算します:

PROC_COUNT : process(head, tail) begin if head < tail then count <= head - tail + ram_depth; else count <= head - tail; end if; end process; 

遅延コピーcount_p1は、FIFOが前サイクルで空だったかを検出するために必要です。これはout_validに影響します:

PROC_COUNT_P1 : process(clk) begin if rising_edge(clk) then if rst = '1' then count_p1 <= 0; else count_p1 <= count; end if; end if; end process; 

Ready出力の更新

ライターにはFIFOがさらにデータを受け入れ可能かを知らせる必要があります。ready信号はカウントがram_depth - 1未満のときハイになります:

PROC_IN_READY : process(count) begin if count < ram_depth - 1 then in_ready_i <= '1'; else in_ready_i <= '0'; end if; end process; 

同時読み書きの検出

同じサイクルで読み取りと書き込みの両方が発生した場合、FIFOの占有数は変わりませんが、内部状態はFIFOがほぼ空のときに値が利用可能になるまで2サイクルかかることを反映する必要があります。したがって、このイベントをread_while_write_p1に取得します:

PROC_READ_WHILE_WRITE_P1: process(clk) begin if rising_edge(clk) then if rst = '1' then read_while_write_p1 <= '0'; else read_while_write_p1 <= '0'; if in_ready_i = '1' and in_valid = '1' and out_ready = '1' and out_valid_i = '1' then read_while_write_p1 <= '1'; end if; end if; end if; end process; 

Valid出力の更新

out_valid信号は、out_dataが使用可能なワードを保持しているときに下流ロジックに通知します。以下の組み合わせプロセスは、デフォルトでハイに設定しますが、2つのコーナー・ケースでクリアします:

PROC_OUT_VALID : process(count, count_p1, read_while_write_p1) begin out_valid_i <= '1'; -- FIFOが空、または前サイクルで空だった場合 if count = 0 or count_p1 = 0 then out_valid_i <= '0'; end if; -- FIFOに1アイテムのみのときに同時読み書きが発生した場合 if count = 1 and read_while_write_p1 = '1' then out_valid_i <= '0'; end if; end process; 

最初の条件は、最初の書き込み後の伝播遅延中にout_validがローのままであることを保証します。2番目は、FIFOが1サイクルフルに見えるが実際には出力するデータを保持していない状況を防ぎます。

Vivadoでの合成

この設計をXilinx Vivadoで合成するには、ジェネリックに具体的な値を指定します。設定ダイアログ(General → Generics/Parameters)で、ターゲットZynqデバイスのRAMB36E1プリミティブに一致する深度を選択します。実装後、リソース使用量は控えめです。ブロックRAM 1個に加えて少数のLUTとFF。

Ready/Validハンドシェイクを使用したブロックRAMベースのAXI FIFO実装

Ready/Validハンドシェイクを使用したブロックRAMベースのAXI FIFO実装

AXIはReady/Valid以上のもの

AXI(Advanced eXtensible Interface)はARMのAMBAバス・アーキテクチャのコンポーネントであり、シンプルなready/validハンドシェイクを超えた豊富な機能セットを提供します。より深い理解のために、以下のリソースを検討してください:

VHDL

  1. インダストリアル・インターネット:接続性、分析、ユーザー体験で資産管理を革新
  2. 資産トラッキングのベストプラクティス:資産データの価値を引き出す
  3. データ駆動型サプライチェーン:明日のロジスティクスを支える
  4. 信頼できるサプライチェーンデータを確保する実証済み戦略
  5. AIが解決するサプライチェーンの「汚いデータ」問題
  6. クラウド革命:IT、セキュリティ、キャリアをどう変えるか
  7. IoTデータを解き放つ:ビジネス・ルール管理が企業価値を推進
  8. IoTで製造オペレーションをAI対応へ — ビッグデータ活用で次世代ファクトリーを準備
  9. IoTへの洞察を深める:データ可視化とグラフデータベースの活用
  10. レストランにおけるIoT活用の極意:効率化、廃棄削減、顧客満足の実現
  11. VHDLのTEXTIOライブラリでテキスト・ファイルからFPGAブロックRAMを初期化する