¿Qué hace Figuras TikZ de hardware (hwfig v1.1)?
Usa esta habilidad siempre que el usuario quiera una figura de hardware en LaTeX/TikZ: flujo de datos de un kernel HLS/FPGA, una capa de red neuronal cuantizada, un diagrama de bloques de un SoC Versal/Zynq, arreglos de motores de IA (AIE), arreglos sistólicos, árboles de sumadores, pipelines, NoCs, jerarquías de memoria, dominios de reloj, planos de planta. La salida es siempre código TikZ editable más una vista previa compilada en PDF/PNG.
Flujo de trabajo
- Obtén el paquete. Copia
hwfig.stydel directorio base de esta habilidad al directorio de trabajo (a menos que el usuario ya tenga una copia — si la suya no tienev1.1en su línea\ProvidesPackage, ofrécete a actualizarla). Lee el archivo y cópialo byte por byte; nunca lo reescribas ni redefinas los estilos en línea — las paletas solo funcionan a través de los colores de rol. - Elige una paleta (por defecto
grey), ya sea como opción del paquete\usepackage[okabe]{hwfig}o con\hwpalette{...}en cualquier lugar (local al grupo, por lo tanto por figura):grey— predeterminado para impresión/revistas, refleja la plantilla de referencia (cajas de cómputo blancas, cuantizadores grises, constantes grises discontinuas).okabe— Okabe–Ito, segura para daltonismo, máximo contraste. Buena opción predeterminada para artículos a color.tol— Paul Tol muted, segura para daltonismo, más suave.nord— tonos fríos, para diapositivas.slate— azul grisáceo + malva + coral, combina con presentaciones científicas. Si el usuario no lo especifica, producegreyy ofrece una paleta de color; para comparar, compila la misma figura en varias paletas (un bucle\foreach \pal in {grey,okabe,...}{\hwpalette{\pal}...}dentro de un documentostandaloneda una página por cada una). Un nombre de paleta desconocido es un error grave.
- Dibuja el diseño en una cuadrícula primero (coordenadas
at (x,y)explícitas, paso de columna ~2.4 cm, filas ±1.4 cm), luego cablea. Las coordenadas explícitas son mejores quepositioningpara figuras de flujo de datos densas. - Compila como
\documentclass[tikz,border=4pt]{standalone}+\usepackage{hwfig}conpdflatex -interaction=batchmode -halt-on-error(con tiempo de espera;nonstopmodepuede colgarse), rasteriza conpdftoppm -r 110 -png, mira el PNG y corrige superposiciones (etiquetas sobre cables, cables que cruzan cajas, títulos que chocan, etiquetas de marco que tocan nodos) antes de entregar. Itera hasta que quede limpio. - Entrega el
.tex(cuerpo de la figura listo para pegar en un artículo), el.styy el PDF. Recuerda al usuario que en su artículo necesita\usepackage{hwfig}(o\usepackage[<paleta>]{hwfig}).
Gramática visual (mantenla consistente)
- Los datos fluyen de izquierda a derecha; la ruta principal se sitúa sobre un eje horizontal, las ramas paralelas arriba/abajo (±1.4 cm).
- Las constantes en tiempo de compilación (
ctime, caja discontinua) se sitúan directamente encima/debajo del bloque que configuran y se conectan condarr(flecha discontinua). - Cada bloque de cómputo que cambia de precisión va seguido de un
qbox(requantización/desplazamiento/saturación). - Las ramas se fusionan en un nodo
opcon cables de codo que se aproximan verticalmente:\draw[arr] (qr.east) -| ($(sum.north)+(0,0.32)$) -- (sum.north); - Ramas alternativas desde una fuente: una coordenada de bifurcación con un punto,
\fill[hwwire] (fork) circle (1.3pt);, luego codos|-hacia cada rama. - Usa
hotpara la ruta crítica/destacada,buspara caminos de datos anchos conpic[pos=.5]{buswidth=512},node[lbl,midway,above]{AXI4-S}para nombres de protocolo (lblboxcuando la etiqueta debe colocarse sobre cables que se cruzan). - Los marcos de agrupación van en la capa de fondo con
fit:\begin{scope}[on background layer]\node[group,fit=(a)(b),label={[grouplabel]above:PL}] {};\end{scope} - Dominios de reloj:
clkdomain(color de acento, discontinuo) oclkdomain=<color>; marca los cruces con un nodocdc. - Comienza cada imagen con
\begin{tikzpicture}[hw](establece la fuente\footnotesize, el ancho de línea, las puntas de flecha).
Enrutamiento y etiquetas (verifica estos en cada PNG)
- Espacios entre regiones. Deja ≥ 0.6 cm entre marcos adyacentes (Runtime | Message passing, PL | AIE). Los nodos, los
opde fusión y los cables nunca deben apoyarse en el borde de un marco — si un nodo no pertenece a ningún marco, dale espacio fuera de ambos. - Canales de enrutamiento. Los cables entre regiones corren en un canal vacío entre los marcos (defínelo:
\def\chan{6.7}), luego en su propio nivel horizontal debajo/encima del marco de destino (\def\lvla{-1.7}). Dos cables nunca comparten un nivel; mantén ≥ 0.3 cm entre un cable y cualquier borde de marco o lado de bloque paralelo, y ≥ 0.4 cm entre cables paralelos. - Las etiquetas solo van en segmentos libres. Pon
lbl/buswidthen un segmento que esté completamente en espacio vacío — nunca donde el cable cruce un borde de marco, y nunca a menos de ~0.2 cm de un bloque. Si el único tramo libre es vertical, rota la etiqueta para que se lea de abajo arriba:node[lbl,rotate=90,below]{AXI4-S}. En enlaces cortos usapic[pos=.35..0.4]para que el número se aleje del bloque de destino. - Segmentos explícitos para codos etiquetados.
-|/|-no pueden tomar una etiqueta en una pata elegida; escribe las esquinas explícitamente:(a.east) -- (\chan,ya) -- node[lbl,...]{X} (\chan,\lvla) -- (b.south|-{(0,\lvla)}) -- (b.south); - Matemáticas en etiquetas:
$W_{\mathrm{root}}$; etiquetas de dos líneas con\\(todos los estilos tienenalign=center).
Estilos de nodo (todos conscientes de la paleta)
| estilo | uso |
|---|---|
runtime | Entradas/salidas, puertos, tensores en tiempo de ejecución |
ctime | Constantes en tiempo de compilación: pesos, escalas, configuración |
hlsbox | Kernel de cómputo / función HLS / kernel AIE |
qbox | Cuantizador, requantización, desplazamiento+sat |
op | +, ×, max (círculo) |
mux, demux | Multiplexor (entradas al oeste, salida al este) / demultiplexor (espejo) |
mem, bram, uram | Búferes en chip |
fifo | Stream/FIFO |
reg / ff | Registro con cuña de reloj |
lut, dsp | Primitivas FPGA (dsp coloca una pequeña etiqueta "DSP" fuera de su esquina superior derecha — deja espacio) |
extmem | DDR / HBM (cilindro) |
cpu | PS / ARM / RISC-V (doble marco) |
host | CPU host (lado PCIe) |
xbar | Interconexión AXI / barra NoC (\rotatebox{90}{AXI IC}) |
router | Enrutador/conmutador NoC (diamante) |
pe | Elemento de procesamiento |
aie | Tile de motor de IA (núcleo + memoria local; etiqueta centrada en el núcleo) |
chip | Paquete/dado con pines |
port | Marcador de pin pequeño |
cdc | Sincronizador de cruce de dominio de reloj |
group, plregion, psregion, clkdomain | Marcos de fondo |
grouplabel, lbl, lblbox | Títulos de marco, etiquetas de cable (lblbox = fondo blanco) |
Estilos de borde: arr, darr, bus, hot. Marca de bus: pic[pos=.5]{buswidth=32} (número a la derecha de la marca) o buswidth'=32 (a la izquierda).
Pics paramétricos
Pasa opciones por pic — permanecen locales a ese pic, por lo que diferentes tamaños pueden compartir una imagen:
\pic (A) at (0,0) {aiearray={rows=2,cols=4}};. \hwset{key=value,...} establece valores predeterminados para el resto del ámbito actual. Los nodos internos son direccionables como (name-...).
| pic | claves | partes direccionables |
|---|---|---|
aiearray | rows, cols, dx, dy, tilelabel | tiles (n-t<r>-<c>) (r=1 abajo), shims (n-s<c>), marco (n-box) |
systolic | rows, cols | (n-pe<r>-<c>) (r=1 arriba) |
addertree | depth (2^depth entradas) | entradas (n-in<k>), sumadores (n-a<level>-<k>), salida (n-out) |
pipeline | labels={Load,MAC,Requant,...} | etapas (n-st<k>), registros (n-r<k>) |
noc | rows, cols, nocpe (verdadero/falso) | enrutadores (n-n<r>-<c>), PEs (n-pe<r>-<c>) |
fabric | columns={I,C,C,D,C,B,...}, fabricrows (cualquier valor) | partes superiores de columna (n-c<k>). C=CLB D=DSP B=BRAM U=URAM I=IO |
legend | legend={comp/Compute,mem/BRAM,...} (roles: io comp quant const op mem ctrl group); espaciado automático | — |
Enruta los cables alrededor de los pics (por ejemplo, hacia los tiles shim desde abajo: (k1.east) -- ++(0.9,0) |- ($(arr-s1.south)+(0,-0.35)$) -- (arr-s1.south)), nunca a través de los tiles.
Paletas personalizadas
No se necesitan internas @ — establece los 8 roles (dibujo, relleno) y los tres colores de cable:
\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}} % cable, cable constante, acento/caliente
\hwpalette{mine}
Mantén los rellenos ≤ 25% de tinte para que el texto negro siga siendo legible y verifica que la conversión a escala de grises aún separe los roles.
Errores comunes
- Escribe los archivos
.texcon la herramienta de escritura de archivos, no con heredocs de shell,sedo literales de cadena de Python: esos convierten\\en\(o\c...en caracteres de control) y rompen los saltos de línea en el texto del nodo. - Un signo de dos puntos o coma dentro del texto de
label=rompe el análisis de claves — ponlo entre llaves:label={[grouplabel]above:{INT8: shifts}}. - Una lista de
fit=no puede contener($(a)+(1,2)$)(la coma divide la lista); define primero una\coordinatenombrada. - Para una línea extra dentro de un nodo, usa un nodo simple con
align=centery\\[-2pt]{\tiny ...}— no superpongas una segunda etiqueta en la caja. shapes.geometrictrapeziumcon texto vacío divide por cero — por esomux/demuxson imágenes de trazado personalizadas; no los intercambies.- Dentro de
\foreach, usa\pgfmathtruncatemacropara aritmética de enteros antes de usar valores en nombres de nodos; en\foreach \a/\b in {...}una/dentro del texto de la etiqueta la divide (escribePort, noI/O). clkdomaintiene un relleno claro; pasafill=nonecuando lo dibujes sobre unfabricu otro contenido denso.- MiKTeX ignora
TEXINPUTSal estilo POSIX; manténhwfig.styjunto al.tex(o pasa--include-directory=<ruta de windows>). - Mantén las figuras con un ancho ≤ ~16 cm para un artículo de dos columnas a
\footnotesize; escala con\resizebox{\linewidth}{!}{...}solo como último recurso.
Ejemplo de referencia (capa GNN, la plantilla base)
\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}
Ejemplo de referencia (SoC Versal)
\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};
% niveles de enrutamiento
\def\chan{6.7} % canal vertical entre regiones PL y AIE
\def\lvla{-1.7} % mm2s -> AIE, debajo del marco AIE
\def\lvlb{-2.3} % AIE -> s2mm, un nivel más abajo (= fila 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: directamente al canal, hacia abajo, a lo largo del nivel a, hacia arriba al 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: hacia abajo al nivel b, izquierda a 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}
Código fuente del paquete
hwfig.sty (v1.1, de Pelayo Leguina, [email protected], LPPL 1.3c) se distribuye junto a este archivo. El registro de cambios, la galería y los ejemplos viven en el repositorio público hwfig; esta habilidad se mantiene allí bajo skill/ y se empaqueta con skill/package.sh.