always@(a)
begin
#1 t<=a;
#1 c<=t;
end
我正在使用下面给出的测试平台来分析上述Verilog代码
a=0;
#5 a=1;
#5 a=0;
#5 a=1;
#5;
这是我的分析: 从上面的测试台上,我可以看出“ a”是一个总长度为20ns的时钟信号,OFF和ON时间均为5ns。在第0 ns时,“ a”从X更改为0。因此始终触发块。块中的第一个语句具有1ns的内部延迟,它等待1ns。 1ns编译器知道它是非阻塞语句后,就不会进行赋值评估。因此,“ a”值将被存储为临时值,并并行执行第二条语句。由于第二条语句也存在内部延迟,因此它等待1ns 。然后进行评估。由于两个评估均已完成,因此现在将进行分配。
time a t c
0ns 0 x x
1ns 0 x x
2ns 0 x x
3ns 0 0 x
4ns 0 0 x
此分析正确吗?
答案 0 :(得分:0)
不,不是这样,非阻塞分配的工作方式与您描述的不同。
您正确的是,非阻塞语句的实际赋值是“延迟”执行的。但是什么时候“以后”呢?
当不再有未完成的阻塞事件时,将处理“非阻塞”事件。但是在处理延迟之前。因此,一旦模拟器发现必须处理您的#1
,它就会首先处理所有非阻塞分配,然后才开始处理延迟。
这意味着甚至在#1
延迟t
开始之前,它就已经收到了a
的值。
Verilog标准中有一整章,描述了各种“动作”应以什么顺序执行。
答案 1 :(得分:0)
将always
块重新编写为单独的行并有意识地移动begin/end
块的位置可能会有所帮助。这不会对行为产生影响,因为所有操作都是按顺序执行的。
always // instantiate a procedural block
begin
@a // blocking event delay waits for a change on -a-
#1 // blocking time delay waits for 1 time unit
t <= a; // non-blocking assignment
// uses the current value of -a- one time unit after it changed
// and schedules an assignment to t
#1 // blocking time delay waits for 1 time unit
// since there is no more active things to do -a- gets updated
c <= a; // uses the updated value of t and schedules an assignment to c
end // now 2 time units after -a- was first changed
// goes back to the top of the block and waits for another change
// on -a-.
请注意,执行块时在 a 上进行的任何更改都将丢失。这是一个不错的presentation on non-blocking assignments。