Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Non-Blocking versus blocking

471 views
Skip to first unread message

Ali Karaali

unread,
May 19, 2010, 11:41:00 AM5/19/10
to
Hello everybody,

I'm very newbie at verilog and I know this is very classical issue for
newbies but I haven't got rid of confusing yet. Very simple design
below;

module delay(input clk, output enable);
reg[2:0] count;
always@(posedge clk)
count = count + 1;

assign enable = (count == 7);
endmodule

module myTopModule(input clk, output out);
wire tmp;
always@(posedge clk)
out <= tmp;

delay d_i(.clk(clk), .enable(tmp));
endmodule

What is the problem of that design or are there any? I tried to give
to output 7 cycles 0 and 1 cycle 1.

Jonathan Bromley

unread,
May 19, 2010, 12:00:46 PM5/19/10
to
On May 19, 4:41 pm, Ali Karaali <ali...@gmail.com> wrote:
> I'm very newbie at verilog and I know this is very classical issue for
> newbies but I haven't got rid of confusing yet. Very simple design
> below;
>
> module delay(input clk, output enable);
>     reg[2:0] count;
>     always@(posedge clk)
>         count = count + 1;
>
>     assign enable = (count == 7);
> endmodule
>
> module myTopModule(input clk, output out);
>     wire tmp;
>     always@(posedge clk)
>         out <= tmp;
>
>     delay d_i(.clk(clk), .enable(tmp));
> endmodule
>
> What is the problem of that design or are there any?

(1)
Variable "count" is not reset, so it will start at 3'bX
and will remain stuck at 3'bX throughout (because X+1 = X).
In hardware it would start at *some* value, and you would
indeed get one pulse per 8 clocks. But simulation is
more pessimistic. You need a reset.

(2)
Yes, you were right in the title: you *must* use
nonblocking assignment to "count", because its
value is used outside the always block:

always @(posedge clk)


count <= count + 1;

(3)
Why two always blocks, a module instance and an assign?
Why not

module YourTopModule (
input clk,
input synchronous_reset,
output reg out );

reg [2:0] count;

always @(posedge clk) begin
if (synchronous_reset)
count <= 0;
out <= 0;
else begin


count <= count + 1;

out <= (count == 7);
end
end
endmodule

Astute observers will note that it would then be possible
to bury "count" in the always block and assign to it using
blocking assignment, but let's set that aside for a while
to avoid unnecessary confusion for the OP.
--
Jonathan Bromley

Ali Karaali

unread,
May 19, 2010, 12:32:09 PM5/19/10
to
On 19 Mayıs, 19:00, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> On May 19, 4:41 pm, Ali Karaali <ali...@gmail.com> wrote:
>
>
>
> > I'm very newbie at verilog and I know this is very classical issue for
> > newbies but I haven't got rid of confusing yet. Very simple design
> > below;
>
> > module delay(input clk, output enable);
> >     reg[2:0] count;
> >     always@(posedge clk)
> >         count = count + 1;
>
> >     assign enable = (count == 7);
> > endmodule
>
> > module myTopModule(input clk, output out);
> >     wire tmp;
> >     always@(posedge clk)
> >         out <= tmp;
>
> >     delay d_i(.clk(clk), .enable(tmp));
> > endmodule
>
> > What is the problem of that design or are there any?
>
> (1)
> Variable "count" is not reset, so it will start at 3'bX
> and will remain stuck at 3'bX throughout (because X+1 = X).
> In hardware it would start at *some* value, and you would
> indeed get one pulse per 8 clocks.  But simulation is
> more pessimistic.  You need a reset.

I know I need a reset, I just wanted to interest just the real problem
but thanks.

> (2)
> Yes, you were right in the title: you *must* use
> nonblocking assignment to "count", because its
> value is used outside the always block:

So this is the rule? If I use a left hand side variable from outside
of the always block, I need an nonblocking assignment? Is it true for
the always@(*) because I used the code at below in a design as a
lookup table.

always@(*)
case(address)
3 : real_addr = 2;
6 : real_addr = 4;
9 : real_addr = 6;
default: real_addr = real_addr;
endcase

and I used the real_addr in another always block.


>
>   always @(posedge clk)
>      count <= count + 1;
>
> (3)
> Why two always blocks, a module instance and an assign?
> Why not
>
> module YourTopModule (
>   input clk,
>   input synchronous_reset,
>   output reg out );
>
>   reg [2:0] count;
>
>   always @(posedge clk) begin
>     if (synchronous_reset)
>       count <= 0;
>       out <= 0;
>     else begin
>       count <= count + 1;
>       out <= (count == 7);
>     end
>   end
> endmodule
>
> Astute observers will note that it would then be possible
> to bury "count" in the always block and assign to it using
> blocking assignment, but let's set that aside for a while
> to avoid unnecessary confusion for the OP.

Actually I wrote the code like that

reg [2:0] count;
always@(posedge clk) begin


count <= count + 1;

case(count)
0, 1, 2, 3, 4, 5, 6: out <= 0;
7: out <= 1;
endcase
end

and the instructor is also angry that because he said the design had
an unnecessary flop just before the out I suppose yours too?
> --
> Jonathan Bromley

johnp

unread,
May 19, 2010, 12:57:44 PM5/19/10
to

You should take a look at papers by Cliff Cummings, especially
http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
He has other good papers at his web site that are very informative.

Note that rules are made to be broken, but Cliff's suggestions and
insights
will serve you well!

John Providenza

johnp

unread,
May 19, 2010, 1:04:16 PM5/19/10
to

Note that your case statement will infer a latch, usually not desired/
expected
and likely to irritate your professor/colleagues/tools


always@(*)
case(address)
3 : real_addr = 2;
6 : real_addr = 4;
9 : real_addr = 6;
default: real_addr = real_addr;
endcase

The default statement says "if you don't get 3, 6, or 9, hold the
current value".
Since this is not clocked, "hold" equates to a latch.

John Providenza

Jonathan Bromley

unread,
May 19, 2010, 4:03:55 PM5/19/10
to
On Wed, 19 May 2010 09:32:09 -0700 (PDT), Ali Karaali wrote:

>I know I need a reset, I just wanted to interest just the real problem
>but thanks.

OK. Sorry, you said you were new to this game so it
seemed like an obvious thing to pick up.

>> (2)
>> Yes, you were right in the title: you *must* use
>> nonblocking assignment to "count", because its
>> value is used outside the always block:
>
>So this is the rule? If I use a left hand side variable from outside
>of the always block, I need an nonblocking assignment?

Very close. I should have been more precise: that rule is
valid for CLOCKED always blocks.

> Is it true for
>the always@(*) because I used the code at below in a design as a
>lookup table.
>
>always@(*)
> case(address)
> 3 : real_addr = 2;
> 6 : real_addr = 4;
> 9 : real_addr = 6;
> default: real_addr = real_addr;
> endcase
>
>and I used the real_addr in another always block.

No. Combinational always (using always @* or some other
complete sensitivity list) does not require nonblocking assignment.
It's usually harmless, but (as Cliff Cummings discusses in the
papers that JohnP mentioned) there are some situations
where it can be less appropriate. Blocking assignment is
good in combinational always blocks because such blocks
will invariably re-trigger whenever necessary, so they
are sure to settle to the correct value.

On the other hand,
clocked always blocks trigger just once because of the
external clock condition - note that this clock does
NOT appear anywhere else in the code of the always
block - and it's easy to get read/write race conditions
if you don't use nonblocking assignment to variables
that are used outside the always block.

>> (3)
>> Why two always blocks, a module instance and an assign?

[snip]


>Actually I wrote the code like that
>
>reg [2:0] count;
>always@(posedge clk) begin
> count <= count + 1;
> case(count)
> 0, 1, 2, 3, 4, 5, 6: out <= 0;
> 7: out <= 1;
> endcase
>end
>
>and the instructor is also angry that because he said the design had
>an unnecessary flop just before the out I suppose yours too?

Hmmm.. Your original code had an additional flop on "out"
(in the second clocked always block, in the top module)
so I didn't have any problem with putting one in myself :-)

If you absolutely insist on not having a flop on "out" (and I can't
see why you should so insist; your instructor owes you that
explanation) then you must combinationally decode it off "count",
without an added flop. That is bad for other reasons. But if the
specification said "only three flops", then you have no choice.
For extra credit, work out how to use those three flops to make
an 8-state counter that can be decoded without glitches :-)
--
Jonathan Bromley

Jonathan Bromley

unread,
May 19, 2010, 4:27:04 PM5/19/10
to
On Wed, 19 May 2010 09:32:09 -0700 (PDT), Ali Karaali wrote:

An afterthought:

>I used the code at below in a design as a lookup table.

I think JohnP may have mentioned this...
your design is flawed.

>always@(*)
> case(address)
> 3 : real_addr = 2;
> 6 : real_addr = 4;
> 9 : real_addr = 6;
> default: real_addr = real_addr;
> endcase

The "no change" assignment real_addr=real_addr
(or, equivalently, missing off the default clause completely)
implies a latch, which is not nice. It's certainly not a
lookup table. Did you perhaps intend

default: real_addr = address;

?? That would have been OK.

An always@* block (or any logically equivalent construct,
such as a continuous assignment) should always generate
a pure function of its inputs, so that it maps to combinational
logic.

In verification (testbench) code none of these rules
necessarily apply. They are there to ensure reliable
mapping between simulation behaviour and the final
results of logic synthesis.
--
Jonathan Bromley

Ali Karaali

unread,
May 19, 2010, 5:55:44 PM5/19/10
to
On 19 Mayıs, 23:03, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> On Wed, 19 May 2010 09:32:09 -0700 (PDT), Ali Karaali wrote:
> >I know I need a reset, I just wanted to interest just the real problem
> >but thanks.
>
> OK.  Sorry, you said you were new to this game so it
> seemed like an obvious thing to pick up.
>
> >> (2)
> >> Yes, you were right in the title: you *must* use
> >> nonblocking assignment to "count", because its
> >> value is used outside the always block:
>
> >So this is the rule? If I use a left hand side variable from outside
> >of the always block, I need an nonblocking assignment?
>
> Very close.  I should have been more precise: that rule is
> valid for CLOCKED always blocks.

Confusing goes on. Actually I'm a grad student and after the many
years imperative languages experience, that's a kind of languages is
very hard to understand. Sorry for "easy" questions that I have one
million... :-)

I didn't read the Cliff's papers but I will as soon as possible.

If need to back the first design, what is the problem? Why can't I use
blocking assignment in clocked always block. You said if you use the
value used outside the always block, so what happened if I used?

I know that


assign enable = (count == 7);

and
always@(*)


enable = (count == 7);

are same, aren't it? And the execution of the star always block will
begin when the count is changed. When will count change? The blocking
assignment is finished.

always@(posedge clk)


count = count + 1;

So what is wrong? Really I don't understand more correctly can't. Is
there any wrong the order of the changing values of count and enable?
If so, what, why? :-)
If I say,
event_1 is and
always@(posedge clk)


count = count + 1;

event_2 is
always@(*)


enable = (count == 7);

The order of the events are guaranteed to event_1 and event_2?

Jonathan Bromley

unread,
May 19, 2010, 6:33:44 PM5/19/10
to
On Wed, 19 May 2010 14:55:44 -0700 (PDT), Ali Karaali wrote:

>Confusing goes on. Actually I'm a grad student and after the many
>years imperative languages experience, that's a kind of languages is
>very hard to understand. Sorry for "easy" questions that I have one
>million... :-)

OK! Some parts of Verilog are just like other imperative
languages, but some are quite different....

>If need to back the first design, what is the problem? Why can't I use
>blocking assignment in clocked always block. You said if you use the
>value used outside the always block, so what happened if I used?
>
>I know that
>assign enable = (count == 7);
>and
>always@(*)
> enable = (count == 7);
>are same, aren't it? And the execution of the star always block will
>begin when the count is changed. When will count change? The blocking
>assignment is finished.

Yes, you're right so far.

>always@(posedge clk)
> count = count + 1;
>
>So what is wrong?

Nothing is wrong IN THAT EXAMPLE ALONE.

But, in the real world, such examples fit together
into bigger designs. That's where the trouble starts.

>If I say,
>event_1 is and
>always@(posedge clk)
> count = count + 1;
>event_2 is
>always@(*)
> enable = (count == 7);
>
>The order of the events are guaranteed to event_1 and event_2?

Yes (unless some other block also updates "count", but that
would be very bad for design).

But please consider this little design:

always @(posedge clock)
if (reset)
Q0 = 0;
else
Q0 = ~Q1;

always @(posedge clock)
if (reset)
Q1 = 0;
else
Q1 = Q0;

Each block, taken on its own, is a good description of
a flipflop with synchronous reset. Linking the two blocks
together, you should expect to get a 2-bit twisted ring
counter (count sequence 00-01-11-10-00), right?
No, wrong. The problem is that the SIMULATOR
must execute the two blocks sequentially at the
moment of @(posedge clock). If the first block
executes first, then Q1 will get the wrong value.
If the second block executes first, then Q0 will
get the wrong value. Simulation will not match
the results you get from synthesised hardware.

But when we use nonblocking assignment,
life is good:

always @(posedge clock)
if (reset)
Q0 <= 0;
else
Q0 <= ~Q1;

always @(posedge clock)
if (reset)
Q1 <= 0;
else
Q1 <= Q0;

Now, when @(posedge clock) happens, the
two blocks both execute - in some unknown
sequence - but that's OK because each one
uses the OLD value for the right-hand side of
the assignments. In other words, the value of
Q0 and Q1 as they were just before the clock.
The nonblocking assignment <= does NOT
immediately update the left-side target. Instead
it schedules the update to take place a short time
later.

What does "a short time" mean? It is what VHDL
would call a "delta cycle": we wait until ALL always
blocks have finished executing and are waiting for
their controlling event. Then, and NOT BEFORE,
we update all the left-side target variables with their
new scheduled values. Of course this may trigger
some other always blocks to execute, but that's OK
because NONE OF THE UPDATES HAVE CAUSED A
NEW CLOCK EVENT so the clocked always blocks
will NOT execute again.

Please don't fight it. Follow the rule - the only one
that matters:
- Use blocking assignment (=) everywhere, EXCEPT:
- when assigning, in a clocked always block, to a
variable that will be used outside the block, use
nonblocking assignment (<=).

You will read other, less flexible rules - for example in
Cliff Cummings's papers. That's OK too. It is NOT
OK to use blocking assignment to clocked variables
that will be used in other always blocks.

Enjoy!
--
Jonathan Bromley

rickman

unread,
May 19, 2010, 10:52:54 PM5/19/10
to
On May 19, 6:33 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

I don't use Verilog much so this is a bit confusing to me. I have
always equated the blocking assignment to variable assignment in VHDL
and non-blocking assignment to signal assignment. Your statement that
blocking assignments for combinatorial logic in always blocks doesn't
map to VHDL. What is wrong with non-blocking assignments for
combinatorial logic in always blocks?

Rick

Patrick Maupin

unread,
May 19, 2010, 11:05:23 PM5/19/10
to

I know that it can sometimes cause simulation slowdowns if you use non-
blocking assignments in combinatorial always blocks. Other than that,
I've never done it, so never thought deeply about it.

Regards,
Pat

Jonathan Bromley

unread,
May 20, 2010, 3:38:39 AM5/20/10
to
[me]

> > - Use blocking assignment (=) everywhere, EXCEPT:
> > - when assigning, in a clocked always block, to a
> >   variable that will be used outside the block, use
> >   nonblocking assignment (<=).

[Rick]


> I don't use Verilog much so this is a bit confusing to me.  I have
> always equated the blocking assignment to variable assignment in VHDL
> and non-blocking assignment to signal assignment.  Your statement that
> blocking assignments for combinatorial logic in always blocks doesn't
> map to VHDL.  What is wrong with non-blocking assignments for
> combinatorial logic in always blocks?

There's nothing _wrong_ with it, and you're broadly right to
think of nonblocking assignment as similar to signal assignment
in VHDL. However, there are a few issues that change the scene.

First, the continuous assignment in Verilog

assign target = expression;

is superficially very much like a VHDL concurrent signal
assignment, but it has blocking assignment (no delta delay)
behaviour. So it's probably more consistent to make all your
other combinational logic have that same behaviour too.

The second issue is that blocking assignment in combinational
logic allows you to implement clock gating without a delta
delay. As I'm sure you are aware, the fact that every VHDL
signal assignment - even a trivial copy - costs a delta delay
can easily introduce strange behaviour in RTL (zero-delay)
simulation, if you do any manipulation at all of the clock.
Blocking assignment in Verilog combinational logic allows you
to avoid that problem in almost all practical cases.

There's a further tweak, too - what should you do about latches
(if you use them)? Most people would say that assignments to
latch variables like this...

always @*
if (Transparent)
Q = D;

should be done with blocking assignment because they are
essentially combinational.

Patrick is right that nonblocking assignment has a
performance cost in the simulator. It typically prevents
the simulator from merging combinational blocks into a
single sequential process. Whether that is a significant
issue in practice I really have no idea. My gut feeling
is that the difference would be insignificant in most
realistic simulations, but others may know different from
experience.
--
Jonathan Bromley

Jan Decaluwe

unread,
May 20, 2010, 4:08:17 AM5/20/10
to
On May 20, 4:52 am, rickman <gnu...@gmail.com> wrote:

> I don't use Verilog much so this is a bit confusing to me.  I have
> always equated the blocking assignment to variable assignment in VHDL
> and non-blocking assignment to signal assignment.  Your statement that
> blocking assignments for combinatorial logic in always blocks doesn't
> map to VHDL.  What is wrong with non-blocking assignments for
> combinatorial logic in always blocks?

Absolutely nothing. In fact, using non-blocking assignments in the
VHDL way, for every signal that communicates with other blocks, is a
very good idea.

Cummings' guideline to use only blocking assignments for combinatorial
logic is problematic, because it creates an unnecessary exception that
encourages something that is inherently dangerous.

The fact that communication based on blocking assignments works for
combinatorial logic is a coincidence and actually not that trivial to
prove. It depends not only on the inherent nature of combinatorial
logic, but also on "sensible usage".

Cummings' guidelines are problematic in general because they
artificially discuss races in the context of synthesizable logic. But
Verilog, the language, doesn't care about synthesis. Races are races,
and there are plenty of race opportunities in high level models and
test benches also. Those cases need a working guideline too.

So here it is: Decaluwe's universal guideline for race-free HDL
assignments.
"""
Use non-blocking assignments (signals) for communication.
Use blocking assignments (variables) for local computation.
"""

In other words: keep those bl**king assignments local :-)

It works for everything: for combinatorial logic, sequential logic,
test benches and high level models. Moreover, it works for both
Verilog and VHDL (and MyHDL). Finally, it lets you use blocking
assignments locally, including in sequential logic descriptions, a
feature dear to my heart.

Think about it: one simple guideline which is safer and more powerful,
and you can simply forget about Cummings' awkward guidelines and
reasoning style. Life can be simple :-)

Jan


rickman

unread,
May 20, 2010, 8:34:22 AM5/20/10
to
On May 20, 3:38 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

I was not aware that Verilog did not use delta delays in combinatorial
assignments. I would say in this case blocking assignments are a bad
thing. If I am gating my clock, then that introduces delays. If
simulating a delta delay causes issues in my simulation, then that
would match the real world, no? I suppose there are tools used to
assure that minimum hold times are maintained, which is where clock
skew would bite you.


> There's a further tweak, too - what should you do about latches
> (if you use them)?  Most people would say that assignments to
> latch variables like this...
>
>    always @*
>      if (Transparent)
>        Q = D;
>
> should be done with blocking assignment because they are
> essentially combinational.

But why would it matter? Convention is fine, but if it doesn't have a
purpose, then what's the... purpose?


> Patrick is right that nonblocking assignment has a
> performance cost in the simulator.  It typically prevents
> the simulator from merging combinational blocks into a
> single sequential process.  Whether that is a significant
> issue in practice I really have no idea.  My gut feeling
> is that the difference would be insignificant in most
> realistic simulations, but others may know different from
> experience.

How could combinatorial blocks be merged or even properly be evaluated
without delta delays? Help me understand.

assign A = B xor C;

assign B = not C;

If C changes, does A fire once or twice? Does it depend on the order
of evaluation of the two assignments? Does A ever have the value of
zero?

I'm not so worried about performance issues unless they are truly
significant. I'm much more concerned that the simulation matches the
real world as much as possible.

BTW, is there a reason why the non-delay assignment is called
"blocking"? I'm trying to come up with a way to remember the names
correctly. It seems to me the delayed assignment would be called
blocking...

Rick

Jonathan Bromley

unread,
May 20, 2010, 10:15:46 AM5/20/10
to
Rick,

> I was not aware that Verilog did not use delta delays in combinatorial
> assignments.  I would say in this case blocking assignments are a bad
> thing.  If I am gating my clock, then that introduces delays.  If
> simulating a delta delay causes issues in my simulation, then that
> would match the real world, no?  I suppose there are tools used to
> assure that minimum hold times are maintained, which is where clock
> skew would bite you.

Right - I think the idea is that clock gating would normally
be designed (after P&R) to avoid hold time trouble, but it's
tough to represent that in your RTL, so one possible way out
is to arrange that zero-delay combinational logic is "faster"
than zero-delay clock-to-output propagation of a FF. This will
automatically give RTL zero-delay sim that matches your finished
device with real delays in it.

> > There's a further tweak, too - what should you do about latches
>

> But why would it matter?  Convention is fine, but if it doesn't have a
> purpose, then what's the... purpose?

Errrm, I don't really know... Cliff Cummings discusses this briefly
in the well-known publications, but I've never had any reason to
design latches in Verilog so I didn't give it much attention.
I'm pretty sure that the same arguments apply as for combinational
logic: nonblocking <= assignment will work just fine, but introduces
delta delays that might possibly cause trouble with clock skew;
blocking = assignment is also OK and may possibly help to avoid
the clock skew problem.

> How could combinatorial blocks be merged or even properly be evaluated
> without delta delays?  Help me understand.
>
> assign A = B xor C;
> assign B = not C;

That's a perfect example: the simulator can analyse the
dependencies among variables, and then collapse that to
(approximately!)

always @(C) begin
B = not C;


A = B xor C;

end

The transformation saves some swapping between processes,
and there's no visible difference to the user. It's
process swapping that dominates simulation performance
for RTL, and especially for gate-level sim, so this
kind of process merging is good. In VHDL it usually
can be done only for processes that have identical
sensitivity lists (in other words, clocked processes
triggered by the same clock edge).

> If C changes, does A fire once or twice?  Does it depend on the order
> of evaluation of the two assignments?  

I guess so. But I defy you to write any code that would reliably
allow you to tell the difference, and of course you would never
expect RTL code to model combinational glitching in a trustworthy
manner, so there's nothing wrong with that. The final settled
result will be the same in either case.

> Does A ever have the value of zero?

It might, but it would have that value for "less than a delta
cycle" (in VHDL-speak) - the zero might be present on the
internal representation of A, but only within iterations around
the Active region of the Verilog scheduler (don't ask); and
simulators are NOT obliged to detect such glitches even if you
have some other block somewhere like this...

always @A $display("at time %0d, A=%b", $time, A);

Delta-delay glitches, such as can be obtained with
combinational logic in VHDL or nonblocking assignment
in Verilog, *would* be detected by that code.

> I'm not so worried about performance issues unless they are truly
> significant.  I'm much more concerned that the simulation matches the
> real world as much as possible.

Fully agreed. I was merely responding to Patrick's point.
On the other hand, one of Verilog's flagship features is
its performance (matters very much to post-layout sim people)
and some of the rules about nondeterminacy are at least in
part designed to help get that performance by allowing
simulators to do various optimisations. Mismatches with
reality will always happen when you work in the grey areas,
and that's precisely what "coding guidelines" are designed
to help you avoid (as, of course, you know very well).

> BTW, is there a reason why the non-delay assignment is called
> "blocking"?  I'm trying to come up with a way to remember the names
> correctly.  It seems to me the delayed assignment would be called
> blocking...

"Blocking" in the sense of blocking the flow of procedural
execution until the update has taken effect. The meaning
is more obvious when you add intra-assignment delay (roughly
equivalent to VHDL "after" delay):

A = #5 EXPR; // (1) Blocking
A <= #5 EXPR; // (2) Nonblocking

Line (1) first evaluates EXPR, then blocks execution for 5 time units,
then updates A, then moves on to executing the next statement.

Line (2) evaluates EXPR, but then does NOT block; it simultaneously:
- sets up a scheduled update of A at a time 5 units in the future;
- moves on immediately to execution of the next statement.

The second form (2), nonblocking, is very similar to VHDL
A <= transport EXPR after 5 ns;

The first form (1), blocking, is effectively:
temp_variable = EXPR;
#5; // like WAIT FOR 5 NS;
A = temp_variable;

Anyway, that's the reason for the [non]blocking naming, I think.

I don't think anyone can be blamed for wanting to steer clear
of all this stuff....

--
Jonathan Bromley

Patrick Maupin

unread,
May 20, 2010, 1:28:11 PM5/20/10
to
On May 20, 3:08 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:

> Cummings' guideline to use only blocking assignments for combinatorial
> logic is problematic, because it creates an unnecessary exception that
> encourages something that is inherently dangerous.

Can you show a real-world example of this danger?

> The fact that communication based on blocking assignments works for
> combinatorial logic is a coincidence and actually not that trivial to
> prove. It depends not only on the inherent nature of combinatorial
> logic, but also on "sensible usage".

Blocking assignments to "registers" inside non-clocked blocks and
continuous assignments to "wires" are essentially the same thing. I
don't see this as any kind of coincidence. If proof of a non-clocked
set of gates requires some sort of inherent propagation delay, that
might make the proof suspect, unless you can also prove that the
propagation delay is the correct magnitude.

> Cummings' guidelines are problematic in general because they
> artificially discuss races in the context of synthesizable logic. But
> Verilog, the language, doesn't care about synthesis. Races are races,
> and there are plenty of race opportunities in high level models and
> test benches also. Those cases need a working guideline too.

In general, the bad effects of a race in your test bench will be that
the test fails. In general the bad effects of a post-synthesis race
are either, again, that the test fails (if you are lucky) or that the
silicon fails (if you are unlucky). So why is it a problem to explain
things in the context of synthesis?

> So here it is: Decaluwe's universal guideline for race-free HDL
> assignments.
> """
> Use non-blocking assignments (signals) for communication.
> Use blocking assignments (variables) for local computation.
> """

[ Rest of comment on this snipped. ]

Yes, this will work. But in practice, examination to insure that
these guidelines have been followed can be more time-consuming than if
other guidelines are followed, and it may be possible, using just
these guidelines, to write code that may be more conceptually
difficult to understand than the code you write using other
guidelines. But that's (obviously) just my opinion.

Regards,
Pat

Jonathan Bromley

unread,
May 20, 2010, 4:34:51 PM5/20/10
to
On Thu, 20 May 2010 10:28:11 -0700 (PDT), Patrick Maupin wrote:

>On May 20, 3:08�am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
>
>> Cummings' guideline to use only blocking assignments for combinatorial
>> logic is problematic, because it creates an unnecessary exception that
>> encourages something that is inherently dangerous.
>
>Can you show a real-world example of this danger?

Easily, if you will permit the choice of "real world" to
extend somewhat outside the very constrained bounds of
RTL-for-synthesis.

>> The fact that communication based on blocking assignments works for
>> combinatorial logic is a coincidence and actually not that trivial to
>> prove. It depends not only on the inherent nature of combinatorial
>> logic, but also on "sensible usage".

I suspect that Jan, like me, is unhappy about Verilog's
completely uncontrolled concurrency model.

Decades ago, software folk discovered that you need some
structures and disciplines to make concurrency work.
Without them, processes merrily trample on each other's
variables and all bets are off. There are many possible
ways to do it right, some prettier than others:

- evaluate/update disciplines (VHDL, SystemC, various other
discrete-event simulation languages)
- semaphores (readily available as OS primitives in many
environments)
- monitors (ditto) - VHDL protected types are a bit like this
- Ada-style client-server rendezvous
- CSP (Occam, Handel-C, Haste)

And then there's Verilog:
- anyone can mess with any shared variable at any time,
with an explicit caveat in the language that you can't
expect any kind of built-in control

So I would totally support Jan's position that combinational
logic, with its acyclic dependencies and stateless behaviour,
is a special case that just happens to work well in Verilog.
The late addition of nonblocking assignment to Verilog was,
I suggest, an admission that this uncontrolled concurrency
was indeed a very serious problem in other situations.
Clocked logic is just one such, but one that is likely to
be evident and problematic for hardware designers.

>Blocking assignments to "registers" inside non-clocked blocks and
>continuous assignments to "wires" are essentially the same thing.

In the synthesis mindset, yes. But only there. In the
semantics of Verilog as a simulation language (and that's
how it's defined) they are as different as chalk and cheese.
They happen to give the same results if you use them
to model zero-delay combinational logic. Of course
that is partly a reflection of Verilog's cleverly
focused design for its chosen applications.

>don't see this as any kind of coincidence.

No more than the "coincidence" that concurrent signal
assignment and a combunational-style process in VHDL
are exactly equivalent by definition. And there they
both exhibit delta-delay behaviour. Once again:
combinational logic is a special case that can be
handled in a variety of ways. Some of those ways don't
work reliably for more general concurrency problems.

> If proof of a non-clocked
>set of gates requires some sort of inherent propagation delay, that
>might make the proof suspect, unless you can also prove that the
>propagation delay is the correct magnitude.

There is of course no such "proof"; indeed, the nature of
combinational logic (output must be a pure function of
inputs) makes it possible to prove just the opposite.
I don't think that in any way invalidates Jan's concerns,
except possibly from a myopic RTL-centric viewpoint.
--
Jonathan Bromley

Patrick Maupin

unread,
May 20, 2010, 5:28:49 PM5/20/10
to
On May 20, 3:34 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> On Thu, 20 May 2010 10:28:11 -0700 (PDT), Patrick Maupin wrote:
> >On May 20, 3:08 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
>
> >> Cummings' guideline to use only blocking assignments for combinatorial
> >> logic is problematic, because it creates an unnecessary exception that
> >> encourages something that is inherently dangerous.
>
> >Can you show a real-world example of this danger?
>
> Easily, if you will permit the choice of "real world" to
> extend somewhat outside the very constrained bounds of
> RTL-for-synthesis.

OK, I'll bite. Show me...

[ Other stuff snipped..]

> I suspect that Jan, like me, is unhappy about Verilog's
> completely uncontrolled concurrency model.
>
> Decades ago, software folk discovered that you need some
> structures and disciplines to make concurrency work.  
> Without them, processes merrily trample on each other's
> variables and all bets are off.  There are many possible
> ways to do it right, some prettier than others:
>
> - evaluate/update disciplines (VHDL, SystemC, various other
>   discrete-event simulation languages)
> - semaphores (readily available as OS primitives in many
>   environments)
> - monitors (ditto) - VHDL protected types are a bit like this
> - Ada-style client-server rendezvous
> - CSP (Occam, Handel-C, Haste)

While the language constructs are nice, certainly it is possible to do
useful concurrency work in C. And semaphores, monitors, and mutexes
are used from C every day without a fundamental language rework. (As
an aside, while erlang or go may be the way of the future, replacing
Ada and Occam as the way of the future, and while the C/C++ standard
may lurch towards the future by digesting those really useful bits
from other languages, it is possible that the dominant system language
for a long time to come will be called C, just as the dominant
technical language is called English.)

> And then there's Verilog:
> - anyone can mess with any shared variable at any time,
>   with an explicit caveat in the language that you can't
>   expect any kind of built-in control

Au contraire. It may not be as great as some of the languages you
mentioned, but it's certainly much better than C. If you want to
insure that another process can never see incoherent state between
variable X and variable Y, just make sure you update them at exactly
the same time. No semaphore, mutex, or monitor required. Also,
unlike C, (assuming you at least follow the rule of at most one module
per file) two different processes in different files cannot write to
the same "shared variable" in synthesizable code at all, and can't
very easily do it inadvertently in non-synthesizable code.

> So I would totally support Jan's position that combinational
> logic, with its acyclic dependencies and stateless behaviour,
> is a special case that just happens to work well in Verilog.

Special case, perhaps. Coincidence? I think not :-)

> The late addition of nonblocking assignment to Verilog was,
> I suggest, an admission that this uncontrolled concurrency
> was indeed a very serious problem in other situations.
> Clocked logic is just one such, but one that is likely to
> be evident and problematic for hardware designers.
>
> >Blocking assignments to "registers" inside non-clocked blocks and
> >continuous assignments to "wires" are essentially the same thing.
>
> In the synthesis mindset, yes.  But only there.  In the
> semantics of Verilog as a simulation language (and that's
> how it's defined) they are as different as chalk and cheese.
> They happen to give the same results if you use them
> to model zero-delay combinational logic.  Of course
> that is partly a reflection of Verilog's cleverly
> focused design for its chosen applications.

I do view the synthesis results as the end product, yes. Anything
that has to be done in the testbench is ancillary to that (and by the
way, Verilog's laissez-faire attitude to coding is a double-edged
sword that can, in some cases, make the test code very readable and
maintainable).

> >don't see this as any kind of coincidence.
>
> No more than the "coincidence" that concurrent signal
> assignment and a combunational-style process in VHDL
> are exactly equivalent by definition. And there they
> both exhibit delta-delay behaviour.  Once again:
> combinational logic is a special case that can be
> handled in a variety of ways.  Some of those ways don't
> work reliably for more general concurrency problems.
>
> > If proof of a non-clocked
> >set of gates requires some sort of inherent propagation delay, that
> >might make the proof suspect, unless you can also prove that the
> >propagation delay is the correct magnitude.
>
> There is of course no such "proof"; indeed, the nature of
> combinational logic (output must be a pure function of
> inputs) makes it possible to prove just the opposite.

Agreed.

> I don't think that in any way invalidates Jan's concerns,
> except possibly from a myopic RTL-centric viewpoint.

Guilty as charged. While the process of getting to correct
synthesizable logic is interesting, useful, and necessary, the actual
synthesizable logic itself is, if not more interesting, at least more
useful and necessary.

Regards,
Pat

Jonathan Bromley

unread,
May 21, 2010, 3:44:04 AM5/21/10
to
Patrick,

I don't have time to write a complete reply just now,
but I can't let this piece of nonsense go unchallenged:

[me]


> > And then there's Verilog:
> > - anyone can mess with any shared variable at any time,

<snip>
[Pat]


> If you want to
> insure that another process can never see incoherent state between
> variable X and variable Y, just make sure you update them at exactly
> the same time.

That is simply untrue:

always @(posedge clock)
X = some_expression;
always @(posedge clock)
Y = some_other_expression;
always @(posedge clock) begin : observer
if (some relationship between X and Y) ....;
end

"observer" has absolutely no guarantee of coherence of X and Y.
So, you may say, let's update them together:

always @(posedge clock) begin
X = some_expression;
Y = some_other_expression;
end

Bzzzt! Doesn't work: Verilog does not guarantee atomic execution
of a zero-time sequential block, so "observer" still has no
guarantee of coherence. So we must resort to yet another
special case (and even this unusable mess isn't strictly
guaranteed to give atomic update, even though it will
most likely do so in practice):

always @(posedge clock)
{X,Y} = {some_expression, some_other_expression};

> No semaphore, mutex, or monitor required.

You're kidding, right? In Verilog you make this
work correctly by wheeling out the evaluate/update
model made possible by nonblocking assignment.
In other environments you would use other exclusion
or synchronisation primitives. Either way, you need
some discipline.

Verilog is _much_ worse than C in this regard because
it has concurrency constructs built in to the language,
but they are completely undisciplined. In C, to get
concurrency you must appeal to some library or toolkit;
if properly designed, that library will provide not
only the parallelism but also the synchronisation
primitives that you need, so you get a proper way to
do things as a single package.

I'll try to respond more thoughtfully to your other
points over the weekend.
--
Jonathan Bromley

nemo

unread,
May 21, 2010, 4:13:21 AM5/21/10
to
On May 20, 10:15 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> Rick,
>
> > I was not aware that Verilog did not use delta delays in combinatorial
> > assignments.  I would say in this case blocking assignments are a bad
> > thing.  If I am gating my clock, then that introduces delays.  If
> > simulating a delta delay causes issues in my simulation, then that
> > would match the real world, no?  I suppose there are tools used to
> > assure that minimum hold times are maintained, which is where clock
> > skew would bite you.
>
> Right - I think the idea is that clock gating would normally
> be designed (after P&R) to avoid hold time trouble, but it's
> tough to represent that in your RTL, so one possible way out
> is to arrange that zero-delay combinational logic is "faster"
> than zero-delay clock-to-output propagation of a FF.  This will
> automatically give RTL zero-delay sim that matches your finished
> device with real delays in it.

Personally I think this is a strange concept that a zero-delay sim
should be... I can't think of a word, "optimized" is not right,
"tweaked" seems biased... "adjusted" to allow a particular type of
design to simulate as if there were no delay in a logic element, but
that there is a delay in sequential elements. This can be handled
very easily by adding explicit delays to sequential elements. Then it
is very clear that an assumption is being made about relative delays.
I guess this shows that I never gate clocks. I can see how this would
be a real can of worms.

Has anyone here used clock gating in VHDL? How do you handle that?


> > How could combinatorial blocks be merged or even properly be evaluated
> > without delta delays?  Help me understand.
>
> > assign A = B xor C;
> > assign B = not C;
>
> That's a perfect example: the simulator can analyse the
> dependencies among variables, and then collapse that to
> (approximately!)
>
>   always @(C) begin
>     B = not C;
>     A = B xor C;
>   end
>
> The transformation saves some swapping between processes,
> and there's no visible difference to the user.  

Except that it produces a glitch free output which is not realistic.
Of course, in the real world the implemented logic will be determined
by the tools so there may or may not be a glitch in the output. So I
guess this is similar to clock gating.


> > BTW, is there a reason why the non-delay assignment is called
> > "blocking"?  I'm trying to come up with a way to remember the names
> > correctly.  It seems to me the delayed assignment would be called
> > blocking...
>
> "Blocking" in the sense of blocking the flow of procedural
> execution until the update has taken effect.  The meaning
> is more obvious when you add intra-assignment delay (roughly
> equivalent to VHDL "after" delay):
>
>   A = #5 EXPR;  // (1) Blocking
>   A <= #5 EXPR; // (2) Nonblocking
>
> Line (1) first evaluates EXPR, then blocks execution for 5 time units,
> then updates A, then moves on to executing the next statement.

Wow! I didn't know it worked like that. I don't think that is the
same in VHDL. I think the VHDL "after" delay is done without blocking
the execution of the sequential flow even for variables.


> Line (2) evaluates EXPR, but then does NOT block; it simultaneously:
> - sets up a scheduled update of A at a time 5 units in the future;
> - moves on immediately to execution of the next statement.
>
> The second form (2), nonblocking, is very similar to VHDL
>   A <= transport EXPR after 5 ns;
>
> The first form (1), blocking, is effectively:
>   temp_variable = EXPR;
>   #5;  // like WAIT FOR 5 NS;
>   A = temp_variable;
>
> Anyway, that's the reason for the [non]blocking naming, I think.
>
> I don't think anyone can be blamed for wanting to steer clear
> of all this stuff....

Yeah, it will be interesting to learn.

Rick

nemo

unread,
May 21, 2010, 4:19:04 AM5/21/10
to

This last guideline is essentially what VHDL does. Variables only
have scope within a process so can not be used for communication
between processes. What guidelines would accomplish the same thing
and be easier to verify? Sounds like something a tool should be
checking for you.

Rick

Jan Decaluwe

unread,
May 21, 2010, 5:07:14 AM5/21/10
to
On May 20, 7:28 pm, Patrick Maupin <pmau...@gmail.com> wrote:
> On May 20, 3:08 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
>
> > Cummings' guideline to use only blocking assignments for combinatorial
> > logic is problematic, because it creates an unnecessary exception that
> > encourages something that is inherently dangerous.
>
> Can you show a real-world example of this danger?

Use blocking assignments for communication anywhere else, and you
immediately have race problems. Just look in the manuals of mainstream
synthesis vendors for plenty of problematic examples.

"As a matter of forming good coding habits", avoid blocking
assignments for communication altogether, and stop worrying about
races.

> > The fact that communication based on blocking assignments works for
> > combinatorial logic is a coincidence and actually not that trivial to
> > prove. It depends not only on the inherent nature of combinatorial
> > logic, but also on "sensible usage".
>
> Blocking assignments to "registers" inside non-clocked blocks and
> continuous assignments to "wires" are essentially the same thing.  I
> don't see this as any kind of coincidence.

That is not what I was talking about.

Suppose you start manipulating clocks combinatorially, using assigns
or blocking assignments. I don't see why the resulting transactions
would be race-free. I immediately add that this is probably
nonsensical usage, and that in practice, blocking assignment-based
communication works for the special case of "meaningful" combinatorial
logic. But do you see why I call that a coincidence? It feels like
plain luck based on shaky foundations.

> > Cummings' guidelines are problematic in general because they
> > artificially discuss races in the context of synthesizable logic. But
> > Verilog, the language, doesn't care about synthesis. Races are races,
> > and there are plenty of race opportunities in high level models and
> > test benches also. Those cases need a working guideline too.
>
> In general, the bad effects of a race in your test bench will be that
> the test fails.  In general the bad effects of a post-synthesis race
> are either, again, that the test fails (if you are lucky) or that the
> silicon fails (if you are unlucky).  So why is it a problem to explain
> things in the context of synthesis?

Given the fact that races are costly in any case, do you see the value
of having one single guideline that covers everything?

> > So here it is: Decaluwe's universal guideline for race-free HDL
> > assignments.
> > """
> > Use non-blocking assignments (signals) for communication.
> > Use blocking assignments (variables) for local computation.
> > """
>
> [ Rest of comment on this snipped. ]
>
> Yes, this will work.  But in practice, examination to insure that
> these guidelines have been followed can be more time-consuming than if
> other guidelines are followed

I have a single guideline that covers everything; Cummings has a set
of guidelines that covers synthesis only and that introduces a number
of special cases. It seems obvious that my proposal will make the work
of the reviewer or the linting tool both more meaningful and much
simpler.

Jan


Jan Decaluwe

unread,
May 21, 2010, 7:12:27 AM5/21/10
to
On May 20, 10:34 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> I suspect that Jan, like me, is unhappy about Verilog's
> completely uncontrolled concurrency model.

Absolutely correct. Rather unhappy :-)

In 1990, I designed a chip with Verilog, using blocking assignments
only because that's all there was at the time. Non-blocking behavior
was provided by using modules and ports - otherwise Verilog would have
been completely unusable at the time.

Much later, in 2000, I found out that simulation vendors had exploited
loopholes in the Verilog standard to take away non-blocking behavior
from ports. In other words, my trusted coding style and legacy code
had now become undeterministic and unreliable.

When I complained about this, I experienced not a single grain of
sympathy or understanding from the Verilog design community. Instead,
they started to explain the loopholes to me. The message was that I
had been stupid to think that it was possible to design with Verilog
in a reliable way at the time.

At that moment, I developed a fundamental distrust against Verilog's
zero-delay (non)model, and against Verilog's design community and its
guru's in the same pass. I learned to forgive VHDL almost anything
just for giving us the delta cycle algorithm. When using Verilog, I
tried to do it as much as possible as VHDL. And whenever I hear
someone sing the praises of Verilog's ease of use, I invariably think:
you don't have enough experience.

For my outcry in despair at the time, see:

http://groups.google.com/group/comp.lang.verilog/browse_frm/thread/edc6d326a821c9a9/67ec9f89afe22b3b

Jan


Jonathan Bromley

unread,
May 21, 2010, 8:37:46 AM5/21/10
to
On May 21, 12:12 pm, Jan Decaluwe <j...@jandecaluwe.com> wrote:

> For my outcry in despair at the time, see:
>

> http://groups.google.com/group/comp.lang.verilog/browse_frm/thread/ed...

At least Evan Lavelle backed you up :-)
--
Jonathan Bromley

Jan Decaluwe

unread,
May 21, 2010, 9:20:15 AM5/21/10
to
On May 21, 2:37 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

That's right. My thanks to him, even if they are little out-of-date :-)

Patrick Maupin

unread,
May 21, 2010, 2:40:22 PM5/21/10
to
On May 21, 2:44 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> Patrick,
>
> I don't have time to write a complete reply just now,
> but I can't let this piece of nonsense go unchallenged:
>
> [me]> > And then there's Verilog:
> > > - anyone can mess with any shared variable at any time,
>
> <snip>
> [Pat]
>
> > If you want to
> > insure that another process can never see incoherent state between
> > variable X and variable Y, just make sure you update them at exactly
> > the same time.
>
> That is simply untrue:
>
> always @(posedge clock)
>   X = some_expression;
> always @(posedge clock)
>   Y = some_other_expression;
> always @(posedge clock) begin : observer
>   if (some relationship between X and Y) ....;
> end

Yes, I should have known that you would be both pedantic and
dismissive.
What I said is not nonsense *if* you always use non-blocking
assignments in sequential blocks. Of course you know I believe that
is the right answer, so of course you show an opposite example.

<snipped lots more examples of blocking assignments>

> > No semaphore, mutex, or monitor required.
>
> You're kidding, right?  In Verilog you make this
> work correctly by wheeling out the evaluate/update
> model made possible by nonblocking assignment.

Ahhh, so you *do* understand. But yes, a C semaphore or mutex or
monitor requires something *below* the level of the language, whereas
the Verilog language itself provides the needed primitives, and, let's
face it, "evaluate/update" is what has to happen with clocked
processes in all but the simplest cases.

> In other environments you would use other exclusion
> or synchronisation primitives.  Either way, you need
> some discipline.

Coding requires discipline. With verilog, there is no *extra*
discipline that would be required for the kind of IPC thing we were
discussing than there is for sequential coding in general.

> Verilog is _much_ worse than C in this regard because
> it has concurrency constructs built in to the language,
> but they are completely undisciplined.  In C, to get
> concurrency you must appeal to some library or toolkit;
> if properly designed, that library will provide not
> only the parallelism but also the synchronisation
> primitives that you need, so you get a proper way to
> do things as a single package.

You can easily be as undisciplined in C. The fact that C has no
concurrency, but C + package allows you concurrency doesn't mean that
C + package enforces anything on the user.

Regards,
Pat

Patrick Maupin

unread,
May 21, 2010, 2:47:10 PM5/21/10
to
On May 21, 3:19 am, nemo <gnu...@gmail.com> wrote:

> This last guideline is essentially what VHDL does.  Variables only
> have scope within a process so can not be used for communication
> between processes.  What guidelines would accomplish the same thing
> and be easier to verify?  Sounds like something a tool should be
> checking for you.

Obviously opinions vary, but if you always use non-blocking
assignments in sequential blocks, and always use blocking assignments
in combinatorial blocks, and adhere to a few other guidelines, it's
very easy to spot issues at a glance.

Regards,
Pat

Patrick Maupin

unread,
May 21, 2010, 2:59:48 PM5/21/10
to
On May 21, 4:07 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
> On May 20, 7:28 pm, Patrick Maupin <pmau...@gmail.com> wrote:
>
> > On May 20, 3:08 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
>
> > > Cummings' guideline to use only blocking assignments for combinatorial
> > > logic is problematic, because it creates an unnecessary exception that
> > > encourages something that is inherently dangerous.
>
> > Can you show a real-world example of this danger?
>
> Use blocking assignments for communication anywhere else, and you
> immediately have race problems. Just look in the manuals of mainstream
> synthesis vendors for plenty of problematic examples.

So by "anywhere else" you mean in a sequential block. Yes, I don't do
that.

> "As a matter of forming good coding habits", avoid blocking
> assignments for communication altogether, and stop worrying about
> races.

Well, I just avoid blocking assignments at all in sequential blocks.
As we have discussed previously, that can also be a viable strategy.


[ stuff snipped]

> Suppose you start manipulating clocks combinatorially, using assigns
> or blocking assignments. I don't see why the resulting transactions
> would be race-free. I immediately add that this is probably
> nonsensical usage, and that in practice, blocking assignment-based
> communication works for the special case of "meaningful" combinatorial
> logic. But do you see why I call that a coincidence? It feels like
> plain luck based on shaky foundations.

I see. I agree that (as you have also pointed out in other posts) the
foundations of Verilog were somewhat shaky (at least in the sense of
not being regular and extremely well thought out) and that some of the
subsequent fixes have created a non-orthogonal language.
"Coincidence" sounds like a lucky accident we got there at all, when
at the end of the day, it was through a lot of hard work, so "hack"
might be a better word :-)

[ stuff snipped ]

> Given the fact that races are costly in any case, do you see the value
> of having one single guideline that covers everything?

Yes, but I also see the cost. For example, in a large block with
intermingled blocking/non-blocking assignments, there might be a lot
of scrolling back and forth to determine if a variable is local or
not. For another example, if you need the local variable in another
block, now you have to go back and check all the uses of it and
possibly do some recoding.

> I have a single guideline that covers everything; Cummings has a set
> of guidelines that covers synthesis only and that introduces a number
> of special cases.

Cummings certainly covers synthesis. What in his guidelines will
break for non-synthesis?

> It seems obvious that my proposal will make the work
> of the reviewer or the linting tool both more meaningful and much
> simpler.

Well, I've shown you an example of how I would code something, so you
know my mileage varies on that.

Regards,
Pat

Ali Karaali

unread,
May 22, 2010, 1:24:52 PM5/22/10
to
[Jonathan Bromley]

>The second issue is that blocking assignment in combinational
>logic allows you to implement clock gating without a delta
>delay.

What do you mean by that(implementing clock gating)?

I know,
always@(*) begin
a = b;
c = a;
end
these statements are executed sequentaly, a = b blocks the c = d;

But what about these?
always@(*) begin
a = b; //statement1
c = d; //statement2
end
Is there any order of those staments?

As for the nonblocking,
Is there any order between nonblocking assignments in the same
execution
path according to the verilog standart?

always@(posedge clk) begin
a <= b;
c <= d;
end

Ali

Andy

unread,
May 22, 2010, 4:40:55 PM5/22/10
to
On May 21, 1:40 pm, Patrick Maupin <pmau...@gmail.com> wrote:
>
> You can easily be as undisciplined in C.  The fact that C has no
> concurrency, but C + package allows you concurrency doesn't mean that
> C + package enforces anything on the user.


And just like C + package, Verilog does not enforce anything either.

Andy

Jonathan Bromley

unread,
May 22, 2010, 5:06:08 PM5/22/10
to
On Sat, 22 May 2010 10:24:52 -0700 (PDT), Ali Karaali wrote:

>[Jonathan Bromley]
>
>>The second issue is that blocking assignment in combinational
>>logic allows you to implement clock gating without a delta
>>delay.
>
>What do you mean by that(implementing clock gating)?

If you're using an FPGA, please don't worry about it.

When designing ASICs for low power consumption, folk
often use clock gating to suppress the clock to some
part of the design when it's not active. This is
*not* usually a good idea in an FPGA design, but in
an ASIC it can be a useful technique. So let's
suppose that the designer has correctly crafted a
clock gating signal ClockIsActive, and has carefully
arranged its timing so that
MasterClock & ClockIsActive
will behave nicely, with no unpleasant glitches.
OK, so now we try...

always @(posedge MasterClock)
Qm <= something;

always @*
GatedClock <= MasterClock & ClockIsActive;

always @(posedge GatedClock)
Qg <= Qm;

The problem is that GatedClock is delayed by
one nonblocking assignment delay (a delta cycle)
in just the same way as Qm is delayed. So now
there is a simulation race condition between the
change of Qm and the (posedge GatedClock) that's
used to sample it.

However, if you change the clock gate logic to

always @*
GatedClock = MasterClock & ClockIsActive;

or, just as good,

assign GatedClock = MasterClock & ClockIsActive;

then the clock gate (and any other combinational logic)
updates earlier than the nonblocking assignments, and the
sampling of Qm in the GatedClock domain works correctly.

Of course, this is merely a trick to make zero-delay
simulation work correctly. In the finished device it's
very important to apply appropriate timing constraints
to ensure that the real logic also behaves in this way.


>always@(*) begin
> a = b;
> c = a;
>end
>these statements are executed sequentaly, a = b blocks the c = d;
>
>But what about these?
>always@(*) begin
> a = b; //statement1
> c = d; //statement2
>end
>Is there any order of those staments?

Yes, certainly. Sequential statements in a begin...end block
are definitely executed in order. The whole point about blocking
assignment is that the assignment has completed (has taken effect)
before the next statement is executed. Just like normal software.

>As for the nonblocking,
>Is there any order between nonblocking assignments in the same
>execution
>path according to the verilog standart?
>
>always@(posedge clk) begin
> a <= b;
> c <= d;
>end

Yes! The two assignments execute sequentially. Consequently the
order of activity is:

1) Evaluate "b"
2) Make a delayed assignment of that value to "a" - put the
assignment on the queue of future activity, but don't do it yet
3) Evaluete "d"
4) Make the delayed assignment to "c"
5) Do any other "always" blocks that were triggered by
(posedge clk), in the same way as I just described
6) When all such activity is finished, update the variables
that have scheduled delayed assignments, BUT DO IT IN THE
SAME ORDER IN WHICH THE CORRESPONDING ASSIGNMENTS WERE
EXECUTED (first-in first-out). Therefore, first update
"a" and then update "c".

Hope this helps you to see what's happening.
--
Jonathan Bromley

Jonathan Bromley

unread,
May 22, 2010, 5:38:11 PM5/22/10
to
On Fri, 21 May 2010 11:40:22 -0700 (PDT), Patrick Maupin wrote:

>Yes, I should have known that you would be both pedantic and
>dismissive.

"Pedantic" I regard as a compliment in this context, because
it's too easy to say things that are unclear or have loopholes;
pedantry is useful. "Dismissive" is less welcome; I'm sorry
you felt that. I think we are diametrically opposed on some
"cultural" issues about how these things are best done, but
that doesn't mean I dismiss your position; I'm just rather
keen to expose any weaknesses I perceive in it :-)

>Of course you know I believe that

[the use of NBA to give meaning to "at the same time"]


>is the right answer, so of course you show an opposite example.

Yes, because it is important to be pedantic. The notion of
"at the same time" is not at all simple in Verilog (take
a look at the LRM description of the scheduler!) and it
is completely inappropriate to use such a phrase when
trying to be precise about what makes sense and what doesn't.
By contrast, VHDL's extremely rigid evaluate/update model
makes it rather easy to reason about "at the same time"
provided you avoid a very tiny set of well-documented
loopholes in the language (the broken form of shared
variable in VHDL93, sharing access to files).

>Ahhh, so you *do* understand.

Well, of course I do to some extent; and, of course, so
do you. We both know perfectly well how to achieve the
results we need. The difference seems to be that you
are a vigorous apologist for the status quo, while I
would love to have things be very different. However,
I'm sufficiently pragmatic to know that I can't make
a real difference. That doesn't, and shouldn't, stop
me having a good old rant about it from time to time :-)

> But yes, a C semaphore or mutex or
>monitor requires something *below* the level of the language

I don't think I agree with that. C is a sufficiently low-level
language that you can create those primitives within the core
language if you wish to do so.

>whereas
>the Verilog language itself provides the needed primitives, and, let's
>face it, "evaluate/update" is what has to happen with clocked
>processes in all but the simplest cases.

Right; but Verilog does leave Pandora's box wide open, doesn't it?
Since Verilog does not _enforce_ the use of nonblocking assignment
to shared variables, it effectively has free uncontrolled sharing
of variables among concurrent processes. And yet it didn't, until
SystemVerilog, have even a mutex or semaphore available! This
situation is tolerable only because many (most??) Verilog users
are working within a framework that looks pretty much like
synthesisable logic, where a few fairly simple coding guidelines
are enough to keep you out of trouble. Anyone who's tried to
write a reasonably sophisticated testbench in Verilog, with
multiple threads of control, either is familiar with the
problem of mutual exclusion and has tricks for dealing with
it, or has their head buried in the sand.

--
Jonathan Bromley

Patrick Maupin

unread,
May 22, 2010, 11:22:02 PM5/22/10
to
On May 22, 4:38 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> On Fri, 21 May 2010 11:40:22 -0700 (PDT), Patrick Maupin wrote:
> >Yes, I should have known that you would be both pedantic and
> >dismissive.
>
> "Pedantic" I regard as a compliment in this context, because
> it's too easy to say things that are unclear or have loopholes;
> pedantry is useful. "Dismissive" is less welcome; I'm sorry
> you felt that.

Well, you did use the word "nonsense" instead of simply explaining
that my statement simply required a (bit, lot?) more qualification...

> I think we are diametrically opposed on some
> "cultural" issues about how these things are best done, but
> that doesn't mean I dismiss your position; I'm just rather
> keen to expose any weaknesses I perceive in it :-)

Sure, and the pedantry is fine and helpful in that regard.

> >Of course you know I believe that
>
> [the use of NBA to give meaning to "at the same time"]
>
> >is the right answer, so of course you show an opposite example.
>
> Yes, because it is important to be pedantic. The notion of
> "at the same time" is not at all simple in Verilog (take
> a look at the LRM description of the scheduler!) and it
> is completely inappropriate to use such a phrase when
> trying to be precise about what makes sense and what doesn't.

But, if all assignments in clocked processes are nonblocking, "at the
same time" can make a great deal of sense when dealing with
combinations of those signals.

> By contrast, VHDL's extremely rigid evaluate/update model
> makes it rather easy to reason about "at the same time"
> provided you avoid a very tiny set of well-documented
> loopholes in the language (the broken form of shared
> variable in VHDL93, sharing access to files).

Sure, but VHDL has its own set of problems.

>
> >Ahhh, so you *do* understand.
>
> Well, of course I do to some extent; and, of course, so
> do you. We both know perfectly well how to achieve the
> results we need. The difference seems to be that you
> are a vigorous apologist for the status quo, while I
> would love to have things be very different.

I wouldn't mind terribly if things were different in some ways, but on
balance, I prefer Verilog over VHDL. For one thing, I
programmatically generate a lot of RTL, and I find it extremely easy
to generate Verilog. It's low-level enough that it doesn't get in the
way of trying to place application-specific abstractions on top of it.

> However,
> I'm sufficiently pragmatic to know that I can't make
> a real difference. That doesn't, and shouldn't, stop
> me having a good old rant about it from time to time :-)

Be my guest. But it would nice if you could rant in such a way that
you made the actual target of the rant a bit clearer at the top of the
post :-)

> > But yes, a C semaphore or mutex or
> >monitor requires something *below* the level of the language
>
> I don't think I agree with that. C is a sufficiently low-level
> language that you can create those primitives within the core
> language if you wish to do so.

Well, it's been a decade and a half since I've done any of that sort
of thing in C, but IIRC, the core language doesn't have, e.g. atomic
operations. Now it may be that "i += 1" is usually atomic on a
processor that supports atomic increment; but with multiprocessing,
all bets are off, unless you use (e.g. on the x86) a LOCK prefix in
front of the INC instruction. (In a multiprocessing environment, even
disabling interrupts will be insufficient to guarantee
sychronization.) On a multiprocessin X86, you really need to be able
to do things like LOCK and XCHG or XADD for a full set of primitives,
and I don't think the C language directly supports this; at least not
back when I was doing a lot of C.

> >whereas
> >the Verilog language itself provides the needed primitives, and, let's
> >face it, "evaluate/update" is what has to happen with clocked
> >processes in all but the simplest cases.
>
> Right; but Verilog does leave Pandora's box wide open, doesn't it?

Absolutely.

> Since Verilog does not _enforce_ the use of nonblocking assignment
> to shared variables, it effectively has free uncontrolled sharing
> of variables among concurrent processes.

Right, but as you know, I always use nonblocking assignments in
clocked processes, so really and truly, this is a non-issue for me.

> And yet it didn't, until
> SystemVerilog, have even a mutex or semaphore available!

And, to my knowledge, C still doesn't either...

> This
> situation is tolerable only because many (most??) Verilog users
> are working within a framework that looks pretty much like
> synthesisable logic, where a few fairly simple coding guidelines
> are enough to keep you out of trouble.

Yes. As I mentioned, myopically speaking :-), that's the closest to
the final product.

> Anyone who's tried to
> write a reasonably sophisticated testbench in Verilog, with
> multiple threads of control, either is familiar with the
> problem of mutual exclusion and has tricks for dealing with
> it, or has their head buried in the sand.

Sure, but at the end of the day, you can probably get into trouble
with synchronization (where trouble is defined as "unexpected
behavior") in any language. Personally, although there will always be
room for improvement, I think that the "new world order" (at least for
the world where I live) where synthesizable stuff is in Verilog and
testbenches are moving to System Verilog, is really not too bad.

Regards,
Pat

Patrick Maupin

unread,
May 22, 2010, 11:23:42 PM5/22/10
to

Yes. By "as undisciplined" I meant "equally undisciplined." Sorry if
that was unclear.

Regards,
Pat

Jan Decaluwe

unread,
May 23, 2010, 9:46:11 AM5/23/10
to
On May 21, 8:59 pm, Patrick Maupin <pmau...@gmail.com> wrote:
> On May 21, 4:07 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:

> > Use blocking assignments for communication anywhere else, and you
> > immediately have race problems. Just look in the manuals of mainstream
> > synthesis vendors for plenty of problematic examples.
>
> So by "anywhere else" you mean in a sequential block.  Yes, I don't do
> that.

No, I do mean anywhere else, in particular also for verification-
related tasks where the RTL paradigm does not apply, and which is
typically the bulk of the work.

(When I use the word "sequential" in the context of HDL coding, I mean
RTL. Of course, if you would define it as "anything non-
combinatorial", we are saying the same thing.)

> > "As a matter of forming good coding habits", avoid blocking
> > assignments for communication altogether, and stop worrying about
> > races.
>
> Well, I just avoid blocking assignments at all in sequential blocks.
> As we have discussed previously, that can also be a viable strategy.

I know what you do for synthesis, now let's see about test benches.

> > Given the fact that races are costly in any case, do you see the value
> > of having one single guideline that covers everything?
>
> Yes, but I also see the cost.  For example, in a large block with
> intermingled blocking/non-blocking assignments, there might be a lot
> of scrolling back and forth to determine if a variable is local or
> not.  For another example, if you need the local variable in another
> block, now you have to go back and check all the uses of it and
> possibly do some recoding.

Correct. Note that VHDL makes this task much easier and less costly as
safe communication is enforced by the language.

> > I have a single guideline that covers everything; Cummings has a set
> > of guidelines that covers synthesis only and that introduces a number
> > of special cases.
>
> Cummings certainly covers synthesis.  What in his guidelines will
> break for non-synthesis?

Short answer: nothing, but that is irrelevant because nobody wants
similar restrictions beyond synthesis.

Long answer: this is a puzzling question.

First, the fact that Cummings talks specifically about synthesis tells
me indirectly that he doesn't want to impose anything similar for test
benches and higher level modeling. I don't want to give the impression
of critisizing him for something he doesn't say, I have enough work
with what he actually does say already :-)

Then, his guidelines are formulated in RTL jargon, which makes them
not applicable at higher levels. We first need a translation step that
extracts the "spirit" of his guidelines.

The spirit of his guidelines is: use only a single type of assignment
in any given always block. To me, it is close to obvious that no
Verilog verification engineer will find this acceptable. But of
course, what I find obvious doesn't count, so I will state my
hypothesis explicitly in a form that can be disproven.

My hypothesis is that anyone serious about using Verilog for
verification will, in the same always block:
1) want reliable communication, hence non-blocking assignments.
2) systematically need variable semantics internally for modeling,
hence blocking assignments.

If this is right, the spirit of Cummings is not applicable and you
basically need my guideline. Actually, I suspect that this is what
most Verilog verification engineers are doing already, and I would be
rather surprized if you didn't.

Jan

Patrick Maupin

unread,
May 23, 2010, 1:38:14 PM5/23/10
to
On May 23, 8:46 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
> On May 21, 8:59 pm, Patrick Maupin <pmau...@gmail.com> wrote:
>
> > On May 21, 4:07 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
> > > Use blocking assignments for communication anywhere else, and you
> > > immediately have race problems. Just look in the manuals of mainstream
> > > synthesis vendors for plenty of problematic examples.
>
> > So by "anywhere else" you mean in a sequential block.  Yes, I don't do
> > that.
>
> No, I do mean anywhere else, in particular also for verification-
> related tasks where the RTL paradigm does not apply, and which is
> typically the bulk of the work.

OK. I saw "synthesis" in the original, and thought that was what we
were talking about. Also, you mentioned that you never use blocking
assignments for "communication." Depending on what you mean by
"communication", that could be extremely limiting in a testbench, so I
assumed the context was RTL.

> (When I use the word "sequential" in the context of HDL coding, I mean
> RTL. Of course, if you would define it as "anything non-
> combinatorial", we are saying the same thing.)

Well, if we have to have more categories than combinatorial and
sequential, I would call the third category "advanced." "Advanced" is
really sequential, but is usually a tiny portion of the design. It
can happen in both testbenches and synthesizable logic, however. For
example, in synthesizable it could be I/O latches, or clock gaters.
In testbenches, the same thing, plus clock generation and a few other
corner cases.

In general, you don't need that much advanced stuff, and in general
(especially in RTL) the junior guy isn't coding it, so I have to say
up front, that while it would be nice for a set of guidelines to cover
"advanced", it really isn't that bad if the rules have to be bent a
bit for the advanced stuff.

> > > "As a matter of forming good coding habits", avoid blocking
> > > assignments for communication altogether, and stop worrying about
> > > races.
>
> > Well, I just avoid blocking assignments at all in sequential blocks.
> > As we have discussed previously, that can also be a viable strategy.
>
> I know what you do for synthesis, now let's see about test benches.

Testbenches have slightly relaxed rules, which probably violate your
rule about not using blocking assignments for communications. For
example, if I am generating a signal that is an asynchronous input to
RTL, there is no reason not to use nonblocking assignments to create
it. However, we still follow the rule of not mixing blocking and
nonblocking in the same block.

> > > Given the fact that races are costly in any case, do you see the value
> > > of having one single guideline that covers everything?
>
> > Yes, but I also see the cost.  For example, in a large block with
> > intermingled blocking/non-blocking assignments, there might be a lot
> > of scrolling back and forth to determine if a variable is local or
> > not.  For another example, if you need the local variable in another
> > block, now you have to go back and check all the uses of it and
> > possibly do some recoding.
>
> Correct. Note that VHDL makes this task much easier and less costly as
> safe communication is enforced by the language.

You say that like the cost is unbearable, and like VHDL doesn't have
other costs.

> > > I have a single guideline that covers everything; Cummings has a set
> > > of guidelines that covers synthesis only and that introduces a number
> > > of special cases.
>
> > Cummings certainly covers synthesis.  What in his guidelines will
> > break for non-synthesis?
>
> Short answer: nothing, but that is irrelevant because nobody wants
> similar restrictions beyond synthesis.

Certainly, one of Cummings's major objectives is to insure that
simulation and synthesis results match, and there is no requirement
for that in a testbench. But in that vein, if I understand your
guideline about blocking assignments correctly, I don't want *that*
restriction for a testbench at all.

> Long answer: this is a puzzling question.
>
> First, the fact that Cummings talks specifically about synthesis tells
> me indirectly that he doesn't want to impose anything similar for test
> benches and higher level modeling. I don't want to give the impression
> of critisizing him for something he doesn't say, I have enough work
> with what he actually does say already :-)

Well, you agree that some guidelines are required for testbenches. In
fact, if I understand you correctly, you yourself have a guideline
that I don't follow for testbenches. So, as a starting point, you
could do much worse than reading Cummings's papers and understanding
the reasoning behind his guidelines.

> Then, his guidelines are formulated in RTL jargon, which makes them
> not applicable at higher levels. We first need a translation step that
> extracts the "spirit" of his guidelines.

I can agree with that.

> The spirit of his guidelines is: use only a single type of assignment
> in any given always block.

I do that.

> To me, it is close to obvious that no
> Verilog verification engineer will find this acceptable.

Our dedicated testbench engineers are much more adamant than I am
about following this guideline, so I really don't know how you arrived
at this conclusion.

> But of
> course, what I find obvious doesn't count, so I will state my
> hypothesis explicitly in a form that can be disproven.
>
> My hypothesis is that anyone serious about using Verilog for
> verification will, in the same always block:
> 1) want reliable communication, hence non-blocking assignments.

When a testbench is generating a completely independent signal for
simulation purposes (for an async input), non-blocking assignments may
not be required at all.

> 2) systematically need variable semantics internally for modeling,
> hence blocking assignments.

When a testbench is manipulating dependent signals, we code that like
the RTL -- the blocking and nonblocking assignments are in *different*
always blocks. Honestly, this is not a terrible burden.

> If this is right, the spirit of Cummings is not applicable and you
> basically need my guideline. Actually, I suspect that this is what
> most Verilog verification engineers are doing already, and I would be
> rather surprized if you didn't.

If I understand your guideline correctly, it says any varying inputs
to my DUT need to be created from nonblocking assignments inside the
testbench. I certainly don't need or want that guideline.

Regards,
Pat

Ali Karaali

unread,
May 23, 2010, 5:06:36 PM5/23/10
to
On 23 Mayıs, 00:06, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

> On Sat, 22 May 2010 10:24:52 -0700 (PDT), Ali Karaali wrote:
> >[Jonathan Bromley]
>
> >always@(*) begin
> >    a = b;
> >    c = a;
> >end
> >these statements are executed sequentaly, a = b blocks the c = d;

When b is assigned to a, the always star block will be activated again
because
right handside of the variable is changed?
When activated the block stars immediately or after finish the
execution path?
So the right values is assigned after two iteration but it takes very
small time?

Jonathan Bromley

unread,
May 24, 2010, 4:29:34 AM5/24/10
to
On May 23, 10:06 pm, Ali Karaali <ali...@gmail.com> wrote:

> > >always@(*) begin
> > >    a = b;
> > >    c = a;
> > >end
>

> When b is assigned to a, the always star block
> will be activated again because
> right handside of the variable is changed?

Yes, but....

> When activated the block stars immediately or after finish the
> execution path?

That's not quite the right question. It's important to see
that "always@*" is not a Verilog keyword. What's really
happening is...

always
@* begin
...
end

And, of course, "always" is a procedural infinite loop,
exactly equivalent to "initial forever" or, if you
prefer, "initial while(1)". Some people think, wrongly,
that "always @*" represents a block of code that is
automatically launched whenever an input signal
changes value. That is not the case. The infinite
loop starts to execute at time 0. It immediately
freezes at the @* event control, waiting until
there is a value change on one or more of its inputs;
the event control is then released, and execution
proceeds. The software (procedural code) in the
begin...end block then executes to the end, and
then the "always" construct causes execution to
loop back to the beginning and the whole thing
starts all over again, waiting for @*.

So let's use this understanding to follow what
happens in your example:

1)
At time 0, the "always" statement starts to execute.
2)
Immediately, its execution freezes on @*.
3)
Some time later, some other code changes the value
of variable 'b'.
4)
The @* event control is released; execution of your
code proceeds. First, 'a' is updated with the new
value of 'b'. Next, 'c' is updated with the new
value of 'a' (which came from 'b', of course). This
is just normal software-like execution. Blocking
assignment (with no delay) works exactly like normal
assignment in C or other imperative languages.
5)
Execution has now reached the "end", so the "always"
iterates and execution once more hits the @*. Note
that both 'a' and 'c' already have their correct new
values, after only one iteration of the code.

So far, so clear. Now things get a little more
difficult. As you say, there is a value change
on 'a'. Does that release the @*? I would argue
that it does not, because 'a' already has its new
value at the moment when execution reaches @*.
There is no further value change on 'a'.
However, some simulators (I believe) compute
"value change" by looking at the value of a
variable before and after the execution of code
at a given point in time. Such a simulator might
now see that 'a' has changed since the beginning
of the time-slot, and therefore might choose to
release the @* for a second time. THIS DOES NOT
MATTER because your code describes proper
combinational logic and the second iteration,
if it occurs, will give exactly the same results
as before.

> So the right values is assigned after two iteration
> but it takes very small time?

Possibly.... see above.

Now it's your chance to show how well you understand
all this... let's try another example....

always @* begin


a <= b;
c <= a;
end

Can you "tell the story" of this code, in the same
way as I did for your example? The final result
is almost the same, but the processing is very
different.........

Jonathan Bromley

Ali Karaali

unread,
May 24, 2010, 7:03:28 AM5/24/10
to
On 24 Mayıs, 11:29, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:

For example
@t = 0 a = 3, b = 5, c = 2;

1-) At time = 0 always is started to execute
2-) it is freezed on @*.
3-) (@t = 2 b = 7) b is changed somewhere and @* is released and
the execution is started at the end of begin keyword.
4-) "assigned b to a" in a queue, therefore b isn't change.
(@t = 2) a = 3 b = 7 c = 2 ( a = 7 is in the queue)
5-) "assigned a to c" in a queue too, c isn't change either.
(@t = 2) a = 3 b = 7 c = 2 ( c = 3 is in the queue)
6-) Whole statements is finished so fetch the queue elements,
(@t = 2 + delta_t) b is assigned to a
a = 7 b = 7 c = 2
@(t = 2 + delta_t)and a (a = 3; the value of 'a' at t = 2) is assigned
to c but
a = 7 b = 7 c = 3
7-) And freeze @*
8-) But a was changed so @* is released.
9-) "assigned b to a" in a queue.
(@t = 2 + delta_t)a = 7, b = 7, c = 3
10-)"assigned a to c" in a queue too.
(@t = 2 + delta_t)a = 7, b = 7, c = 3 (c = 7 in the queue)
11-) Whole statements is finished
(@t = 2 + 2*delta_t)and a is assigned to c
a = 7 b = 7 c = 7

But I need to think about all of them again.
@6 How much time does between two assignment have?
a = 7 between c = 3
isn't againg a delta time, right?


Ali


Jonathan Bromley

unread,
May 24, 2010, 9:53:35 AM5/24/10
to
Ali,

> >   always @* begin
> >     a <= b;
> >     c <= a;
> >   end
>
> > Can you "tell the story" of this code, in the same
> > way as I did for your example?  The final result
> > is almost the same, but the processing is very
> > different.........

Hey, wait a minute. This isn't what's supposed to
happen here. The idea is that lazy students ask
idiotic questions, and we tell them they are being
lazy. But now you go and ruin it: not only have
you asked a completely reasonable question based
on your own thoughtful concerns, but you also are
prepared to do some real work to dig deeper. Be
very careful... this might become a habit :-)

> For example
> @t = 0 a = 3, b = 5, c = 2;
>
> 1-) At time = 0 always is started to execute
> 2-) it is freezed on @*.
> 3-) (@t = 2 b = 7) b is changed somewhere and @* is released and
> the execution is started at the end of begin keyword.
> 4-) "assigned b to a" in a queue, therefore b isn't change.
> (@t = 2) a = 3 b = 7 c = 2 ( a = 7 is in the queue)
> 5-) "assigned a to c" in a queue too, c isn't change either.
> (@t = 2) a = 3 b = 7 c = 2 ( c = 3 is in the queue)
> 6-) Whole statements is finished

Correct so far.

> so fetch the queue elements,
> (@t = 2 + delta_t) b is assigned to a
> a = 7 b = 7 c = 2
> @(t = 2 + delta_t)and a (a = 3; the value of 'a' at t = 2) is assigned
> to c but
> a = 7 b = 7 c = 3
> 7-) And freeze @*

Not quite. You have switched these around. FIRST the always
block loops around to @* and freezes. And the same thing
happens to any other always blocks that were running at the
same moment of simulation time. Then, when every one of
those always blocks is stuck at an @ or # event control,
the nonblocking assignments on the queue will take effect.

You say "+delta_t". That would be exactly correct for
VHDL. For Verilog, though, there is no exact idea of
a "delta cycle". But it's still a useful and sensible
idea.

> 8-) But a  was changed so @* is released.
> 9-) "assigned b to a" in a queue.
> (@t = 2 + delta_t)a = 7, b = 7, c = 3
> 10-)"assigned a to c" in a queue too.
> (@t = 2 + delta_t)a = 7, b = 7, c = 3 (c = 7 in the queue)
> 11-) Whole statements is finished

and then back to freeze at @* again, and then...

> (@t = 2 + 2*delta_t)and a is assigned to c
> a = 7 b = 7 c = 7
>
> But I need to think about all of them again.
> @6 How much time does between two assignment have?
> a = 7 between c = 3
> isn't againg a delta time, right?

No; all those nonblocking updates happen together.

However, it is DEFINED that they happen in the same
sequence that they were executed. Often this is not
so important, but there's one place where it is
essential. Consider this clocked logic:

always @(posedge clock) begin
Q <= 0; // default assignment
if (some_complicated_condition) begin
if (some_other_condition) begin
Q <= 1; // change your mind
end
end
end

This is a very useful coding trick, but you can see
that the two nonblocking assignments MUST take effect
in the same order that they were executed, if this
code is to make sense.

Regards
--
Jonathan Bromley

Jan Decaluwe

unread,
May 24, 2010, 11:33:35 AM5/24/10
to
On May 23, 7:38 pm, Patrick Maupin <pmau...@gmail.com> wrote:

> Certainly, one of Cummings's major objectives is to insure that
> simulation and synthesis results match, and there is no requirement
> for that in a testbench.  But in that vein, if I understand your
> guideline about blocking assignments correctly, I don't want *that*
> restriction for a testbench at all.

The guideline of not using blocking assignments for communication is
intended to guarantee, by construction, that simulation results of
exactly the same testbench, written in standard Verilog, match among
themselves: between different runs with other command line options,
simulator revisions and of course different simulators. Wouldn't you
agree that this goal makes at least as much sense?

> When a testbench is generating a completely independent signal for
> simulation purposes (for an async input), non-blocking assignments may
> not be required at all.

Independent doesn't mean "will never happen simultanuously". Depending
on the case, the parameters, independent clock period values,
randomized delay values, it may happen. With a blocking assignment,
the race potential is there, but it may be rare and obscure and
therefore hard to debug.

I grant to you that if this is a one-shot signal, it's unlikely that
this will cause a problem. But the real danger I see is this. You keep
the guideline not to mix blocking and nonblocking assignments in the
same always block, but apparently you relax the guideline to restrict
blocking assignments to purely combinatorial blocks. But blocking
assignments are much more expressive than nonblocking ones. Therefore,
the temptation to start using them in ways that are truly unsafe must
be almost irresistible. After all, everything will probably seem to
work fine at first. No guideline of yours prevents this; you have to
rely on the competence and discipline of each individual testbench
engineer.

> When a testbench is manipulating dependent signals, we code that like
> the RTL -- the blocking and nonblocking assignments are in *different*
> always blocks.  Honestly, this is not a terrible burden.

As you know, I don't think highly of this coding style even for
synthesis. But with synthesis there is at least the typical argument
that such code is "closer to hardware". Obviously for testbenches this
doesn't count: the only thing that matters is expressing functionality
in the clearest way. So I wonder where the idea to use this coding
style for testbenches also comes from.

> If I understand your guideline correctly, it says any varying inputs
> to my DUT need to be created from nonblocking assignments inside the
> testbench.  I certainly don't need or want that guideline.

Let me start with apologies to Janick Bergeron, whose book "Writing
Testbenches" (2000 edition) I have been rereading on this occasion.

It's not my guideline, but his. I now realize that I read it a long
time ago, and then forgot about its origin. Obviously it made so much
sense that I started thinking it was my own idea :-) (To my credit, I
added the synthesis component, pointing out that it's the only
guideline you need in that case also.)

In my view the coding style you describe advocates the use of blocking
assignments in exactly the wrong way:
- a lax attitude towards blocking assignments for communication,
resulting in a real danger of non-deterministic, non-portable Verilog
test benches that may fail in mysterious ways
- severe restrictions on using blocking assignments locally, making it
cumbersome to use plain old variable semantics even if such usage
would be totally safe

Jan

Patrick Maupin

unread,
May 24, 2010, 1:32:57 PM5/24/10
to
On May 24, 10:33 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
> On May 23, 7:38 pm, Patrick Maupin <pmau...@gmail.com> wrote:
>
> > Certainly, one of Cummings's major objectives is to insure that
> > simulation and synthesis results match, and there is no requirement
> > for that in a testbench.  But in that vein, if I understand your
> > guideline about blocking assignments correctly, I don't want *that*
> > restriction for a testbench at all.
>
> The guideline of not using blocking assignments for communication is
> intended to guarantee, by construction, that simulation results of
> exactly the same testbench, written in standard Verilog, match among
> themselves: between different runs with other command line options,
> simulator revisions and of course different simulators. Wouldn't you
> agree that this goal makes at least as much sense?

Nonblocking assignments will certainly guarantee this for signals
running off the same clock. If a signal is generated from a clock,
it's certainly a great idea, but for signals generated from a clock, I
already told you that we already use nonblocking assignments.

> > When a testbench is generating a completely independent signal for
> > simulation purposes (for an async input), non-blocking assignments may
> > not be required at all.
>
> Independent doesn't mean "will never happen simultanuously". Depending
> on the case, the parameters, independent clock period values,
> randomized delay values, it may happen. With a blocking assignment,
> the race potential is there, but it may be rare and obscure and
> therefore hard to debug.

"Independent" == "Not synchronous" == "Synchronizer required inside
the DUT" == "Lots of testing to insure that clock cross happens OK" ==
"give me whatever race potentials you've got." Seriously.

> I grant to you that if this is a one-shot signal, it's unlikely that
> this will cause a problem.

Not a one-shot signal. An *independent* signal, that has to be
synchronized by the RTL.

> But the real danger I see is this. You keep
> the guideline not to mix blocking and nonblocking assignments in the
> same always block, but apparently you relax the guideline to restrict
> blocking assignments to purely combinatorial blocks.

Yes, for stimulus.

> But blocking
> assignments are much more expressive than nonblocking ones. Therefore,
> the temptation to start using them in ways that are truly unsafe must
> be almost irresistible.

You say that like I work with little children or something.

> After all, everything will probably seem to
> work fine at first. No guideline of yours prevents this; you have to
> rely on the competence and discipline of each individual testbench
> engineer.

The guidelines *do* prevent this for a correct definition of
"independent". And trust me, an incompetent test engineer can screw
up no matter how many guidelines you give him.

> > When a testbench is manipulating dependent signals, we code that like
> > the RTL -- the blocking and nonblocking assignments are in *different*
> > always blocks.  Honestly, this is not a terrible burden.
>
> As you know, I don't think highly of this coding style even for
> synthesis. But with synthesis there is at least the typical argument
> that such code is "closer to hardware". Obviously for testbenches this
> doesn't count: the only thing that matters is expressing functionality
> in the clearest way. So I wonder where the idea to use this coding
> style for testbenches also comes from.

You spent a lot of time saying "here, use this one rule on your
testbenches and your RTL; then they're the same." Then when I say our
testbenches and code mostly *are* the same, you act like that's
silly. Bah!

> > If I understand your guideline correctly, it says any varying inputs
> > to my DUT need to be created from nonblocking assignments inside the
> > testbench.  I certainly don't need or want that guideline.
>
> Let me start with apologies to Janick Bergeron, whose book "Writing
> Testbenches" (2000 edition) I have been rereading on this occasion.
>
> It's not my guideline, but his. I now realize that I read it a long
> time ago, and then forgot about its origin. Obviously it made so much
> sense that I started thinking it was my own idea :-) (To my credit, I
> added the synthesis component, pointing out that it's the only
> guideline you need in that case also.)
>
> In my view the coding style you describe advocates the use of blocking
> assignments in exactly the wrong way:
> - a lax attitude towards blocking assignments for communication,

No, a clear understanding of the distinction between independent
stimulus and other stuff. Look, in most cases, if I'm generating
independent stimulus for a port, I don't even need to explicitly
generate a clock for it in the testbench. So, if something's
unclocked, and a random sweep is made to make sure that source
frequency and jitter variations aren't problems, how *exactly* does a
nonblocking assignment help me?

> resulting in a real danger of non-deterministic, non-portable Verilog
> test benches that may fail in mysterious ways

But they're not and they don't. (We just migrated a bunch of chips
from Mentor to Cadence last year FWIW.)

> - severe restrictions on using blocking assignments locally, making it
> cumbersome to use plain old variable semantics even if such usage
> would be totally safe

You say "severe restriction" but that's simply not true. It's just a
different coding style which makes it very easy to reason about how
things work.

Regards,
Pat

Jonathan Bromley

unread,
May 25, 2010, 4:22:54 PM5/25/10
to
On Fri, 21 May 2010 01:13:21 -0700 (PDT), nemo wrote:

>> � A = #5 EXPR; �// (1) Blocking


>> � A <= #5 EXPR; // (2) Nonblocking
>>
>> Line (1) first evaluates EXPR, then blocks execution for 5 time units,
>> then updates A, then moves on to executing the next statement.
>
>Wow! I didn't know it worked like that. I don't think that is the
>same in VHDL. I think the VHDL "after" delay is done without blocking
>the execution of the sequential flow even for variables.

Sorry, I just noticed I left this thread dangling.

Unless something changed while I wasn't looking, you can't
do AFTER-style delayed assignment to VHDL variables at all.
It works only for signals. Jolly good thing too :-)

One very interesting gnarly corner of all this is that
you cannot do _inertial_ delayed assignment to Verilog
variables. I think I pointed out that Verilog's NBA
A <= #5 EXPR;
is pretty close to VHDL's


A <= transport EXPR after 5 ns;

But what about a non-TRANSPORT delay in VHDL? That
inertial-type delay is available in Verilog [*] only
by using a continuous assign with a delay, or a wire
delay:

wire #3 W3; // net with 3 units delay
wire W5; // wire with no delay

assign #5 W5 = EXPR5; // *Driver* with 5-unit delay
// like VHDL concurrent W5 <= EXPR5 after 5 ns;

assign W3 = EXPR3; // no driver delay, just the net delay
// like VHDL concurrent W3 <= EXPR3 after 3 ns;

[*] Wait until Cary R. puts his head above the parapet to
explain all the other weird and wonderful timing machinery
you can use in Verilog thanks to primitives and specify blocks.
It's complicated and I almost never use it, so I won't even
try to explain - I'd get it badly wrong. Gate-level sim
people rely heavily on it.
--
Jonathan Bromley

Jan Decaluwe

unread,
May 26, 2010, 5:19:14 AM5/26/10
to
On May 24, 7:32 pm, Patrick Maupin <pmau...@gmail.com> wrote:
> On May 24, 10:33 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
>
> > On May 23, 7:38 pm, Patrick Maupin <pmau...@gmail.com> wrote:
>
> > > Certainly, one of Cummings's major objectives is to insure that
> > > simulation and synthesis results match, and there is no requirement
> > > for that in a testbench.  But in that vein, if I understand your
> > > guideline about blocking assignments correctly, I don't want *that*
> > > restriction for a testbench at all.
>
> > The guideline of not using blocking assignments for communication is
> > intended to guarantee, by construction, that simulation results of
> > exactly the same testbench, written in standard Verilog, match among
> > themselves: between different runs with other command line options,
> > simulator revisions and of course different simulators. Wouldn't you
> > agree that this goal makes at least as much sense?
>
> Nonblocking assignments will certainly guarantee this for signals
> running off the same clock.  If a signal is generated from a clock,
> it's certainly a great idea, but for signals generated from a clock, I
> already told you that we already use nonblocking assignments.

It might help if you stopped thinking about clocks. Verilog doesn't
know about them: all it sees are events that may happen
simultanuously.

> > > When a testbench is generating a completely independent signal for
> > > simulation purposes (for an async input), non-blocking assignments may
> > > not be required at all.
>
> > Independent doesn't mean "will never happen simultanuously". Depending
> > on the case, the parameters, independent clock period values,
> > randomized delay values, it may happen. With a blocking assignment,
> > the race potential is there, but it may be rare and obscure and
> > therefore hard to debug.
>
> "Independent" == "Not synchronous" == "Synchronizer required inside
> the DUT" == "Lots of testing to insure that clock cross happens OK" ==
> "give me whatever race potentials you've got."  Seriously.

Thanks for pointing that out.

As a thought experiment, I will now construct a standards-compliant
Verilog simulation of your testbench that, given the same inputs,
produces different results. I will wait until a blocking assignment of
a new value happens in the same timestep as the sampling in the DUT.
Given your independent timing, and thanks to your extensive testing,
this situation will certainly happen. At that point, I will reverse
the order of the two events within the simulator engine. The sampled
value will now behave differently. Hence, I have proven that your
testbench is nondeterministic.

> > But the real danger I see is this. You keep
> > the guideline not to mix blocking and nonblocking assignments in the
> > same always block, but apparently you relax the guideline to restrict
> > blocking assignments to purely combinatorial blocks.
>
> Yes, for stimulus.
>
> > But blocking
> > assignments are much more expressive than nonblocking ones. Therefore,
> > the temptation to start using them in ways that are truly unsafe must
> > be almost irresistible.
>
> You say that like I work with little children or something.

The fact is that it has happened and now the poison is in your
testbenches.

> > After all, everything will probably seem to
> > work fine at first. No guideline of yours prevents this; you have to
> > rely on the competence and discipline of each individual testbench
> > engineer.
>
> The guidelines *do* prevent this for a correct definition of
> "independent".  

I have proven otherwise.

> > > When a testbench is manipulating dependent signals, we code that like
> > > the RTL -- the blocking and nonblocking assignments are in *different*
> > > always blocks.  Honestly, this is not a terrible burden.
>
> > As you know, I don't think highly of this coding style even for
> > synthesis. But with synthesis there is at least the typical argument
> > that such code is "closer to hardware". Obviously for testbenches this
> > doesn't count: the only thing that matters is expressing functionality
> > in the clearest way. So I wonder where the idea to use this coding
> > style for testbenches also comes from.
>
> You spent a lot of time saying "here, use this one rule on your
> testbenches and your RTL; then they're the same."  Then when I say our
> testbenches and code mostly *are* the same, you act like that's
> silly.  Bah!

In another post, I have warned explicitly about the danger that
Cumming's rule for blocking assignments, while safe in his specific
case, may encourage unsafe coding practices. You asked for a real-life
example of this danger, and I wasn't able to come up with a very good
one readily.

It now turns out that your own case provides an excellent example of
what I mean. In the same pass, it validates my concern from somewhat
speculative to very real. My case against Cumming's guidelines has
therefore become much stronger.

> > > If I understand your guideline correctly, it says any varying inputs
> > > to my DUT need to be created from nonblocking assignments inside the
> > > testbench.  I certainly don't need or want that guideline.
>
> > Let me start with apologies to Janick Bergeron, whose book "Writing
> > Testbenches" (2000 edition) I have been rereading on this occasion.
>
> > It's not my guideline, but his. I now realize that I read it a long
> > time ago, and then forgot about its origin. Obviously it made so much
> > sense that I started thinking it was my own idea :-) (To my credit, I
> > added the synthesis component, pointing out that it's the only
> > guideline you need in that case also.)
>
> > In my view the coding style you describe advocates the use of blocking
> > assignments in exactly the wrong way:
> > - a lax attitude towards blocking assignments for communication,
>
> No, a clear understanding of the distinction between independent
> stimulus and other stuff.  Look, in most cases, if I'm generating
> independent stimulus for a port, I don't even need to explicitly
> generate a clock for it in the testbench.

For a clear understanding, I repeat my suggestion to stop thinking
about clocks.

>  So, if something's
> unclocked, and a random sweep is made to make sure that source
> frequency and jitter variations aren't problems, how *exactly* does a
> nonblocking assignment help me?

With nonblocking assignments, any standards compliant Verilog
simulator would, given the same inputs, always give you the same
results, guaranteed. Hence, your testbenches would now be
deterministic.

> > resulting in a real danger of non-deterministic, non-portable Verilog
> > test benches that may fail in mysterious ways
>
> But they're not and they don't.  (We just migrated a bunch of chips
> from Mentor to Cadence last year FWIW.)

I have proven that your test benches are nonderministic. You have
strong evidence that this nondeterminism is not revealed between
Mentor and Cadence, which happens to be in line with my expectations.

Jan

Patrick Maupin

unread,
May 26, 2010, 1:18:00 PM5/26/10
to
On May 26, 4:19 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:

> It might help if you stopped thinking about clocks. Verilog doesn't
> know about them: all it sees are events that may happen
> simultanuously.

Sorry, one of the reasons I like Verilog is that it doesn't try to get
in the way of thinking about the clocks (when that's what I need to be
thinking about).

> > "Independent" == "Not synchronous" == "Synchronizer required inside
> > the DUT" == "Lots of testing to insure that clock cross happens OK" ==
> > "give me whatever race potentials you've got."  Seriously.
>
> Thanks for pointing that out.
>
> As a thought experiment, I will now construct a standards-compliant
> Verilog simulation of your testbench that, given the same inputs,
> produces different results. I will wait until a blocking assignment of
> a new value happens in the same timestep as the sampling in the DUT.
> Given your independent timing, and thanks to your extensive testing,
> this situation will certainly happen. At that point, I will reverse
> the order of the two events within the simulator engine. The sampled
> value will now behave differently. Hence, I have proven that your
> testbench is nondeterministic.

Yes, but you *completely missed* the point, EVEN THOUGH I CLEARLY
POINTED IT OUT, where *it doesn't matter at all*, because the
testbench is sweeping to prove in testing that it doesn't matter which
side of an internal clock an external transition happens on. Enough
data is taken that, at the margin, where a single sample could have
been in one timeslot or the next, IT REALLY DOESN'T MATTER.

> The fact is that it has happened and now the poison is in your
> testbenches.

There is no poison. The testbenches work. The chips work. The fact
that one simulator might order a few events differently than another
is of no consequence.

> > The guidelines *do* prevent this for a correct definition of
> > "independent".  
>
> I have proven otherwise.

No, you have proven (which I already knew) that Verilog won't
guarantee whether signal A or B happens first, which is a problem with
a fragile DUT where precise ordering of one signal vs. another is
important. You took the time to prove this AFTER I went out of my way
to explain that we don't do that.

> In another post, I have warned explicitly about the danger that
> Cumming's rule for blocking assignments, while safe in his specific
> case, may encourage unsafe coding practices. You asked for a real-life
> example of this danger, and I wasn't able to come up with a very good
> one readily.

That's because there is no good case.

> It now turns out that your own case provides an excellent example of
> what I mean. In the same pass, it validates my concern from somewhat
> speculative to very real. My case against Cumming's guidelines has
> therefore become much stronger.

That's because you don't understand, either deliberately or not.

> For a clear understanding, I repeat my suggestion to stop thinking
> about clocks.

And I just explained very carefully that I *absolutely don't* need to
think about clocks when generating stimulus, because the stimulus is
*independent* of any clock, and if it matters whether stimulus that
occurs at the same time as a device clock (within some epsilon) falls
on one side or the other of the clock, then we have a broken device.

> I have proven that your test benches are nonderministic.

Yes, at the margins, for cases where I already told you we are doing
huge sweeps of data. Guess what? In real life, the DUT needs to cope
with non-deterministic input. For the testbench, it is sufficient to
insure that all possible cases are covered, not that all possible
cases are covered in exactly the same fashion on every possible
simulator.

> You have
> strong evidence that this nondeterminism is not revealed between
> Mentor and Cadence, which happens to be in line with my expectations.

It wouldn't be revealed for *any* compliant simulator we used, because
the tests are constructed in a manner where *it doesn't matter*
whether you believe that or not.

We have been doing this for *years* and have never had a broken chip
due to this thing you seem to think is the most important thing in the
world.

Regards,
Pat

Cary R.

unread,
May 26, 2010, 9:33:40 PM5/26/10
to
Jonathan Bromley wrote:

> [*] Wait until Cary R. puts his head above the parapet to
> explain all the other weird and wonderful timing machinery
> you can use in Verilog thanks to primitives and specify blocks.
> It's complicated and I almost never use it, so I won't even
> try to explain - I'd get it badly wrong. Gate-level sim
> people rely heavily on it.

I'm busy so I'll keep my head low! The quick answer is gate and UDP
primitives have inertial delays. Using a specify block (usually used to
model physical gate delays) you can control which pulse widths get
ignored (inertial delay), which get turned into an 'X' and which get
passed (transport delay). With this you can define that pulses less than
60% of the gates delay are ignore. Pulses less than 80% and greater than
or equal to 60% of the gates delay generate an 'X' and any pulse 80% of
the gates delay or greater will be passed. The default values for these
limits generate inertial delays equal to 100% of the gates delay.

Not quite as bad as Jonathan made it sound, but this is ignoring how
delays are actually defined in a specify block. Lets just say "Here be
Dragons" and I'm staying in the castle for now ;-).

If you are doing RTL design then you can safely ignore all this unless
you want to get fancy in your test code and even then my suggestion
would be ignore this unless you really need it. You can do many
wonderful things with the rest of Verilog if you are not constrained by
synthesis requirements.

Cary

sh...@cadence.com

unread,
May 28, 2010, 8:00:30 PM5/28/10
to
On May 24, 4:29 am, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
>

> So far, so clear.  Now things get a little more
> difficult.  As you say, there is a value change
> on 'a'.  Does that release the @*?  I would argue
> that it does not, because 'a' already has its new
> value at the moment when execution reaches @*.
> There is no further value change on 'a'.

Your argument would be correct.

> However, some simulators (I believe) compute
> "value change" by looking at the value of a
> variable before and after the execution of code
> at a given point in time.  Such a simulator might
> now see that 'a' has changed since the beginning
> of the time-slot, and therefore might choose to
> release the @* for a second time.  THIS DOES NOT
> MATTER because your code describes proper
> combinational logic and the second iteration,
> if it occurs, will give exactly the same results
> as before.

I am doubtful that there are any simulators that do this. If there
are, I would claim that they are not valid implementations of Verilog.

Depending on how I interpret your description, such a simulator might
be completely nonfunctional. Suppose that the simulator allowed an
event control to continue immediately, without blocking, if the event
expression had changed value earlier in the current time slice. Then
an always block with an event control would go into an infinite loop
and hang the simulation. It would wake up when the event it was
waiting for occurred. Then when it looped back to the event control
(assuming no other delaying statements in the block), it would find
that the event had occurred earlier in the current time slice, and
continue executing again. And again and again...

Perhaps you could find a way to adjust this mechanism so that it only
responded to a given event once. But it is much simpler to take the
LRM description at face value. It waits for the event. That means
the event must be one that occurs after it starts waiting.

So your earlier argument is correct. This speculation about
simulators that might do something else is probably just a red
herring.

Note that this is the distinction between the
wait(named_event.triggered) mechanism added in SystemVerilog and
@named_event. The "triggered" property (really more like a method)
does keep track of whether the named event was triggered earlier in
the current time slice. And if you wrote an always block whose only
delaying statement was that wait, it would go into an infinite loop as
soon as the event was triggered.

Jonathan Bromley

unread,
May 29, 2010, 8:36:30 AM5/29/10
to
On Fri, 28 May 2010 17:00:30 -0700 (PDT), sh...@cadence.com wrote:


>> However, some simulators (I believe) compute
>> "value change" by looking at the value of a
>> variable before and after the execution of code
>> at a given point in time.

[...]


>I am doubtful that there are any simulators that do this. If there
>are, I would claim that they are not valid implementations of Verilog.

Oh dear. Of course you're right. On re-reading that paragraph
it's clear I was mostly writing garbage and I'm not entirely
sure what I was thinking about.

I suspect that I was working hard to point out that any
propely-formed description of combinational logic must
work correctly even if it unnecessarily executes again
after computing the correct stable output values.
And I tried, unsuccessfully, to find some
justification for why that might happen in the
code the OP presented. Whoops.

>So your earlier argument is correct. This speculation about
>simulators that might do something else is probably just a red
>herring.

Red and putrescent, yes.

>Note that this is the distinction between the
>wait(named_event.triggered) mechanism added in SystemVerilog and
>@named_event. The "triggered" property (really more like a method)
>does keep track of whether the named event was triggered earlier in
>the current time slice. And if you wrote an always block whose only
>delaying statement was that wait, it would go into an infinite loop as
>soon as the event was triggered.

Indeed so. event.triggered is extremely useful for some
kinds of testbench synchronisation, but wouldn't make sense
in this context.

Thanks for putting the record straight (as usual!).
--
Jonathan Bromley

0 new messages