FPGA基础 -- Verilog 行为级建模之过程性结构
Verilog 中的“过程性结构(Procedural Constructs)”**,这是行为级建模的核心内容之一。
一、什么是过程性结构(Procedural Constructs)
过程性结构是 Verilog 中用来描述“按顺序执行”的语句块,通常出现在 always
或 initial
块中。与数据流建模(assign
)的并行逻辑不同,过程性结构是一种顺序执行的行为描述方式,更贴近软件语言中的过程控制逻辑。
二、基本过程性结构分类
类型 | 关键字 | 用途 |
---|---|---|
顺序结构 | begin ... end | 组织多个语句顺序执行 |
条件结构 | if / if-else / case | 条件分支 |
循环结构 | for / while / repeat / forever | 多次执行语句块 |
并发结构 | fork ... join (仿真用) | 并发执行(testbench 中) |
注意:综合工具仅支持有限子集,如
for
和if/case
的结构。while
、repeat
、forever
、fork
一般只用于 testbench。
三、顺序结构:begin
… end
✅ 示例
always @(posedge clk) begina <= b;c <= d;
end
- 多个语句按顺序执行;
- 可嵌套使用。
四、条件结构详解
4.1 if
/ else
always @(posedge clk) beginif (en)q <= d;elseq <= 0;
end
4.2 多级嵌套 if-else if
if (a == 2)y <= 1;
else if (a == 3)y <= 2;
elsey <= 0;
⚠️ 注意:避免未完全覆盖条件会导致 latch 推断(不综合安全)
4.3 case
结构
case (sel)2'b00: y = a;2'b01: y = b;default: y = c;
endcase
casex
和 casez
类型 | 支持通配符 | 示例 | 用途 |
---|---|---|---|
casex | x / z 都匹配 | casex(sel) | 适用于 don’t care |
casez | 只 z 匹配 | casez(sel) | 保留 x 作为明确值 |
⚠️ 综合建议:
- 尽量使用
case
或casez
; - 始终写
default
分支; - 否则容易推断不完整组合逻辑(=> latch)。
五、循环结构详解
5.1 for
循环(唯一综合安全的循环)
integer i;
always @(posedge clk) beginfor (i = 0; i < 4; i = i + 1)sum[i] <= sum[i] + data[i];
end
综合时的行为:
综合工具会将循环展开为多个并行语句,所以 for
的次数必须是常数。
5.2 while
、repeat
、forever
仅用于仿真(initial block / testbench):
// while
while (a < 5) a = a + 1;// repeat
repeat (10) @(posedge clk) $display("Tick");// forever
forever beginclk = ~clk;#5;
end
六、组合逻辑中的过程性结构写法
组合逻辑 always 块写法建议:
always @(*) begincase (op)2'b00: y = a + b;2'b01: y = a - b;default: y = 0;endcase
end
⚠️ 注意事项:
- 输入变化全部列入
@(*)
; - 所有输出变量都要在所有路径中赋值;
- 否则综合工具会推断 latch(存储器件),不符合组合逻辑预期。
七、阻塞与非阻塞赋值的过程性差异
7.1 阻塞赋值 =
- 左右同步执行,常用于组合逻辑
- 有“顺序”语义(会等待执行完当前语句才继续)
a = b;
c = a; // 此处使用的是 b 的值
7.2 非阻塞赋值 <=
- 同步赋值,常用于时序逻辑(寄存器更新)
- 在时钟沿之后,所有赋值同时生效
a <= b;
c <= a; // 下一时钟时刻才会看到上一个周期的 b 和 a
综合建议:
场景 | 建议赋值方式 |
---|---|
时序逻辑(always @(posedge clk)) | 非阻塞赋值 (<= ) |
组合逻辑(always @(*)) | 阻塞赋值 (= ) |
八、综合常见错误总结
错误写法 | 问题 | 建议 |
---|---|---|
if /case 不完整 | 推断 latch | 加 default 分支或完整条件覆盖 |
混用 = 与 <= | 时序混乱 | 按规则区分阻塞/非阻塞 |
@(*) 中漏信号 | 组合逻辑更新不全 | 保证包含所有输入变量 |
使用 while / repeat | 不可综合 | 仅用于 testbench |
九、Testbench 中的过程结构支持
在 testbench 中,过程结构提供仿真流程控制:
initial beginrst_n = 0;#20 rst_n = 1;
endalways #5 clk = ~clk; // forever loop 替代
还可结合 fork ... join
实现并发仿真:
initial forkbegin #10 a = 1; endbegin #15 b = 1; end
join
十、实战建议与进阶方向
-
实践推荐:
- 先用组合逻辑练习
if
/case
; - 再通过寄存器实现
always @(posedge clk)
; - 理解
for
在综合后是硬件资源复制。
- 先用组合逻辑练习
-
配合写 Testbench
- 结合
initial
与forever
模拟时钟; - 观察行为过程性赋值的执行顺序。
- 结合
-
进阶探索:
- SystemVerilog
always_comb
/always_ff
精准区分组合与时序; - 掌握行为模型的
task
/function
拆解方式。
- SystemVerilog