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
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