FPGA基础 -- Verilog行为级建模之alawys语句
Verilog 中的 always
语句块,这是行为级建模的核心结构之一,在 RTL 级设计中广泛用于时序逻辑和组合逻辑的建模。
一、什么是 always
语句?
✅ 定义:
always
语句用于描述可综合的硬件行为逻辑,表示一个**“事件驱动”的过程块**,当敏感列表中某个信号发生变化时,always
块会立即触发执行。
二、基本语法格式
always @(sensitivity_list)begin// 过程性代码end
sensitivity_list
是触发该块执行的信号列表。
三、分类:三种常见 always
使用方式
类型 | 敏感列表 | 用途 | 典型应用 |
---|---|---|---|
时序逻辑 | posedge clk / negedge rst_n | 同步逻辑 | 寄存器建模、状态机 |
组合逻辑 | (*) 或所有组合信号列出 | 无时序行为 | 算术逻辑单元(ALU) |
异步逻辑 | posedge clk or negedge rst | 异步复位结构 | 上电初始化控制 |
四、时序逻辑建模(推荐使用方式)
4.1 同步复位寄存器建模:
always @(posedge clk) beginif (!rst_n)q <= 0;elseq <= d;
end
✅ 非阻塞赋值
<=
,确保“并行硬件”的表达。
4.2 异步复位建模:
always @(posedge clk or negedge rst_n) beginif (!rst_n)q <= 0;elseq <= d;
end
✅
posedge clk or negedge rst_n
:表示rst_n
变化时立即响应。
五、组合逻辑建模
推荐使用 always @(*)
always @(*) begincase (sel)2'b00: y = a;2'b01: y = b;default: y = 0;endcase
end
✅ 使用
=
阻塞赋值。
✅ 确保对每个输出都完全赋值,否则综合工具会推断出 latch(锁存器)!
六、敏感列表详解
✅ 常见写法对比:
写法 | 解释 | 建议 |
---|---|---|
always @(a or b or c) | 显式列出每个信号 | ✅ 可控但冗长 |
always @(*) | 隐式敏感列表,表示所有用到的组合信号 | ✅ 推荐用于组合逻辑 |
always @(posedge clk) | 上升沿触发(时序逻辑) | ✅ 推荐用于寄存器 |
七、阻塞/非阻塞赋值回顾(重点)
场景 | 使用赋值类型 | 示例 |
---|---|---|
时序逻辑(同步时钟) | 非阻塞 <= | q <= d; |
组合逻辑 | 阻塞 = | y = a + b; |
⚠️ 错误示例:混用赋值类型
always @(posedge clk) begina = b; // ❌ 错误:阻塞赋值在时序逻辑中易引发竞态c <= a; // 实际 c 得到的是旧值,不是当前周期的 b
end
八、综合注意事项(总结)
误用 | 影响 | 修正建议 |
---|---|---|
@(*) 中漏掉信号 | 可能漏更新,综合错误 | 使用 @(*) 自动推导 |
混用 = 与 <= | 引起竞态与不符合意图 | 遵循赋值语义规则 |
不完全赋值 | 可能推断 latch | 加默认路径 / default 分支 |
变量多处被赋值 | 冲突或竞态 | 避免变量在多个 always 中赋值 |
九、典型设计范式:分离时序与组合逻辑
// 状态寄存器
always @(posedge clk or negedge rst_n)if (!rst_n) state <= IDLE;else state <= next_state;// 下一状态逻辑
always @(*) begincase (state)IDLE: if (start) next_state = RUN;RUN: if (done) next_state = IDLE;default: next_state = IDLE;endcase
end
✅ 这是 FSM 设计的推荐结构:组合逻辑决定 next_state,时序逻辑更新 state。
十、仿真辅助结构(testbench 中的 always
)
always #5 clk = ~clk; // 每 5ns 翻转一次
- 通常用于生成仿真用时钟;
- 非综合代码,仅用于
initial
或 testbench。
十一、拓展:SystemVerilog 中的 always_ff
/ always_comb
类型 | SystemVerilog 替代 | 特点 |
---|---|---|
时序逻辑 | always_ff | 自动检查敏感列表,防止误用 |
组合逻辑 | always_comb | 自动推导敏感列表 |
✅ 更强语义检查,更安全可维护,但需要 SystemVerilog 工具支持。
十二、实战示例总结:组合 + 寄存器 + 状态机
// 组合逻辑:计数器是否达到最大值
always @(*) begindone = (cnt == 15);
end// 时序逻辑:计数器累加
always @(posedge clk or negedge rst_n) beginif (!rst_n)cnt <= 0;else if (en)cnt <= cnt + 1;
end
小结
内容 | 核心要点 |
---|---|
语义 | always 块是硬件中的过程行为 |
时序建模 | 使用 posedge clk + 非阻塞赋值 |
组合建模 | 使用 @(*) + 阻塞赋值,完整赋值 |
综合约束 | 不可在综合逻辑中使用 #延迟 等 |
推荐实践 | 将时序逻辑与组合逻辑分离建模,提高可读性与综合效果 |