交通控制器仿真仅执行1个时钟周期问题排查求助
问题定位与修复方案
核心问题:组合逻辑环路引发仿真异常
你的代码存在组合逻辑环路,这是导致仿真时信号跳变、提前停止的根本原因:
count变量在组合逻辑块(always @(current_state))中被赋值,但该变量同时作为这个逻辑块的判断条件(if(count < 5)),而敏感列表仅包含current_state。这种设计会让仿真器陷入无限循环的组合逻辑计算,直接触发仿真异常。- 另外,
count属于时序逻辑变量,本应在时钟沿更新,却被错误地放在组合逻辑中修改,违背了时序电路的设计规范。
修复步骤
1. 重构count的更新逻辑
将count的更新移至时序逻辑块,和current_state同步在时钟沿更新:
// 时序逻辑:更新状态与计数器 always @ (posedge clk_i or negedge rst_i) begin if (!rst_i) begin current_state <= s0; count <= 0; end else begin current_state <= next_state; // 若状态未切换,计数器自增;切换则清零 if (next_state == current_state) begin count <= count + 1; end else begin count <= 0; end end end
2. 修改组合逻辑的状态转移判断
组合逻辑块仅负责根据current_state和count计算next_state,不再修改count,同时修正敏感列表(添加count):
// 组合逻辑:计算下一个状态 always @ (current_state, count) begin case(current_state) s0 : next_state = (count < 5) ? s0 : s1; s1 : next_state = (count < 1) ? s1 : s2; s2 : next_state = (count < 1) ? s2 : s3; s3 : next_state = (count < 5) ? s3 : s4; s4 : next_state = (count < 1) ? s4 : s5; s5 : next_state = (count < 1) ? s5 : s0; default : next_state = s0; endcase end
3. 规范赋值风格
组合逻辑中统一使用阻塞赋值(=),时序逻辑使用非阻塞赋值(<=),符合Verilog设计的最佳实践。
完整修复后的traffic_top模块代码
module traffic_top ( input clk_i, input rst_i, output logic [2:0] light_A_o, output logic [2:0] light_B_o ); // 独热码定义状态 parameter s0 = 6'b000001, s1 = 6'b000010, s2 = 6'b000100, s3 = 6'b001000, s4 = 6'b010000, s5 = 6'b100000; reg [5:0] current_state, next_state; reg [2:0] count; // 时序逻辑:更新状态与计数器 always @ (posedge clk_i or negedge rst_i) begin if (!rst_i) begin current_state <= s0; count <= 0; end else begin current_state <= next_state; if (next_state == current_state) begin count <= count + 1; end else begin count <= 0; end end end // 组合逻辑:计算下一个状态 always @ (current_state, count) begin case(current_state) s0 : next_state = (count < 5) ? s0 : s1; s1 : next_state = (count < 1) ? s1 : s2; s2 : next_state = (count < 1) ? s2 : s3; s3 : next_state = (count < 5) ? s3 : s4; s4 : next_state = (count < 1) ? s4 : s5; s5 : next_state = (count < 1) ? s5 : s0; default : next_state = s0; endcase end // 输出信号灯逻辑 always @ (*) begin case(current_state) s0 : begin light_A_o = 3'b001; light_B_o = 3'b100; end s1 : begin light_A_o = 3'b010; light_B_o = 3'b100; end s2 : begin light_A_o = 3'b100; light_B_o = 3'b100; end s3 : begin light_A_o = 3'b100; light_B_o = 3'b001; end s4 : begin light_A_o = 3'b100; light_B_o = 3'b010; end s5 : begin light_A_o = 3'b100; light_B_o = 3'b100; end default : begin light_A_o = 3'b100; light_B_o = 3'b100; end endcase end endmodule
仿真验证说明
修复后仿真将正常运行:
- 复位后从
s0状态启动,count在每个时钟周期自增,达到设定值后切换状态并清零计数器。 - 信号灯将按照红、黄、绿的预期时序切换,不会再出现信号跳变或提前停止的问题。
内容的提问来源于stack exchange,提问作者Jugal Gore
相关产品推荐
相关产品推荐

