既然always_ff等价于always @(posedge clk),为何还要写前者?
关于SystemVerilog中always_ff与always @(posedge clk)的疑问解答
为什么要写
always_ff @(posedge clk)而不是只用always @(posedge clk)?always_ff是SystemVerilog新增的显式时序逻辑块声明,和传统的always @(posedge clk)相比,它能让综合、lint工具做更严格的语法检查:- 强制这个块只能用于时序逻辑,不允许在里面写组合逻辑的违规操作(比如在块内修改输入信号、用阻塞赋值实现组合逻辑等);
- 敏感列表只能包含时钟(可选加异步复位),避免你不小心写错敏感列表(比如漏加复位信号)却没被工具及时发现。
简单说,always_ff就是给工具和读代码的人明确划界:“这块是纯时序逻辑,别乱搞”,从编码层面减少人为失误。
为什么要区分不同的always结构?
SystemVerilog把always块拆成always_ff(时序)、always_comb(组合)、always_latch(锁存器),核心原因有两个:- 可读性拉满:别人看代码不用去翻敏感列表和赋值方式,一眼就知道这个块的逻辑类型;
- 工具检查更精准:比如
always_comb会自动推断完整的敏感列表,还会检查是否有意外生成锁存器的风险;always_latch则专门用于声明锁存器逻辑,避免工具误优化。
传统的always块是隐式的,工具和人都得自己判断逻辑类型,很容易埋下bug。
有没有
always @(posedge clk)不生成触发器的情况?
有,而且大多是不规范写法导致的:- 比如在时钟敏感块里直接把输入信号组合后赋值给输出,完全没有状态存储需求——比如:
这种逻辑里,out的值只依赖当前时钟沿的输入,不需要保留上一周期的状态,综合工具会直接优化成组合逻辑,不会生成触发器,但这属于错误的编码方式,时序块的设计初衷就是用来做状态存储。always @(posedge clk) begin out = in_a & in_b; end - 另外,如果逻辑被工具完全优化掉(比如所有输入都是常量,输出结果固定),对应的触发器也会被删掉。
- 比如在时钟敏感块里直接把输入信号组合后赋值给输出,完全没有状态存储需求——比如:
这在ASIC设计中比FPGA更重要吗?
是的,而且重要得多。ASIC流片成本极高,一旦出问题损失巨大,所以设计阶段的每一步都要尽可能规避风险。always_ff这类显式声明能让lint、综合工具更早发现逻辑错误(比如把组合逻辑塞进时序块),避免后期仿真或流片才暴露问题。
FPGA迭代成本低,即使写错了也能重新烧写,但规范的编码风格依然推荐用always_ff,既能减少bug,也能让代码更易维护。
内容的提问来源于stack exchange,提问作者igrok
相关产品推荐
相关产品推荐

