Simulation time

As far as physics currently understands time is a single continuous dimension.

Simulation time is discrete but multidimensional!     (Short aside: Event Driven Simulation.)

Naturally, none of this relates to the actual time taken to run the simulation, which depends on how much switching activity takes place in the design.


Assignment timing

Assuming they are scheduled to happen at the same time:

Example

always @ (posedge clk) a = b;       // Blocking
always @ (posedge clk) b = a;       // Blocking
always @ (posedge clk) x <= y;      // Non-blocking
always @ (posedge clk) y <= x;      // Non-blocking

After a clock edge:

However:

always @ (posedge clk)
begin
a = b;
b = a;
end

is entirely predictable – if rather pointless.

Potential pitfall

always @ (posedge clk) x <= a;   // Non-blocking
always @ (posedge clk) a = b;    // Blocking

In simulation x will always take the value from b.

However a synthesizer will probably see this as two sequential flip-flops.

A synthesized circuit will behave differently from the simulation!

Okay, that's the wrong thing to happen but complaining won't change it.

Guidelines

[Forward reference]

Stylistic pitfall (?)

When simulating synchronous circuit models the most convenient thing to write is:

always @ (posedge clk)
if (count < 9) count <= count + 1; else count <= 0;

‘count’ then changes:

The resulting trace may be slightly misleading although it is safe.

But what if the inputs (RHS) are generated with a blocking assignment ...

Therefore keep all blocks and modules in the same style!


This might aid readability …

(Perhaps) the obvious way to stimulate a design may be something like this:

initial clk = 1;
always #5 clk <= !clk;
 
initial
  begin
  data = 0;
  #10;
  data = 1;
  #10;
  data = 2;
  #10;
  end
 
always @ (posedge clk) value_1 <= data;
always @ (posedge clk) value_2 <= value_1;

Unfortunately – because the blocking assignment (data) completes before the non-blocking assignments – this will lead to the following timing relationship:

Unfortunate timing

Offsetting input changes slightly from the clock may help.

parameter period = 10; // Makes changes easier
 
initial clk = 1;
always #(period/2) clk <= !clk;
 
initial
  begin
  #1; // Inputs delayed
  data = 0;
  #period;
  data = 1;
  #period;
  data = 2;
  #period;
  end
 
always @ (posedge clk) value_1 <= data;
always @ (posedge clk) value_2 <= value_1;

Unfortunate timing

There are a couple of disadvantages of the form above.

parameter period = 10; // Makes changes easier
 
initial clk = 1;
always #(period/2) clk <= !clk;
 
initial
  begin
  data <= #1 0; // Inertial delay
  #period;
  data <= #1 1;
  #period;
  data <= #1 2;
  #period;
  end
 
always @ (posedge clk) value_1 <= #1 data;
always @ (posedge clk) value_2 <= #1 value_1;

Nicer timing

The evaluation here takes place at the clock edge: it is just the result assignment which is delayed.
Suggest that this is clearer!

Rather than inserting explicit delay times it may be more robust to count the clock edges. The ‘@’ symbol means ‘at the next event from the following list’ so: ‘@ (posedge clk)’ means ‘wait until the next active clock edge’ — this will always keep execution in synchronisation with the clock.

repeat (10) @ (posedge clk)’ will, of course wait for the tenth successive clock edge etc.


Delays

Here are some convenient methods:

#20 a = l;           // Delay in execution of sequential block
 
wire #4 q;           // Declare a ‘net delay’ ...
assign q = a & b;    // q changes 4 timesteps after an input change
 
register <= #10 input_value; // Propagation delay on signal

Uses include


Delays

Time is modelled in two ways:

Examples:

initial
begin
a = 0;
#10;
a = 1;
end
 
assign b = !a; assign c = !b;

Time action
 0   a = 0 
 0   b = 1 
 0   c = 0 
 10   a = 1 
 10   b = 0 
 10   c = 1 

At any point there is only one thing which is scheduled to happen, but a change schedules a(n immediate) change on b, etc.

initial
begin
a = 0;
#10;
a = 1;
end
 
assign #5 b = !a;
assign #6 c = !b;

Time action
 0   a = 0 
 5   b = 1 
 10   a = 1 
 11   c = 0 
 15   b = 0 
 21   c = 1 

Delays can alter when switching occurs.

Delays can also be inserted within assignments to delay the assignment without retarding the flow of execution, e.g.:

a <= #10 b;

Same unit: different delays

For added veracity it is possible to specify different rising, falling and turn-off delays for a signal by listing these in brackets. E.g.

#(3,2)

means a rising delay of 3, a falling delay of 2. The turn-off delay has not been specified so defaults to the minimum of these (if appropriate).


Glitches

‘Glitches’ are brief signal changes which result from signal races through combinatorial logic; they will only be visible in simulation if gates (or other logic blocks) include delay models. Thus they will not (typically) appear in an abstracted simulation.

Glitches may appear in more detailed models, including a netlist extracted from a synthesized design: i.e. one which includes details of the actual circuits and delays. This could cause problems running the same simulation successfully as previously, depending on how the testbench is constructed. There is a little bonus page about this here.


Up to simulation

Back to parallelism in simulation

Forward simulation events

Bonus pages

Event Driven Simulation

Trouble with glitches