Verilog FSM全状态赋值仍出现锁存器推断的问题排查
Verilog FSM综合锁存器推断警告的原因及解决方法
问题背景
使用Verilog设计有限状态机(FSM),在Synopsys Design Vision中综合时出现锁存器推断警告。涉及finish、A_times_B_enable等信号,核心代码如下:
// control path always @(*) begin casex (current_state) s0: begin read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s0; if (go == 1'b1) next_state = s1; end s1: begin read_addr_sel = 2'b00; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s2; end s2: begin read_addr_sel = 2'b01; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s3; end s3: begin read_addr_sel = 2'b01; size_count_sel = 2'b00; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s4; end s4: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s5; end s5: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b00; finish = 1'b0; next_state = s6; end s6: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; finish = 1'b0; next_state = s6; if (SizeCount == 16'b11) next_state = s7; end s7: begin read_addr_sel = 2'b10; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; finish = 1'b0; next_state = s7; if (SizeCount == 16'b01) next_state = s8; end s8: begin read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; finish = 1'b0; next_state = s9; end s9: begin read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b01; finish = 1'b0; next_state = s10; end s10: begin read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b1; next_state = s0; end endcase end
原因分析
锁存器推断的核心原因是组合逻辑块中存在未被完全赋值的信号:
- 代码中的
casex语句没有定义default分支,当current_state取到未列出的状态值(比如状态编码的冗余状态、复位后的未知状态,或是casex匹配逻辑覆盖不全的情况)时,所有输出信号都不会被赋值。 - 综合器会默认认为这些信号需要保持之前的值,因此推断出锁存器来实现“保持”功能。
解决方法
有两种可靠的方式避免锁存器推断,推荐使用第一种(更不易遗漏):
方法1:在组合逻辑块开头为所有信号赋默认值
在always @(*)块的最开始,给所有输出信号设置默认值,后续casex分支中只需要修改需要变化的信号值即可。这种方式能确保所有信号在任何情况下都有明确赋值。
修改后的代码示例:
// control path always @(*) begin // 先给所有信号赋默认值 read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s0; casex (current_state) s0: begin // 只修改需要变化的信号,其余沿用默认值 if (go == 1'b1) next_state = s1; end s1: begin read_addr_sel = 2'b00; next_state = s2; end s2: begin read_addr_sel = 2'b01; next_state = s3; end s3: begin read_addr_sel = 2'b01; size_count_sel = 2'b00; next_state = s4; end s4: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; next_state = s5; end s5: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b00; next_state = s6; end s6: begin read_addr_sel = 2'b01; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; next_state = s6; if (SizeCount == 16'b11) next_state = s7; end s7: begin read_addr_sel = 2'b10; size_count_sel = 2'b01; ABenable = 1'b1; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; next_state = s7; if (SizeCount == 16'b01) next_state = s8; end s8: begin read_addr_sel = 2'b10; A_times_B_enable = 1'b1; Accumulate_sel = 2'b01; next_state = s9; end s9: begin Accumulate_sel = 2'b01; next_state = s10; end s10: begin finish = 1'b1; next_state = s0; end endcase end
方法2:为casex添加default分支
在casex的最后添加default分支,在该分支中为所有信号赋值(比如复位到初始状态的输出):
casex (current_state) // 原有状态分支... default: begin read_addr_sel = 2'b10; size_count_sel = 2'b10; ABenable = 1'b0; A_times_B_enable = 1'b0; Accumulate_sel = 2'b10; finish = 1'b0; next_state = s0; end endcase
注意事项
- 组合逻辑
always @(*)块中,所有被赋值的信号必须在所有可能的执行路径上都有明确赋值,否则必然会触发锁存器推断。 - 优先使用“默认值+分支修改”的方式,既简化代码,又能彻底避免遗漏赋值的问题。
内容的提问来源于stack exchange,提问作者valve
相关产品推荐
相关产品推荐

