Stratified event queue and time 0 race conditions

I have some constants that are set to both variables (via initializers), and net types through continuous assignments to constants:


bit  [ 7 : 0 ] foo_byte_var = 'h11;
wire [ 7 : 0 ] bar_byte_wire = 'h22;

I have some logging code that displays these values:


initial $info( "foo_byte_var=0x%0x, bar_byte_wire=0x%0x", foo_byte_var, bar_byte_wire );

In the past to avoid a time 0 race, I’d often just stick a #1 on the $info to ensure the values had all propagated before being displayed. But, is this #1 necessary?

Then on to my second question, I have another continuous assignment:


wire [ 7 : 0 ] baz_byte_wire = foo_byte_var + bar_byte_wire;
initial $info( "baz_byte_wire=0x%0x", baz_byte_wire )

How does this change things? I understand from “static initialization order fiasco” that I can’t do math with variable initializers and count on things always working. But with the $info() and it’s scheduled time in the event queue, along with the continuous assignment to constants or functions of constants, would things work?

I’m starting to delve deeper in the SystemVerilog standard with respect to the event queue (and getting dizzy!).

I’m thinking if I change my line to:


initial #1step $info(...)

This would make things always work and avoid 0-time race conditions?

In reply to Mark Curry:

There’s some confusion between a feature associated with variable and wire declarations.

All static variable declarations with initializations get lumped together into an indeterminate ordered series of procedural assignment statements (the fiasco) that execute before any processes begin.

What looks like a wire declaration with an initialization is really a short-cut for a declaration with a separate continuous assignment. Its scheduling is unrelated to a variable declaration with initialization. A continuous assignment is a separate process that has indeterminate ordering with all the other initial and always processes.

wire [ 7 : 0 ] bar_byte_wire = 'h22; // is the same as
wire [ 7 : 0 ] bar_byte_wire;
assign bar_byte_wire = 'h22;

This short-cut came long before variable initialization syntax was added to Verilog-2001. Had variable initialization come first, I doubt this would have been added to the LRM. I suggest people refrain from using this short-cut and avoid the confusion.

If you need to print the settled values, you can use $strobe. But I would think about using parameters or the
let
construct to avoid fiascos and settling

let baz_byte_wire = foo_byte_var + bar_byte_wire;

In reply to dave_59:

Dave,
Thanks for the response. I’m quite clear on variable initialization vs. “short-cutted” continuous assignment - which I’m using on the wires above.

Back to your response, why will $strobe work while $info won’t? Your answer implies there’s some difference in where/how these two functions sample things with respect to what region of the event queue. I’m reading the SystemVerilog 2012 spec, section 4 “Scheduling semantics” trying to understand this all better than I have in the past. Where’s the info on why $strobe will work? Looks like I need to read up on “let” keyword too - another part of the standard I’ve never used…

Thanks,
Mark

In reply to Mark Curry:

$info is just like $display with a little more information with it. It executes in whatever region the current process is in.

$strobe sets up a callback to execute in the postponed region. It’s been in the Verilog LRM since Ronald Reagan was president. It’s defined in section 21.2.2 Strobed monitoring of the IEEE 1800-2017 SystemVerilog LRM

In reply to dave_59:

From the standard:

$monitor , $strobe , and other similar events are scheduled in the Postponed region.

What are “other similar events”?

Related to your response:

$info is just like $display with a little more information with it. It executes in whatever region the current process is in.

Sorry to be dense, but is there anyway to control “whatever region the current process is in”? Your answer implies that a $display() would work if I set things up correctly such that it get’s called from a process in the postponed region. Is there any way to do this, or is it only implied from context (i.e. I’m thinking the $display() within an assertion or property implies something about event region).

I know I’m getting pedantic (I’ll likely use your $strobe() suggestion) but I’m peeling back the covers a little, and trying to understand some nittty-gritty details a little better.

Regards,
Mark

In reply to Mark Curry:

The postponed region is a read-only region where you can only execute statements that do not write to any variables. You should not have to worry about similar events unless you write applications that interface with simulation tools.

Yes, the action block of a concurrent or an observed deferred assertion gets executed in the reactive region, and the action block of a final deferred assertion gets executed in the postponed region.