Verilog中case语句如何保留变量值?常规写法是否为最优方案?
Verilog状态机保留变量值写法的正误说明
你当前写法的问题
你写的a = a本身语法合法,但不是常规场景下的最佳实现,甚至无法解决你担心的锁存器问题:
- 你用的是电平敏感的组合逻辑
always块,只要你的需求是让变量在特定状态下保持取值,无论是否写a = a,编译器都会推断出锁存器(Latch)。锁存器属于异步器件,会引入毛刺、时序分析困难、面积浪费等问题,是常规数字设计中需要避免的写法。 - 手动编写敏感列表
@(state, a, b)容易遗漏信号,引发仿真和综合结果不一致的问题,组合逻辑更推荐用@(*)让编译器自动推导敏感列表。
常规场景的最佳实现(99%的状态机设计适用)
状态机的变量保留需求几乎都应该通过时序逻辑寄存器实现,寄存器本身就有保持取值的特性,完全不需要写a = a,只要在不需要更新的分支不做赋值即可:
// 带异步复位的时序逻辑示例 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin a <= 1'b0; // 按需设置复位初始值 end else begin case(state) S1: a <= b; S2: ; // 无赋值操作,a自动保持上一个时钟周期的取值 // 其余状态如果不需要更新a,都可以留空 endcase end end
额外规范提示:时序逻辑统一使用非阻塞赋值<=,可以避免仿真阶段的竞争冒险问题。
特殊场景的合法写法(仅确认需要锁存器时使用)
如果确实有特殊需求必须在组合逻辑中实现变量保持,更易维护的写法是先给变量赋默认保持值,再写分支逻辑,不需要在每个保持分支重复写a = a:
always @(*) begin a = a; // 先设置默认值:所有未明确赋值的分支都保持原有取值 case(state) S1: a = b; S2: ; // 不需要额外写赋值 endcase end
注意:该写法仍然会生成锁存器,非必要不要使用
内容的提问来源于stack exchange,提问作者richbai90
相关产品推荐
相关产品推荐

