2022年の5月くらいに作ってたTclスクリプトの紹介
実用的な回路を256個も含んで並列処理、というのはハードウェアリソースの面で現実的ではなさそうなのでネタっぽさはあるが、複数のIPコアを含むブロックデザインを作る際に、作成したTclスクリプトで作業効率が上がった。
「IPコア」という表記をする場合は高位合成ベースのIPコアを指す。

背景

VivadoのブロックデザインにはIPコア同士を接続できる機能Run Connection Automationがある。この機能を使って、Zynq SoC向けにVitis HLSで作成したIPコアを複数個使ってブロックデザインを作成したいが、AXI4-Liteインターフェイスを含むIPコアを64個より多く含んで自動接続することができない。その原因は、AXI Interconnectのマスタ側は最大64接続?であるが、その数を超えたIPコアがあっても新たにAXI Interconnectを追加してくれないためである。実際に128個の加算回路IPコアを追加しRun Connection Automationした際のエラーを画像に示す。65個目の加算回路IPコアの接続でエラーが出ている。 error

また、Zynq SoC向けにAXI4-StreamインターフェイスのIPコアをAXI DMA IPを用いてデータ入出力することがしばしば発生する。IPコアを複数個追加しAXI DMA IPと1対1に接続するとき、追加した数だけAXI DMA IPの設定(チャネルの設定)する必要があり、手間である(AXI Interconnectの件よりも、これを解決するのが本命だった)。

何をしたか

UG835を参考に、Zynq SoC向けの高位合成ベースのIPコアを最大256個含むブロックデザインを自動で追加・接続のできるTclスクリプトを作成した。スクリプトは vivado-auto-bd-playgroud - GitHub にてMITライセンスで公開している。
DYGV/vivado-auto-bd-playgroud - GitHub

どんなブロックデザインが生成できるか

同一のIPコアを複数個

作成したスクリプトを使うことで画像のようなブロックデザインを自動で作成することができる。以下の画像は入出力がAXI4-Liteの加算回路のIPコアを自動で256個追加・接続したときのブロックデザインである(画像では、もやは何がなんだかわからない)。 add_256

異種のIPコアを複数個

また、複数種類のIPコアを複数個、追加・接続することもできる。以下の画像は、入出力にAXI4-Streamを使うIPコアを4つ、入出力にAXI4-Liteを使うIPコアを8個追加した例である。AXI4-Streamの場合はDMA回路の設定を含めて自動で行われる。 diff

スクリプトの使い方

  1. 後述の環境制限をよく読み、Vitis HLSでC Synthesisexport RTL
  2. vivado_block_design.tclを必要なパラメータと一緒にvivadoのコマンドライン引数に渡す
    vivado -nolog -nojournal -mode batch \
    -source ./vivado_block_design.tcl \
    -tclargs -project_name vivado \
    -device_part <デバイスパーツ> \
    -ips_directory <IPコア(.zip)のディレクトリ> \
    -start_gui 1 \
    -auto_connect 1 \
    -write_bitstream 0  \
    -ip <IPコア1のトップ関数名(IPコア名)> <その個数> \
    -ip <IPコア2のトップ関数名(IPコア名)> <その個数> \
    -ip <IPコア3のトップ関数名(IPコア名)> <その個数>
    ...
    

スクリプトの簡単な説明

簡単にスクリプトの特徴を挙げる

  • IPコアを指定された個数分ブロックデザインに追加する
  • apply_bd_automationは使わない
  • インターフェイス、ピンの接続は、connect_bd_intf_netconnect_bd_netによって接続する
  • 必要に応じてAXI Interconnectを追加する
  • 必要に応じてAXI InterconnectにAXI Interconnectを接続する
  • AXI4-Streamインターフェイスによるデータ入出力を行うIPコアがある場合はDMA回路を追加・接続する
  • IPコアと対になるDMA回路のチャネルの設定を行う

動作確認済みの環境

  • OS: Ubuntu 22.04
  • Vivado/Vitis HLS: 2022.1

制限

  • ターゲットデバイスがZynq SoCであること

  • 高位合成した回路のインターフェイスがAXI4-[Stream|Lite]であること

  • AXI4-Streamを用いる場合
    データの入出力にAXI DMA IPコアが追加・接続される。IPコアとDMA IPコアは1対1、例えばIPコアを4つ追加したら4つのDMA IPコアが追加・接続される。

  • IP化の際にVitis HLSのexport RTLで以下を指定する

    • Export Format: Vivado IP (.zip)
    • IP Configuration
      • Vendor: xilinx.com
      • Library: hls
      • Version: 1.0
  • 異種のIPコアを含むブロックデザインを生成したい場合は同じディレクトリにexport RTLする

  • ブロックデザイン生成可能なインターフェイス

    // 入出力全てAXI4-Liteでbundleされる状況 
    void top_func_case_1(int in, int out){
    #pragma HLS INTERFACE s_axilite port=in
    #pragma HLS INTERFACE s_axilite port=out
    #pragma HLS INTERFACE s_axilite port=return
        // ...(処理)...
    }
    
    // 入力がAXI4-Streamで出力がAXI4-Lite
    void top_func_case_2(hls::stream<hls::axis<int, 0, 0, 0>> &in, int out) {
    #pragma HLS INTERFACE axis port=in
    #pragma HLS INTERFACE s_axilite port=out
    #pragma HLS INTERFACE s_axilite port=return
        // ...(処理)...
    }
    
    // 入力がAXI4-Liteで出力がAXI4-Stream
    void top_func_case_3(int in, hls::stream<hls::axis<int, 0, 0, 0>> &out) {
    #pragma HLS INTERFACE s_axilite port=in
    #pragma HLS INTERFACE axis port=out
    #pragma HLS INTERFACE s_axilite port=return
        // ...(処理)...
    }
    
    // 入力がAXI4-Streamで出力がAXI4-Stream
    void top_func_case_4(hls::stream<hls::axis<int, 0, 0, 0>> &in,   
        hls::stream<hls::axis<int, 0, 0, 0>> &out) {
    #pragma HLS INTERFACE axis port=in
    #pragma HLS INTERFACE axis port=out
    #pragma HLS INTERFACE s_axilite port=return
        // ...(処理)...
    }
    
  • 個数 (同一のIPコアのみで構成する場合)

    • top_func_case_1: 最大256個
    • top_func_case_2: 最大128個
    • top_func_case_3: 最大128個
    • top_func_case_4: 最大128個
  • 動作未確認なインターフェイス

    // AXI4-Streamインターフェイスが3つ以上ある場合
    void top_func(
        hls::stream<hls::axis<int, 0, 0, 0>> &in_1,
        hls::stream<hls::axis<int, 0, 0, 0>> &in_2
        hls::stream<hls::axis<int, 0, 0, 0>> &out) {
    #pragma HLS INTERFACE axis port=in_1
    #pragma HLS INTERFACE axis port=in_2
    #pragma HLS INTERFACE axis port=out
    #pragma HLS INTERFACE s_axilite port=return
        // ...(処理)...
    }