All #0 related code examples I have found are related to procedural code (IE code inside begin-end). What about continuous assignments and primitive instantiations? The IEEE 1364 & IEEE 1800 (Verilog & SystemVerilog respectively) only give a one line description that I can find (Quoting all version of IEEE 1364 under the section name "The stratified event queue"):
An explicit zero delay (
#0) requires that the process be suspended and added as an inactive event for the current time so that the process is resumed in the next simulation cycle in the current time.
I read documents and talked with a few engineers that have been working with Verilog long before the IEEE Std 1364-1995. In summary, the inactive region was failed solution to synchronizing flip-flops with Verilog's indeterminate processing order. Later Verilog created non-blocking assignments (<=) and resolved the synchronizing with indeterminate order. The inactive region was left in the scheduler to not break legacy code and a few obscure corner cases. Modern guidelines say to avoid the using #0 because it creates race conditions and may hinder simulation performance. The performance impact is a don't care for small designs. I run huge designs that with mixed RTL to transistor level modules. So even small performance gains add up and not having to debug a rouge race conditions are time savers.
I've ran test case removing/adding #0 to Verilog primitives on large scale designs. Some simulators have notable changes others do not. It is difficult to tell who is doing a better job following the LRM or has a smarter optimizer.
Adding a per-compile script to remove hard coded forms of #0, is easy enough. The challenge is with parameterized delay. Do I really need to create generate blocks for to avoid the inactive region? Feels like it could introduce more problems than solve:
generate
if ( RISE > 0 || FALL > 0)
tranif1 #(RISE,FALL) ipassgate ( D, S, G );
else
tranif1 ipassgate ( D, S, G );
if ( RISE > 0 || FALL > 0 || DECAY > 0)
cmos #(RISE,FALL,DECAY) i1 ( out, in, NG, PG );
else
cmos i1 ( out, in, NG, PG );
if (DELAY > 0)
assign #(DELAY) io = drive ? data : 'z;
else
assign io = drive ? data : 'z;
endgenerate
Verilog primitives and continuous assignments have been with Verilog since the beginning. I believe parameterized delay has been around longer then the inactive region. I haven't found any documentation on recommendation or explanation for these conditions. My local network of Verilog/SystemVerilog gurus are all unsure which region it should run in. Is there a detail we are all overlooking or is it a gray area in the language? If it is a gray area, how do I determine which way it is implanted?
An accepted answer should include a citation to any version of IEEE1364 or IEEE1800. Or at least a way to do proof of concept testing.
This is an easy one. Section 28.16 Gate and net delays of the 1800-2012 LRM as well as section 7.14 Gate and net delays of the 1364-2005 LRM both say
For both gates and nets, the default delay shall be zero when no delay specification is given. So that means
gateName instanceName (pins);
is equivalent to writing
gateName #0 instanceName (pins);
I'm not sure where the text you quoted came from, but section 4.4.2.3 Inactive events region of the 1800-2012 LRM says
If events are being executed in the active region set, an explicit #0 delay control requires the process to be suspended and an event to be scheduled into the Inactive region of the current time slot so that the process can be resumed in the next Inactive to Active iteration.
The key text is delay control, which is a procedural construct. So #0 as an inactive event only applies to procedural statements.
The problem with procedural #0's is that they move race conditions, they don't eliminate them. Sometimes you have to add multiple serial #0's to move away from a races condition, but you don't always know how many because another piece of code is also adding #0's. Just look at the UVM code; it's littered with messy #0's because they did not take the time to code things properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With