问题
I am trying to implement a simple event based Verilog simulator in Python, but I actually struggle to find some details in the specification (section 11 of IEEE 1364-2005).
Let's say I just perfomed an update event on clk
which now obtained the new value 1 (0 before). According to the specification this requires me to schedule 'evaluation events' for sensitive processes.
Do I have to schedule the evaluation of an always @(posedge clk)
block as active or inactive event? I'm guessing that the latter is correct?
Or actually, to speak more general. Are basically all events scheduled as inactive events with the following exceptions:
- Non blocking assignment updates as non-blocking assignment events
- continuous assignments as active events
Thanks a lot!
回答1:
By default everything runs in the Active region. The exceptions being:
- #0 blocking assignments are in the Inactive region
- Non-blocking assignments are in the NBA region
- $monitor, $strobe, and PLI/VPI are in the Monitor region
We can prove that @
happens in the Active region, by running the following in any existing simulator:
int x;
initial begin
$monitor("From $monitor: x is %0d",x);
#0 x = 5; // inactive event
x = 3; // active event (after inactive event)
#1; // go to next time stamp
fork
#0 x = 7; // inactive event
x = 11; // active event
join
#0 fork // inactive region
#0 x = 2; // inactive event
x = 5; // active event
x <= 4; // NBA event
join
end
// active event region
always @* $display("From @* $display: x is %0d",x);
Outputs:
From @* $display: x is 3 From $monitor: x is 3 From @* $display: x is 11 From @* $display: x is 7 From @* $display: x is 5 From @* $display: x is 2 From @* $display: x is 4 From $monitor: x is 4
Display reports more times then monitor. This rules out @
accruing in the Monitor or Future region. Display is is reporting on every event region. Each event region can only loop back to the Active region. Therefor, the @
must be handled in the Active region and each region that updates the variable x
is triggering a new Active region event.
This can also be proved by knowing looking at the history of Verilog. Unfortunately, this is not well documented. I leaned learned about it through people that were using/developing verilog in the late '80s early '90s. The over all explanation is: The Inactive and NBA regions were added to Verilog before IEEE Std 1364-1995, @
predates these two region. The regions were added to add determinism to a non-deterministic simulator.
always @(posedge clk) pipe0 = in;
always @(posedge clk) pipe1 = pipe0; // unpredictable, non-deterministic order
always @(posedge clk) #0 pipe0 = in; // Inactive region added some determinism
always @(posedge clk) pipe1 = pipe0;
always @(posedge clk) #0 pipe0 = in; // But was fragile
always @(posedge clk) #0 pipe1 = pipe0; // unpredictable order again
always @(posedge clk) pipe2 = pipe1;
always @(posedge clk) pipe0 <= in;
always @(posedge clk) pipe1 <= pipe0;
always @(posedge clk) pipe2 <= pipe1; // NBA region fixed it
...
always @(posedge clk) pipeN <= pipeM; // and made it scalable
clarification based on feedback from comments
Events are activated, not moved. Activated NBA events enter the true condition ofif (E is an update event)
, modified object and schedule new evaluation events (handled the next time Active region entered). Once all the activated events are completed, the schedule goes back to the top of the while-loop. The NBA region only assigns values, the evaluation was actually done in an earlier Active region stage. From your example:
module TEST;
reg test = 0;
reg test2 = 0;
reg clk = 0;
initial begin
clk <= 1;
test <= 1;
end
always @(posedge clk) begin
test2 <= test;
end
endmodule
Each iteration of the while loop would look something like this:
Iteration:0 Active: <----- This is region is executing clk$tmp = eval(1) test$tmp = eval(1) Inactive: NBA: clk = clk$tmp test = test$tmp Iteration:1 Active: Inactive: NBA: <----- This is region is executing clk = clk$tmp test = test$tmp Active.schedule( eval( "@(posedge clk)" ) Iteration:2 Active: <----- This is region is executing eval( "@(posedge clk)" ) Active.schedule( "test2$tmp = eval(test)" ) NBA.schedule( "test2 = test2$tmp" ) Inactive: NBA: Iteration:3 Active: <----- This is region is executing test2$tmp = eval(test) Inactive: NBA: test2 = test2$tmp Iteration:4 Active: Inactive: NBA: <----- This is region is executing test2 = test2$tmp Iteration:5 --> next simulation cycle
来源:https://stackoverflow.com/questions/22815281/evaluation-event-scheduling-verilog-stratified-event-queue