Diary/2022-12-4
PYNQ/KV260のビルド
GitHubで公開されてているKria-PYNQのbaseをビルドしてみる.
ライセンスは https://github.com/Xilinx/Kria-PYNQ/blob/main/LICENSE によると
BSD 3-Clause License なので,オリジナル作るときはこれをベースにすすめればよさそう.
git clone https://github.com/Xilinx/Kria-PYNQ.git cd Kria-PYNQ git checkout v3.0 git submodule update --init --recursive source /tools/Xilinx/Vitis/2020.2/settings64.sh kv260/base make
Vivado/Vitis HLSの日付のバグを踏むので
https://support.xilinx.com/s/article/76960
をちゃんと当てとかないとダメ
また,2020.2.2のアップデートをインストールしとくのと
KV260のボードファイルを用意しておく必要があるのは注意.
ボードファイルは,
https://github.com/Xilinx/XilinxBoardStore/tree/2020.2.2/boards/Xilinx/kv260
を /tools/Xilinx/Vivado/2020.2/data/boards/board_files にコピーしとく.
ビルドがおわると,PYNQでPLをオーバーレイするのに必要な
- base.bit
- base.hwh
- base.dtbo
が生成される.
base/base.xprを開いてブロックデザインをみてみると↓のような感じ.
ロゴが入っているのがZYNQ UltraSCALE+.
左側の濃いブロックがiop_pmod0でPMODにつながっていて,
右側の濃いブロックはmipi.
iop_pmod0の中身はこんな感じ.中にMicroBlazeがいる.
mipiの中身はこんな感じ.Vitis HLSで作ったモジュール達が入っている.
入力はmipi_phy_ifで外から入っていて,
計算した結果はAXI Video Direct Memory Accessを介して
Zynq UltraSCALE+のS_AXI_HPI_FPDに入力されている.
オリジナルIPの組み込み
Kria-PYNQ/baseにオリジナルのIPを組み込んでみる.
mkdir myipcore cd myipcore source /tools/Xilinx/Vitis/2020.2/settings64.sh vitis_hls
とかして,Vitis HLS開いて,プロジェクトを作る.
プロジェクトを作ったら,たとえば,こんな感じの関数を vector_add.c に実装して,
#include "vector_add.h" void vector_add(int a[128], int b[128], int c[128]){ #pragma HLS INTERFACE s_axilite port=return #pragma HLS INTERFACE s_axilite port=a #pragma HLS INTERFACE s_axilite port=b #pragma HLS INTERFACE s_axilite port=c for(int i = 0; i < 128; i++){ c[i] = a[i] + b[i]; } }
こんな感じのテストベンチを vector_add_tb.c に実装.
#include <stdio.h> #include "vector_add.h" int main(int argc, char **argv){ int a[128]; int b[128]; int c[128]; int c_sw[128]; int i; for(i = 0; i < 128; i++){ a[i] = i; b[i] = i; c[i] = 0; c_sw[i] = a[i] + b[i]; } vector_add(a, b, c); for(i = 0; i < 128; i++){ if(c_sw[i] != c[i]){ printf("%d: expected %d, but the actual %d\n", i, c_sw[i], c[i]); return 1; } } return 0; }
C Simulation -> C Synthesis -> Co-Simulation -> Export RTLする.
仮引数のa, b, cは,それぞれs_axi_controlのオフセット512, 1024, 1536にマッピングされた.
関数の制御/ステータス信号および仮引数はすべて一つのAXI4-LiteなSlaveにまとめられる.
メモリマップは
//------------------------Address Info------------------- // 0x000 : Control signals // bit 0 - ap_start (Read/Write/COH) // bit 1 - ap_done (Read/COR) // bit 2 - ap_idle (Read) // bit 3 - ap_ready (Read) // bit 7 - auto_restart (Read/Write) // others - reserved // 0x004 : Global Interrupt Enable Register // bit 0 - Global Interrupt Enable (Read/Write) // others - reserved // 0x008 : IP Interrupt Enable Register (Read/Write) // bit 0 - enable ap_done interrupt (Read/Write) // bit 1 - enable ap_ready interrupt (Read/Write) // others - reserved // 0x00c : IP Interrupt Status Register (Read/TOW) // bit 0 - ap_done (COR/TOW) // bit 1 - ap_ready (COR/TOW) // others - reserved // 0x200 ~ // 0x3ff : Memory 'a' (128 * 32b) // Word n : bit [31:0] - a[n] // 0x400 ~ // 0x5ff : Memory 'b' (128 * 32b) // Word n : bit [31:0] - b[n] // 0x600 ~ // 0x7ff : Memory 'c' (128 * 32b) // Word n : bit [31:0] - c[n] // (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
という感じ.
生成したIPコアをIPIに組み込むために,
IPカタログのリポジトリにmyipcoreディレクトリを追加してコアのインスタンスを生成して,
M_AXI_HPM0_LPDから制御されるps8_0_axi_periphなるAXI Interconnectの先にぶらさげる.
で,Generate Bitstreamで,しばらく待つと,
- kv260/base/base/base.runs/impl_1/base_wrapper.bit
- kv260/base/base/base.gen/sources_1/bd/base/hw_handoff/base.hwh
ができる.
両方ともKriaに転送して,
たとえば,/home/root/jupyter_notebooksの下にmyipcoreとか作って置いておく.
あとは,Juypter環境で,同じフォルダにPython3ノートを作って,
from pynq import Overlay base = Overlay("./myipcore.bit") from pynq import MMIO mmio = MMIO(base_addr=base.ip_dict['vector_add_0']['phys_addr'], length=0x1000, debug=True)
として追加したvector_add_0へのハンドラ(メモリ領域へのアクセサ)を取得する.
mmio.read(0)
とかすると,ap_idleに相当する4が返ってくる.
for i in range(128): mmio.write(512+4*i, i) mmio.write(1024+4*i, i) mmio.write(1536+4*i, 0)
として,仮引数のa, b, cに相当する領域を初期化した後,
mmio.write(0, 1)
で,処理の実行開始.処理はすぐに終わるはずなので,
mmio.read(0)
とすると,今度はap_readyとap_idleが立った状態の6が返ってくる.
for i in range(128): print(mmio.read(1536+4*i))
で,cの先のメモリを読むと,
0 2 4 6 8 10 12 14 16 ...
と,aとbを足した値が格納されていて,正しく処理が実行できたことがわかる.