英文:
Why would a non-blocking assignment like this cause the process to re-enter?
问题
always @(clk) begin #10 clk <= ~clk;end //工作正常
always @(clk) begin #10 clk = ~clk;end //不工作
工作正常表示执行重新进入always块,行为类似振荡器。
不工作表示只执行一次。
我已阅读Verilog标准中的调度语义部分,按我理解,一个时间步内,进程中的所有语句同时放置在层次化事件队列中,直到遇到进程中的时序控制语句时暂停进程。然后对这些语句进行排序和排序。如果语句在begin end块中,需要按照它们出现的顺序进行排序。
按我理解,阻塞赋值和非阻塞赋值都可以生成一个跳动的时钟,因为在进程中检测到时序控制语句之前会先发生。
一个时间步内的事件评估是逐句进行的吗?还是我对此有误解?
为什么非阻塞赋值的更新事件可以在同一个时间步内触发敏感事件?
你能告诉我事件的评估和更新是如何进入层次化事件队列的吗?
英文:
always @(clk) begin #10 clk <= ~clk;end //works
always @(clk) begin #10 clk = ~clk;end //doesn't work
Works means execution re-enters the always block, behaves like a oscillator.
Does not work mean it execute only once.
I've read Scheduling semantics part in Verilog Standard, as I understand it now, in a time step, all statements in the process are placed in the hierarchical event queue at the same time, until the process is suspended when the timing control statement in the process is encountered. The statements are then sorted and sorted. If the statements are in a begin end block, the statements need to be sorted in the order in which they appear.
As I understand it, both blocking and non-blocking assignments can generate a flapping clock because the timing control statement in the process is detected before the assignment is updated.
Is the evaluation of events in a time step done sentence by sentence? Or there's something wrong with my understanding.
Why can a non-blocking update event trigger a sensitive event at the same time step?
Could You tell me how evaluation and update events enter the hierarchical event queue?
答案1
得分: 3
为了更好地理解这一点,您需要在always
循环中展开该语句。
initial #0 clk = 0; //我假设您已经有了这段代码。
initial begin
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
...
end
这段代码之所以有效,是因为在遇到第一个@clk
后,clk
被设置为0。它等待10个时间单位,然后执行非阻塞赋值语句。在非阻塞赋值更新clk
的值之前,下一个@(clk)
就被遇到了。
在第二种情况下,
initial #0 clk = 0; //我假设您已经有了这段代码。
initial begin
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
...
end
同样,第一个@clk
后clk
被设置为0。但由于现在有一个阻塞赋值语句,clk
的更新会先发生,然后遇到@(clk)
。所以它等待clk
的改变,但这个改变永远不会发生。
事件控制的关键在于它们必须在执行过程线程中的任何事件表达式发生变化之前被遇到。请注意,我添加了#0
来确保先看到@
。没有延迟的话,就会出现竞争条件。即使在原始代码中使用always
结构建模时,仍然存在竞争条件,但大多数用户不会看到这一点,因为模拟器倾向于在initial
进程之前启动always
进程。
在您的情况下,不需要事件控制。您可以简单地编写:
always #10 clk = ~clk;
甚至更好的写法是
initial begin
clk = 0; //确保在时间0时不会发生posedge。
forever #10 clk = ~clk;
end
英文:
To better understand this, you need to unroll the statement in the always
loop.
initial #0 clk = 0; // I'm assuming you have this code already.
initial begin
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
@(clk) #10 clk <= ~clk;
...
end
This works because clk
is set to 0 after encountering the first @clk
. It waits 10 time units and then executions the nonblocking assignment statement. The next @(clk)
is encountered before the nonblocking assignment updates the value of clk
.
In the second case,
initial #0 clk = 0; // I'm assuming you have this code already.
initial begin
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
@(clk) #10 clk = ~clk;
...
end
Again,clk
is set to 0 after encountering the first @clk
. But since you now have a blocking assignment statement, the update to clk
occurs first, and then you encounter the @(clk)
. So it waits for a change on clk
that never happens.
The key thing about event controls they have to be encountered in the procedural thread of execution before any change to the event expression happens. Note that I added a #0
to make sure the the @
is seen first. Without the delay, there is a race condition. There is still a race condition when the original code was modeled with an always
construct, but most users do not see this because simulators tend to start always
processes before initial
processes.
In your case, there is no need for an event control. You can simply write:
always #10 clk = ~clk;
Even better is
initial begin
clk = 0; // make sure that a posedge does not occur at time 0.
forever #10 clk = ~clk;
end
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论