///
LSU EE 3755 -- Computer Organization
//
///
Verilog Notes 4 – Fall
2009 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
////////////////////////////////////////////////////////////////////////////////