SystemVerilog测试中always与initial块顺序引发的功能异常
SystemVerilog仿真中initial与always块顺序影响功能的原因分析
你遇到的问题本质是仿真0时刻的阻塞赋值竞争,下面具体拆解原因:
可正常运行的代码(always在前)
top test(clk, reset, writedata, dataadr, pc, instr, readdata, memwrite); always begin reset = 0; clk = 0; #10; reset = 0; clk = 1; #10; end initial begin clk = 0; reset = 1; #10; end
仿真0时刻的执行顺序:
- 先执行
always块的阻塞赋值:reset=0、clk=0 - 接着执行
initial块的阻塞赋值:clk=0(无变化)、reset=1 - 两个块均进入
#10延迟阶段
此时reset在0时刻的最终值是1,模块能正确完成复位,输出符合预期。
异常代码(initial在前)
top test(clk, reset, writedata, dataadr, pc, instr, readdata, memwrite); initial begin clk = 0; reset = 1; #10; end always begin reset = 0; clk = 0; #10; reset = 0; clk = 1; #10; end
仿真0时刻的执行顺序:
- 先执行
initial块的阻塞赋值:clk=0、reset=1 - 接着执行
always块的阻塞赋值:reset=0、clk=0 - 两个块进入延迟阶段
此时reset在0时刻的最终值被覆盖为0,模块没有得到有效复位,导致输出变为未确定状态。
核心原因
SystemVerilog中,同一仿真时刻内的阻塞赋值(=)会按照代码书写的顺序依次执行,后面的赋值会直接覆盖前面的结果。而always块在仿真启动时(0时刻)会立即进入第一次循环,执行所有无延迟的阻塞赋值语句,直到遇到#延迟才暂停。
你原本以为两个块独立执行,但实际上0时刻它们的赋值操作是串行执行的,顺序由代码书写位置决定,最终导致信号值被覆盖。
解决方法
- 改用非阻塞赋值(
<=):同一时刻的非阻塞赋值会被放入调度队列,在当前时刻结束后统一更新信号值,不会出现覆盖问题。修改后代码如下:
top test(clk, reset, writedata, dataadr, pc, instr, readdata, memwrite); initial begin clk <= 0; reset <= 1; #10; end always begin reset <= 0; clk <= 0; #10; reset <= 0; clk <= 1; #10; end
- 或者避免0时刻的竞争:调整
always块中reset的赋值时机,比如在第一个延迟后再设置reset=0,确保复位信号先生效:
always begin clk = 0; #10; reset = 0; // 延迟后再修改reset clk = 1; #10; end
内容的提问来源于stack exchange,提问作者asimtot
相关产品推荐
相关产品推荐

