3. Verilog HDL 基础与 RTL 设计:组合逻辑、时序逻辑、状态机与流水线
各位同学,咱们今天聊点硬核的。Verilog 这玩意儿,说白了就是硬件工程师的“普通话”。你写出来的每一行代码,最后都会变成实实在在的门电路和触发器。我见过不少新手,把 Verilog 当 C 语言写,结果综合出来的电路自己都看不懂。嗯,咱们今天就把这事掰扯清楚。
3.1 组合逻辑:信号一进来,输出立马变
组合逻辑的特点很简单:输出只取决于当前的输入。没有记忆,没有时钟,信号路径上走多快,输出就变多快。我在项目中遇到过最典型的组合逻辑就是地址译码器——地址线一变,片选信号立刻跟着跳。
Verilog 里描述组合逻辑,我习惯用 assign 连续赋值,或者 always @(*) 过程块。看个例子:
// 方式一:assign 连续赋值
assign sel = (addr >= 8'h20) && (addr <= 8'h2F) ? 1'b1 : 1'b0;
// 方式二:always 块(组合逻辑)
always @(*) begin
if (addr >= 8'h20 && addr <= 8'h2F)
sel = 1'b1;
else
sel = 1'b0;
end
3.2 时序逻辑:靠时钟吃饭,有记忆
时序逻辑就不一样了。它靠时钟沿干活,输出不仅看当前输入,还得看之前的状态。说白了,它是有记忆的。寄存器(flip-flop)是时序逻辑的基本单元。
我写时序逻辑,几乎只用 always @(posedge clk) 或者 always @(negedge clk)。复位方式我推荐同步复位,除非有特殊要求。为什么?因为异步复位容易引起亚稳态,我在调试一块 ISP 管线时就吃过这个亏——复位释放时刻刚好在时钟沿上,整个状态机跑飞了。
// 带同步复位的 D 触发器
always @(posedge clk) begin
if (rst_n)
q <= 1'b0;
else
q <= d;
end
<=。组合逻辑用阻塞赋值 =。这个规矩别打破,否则仿真和综合结果不一致,你查三天都查不出来。
3.3 有限状态机:ISP 控制逻辑的骨架
有限状态机(FSM)是数字设计的核心。ISP 管线里的曝光控制、增益切换、白平衡校准,背后全是状态机在调度。我习惯把状态机分成三段式来写:
- 第一段: 时序逻辑,描述状态跳转
- 第二段: 组合逻辑,描述下一状态的条件
- 第三段: 组合逻辑,描述输出
为什么用三段式?因为可读性强,综合出来的电路也干净。我曾经接手过一个项目,前任工程师把所有逻辑塞在一个 always 块里,状态机写得像意大利面条。我花了整整两天才理清楚。
// 三段式状态机示例
// 第一段:状态寄存器
always @(posedge clk or posedge rst) begin
if (rst)
state <= IDLE;
else
state <= next_state;
end
// 第二段:下一状态逻辑
always @(*) begin
case (state)
IDLE: next_state = start ? READ : IDLE;
READ: next_state = done ? PROCESS : READ;
PROCESS: next_state = done ? IDLE : PROCESS;
default: next_state = IDLE;
endcase
end
// 第三段:输出逻辑
always @(*) begin
case (state)
IDLE: data_valid = 1'b0;
READ: data_valid = 1'b0;
PROCESS: data_valid = 1'b1;
default: data_valid = 1'b0;
endcase
end
3.4 流水线设计:用面积换速度
流水线是 ISP 硬件加速的灵魂。你想想看,一个像素处理要经过黑电平校正、去噪、白平衡、颜色插值……如果每个模块都串行做,一帧图像要等多久?流水线的思路就是:把一个大任务拆成多个小阶段,每个阶段用寄存器隔开,所有阶段同时工作。
我举个例子。假设一个简单的加法链:a + b + c + d。非流水线实现需要三级加法,每级都要等上一级算完。流水线实现就是:
// 非流水线
always @(posedge clk)
sum <= a + b + c + d; // 组合路径太长,时序容易崩
// 三级流水线
reg [7:0] sum1, sum2;
always @(posedge clk) begin
sum1 <= a + b; // 第一级
sum2 <= sum1 + c; // 第二级
sum <= sum2 + d; // 第三级
end
流水线每级只做一点点事,路径短,频率就能跑高。代价是多了几级寄存器,还有 3 个时钟周期的延迟。在 ISP 里,这种延迟完全可以接受——你想想看,一帧图像有几百万个像素,流水线填满后,每个时钟周期都能出一个结果。
3.5 知识体系总览
下面这张图把本章的核心逻辑串起来了。你仔细看看,组合逻辑和时序逻辑是基础,状态机管控制,流水线管加速——三者配合,才能搭出高效的 ISP 硬件。
3.6 实战建议:从代码到电路
最后给你几条实在的建议:
- 写代码前先画电路: 我习惯在纸上先画出寄存器、多路选择器、加法器,再动手写 Verilog。代码是电路的描述,不是软件逻辑。
- 仿真看波形: 别只盯着 log 文件。打开波形图,看看每个时钟沿数据对不对。我调试 ISP 管线时,90% 的问题都是看波形发现的。
- 综合后看报告: 看看工具给你推断了多少寄存器、多少 LUT。如果综合出来的电路跟你预期不一样,那代码肯定有问题。