本文档定义了在 LLD(底层设计)文档中创建、复用和发布 FPGA 时序图的标准工作流程。目标是实现所有 FPGA 子项目的一致性,并通过模板复用实现零成本的图表编写。
ip_common/doc/timing/ 中的现有图表开始。这保证了仓库中每份设计文档的信号命名约定、时钟域符号和视觉风格一致。
ip_common/doc/timing/
├── _templates/
│ ├── axi4-stream.wave.json # AXI4-Stream 握手(TVALID/TREADY/TDATA)
│ ├── axi4-lite.wave.json # AXI4-Lite 读写事务
│ ├── avalon-mm.wave.json # Avalon-MM 突发读取
│ ├── spi-master.wave.json # SPI 主机(CPOL=0, CPHA=0)
│ ├── i2c-read.wave.json # I2C 读事务
│ ├── uart-frame.wave.json # UART 8N1 帧
│ ├── memory-rw.wave.json # 简单内存读写(addr/rden/wren/rdata/wdata)
│ ├── pipe-valid.wave.json # 通用 valid/ready 流水线阶段
│ └── reset-release.wave.json # 异步复位解除 + PLL 锁定
├── README.md # 模板使用指南
└── Makefile # 批量渲染所有模板为 SVG
# 第 1 步:选择最接近的模板
ls ip_common/doc/timing/_templates/
# 第 2 步:拷贝到你的模块文档目录中
cp ip_common/doc/timing/_templates/axi4-stream.wave.json \
my_module/doc/timing/my_module_tx.wave.json
# 第 3 步:在 JSON 中仅编辑信号名称(不改变结构)
vim my_module/doc/timing/my_module_tx.wave.json
编辑时,遵循以下规则:
| 可以修改的内容 | 必须保留的内容 |
|---|---|
信号名称(如 m_axis_tdata 改为 s_axis_tdata) |
信号排列顺序(先 clk,再控制信号,最后数据信号) |
| 数据通道数量(如 8 位改为 32 位) | 时钟周期 / tick 间距 |
| Testbench 实例前缀 | wavedrom 根结构 |
颜色提示(每个信号的 #RRGGBB 值) |
阶段标签(Cfg、Wait、Burst) |
{
"signal": [
{ "name": "clk", "wave": "p......", "period": 2 },
{ "name": "reset_n", "wave": "0.1...." },
{ "name": "valid", "wave": "0.10..1", "node": ".A.B..C" },
{ "name": "ready", "wave": "1.0.10." },
{ "name": "data[7:0]", "wave": "x.=.=.x", "data": ["A5", "3C", "F0"] }
],
"head": { "text": "My Module: Write Transaction" },
"foot": { "text": "tick = 10 ns", "tock": 1 }
}
| 字符 | 含义 |
|---|---|
p |
正时钟沿(clk 前半周期为高) |
n |
负时钟沿 |
P |
正时钟沿带箭头 |
N |
负时钟沿带箭头 |
0 |
低电平(逻辑 0) |
1 |
高电平(逻辑 1) |
x |
无关/未知(灰色填充) |
z |
高阻态(三态,中间虚线) |
= |
数据总线(该 tick 取 data 数组中的值) |
2 |
值为 2 的数据总线 |
3, 4, 5 |
= 的彩色变体(谨慎使用) |
. |
重复上一个状态 |
| |
间隙分隔符(跳过半个 tick) |
{
"signal": [
{ "name": "aclk", "wave": "p..............", "period": 2 },
{ "name": "aresetn", "wave": "0.1............" },
{ "name": "s_axis_tvalid", "wave": "0.....10..10...", "node": "..A....B..C.D" },
{ "name": "s_axis_tready", "wave": "1..0..10.10.10." },
{ "name": "s_axis_tdata", "wave": "x..=.=.=.=.=.=.",
"data": ["D0", "D1", "D2", "D3", "D4", "D5"] },
{ "name": "s_axis_tlast", "wave": "0.............10" },
{ "name": "s_axis_tkeep", "wave": "x..=.=.=.=.=.=.",
"data": ["FF", "FF", "FF", "FF", "FF", "0F"] }
],
"head": { "text": "AXI4-Stream: 5-beat Burst with Backpressure" },
"foot": { "text": "Burst length = 5; D4 triggers backpressure deassertion on TREADY" },
"edge": ["A~>B TREADY deasserts", "C->D TREADY reasserts"],
"config": { "hscale": 1.5 }
}
"edge": [
"P->Q Clock crossing event",
"A~>B Setup time check",
"C-~>D Hold time check",
"E->F Propagation delay: 3.2 ns max"
]
边沿符号:->(实线箭头)、~>(虚线箭头)、-~>(点线箭头)。
| 图表类型 | 工具 | 理由 |
|---|---|---|
| 时序波形(信号随时间变化) | Wavedrom | 专为数字时序设计 |
| 框图、架构图 | Mermaid(flowchart/graph) | 自动布局整洁 |
| 状态机 | Mermaid(stateDiagram) | 标准 UML 符号 |
| 序列图 | Mermaid(sequenceDiagram) | 模块交互流程 |
| 流水线阶段 | Mermaid(graph LR) | 从左到右的数据流 |
wavedrom 代码块):
%%FENCED_5%%wavedrom
{
"signal": [
{ "name": "clk", "wave": "p...." },
{ "name": "data", "wave": "x.=.x", "data": ["A5"] }
]
}
%%FENCED_6%%
Mermaid(使用 mermaid 代码块):
%%FENCED_7%%mermaid
sequenceDiagram
participant CPU
participant DMA
participant DDR
CPU->>DMA: Configure descriptor
DMA->>DDR: Read burst (4 beats)
DDR-->>DMA: Return data
DMA->>CPU: IRQ: transfer done
%%FENCED_8%%
%%FENCED_9%%mermaid
graph TB
subgraph clk_100MHz ["Domain: 100 MHz"]
TX[TX FSM]
FIFO_W[Async FIFO<br/>Write Side]
end
subgraph clk_150MHz ["Domain: 150 MHz"]
FIFO_R[Async FIFO<br/>Read Side]
RX[RX FSM]
end
TX -->|wr_data[31:0]| FIFO_W
FIFO_W -.->|CDC crossing| FIFO_R
FIFO_R -->|rd_data[31:0]| RX
%%FENCED_10%%
md2html 工具可以在一次处理中同时完成 Wavedrom 和 Mermaid 的渲染:
# 安装 md2html 工具(如果尚未安装)
cd /home/user/tools/
git clone https://github.com/BuckHuang/md2html.git
cd md2html && make install
# 转换单个 .md 文件(自动检测 Wavedrom + Mermaid 代码块)
md2html my_module/doc/my_module_lld.md
# 转换目录树中的所有 .md 文件
md2html --recursive my_module/doc/
# 输出到指定目录
md2html my_module/doc/my_module_lld.md -o /var/www/html/docs/
# 监视模式(保存时自动转换)
md2html --watch my_module/doc/
`wavedrom 和 `mermaid 代码块wavedrom-cli 将 Wavedrom JSON 渲染为 SVGmermaid-cli(mmdc)将 Mermaid 图表渲染为 SVG
my_module/doc/
├── timing/
│ ├── my_module_rx.wave.json # Wavedrom 源文件(可编辑)
│ └── my_module_tx.wave.json
├── images/
│ ├── block_diagram.mmd # Mermaid 源文件(可编辑)
│ └── state_machine.mmd
├── my_module_lld.md # 主设计文档(引用以上文件)
└── html/ # 生成的输出(提交以供审查)
└── my_module_lld.html
> 每次编辑 Markdown 文档,必须将版本号递增 1 并更新时间戳。
这适用于 doc/ 目录下或任何用于 HTML 渲染目录下的所有 .md 文件。
将此内容放在每份文档的顶部,紧跟标题之后:
> **Version:** 3 | **Date:** 2026-07-24 | **Author:** huanghm
每次进行任何编辑后,将 Version 递增 1,并将 Date 更新为当天日期。
修改前:
> **Version:** 3 | **Date:** 2026-07-20 | **Author:** huanghm
修改后(例如,修复了 Wavedrom 代码块中的信号名称):
> **Version:** 4 | **Date:** 2026-07-24 | **Author:** huanghm
#!/bin/bash
# /home/user/tools/bump-version.sh
# 用法: bump-version.sh my_doc.md
FILE="$1"
if [ ! -f "$FILE" ]; then
echo "Usage: bump-version.sh <markdown-file>"
exit 1
fi
TODAY=$(date +%Y-%m-%d)
# 匹配版本行并递增版本号
sed -i -E "s/\*\*Version:\*\* ([0-9]+)/\*\*Version:\*\* $(( \1 + 1 ))/" "$FILE"
# 更新日期
sed -i -E "s/\*\*Date:\*\* [0-9]{4}-[0-9]{2}-[0-9]{2}/\*\*Date:\*\* $TODAY/" "$FILE"
echo "Bumped $(basename "$FILE") to version $(grep -oP 'Version:\*\* \K[0-9]+' "$FILE")"
| 症状 | 原因 | 修复方法 |
|---|---|---|
| Wavedrom 渲染为空白框 | JSON 语法错误(缺少逗号/花括号) | 使用 python -m json.tool file.wave.json 验证 |
| Mermaid 图表不渲染 | mmdc 未安装 | npm install -g @mermaid-js/mermaid-cli |
| 边沿箭头方向错误 | 节点标签 A、B 等未按顺序排列 |
从左到右重命名节点 |
| HTML 输出缺少图表 | Wavedrom/Mermaid 代码块未被识别 | 检查代码块标签是否精确使用了 wavedrom 或 mermaid |
| HTML 中 SVG 太小 | 内联 SVG 缺少 viewBox | 在 Wavedrom JSON 中添加 "config": { "hscale": 2 } |