SICI · 天机门 · 第六章 · 炼气收官

硬件描述语言 · 炼气六层 · 语言铸器

用文字画电路不过是换种笔——这句话,仿真幻影说对了一半。

门楣刻字:「描述即设计,代码即铸造」
序章 · 铸器堂

咒语之门 · 抽象层次反直觉挑战

同一块电路的五种面目——你设计的是什么?

铸器堂的门没有锁。推开它,你看见的不是图纸、不是器件、不是面包板。是一面墙,墙上刻满了字。

微码之殿,微码翻译层

诺依曼老祖站在墙边,手里没有图纸,只有一支笔。「你之前的设计,画在纸上,就是一张纸。刻进硅里,要多少道工序?」你还没回答,墙上那些字忽然亮了——一行 module 底下长出了线、长出了门、长出了触发器,最后长出了一整座处理器。

诺依曼老祖 诺依曼老祖

「从今天起,你不画了。你写。但先告诉我——同一块电路,从系统级到晶体管级,你看到的是同一个东西吗?哪一层最重要?」

抽象层次反直觉挑战 · 五层下探

拖动滑块逐层下探,走完系统→行为→RTL→门→晶体管五层。每层代码不同,电路不同——但都是同一块电路。

📜
系统级
「一个加法器」
🧮
行为级
算法伪代码
📝
RTL级
always/assign
🔌
门级
AND/OR/NOT
晶体管级
MOS管阵列
层次 系统级
代码 / 描述
// 一个加法器:把两个数加起来
点选运算符,看门级电路实时变化。走完五层解锁下一幕。
你刚拖过的五层,是同一块电路的五种面目。HDL 不是在画图——它是在用语言铸造一座可以从任何层次审视的硬件。画图即设计的自信,在此裂开第一道缝。
第一幕 · 自信

module 初铸 · 骨架拼装

module 不是函数——它是芯片的壳

笔尖触墙的瞬间,字开始自己排列。老祖的声音在耳边:「先造一个壳。module——你的一切设计都装在里面。」墙上浮出一个空壳的轮廓:module ___ ( ___ ); endmodule

诺依曼老祖 诺依曼老祖

「名字,端口,方向。三样东西,你来填。module 不是函数——函数被调用、执行、返回。module 被实例化,像芯片被焊在板上,端口就是引脚。」

module 骨架拼装 · 从碎片池拖出正确的片段

按正确顺序点击碎片,拼出:module counter(input clk, input rst, output [3:0] count); endmodule

— 拼装区 —

端口方向实验 · 切换 clk 的方向看电路反应

端口方向接反——电路图红叉,下游全黑。端口不是标签,是方向。
module 不是函数。函数被调用、执行、返回。module 被实例化——像一块芯片被焊在板上,端口就是它的引脚。你填的不是参数列表,是引脚定义。
第一幕 · 困惑

数据之骨 · wire/reg/integer/parameter

reg 是寄存器?这个名字会骗你到 Boss 战

壳是空的。老祖往里扔了四块骨头。「wire——线。reg——变量。integer——整数。parameter——参数。」你伸手去拿 reg,老祖按住你的手:「你知道 reg 是什么吗?」「寄存器?」你说。老祖摇头:「这个名字会骗你到 Boss 战。」

仿真幻影 仿真幻影 · 低语

「reg 就是寄存器……你这么以为?我记下了。S9 见。」

数据类型归类 · 把四块骨头拖到正确场景

点击数据类型,再点击对应场景槽位,完成匹配。

wire
assign 连续赋值
reg
always 块赋值
integer
for 循环计数
parameter
编译期常量

reg 真相实验 · 同一个 reg 挂到两种 always 下

always @(*) 组合逻辑
综合结果:组合门 · 无触发器
always @(posedge clk) 时序逻辑
综合结果:触发器出现
同一个 reg——在组合逻辑里是线,在时序逻辑里才是寄存器。reg 不决定你造了什么,always 的敏感列表才决定。
reg 不决定你造了什么。always 的敏感列表才决定。reg 只是说"我在 always 里被赋值"——至于是线还是寄存器,要看你写的 always 是组合的还是时序的。这个名字是 Verilog 最大的谎言。
第一幕 · 崩塌

行为之惑 · 并发执行模型

三行 assign 同时生效——你的顺序大脑裂开了

骨架搭好了。老祖递给你两把锤子:「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 与锁存器

if 忘了 else——综合送你一颗你不需要的锁存器

并发的震荡还没散,老祖递来新工具。「RTL——寄存器传输级。你写 if-else,写 case,写 for。但记住:你写的每一行,都要能变成门和触发器。」你接过工具,写了一个选择器:always @(*) begin if (sel) y = a; end 老祖看着你没写 else 的那行代码,没说话。综合结果的弹窗亮了。你看见了不该有的东西。

诺依曼老祖 诺依曼老祖

「仿真器说'没赋值就保持原值',它觉得你在乎稳定性。综合器说'保持原值就要存住它,存住它就要锁存器'——你没要的东西,它给你造了。」

if-else / case 编辑器 · 切换有无 else/default

always @(*) begin if (sel) y = a; end
⚠ 综合结果:推断锁存器(inferred latch)—— y 上挂了一颗你从未设计过的锁存器
仿真不报的,综合来收。组合逻辑的 if-else 必须完备、case 必须有 default。
仿真器说"没赋值就保持原值",综合器说"保持原值就要锁存器"。你没要的东西,它给你造了。仿真不报的,综合来收——这就是仿真幻影的第一个据点。
第二幕 · 深入

门级与组合 · RTL 的骨骼

一行 assign 下面是四个 NOT、两个 AND、一个 OR

老祖让你低头看脚下。你写的 RTL 代码浮在空中,底下投出影子——影子里全是门。「你写的每一行 assign,下面是两个 NOT、两个 AND、一个 OR。」他递给你一把放大镜:「自己拆。」

诺依曼老祖 诺依曼老祖

「你以为你写的是代码。不,你写的是一整座门阵列。RTL 是它的名字,门级是它的骨骼。综合不是翻译——是铸造。」

RTL→门级映射放大镜 · 逐行扫描

选择一行 RTL 代码,查看其门级网表展开。

assign y = a & b → 1× AND 门

ALU 实例化 · 4 位 ALU 综合展开

点击下方按钮综合 4 位 ALU(add/sub/and/or)
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
仿真:全绿 ✓
非阻塞版 <=
always @(posedge clk) begin a <= b; // RHS 先求值 c <= a; // c 拿到旧 a end
仿真:全绿 ✓

规范铭刻 · 两条铁律

赋值铁律

铁律一:组合逻辑 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编码
🔬
仿真验证
综合映射
📍
布局布线
💾
比特流烧录
🔌
上板验证
— 拖拽上方卡片到此处排序 —

方法论铭刻 · 五步流程 + 验证目标

数字设计方法论

规格→ 验证需求
HDL→ 验证描述
仿真→ 验证行为
综合→ 验证可制造性
验证→ 验证一致性

炼气期全境回顾

ch01 数字逻辑基础
ch02 组合逻辑电路
ch03 时序逻辑电路
ch04 有限状态机
ch05 算法与复杂性
ch06 硬件描述语言
炼气六层 · 语言铸器 · 圆满 +100 XP
你从画图的人变成了写字的人。但图和字都不是硬件——它们是描述。真正的硬件在综合之后、在 FPGA 之上、在硅片之中。描述即设计——但描述不是终点,是起点。从描述到硬件,还有整座山要翻。
ch07 计算机组成 🔒(点亮全部图谱后开启)