retriggering

J

Jason Zheng

Guest
I'm quite interested in various ways to retrigger events in verilog. So
I wrote a simple test code:

`timescale 1ns / 100ps
module test;

event bar;

always @ (bar) begin:foo_trig
foo_task;
end

task foo_task;
begin
#300 $display("%t... foo_task triggered", $stime);
end
endtask

initial
begin
repeat (16) begin
#50 disable foo_trig;
-> bar;
end
#5000 $finish;
end

endmodule // test

If all goes well, only the last ->bar will trigger foo_task, right?

I run this piece of code in 3 simulators, namely ncverilog, iverilog,
and cver. As it turns out, iverilog and cver didn't print anything. Only
ncverilog printed the result that I expected.

Disappointed, I changed the code a little bit:

repeat (16) begin
#49 disable foo_trig;
#1 -> bar;
end

Now all three simulators have the same result. It seems that iverilog
and cver are disabling foo_trig before ->bar takes place. My question is
: Is this a gray area in verilog language? Or is it a common bug shared
by iverilog and cver? Or is it a ncverilog bug? Comments?

cheers,

jz
 
sharp@cadence.com wrote:
This is presumably a race condition.

You disable the block foo_trig, so your always process will be
scheduled to start executing from the end of the block. Now you have a
race with two possible execution orders: the initial block could
continue executing and trigger bar, followed by the always block
executing from the end of foo_trig and starting to wait on bar.
Alternately, the always block could start executing from the end of
foo_trig and start waiting on bar, then the initial block could resume
and trigger bar. Either of these is a legal ordering. When two
processes are ready to run, the order that they run in is
non-deterministic in the language.

I don't quite understand your point:

Order #1: ->bar first, then always@(bar) block
Order #2: always@(bar) first, then ->

I don't really see the difference between the two orders. The first
order is straighforward, you trigger, then the always block wakes up and
execute foo_trig block. In the second order, always@(bar) executes
first, but since there are no bar event yet, it goes to sleep. Then
->bar happens and repeat. Next, the always block should be waken up by
the bar event before disable foo_trig is reached.

Anyway, all above is based on assumptions of how an arbitrary simulator
schedule things, which make things happen as specified in the language.
What about the language experts? What does the piece of code mean purely
based on verilog 1995?

-jz
 
Neo wrote:
jason,
I feel display statements cannot be equated to events and hence not
suitable as examples. this one below does have the race condition
<snip>

I know, I know. It's just that it frustrates me that the verilog
language spec. did not point this out. The only thing that I could find
that's close to what I described was about non-blocking assignments. And
non-blocking assignments do have guaranteed order, and that is they get
processed at the same time. But events such as triggering and disable,
coding them in a sequencial order already imposes a NATURAL order of
execution. So even without the evil #0 (which can lead to unexpected
results sometimes), it should be clear enough that the first statement
should be executed FIRST. One can talk on and on about how verilog has
limited number of execution phases, but this is simply a matter of
common sense.

while I am curious as to why this dosent work as a pulse generator as
reqd:-
always @ (button_event)
begin
out = 0;
while (button_event)
begin: pulse_gen
out = 0;
#5 out = 1;
#20 out = 0;
#5;
end
end
I don't think that will work. I'll you an example.

initial
begin
#100 -> button_event;
#15 -> button_event;
end

At the end of execution, you will only see one pulse starting at tick
105 and falls at tick 125. But as I said, I'm modeling a pulse-generator
that can be re-triggered. I'm expecting a pulse rising at tick 125, and
falling at tick 140. A lot of things work that way in real life.

cheers,

jz
 
Berty wrote:
You missed one point and it is that in your display example you put
both statement (display) in same block (initial) therefore you are
guaranty to have the first first and second second.
snip
Interesting. That's the point that I made in my post. But my original
code was:

initial
repeat (16) begin
#50 disable foo_trig;
-> bar;
end

As you can see the disable and ->bar are in the same block, which should
have imposed a natural ordering: disable should happen first, then bar
should be triggered. If you can show me in the verilog spec that there
is no guarantee for the execution of these two statements, then the
discussion ends.

a. a small suggestion, don't use reserved word for your variable, for
example don't use output as name of the register as it might get you
into "problem".
my bad, but I'm sure you understood the code. May I suggest you to do a
spell and grammar check before you post? -----------------
|
V
b. As for being able to retrigger here one solution wihtout the use of
disable

integer pulsewidth ;
initial pulsewidth = 0 ;
always @ (pulse_trig)
pulsewidth = 100;

always begin
#1;
if (pulsewidth!=0)
pulsewidth = pulsewidth - 1;
end

wire pulse = (pulsewidth!=0);

obviously you can write it other way as this is just an example ,There
is also one more "fine tuning" which you can do with the #1 in the
last always, which have to do with what to do when the decrement and
the update take place on same tick time but this can be solved by
moving the #1 if needed depend on what you want to happen in such
scenario.
Exactly, this is not a universal solution, as you can fire the trigger
at the same time you are updating the pulsewidth. I don't see how you
can apply this in a general way. Try packaging that as a model and
telling your users that they can't fire a trigger on the 1 tick marks.
Have fun.

The point that I tried to make was not that my solution was the only
solution. It is a solution that demonstrates a good and efficient use of
disable statements. However there are dangers involved with disables if
you abuse it. That's out of the topic in this thread, however.

cheers,

jz
 
sharp@cadence.com wrote:

The code is nondeterministic based on the Verilog-1995 LRM. After the
disable statement, you have two processes that are ready to run. The
order they run in is nondeterministic in the language.
In other words, (->bar) and (alway @ bar) take place at the same time.
Still sounds a little unfair to me, but I will argue no more. Thanks for
the explanation.

cheers,

jz
 
Berty wrote:
You are only somewhat correct when you write "As you can see the
disable and ->bar ... " as indeed they are in the same block however
this is not the "end of it" meaning in contrast to the display for
example the event activate another block and hence you need to look on
the whole as not a single block.

Just to clarify things a little bit. With all due respect, what you said
was that ->bar and disable statements were racing, which was not true.
As sharp pointed out from the verilog 2001 spec, verilog actually
guarantees the execution order within the same block. Hence there was no
racing between ->bar and disable.

The real racing was between ->bar and alway @ (bar), since both were
free to run once disable is executed. This is where verilog becomes
undeterministic.

As for disable you should do what ever you find comfortable and easy,
myself I don't "like" the use of disable unless I have to and
therefore I wrote my suggested code. Use it or ignore it as you like.
Fair enough, as long as your solution works.

cheers,

jz
 
Jason,
The statements in the initial statement all get excuted sequentially
but I suspect there is a race condition where you disable the task and
trigger the event. As a result the task might be disabled before or
after the event triggering. Your second case works as expected because
of event ordering. the same will happen when instead of #49 and #1 we
put #50 and #0 for the two statements.
I observed a curious behavior in modelsim. Your original code as you
said dosent print out the message but what I observed in modelsim is
the task gets disabled for alternate cycles. ie.,
pass,fail,pass,faill...etc so as your repeat loop is for 16 the task is
disabled for the 16th loop. If we change the repeat number to an odd
value like 17 the it does come out with a task triggered message. I
would like to know why this is so, any comments?
 
This is presumably a race condition.

You disable the block foo_trig, so your always process will be
scheduled to start executing from the end of the block. Now you have a
race with two possible execution orders: the initial block could
continue executing and trigger bar, followed by the always block
executing from the end of foo_trig and starting to wait on bar.
Alternately, the always block could start executing from the end of
foo_trig and start waiting on bar, then the initial block could resume
and trigger bar. Either of these is a legal ordering. When two
processes are ready to run, the order that they run in is
non-deterministic in the language.
 
I'm not sure what you try to do but generally speaking your code will
do nothing.

You have 16 time disable the task and than activate it using the event
bar however since there is no delay in between the two they are both
done together and this is the race, meaning whether the activation will
take place before or after as the activation and disable will enter the
queue for the next tick and base on which will be evaluate first you
will get the result.

It is not advice to enable and disable on the same tick time, and
probably not what you really want to do.

By the way if you do put small delay between the two than you will see
the print of the 16'th time (last loop) as the prior 15 will be
disable since the display take place only after 300 while the disable
will be done after 50.

Have fun.
 
Berty wrote:

You have 16 time disable the task and than activate it using the event
bar however since there is no delay in between the two they are both
done together and this is the race, meaning whether the activation will
take place before or after as the activation and disable will enter the
queue for the next tick and base on which will be evaluate first you
will get the result.
I see, you are implying that verilog makes no guarantee of the execution
order of two adjacent statements with no explicit delays. Now we are
talking. How about this piece of code?

initial begin
$display("First");
$display("Second");
end

If what you said were true, then it is possible that "Second" comes
before "First." But we all know that "First" always comes before
"Second." You were probably thinking something like this:

initial $display("First");
initial $display("Second");

But that's not the case in my code.

It is not advice to enable and disable on the same tick time, and
probably not what you really want to do.
It makes perfect sense to do so, as long as you disable first, then
enable. Suppose you want to model a pulse-generator that generate 100ns
pulses whenever a button is pressed. During the 100ns, if the button is
pressed again, the pulse should be re-started.

always @ (button_event)
begin
disable pulse_gen;
-> pulse_trig;
end

always @ (pulse_trig)
begin: pulse_gen
output = 0;
#5 output = 1;
#20 output = 0;
#5;
end

By the way if you do put small delay between the two than you will see
the print of the 16'th time (last loop) as the prior 15 will be
disable since the display take place only after 300 while the disable
will be done after 50.
Exactly, that's the whole point I was trying to show. See my example #2
in original code.

cheers,

jz
 
jason,
I feel display statements cannot be equated to events and hence not
suitable as examples. this one below does have the race condition

`timescale 1ns / 100ps
module test_race;

event bar1,bar2;
reg x;

always @ (bar1)
begin
x = 1;
end

always @ (bar2)
begin
x = 0;
end

initial
begin
repeat (10) begin
#5 -> bar2;
-> bar1;
$display("%t... bar event triggered", $stime);
end
#50 $stop;
end

endmodule // test

while I am curious as to why this dosent work as a pulse generator as
reqd:-
always @ (button_event)
begin
out = 0;
while (button_event)
begin: pulse_gen
out = 0;
#5 out = 1;
#20 out = 0;
#5;
end
end
 
You missed one point and it is that in your display example you put
both statement (display) in same block (initial) therefore you are
guaranty to have the first first and second second.

If you put them in different then indeed it is not guaranty and this is
what happen in your initial example as you are not doing
"everything" in same block (initial/always).

As for your example
a. a small suggestion, don't use reserved word for your variable, for
example don't use output as name of the register as it might get you
into "problem".

b. As for being able to retrigger here one solution wihtout the use of
disable

integer pulsewidth ;
initial pulsewidth = 0 ;
always @ (pulse_trig)
pulsewidth = 100;

always begin
#1;
if (pulsewidth!=0)
pulsewidth = pulsewidth - 1;
end

wire pulse = (pulsewidth!=0);

obviously you can write it other way as this is just an example ,There
is also one more "fine tuning" which you can do with the #1 in the
last always, which have to do with what to do when the decrement and
the update take place on same tick time but this can be solved by
moving the #1 if needed depend on what you want to happen in such
scenario.

Have fun.
 
Jason Zheng wrote:
I don't quite understand your point:

Order #1: ->bar first, then always@(bar) block
Order #2: always@(bar) first, then -

I don't really see the difference between the two orders. The first
order is straighforward, you trigger, then the always block wakes up
and
execute foo_trig block.
In the first order, the always block wakes up at the end of the block,
then loops back and executes the @(bar). It then goes to sleep to wait
for bar. That means the NEXT bar. The last one already happened just
before the always block started waiting, so the always block missed it.
An event has no duration. If you weren't already waiting for it when
it happened, you missed it. This is a race condition in the code.

What about the language experts? What does the piece of code mean
purely
based on verilog 1995?
The code is nondeterministic based on the Verilog-1995 LRM. After the
disable statement, you have two processes that are ready to run. The
order they run in is nondeterministic in the language.
 
From IEEE Std 1364-2001, 5.4.1: "Statements within a begin-end block
shall be executed in the order in which they appear in that begin-end
block. Execution of statements in a particular begin-end block can be
suspended in favor of other processes in the model; however, in no case
shall the statements in a begin-end block be executed in any order
other than that in which they appear in the source."

So your two displays in the same begin-end block will always execute in
order. However, if you have multiple processes that are ready to run,
their execution could be arbitrarily interleaved. In practice,
simulators do not arbitrarily suspend one process to run another. This
would be inefficient, and many coding styles would not work as
expected. In practice, simulators will only switch to another process
when the current process suspends, or possibly when the current process
does something to trigger the other process (i.e. make it ready to
run). The disabling of a block in another process may or may not cause
the current process to suspend in favor of the one with the disabled
block, as you have seen.
 
You are only somewhat correct when you write "As you can see the
disable and ->bar ... " as indeed they are in the same block however
this is not the "end of it" meaning in contrast to the display for
example the event activate another block and hence you need to look on
the whole as not a single block.

As for disable you should do what ever you find comfortable and easy,
myself I don't "like" the use of disable unless I have to and
therefore I wrote my suggested code. Use it or ignore it as you like.

have fun
 

Welcome to EDABoard.com

Sponsor

Back
Top