序章 · 铸器堂
咒语之门 · 抽象层次反直觉挑战
同一块电路的五种面目——你设计的是什么?
铸器堂的门没有锁。推开它,你看见的不是图纸、不是器件、不是面包板。是一面墙,墙上刻满了字。
诺依曼老祖站在墙边,手里没有图纸,只有一支笔。「你之前的设计,画在纸上,就是一张纸。刻进硅里,要多少道工序?」你还没回答,墙上那些字忽然亮了——一行 module 底下长出了线、长出了门、长出了触发器,最后长出了一整座处理器。
诺依曼老祖
「从今天起,你不画了。你写。但先告诉我——同一块电路,从系统级到晶体管级,你看到的是同一个东西吗?哪一层最重要?」
抽象层次反直觉挑战 · 五层下探
拖动滑块逐层下探,走完系统→行为→RTL→门→晶体管五层。每层代码不同,电路不同——但都是同一块电路。
层次
系统级
assign y = a & b
assign y = a | b
点选运算符,看门级电路实时变化。走完五层解锁下一幕。
你刚拖过的五层,是同一块电路的五种面目。HDL 不是在画图——它是在用语言铸造一座可以从任何层次审视的硬件。画图即设计的自信,在此裂开第一道缝。
拿笔写下第一个 module
第一幕 · 自信
module 初铸 · 骨架拼装
module 不是函数——它是芯片的壳
笔尖触墙的瞬间,字开始自己排列。老祖的声音在耳边:「先造一个壳。module——你的一切设计都装在里面。」墙上浮出一个空壳的轮廓:module ___ ( ___ ); endmodule
诺依曼老祖
「名字,端口,方向。三样东西,你来填。module 不是函数——函数被调用、执行、返回。module 被实例化,像芯片被焊在板上,端口就是引脚。」
module 骨架拼装 · 从碎片池拖出正确的片段
按正确顺序点击碎片,拼出:module counter(input clk, input rst, output [3:0] count); endmodule
— 拼装区 —
端口方向实验 · 切换 clk 的方向看电路反应
clk → input
clk → output
端口方向接反——电路图红叉,下游全黑。端口不是标签,是方向。
module 不是函数。函数被调用、执行、返回。module 被实例化——像一块芯片被焊在板上,端口就是它的引脚。你填的不是参数列表,是引脚定义。
壳造好了 · 往里填什么骨头
第一幕 · 困惑
数据之骨 · wire/reg/integer/parameter
reg 是寄存器?这个名字会骗你到 Boss 战
壳是空的。老祖往里扔了四块骨头。「wire——线。reg——变量。integer——整数。parameter——参数。」你伸手去拿 reg,老祖按住你的手:「你知道 reg 是什么吗?」「寄存器?」你说。老祖摇头:「这个名字会骗你到 Boss 战。」
仿真幻影 · 低语
「reg 就是寄存器……你这么以为?我记下了。S9 见。」
数据类型归类 · 把四块骨头拖到正确场景
点击数据类型,再点击对应场景槽位,完成匹配。
reg 真相实验 · 同一个 reg 挂到两种 always 下
always @(*) 组合逻辑
综合结果:组合门 · 无触发器
always @(posedge clk) 时序逻辑
综合结果:触发器出现
同一个 reg——在组合逻辑里是线,在时序逻辑里才是寄存器。reg 不决定你造了什么,always 的敏感列表才决定。
reg 不决定你造了什么。always 的敏感列表才决定。reg 只是说"我在 always 里被赋值"——至于是线还是寄存器,要看你写的 always 是组合的还是时序的。这个名字是 Verilog 最大的谎言。
骨头有了 · 让信号动起来
骨架搭好了。老祖递给你两把锤子:「assign——连续赋值。always——行为块。」你接过 assign,写下三行:assign x = a & b; assign y = x | c; assign z = y ^ d; 你以为 x 先算完,再传给 y,再传给 z。信号波形弹出来的瞬间,你的手停了。三行同时生效。没有先后。
仿真幻影 · 低语
「你在 always 里用软件思维排序?我记下了。这笔账 S9 翻。」
执行顺序实验 · 三行 assign 的波形
三行 assign 看似有依赖关系,但它们同时生效。拖动时间轴观察。
时间
t=0
assign vs always 对照
三行 assign(并发)
assign x = a & b;
assign y = x | c;
assign z = y ^ d;
// 三行同时生效,无先后
always @(*) 块(块内顺序,块间并发)
always @(*) begin
x = a & b; // 先执行
y = x | c; // 后执行(阻塞)
z = y ^ d;
end
// 块内顺序,多个 always 块间并发
assign 是永不断的线,always 是永远转的作坊。程序一行行走,城市同时活。
你以为你在写程序。不。你在描述一座城——assign 是永不断的线,always 是永远转的作坊。程序一行行走,城市同时活。你用写程序的脑子写城市,城市就会用地震回报你。
没有顺序的代码 · 怎么写出可综合的硬件
并发的震荡还没散,老祖递来新工具。「RTL——寄存器传输级。你写 if-else,写 case,写 for。但记住:你写的每一行,都要能变成门和触发器。」你接过工具,写了一个选择器:always @(*) begin if (sel) y = a; end 老祖看着你没写 else 的那行代码,没说话。综合结果的弹窗亮了。你看见了不该有的东西。
诺依曼老祖
「仿真器说'没赋值就保持原值',它觉得你在乎稳定性。综合器说'保持原值就要存住它,存住它就要锁存器'——你没要的东西,它给你造了。」
if-else / case 编辑器 · 切换有无 else/default
if (sel) y = a; (无 else)
if (sel) y = a; else y = b;
case 无 default
case 有 default
always @(* ) begin
if (sel) y = a;
end
⚠ 综合结果:推断锁存器(inferred latch)—— y 上挂了一颗你从未设计过的锁存器
仿真不报的,综合来收。组合逻辑的 if-else 必须完备、case 必须有 default。
仿真器说"没赋值就保持原值",综合器说"保持原值就要锁存器"。你没要的东西,它给你造了。仿真不报的,综合来收——这就是仿真幻影的第一个据点。
RTL 代码下面 · 到底长着什么门
老祖让你低头看脚下。你写的 RTL 代码浮在空中,底下投出影子——影子里全是门。「你写的每一行 assign,下面是两个 NOT、两个 AND、一个 OR。」他递给你一把放大镜:「自己拆。」
诺依曼老祖
「你以为你写的是代码。不,你写的是一整座门阵列。RTL 是它的名字,门级是它的骨骼。综合不是翻译——是铸造。」
RTL→门级映射放大镜 · 逐行扫描
选择一行 RTL 代码,查看其门级网表展开。
assign y = a & b
assign y = sel ? a : b
assign y = (a & b) | c
assign y = a & b → 1× AND 门
ALU 实例化 · 4 位 ALU 综合展开
点击下方按钮综合 4 位 ALU(add/sub/and/or)
▶ 综合 ALU
RTL 是门级网表的抽象名字。每行代码比你以为的重得多。
你以为你写的是代码。不,你写的是一整座门阵列。RTL 是它的名字,门级是它的骨骼。综合不是翻译——是铸造。
什么力量 · 让门阵列动起来
第二幕 · 再崩塌
时序之锁 · 仿真初值 ≠ 硬件初值
没有复位的触发器,上电时是垃圾
你在门阵列里穿行,忽然脚下的线全停了。所有信号冻结——没有时钟,门阵列只是一堆死石头。老祖的声音从很远传来:「要让它动,你需要一个心跳。」墙上浮出一行代码:always @(posedge clk) q <= d; 你照着写。波形弹出来——完美。然后你看见墙角站着一个影子。它没有脸,但它在笑。
仿真幻影 · 首次现身
「你忘了什么。上电的时候,q 里是什么?仿真器大方地给了你 0。我给你真相——unknown。你看见了吗?这就是我的脸。」
D 触发器建模 · 仿真 vs 综合后仿真
always @(posedge clk) q <= d; // 无复位
仿真波形
上电:q = 0(仿真器大方给的理想初值)
综合后仿真
上电:q = UNKNOWN (触发器未初始化)
修复 · 加异步复位
always @(posedge clk or posedge rst)
if (rst) q <= 0; // 复位清零
else q <= d;
仿真器大方地给了你初值 0。真实硬件不会。没有复位的触发器,上电时是垃圾。
仿真器大方地给了你初值 0。真实硬件不会。没有复位的触发器,上电时是垃圾。仿真不报的,硬件来收。这就是仿真幻影的第一张脸。
= 和 <= · 一字之差差的是什么
第二幕 · 核心危机
赋值之殇 · 阻塞 vs 非阻塞
仿真全绿 · 综合后分道扬镳
仿真幻影的最后一句话还在回响。老祖递来两面镜子,一模一样的代码,唯一区别是一个用 =,一个用 <=。「同一个 always @(posedge clk),同一个逻辑。你告诉我,哪个对。」你看着两份仿真波形——完全一样。全绿。「都一样?」你说。老祖把镜子翻过来。背面是综合后的波形。两条线,分道扬镳。
仿真幻影 · 彻底显形
「你终于看见我了。你的代码在我的镜子里是完美的——但镜子外面呢?= 和 <= 的差距,就是仿真和综合的差距。这就是我的全部力量。」
双镜对比 · 翻转镜子看综合后真相
阻塞版 =
always @(posedge clk) begin
a = b; // a 立即更新
c = a; // c 拿到新 a
end
仿真:全绿 ✓
综合后:分叉 ✗(c 拿到新 a 还是旧 a 取决于布线延迟)
非阻塞版 <=
always @(posedge clk) begin
a <= b; // RHS 先求值
c <= a; // c 拿到旧 a
end
仿真:全绿 ✓
综合后:确定 ✓(c 确定拿到旧 a,与硬件一致)
🪞 翻转镜子 · 看综合后真相
规范铭刻 · 两条铁律
赋值铁律
铁律一:组合逻辑 always @(*) 用阻塞 =
铁律二:时序逻辑 always @(posedge clk) 用非阻塞 <=
混用者,仿真幻影食之
= 是"先算完再传",<= 是"同时采样同时更新"。翻转镜子看见真相后,刻下铁律。
= 是"先算完再传"——仿真器按你的代码顺序做。<= 是"同时采样同时更新"——这才是一组真实触发器在时钟沿的行为。你以为 = 和 <= 差不多。它们的差距,就是仿真和综合的差距。
裂缝怎么填 · 重构
第三幕 · 顿悟
重铸模块 · 模块化与三段式 FSM
裂缝不是被填上的——是被拆开的
你盯着那道裂缝。仿真幻影退了,但裂缝还在。老祖递来锤子和钉。「你之前写的代码,从头到尾堆在一个 module 里。一坨。拆开。」你把计数器拆成一个模块,把 ALU 拆成另一个模块,用端口把它们接起来。
诺依曼老祖
「你之前的状态机写在哪?一个 always 里?一段式。拆成三段——状态寄存器、次态逻辑、输出逻辑。时序段只用 <=,组合段只用 =,各走各的路。裂缝不是被填上的——是被拆开的。」
模块实例化 · 拖拽模块图标连接端口
ALU.a .b .op .result
── wire ──
Counter.clk .rst .count
▶ 连接端口
FSM 三段式重构 · 时序 / 组合 / 组合
第一段 · 状态寄存器(时序)
always @(posedge clk)
current_state <= next_state;
// 只用 <=
第二段 · 次态逻辑(组合)
always @(*)
case(current_state)
... // 只用 =
endcase
第三段 · 输出逻辑(组合)
always @(*)
case(current_state)
... // 只用 =
endcase
三段式把时序和组合分开——= 和 <= 各走各路。裂缝不是被填上的,是被拆开的。
一段式把状态、次态、输出混在一起——赋值方式也混在一起,= 和 <= 在同一个 always 里打架。三段式把时序和组合分开——时序段只用 <=,组合段只用 =,各走各的路。裂缝不是被填上的——是被拆开的。
怎么证明设计是对的 · 仿真靠得住吗
终幕 · 对决
仿真幻影 · 三问排除法收网
仿真通过了——但仿真靠得住吗?
你写完了 testbench。激励波形铺满屏幕,输出全绿。「仿真通过。」你说。镜子碎了。仿真幻影从碎镜中走出来,这一次它有了脸——你的脸。
仿真幻影
「你的代码在我的镜中完美无瑕。每一行都按你的意思执行,每一个波形都如你所愿。你为什么害怕把镜子换成现实?三问。答不上来,你就永远活在镜子里。」
诺依曼老祖
「你的刻痕,够用了。七道综合刻痕,逐道收网。」
渊账累计 0 笔 · 三问全对后清零
⚔ 应战 · 连渊三问
雾散 · 硬件之门
尾声 · 铸器之道
铸器之道 · 描述即设计
炼气六层 · 语言铸器 · 圆满
碎镜重组。你站在一面清澈的镜子前。镜中不是波形,是门——你写的每一行代码,都变成了真实的 AND、OR、D 触发器。老祖递来最后一组工具。「Verilog 是开始,不是终点。SystemVerilog 是它的进化。然后——FPGA。你的代码烧进去,变成真实的硬件在跑。最后——流程。规格、HDL、仿真、综合、验证。缺一步,仿真幻影就回来。」
诺依曼老祖
「你用语言铸造了硬件。但硬件——怎么变成一台机器?那是下一座山。」
知识图谱点亮 · 十六碎片排认知链
点击下方碎片,按因果顺序点亮认知链。
排错处会闪烁红光,提示该知识点依赖的前置知识。
SystemVerilog 三项进化
logic 替代 wire/reg
logic [7:0] data;
// 不再纠结 reg/wire
interface 端口打包
.bus(my_bus)
// 一行替代十行
assertion 断言
assert property (@(posedge clk)
!rst |-> count==0);
// 仿真器自动检查
FPGA 流程排序 · 拖动七张卡排成正确顺序
— 拖拽上方卡片到此处排序 —
方法论铭刻 · 五步流程 + 验证目标
数字设计方法论
规格 → 验证需求
HDL → 验证描述
仿真 → 验证行为
综合 → 验证可制造性
验证 → 验证一致性
描 述 即 设 计
炼气期全境回顾
ch01 数字逻辑基础
ch02 组合逻辑电路
ch03 时序逻辑电路
ch04 有限状态机
ch05 算法与复杂性
ch06 硬件描述语言
你从画图的人变成了写字的人。但图和字都不是硬件——它们是描述。真正的硬件在综合之后、在 FPGA 之上、在硅片之中。描述即设计——但描述不是终点,是起点。从描述到硬件,还有整座山要翻。
ch07 计算机组成 🔒(点亮全部图谱后开启)