Re: [sv-bc] @* vs. always_comb

From: Clifford E. Cummings <cliffc_at_.....>
Date: Mon Dec 05 2005 - 18:02:10 PST
Hi, Nasim -

I'm afraid I find myself in almost complete disagreement with your 
recommendations and in fact, I am surprised to see some of these 
recommendations coming from a verification engineer. You also have a major 
flaw in your latch example that would have been avoided by using the 
always_latch.

First, let me point out that there is no defined order of execution of the 
initial block and all of the always block variations (defined below). That 
having been said, I have noted that most, if not all, of the major Verilog 
simulation vendors actually schedule the always block statements before 
scheduling initial block statements in the active events region (although 
this is not defined in the LRM - and should be defined). This is why time-0 
initial block statements trigger always blocks that are sensitive to 
signals assigned at time-0 in an initial block. I personally do not count 
on this ordering and I recommend that time-0 initial block assignments be 
made with nonblocking assignments to guarantee this ordering.

The new always_comb, always_latch and always_ff blocks do trigger once 
automatically at time-0, as you have noted before.

More below - BTW - I do like you list and methodical approach even if I 
disagree with your recommendations.

At 03:02 PM 12/5/2005, Nasim Hussain wrote:
>ummm... sorry for making this reply too long...
>
>it's just a personal opinion, but if i were to choose from these 7 :
>
>         (1) initial
>         (2) always
>         (3) always_comb
>         (4) always_ff
>         (5) always_latch
>         (6) always @*
>         (7) final
>
>
>i am *ONLY* going to advise users to use 1, 2 & 3, and that is it.
>i have no need for 4, 5, 6 & 7.

I strongly disagree.

>to model an asynch. resettable FF (for behavioral code) -
>
>         always @(posedge clk or posedge reset) begin
>                 if (reset) q[(SIZE - 1):0] <= {SIZE {1'b0}};
>                 else q[(SIZE - 1):0] <= d[(SIZE - 1):0];
>         end
>
>is as good as it can get. it's simple, concise and reflects the actual
>intent of what i need for the tool to do. no need for it to do any kind
>of checking, it needs to know all that it needs to know from what i have
>given or specified.

Close.

     always_ff @(posedge clk or posedge reset)
       if (reset) q <= '0; // using new 0-fill SystemVerilog syntax
       else       q <= d;

q and d are sized in the module header declaration and '0 fills exactly the 
number of 0's needed to avoid lint-tool warnings.

The extra begin-end in you example actually encourages a coding style that 
could fail synthesis. If somebody accidentally adds another assignment 
after the begin statement, simulation would run but synthesis would fail. 
Better to drop the begin-end from a clocked always block (poor coding style).

>i find
>         always_ff @(posedge clock iff reset==0 or posedge reset) begin
>                 ...
>                 ...
>                 ...
>         end
>
>confusing and serves me no real purpose. again, a personal opinion.
>just don't make assignments to the same variable from *different*
>procedural blocks. i am sure you all know that.

The extra iff test might improve simulator performance in the future, but 
in general, I agree that it offers little value in this context.

What you seem to be missing is that the new always_variety statements have 
built-in assertions. If a tool does do the additional checking (optional), 
the designer has indicated intent in the always_variety block and it can be 
checked by a tool. I expect both synthesis and linting tools will do this 
checking. Simulators? I don't know if they will ever do this checking or not.

The second safeguard built into the new always_variety statements is the 
checking for accidental assignments to the same variable from more than one 
always_variety block, and this happens at compile time. Why wouldn't you 
want the additional checking (again, surprising from a verification engineer).

A possible added benefit to using the always_ff is the potential to 
RTL-code dual data-rate flip-flops. Because user intent is known 
(always_ff) future synthesis tools may allow us to code always_ff (clk or 
posedge reset) and understand that flops that clock on both clock edges are 
intended (we may want to overload the edge keyword to avoid mistakes due to 
omissions - always_ff @(edge clk or posedge reset)). Tektronix has been 
using dual data-rate flip-flops for more than a 15 years to do high-speed 
data acquisition.

>same deal with latches. for example, all i need for an asynch.
>resettable LATCH is -
>
>         always @(d or posedge clk or posedge reset) begin
>                 if (reset) q[(SIZE - 1):0] <= {SIZE {1'b0}};
>                 else if (clk) q[(SIZE - 1):0] <= d[(SIZE - 1):0];
>         end
>
>i have absolutely no need for always_latch. yes, it might save me from
>typing in a few extra words, but i think that is it. as a rule: we never
>use blocking timing controls inside sequential elements.

And your code has mistakes that would have been avoided with the 
always_latch. This mistake might not be caught during simulation but it 
will fail during synthesis.

Synthesis tools enforce a coding style that requires that EITHER all 
signals in a sensitivity list have an edge or none of the signals have an 
edge. You have mixed them and it will cause a synthesis tool failure.

There are two problems with this coding style that do not correspond to 
real hardware. First, the clock signal is not really edge-sensitive, it is 
level sensitive to handle the transparent mode (in this case, the 
simulation appears to function correctly, but it also works if the posedge 
is removed). Second, a problem occurs when reset is removed (negedge reset) 
because if the latch is in transparent mode when reset is removed, the 
d-input should immediately propagate to the q-output, but that will not 
occur until the next sensitivity trigger occurs (wrong functionality).

     always_latch
       if (reset)    q <= '0;
       else if (clk) q <= d;

(and again, remove the potentially problematic begin-end)

>also, i am not sure when and where always_ff and always_latch fires, but
>i am speculating it must be within the *active* slot, along with it's
>gazillion other friends. my understanding (hopefully not flawed) is that
>all of
>
>         (3) always_comb
>         (4) always_ff
>         (5) always_latch
>
>will happen AFTER the "initial" (w/ blocking timing control) and
>"always" blocks... meaning somewhat at the end of the active slot, but
>before the beginning of the inactive slot ?

Yes and no. Yes they all fire in the active events region, just like always 
blocks (we would not want the behavior to be any different), but no, they 
are not defined to fire after initial blocks (and again, most 
implementations fire the initial blocks after the always blocks).

>till today, i don't fully comprehend all of the intricacies associated
>with using "always @*" and consequently, i have maintained my distance
>from it. "inferred" sensitivity lists aren't big on my plate. telling a
>tool to be automatically sensitive to ALL the signals that it believes
>it read within a procedural block - to me, that is a risky game. most of
>the time, you want ALL signals on the RHS of assignments + signal
>enables within the conditional if-else-if statements, but ...

Again, I completely disagree.

The @* removed problems related to missing signals from the sensitivity 
list. These missing signals were often difficult to debug if a linting tool 
was not used, and always yielded a mismatch between pre- and post-synthesis 
simulations. The @* removed the silly requirement to list all signals 
twice, once in the functional statements and again the sensitivity list of 
the always block. Do you worry about the implied sensitivity list of a 
continuous assignment??

I apologize but not "fully comprehend"-ing a new and powerful construct is 
a poor reason to avoid it. The @* is more concise and fixes common 
sensitivity list problems - that's "Win-Win!"

>... that said, i believe using SV's always_comb might be of some
>benefit, despite it being somewhat of an older, but wiser brother to
>"always @*".

Actually, @* was part of Verilog-2001. It was the "older ... brother." It 
could be used to model combinational logic and latches. The always_comb and 
always_latch were new SystemVerilog additions that indicated 
designer-intent, included built-in assertions (if implemented) and avoided 
the troublesome multi-block assignment to a common variable.

always_comb builds its sensitivity list the same way as always @*. Your 
fears of always @* are illogical.

I still think always @* has use in verification because now an engineer 
does not have to think about verification code in terms of combinational 
logic and latches.

>always_comb (if it fires AFTER initial and always blocks)
>can be useful to catch changing signals at time 0 (kind of similar to
>C/C++'s do-while loop where it is guaranteed to execute at least once).
>
>
>
>finally, i have absolutely no need for the "final" block.

Again, I disagree.

Have you ever had final reporting code not execute because of $finish race 
conditions? I have. All the time!

As was discussed on one of the SV threads in recent months, you can think 
of final blocks as $finish subroutines. It is important to remember that 
nonblocking assignments are not allowed (only code that is permitted in a 
function is allowed) and $strobe commands will not fire in time ($finish 
finishes in the active events region before the postponed $strobe commands 
can be activated).

My biggest complaint about final blocks is that they should report and 
error or warning if somebody puts a $strobe inside a final block. EDA 
vendors are going to field lots of questions about final-$strobe if this is 
not done.

>my conclusion - for me (can't speak for other people) -
>
>         (1) initial                     YES, of-course!

Yes - testbenches and program blocks.

>         (2) always                      YES, of-course!

Rarely used any more. Supported for legacy code.

>         (3) always_comb                 USE, but judiciously!
>         (4) always_ff                   NOT necessary!
>         (5) always_latch                NOT necessary!

Yes-Yes and Yes!! Built-in assertions. Visible designer intent. Removes 
silly sensitivity list mistakes (like your latch-code above). Flags errors 
whenever multiple assignments are made to the same variable. Very 
surprising conclusion from a verification engineer.

>         (6) always @*                   NO!

Yes in Verilog-only environments and yes even in SystemVerilog verification 
code.

>         (7) final                       NEVER!

Yes - for final reporting of testbench statistics to avoid the $finish-race 
condition.

>thanks.
>-nasim

Regards - Cliff

>----------------------------------------------------------------------
>Nasim Hussain           | Life is short,   ---     _ o     _~o     _ o
>UltraSPARC Verification |   go wherever  ----    _`\<,   _`\<,   _`\<,
>SUN Microsystems, Inc.  |     you want...  ---  ( )/( ) ( )/( ) ( )/( )
>work - (408) 720-4927   |
>home - (650) 967-7730   |

----------------------------------------------------
Cliff Cummings - Sunburst Design, Inc.
14314 SW Allen Blvd., PMB 501, Beaverton, OR 97005
Phone: 503-641-8446 / FAX: 503-641-8486
cliffc@sunburst-design.com / www.sunburst-design.com
Expert Verilog, SystemVerilog, Synthesis and Verification Training 
Received on Mon Dec 5 18:03:56 2005

This archive was generated by hypermail 2.1.8 : Mon Dec 05 2005 - 18:04:32 PST