11.6   Timing Controls and Delay


Chapter start

Previous page

Next page

11.6   Timing Controls and Delay

The statements within a sequential block are executed in order, but, in the absence of any delay, they all execute at the same simulation time--the current time step. In reality there are delays that are modeled using a timing control.

11.6.1   Timing Control

A timing control is either a delay control or an event control [Verilog LRM 9.7]. A delay control delays an assignment by a specified amount of time. A timescale compiler directive is used to specify the units of time followed by the precision used to calculate time expressions,

`timescale 1ns/10ps // Units of time are ns. Round times to 10 ps.

Time units may only be s , ns , ps , or fs and the multiplier must be 1, 10, or 100. We can delay an assignment in two different ways:

  • Sample the RHS immediately and then delay the assignment to the LHS.
  • Wait for a specified time and then assign the value of the LHS to the RHS.

Here is an example of the first alternative (an intra-assignment delay):

x = #1 y; // intra-assignment delay

The second alternative is delayed assignment:

#1 x = y; // delayed assignment

These two alternatives are not the same. The intra-assignment delay is equivalent to the following code:

begin // Equivalent to intra-assignment delay.
hold = y; // Sample and hold y immediately.
#1; // Delay.
x = hold; // Assignment to x. Overall same as x = #1 y.
end 

In contrast, the delayed assignment is equivalent to a delay followed by an assignment as follows:

begin // Equivalent to delayed assignment.
#1; // Delay.
x = y; // Assign y to x. Overall same as #1 x = y.
end 

The other type of timing control, an event control, delays an assignment until a specified event occurs. Here is the formal definition:

event_control ::= @ event_identifier | @ (event_expression)
event_expression ::= expression | event_identifier
  | posedge expression | negedge expression
  | event_expression or event_expression

(Notice there are two different uses of 'or' in this simplified BNF definition--the last one, in bold, is part of the Verilog language, a keyword.) A positive edge (denoted by the keyword posedge ) is a transition from '0' to '1' or 'x' , or a transition from 'x' to '1 '. A negative edge ( negedge ) is a transition from '1' to '0' or 'x' , or a transition from 'x' to '0'. Transitions to or from 'z' do not count. Here are examples of event controls:

module delay_controls; reg X, Y, Clk, Dummy;
always #1 Dummy=!Dummy; // Dummy clock, just for graphics.
// Examples of delay controls:
always begin #25 X=1;#10 X=0;#5; end
// An event control:
always @(posedge Clk) Y=X; // Wait for +ve clock edge.
always #10 Clk = !Clk; // The real clock.
initial begin Clk = 0;
  ("T   Clk X Y");
  ("%2g",,,,Clk,,,,X,,Y);
  ;#100 ; end
endmodule
T   Clk X Y
 0  0   x x
10  1   x x
20  0   x x
25  0   1 x
30  1   1 1
35  1   0 1
40  0   0 1
50  1   0 0
60  0   0 0
65  0   1 0
70  1   1 1
75  1   0 1
80  0   0 1
90  1   0 0

The dummy clock in delay_controls helps in the graphical waveform display of the results (it provides a one-time-tick timing grid when we zoom in, for example). Figure 11.1 shows the graphical output from the Waves viewer in VeriWell (white is used to represent the initial unknown values). The assignment statements to 'X' in the always statement repeat (every 25 + 10 + 5 = 40 time ticks).

FIGURE 11.1  Output from the module delay_controls .

 

Events can be declared (as named events), triggered, and detected as follows:

module show_event;
reg clock;
event event_1, event_2; // Declare two named events.
always @(posedge clock) -> event_1; // Trigger event_1.
always @ event_1 
begin ("Strike 1!!"); -> event_2; end // Trigger event_2.
always @ event_2 begin ("Strike 2!!");
; end // Stop on detection of event_2.
always #10 clock = ~ clock; // We need a clock.
initial clock = 0;
endmodule 
Strike 1!!
Strike 2!!

11.6.2   Data Slip

Consider this model for a shift register and the simulation output that follows:

module data_slip_1 (); reg Clk, D, Q1, Q2;
/************* bad sequential logic below ***************/
always @(posedge Clk)  Q1 = D;
always @(posedge Clk)  Q2 = Q1; // Data slips here!
/************* bad sequential logic above ***************/
initial begin Clk = 0; D = 1; end always #50 Clk = ~Clk;
initial begin ("t   Clk D Q1 Q2");
("%3g",,,Clk,,,,D,,Q1,,,Q2); end
initial #400 ; // Run for 8 cycles.
initial ;
endmodule 
t   Clk D Q1 Q2
  0 0   1 x  x
 50 1   1 1  1
100 0   1 1  1
150 1   1 1  1
200 0   1 1  1
250 1   1 1  1
300 0   1 1  1
350 1   1 1  1

The first clock edge at t = 50 causes Q1 to be updated to the value of D at the clock edge (a '1' ), and at the same time Q2 is updated to this new value of Q1 . The data, D , has passed through both always statements. We call this problem data slip.

If we include delays in the always statements (labeled 3 and 4) in the preceding example, like this--

always @(posedge Clk)  Q1 = #1 D;  // The delays in the assignments
always @(posedge Clk)  Q2 = #1 Q1; // fix the data slip.

--we obtain the correct output:

t   Clk D Q1 Q2
  0 0   1 x  x
 50 1   1 x  x
 51 1   1 1  x
100 0   1 1  x
150 1   1 1  x
151 1   1 1  1
200 0   1 1  1
250 1   1 1  1
300 0   1 1  1
350 1   1 1  1

11.6.3   Wait Statement

The wait statement [Verilog LRM9.7.5] suspends a procedure until a condition becomes true. There must be another concurrent procedure that alters the condition (in this case the variable Done --in general the condition is an expression) in the following wait statement; otherwise we are placed on "infinite hold":

wait (Done) ; // Wait until Done = 1 then stop.

Notice that the Verilog wait statement does not look for an event or a change in the condition; instead it is level-sensitive--it only cares that the condition is true.

module test_dff_wait;
reg D, Clock, Reset; dff_wait u1(D, Q, Clock, Reset);
initial begin D=1; Clock=0;Reset=1'b1; #15 Reset=1'b0; #20 D=0; end
always #10 Clock = !Clock; 
initial begin ("T  Clk D Q Reset");
  ("%2g",,,Clock,,,,D,,Q,,Reset); #50 ; end
endmodule 
module dff_wait(D, Q, Clock, Reset);
output Q; input D, Clock, Reset; reg Q; wire D;
always @(posedge Clock) if (Reset !== 1) Q = D;
always begin wait (Reset == 1) Q = 0; wait (Reset !== 1); end 
endmodule
T  Clk D Q Reset
 0 0   1 0 1
10 1   1 0 1
15 1   1 0 0
20 0   1 0 0
30 1   1 1 0
35 1   0 1 0
40 0   0 1 0

We must include wait statements in module dff_wait above to wait for both Reset==1 and Reset==0 . If we were to omit the wait statement for Reset==0 , as in the following code:

module dff_wait(D,Q,Clock,Reset);
output Q; input D,Clock,Reset; reg Q; wire D;
always @(posedge Clock) if (Reset !== 1) Q = D;
// We need another wait statement here or we shall spin forever.
always begin wait (Reset == 1) Q = 0; end 
endmodule

the simulator would cycle endlessly, and we would need to press the 'Stop' button or 'CTRL-C' to halt the simulator. Here is the console window in VeriWell:

C1> .
T  Clk D Q Reset                   <- at this point nothing happens, so press CTRL-C
Interrupt at time 0
C1>

11.6.4   Blocking and Nonblocking Assignments

If a procedural assignment in a sequential block contains a timing control, then the execution of the following statement is delayed or blocked. For this reason a procedural assignment statement is also known as a blocking procedural assignment statement [Verilog LRM 9.2]. We covered this type of statement in Section 11.5.3. The nonblocking procedural assignment statement allows execution in a sequential block to continue and registers are all updated together at the end of the current time step. Both types of procedural assignment may contain timing controls. Here is an artificially complicated example that illustrates the different types of assignment:

module delay;
reg a,b,c,d,e,f,g,bds,bsd;
initial begin 
a = 1; b = 0; // No delay control.
#1 b = 1;     // Delayed assignment.
c = #1 1;     // Intra-assignment delay.
#1;           // Delay control.
d = 1;        //
e <= #1 1;    // Intra-assignment delay, nonblocking assignment
#1 f <= 1;    // Delayed nonblocking assignment.
g <= 1;       // Nonblocking assignment.
end 
initial begin #1 bds = b; end // Delay then sample (ds).
initial begin bsd = #1 b; end // Sample then delay (sd).
initial begin ("t a b c d e f g bds bsd");
("%g",,,a,,b,,c,,d,,e,,f,,g,,bds,,,,bsd); end
endmodule 
t a b c d e f g bds bsd
0 1 0 x x x x x x   x
1 1 1 x x x x x 1   0
2 1 1 1 x x x x 1   0
3 1 1 1 1 x x x 1   0
4 1 1 1 1 1 1 1 1   0

Many synthesis tools will not allow us to use blocking and nonblocking procedural assignments to the same reg within the same sequential block.

11.6.5   Procedural Continuous Assignment

A procedural continuous assignment statement [Verilog LRM 9.3] (sometimes called a quasicontinuous assignment statement) is a special form of the assign statement that we use within a sequential block. For example, the following flip-flop model assigns to q depending on the clear, clr_, and preset, pre_, inputs (in general it is considered very bad form to use a trailing underscore to signify active-low signals as I have done to save space; you might use " _n " instead).

module dff_procedural_assign;
reg d,clr_,pre_,clk; wire q; dff_clr_pre dff_1(q,d,clr_,pre_,clk);
always #10 clk = ~clk;
initial begin clk = 0; clr_ = 1; pre_ = 1; d = 1;
  #20; d = 0; #20; pre_ = 0; #20; pre_ = 1; #20; clr_ = 0;
  #20; clr_ = 1; #20; d = 1; #20; ; end 
initial begin 
  ("T  CLK PRE_ CLR_ D Q");
  ("%3g",,,,clk,,,,pre_,,,,clr_,,,,d,,q); end 
endmodule 
module dff_clr_pre(q,d,clear_,preset_,clock);
output q; input d,clear_,preset_,clock; reg q;
always @(clear_ or preset_)
  if (!clear_) assign q = 0; // active-low clear
  else if(!preset_) assign q = 1; // active-low preset
  else deassign q;
always @(posedge clock) q = d;
endmodule 
T  CLK PRE_ CLR_ D Q
  0  0   1   1   1 x
 10  1   1   1   1 1
 20  0   1   1   0 1
 30  1   1   1   0 0
 40  0   0   1   0 1
 50  1   0   1   0 1
 60  0   1   1   0 1
 70  1   1   1   0 0
 80  0   1   0   0 0
 90  1   1   0   0 0
100  0   1   1   0 0
110  1   1   1   0 0
120  0   1   1   1 0
130  1   1   1   1 1

We have now seen all of the different forms of Verilog assignment statements. The following skeleton code shows where each type of statement belongs:

module all_assignments
//... continuous assignments.
always // beginning of procedure
  begin // beginning of sequential block
  //... blocking procedural assignments.
  //... nonblocking procedural assignments.
  //... procedural continuous assignments.
  end
endmodule

Table 11.4 summarizes the different types of assignments.

TABLE 11.4    Verilog assignment statements.

Type of Verilog assignment

Continuous assignment statement

Procedural assignment statement

Nonblocking procedural assignment statement

Procedural continuous assignment statement

Where it can occur

outside an always or initial statement, task, or function

inside an always or initial statement, task, or function

inside an always or initial statement, task, or function

always or initial statement, task, or function

Example

wire [31:0] DataBus;
assign DataBus =  Enable ? Data :  32'bz
reg Y;
always @(posedge clock) Y = 1;
reg Y;
always Y <= 1;
always @(Enable)
if(Enable) assign Q = D;
else deassign Q;

Valid LHS of assignment

net

register or memory element

register or memory element

net

Valid RHS of assignment

<expression>

net, reg or memory element

<expression>

net, reg or memory element

<expression>

net, reg or memory element

<expression>

net, reg or memory element

Book

11.5.1

11.5.3

11.6.4

11.6.5

Verilog LRM

6.1

9.2

9.2.2

9.3


Chapter start

Previous page

Next page




© 2024 Internet Business Systems, Inc.
670 Aberdeen Way, Milpitas, CA 95035
+1 (408) 882-6554 — Contact Us, or visit our other sites:
AECCafe - Architectural Design and Engineering EDACafe - Electronic Design Automation GISCafe - Geographical Information Services TechJobsCafe - Technical Jobs and Resumes ShareCG - Share Computer Graphic (CG) Animation, 3D Art and 3D Models
  Privacy PolicyAdvertise