Vivado IPI で Add moduleしたときのインターフェースパラメータの伝搬
Vivado IPI は、「Add Module」を行うことで簡単にモジュールのインスタンスを追加できます。特にAXI関係はポート名から自動的にインターフェースを推論してくれるため非常に便利です。しかし、Vivado 2018.2では、その他のインターフェースは、インスタンスのパラメータがインターフェースに正しく設定されず、意図したハードウェアにならないのでValidate Design用のTclスクリプトを書いた。
Vivadoのテンプレートに従い、下記のようなコードを書いたとすると IPI上でAdd Moduleを行うとBRAMインターフェースとして信号が束ねられ、Block Memory Generatorに簡単に接続が行える。
module ip2bram #( parameter integer MEM_WIDTH = 64, parameter integer MEM_SIZE = 1024 ) ( (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram EN" *) (* X_INTERFACE_PARAMETER = "MASTER_TYPE BRAM_CTRL,MEM_ECC None,READ_WRITE_MODE READ_WRITE" *) output bram_en, // Chip Enable Signal (optional) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram DOUT" *) input [MEM_WIDTH-1:0] bram_dout, // Data Out Bus (optional) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram DIN" *) output [MEM_WIDTH-1:0] bram_din, // Data In Bus (optional) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram WE" *) output [MEM_WIDTH/8-1:0] bram_we, // Byte Enables (optional) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram ADDR" *) output [$clog2(MEM_SIZE)-1:0] bram_addr, // Address Signal (required) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram CLK" *) output bram_clk, // Clock Signal (required) (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram RST" *) output bram_rst // Reset Signal (required) ); // user logic here endmodule
通常であれば「Validate Design」を実行するとパラメータが伝搬し、Block Memory Generator側のビット幅が変更されるが、Vivado 2018.2 ではインターフェースのパラメータが伝搬しない。
これは、モジュールインスタンスのパラメータとインターフェースのパラメータが正しく連動していないため起こっている。 たとえば、モジュールをクリックして、上記のようにMEM_WIDTHを64に変更しても、下記のように インターフェースの設定値は 128のままになる。
手動でこの2カ所を変更しても良いが、できればどちらか一方を修正するだけで通常のValidateと同じようにインターフェースにも値が設定されて欲しい。 そこで、簡単なTclスクリプトで値を設定できるようにした。Tclスクリプトは、ツールメニューより追加を行うことができる。
source tcl fileにvalidate-design.tcl
を指定する。
自作モジュールのどのインターフェースパラメータがモジュールパラメータと紐付くかはjsonで記述する。
デフォルトでは、Tclスクリプトと同じディレクトリのconfig.json
が読まれる。フォーマットはdictが3重になっており、最初のkeyはモジュール名、次のkeyはインターフェース名( (* X_INTERFACE_INFO = "xilinx.com:interface:bram:1.0 bram EN" *)
)のbram
部分、最後のkeyがインターフェースのパラメータ名、値にモジュールのパラメータ名を指定する。下記例では、ip2bram
モジュールのbram
インターフェースのMEM_WIDTH
とMEM_SIZE
のパラメータはそれぞれモジュールのパラメータMEM_WIDTH
とMEM_SIZE
を使用することになる。
{ "ip2bram":{ "bram":{ "MEM_WIDTH": "MEM_WIDTH", "MEM_SIZE": "MEM_SIZE" } } }
あとは、追加したスクリプトを通常のValidate Designと同じように実行すれば、モジュールのパラメータからインターフェースにも値が設定され、意図した回路となる。
(アドレス幅はBlock Memory Generator側が32bitにするのチェックボックスが付いているため値が伝搬していないように見えますが意図した動作です)
※ 職場で同じようなコードを使ったら動かない場合があったので修正した