Community研究与数据分析github.com

pleguina/tikz-hardware-figures

使用 TikZ 绘制可发表质量的硬件/FPGA/数据流框图(HLS 内核、AIE 阵列、脉动阵列、SoC、流水线),支持灰度或色盲安全调色板。

tikz-hardware-figures 是什么?

该技能使得用户能生成 LaTeX/TikZ 硬件图形,涵盖 HLS/FPGA 内核数据流、量化神经网络层、Versal/Zynq SoC 框图、AI Engine 阵列、脉动阵列、加法器树、流水线、NoC、存储器层次结构、时钟域和平面图等。输出始终为可编辑的 TikZ 源码(基于 `hwfig` 包 v1.1)和编译好的 PDF/PNG 预览。工作流程包括:选择调色板(灰度、Okabe‑Ito、Tol 柔和色、Nord、Slate)、在网格上手绘布局、使用显式 `at (x,y)` 坐标布线、编译并以迭代方式检查重叠,直到图形干净。该技能支持平台(LaTeX/TikZ)和角色样式(例如 `hlsbox`、`qbox`、`op`、`mem`、`aie`),并包含两种参考示例(GNN 层和 Versal SoC),展示了视觉语法——数据流从左到右、经过量化器、使用 `hot` 突出显示关键路径、用 `bus` 表示宽数据通路、用分组帧表示区域——以及避免陷阱(例如在 `fit` 列表中使用 `$()` 坐标、在标签中使用冒号或逗号)的各种注意事项。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pleguina/hwfig/tree/HEAD/skill

Installed? Explore more 研究与数据分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

TikZ 硬件图形(hwfig v1.1)

当用户希望使用 LaTeX/TikZ 创建硬件图形时使用此技能:HLS/FPGA 内核的数据流、量化神经网络层、Versal/Zynq SoC 框图、AI Engine 阵列、脉动阵列、加法器树、流水线、NoC、存储器层次结构、时钟域、平面图。输出始终是可编辑的 TikZ 源码以及编译的 PDF/PNG 预览。

工作流程

  1. 获取包。 将此技能基础目录中的 hwfig.sty 复制到工作目录(除非用户已有副本——如果他们的副本的 \ProvidesPackage 行中没有 v1.1,则提供更新)。读取文件并逐字节复制;绝不要重新输入或内联重新定义样式——调色板仅通过角色颜色生效。
  2. 选择调色板(默认为 grey),可以作为包选项 \usepackage[okabe]{hwfig} 或使用 \hwpalette{...} 在任何位置设置(组本地,因此每个图形独享):
    • grey — 打印/期刊默认,镜像参考模板(白色计算框、灰色量化器、虚线灰色常量)。
    • okabe — Okabe–Ito,色盲安全,对比度最强。彩色论文的良好默认选项。
    • tol — Paul Tol 柔和色调,色盲安全,更柔和。
    • nord — 冷色调,用于幻灯片。
    • slate — 蓝灰 + 紫红 + 珊瑚色,与科学幻灯片模板匹配。 如果用户没有指定,则生成 grey 并提供一个彩色调色板;要进行比较,可以在多个调色板中编译同一图形(在 standalone 文档内部使用循环 \foreach \pal in {grey,okabe,...}{\hwpalette{\pal}...} 会为每个调色板生成一页)。未知的调色板名称会导致硬错误。
  3. 首先在网格上绘制布局草图(显式 at (x,y) 坐标,列间距约 2.4 cm,行间距 ±1.4 cm),然后布线。对于密集数据流图形,显式坐标优于 positioning。
  4. 编译为 \documentclass[tikz,border=4pt]{standalone} + \usepackage{hwfig},使用 pdflatex -interaction=batchmode -halt-on-error(带超时;nonstopmode 可能挂起),使用 pdftoppm -r 110 -png 栅格化,查看 PNG,并在交付前修复重叠(导线上的标签、穿过盒子的导线、碰撞的标题、接触节点的框架标签)。迭代直到图形清晰。
  5. 交付 .tex(可直接粘贴到论文中的图形主体)、.sty 和 PDF。提醒用户在他们的论文中需要 \usepackage{hwfig}(或 \usepackage[<调色板>]{hwfig})。

视觉语法(保持一致性)

  • 数据流为从左到右;主路径位于水平轴上,平行分支位于上方/下方(±1.4 cm)。
  • 编译时常量(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 上检查这些)

  • 区域间的间隙。 相邻框架之间保留 ≥ 0.6 cm(Runtime | Message passing, PL | AIE)。节点、合并 op 和导线绝不得位于框架边缘上——如果节点不属于任一框架,则在其外部留出空间。
  • 布线通道。 区域之间的导线在框架间的空通道中运行(定义它:\def\chan{6.7}),然后在目标框架下方/上方自己的水平层级上运行(\def\lvla{-1.7})。两条导线绝不共享一个层级;导线与任何平行框架边缘或块侧面之间保持 ≥ 0.3 cm,平行导线之间保持 ≥ 0.4 cm。
  • 标签仅位于空闲线段上。 将 lbl/buswidth 放在完全位于空白空间中的线段上——绝不要在导线穿过框架边界的位置,也绝不要在距离块约 0.2 cm 范围内。如果唯一的空闲段是垂直的,则将标签旋转为从下到上阅读: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, dspFPGA 原语(dsp 会在其右上角外侧放置一个小的 "DSP" 标签——留出空间)
extmemDDR / HBM(圆柱体)
cpuPS / ARM / RISC-V(双框)
host主机 CPU(PCIe 侧)
xbarAXI 互连 / NoC 条(\rotatebox{90}{AXI IC})
routerNoC 路由器/交换机(菱形)
pe处理单元
aieAI Engine 瓦片(核心 + 本地存储器;标签居中对齐于核心)
chip封装/芯片,带引脚
port小引脚标记
cdc时钟域交叉同步器
group, plregion, psregion, clkdomain背景框架
grouplabel, lbl, lblbox框架标题、导线标签(lblbox = 白色背景)

边样式:arr, darr, bus, hot。总线刻度标记:pic[pos=.5]{buswidth=32}(数字在刻度标记右侧)或 buswidth'=32(左侧)。

参数化图片

每个图片可以传递选项——它们仅在该图片内局部生效,因此不同尺寸可以共享同一图片: \pic (A) at (0,0) {aiearray={rows=2,cols=4}};。使用 \hwset{key=value,...} 可以为当前作用域的其余部分设置默认值。内部节点可以通过 (name-...) 进行寻址。

图片键可寻址部分
aiearrayrows, cols, dx, dy, tilelabel瓦片 (n-t<r>-<c>)(r=1 为底部),shim (n-s<c>),框架 (n-box)
systolicrows, cols(n-pe<r>-<c>)(r=1 为顶部)
addertreedepth(2^depth 输入)输入 (n-in<k>),加法器 (n-a<level>-<k>),输出 (n-out)
pipelinelabels={Load,MAC,Requant,...}级 (n-st<k>),寄存器 (n-r<k>)
nocrows, cols, nocpe(true/false)路由器 (n-n<r>-<c>),PE (n-pe<r>-<c>)
fabriccolumns={I,C,C,D,C,B,...}, fabricrows(任意值)列顶部 (n-c<k>)。C=CLB D=DSP B=BRAM U=URAM I=IO
legendlegend={comp/Compute,mem/BRAM,...}(角色:io comp quant const op mem ctrl group);自动间距—

导线应绕过图片布线(例如,从下方进入 shim 瓦片:(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 heredoc、sed 或 Python 字符串字面量:这些工具经常将 \\ 变成 \(或将 \c... 变成控制字符)并破坏节点文本中的换行符。
  • label= 文本中的冒号或逗号会破坏键解析——用花括号括起来:label={[grouplabel]above:{INT8: shifts}}。
  • fit= 列表不能包含 ($(a)+(1,2)$)(逗号会分割列表);先定义一个命名的 \coordinate。
  • 要在节点内添加额外行,请使用带有 align=center 和 \\[-2pt]{\tiny ...} 的普通节点——不要在盒子上叠加第二个标签。
  • shapes.geometric 的 trapezium 在文本为空时会除以零——这就是为什么 mux/demux 是自定义路径图片;不要将它们改回去。
  • 在 \foreach 内部,在节点名称中使用值之前,使用 \pgfmathtruncatemacro 进行整数算术;在 \foreach \a/\b in {...} 中,标签文本内部的 / 会分割它(写成 Port,而不是 I/O)。
  • clkdomain 具有浅色填充;当它在 fabric 或其他密集内容上绘制时,传递 fill=none。
  • MiKTeX 忽略 POSIX 风格的 TEXINPUTS;将 hwfig.sty 放在 .tex 旁边(或传递 --include-directory=<windows path>)。
  • 对于使用 \footnotesize 的双栏论文,将图形宽度保持在约 16 cm 以内;仅作为最后手段使用 \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};

  % 布线层级
  \def\chan{6.7}    % PL 和 AIE 区域之间的垂直通道
  \def\lvla{-1.7}   % mm2s -> AIE,在 AIE 框架下方
  \def\lvlb{-2.3}   % AIE -> s2mm,再低一层(= s2mm 行)

  \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:向右进入通道,向下,沿层级 a,向上进入 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:向下到层级 b,向左到 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 打包。

相关技能