/// LSU EE 3755 -- Computer Organization
//
/// Verilog Notes 4 – Fall 2005 Delay, Descriptive Styles
/// Contents
/// Delays
/// Ripple Adder and Delays
/// The Event Queue and Verilog Simulation
//
Descriptive Styles
//
Implicit Structural Descriptive Style
//
Behavioral
/// Lexicographic Conventions
//
//
:Sample: A short example of Verilog,
much less than a whole module.
//
:Example: A long example of Verilog code, usually a module.
//
[bar]: Information that EE 3755
students are not yet responsible for
// but is included here anyway.
///
References
//
:P: Palnitkar, "Verilog HDL"
//
:Q: Qualis, "Verilog HDL Quick
Reference Card Revision 1.0"
//
:PH: Patterson & Hennessy,
"Computer Organization & Design"
////////////////////////////////////////////////////////////////////////////////
///
Delays
//
:P: 6.2, 6.2.2, 6.2.3
//
A /delay/ is a specification of elapsed time, the amount of
//
time the simulator is supposed to wait.
//
The simulator keeps track of simulated time, measured in cycles.
//
This is unlike conventional languages.
//
The default delay is zero.
//
//
If delays are not specified things happen instantly.
//
//
The default delay for a gate is zero.
//
//
The default delay for an assign is zero.
//
//
The default delay for an assign with a really complex expression
//
is zero.
//
//
The default delay for a module containing a zillion gates is zero.
//
//
Zero is NOT the same as one.
//
//
Delays can be specified in a variety of ways.
//
//
The following will be covered in
class:
//
// Delays in wires and assigns (this set).
// Delays in behavioral statements (later
this semester).
//
// See "delays" module, below, for
further description.
//
:Example:
//
//
A module that just passes the signal through, like wire. Suppose
//
at t=5 input a changes from 0 to 1, when does x change?
module
no_delays(x,a);
input a;
output x;
assign x = a;
wire
w = x;
endmodule
//
Ans: x changes at 5 + 0 = 5.
//
:Example:
//
//
A module that just passes the signal through unchanged, though it
//
passes through two inverters. Suppose
at t=5 input a changes from
//
0 to 1, when does x change?
module
no_delays2(x,a);
input a;
output x;
wire
b;
not n1(b,a);
not n2(x,b);
endmodule
//
Ans: x changes at 5.
//
:Example:
//
//
Illustration and explanation of delays in assigns and wires.
module
delays(x,a);
input a;
output x;
// Delay (For nets.)
//
wire #7
w = a;
//
// w gets value of a 7 cycles after each
change in a (a must hold
// steady for at least 7 cycles).
// Delay (For continuous assignments.)
//
assign #3 x = w;
//
// x gets value of "w" 3 cycles
after each change in "w" (w must
// hold steady for at least 3 cycles).
endmodule
////////////////////////////////////////////////////////////////////////////////
///
Ripple Adder and Delays
//
:Example:
//
//
The binary full adder presented earlier.
There are no delays here.
module
bfa_implicit(sum,cout,a,b,cin);
input a,b,cin;
output sum,cout;
assign sum =
~a & ~b & cin |
~a & b & ~cin |
a & ~b & ~cin |
a & b & cin;
assign cout = a & b | b & cin | a
& cin;
endmodule
//
:Example:
//
//
The same BFA with delays.
//
Suppose "a" changes at t=5 and "b" changes at t=20.
//
When do sum and cout change?
module
bfa_implicit_d(sum,cout,a,b,cin);
input a,b,cin;
output sum,cout;
assign #3 sum =
~a & ~b & cin |
~a & b & ~cin |
a & ~b & ~cin |
a & b & cin;
assign #2 cout = a & b | b & cin |
a & cin;
endmodule
//
Ans: sum: t=8 and t=23; cout t=7 and
t=22.
//
:Example:
//
//
A 4-bit ripple adder constructed using the undelayed BFA.
//
If a changes at t=5 when does sum change?
module
ripple_4(sum,cout,a,b);
input [3:0] a, b;
output [3:0] sum;
output cout;
wire c0, c1, c2;
bfa_implicit bfa0(sum[0],c0,a[0],b[0],1'b0);
bfa_implicit bfa1(sum[1],c1,a[1],b[1],c0);
bfa_implicit bfa2(sum[2],c2,a[2],b[2],c1);
bfa_implicit
bfa3(sum[3],cout,a[3],b[3],c2);
endmodule
//
Ans: t = 5.
//
:Example:
//
//
A 4-bit ripple adder constructed using the BFA with delays.
//
Suppose at t=0 a=0 and b=4'b1111
//
If a changes to 1 at t=100 when does sum stop changing?
module
ripple_4_d(sum,cout,a,b);
input [3:0] a, b;
output [3:0] sum;
output cout;
wire c0, c1, c2;
bfa_implicit_d
bfa0(sum[0],c0,a[0],b[0],1'b0);//sum[0] changes at 103,
//c0 changes at 102.
bfa_implicit_d
bfa1(sum[1],c1,a[1],b[1],c0); //sum[1]
changes at 105,
//c1 changes at 104.
bfa_implicit_d
bfa2(sum[2],c2,a[2],b[2],c1); //sum[2]
changes at 107,
//c2 changes at 106.
bfa_implicit_d
bfa3(sum[3],cout,a[3],b[3],c2);//sum[3] changes at 109,
//cout changes at 108.
endmodule
//
Ans t=109
//
:Example:
//
//
A 4-bit adder using operators and no delays. This would be
//
a better way of coding a 4-bit adder in Verilog, but it's
//
not a good way to demonstrate the low speed of a ripple adder
//
to a computer organization class.
//
Think about CLA(fast) and Ripple Carry Adder(slow).
//
If no delay CLA and RCA will compute at the same time.
module
another_adder(sum,cout,a,b);
input [3:0] a, b;
output [3:0] sum;
output cout;
wire [4:0] sum_with_carry = a + b;
assign sum = sum_with_carry[3:0];
assign cout = sum_with_carry[4];
endmodule
//
:Example:
//
//
This is not really an example and students are not expected
//
to understand it. This is a testbench
for the adder, it
//
instantiates the adders, generates inputs for them, and checks
//
for the correct output.
//
module
demoadd();
wire [4:0] sum1, sum2, sum3;
reg [4:0] shadow_sum;
reg [3:0]
a, b;
integer
i;
ripple_4 adder1(sum1[3:0],sum1[4],a,b);
ripple_4_d adder2(sum2[3:0],sum2[4],a,b);
another_adder
adder3(sum3[3:0],sum3[4],a,b);
task check_sum;
input [4:0] s;
input [79:0] name;
if( s != shadow_sum ) begin
$display("Wrong sum in %s: %d +
%d = %d != %d\n",
name, a, b, shadow_sum, s);
$stop;
end
endtask
initial begin
for(i=0; i<=255; i=i+1) begin
a = i[3:0];
b = i[7:4];
shadow_sum = a + b;
#10;
check_sum(sum1,"Ripple");
check_sum(sum2,"Ripple_d");
check_sum(sum3,"Operator");
end
$display("Tests completed.");
end
endmodule
////////////////////////////////////////////////////////////////////////////////
///
The Event Queue and Verilog Simulation
/// The Verilog Simulator Event Queue
//
//
Simulator maintains a "to-do list" called an /event queue/.
//
//
An entry in the event queue specifies something that the simulator
// needs to do. These include:
//
// (A) Changing the value of a wire [or reg].
//
// (B) Evaluating an expression appearing in
an assign statement.
//
// (C) Determining the output of a gate.
//
//
(The letters above are used in the example below.)
//
//
Each entry has a /timestamp/ which indicates when the action
// specified by the entry is supposed to be
done.
//
//
Entries are sorted by timestamp.
//
//
[Entries with the same timestamp are divided in to five layers.]
/// How Verilog Simulators Run
//
//
Wires [and registers] are initialized to x.
//
//
Initial entries are put in the event queue. (Covered later in the
// semester.)
//
//
WHILE there the event queue is non-empty:
//
// Remove any entry with the smallest time
stamp.
//
// Set the time to that time stamp.
//
// If the entry changes the value of a wire
[or reg]:
//
// Put entries in the event queue for all
gates and expressions
// [and event controls] affected by the
wire [or reg].
//
// Else If the entry is for an expression in
an assign statement:
//
// Evaluate the expression. Put an entry in the event queue
// to modify the wire that's assigned. The entry's time stamp
// is the current time plus the delay (plus
zero if no delay).
// [Delete other entries in the event queue
corresponding to the
// same assign.]
//
// Else If the entry is for a gate:
//
// Determine the output of the gate. Put an
entry in the event
// queue to modify the wire connected to
the gate's output. The
// entry's time stamp is the current time
plus the delay (plus
// zero if no delay). [Delete other entries in the event queue
// corresponding to the same gate
instance.]
//
// Else If ... (Covered with procedural code.)
//
//
End simulation (when while loop is done).
//
:Example:
//
//
Module illustrating timing and event queue.
The testbench (shown
//
further below) sets a and b equal to 0 at t=0.
module
timing(x,y,a,b);
input a, b;
output x,y;
wire d, e;
not #2 n1(d,a);
not #3 n2(e,d);
assign x = b ^ d ^ e;
xor a1(y,b,d,e);
endmodule
/// Event Queue for Example
//
//
The comments below show the contents of the event queue as the
//
module above is simulated with the testbench way below. Some
//
events generated by the testbench have not been shown.
// Event Queue After Testbench Starts, t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 1 timestamp = 0; A: Set a <- 0
//
Entry 0 timestamp = 0; A: Set b <- 0
//
Entry 0 removed.
//
Change b from x to 0.
//
Add affected items:
// Event Queue at t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 4 timestamp = 0; B: Evaluate: xor a1(y,b,d,e);
//
Entry 3 timestamp = 0; B: Evaluate: assign x = b ^ d ^ e;
//
Entry 1 timestamp = 0; A: Set a <- 0
//
Entry 1 removed.
//
Change a from x to 0.
//
Add affected items.
// Event Queue at t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a);
//
Entry 4 timestamp = 0; C: Evaluate: xor a1(y,b,d,e);
//
Entry 3 timestamp = 0; B: Evaluate: assign x = b ^ d ^ e;
//
Entry 3 removed.
//
Compute b ^ d ^ e, result wire x does not change (was undefined, still is)
// Event Queue at t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a);
//
Entry 4 timestamp = 0; C: Evaluate: xor a1(y,b,d,e);
//
Entry 4 removed
//
Compute xor a1(y,b,d,e). Output y does
not change (was x, still is).
// Event Queue at t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a);
//
Entry 5 removed.
//
Compute n1(d,a). d is to change from x
to 1.
//
Insert change to d in event queue for 2 cycles later.
// Event Queue at t = 0
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 6 timestamp = 2; Set d <- 1
//
Remove entry 6.
//
Change time to t = 2.
//
Set d to 1.
//
Add items affected by d.
// Event Queue at t = 2
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 9 timestamp = 2; assign x = b ^ d ^ e;
//
Entry 8 timestamp = 2; xor a1(y,b,d,e);
//
Entry 7 timestamp = 2; not #3 n2(e,d);
//
Remove entry 7.
//
Compute n2(e,d). e is to change from x
to 0
//
Insert change to e in event queue for 3 cycles later.
// Event Queue at t = 2
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 10 timestamp = 5; Set e <- 0
//
Entry 9 timestamp = 2; assign x = b ^ d ^ e;
//
Entry 8 timestamp = 2; xor a1(y,b,d,e);
//
Remove entry 8.
//
Compute xor(y,b,d,e)
//
No change in y. (Was x, still is.)
// Event Queue at t = 2
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 10 timestamp = 5; Set e <- 0
//
Entry 9 timestamp = 2; assign x = b ^ d ^ e;
//
Remove entry 9
//
Compute b ^ d ^ e
//
No change in x.
// Event Queue at t = 2
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 10 timestamp = 5; Set e <- 0
//
Remove entry 10.
//
Change time to t = 5
//
Set e to 0
//
Add affected items.
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 12 timestamp = 5; assign x = b ^ d ^ e;
//
Entry 11 timestamp = 5; xor a1(y,b,d,e);
//
Remove entry 11.
//
Evaluate xor(y,b,d,e) y to change from
x to 1.
//
Add change to queue.
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 13 timestamp = 5; Set x <- 1
//
Entry 12 timestamp = 5; assign x = b ^ d ^ e;
//
Remove entry 12.
//
Evaluate b ^ d ^ e. wire x to change
from x to 1.
//
Add change to queue.
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 14 timestamp = 5; Set y <- 1
//
Entry 13 timestamp = 5; Set x <- 1
//
Remove entry 13.
//
Set x to 1.
//
Add affected items. (The affected item is in the testbench which isn't shown.)
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 15 timestamp = 5; Some procedural stuff.[always @( a or b or x
or y )]
//
Entry 14 timestamp = 5; Set y <- 1
//
Remove entry 14
//
Set y to 1.
//
Add affected items. (The affected item is already there, the always thing.)
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Entry 15 timestamp = 5; Some procedural stuff.[always @( a or b or x
or y )]
//
Remove entry 15
//
The procedural code prints a message.
// Event Queue at t = 5
//
//
Entry 2 timestamp = 8; Resume testbench procedural code.
//
Remove entry 2 (finally).
//
Change time to t = 8
//
Continue running the procedural code until... something else
// is put in the event queue. More details will be provided when
procedural
// code covered.
//
:Example:
//
//
The testbench for the code above. This
module uses procedural
//
code which has not been covered yet. It
can be ignored for now.
module
demo_timing();
reg a, b;
wire x, y;
timing everyones_timing_module_instance(x,y,a,b);
integer i;
always @( a or b or x or y )
$display(" a,b = %d, %d x,y= %d, %d",a,b,x,y);
initial begin
for(i=0; i<4; i=i+1) begin
{a,b} = i[1:0];
#8;
end
end
endmodule
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
Descriptive Styles
///
Descriptive Style Definition
//
// A set of rules for a Verilog description.
///
Three Major Styles
//
// Explicit Structural: Most restrictive.
// Implicit Structural: Still restrictive.
// Behavioral: Least restrictive. (Not yet covered.)
//
// A Verilog description is called ``explicit structural''
if it
// follows explicit structural design rules.
(described below).
// The same holds for the other styles.
/// Explicit Structural Descriptive Style
//
// The Verilog specifies every component and
how they are wired.
//
// Tedious to write
//
// Rules:
// No operators (+,&,~, etc.)
// No assign's (continuous assignments).
// No initial/always blocks (covered later).
//
:Example:
//
// The module below is explicit structure and
is neither implicit
// structural nor behavioral.
module
bfa_structural(sum,cout,a,b,cin);
input a,b,cin;
output sum,cout;
wire
term001, term010, term100,term111;
wire
ab, bc, ac;
wire
na, nb, nc;
or o1(sum,term001,term010,term100,term111);
or o2(cout,ab,bc,ac);
and a1(term001,na,nb,cin);
and a2(term010,na,b,nc);
and a3(term100,a,nb,nc);
and a4(term111,a,b,cin);
not n1(na,a);
not n2(nb,b);
not n3(nc,cin);
and a10(ab,a,b);
and a11(bc,b,cin);
and a12(ac,a,cin);
endmodule
////////////////////////////////////////////////////////////////////////////////
///
Implicit Structural Descriptive Style
//
Some components and wiring are specified using expressions.
//
Less tedious to write
//
Rules:
// No initial/always blocks (covered later).
//
:Example:
//
// The module below is implicit structure and
is neither explicit
// structural nor behavioral.
module
bfa_implicit(sum,cout,a,b,cin);
input a,b,cin;
output sum,cout;
assign sum =
~a & ~b & cin |
~a & b & ~cin |
a & ~b & ~cin |
a & b & cin;
assign cout = a & b | b & cin | a
& cin;
// It can't be explicit structural because
of the assign and operators.
endmodule
////////////////////////////////////////////////////////////////////////////////
///
Behavioral
//
Easiest to write.
//
:Example:
//
// The module below is behavioral and is
neither explicit nor
// implicit structural.
//
module
bfa_behavioral(sum,cout,a,b,cin);
input a,b,cin;
output sum,cout;
// Material for this module will be covered
later.
// It's here to show what behavioral code
looks like.
// We aren’t going to explain behavioral
code now.
reg
sum, cout;
always @( a or b or cin )
begin
sum = ~a & ~b & cin |
~a & b & ~cin |
a & ~b & ~cin |
a & b &
cin;
cout = a & b | b & cin | a
& cin;
end
endmodule
////////////////////////////////////////////////////////////////////////////////