TikZ 硬體圖形 (hwfig v1.1)
當使用者需要在 LaTeX/TikZ 中建立硬體圖形時使用此技能:HLS/FPGA 核心的資料流程、量化神經網路層、Versal/Zynq SoC 方塊圖、AI Engine 陣列、脈動陣列、加法器樹、管線、NoC、記憶體階層、時脈域、平面規劃。輸出始終是可編輯的 TikZ 原始碼加上已編譯的 PDF/PNG 預覽。
工作流程
- 取得套件。 從此技能的基礎目錄將
hwfig.sty複製到工作目錄(除非使用者已有副本 — 如果他們的\ProvidesPackage行中沒有v1.1,則提供更新選項)。讀取檔案並逐位元組複製;切勿重新輸入或直接重新定義內部樣式 — 色板僅能透過角色顏色運作。 - 選擇色板(預設為
grey),可以作為套件選項\usepackage[okabe]{hwfig}或在任何地方使用\hwpalette{...}(群組區域性,因此每個圖形獨立):grey— 印刷/期刊預設值,鏡像參考模板(白色運算方塊、灰色量化器、虛線灰色常數)。okabe— Okabe–Ito,色盲安全,對比度最強。彩色論文的好預設值。tol— Paul Tol muted,色盲安全,色調較柔和。nord— 冷色調,適合投影片。slate— 藍灰色 + 紫紅色 + 珊瑚色,搭配科學投影片。 如果使用者未指定,則產生grey並提供一個彩色色板;若要比較,請在一個standalone文件中以多個色板編譯同一圖形(在\foreach \pal in {grey,okabe,...}{\hwpalette{\pal}...}迴圈內,每個色板產生一頁)。未知的色板名稱會導致硬錯誤。
- 先在網格上繪製佈局(明確的
at (x,y)座標,列間距約 2.4 公分,行間距 ±1.4 公分),然後進行連線。對於密集的資料流程圖,明確座標優於positioning。 - 編譯為
\documentclass[tikz,border=4pt]{standalone}+\usepackage{hwfig},使用pdflatex -interaction=batchmode -halt-on-error(在超時限制下;nonstopmode可能會掛起),光柵化為pdftoppm -r 110 -png,檢查 PNG,並修正重疊問題(導線上的標籤、跨越方塊的導線、碰撞的標題、接觸節點的框架標籤),然後再交付。迭代直到圖形清晰。 - 交付
.tex檔案(準備好貼入論文的圖形主體)、.sty檔案和 PDF。提醒使用者在他們的論文中需要\usepackage{hwfig}(或\usepackage[<色板>]{hwfig})。
視覺語法(保持一致)
- 資料流向左 → 右;主路徑位於水平軸上,平行分支位於上方/下方(±1.4 公分)。
- 編譯時常數(
ctime,虛線框)直接位於其配置的區塊上方/下方,並使用darr(虛線箭頭)連接。 - 每個改變精度的運算區塊後面都跟著一個
qbox(重新量化/移位/飽和)。 - 分支透過肘型導線合併到
op節點,導線垂直接近:\draw[arr] (qr.east) -| ($(sum.north)+(0,0.32)$) -- (sum.north); - 來自同一來源的替代分支:一個帶有點的分叉座標,
\fill[hwwire] (fork) circle (1.3pt);,然後用|-肘型連接到每個分支。 - 使用
hot表示關鍵/高亮路徑,bus表示具有pic[pos=.5]{buswidth=512}的寬資料路徑,node[lbl,midway,above]{AXI4-S}表示協定名稱(當標籤必須位於交叉導線上時使用lblbox)。 - 分組框架位於背景層,使用
fit:\begin{scope}[on background layer]\node[group,fit=(a)(b),label={[grouplabel]above:PL}] {};\end{scope} - 時脈域:
clkdomain(強調色,虛線)或clkdomain=<color>;使用cdc節點標記跨域點。 - 每張圖片以
\begin{tikzpicture}[hw]開頭(設定字體\footnotesize、線寬、箭頭尖端)。
路由與標籤(在每個 PNG 上檢查這些)
- 區域間的間隙。 在相鄰框架之間(Runtime | Message passing, PL | AIE)留出 ≥ 0.6 公分的空間。節點、合併
op和導線絕不能位於框架邊緣上 — 如果一個節點不屬於任何框架,則在框架外部為其留出空間。 - 路由通道。 區域間的導線在框架之間的空通道中執行(定義:
\def\chan{6.7}),然後在目標框架下方/上方的自己的水平層級上執行(\def\lvla{-1.7})。兩條導線絕不共享同一層級;在導線與任何平行框架邊緣或區塊側面之間保持 ≥ 0.3 公分,在平行導線之間保持 ≥ 0.4 公分。 - 標籤僅位於空閒段上。 將
lbl/buswidth放在完全位於空白空間的段上 — 絕不能放在導線穿過框架邊框的位置,也絕不能放在距離區塊約 0.2 公分以內。如果唯一的空閒段是垂直的,請將標籤旋轉為從下往上讀取:node[lbl,rotate=90,below]{AXI4-S}。在短連結上使用pic[pos=.35..0.4],以便數字避開目標區塊。 - 帶標籤的肘型角的明確分段。
-|/|-無法在選定的腿上放置標籤;請明確寫出轉角:(a.east) -- (\chan,ya) -- node[lbl,...]{X} (\chan,\lvla) -- (b.south|-{(0,\lvla)}) -- (b.south); - 標籤中的數學公式:
$W_{\mathrm{root}}$;使用\\實現兩行標籤(所有樣式都設定了align=center)。
節點樣式(所有樣式都感知色板)
| 樣式 | 用途 |
|---|---|
runtime | 執行時輸入/輸出、連接埠、張量 |
ctime | 編譯時常數:權重、縮放因子、配置 |
hlsbox | 計算核心 / HLS 函數 / AIE 核心 |
qbox | 量化器、重新量化、移位+飽和 |
op | +、×、max(圓圈) |
mux, demux | 多工器(輸入在西方,輸出在東方)/ 解多工器(鏡像) |
mem, bram, uram | 片上緩衝區 |
fifo | 串流/FIFO |
reg / ff | 帶有時脈楔形的暫存器 |
lut, dsp | FPGA 原始元素(dsp 在其右上角外放置一個小的 "DSP" 標籤 — 請留出空間) |
extmem | DDR / HBM(圓柱體) |
cpu | PS / ARM / RISC-V(雙框架) |
host | 主機 CPU(PCIe 側) |
xbar | AXI 互連 / NoC 條(\rotatebox{90}{AXI IC}) |
router | NoC 路由器/交換器(菱形) |
pe | 處理元素 |
aie | AI Engine 磁貼(核心 + 本地記憶體;標籤以核心為中心) |
chip | 封裝/晶粒,帶有引腳 |
port | 小型引腳標記 |
cdc | 時脈域交叉同步器 |
group, plregion, psregion, clkdomain | 背景框架 |
grouplabel, lbl, lblbox | 框架標題、導線標籤(lblbox = 白色背景) |
邊緣樣式:arr, darr, bus, hot。匯流排刻度標記:pic[pos=.5]{buswidth=32}(數字在刻度右側)或 buswidth'=32(左側)。
參數化 pics
每個 pic 傳遞選項 — 它們保持該 pic 的區域性,因此不同大小可以共享同一張圖片:
\pic (A) at (0,0) {aiearray={rows=2,cols=4}};。\hwset{key=value,...} 為當前作用域的其餘部分設定預設值。內部節點可透過 (name-...) 定址。
| pic | 鍵 | 可定址部分 |
|---|---|---|
aiearray | rows, cols, dx, dy, tilelabel | 磁貼 (n-t<r>-<c>)(r=1 底部),襯墊 (n-s<c>),框架 (n-box) |
systolic | rows, cols | (n-pe<r>-<c>)(r=1 頂部) |
addertree | depth(2^depth 個輸入) | 輸入 (n-in<k>),加法器 (n-a<level>-<k>),輸出 (n-out) |
pipeline | labels={Load,MAC,Requant,...} | 階段 (n-st<k>),暫存器 (n-r<k>) |
noc | rows, cols, nocpe(true/false) | 路由器 (n-n<r>-<c>),PE (n-pe<r>-<c>) |
fabric | columns={I,C,C,D,C,B,...},fabricrows(任意值) | 列頂部 (n-c<k>)。C=CLB D=DSP B=BRAM U=URAM I=IO |
legend | legend={comp/Compute,mem/BRAM,...}(角色:io comp quant const op mem ctrl group);自動間距 | — |
導線應繞過 pics 佈線(例如,從下方進入襯墊磁貼:(k1.east) -- ++(0.9,0) |- ($(arr-s1.south)+(0,-0.35)$) -- (arr-s1.south)),絕不能穿過磁貼。
自訂色板
無需 @ 內部機制 — 設定所有 8 個角色(繪製、填色)和三個導線顏色:
\hwdefinepalette{mine}{%
\hwrole{io}{black}{white} \hwrole{comp}{teal}{teal!12} \hwrole{quant}{orange}{orange!15}
\hwrole{const}{black!55}{black!4} \hwrole{op}{red!70!black}{red!10} \hwrole{mem}{blue!60!black}{blue!10}
\hwrole{ctrl}{violet}{violet!10} \hwrole{group}{teal!40}{teal!3}
\hwwires{black}{black!50}{red!70!black}} % 導線、常數導線、強調/熱點
\hwpalette{mine}
保持填色 ≤ 25% 色調,以便黑色文字保持可讀,並檢查其灰階轉換是否仍能區分角色。
陷阱
- 使用檔案寫入工具編寫
.tex檔案,而不是使用 shell heredocs、sed或 Python 字串文字:這些通常會將\\轉換為\(或將\c...轉換為控制字元)並破壞節點文字中的換行。 label=文字中的冒號或逗號會破壞鍵解析 — 請用大括號將其括起來:label={[grouplabel]above:{INT8: shifts}}。fit=清單不能包含($(a)+(1,2)$)(逗號會分割清單);請先定義一個具名\coordinate。- 若要在節點內新增額外一行,請使用純文字節點,搭配
align=center和\\[-2pt]{\tiny ...}— 不要在方塊上疊加第二個標籤。 shapes.geometrictrapezium搭配空文字會除以零 — 這就是為什麼mux/demux是自訂路徑圖片;不要將它們換回來。- 在
\foreach內部,在節點名稱中使用數值之前,請使用\pgfmathtruncatemacro進行整數運算;在\foreach \a/\b in {...}中,標籤文字中的/會將其分割(請寫Port,不要寫I/O)。 clkdomain具有淺色填色;當將其繪製在fabric或其他密集內容上時,請傳遞fill=none。- MiKTeX 忽略 POSIX 風格的
TEXINPUTS;請將hwfig.sty放在.tex旁邊(或傳遞--include-directory=<windows 路徑>)。 - 對於雙欄論文,請將圖形寬度保持在約 16 公分以內,字體為
\footnotesize;僅在最後手段時使用\resizebox{\linewidth}{!}{...}進行縮放。
參考範例(GNN 層,主模板)
\begin{tikzpicture}[hw]
\node[runtime] (xin) at (-0.9,1.4) {$X_i$};
\node[runtime] (xein) at (-0.9,-1.4) {$(X,E)$};
\node[hlsbox] (root) at (2.5,1.4) {Root\\$W_{\mathrm{root}}x_i$};
\node[qbox] (qr) at (4.9,1.4) {$Q_r$\\shift + sat8};
\node[mem] (agg) at (2.5,-1.4) {Mean aggregation\\$m_i$};
\node[hlsbox] (neigh) at (5.5,-1.4) {Neighbor\\$W_{\mathrm{neigh}}m_i+b$};
\node[qbox] (qn) at (8.1,-1.4) {$Q_n$\\shift + sat8};
\node[op] (sum) at (9.8,0) {$+$};
\node[qbox,minimum width=1.45cm] (qc) at (11.6,0) {sat8};
\node[hlsbox,minimum width=1.55cm] (relu) at (13.6,0) {$\rho_l$\\ReLU / id.};
\node[runtime] (yout) at (15.5,0) {$y_i^{(l)}$};
\node[ctime] (wroot) at (2.5,2.45) {$W_{\mathrm{root}}$};
\node[ctime] (wneigh) at (5.5,-2.55) {$W_{\mathrm{neigh}},b$};
\node[ctime] (sr) at (4.9,2.45) {$S_r$};
\node[ctime] (sn) at (8.1,-2.55) {$S_n$};
\node[ctrl] (fsm) at (13.6,-1.6) {Layer FSM};
\draw[arr] (xin)--(root);
\draw[bus] (xein)--(agg) pic[pos=.5]{buswidth=16};
\draw[arr] (agg)--(neigh);
\draw[arr] (root)--(qr);
\draw[arr] (neigh)--(qn);
\draw[arr] (qr.east) -| ($(sum.north)+(0,0.32)$) -- (sum.north);
\draw[arr] (qn.east) -| ($(sum.south)+(0,-0.32)$) -- (sum.south);
\draw[hot] (sum)--(qc);
\draw[hot] (qc)--(relu);
\draw[hot] (relu)--(yout);
\draw[darr] (wroot)--(root);
\draw[darr] (wneigh)--(neigh);
\draw[darr] (sr)--(qr);
\draw[darr] (sn)--(qn);
\draw[darr] (fsm)--(relu);
\begin{scope}[on background layer]
\node[group,fit=(xin)(xein),label={[grouplabel]above:Runtime}] {};
\node[group,fit=(root)(qr)(agg)(neigh)(qn)(wroot)(wneigh),label={[grouplabel]above:Message passing}] {};
\end{scope}
\end{tikzpicture}
參考範例(Versal SoC)
\begin{tikzpicture}[hw]
\node[host] (host) at (-3.4,0.3) {Host\\(x86)};
\node[cpu] (ps) at (0,2.2) {PS\\Cortex-A72};
\node[extmem] (ddr) at (0,-2.0) {DDR4};
\node[xbar,minimum height=5.6cm] (noc) at (2,0.1) {\rotatebox{90}{NoC}};
\node[hlsbox] (k1) at (4.7,1.6) {mm2s\\(HLS)};
\node[hlsbox] (k2) at (4.7,-2.3) {s2mm\\(HLS)};
\node[bram] (buf) at (4.7,-0.35) {BRAM buf};
\pic (arr) at (8.3,0.1) {aiearray};
% routing levels
\def\chan{6.7} % vertical channel between PL and AIE regions
\def\lvla{-1.7} % mm2s -> AIE, under the AIE frame
\def\lvlb{-2.3} % AIE -> s2mm, one level lower (= s2mm row)
\draw[bus] (host) -- (host-|noc.west) node[lbl,midway,above=2pt]{PCIe Gen4};
\draw[arr] (ps.east) -- (ps-|noc.west);
\draw[arr,<->] (ddr.east) -- (ddr-|noc.west);
\draw[bus] (k1-|noc.east) -- (k1) pic[pos=.4]{buswidth=128};
\draw[bus] (k2) -- (k2-|noc.east);
% mm2s -> shim 1: right into the channel, down, along level a, up into the shim
\draw[arr] (k1.east) -- (\chan,1.6)
-- node[lbl,rotate=90,below]{AXI4-S} (\chan,\lvla)
-- (arr-s1.south|-{(0,\lvla)}) -- (arr-s1.south);
% shim 4 -> s2mm: down to level b, left to s2mm
\draw[arr] (arr-s4.south) -- (arr-s4.south|-{(0,\lvlb)})
-- node[lbl,above,pos=0.2]{AXI4-S} (k2.east);
\draw[darr] (buf) -- (k1);
\draw[darr] (buf) -- (k2);
\begin{scope}[on background layer]
\node[psregion,fit=(ps),label={[grouplabel]above:PS}] {};
\node[plregion,fit=(k1)(k2)(buf),inner sep=8pt,label={[grouplabel]above:PL @ 300 MHz}] {};
\node[clkdomain,fit=(arr-box),inner sep=3pt,label={[grouplabel,text=hwaccent]above:AIE array $3\times4$ @ 1.25 GHz}] {};
\end{scope}
\end{tikzpicture}
套件原始碼
hwfig.sty(v1.1,作者 Pelayo Leguina,[email protected],LPPL 1.3c)與此檔案一同提供。變更日誌、圖庫和範例位於公共 hwfig 儲存庫中;此技能在其 skill/ 目錄下維護,並透過 skill/package.sh 打包。