I have found this verilog code in SystemC 2.0 User's Guide at page
191:
http://www.cse.iitd.ernet.in/~cs5030223/UserGuide20.pdf
//////////////////////////////////////////////////////////////////////////////////////////////
module dffa(clock, reset, din, dout);
input clock, reset, din;
output dout;
reg dout;
always @(posedge clock or reset)
begin
if (reset)
dout <= 1’b0; //nonblocking assignment
else
dout = din; // blocking assignment
end
endmodule
/////////////////////////////////////////////////////////////////////////////////////////////////
But one of the Coding style in the famous paper for nonblocking
assigment mentioned as follow:
Guideline #5: Do not mix blocking and nonblocking assignments in the
same always block.
http://csg.csail.mit.edu/6.375/papers/cummings-nonblocking-snug99.pdf
It's true that I do it.
It's true that most don't.
http://groups.google.com/groups/search?q=%22single+always+block%22+Cliff+hits+nail
-- Mike Treseler
> It's not against the rules to mix. It's prudent to avoid mixing them.
> Also, you'll find that many synthesizers won't allow you to mix them.
Really?
Which one.
-- Mike Treseler
Take a brief look at the content of " Nonblocking Assignments in
Verilog Synthesis, Coding Styles That Kill!" about this topic:
module ba_nba6 (q, a, b, clk, rst_n);
output q;
input a, b, rst_n;
input clk;
reg q, tmp;
always @(posedge clk or negedge rst_n)
if (!rst_n) q = 1'b0; // blocking assignment to "q"
else begin
tmp = a & b;
q <= tmp; // nonblocking assignment to "q"
end
endmodule
Above example will most likely simulate correctly most of the time,
but Synopsys tools will report a syntax error because the blocking
assignment is assigned to the same variable as one of the nonblocking
assignments. This code must be modified to be synthesizable.
Yes, of course, but I was refer it from part of a code from a SystemC
2.0 User's Guide which was wrote by Experts in OSCI, I just want to
know is it a simple mistake or there are any idea behind it.
Regards
ARH
>>> Also, you'll find that many synthesizers won't allow you to mix them.
Mike wrote:
>> Really?
>> Which one.
ARH wrote:
> Above example will most likely simulate correctly most of the time,
> but Synopsys tools will report a syntax error because the blocking
> assignment is assigned to the same variable as one of the nonblocking
> assignments. This code must be modified to be synthesizable.
That would be an appropriate error.
I understood Kevin to mean that some synthesizer disallows all such
assignments. This is not the case for quartus, xst or mentor.
-- Mike Treseler
> Yes, of course, but I was refer it from part of a code from a SystemC
> 2.0 User's Guide which was wrote by Experts in OSCI, I just want to
> know is it a simple mistake or there are any idea behind it.
>
> Regards
> ARH
Assigning a non-blocking and a blocking assignment to the same variable
is generally quite bad style because it increases the possiblities of
races, glitches, and other nasty behaviours (upto the synthesized code
doing something different than the simulated code, which is the worst
thing of all in my book). Moreover, some of these effects are
simulator and synthesizer dependent, meaning you are potentially
writing non-portable code.
However, to answer your more important question, in the example
provided it is probably a typographical error. I have never seen a
case where mixing blocking and non-blocking assignments to the same
variable on different legs of an if serves any useful purpose. Either
the code works with both assignments one of the two directions or the
simulated code has an artifact that is likely not supported portably
by all synthesizers.
In particular, if one uses a non-blocking assignment, the semantics of
Verilog generally describe a flop (or some other kind of register).
In conrast, a blocking assignment has semantics more approriate to
combinatorial code without a clocked element. Now, these are general
statements and not strictly true, e.g. one can desicribe blocks that
are flops using blocking assignments and vice-versa, so some typos
don't matter and you can use the "wrong" type of assignment and get
correctly syntehsized results. Still, a variable is probably either
clocked or not, and you should use the type of assignment which
represents its usage for most reliable results.
Hope this helps,
-Chris
******************************************************************************
Chris Clark Internet: christoph...@compiler-resources.com
Compiler Resources, Inc. or: com...@world.std.com
23 Bailey Rd Web Site: http://world.std.com/~compres
Berlin, MA 01503 voice: (508) 435-5016
USA fax: (978) 838-0263 (24 hours)
------------------------------------------------------------------------------
> Hope this helps,
> -Chris
>------------------------------------------------------------------------------
Thanks Chris, I have similar idea about this error in SystemC 2.0
official documentations, but I didn't sure about it. So I should point
it in SystemC forum for correction in the future releases. But isn't
it strange if this guide have a error and no one see it since 2002 ?
Regards
-ARH
One moment--I just looked this up in the Synplify documentation, and it
actually says you can't use blocking and nonblocking for the same
register. So perhaps you can mix them in the same process as long as
you don't for the same reg.
-Kevin
>I have found this verilog code in SystemC 2.0 User's Guide at page
>191:
>http://www.cse.iitd.ernet.in/~cs5030223/UserGuide20.pdf
>
>//////////////////////////////////////////////////////////////////////////////////////////////
>module dffa(clock, reset, din, dout);
>input clock, reset, din;
>output dout;
>reg dout;
> always @(posedge clock or reset)
> begin
> if (reset)
> dout <= 1’b0; //nonblocking assignment
> else
> dout = din; // blocking assignment
> end
>endmodule
It's a typo; as simple as that. Both assignments should
be nonblocking. No doubt, no argument.
I hate to harp on and be boring and all that stuff, but
this issue is really, really simple and people seem to
make a big deal about it when there's no need. I and
others have chewed over this issue at great length here
and elsewhere, but the same old canards keep on coming up:
CANARD #1: Nonblocking assignment implies a flop.
~~~~
Nope. See below.
CANARD #2: You shouldn't ever use blocking assignment in
a clocked always block.
~~~~
Nope. See below. This one is especially pernicious because
it has received a "seal of approval" from one throwaway (and,
I believe, self-evidently wrong) comment in an otherwise
excellent, authoritative and widely-quoted paper by Cliff
Cummings.
CANARD #3: Blocking assignment implies combinational logic.
~~~~
Nope. See below.
THE ONLY RULES THAT MATTER for synthesis are...
1) In a Verilog clocked always block, you must NEVER use
blocking assignment to write to a variable that will be
read (used) in any other block clocked by the same clock.
Failure to observe this rule will yield mysterious
read/write races and consequent mismatches between
simulation and synthesis.
2) In a Verilog clocked always block, you must NEVER
mix blocking and nonblocking assignment to the same
variable. Failure to observe this rule will confuse
the hell out of synthesis tools, and quite right too.
~~~~~~~~~~~~
There are also some RECOMMENDATIONS - not rules - that
will make it easier to reason about what you are doing,
and are very strongly urged on beginners to keep them
out of trouble:
a) Use nonblocking assignments ONLY in clocked always
blocks, nowhere else. In combinational logic there is
generally no need for nonblocking assignments; if you
need to use them, you've almost certainly got a sensitivity
list wrong, or perhaps you've mistakenly created
combinational feedback. Note that nonblocking assignment
in a combinational block does NOT imply storage.
b) It is easier to reason about your clocked logic if
you use only nonblocking assignments in it. Registers
thus assigned-to are sure to imply flops. Registers
written using blocking assignment may or may not imply
flops depending on how you used them. You can exploit
this to do various creative things, and ALL credible
synthesis tools support such use, but it takes a good
level of understanding of synthesis to be able to do it
with confidence.
Of course, when writing testbench code these "rules"
are no longer so important and you can do anything you
want; and, of course, that brings with it a burden of
understanding.
So, please, please, no more speculation... it's easy.
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan...@MYCOMPANY.com
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
> One moment--I just looked this up in the Synplify documentation, and it
> actually says you can't use blocking and nonblocking for the same
> register. So perhaps you can mix them in the same process as long as
> you don't for the same reg.
Using one each for the two halves of an if-then-else is
just weird. Actually, I might not believe that for an
asynchronous reset. Hmmm.
(from another post)
> module dffa(clock, reset, din, dout);
> input clock, reset, din;
> output dout;
> reg dout;
> always @(posedge clock or reset)
> begin
> if (reset)
> dout <= 1’b0; //nonblocking assignment
> else
> dout = din; // blocking assignment
> end
> endmodule
Of course asynchronous reset isn't a good idea, but I am
not sure I believe this should be illegal. On the other hand,
module dffa(clock, din, dout);
input clock, reset, din;
output dout;
reg dout;
always @(posedge clock or reset)
begin
if (din)
dout <= 1’b1; //nonblocking assignment
else
dout = 1’b0; // blocking assignment
end
endmodule
now, that is just weird.
-- glen
> In particular, if one uses a non-blocking assignment, the semantics of
> Verilog generally describe a flop (or some other kind of register).
> In conrast, a blocking assignment has semantics more approriate to
> combinatorial code without a clocked element. Now, these are general
> statements and not strictly true, e.g. one can desicribe blocks that
> are flops using blocking assignments and vice-versa, so some typos
> don't matter and you can use the "wrong" type of assignment and get
> correctly syntehsized results. Still, a variable is probably either
> clocked or not, and you should use the type of assignment which
> represents its usage for most reliable results.
But an asynchronous reset to a FF is not clocked logic!
(and also I agree that the statements aren't strictly true.)
-- glen
Hi Glen
According to Jonathan's post, your code isn't true because it still
have mixed assignment. did you think there is different between
assigning Logic Bits and signals to "dout" ? you clearly delete
asynchronous reset functionality in this code and I think it isn't
equivalent with my one !
--ARH
>> module dffa(clock, din, dout);
>> input clock, reset, din;
>> output dout;
>> reg dout;
>> always @(posedge clock or reset)
>> begin
>> if (din)
>> dout <= 1’b1; //nonblocking assignment
>> else
>> dout = 1’b0; // blocking assignment
>> end
>> endmodule
> According to Jonathan's post, your code isn't true because it still
> have mixed assignment. did you think there is different between
> assigning Logic Bits and signals to "dout" ? you clearly delete
> asynchronous reset functionality in this code and I think it isn't
> equivalent with my one !
Yes, this is different and maybe should be illegal.
Asynchronous reset is fundamentally different from clocked
logic, so should not be illegal.
I was trying to show two different ways to mix the assignment
operators. Though my preference is to use continuous assign
except for registers.
Also I would have to check the references, but I thought that
the only difference was internal to an always block.
Some posts seemed to disagree with that.
-- glen
This is a poor example to use. The problem is with the non-blocking
assign to q in the reset clause. The non-blocking assign to tmp is
completely OK.
> On May 8, 2:27 am, ARH <haghdo...@gmail.com> wrote:
>>Take a brief look at the content of " Nonblocking Assignments in
>>Verilog Synthesis, Coding Styles That Kill!" about this topic:
>>module ba_nba6 (q, a, b, clk, rst_n);
>> output q;
>> input a, b, rst_n;
>> input clk;
>> reg q, tmp;
>> always @(posedge clk or negedge rst_n)
>> if (!rst_n) q = 1'b0; // blocking assignment to "q"
>> else begin
>> tmp = a & b;
>> q <= tmp; // nonblocking assignment to "q"
>> end
>>endmodule
>>Above example will most likely simulate correctly most of the time,
>>but Synopsys tools will report a syntax error because the blocking
>>assignment is assigned to the same variable as one of the nonblocking
>>assignments. This code must be modified to be synthesizable.
Maybe, but I don't see any reason it can't be synthesized.
To me, the real difference between blocking and non-blocking
comes when a reg is assigned and referenced in the same block.
(That is, both left and right sides of an assignment.)
That doesn't occur here.
> This is a poor example to use. The problem is with the non-blocking
> assign to q in the reset clause. The non-blocking assign to tmp is
> completely OK.
I agree. Especially since it does an asynchronous reset.
It gets complicated if reset and clock occur on the same edge,
but that complicates real logic, too.
Also, if I do write blocking assignment, I always write them
in the reverse order such that no reg is used after it is
changed. That is, the way one would do it in C.
-- glen
Another real difference is when reg is assigned in one block and
referenced in another, when both both blocks are sensitive to same clock
(e.g., a pipeline). With blocking assignment, the reading block, on
same cycle, could see either the old or new. With non-blocking, the
reader always sees old value, as desired. While they could synthesize
the same, blocking assignments can cause simulation / synthesis mismatches.
-- Bill
> glen herrmannsfeldt wrote:
Are you sure about that? I was writing verilog for a while before
I even learned about non-blocking assignment and never had that
problem. At that point I only put one register per module
(mostly structural model except for registers).
Looking at Sternheim & Singh, all the example code uses blocking
assignment. I don't see any discussion that this could be
a problem.
Do you have any examples of legal verilog code with multiple
clocked always blocks that evaluate in the wrong order?
There might be cases with non-clocked (combinatorial) always
blocks, but in that case, as with continuous assignment,
the block/assignment will be executed again in the same time
step if needed. As far as I know, that isn't true for
clocked always blocks. In hardware terms, registers have
zero hold time such that any data changed during a clock
cycle are not used as input to other registers (in different
always blocks) in the same clock cycle.
-- glen
>Looking at Sternheim & Singh, all the example code uses blocking
>assignment. I don't see any discussion that this could be
>a problem.
Aaaaaarggggh. Another one to pulp.
>Do you have any examples of legal verilog code with multiple
>clocked always blocks that evaluate in the wrong order?
Plenty. I don't even need to appeal to nondeterminism;
this one is _guaranteed_ to be broken in any single-threaded
simulator, but gives correct simulation results if nonblocking
assignment is used.
module broken_ring_counter (
input clock,
input reset,
output [1:0] q
);
reg a, b;
always @(posedge clock)
if (reset)
a = 1'b0;
else
a = b;
always @(posedge clock)
if (reset)
b = 1'b0;
else
b = ~a;
assign q = {a, b};
endmodule
Why, oh why, does this argument rage on endlessly?
Why can't people just do it right, and move on to the
real problems?
>>Do you have any examples of legal verilog code with multiple
>>clocked always blocks that evaluate in the wrong order?
> Plenty. I don't even need to appeal to nondeterminism;
> this one is _guaranteed_ to be broken in any single-threaded
> simulator, but gives correct simulation results if nonblocking
> assignment is used.
(snip)
> Why, oh why, does this argument rage on endlessly?
> Why can't people just do it right, and move on to the
> real problems?
If one wants to understand the features of the language,
one should understand this one. Tested with veriwell it
seems that yours doesn't work, as you say. This one,
more like the way I used to write them, does work.
(and even more, yours works with blocking assignment
for reset, and non-blocking for a and b.)
module ring_counter ( clock, reset, q );
input clock;
input reset;
output [1:0] q;
wire a, b;
register r1(clock,a,b,reset);
register r2(clock,b,~a,reset);
assign q = {a, b};
endmodule
module register(clk, q, in, reset);
input clk, in, reset;
output q;
reg q;
always @(posedge clk)
if(reset) q=0;
else q=in;
endmodule
module test;
integer i;
reg clock,reset;
wire [1:0] q;
ring_counter one(clock,reset,q);
initial begin
#1 clock= 1'b0;
#1 clock=~clock;
#1 clock=~clock;
#1 reset= 1'b1;
#1 clock=~clock;
#1 clock=~clock;
#1 reset= ~reset;
#1 clock=~clock;
#1 clock=~clock;
$display("reset=%h",reset);
for(i=0;i<40;i=i+1) begin
#1 clock=~clock;
$display ("%h %h %h", i,q,clock);
#1 clock=~clock;
$display ("%h %h %h", i,q,clock);
end
end
endmodule
Your example and Jonathan's example are fundamentally the same. They
both suffer from a race condition that cannot be deterministically
resolved by the language. Sure, it may run just fine on one particular
compiler, and it may run just fine on 100 different compilers, but you
are never sure if it will run correctly on the next compiler.
The feature of the language does not give specific instructions on how
race conditions are to be resolved. Using blocking assignments in
synchronous logic creates race conditions that can be evaluated either
way.
In Jonathan's example:
always @(posedge clock)
if (reset)
a = 1'b0;
else
a = b;
always @(posedge clock)
if (reset)
b = 1'b0;
else
b = ~a;
Suppose that initially, a is 0 and b is 1. At the clock edge, if the
first block is evaluated first, a will be 1, and b will be 0. If the
second block is evaluated first, a will be 1 and b will be 1.
Now if we convert that example into non-blocking code. No matter which
block is evaluated first, the result is still a=1 and b=1.
~Jason Zheng
--
Outside of a dog, a book is a man's best friend. Inside a dog it's too
dark to read.
-- Groucho Marx
> Your example and Jonathan's example are fundamentally the same. They
> both suffer from a race condition that cannot be deterministically
> resolved by the language. Sure, it may run just fine on one particular
> compiler, and it may run just fine on 100 different compilers, but you
> are never sure if it will run correctly on the next compiler.
> The feature of the language does not give specific instructions on how
> race conditions are to be resolved. Using blocking assignments in
> synchronous logic creates race conditions that can be evaluated either
> way.
Yes, I was trying to understand if block boundaries or module
boundaries are significant as far as assignment. It does seem
interesting that the result is different with the register
in its own module.
-- glen
>I was trying to understand if block boundaries or module
>boundaries are significant as far as assignment. It does seem
>interesting that the result is different with the register
>in its own module.
In the bad old days before nonblocking assignments were
introduced in the Verilog language, continuous assign
statements introduced "just enough" delay to deal with
the problem. Since a port connection is effectively
a continuous assign across the port boundary, you could
make blocking update to a flop work "correctly" by
burying it inside a module. I wasn't writing Verilog
in anger myself at that time, but I understand that
this approach was actively promoted by some vendors.
This was never a good idea. Although (as far as I know)
all current simulators reproduce this particular event
ordering behaviour, it is not guaranteed by the language
standard. So I would expect to see Glen's example
(two flops, each in their own module) work in practice,
but I would never tolerate it in any design over which
I had any control.
Yes, and I think this is what started off the whole thread.
Someone had found a typo in a published example, where
NBA was used in the reset branch and blocking assignment
in the clocked branch of an asynchronously-reset flop model.
In simulation you'll typically get "correct" (i.e. as expected
for the intended hardware design) behaviour even if you use
the wrong kind of assignment in the reset branch. For
asynchronous resets that's entirely understandable, because
the behaviour is asynchronous and there is no concern
about read/write races around a clock edge. For synchronous
resets, your comment (that my ring counter "works" when you
mix the assignment types) is true, but purely an accident of
the design; if another clocked always block were to use the
value of one of those flops, there would be a race between
its being reset synchronously, and its value being used
in the other block.
Synthesis tools (without exception, to the best of my knowledge)
outlaw the mixing of blocking and nonblocking assignment to
any given variable in any always block. There are certainly
a few situations where mixed blocking/nonblocking assignment
to the same variable gives reasonable behaviour, but in
general it's a completely reasonable synthesis restriction
because such a mixture could easily give rise to unrealisable
behaviour. The one situation where people might feel moved
to complain about the restriction is this:
always @(posedge clock or posedge reset)
if (reset)
Q = 0; // asynch reset, blocking!
else
Q <= D; // clocked, must be NBA
I can't find any meaningful cases where this code would
give rise to a race condition in practice. However,
you lose absolutely nothing by using nonblocking assignment
in both branches, and it makes life much easier for synthesis
tools to enforce the "uniform assignment" rule even here.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So, for the last time:
- Keep synthesis happy by avoiding any mixture of blocking
and nonblocking assignment *to the same variable* in any
code that models synthesisable logic. It's easy to find
examples where this rule is strictly unnecessary, but
synthesis tools enforce it and you lose nothing by
observing it.
- In a clocked always block, with or without asynch reset,
NEVER, NEVER, NEVER use blocking assignment to any variable
whose value will be used outside that same always block.
Failure to observe this rule WILL give rise to code that
can suffer races in simulation, and therefore mismatches
between simulation and synthesis.
- In a combinational always block, nonblocking assignments
are always unnecessary and often wrong; stick to blocking
assignments throughout.
That's it.
> In the bad old days before nonblocking assignments were
> introduced in the Verilog language, continuous assign
> statements introduced "just enough" delay to deal with
> the problem. Since a port connection is effectively
> a continuous assign across the port boundary, you could
> make blocking update to a flop work "correctly" by
> burying it inside a module. I wasn't writing Verilog
> in anger myself at that time, but I understand that
> this approach was actively promoted by some vendors.
Maybe I was lucky. Most of my early verilog put them
in a module because it followed the modularity of the
design. (Systolic array processors.)
Looking back at some of the old code, I also put
a delay in.
module reg16(q,data,clock);
output [15:0] q;
reg [15:0] q;
input clock;
input [15:0] data;
always @(negedge clock) #10 q=data;
endmodule
It seems likely that is what the sample code I had at
the time did, either from reference books or Xilinx examples.
> This was never a good idea. Although (as far as I know)
> all current simulators reproduce this particular event
> ordering behaviour, it is not guaranteed by the language
> standard. So I would expect to see Glen's example
> (two flops, each in their own module) work in practice,
> but I would never tolerate it in any design over which
> I had any control.
It seems that even after it was added, the old methods
stayed around. The Sternheim and Singh book from 1993
has non-blocking assignment in the reference sections,
but not in any of the examples. Some examples use #0
for the delay value.
-- glen
> On Tue, 20 May 2008 15:24:59 -0800, glen herrmannsfeldt
> <g...@ugcs.caltech.edu> wrote:
>>yours works with blocking assignment
>>for reset, and non-blocking for a and b.
> Yes, and I think this is what started off the whole thread.
> Someone had found a typo in a published example, where
> NBA was used in the reset branch and blocking assignment
> in the clocked branch of an asynchronously-reset flop model.
Though your example seems to have synchronous reset...
-- glen
> In the bad old days before nonblocking assignments were
> introduced in the Verilog language, continuous assign
> statements introduced "just enough" delay to deal with
> the problem. Since a port connection is effectively
> a continuous assign across the port boundary, you could
> make blocking update to a flop work "correctly" by
> burying it inside a module. I wasn't writing Verilog
> in anger myself at that time, but I understand that
> this approach was actively promoted by some vendors.
>
> This was never a good idea.
All very well, but serious chips had to be designed
in those days also. I dare to suggest that the backbone
of the Internet has been designed without non-blocking
assignments!
Sometimes I get the impression that those "early"
Verilog designers (I was one) are considered idiots
for not using a feature that wasn't available to them :-)
If anyone is to blame, it's the designers of Verilog itself.
I've called this absurd story "horrible" in the past and
I stand by those words.
Jan
--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Kaboutermansstraat 97, B-3000 Leuven, Belgium
From Python to silicon:
http://myhdl.jandecaluwe.com
> So, for the last time:
>
> - Keep synthesis happy by avoiding any mixture of blocking
> and nonblocking assignment *to the same variable* in any
> code that models synthesisable logic. It's easy to find
> examples where this rule is strictly unnecessary, but
> synthesis tools enforce it and you lose nothing by
> observing it.
> - In a clocked always block, with or without asynch reset,
> NEVER, NEVER, NEVER use blocking assignment to any variable
> whose value will be used outside that same always block.
> Failure to observe this rule WILL give rise to code that
> can suffer races in simulation, and therefore mismatches
> between simulation and synthesis.
> - In a combinational always block, nonblocking assignments
> are always unnecessary and often wrong; stick to blocking
> assignments throughout.
>
> That's it.
I can't help it, but I find those rules one more example of
how too much Verilog exposure can corrupt even the finest minds :-)
We want to avoid races at the HDL level. Then why should the
kind of logic I'm describing influence which types of assignment
I should use to accomplish that? This is a mix of HDL concepts
with implementation considerations - often a source of suboptimal
HDL design.
Moreover, there is a much simpler, conceptually clean alternative:
- use non-blocking for communication (between always blocks)
- use blocking for computation (inside always blocks)
This works always, regardless of the kind of logic I'm describing,
and regardless of which HDL I'm using (terminology aside.)
>Though your example seems to have synchronous reset...
Yes; I was trying to decouple the real issue (races at the
clock edge) from the question of whether it's OK to mix
BA and NBA to the same variable, so I thought it best to
have a synch-only design. And if it lacked a reset, it
would have been broken for a different reason :-)
>> - Keep synthesis happy by avoiding any mixture of blocking
>> and nonblocking assignment *to the same variable* in any
>> code that models synthesisable logic. It's easy to find
>> examples where this rule is strictly unnecessary, but
>> synthesis tools enforce it and you lose nothing by
>> observing it.
>> - In a clocked always block, with or without asynch reset,
>> NEVER, NEVER, NEVER use blocking assignment to any variable
>> whose value will be used outside that same always block.
>> Failure to observe this rule WILL give rise to code that
>> can suffer races in simulation, and therefore mismatches
>> between simulation and synthesis.
>> - In a combinational always block, nonblocking assignments
>> are always unnecessary and often wrong; stick to blocking
>> assignments throughout.
>
>I can't help it, but I find those rules one more example of
>how too much Verilog exposure can corrupt even the finest minds :-)
Although I'm probably guilty as charged of corruption, I think
you may perhaps be overstating the case!
[...]
>Moreover, there is a much simpler, conceptually clean alternative:
>- use non-blocking for communication (between always blocks)
>- use blocking for computation (inside always blocks)
The first two of my three "rules" are totally consistent with
this and, indeed, the second of them follows directly from
your alternative - as you are perfectly well aware.
My third "rule" is less clean, I agree, but it is worth noting
that nonblocking variable update (i.e. VHDL signal assignment)
is not at all necessary to build race-free *combinational* logic.
The sensitivity list on every combinational block assures safe
execution ordering among the various blocks. This is just as
well, because continuous assignment in Verilog has semantics
much closer to blocking than to nonblocking assignment, and it
is commonly and correctly used to model combinational logic.
I agree, though, that it drives a wedge between VHDL and
Verilog coding of combinational logic.
The real problem with coding combinational logic comes when
you are trying to describe clock gating or buffering. In this
case, real physical hardware can easily suffer the same races
that you can get in simulation. Use of blocking update in
combinational logic can help to work around that and make
your clock gating work in RTL simulation the same way as you
will finally make it work in the real hardware, with all those
nasty extra delays that you or your P&R tool will introduce
to fix the hold violations....
[using port boundaries to fix simulation races]
>> was never a good idea.
>
>All very well, but serious chips had to be designed
>in those days also.
>Sometimes I get the impression that those "early"
>Verilog designers (I was one) are considered idiots
>for not using a feature that wasn't available to them :-)
No, no, no. I hope you don't believe I'm so arrogant
or so ignorant as to suggest that. However, I *would*
consider you an idiot if you failed to use NBA in your
clocked logic today :-)
>If anyone is to blame, it's the designers of Verilog itself.
>I've called this absurd story "horrible" in the past and
>I stand by those words.
Absurd it may be, but (as you are better aware than I)
we have little choice but to live with it and make the
best of it. For what it's worth, I totally agree with
you about the "horrible" part.
>Looking back at some of the old code, I also put
>a delay in.
>
[...]
>always @(negedge clock) #10 q=data;
Perfect, until the simulated clock period gets
reduced to #10 or shorter...
See Jan Decaluwe's post. The lack of NBA in early
Verilog led to all manner of hackery. It had to be
done at the time, but it's inexcusable today.
>> Moreover, there is a much simpler, conceptually clean alternative:
>> - use non-blocking for communication (between always blocks)
>> - use blocking for computation (inside always blocks)
Jonathan wrote:
>>> - In a combinational always block, nonblocking assignments
>>> are always unnecessary and often wrong; stick to blocking
>>> assignments throughout.
Thanks to Jan and Jonathan
for another pass at the variable assignment rules.
Since I have already adopted an unrelated style rule that says:
"- don't use combinational always blocks"
I intend to adopt Jan's two line formulation as
sufficient for me, and easy to remember.
-- Mike Treseler
While it is easier to understand the structure of the logic implied by
the description, it is often more difficult to understand its behavior
if you use only non-blocking assignments for registers. With
increasing use of re-timing optimizations that move registers around/
between/through combinatorial logic clouds, the exact location/
contents of registers in the synthesized circuit will not match what
was neatly described in non-blocking assignments anyway. The only
thing that will be preserved in circuitry is the cycle-accurate
behavior of the description. Therefore it is preferable to focus on a
descriptive style that best illustrates the cycle-accurate behavior,
including blocking assignments that may result in registers.
Obvious exceptions to this preference include synchronization
boundaries that rely on the explicit location/contents of registers,
which should be excluded from re-timing optimizations anyway.
As to the level of understanding of synthesis required to use blocking
assignments with confidence, I agree whole heartedly. However, if we
are ever going to evolve our design process past writing fancy
netlists of registers and combinatorial functionality, we will have to
reach that level of understanding.
Andy