基于Basys3的Verilog LED序列仿真:步进变化缺失问题求助
LED移位序列仿真问题修复
需求描述
当输入sw=0(对应内部变量x=0)时,LED需执行以下左移序列:
0000000000000001 0000000000000010 0000000000000100 0000000000001000 0000000000010000 0000000000100000 0000000001000000 0000000010000000 0000000100000000 0000001000000000 0000010000000000 0000100000000000 0001000000000000 0010000000000000 0100000000000000 1000000000000000
当sw=1时,LED序列反向执行右移操作。目前已实现main主模块、zaman计时子模块及testbench测试代码,但仿真时LED向量始终为固定值,未出现预期的步进移位变化。
问题代码分析与修复
1. zaman计时模块问题
原模块使用电平敏感的always @(state)块生成秒脉冲,且采用阻塞赋值,导致sec信号时序异常(持续时间过长或触发时机错误),无法正确触发主模块的移位逻辑。
修复后的zaman模块代码:
`timescale 1ns / 1ps module zaman( output reg Y, input clock, input reset ); reg [25:0] state; always @(posedge clock) begin if (reset == 1) begin state <= 0; Y <= 0; end else begin if (state == 50000000) begin state <= 0; Y <= 1; // 生成单时钟周期的秒脉冲 end else begin state <= state + 1; Y <= 0; end end end endmodule
修复说明:
- 将秒脉冲生成逻辑整合到时钟边沿触发的
always块中,确保Y(即主模块的sec信号)是单时钟周期的高电平脉冲,准确触发移位操作。 - 移除冗余的电平敏感
always块,避免时序竞争。
2. main主模块问题
- 复位逻辑使用阻塞赋值,违反时序电路设计规范,导致复位动作不可靠。
- 移位后立即判断
ovr值,由于非阻塞赋值的特性,此时ovr仍为旧值,无法正确触发循环复位逻辑。
修复后的main模块代码:
`timescale 1ns / 1ps module main( output [15:0] led, input clk, input btnC, input sw ); reg [15:0] state; reg x; wire sec; zaman timer (sec, clk, btnC); initial begin state = 16'b0000000000000001; x = 0; end always @ (posedge clk) begin x <= sw; if (btnC == 1) begin state <= 16'b0000000000000001; // 非阻塞赋值,符合时序规范 end else if (sec == 1) begin if (x == 0) begin // 左移到最后一位时,重置为初始值 state <= (state == 16'b1000000000000000) ? 16'b0000000000000001 : (state << 1); end else if (x == 1) begin // 右移到最后一位时,重置为最高位初始值 state <= (state == 16'b0000000000000001) ? 16'b1000000000000000 : (state >> 1); end end end assign led = state; endmodule
修复说明:
- 复位逻辑改用非阻塞赋值,确保时序正确性。
- 移除冗余的
ovr变量,直接通过判断当前state值实现循环移位,避免非阻塞赋值的时序延迟问题。 - 简化移位逻辑,提升代码可读性与可靠性。
3. Testbench仿真时间问题
原Testbench仅仿真160ms,远小于完成16次移位所需的8秒(50000000个时钟周期×10ns周期×16次=8e9ns=8s),导致无法观察到移位变化。
修复后的Testbench代码:
`timescale 1ns / 1ps module maintb; reg clk; reg btnC; reg sw; wire [15:0] led; main uut(.led(led), .btnC(btnC), .sw(sw), .clk(clk)); always #5 clk = ~clk; // 10ns时钟周期 initial begin clk = 0; btnC = 0; sw = 0; // 复位操作 btnC = 1; #10; btnC = 0; // 仿真足够长时间,覆盖16次移位(8秒) #8000000000; $finish; end endmodule
修复说明:
- 延长仿真时间至8秒,确保能观察到完整的移位序列。
- 添加
$finish命令,避免仿真无限持续。
验证说明
修复后重新仿真,LED向量会按照预期每秒执行一次移位操作,左移到最高位后自动重置为最低位,右移同理。若需快速验证,可将zaman模块中的计数阈值50000000改为50000,将仿真时间缩短至80ms即可观察到完整序列。
内容的提问来源于stack exchange,提问作者Sero
相关产品推荐
相关产品推荐

