Delta time updates and race hazards

S

Simon Southwell

Guest
I'm looking for a method to update a wide register (or set of
registers)from the ports of a test element module with a narrower
output, in delta time without a race condition hazard occuring.

In the cut down example below the module 'block' has a byte output
(value) and an index (Idx). To update an external register that's 32
bits wide, 4 values are needed each cycle. To update in delta time an
output 'Update' is toggle for each value and a value 'UpdateComplete'
is returned after the single update on which 'block' is waiting.
Externally an always block triggers on 'Update' and does the partial
update of 'Register' dependant on 'Idx', using blocking assignments. At
the end, 'UpdateComplete' is toggled.

Now the question is, is it guaranteed that Idx and Value will have
changed before the 'always @(Update)' is triggered. Blocking
assignments are used in 'block', but since they are exported onto
ports, and then through wires, implying continuous assignments, is it
the case that these assignments could get reordered so that,
externally, 'Update' changes before either Idx or Value (or both)? Or
is it the case that all affected continuous assignments are resolved,
and placed on the event queue before the next internal blocking
assignment is calculated?

In the real code I'm putting together (a 'virtual processor'
co-simulation element), the interface for the 'block' equivalent is
generic, as the element may be connected to any arbitrary external
environment and need to update any number of registers in a delta
cycle. I'm trying to avoid putting false delays in for each update
(i.e. #1 between block's Value assignment and the Update toggle), and
also, if possible, hierarchical references (e.g. blk.Update).

It appears to simulate correctly (on VCS), even turning on delta cycle
display in the waveforms and inspecting the ordering, but maybe I got
lucky. So is what I have guaranteed safe, or is there a better (but
still clean) method to achieve the goal?

code is given below.

Simon

//
-----------------------------------------------------------------------------------

module block (Clk, Update, UpdateComplete, Idx, Value);

input Clk;
input UpdateComplete;

output Update;
output [1:0] Idx;
output [7:0] Value;

reg Update;
reg [1:0] Idx;
reg [7:0] Value;
integer Count;

initial
Update = 0;

always @(posedge Clk)
begin
Count = 4;

while (Count)
begin
Count = Count - 1;
Idx = Count[1:0];
Value = $random;
Update = ~Update;

@(UpdateComplete);
end
end

endmodule

module test;

wire Update;
wire [1:0] Idx;
wire [7:0] Value;

reg Clk;
reg [31:0] Register;
reg UpdateComplete;

block blk (Clk, Update, UpdateComplete, Idx, Value);

initial
begin
Clk = 1;
UpdateComplete = 1;
forever Clk = #1000 ~Clk;
end

always @(Update)
begin
if (Idx == 2'b00)
Register[7:0] = Value;
else if (Idx == 2'b01)
Register[15:8] = Value;
else if (Idx == 2'b10)
Register[23:16] = Value;
else
Register[31:24] = Value;

UpdateComplete = ~UpdateComplete;
end

endmodule
 
This is not guaranteed to work by the language definition. The
execution order of the statements in the sequential block is
guaranteed, and each blocking assignment is guaranteed to update the
reg before the next statement executes (which is why it is called a
blocking assignment). But as you feared, the continuous assignments to
the wires on the outside of the ports could occur in any order, as
could the actual updates to the wires resulting from those continuous
assignments. It is definitely not the case that continuous assignments
triggered by a blocking assignment will always be evaluated before the
statement following the blocking assignment; there are simulators that
will not do this.

A real simulator will not use a nondeterministic ordering, and the
ordering it uses may allow this code to work. For example, it might
always append events to the event queue, in which case the output nets
would update in the same order as the regs. But the language
definition says that this is not guaranteed.

You might be able to get something guaranteed by using nonblocking
assignments for your Update reg. A nonblocking assignment is
guaranteed not to update until after all your blocking assignments and
associated continuous assignments are complete.
 

Welcome to EDABoard.com

Sponsor

Back
Top