[go: up one dir, main page]

0% found this document useful (0 votes)
12 views89 pages

Verilog chapter 7

Chapter 7 discusses behavioral modeling in Verilog, emphasizing its high level of abstraction and algorithmic approach to circuit design. It covers structured procedures, timing controls, and the differences between blocking and nonblocking assignments, highlighting their significance in digital design. The chapter also provides examples to illustrate the use of initial and always statements, procedural assignments, and various timing control mechanisms.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views89 pages

Verilog chapter 7

Chapter 7 discusses behavioral modeling in Verilog, emphasizing its high level of abstraction and algorithmic approach to circuit design. It covers structured procedures, timing controls, and the differences between blocking and nonblocking assignments, highlighting their significance in digital design. The chapter also provides examples to illustrate the use of initial and always statements, procedural assignments, and various timing control mechanisms.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 89

BEHAVIORAL MODELLING

Chapter 7
Introduction
• Designers do not necessarily think in terms of logic gates or data
flow but in terms of the algorithm they wish to implement in
hardware.
• Verilog provides designers the ability to describe design
functionality in an algorithmic manner.
• The designer describes the behavior of the circuit.
• Thus, Behavioral modeling represents the circuit at a very high
level of abstraction.
• Design at this level resembles C programming more than it
resembles digital circuit design.
• Behavioral Verilog constructs are similar to C language
constructs in many ways.
• Verilog is rich in behavioral constructs that provide the designer
with a great amount of flexibility.
Learning Objectives
• Explain the significance of structured procedures always
and initial in behavioral modeling.
• Define blocking and nonblocking procedural assignments.
• Understand delay-based timing control mechanism in
behavioral modeling.
• Use regular delays, intra-assignment delays, and zero delays.
• Use level-sensitive timing control mechanism in behavioral
modeling.
• Describe event-based timing control mechanism in behavioral
modeling. Use
• Define sequential and parallel blocks.
• Regular event control, named event control, and event OR
control.
• Explain conditional statements using if and else.
• Describe multiway branching, using case, casex, and casez
statements.
• Understand looping statements such as while, for, repeat, and
forever.
• Understand naming of blocks and disabling of named blocks.
• Use behavioral modeling statements in practical examples.
Structured Procedures
• There are two structured procedure statements in Verilog:
always and initial.
• These statements are the two most basic statements in
behavioral modeling.
• All other behavioral statements can appear only inside these
structured procedure statements.
• Verilog is a concurrent programming language unlike the C
programming language, which is sequential in nature.
• Activity flows in Verilog run in parallel rather than in
sequence.
• Each always and initial statement represents a separate activity
flow in Verilog.
• Each activity flow starts at simulation time 0. The statements
always and initial cannot be nested.
Initial Statement
• All statements inside an initial statement constitute an initial
block. An initial block starts at time 0, executes exactly once
during a simulation, and then does not execute again.
• If there are multiple initial blocks, each block starts to execute
concurrently at time 0.
• Each block finishes execution independently of other blocks.
• Multiple behavioral statements must be grouped, typically
using the keywords begin and end.
• If there is only one behavioral statement, grouping is not
necessary.
Example : initial Statement
module stimulus;
reg x,y, a,b, m;
initial
m = 1'b0; //single statement; does not need to be grouped
initial
begin
#5 a = 1'b1; //multiple statements; need to be grouped
#25 b = 1'b0;
end
initial
begin
#10 x = 1'b0;
#25 y = 1'b1;
end
initial
#50 $finish;
endmodule

• The initial blocks are typically used for


initialization, monitoring, waveforms and other
processes that must be executed only once during
the entire simulation run.
• In the above example, the three initial statements start to
execute in parallel at time 0. If a delay #<delay> is seen
before a statement, the statement is executed <delay> time
units after the current simulation time.
• Thus, the execution sequence of the statements inside the
initial blocks will be as follows.
time statement executed
0 m = 1'b0;
5 a = 1'b1;
10 x = 1'b0;
30 b = 1'b0;
35 y = 1'b1;
50 $finish;
Combined Variable Declaration and
Initialization
Variables can be initialized when they are declared.
Example :Initial Value Assignment
//The clock variable is defined first
reg clock;
//The value of clock is set to 0
initial clock = 0;
//Instead of the above method, clock variable
//can be initialized at the time of declaration
//This is allowed only for variables declared
//at module level.
reg clock = 0;
Combined Port/Data Declaration and
Initialization
module adder (sum, co, a, b, ci);
output reg [7:0] sum = 0; //Initialize 8 bit output sum
output reg co = 0; //Initialize 1 bit output co
input [7:0] a, b;
input ci;
--
--
endmodule
Combined ANSI C Style Port Declaration
and Initialization

module adder (output reg [7:0] sum = 0, //Initialize 8 bit output


output reg co = 0, //Initialize 1 bit output co
input [7:0] a, b,
input ci
);
--
--
endmodule
Always Statement
• All behavioral statements inside an always statement
constitute an always block.
• The always statement starts at time 0 and executes the
statements in the always block continuously in a looping
fashion.
• This statement is used to model a block of activity that is
repeated continuously in a digital circuit.
• An example is a clock generator module that toggles the clock
signal every half cycle.
• In real circuits, the clock generator is active from time 0 to as
long as the circuit is powered on.
Example : always Statement

module clock_gen (output reg clock);


//Initialize clock at time zero
initial
clock = 1'b0;
//Toggle clock every half-cycle (time period = 20)
always
#10 clock = ~clock;
initial
#1000 $finish;
endmodule
Procedural Assignments
• Procedural assignments update values of reg, integer, real, or time
variables.
• The value placed on a variable will remain unchanged until another
procedural assignment updates the variable with a different value.
• The left-hand side of a procedural assignment <lvalue> can be one
of the following:
• A reg, integer, real, or time register variable or a memory element
• A bit select of these variables (e.g., addr[0])
• A part select of these variables (e.g., addr[31:16])
• A concatenation of any of the above
• The right-hand side can be any expression that evaluates to a value.
• There are two types of procedural assignment statements: blocking
and nonblocking
Blocking Assignments
• Blocking assignment statements are executed in the order they
are specified in a sequential block.
• A blocking assignment will not block execution of statements
that follow in a parallel block.
• The = operator is used to specify blocking assignments.
• Note that for procedural assignments to registers, if the right-
hand side has more bits than the register variable, the right-
hand side is truncated to match the width of the register
variable.
• The least significant bits are selected and the most significant
bits are discarded.
• If the right-hand side has fewer bits, zeros are filled in the
most significant bits of the register variable.
Example Blocking Statements
reg x, y, z;
reg [15:0] reg_a, reg_b;
integer count;
//All behavioral statements must be inside an initial or always block
initial
begin
x = 0; y = 1; z = 1; //Scalar assignments
count = 0; //Assignment to integer variables
reg_a = 16'b0; reg_b = reg_a; //initialize vectors
#15 reg_a[2] = 1'b1; //Bit select assignment with delay
#10 reg_b[15:13] = {x, y, z} //Assign result of concatenation to // part
select of a vector
count = count + 1; //Assignment to an integer (increment)
end
• The statement y = 1 is executed only after x = 0 is executed.
• The behavior in a particular block is sequential in a begin-end
block if blocking statements are used, because the statements
can execute only in sequence.
• The statement count = count+ 1 is executed last.
• The simulation times at which the statements are executed are
as follows:
• All statements x = 0 through reg_b = reg_a are executed at
time 0
• Statement reg_a[2] = 0 at time = 15
• Statement reg_b[15:13] = {x, y, z} at time = 25
• Statement count = count + 1 at time = 25
• Since there is a delay of 15 and 10 in the preceding statements,
count = count + 1 will be executed at time = 25 units
Nonblocking Assignments
• Nonblocking assignments allow scheduling of assignments
without blocking execution of the statements that follow in a
sequential block.
• A <= operator is used to specify nonblocking assignments.
• Note that this operator has the same symbol as a relational
operator, less_than_equal_to.
• The operator <= is interpreted as a relational operator in an
expression and as an assignment operator in the context of a
nonblocking assignment.
Example 7-7 Nonblocking Assignments

• reg x, y, z;
• reg [15:0] reg_a, reg_b;
• integer count;
• //All behavioral statements must be inside an initial or
always block
• initial
• begin
• x = 0; y = 1; z = 1; //Scalar assignments
• count = 0; //Assignment to integer variables
• reg_a = 16'b0; reg_b = reg_a; //Initialize vectors
• reg_a[2] <= #15 1'b1; //Bit select assignment with delay
• reg_b[15:13] <= #10 {x, y, z}; //Assign result of
concatenation
• //to part select of a vector
• count <= count + 1; //Assignment to an integer
(increment)
• end
• In this example, the statements x = 0 through reg_b = reg_a are
executed sequentially at time 0.
• Then the three nonblocking assignments are processed at the same
simulation time.
1. reg_a[2] = 0 is scheduled to execute after 15 units (i.e., time = 15)
2. reg_b[15:13] = {x, y, z} is scheduled to execute after 10 time units
(i.e., time = 10)
3. count = count + 1 is scheduled to be executed without any delay (i.e.,
time = 0)
• Thus, the simulator schedules a nonblocking assignment statement
to execute and continues to the next statement in the block without
waiting for the nonblocking statement to complete execution.
• Typically, nonblocking assignment statements are executed last in
the time step in which they are scheduled, that is, after all the
blocking assignments in that time step are executed.
Application of nonblocking assignments
• Having described the behavior of nonblocking assignments,
it is important to understand why they are used in digital
design.
• They are used as a method to model several concurrent
data transfers that take place after a common event.
• To understand the read and write operations further, consider
Example 7-8, which is intended to swap the values of registers a
and b at each positive edge of clock, using two concurrent always
blocks.

• Example 7-8 Nonblocking Statements to Eliminate Race Conditions


• //Illustration 1: Two concurrent always blocks with
blocking
• //statements
• always @(posedge clock)
• a = b;
• always @(posedge clock)
• b = a;
• //Illustration 2: Two concurrent always blocks with
nonblocking
• //statements
• always @(posedge clock)
• a <= b;
• always @(posedge clock)
• b <= a;

• In Illustration 1, there is a race condition when blocking statements are used.


• Either a = b would be executed before b = a, or vice versa, depending on the simulator
implementation.
• Thus, values of registers a and b will not be swapped. Instead, both registers will get the
same value (previous value of a or b), based on the Verilog simulator implementation.
• However, nonblocking statements used in Illustration 2 eliminate the race
condition.
• At the positive edge of clock, the values of all right-hand-side variables are "read," and
the right-hand-side expressions are evaluated and stored in temporary variables.
• During the write operation, the values stored in the temporary variables are assigned to
the left-handside variables.
• Separating the read and write operations ensures that the values of registers a and b are
swapped correctly, regardless of the order in which the write operations are performed.
• Example 7-9 Implementing Nonblocking Assignments using Blocking Assignments
• //Emulate the behavior of nonblocking assignments by
• //using temporary variables and blocking assignments
• always @(posedge clock)
• begin
• //Read operation
• //store values of right-hand-side expressions in temporary
variables
• temp_a = a;
• temp_b = b;
• //Write operation
• //Assign values of temporary variables to left-hand-side
variables
• a = temp_b;
• b = temp_a;
• End

For digital design, use of nonblocking assignments in place of blocking


assignments is highly recommended in places where concurrent data
transfers take place after a common event.
Timing Controls

• Various behavioral timing control constructs are available in


Verilog.
• In Verilog, if there are no timing control statements, the
simulation time does not advance.
• Timing controls provide a way to specify the simulation time
at which procedural statements will execute.
• There are three methods of timing control:
-- delay-based timing control, event-based timing control, and
level-sensitive timing control.
Delay-Based Timing Control
• Delay based timing control in expression specifies the time
duration between when the Statement is encountered and when
it is executed.
• In this section, we will discuss delay-based timing control
statements.
• Delays are specified by the symbol #. Syntax for the delay-
based timing control statement is shown.
....Continue
• Delay-based timing control can be specified by a number,
identifier, or mintypmax_expression.
• There are three types of delay control for procedural
assignments: regular delay control, intra-assignment delay
control, and zero delay control.
Regular delay control
• Regular delay control is used when a non-zero delay is specified to the left
of a procedural assignment.

//define parameters
parameter latency = 20;
parameter delta = 2;
//define register variables
reg x, y, z, p, q;

initial
begin
x = 0; // no delay control
#10 y = 1; // delay control with a number. Delay execution of
// y = 1 by 10 units
#latency z = 0; // Delay control with identifier. Delay of 20 units
#(latency + delta) p = 1; // Delay control with expression
#y x = x + 1; // Delay control with identifier. Take value of
y.
#(4:5:6) q = 0; // Minimum, typical and maximum delay values.
//Discussed in gate-level modeling chapter.
end

• the execution of a procedural assignment is delayed by the number


specified by the delay control.
• For begin-end groups, delay is always relative to time when the
statement is encountered.
•Thus, y =1 is executed 10 units after it is encountered in the activity
flow.
Intra-assignment delay control
• Instead of specifying delay control to the left of the
assignment, it is possible to assign a delay to the right of the
assignment operator.
• Such delay specification alters the flow of activity in a
different manner.
• Regular delays defer the execution of the entire assignment.
Intra-assignment delays compute the right hand-side
expression at the current time and defer the assign variable.
• Intra-assignment delays are like using regular delays with
temporary variable to store the current value of a right-hand-
side expression.
Example

//define register variables


reg x, y, z;

//intra assignment delays


initial
begin
x = 0; z = 0;
y = #5 x + z; //Take value of x and z at the time=0, evaluate
//x + z and then wait 5 time units to assign value
//to y.
end
//Equivalent method with temporary variables and regular delay
control
initial
begin
x = 0; z = 0;
temp_xz = x + z;
#5 y = temp_xz; //Take value of x + z at the current time and

//store it in a temporary variable. Even though x and z


//might change between 0 and 5,
//the value assigned to y at time 5 is unaffected.
end
Zero delay control
• Procedural statements in different always-initial blocks may
be evaluated at the same simulation time.
• The order of execution of these statements in different always-
initial blocks is nondeterministic.
• Zero delay control is a method to ensure that a statement is
executed last, after all other statements in that simulation time
are executed.
• This is used to eliminate race conditions.
• However, if there are multiple zero delay statements, the order
between them is nondeterministic.
• Example below illustrates zero delay control.
EXAMPLE
initial
begin
x = 0;
y = 0;
end
initial
begin
#0 x = 1; //zero delay control
#0 y = 1;
end
, four statements x = 0, y = 0, x = 1, y = 1 are to be executed at
simulation time 0. However, since x = 1 and y = 1 have #0, they will be
executed last.
Thus, at the end of time 0, x will have value 1 and y will have value 1. The
order in which x = 1 and y = 1 are executed is not deterministic.
Event-Based Timing Control
• An event is the change in the value on a register or a net.
• Events can be utilized to trigger execution of a statement or a
block of statements.
• There are four types of event-based timing control: regular
event control, named event control, event OR control, and
level sensitive timing control.
Regular event control
• The @ symbol is used to specify an event control.
• Statements can be executed on changes in signal value or at a
positive or negative transition of the signal value.
• The keyword posedge is used for a positive transition, as
shown in Example .
Example Regular Event Control
@(clock) q = d; //q = d is executed whenever signal clock
changes value
@(posedge clock) q = d; //q = d is executed whenever signal
clock does
//a positive transition ( 0 to 1,x or z,
// x to 1, z to 1 )
@(negedge clock) q = d; //q = d is executed whenever signal
clock does
//a negative transition ( 1 to 0,x or z,
//x to 0, z to 0)
q = @(posedge clock) d; //d is evaluated immediately and
assigned
//to q at the positive edge of clock
Named event control
• Verilog provides the capability to declare an event and then
trigger and recognize the occurrence of that event
• The event does not hold any data.
• A named event is declared by the keyword event. An event is
triggered by the symbol ->.
• The triggering of the event is recognized by the symbol @.
Example Named Event Control
//This is an example of a data buffer storing data after the
//last packet of data has arrived.
event received_data; //Define an event called received_data
always @(posedge clock) //check at each positive clock edge
begin
if(last_data_packet) //If this is the last data packet
->received_data; //trigger the event received_data
end
always @(received_data) //Await triggering of event received_data
//When event is triggered, store all four
//packets of received data in data buffer
//use concatenation operator { }
data_buf = {data_pkt[0], data_pkt[1], data_pkt[2],
data_pkt[3]};
end
Event OR Control
• Sometimes a transition on any one of multiple signals or
events can trigger the execution of a statement or a block of
statements.
• This is expressed as an OR of events or signals.
• The list of events or signals expressed as an OR is also known
as a sensitivity list.
• The keyword or is used to specify multiple triggers, as shown
in Example
Example Event OR Control (Sensitivity List)

//A level-sensitive latch with asynchronous reset


always @( reset or clock or d)
//Wait for reset or clock or d to
change
begin
if (reset) //if reset signal is high, set q to 0.
q = 1'b0;
else if(clock) //if clock is high, latch input
q = d;
end
Example Sensitivity List with Comma
Operator

//A level-sensitive latch with asynchronous reset


always @( reset, clock, d)
//Wait for reset or clock or d to
change
begin
if (reset) //if reset signal is high, set q to 0.
q = 1'b0;
else if(clock) //if clock is high, latch input
q = d;
end
//A positive edge triggered D flipflop with asynchronous falling
//reset can be modeled as shown below
always @(posedge clk, negedge reset) //Note use of comma
operator
if(!reset)
q <=0;
else
q <=d;
Level-Sensitive Timing Control
• Event control discussed earlier waited for the change of a
signal value or the triggering of an event.
• The symbol @ provided edge-sensitive control. Verilog also
allows level sensitive timing control,
• That is the ability to wait for a certain condition To Be True
Before a Statement or a block Of Statements Is executed.
• The Keyword wait is used for level sensitive constructs.
Example

always
wait (count_enable) #20 count = count + 1;
• In the above example, the value of count_enable is monitored
continuously.
• If count_enable is 0, the statement is not entered. If it is
logical 1, the statement count =count + 1 is executed after 20
time units.
• If count_enable stays at 1, count will be incremented every 20
time units.
Conditional Statements

• Conditional statements are used for making decisions based


upon certain conditions.
• These conditions are used to decide whether or not a statement
should be executed.
• Keywords if and else are used for conditional statements.
• There are three types of conditional statements.
//Type 1 conditional statement. No else statement.
//Statement executes or does not execute.
if (<expression>) true_statement ;

//Type 2 conditional statement. One else statement


//Either true_statement or false_statement is evaluated
if (<expression>) true_statement ; else false_statement ;

//Type 3 conditional statement. Nested if-else-if.


//Choice of multiple statements. Only one is executed.
if (<expression1>) true_statement1 ;
else if (<expression2>) true_statement2 ;
else if (<expression3>) true_statement3 ;
else default_statement ;
...continue
• The <expression> is evaluated.
• If it is true (1 or a non-zero value), the true_statement is
executed.
• However, if it is false (zero) or ambiguous (x), the
false_statement is executed.
• The <expression> can contain any operators.
• Each true_statement or false_statement can be a single
statement or a block of multiple statements.
• A block must be grouped, typically by using keywords begin
and end.
• A single statement need not be grouped.
Conditional Statement Examples
//Type 1 statements
if(!lock) buffer = data;
if(enable) out = in;
//Type 2 statements
if (number_queued < MAX_Q_DEPTH)
begin
data_queue = data;
number_queued = number_queued + 1;
end
else
$display("Queue Full. Try again");
//Type 3 statements
//Execute statements based on ALU control signal.
if (alu_control == 0)
y = x + z;

else if(alu_control == 1)
y = x - z;
else if(alu_control == 2)
y = x * z;
else
$display("Invalid ALU control signal");
Multiway Branching
• In type 3 conditional statement Conditional Statements, there
were many alternatives, from which one was chosen.
• The nested if-else-if can become unwieldy if there are too
many alternatives.
• A shortcut to achieve the same result is to use the case
statement.
Case Statement
The keywords case, endcase, and default are used in the case
statement.
case (expression)
alternative1: statement1;
alternative2: statement2;
alternative3: statement3;
...
...
default: default_statement;
endcase
• Each of statement1, statement2 , default_statement can be a
single statement or a block of multiple statements.
• A block of multiple statements must be grouped by keywords
begin and end.
• The expression is compared to the alternatives in the order
they are written.
• For the first alternative that matches, the corresponding
statement or block is executed. If none of the alternatives
matches, the default_statement is executed.
• The default_statement is optional. Placing of multiple default
statements in one case statement is not allowed. The case
statements can be nested..
4-to-1 Multiplexer with Case Statement
module mux4_to_1 (out, i0, i1, i2, i3, s1, s0);
// Port declarations from the I/O diagram
output out;
input i0, i1, i2, i3;
input s1, s0;
reg out;
always @(s1 or s0 or i0 or i1 or i2 or i3)
case ({s1, s0}) //Switch based on concatenation of control signals
2'd0 : out = i0;
2'd1 : out = i1;
2'd2 : out = i2;
2'd3 : out = i3;
default: $display("Invalid control signals");
endcase
endmodule
Casex, Casez Keywords

• There are two variations of the case statement. They are


denoted by keywords, casex and casez.
• casez treats all z values in the case alternatives or the case
expression as don't cares.
• All bit positions with z can also represented by ? in that
position.
• casex treats all x and z values in the case item or the case
expression as don't cares.
reg [3:0] encoding;
integer state;
casex (encoding) //logic value x represents a don't care bit.
4'b1xxx : next_state = 3;
4'bx1xx : next_state = 2;
4'bxx1x : next_state = 1;
4'bxxx1 : next_state = 0;
default : next_state = 0;
endcase
• Thus, an input encoding = 4'b10xz would cause next_state = 3
to be executed.
Loops
• There are four types of looping statements in Verilog: while,
for, repeat, and forever.
• The syntax of these loops is very similar to the syntax of loops
in the C programming language.
• All looping statements can appear only inside an initial or
always block.
• Loops may contain delay expressions.
While Loop
• The keyword while is used to specify this loop. The while
loop executes until the while expression is not true.
• If the loop is entered when the while expression is not true, the
loop is not execute at all.
• Each expression can contain the operators
• Any logical expression can be specified with these operators.
• If multiples statements are to be executed in the loop, they
must be grouped typically using keywords begin and end
//Illustration 1: Increment count from 0 to 127. Exit at count
128.
//Display the count variable.
integer count;
initial
begin
count = 0;
while (count < 128) //Execute loop till count is 127.
//exit at count 128
begin
$display("Count = %d", count);
count = count + 1;
end
end
For Loop
• The keyword for is used to specify this loop. The for loop
contains three parts:
1. An initial condition
2. A check to see if the terminating condition is true
3. A procedural assignment to change value of the control
variable
• The initialization condition and the incrementing procedural
assignment are included in the for loop and do not need to be
specified separately.
• Thus, the for loop provides a more compact loop structure
than the while loop.
Syntax

integer count;
initial
for ( count=0; count < 128; count = count + 1)
$display("Count = %d", count);
Repeat Loop
• The keyword repeat is used for this loop. The repeat construct
executes the loop a fixed number of times.
• A repeat construct cannot be used to loop on a general logical
expression.
• A while loop is used for that purpose.
• A repeat construct must contain a number, which can be a
constant, a variable or a signal value.
• However, if the number is a variable or signal value, it is
evaluated only when the loop starts and not during the loop
execution.
//Illustration 1: increment and display count from 0 to 127
• integer count;
• initial
• begin
• count = 0;
• repeat(128)
• begin
• $display("Count = %d", count);
• count = count + 1;
• end
• end
//Illustration 2: Data buffer module example
• //After it receives a data_start signal.
• //Reads data for the next 8 cycles.

It shows how to model a data buffer that latches data at the positive edge of
the clock for the next eight cycles after it receives a data start signal.
module data_buffer(data_start, data, clock);

parameter cycles = 8;
input data_start;
input [15:0] data;
input clock;

reg [15:0] buffer [0:7];


integer i;

always @(posedge clock)


begin
if(data_start) //data start signal is true
begin
i = 0;
repeat(cycles) //Store data at the posedge of next 8 clock
//cycles
begin
@(posedge clock) buffer[i] = data; //waits till next
// posedge to latch data
i = i + 1;
end
end
end
endmodule
Forever loop
• The keyword forever is used to express this loop.
• The loop does not contain any expression and executes forever
until the $finish task is encountered.
• The loop is equivalent to a while loop with an expression that
always evaluates to true, e.g., while (1).
• A forever loop can be exited by use of the disable statement.
• A forever loop is typically used in conjunction with timing
control constructs.
• If timing control constructs are not used, the Verilog simulator
would execute this statement
//Clock generation
//Use forever loop instead of always block
reg clock;

initial
begin
clock = 1'b0;
forever #10 clock = ~clock; //Clock with period of 20 units
end
Blocks
• Block statements are used to group multiple statements to act together as
one.
• In previous examples, we used keywords begin and end to group multiple
statements. Thus, we used sequential blocks where the statements in the
block execute one after another.

In this section, we discuss the block types:


• sequential blocks
• parallel blocks

Three special features of blocks


• Named blocks
• Disabling named blocks
• Nested blocks.
Sequential blocks

The keywords begin and end are used to group statements into
sequential blocks.
Sequential blocks have the following characteristics:
• The statements in a sequential block are processed in the order
they are specified.
• A statement is executed only after its preceding statement
completes execution (except for nonblocking assignments with
intra-assignment timing control).
• If delay or event control is specified, it is relative to the
simulation time when the previous statement in the block
completed execution
Examples of Sequential Blocks
Sequential block without delay Sequential blocks with delay.
reg x, y; reg x, y;
reg [1:0] z, w; reg [1:0] z, w;
initial initial
begin begin
x = 1'b0; x = 1'b0; //completes at sim. time 0
y = 1'b1; #5 y = 1'b1; //completes at sim. time 5
z = {x, y}; #10 z = {x, y}; //completes at sim.
time 15
w = {y, x};
#20 w = {y, x}; //completes at sim.
end time 35

end
Parallel blocks

Parallel blocks are specified by keywords: fork and join.


Parallel blocks have the following characteristics:
• Statements in a parallel block are executed concurrently.
• Ordering of statements is controlled by the delay or event
control assigned to each statement.
• All statements in a parallel block start at the time when the
block was entered. Thus, the order in which the statements are
written in the block is unimportant.
Example of parallel block

//Example 1: Parallel blocks with delay.


reg x, y;
reg [1:0] z, w;

initial
fork
x = 1'b0; //completes at simulation time 0
#5 y = 1'b1; //completes at simulation time 5
#10 z = {x, y}; //completes at simulation time 10
#20 w = {y, x}; //completes at simulation time 20
join
Parallel blocks with deliberate race condition
If two statements that affect the same variable complete at the
same time in parallel blocks then implicit race conditions
might arise as shown in the example
//Parallel blocks with deliberate race condition
reg x, y;
reg [1:0] z, w;
initial
fork
x = 1'b0;
y = 1'b1;
z = {x, y};
w = {y, x};
join
All statements start at simulation time 0. The order in which the
statements will execute is not known. So two cases are possible.

Case 1:
Variables z and w will get values 1 and 2 if x = 1'b0 and y = 1'b1
execute first.

Case 2:
Variables z and w will get values 2'bxx and 2'bxx if x = 1'b0 and
y = 1'b1 execute last.

Thus, the result of z and w is nondeterministic and dependent on


the simulator implementation. In simulation time, all statements
in the fork-join block are executed at once. However, in reality,
CPUs running simulations can execute only one statement at a
time.
Special Features of Blocks - Nested blocks
Blocks can be nested. Sequential and parallel blocks can be
mixed.
//Nested blocks
initial
begin
x = 1'b0;
fork
#5 y = 1'b1;
#10 z = {x, y};
join
#20 w = {y, x};
end
Named blocks

Blocks can be given names.


• Local variables can be declared for the named block. Named
blocks are a part of the design hierarchy.
• Variables in a named block can be accessed by using
hierarchical name referencing.
• Named blocks can be disabled, i.e., their execution can be
stopped.
Named block example

//Named blocks initial


module top; fork: block2 //parallel block
initial named block2
begin: block1 //sequential reg i; // register i is static and
block named block1 local to block2
integer i; //integer i is static // can be accessed
and local to block1 by hierarchical name,
// can be accessed by top.block2.i
hierarchical name, ...
top.block1.i ...
... join
end
Disabling named blocks

• The keyword disable provides a way to terminate the execution of


a named block.
• Disable can be used to get out of loops, handle error conditions, or
control execution of pieces of code, based on a control signal.
• Disabling a block causes the execution control to be passed to the
statement immediately succeeding the block.
Example of disabling named blocks

• //Illustration: Find the first bit with a value 1 in flag (vector


• //variable)
• reg [15:0] flag;
• integer i; //integer to keep count
initial
begin
flag = 16'b 0010_0000_0000_0000;
i = 0;
begin: block1 //The main block inside while is named block1
while(i < 16)
begin
if (flag[i])
begin
$display("Encountered a TRUE bit at element number %d", i);
disable block1; //disable block1 because you found true bit.
end
i = i + 1;
end
end
end
Generate Blocks
• Generate statements allow Verilog code to be generated
dynamically at elaboration time before the simulation begins.
This facilitates the creation of parametrized models.
• Generate statements are particularly convenient when the
same operation or module instance is repeated for multiple bits
of a vector, or when certain Verilog code is conditionally
included based on parameter definitions.
• Generate statements allow control over the declaration of
variables, functions, and tasks, as well as control over
instantiations.
• All generate instantiations are coded with a module scope and
require the keywords generate - endgenerate.
Generate Loop
A generate loop permits one or more of the following to be
instantiated multiple times using a for loop:

• Variable declarations
• Modules
• User defined primitives, Gate primitives
• Continuous assignments
• initial and always blocks
Bit-wise xor of Two N-bit Buses
// This module generates a bit-wise xor of two N-bit buses
module bitwise_xor (out, i0, i1);
// Parameter Declaration. This can be redefined
parameter N = 32; // 32-bit bus by default
output [N-1:0] out; // Port declarations
input [N-1:0] i0, i1;
// Declare a temporary loop variable. This variable is used only
in //the evaluation of generate blocks. This variable does not
exist //during the simulation of a Verilog design genvar j;
generate for (j=0; j<N; j=j+1) begin: xor_loop //Generate the bit-
//wise xor with a single loop
xor g1 (out[j], i0[j], i1[j]);
end //end of the for loop inside the generate block
endgenerate //end of the generate block
// As an alternate style,
// the xor gates could be replaced by always blocks.
// reg [N-1:0] out;
//generate for (j=0; j<N; j=j+1) begin: bit
// always @(i0[j] or i1[j]) out[j] = i0[j] ^ i1[j];
//end
//endgenerate
endmodule

Some interesting observations for above Example are listed below.


• Prior to the beginning of the simulation, the simulator elaborates
(unrolls) the code in the generate blocks to create a flat
representation without the generate blocks. The unrolled code is
then simulated. Thus, generate blocks are simply a convenient way
of replacing multiple repetitive Verilog statements with a single
statement inside a loop.
• Genvar is a keyword used to declare variables that are used only
in the evaluation of generate block. Genvars do not exist during
simulation of the design.

• The value of a genvar can be defined only by a generate loop.

• Generate loops can be nested. However, two generate loops


using the same genvar as an index variable cannot be nested.

• The name xor_loop assigned to the generate loop is used for


hierarchical name referencing of the variables inside the
generate loop. Therefore, the relative hierarchical names of the
xor gates will be xor_loop[0].g1,
xor_loop[1].g1, .......,xor_loop[31].g1.
Generate Conditional

A generate conditional is like an if-else-if generate construct that


permits the following Verilog constructs to be conditionally
instantiated into another module based on an expression that is
deterministic at the time the design is elaborated:

• Modules
• User defined primitives, Gate primitives
• Continuous assignments
• initial and always blocks
Generate Case

A generate case permits the following Verilog constructs to be


conditionally instantiated into another module based on a select-
one-of-many case construct that is deterministic at the time the
design is elaborated:

• Modules
• User defined primitives, Gate primitives
• Continuous assignments
• initial and always blocks
• Example 7-32 Generated Ripple Adder
• // This module generates a gate level ripple adder
• module ripple_adder(co, sum, a0, a1, ci);
• // Parameter Declaration. This can be redefined
• parameter N = 4; // 4-bit bus by default
• // Port declarations
• output [N-1:0] sum;
• output co;
• input [N-1:0] a0, a1;
• input ci;
• //Local wire declaration
• wire [N-1:0] carry;
• //Assign 0th bit of carry equal to carry input
• assign carry[0] = ci;
• // Declare a temporary loop variable. This variable is used only
• // in the evaluation of generate blocks. This variable does not
• // exist during the simulation of a Verilog design because the
• // generate loops are unrolled before simulation.
• genvar i;
• //Generate the bit-wise Xor with a single loop
• generate for (i=0; i<N; i=i+1) begin: r_loop
• wire t1, t2, t3;
• xor g1 (t1, a0[i], a1[i]);
• xor g2 (sum[i], t1, carry[i]);
• and g3 (t2, a0[i], a1[i]);
• and g4 (t3, t1, carry[i]);
• or g5 (carry[i+1], t2, t3);
• end //end of the for loop inside the generate block
• endgenerate //end of the generate block
• // For the above generate loop, the following relative
hierarchical
• // instance names are generated
• // xor : r_loop[0].g1, r_loop[1].g1, r_loop[2].g1,
r_loop[3].g1
• r_loop[0].g2, r_loop[1].g2, r_loop[2].g2, r_loop[3].g2
• // and : r_loop[0].g3, r_loop[1].g3, r_loop[2].g3,
r_loop[3].g3
• r_loop[0].g4, r_loop[1].g4, r_loop[2].g4, r_loop[3].g4
• // or : r_loop[0].g5, r_loop[1].g5, r_loop[2].g5,
r_loop[3].g5
• // Generated instances are connected with the following
• // generated nets
• // Nets: r_loop[0].t1, r_loop[0].t2, r_loop[0].t3
• // r_loop[1].t1, r_loop[1].t2, r_loop[1].t3
• // r_loop[2].t1, r_loop[2].t2, r_loop[2].t3
• // r_loop[3].t1, r_loop[3].t2, r_loop[3].t3
• assign co = carry[N];
• endmodule

You might also like