You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Verilog模拟器对不同赋值场景的处理存在差异?

Verilog模拟器对不同赋值场景的处理差异解析

核心疑问

为何Verilog模拟器对以下几种赋值场景的处理存在差异?

场景1

always  #1 clk =! clk;
initial
begin
@(posedge clk)
start <= 1;
end

场景2

initial
begin
clk <= 1;
start <= 1;
end

等效场景(与场景1效果一致)

initial
begin
clk = 1;
start <= 1;
end

资料显示,场景1中clk与start信号会被同时设置,但clk只能在下一个边沿捕获start信号;场景2却没有这种延迟效果;而第三种写法又能和场景1表现一致。明明非阻塞赋值应该同步完成,为何会出现这种差异?


示例验证模块

示例模块1(对应场景1)

module test();
reg clk=0;
reg start=0;
reg flag=0;

always  #1 clk =! clk;

initial
begin
#5;
@(posedge clk)
start <= 1;
end

always@(posedge clk)
if(start)
  flag<=1;

endmodule

示例模块2(对应场景2)

module test();
reg clk=0;
reg start=0;
reg flag=0;

initial
begin
#5;
clk <= 1;
start <= 1;
end

always@(posedge clk)
if(start)
  flag<=1;

endmodule

仿真结果

场景1仿真结果
场景2仿真结果


差异原因解析

一切差异源于Verilog的事件调度机制,重点要区分阻塞赋值、非阻塞赋值的执行时机,以及边沿敏感块的触发逻辑:

场景1的执行逻辑

  1. always #1 clk = !clk 用阻塞赋值周期性翻转clk,每1时间单位产生一次边沿。
  2. initial块等待posedge clk到来后,执行start <= 1:非阻塞赋值不会立即更新start,而是把更新操作放入非阻塞赋值更新队列。
  3. 当前的clk上升沿已经触发了always@(posedge clk)块,这个块会读取当前的start值(0),因此flag不会被置1。
  4. 直到当前时间步所有事件执行完毕,start才会被更新为1;下一个clk上升沿到来时,always@(posedge clk)读取到start=1,才会置位flag。

场景2的执行逻辑

  1. initial块中两个非阻塞赋值clk <=1和start <=1会被同时放入非阻塞更新队列。
  2. 当前时间步所有顺序执行的代码完成后,队列中的赋值统一执行:clk从0变为1(产生上升沿),start同时变为1。
  3. clk上升沿触发always@(posedge clk)块时,start已经完成更新,因此读取到start=1,直接置位flag——这就是和场景1的核心差异。

等效场景的执行逻辑

  1. clk =1是阻塞赋值,会立即更新clk的值,直接产生上升沿。
  2. 此时start <=1还在非阻塞更新队列中,未完成更新;always@(posedge clk)块触发时,读取到的start仍是旧值0,所以flag不置位。
  3. 当前时间步结束后start才更新为1,下一个clk边沿到来时才会触发flag置位——效果和场景1完全一致。

内容的提问来源于stack exchange,提问作者den251

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:53:26