1. はじめに
AMD 製の FPGA には一部の領域のみを、その他の領域を動作させたまま再度コンフィグレーションする DFX (Dynamic Function eXchange) と呼ばれる機能がある。本記事では最も単純な構成の DFX の手続きを述べる。
本記事が扱う範囲
- Pblock の位置とサイズを決める方策
- ブロック・デザインを用いる DFX の手続き
- XDC ファイルによる Pblock の記述方法
- JTAG 経由で RP を再コンフィグレーションする方法
本記事の対象外
- DFX Decoupler
- AXI インタフェースを持つ RP
- ILA を用いる RP のデバッグ
- PS から RP を再コンフィグレーションする方法
2. 参考文献
- UG909 Vivado Design Suite User Guide Dynamic Function eXchange
- UG947 Vivado Design Suite Tutorial Dynamic Function eXchange
- 01signal.com How-To on Partial Reconfiguration with Vivado
3. DFX Flow
UG909 によると DFX には 'Flow' と呼ばれる手続きがあり、次の 3 通りが存在する。
大分類 | 小分類 | 特徴 | 筆者の所感 |
---|---|---|---|
Vivado Software Flow | - | プロジェクトを作らずに全て Tcl スクリプトで完結する。 | 自動化には適するが、複雑な IP を備える最新のデバイスに対してこの手続きを適用すると手間が掛かりすぎるように思える。 |
Vivado Project Flow | RTL Project Flow |
|
'IP Integrator Project Flow' に比べるとスクリプトで自動化できる部分が多い。 |
Vivado Project Flow | IP Integrator Project Flow |
|
GUI の支援が効くため、DFX に入門するならこれが無難に思える。 |
本記事では表中 3 つ目の IP Integrator Project Flow を扱う。
4. IP Integrator Project Flow の例
4.1. 対象の FPGA と IDE
本例では下記の FPGA と IDE を対象とする。
項目 | 説明 |
---|---|
ボード | Zybo Z7-20 |
FPGA デバイス | xc7z020clg400-1 |
IDE | Vivado 2023.2 |
4.2. ソース・コードと Vivado プロジェクト
本例で使用するソース・コード、および本例の結果として得られる Vivado プロジェクトは下記のリンクから入手できる。
上記 2 つのファイルを展開して得られる 2 つのフォルダ src
と vivado_proj
を同じディレクトリに置けばよい。
4.3. 機能ブロックの概要
次の図は、DFX を使わない状態のトップ・レベルのブロック図である(前記の .7z ファイルには含まれない)。
次の表は先に示したブロック図中のインスタンスの説明である('SR', 'RP' は 'Static Region', 'Reconfigurable Partition' の略)
インスタンス | 説明 | ソース・ファイル | 目標配置先 (SR / RP) |
---|---|---|---|
debounce_wrap_0 | debounce (後述)をブロック・デザインに RTL モジュールとして置くためのラッパー | debounce_wrap.v | SR |
debounce_wrap_0.debounce_inst | i_btn を 40 Hz でリサンプルしてチャタリングを除去する。 | debounce.sv | SR |
sync_rst_wrap_0 | sync_rst (後述)をブロック・デザインに RTL モジュールとして置くためのラッパー | sync_rst_wrap.v | SR |
sync_rst_wrap_0.sync_rst_inst | リセット信号をクロックに同期化する | sync_rst.sv | SR |
blink_ptn_0_wrap_0 | blink_ptn_0 (後述)をブロック・デザインに RTL モジュールとして置くためのラッパー | blink_ptn_0_wrap.v | RP |
blink_ptn_0_wrap_0.blink_ptn_0_inst | 3 色 LED の R,G,B 点灯指令の信号を生成する。指令値は点滅のパターンである。点滅の周波数は 2 種類(通常, 1/2)あり、i_spd_sw の立ち上がりエッジ毎に切り替わる。 | blink_ptn_0.sv | RP |
図中に無い blink_ptn_1 は LED の発光色が blink_ptn_0 と異なる。本記事の目標は DFX によって blink_ptn_0 と blink_ptn_1 を切り替えることである。
4.4. Pblock の決定
(本例では幸運なことに)blink_ptn_0 と blink_ptn_1 の差は僅かであるから、blink_ptn_0 を収容できる Pblock を求めれば十分である。[3] で述べられているように、モジュールを Pblock に閉じ込めない状態で Vivado に自由に配置配線させ、Pblock の制約が無い条件下での最適解を得る。その上で、設計者が望む配置であって、かつモジュールを閉じ込めるのに十分な広さを持つ Pblock を決定する。
次の図は配置配線結果の Device View である。
色分けは下記の通りである:
sync_rst_wrap_0
, debounce_wrap_0
:水色
blink_ptn_0_wrap_0
:黄色
(参考)色分けの UI 操作
前記の Device View と下記の制約から、SLICE_X110Y100 を左下、SLICE_X113Y149 を右上とする矩形を Pblock とすれば良いと考えられる。
- Zynq 7000 SoC では
RESET_AFTER_RECONFIG = true
のために Pblock の上下端が Clock Region の境界と一致する必要がある - Zynq 7000 SoC では Tile (2 個の Slice から成る) が Pblock の境界で分断されてはならない
この段階ではまだ Pblock を作るわけではないが、Pblock を定義する為の UI があるので、利用するとよい。カーソルをドラッグしている間、Pblock の境界が Tile を跨がないよう適当にスナップしてくれる。
Pblock に収めたいセルを Netlist タブで選択して 'Draw Pblock' で矩形を描き、続けて現れるダイアログ・ボックスにて 'Assign selected cell' に✓を入れて OK すると 'Netlist' で選択されているセルが Pblock に取り込まれる。
手動で線引きされた Pblock に含まれていないセルがあれば、Pblock の空き領域に入るように要請が予約され、Device View から消えて見えなくなる。次回の配置配線で反映されるはず。
Block Design を閉じる。Block Design に対する変更(先ほど視覚化のために作った Pblock)は保存しない。
4.5. DFX 有効のプロジェクトの作成
[2] 'Lab 10 DFX BDC Project Flow in IP Integrator for Zynq UltraScale+' を参考にする。
4.5.1. フラットな Block Design を作る
Block Design を作る。階層名は design_1 とした。Figure 4.3.1.「トップ・レベルのブロック図(DFX 無)」と同じ状態にする。
4.5.2. Hierarchical Cell を作る
Static Region, RP 用の Hierarchical Cell を作り、sync_rsp_wrap_0 と debounce_wrap_0 を Static Regionに、blink_ptn_0_wrap_0 を RP にそれぞれ入れる。どちらから先にやってもよい。この例では Static Region から始める。Static Region 向け,RP 向けの Hierarchical Cell の名前をそれぞれ static_region, rp1 とする。
Move '<module name>' selected block to new hierarchy' に✓を入れ、Hierarchical Cell 作成後に自動的に対象のセルを Hierarchical Cell に入れる。本例では Hierarchical Cell の作成時にモジュールを入れたが、 Hierarchical Cell が出来た後に D&D で入れることもできる。同じことを blink_ptn_0_wrap_0 に対しても行い、Block Design が次の図のようになる。
cell を開くと中身が見える。
4.5.3. Block Design Container を作る
先ほど作った rp1 Hierarchical Cell を BDC に変える。Validate Design を実施した後、rp1 の右クリック・メニューから 'Create Block Design Container ...' を実行する。本例では BDC の名称を 'rp1rm1' とする。
この操作は元に戻せない ([1] 'Removing a Block Design Container')。念のためのバックアップ用にプロジェクトを別名で保存しておくとよい。
本例では RM は AXI インタフェースを持たないため、アドレス空間に配置されない。AXI インタフェースを備える RM を用いるプロジェクトに於いては、[2] 'Lab 10 DFX BDC Project Flow in IP Integrator for Zynq UltraScale+' 'Step 3' を参考にして設定する必要がある。
4.5.4. DFX の有効化
Tools → Enable Dynamic Function eXchange で DFX を有効化する。実行後、Flow Navigator に DFX Wizard が現れる。
この操作は元に戻せない
Block Design の rp1 をダブル・クリックし、'Customize Block Design Container' ウィンドウを呼び出す。Enable Dynamic Function eXchange on this container' と 'Freeze the boundary of this container' に✓を入れる。
本例では RM は AXI インタフェースを持たないため、'Addressing' タブの設定は不要(不可能)。AXI インタフェースを備える RM を用いるプロジェクトに於いては、[2] 'Lab 10 DFX BDC Project Flow in IP Integrator for Zynq UltraScale+' 'Step 4' を参考にして設定する必要がある。OK を押してウィンドウを閉じ、Validate Design を実行する。
プロジェクトで DFX が有効になると、Block Design の DFX が有効になっている BDC に DFX マークが表示される。
4.5.5. RM の追加
rp1 には 1 つ目の RM として btn_ptn_0_wrap_0 が既に登録されている。これは BDC を作ったときの Block Design 名 rp1rm1 が踏襲されている。2 つ目の RM として btn_ptn_1_wrap_0 を登録する。rp1 の右クリック・メニューで 'Create Reconfigurable Module …' を選択する。
RM の名前は rp1rm2 とする。
ポートのみが定義された Block Design が開かれる。ここに btn_ptn_1_wrap を Sources ウィンドウから D&D してインスタンス btn_ptn_1_wrap を作り、配線する。
rp1rm2 のBlock Design が完成したら保存ボタン(トップ・レベルのウィンドウの左上にある)を押して保存し、Diagram を閉じてよい。
追加された RM は 'Block Design Customization' ウィンドウの一覧に加わる。
本例では RM は AXI インタフェースを持たないため、'Addressing' タブの設定は不要(不可能)。AXI インタフェースを備える RM を用いるプロジェクトに於いては、[2] 'Lab 10 DFX BDC Project Flow in IP Integrator for Zynq UltraScale+' 'Step 6' を参考にして設定する必要がある。
4.5.6. Block Design の wrapper HDL を作る
トップ・レベルの Block Design のラッパー HDL ソース・ファイルを作る。Sources タブの design_1 の右クリック・メニューから 'Create HDL Wrapper' を開始する。ダイアログ・ボックスが出るので、'Options' に於いて 'Let Vivado …' を選択する。
自動生成された HDL ラッパーをトップ・レベルのモジュールに指定する。
その後、Block Design を Generate する。
4.5.7. DFX Wizard で configuration を定義する
DFX wizard を開始し、configuration を定義する。Edit Reconfigurable Modules' ダイアログ・ボックスには既に登録されている RM と RP の組が示される。Next をクリックして次に進む。
configuration が空なので自動で新規に作る。
configuration runs も空なので自動で新規に作る。
4.5.8. Pblock を定義する
4.4 で決定した Pblock を XDC ファイルで定義する。本例では Pblock 記述専用に XDC ファイルを作り、名前を pblock.xdc とする。本例では Pblock の名前を pblock_rp1 とする。
startgroup
create_pblock pblock_rp1
set_property HD.RECONFIGURABLE true [get_cells -quiet design_1_i/rp1]
# Simple `add_cells_to_pblock <Pblock name>` causes '[Common 17-161]'.
add_cells_to_pblock [get_pblocks pblock_rp1] [get_cells -quiet design_1_i/rp1]
# format: {slice at bottom-left:slice at top-right}
# Note that in 7 series devices, top and bottom side of Pblock must be aligned to clock region to enable `RESET_AFTER_RECONFIG`
resize_pblock [get_pblocks pblock_rp1] -add {SLICE_X110Y100:SLICE_X113Y149}
set_property RESET_AFTER_RECONFIG true [get_pblocks pblock_rp1]
set_property SNAPPING_MODE ON [get_pblocks pblock_rp1]
endgroup
-
HD.RECONFIGURABLE true
を記述しないと論理合成で「RECONFIGURABLE な RP でないとダメ」の旨のエラーが生じる -
add_cells_to_pblock pblock_rp1
という記述では論理合成でエラーが生じる。add_cells_to_pblock
が引数に Pblock の名前ではなく Pblock に関係するオブジェクトを期待していて、[get_pblocks pblock_rp1]
の返す結果は文字列ではなくオブジェクトなのだと推測される
4.5.9. IO, タイミングの制約を定義する
クロックの定義,トップ・レベルのモジュールの IO の定義を作る。本例では名前を top.xdc とする(入手先 URL は冒頭で述べた)。
4.5.10. 配置配線
論理合成と配置配線を行う。Pblock がタイルを跨いでいる旨の警告が出るが、警告が間違っているので構う必要はない。
4.5.11. ビット・ストリームの生成
Flow Navigator から 'Generate Bitstream' を実行すると full と partial のビット・ストリーム・ファイルが作られる。本例では .runs 以下に下記の 4 つが作られる(inst_
の次の数字は Block Design の編集の過程(階層を作ったり消したり)次第で結果が異なるかもしれない)。
役割は名前から容易に推察される。design_1_wrapper.bit が全体コンフィグレーション用、xxx_rp1rmX_inst_xxx が rp1 に RMX (X=1,2) を書き込むためのビット・ストリームである。
- impl_1/design_1_wrapper.bit
- impl_1/design_1_i_rp1_rp1rm1_inst_1_partial.bit
- child_0_impl_1/design_1_wrapper.bit
- child_0_impl_1/design_1_i_rp1_rp1rm2_inst_0_partial.bit
4.5.12. RP の再コンフィグレーション
Hardware Manager を開き、前述の xx_partial.bit
を使って RP を再コンフィグレーションできる。