FPGA基础 -- Verilog 行为级建模之过程性结构

Verilog 中的"过程性结构(Procedural Constructs)"**,这是行为级建模的核心内容之一。


一、什么是过程性结构(Procedural Constructs)

过程性结构是 Verilog 中用来描述"按顺序执行"的语句块,通常出现在 alwaysinitial 块中。与数据流建模(assign)的并行逻辑不同,过程性结构是一种顺序执行的行为描述方式,更贴近软件语言中的过程控制逻辑。


二、基本过程性结构分类

类型 关键字 用途
顺序结构 begin ... end 组织多个语句顺序执行
条件结构 if / if-else / case 条件分支
循环结构 for / while / repeat / forever 多次执行语句块
并发结构 fork ... join(仿真用) 并发执行(testbench 中)

注意:综合工具仅支持有限子集 ,如 forif/case 的结构。whilerepeatforeverfork 一般只用于 testbench。


三、顺序结构:begin ... end

✅ 示例

verilog 复制代码
always @(posedge clk) begin
    a <= b;
    c <= d;
end
  • 多个语句按顺序执行;
  • 可嵌套使用。

四、条件结构详解

4.1 if / else

verilog 复制代码
always @(posedge clk) begin
    if (en)
        q <= d;
    else
        q <= 0;
end

4.2 多级嵌套 if-else if

verilog 复制代码
if (a == 2)
    y <= 1;
else if (a == 3)
    y <= 2;
else
    y <= 0;

⚠️ 注意:避免未完全覆盖条件会导致 latch 推断(不综合安全)


4.3 case 结构

verilog 复制代码
case (sel)
    2'b00: y = a;
    2'b01: y = b;
    default: y = c;
endcase
casexcasez
类型 支持通配符 示例 用途
casex x / z 都匹配 casex(sel) 适用于 don't care
casez 只 z 匹配 casez(sel) 保留 x 作为明确值
⚠️ 综合建议:
  • 尽量使用 casecasez
  • 始终写 default 分支;
  • 否则容易推断不完整组合逻辑(=> latch)。

五、循环结构详解

5.1 for 循环(唯一综合安全的循环)

verilog 复制代码
integer i;
always @(posedge clk) begin
    for (i = 0; i < 4; i = i + 1)
        sum[i] <= sum[i] + data[i];
end
综合时的行为:

综合工具会将循环展开为多个并行语句 ,所以 for 的次数必须是常数。

5.2 whilerepeatforever

仅用于仿真(initial block / testbench):

verilog 复制代码
// while
while (a < 5) a = a + 1;

// repeat
repeat (10) @(posedge clk) $display("Tick");

// forever
forever begin
    clk = ~clk;
    #5;
end

六、组合逻辑中的过程性结构写法

组合逻辑 always 块写法建议:

verilog 复制代码
always @(*) begin
    case (op)
        2'b00: y = a + b;
        2'b01: y = a - b;
        default: y = 0;
    endcase
end

⚠️ 注意事项:

  • 输入变化全部列入 @(*)
  • 所有输出变量都要在所有路径中赋值;
  • 否则综合工具会推断 latch(存储器件),不符合组合逻辑预期。

七、阻塞与非阻塞赋值的过程性差异

7.1 阻塞赋值 =

  • 左右同步执行,常用于组合逻辑
  • 有"顺序"语义(会等待执行完当前语句才继续)
verilog 复制代码
a = b;
c = a; // 此处使用的是 b 的值

7.2 非阻塞赋值 <=

  • 同步赋值,常用于时序逻辑(寄存器更新)
  • 在时钟沿之后,所有赋值同时生效
verilog 复制代码
a <= b;
c <= a; // 下一时钟时刻才会看到上一个周期的 b 和 a
综合建议:
场景 建议赋值方式
时序逻辑(always @(posedge clk)) 非阻塞赋值 (<=)
组合逻辑(always @(*)) 阻塞赋值 (=)

八、综合常见错误总结

错误写法 问题 建议
if/case 不完整 推断 latch default 分支或完整条件覆盖
混用 =<= 时序混乱 按规则区分阻塞/非阻塞
@(*) 中漏信号 组合逻辑更新不全 保证包含所有输入变量
使用 while / repeat 不可综合 仅用于 testbench

九、Testbench 中的过程结构支持

在 testbench 中,过程结构提供仿真流程控制:

verilog 复制代码
initial begin
    rst_n = 0;
    #20 rst_n = 1;
end

always #5 clk = ~clk; // forever loop 替代

还可结合 fork ... join 实现并发仿真:

verilog 复制代码
initial fork
    begin #10 a = 1; end
    begin #15 b = 1; end
join

十、实战建议与进阶方向

  1. 实践推荐:

    • 先用组合逻辑练习 if / case
    • 再通过寄存器实现 always @(posedge clk)
    • 理解 for 在综合后是硬件资源复制。
  2. 配合写 Testbench

    • 结合 initialforever 模拟时钟;
    • 观察行为过程性赋值的执行顺序。
  3. 进阶探索:

    • SystemVerilog always_comb / always_ff 精准区分组合与时序;
    • 掌握行为模型的 task / function 拆解方式。
相关推荐
浩子智控6 小时前
电子设备DevOps
fpga开发
cycf18 小时前
CRC校验
fpga开发
landyjzlai19 小时前
AMBA总线(15)关于AXI-stream(sg模式)
arm开发·fpga开发·amba
白狐_79819 小时前
Quartus Prime 新手完全使用指南
fpga开发
Aaron15881 天前
三种主流接收机架构(超外差、零中频、射频直采)对比及发展趋势浅析
c语言·人工智能·算法·fpga开发·架构·硬件架构·信号处理
博览鸿蒙1 天前
一颗数字系统是如何在 FPGA 上“跑起来”的?
fpga开发
雨洛lhw1 天前
FPGA JTAG接口设计全解析
fpga开发·jtag
minglie12 天前
iverilog 配合 Makefile 搭建 Verilog 仿真工程
fpga开发
芒果树技术2 天前
MangoTree案例分享:基于AtomRIO FPGA平台,客户实现自适应主动减振
测试工具·fpga开发·模块测试
雨洛lhw2 天前
按键电路设计的细节
fpga开发