Verilog Structured procedures

All procedures in the Verilog HDL are specified within one of the following four statements:
— initial construct
— always construct
— Task
— Function
The initial and always constructs are enabled at the beginning of a simulation. The initial construct shall
execute only once, and its activity shall cease when the statement has finished. In contrast, the always
construct shall execute repeatedly. Its activity shall cease only when the simulation is terminated. There
shall be no implied order of execution between initial and always constructs. The initial constructs need not be scheduled and executed before the always constructs. There shall be no limit to the number of initial and always constructs that can be defined in a module.
Tasks and functions are procedures that are enabled from one or more places in other procedures. Tasks and functions are described in (<add link>).

Initial construct:

The following example illustrates use of the initial construct for initialization of variables at the start of
simulation-

initial begin
      areg = 0; // initialize a reg
      for (index = 0; index < size; index = index + 1)
          memory[index] = 0; //initialize memory word
end

Another typical usage of the initial construct is specification of waveform descriptions that execute once to provide stimulus to the main part of the circuit being simulated.

initial begin
      inputs = 'b000000; // initialize at time zero
      #10 inputs = 'b011001; // first pattern
      #10 inputs = 'b011011; // second pattern
      #10 inputs = 'b011000; // third pattern
      #10 inputs = 'b001000; // last pattern
end

Always construct:

The always construct, because of its looping nature, is only useful when used in conjunction with some form of timing control. If an always construct has no control for simulation time to advance, it will create a
simulation deadlock condition.
The following code, for example, creates a zero-delay infinite loop:
always areg = ~areg;
Providing a timing control to the above code creates a potentially useful description as shown in the
following:
always #half_period areg = ~areg;

<< Previous | Next >>

Verilog Block statements

The block statements are a means of grouping statements together so that they act syntactically like a single statement. There are two types of blocks in the Verilog HDL:
— Sequential block, also called begin-end block
— Parallel block, also called fork-join block
The sequential block shall be delimited by the keywords begin and end. The procedural statements in
sequential block shall be executed sequentially in the given order.
The parallel block shall be delimited by the keywords fork and join. The procedural statements in parallel
block shall be executed concurrently.

1). Sequential blocks:

A sequential block shall have the following characteristics:
— Statements shall be executed in sequence, one after another.
— Delay values for each statement shall be treated relative to the simulation time of the execution of
the previous statement.
— Control shall pass out of the block after the last statement executes.
For example: —A sequential block enables the following two assignments to have a deterministic result:

begin
areg = breg;
creg = areg; // creg stores the value of breg
end

The first assignment is performed, and areg is updated before control passes to the second assignment.

2). Parallel blocks:

A parallel block shall have the following characteristics:
— Statements shall execute concurrently.
— Delay values for each statement shall be considered relative to the simulation time of entering the
block.
— Delay control can be used to provide time-ordering for assignments.
— Control shall pass out of the block when the last time-ordered statement executes.

The following example codes show parallel –

fork
#50 r = 'h35;
#100 r = 'hE2;
#150 r = 'h00;
#200 r = 'hF7;
#250 -> end_wave;
join

3). Block names:

Both sequential and parallel blocks can be named by adding : name_of_block after the keywords begin
or fork. The naming of blocks serves several purposes:

— It allows local variables, parameters, and named events to be declared for the block.
— It allows the block to be referenced in statements such as the disable statement

<< Previous | Next >>

Procedural timing controls

The Verilog HDL has two types of explicit timing control over when procedural statements can occur. The
first type is a delay control, in which an expression specifies the time duration between initially encountering the statement and when the statement actually executes. The delay expression can be a
dynamic function of the state of the circuit, but it can be a simple number that separates statement executions in time. The delay control is an important feature when specifying stimulus waveform descriptions.

The second type of timing control is the event expression, which allows statement execution to be delayed until the occurrence of some simulation event occurring in a procedure executing concurrently with this procedure. A simulation event can be a change of value on a net or variable (an implicit event) or the occurrence of an explicitly named event that is triggered from other procedures (an explicit event). Most often, an event control is a positive or negative edge on a clock signal.
The procedural statements encountered so far all execute without advancing simulation time. Simulation
time can advance by one of the following three methods:

— A delay control, which is introduced by the symbol #
— An event control, which is introduced by the symbol @
— The wait statement, which operates like a combination of the event control and the while loop

1). Delay control:

A procedural statement following the delay control shall be delayed in its execution with respect to the
procedural statement preceding the delay control by the specified delay. If the delay expression evaluates to an unknown or high-impedance value, it shall be interpreted as zero delay. If the delay expression evaluates to a negative value, it shall be interpreted as a twos-complement unsigned integer of the same size as a time variable. Specify parameters are permitted in the delay expression. They can be overridden by SDF annotation, in which case the expression is reevaluated.

For example —The next three examples provide an expression following the number sign (#). Execution of the assignment is delayed by the amount of simulation time specified by the value of the expression.

#d rega = regb; // d is defined as a parameter
#((d+e)/2) rega = regb; // delay is average of d and e
#regr regr = regr + 1; // delay is the value in regr

2). Event control:

The execution of a procedural statement can be synchronized with a value change on a net or variable or the occurrence of a declared event. The value changes on nets and variable can be used as events to trigger the execution of a statement. This is known as detecting an implicit event. The event can also be based on the direction of the change, that is, toward the value 1 (posedge) or toward the value 0 (negedge).

— A negedge shall be detected on the transition from 1 to x, z, or 0, and from x or z to 0
— A posedge shall be detected on the transition from 0 to x, z, or 1, and from x or z to 1
Below table shows detecting posedge & negedge-

The following example shows illustrations of edge-controlled statements:

@r rega = regb; // controlled by any value change in the reg r
@(posedge clock) rega = regb; // controlled by posedge on clock
@(negedge clock) rega = regb; // controlled by negative edge

3). Named events:

A new data type, in addition to nets and variables, called event can be declared. An identifier declared as an event data type is called a named event. A named event can be triggered explicitly. It can be used in an event expression to control the execution of procedural statements in the same manner as event controls.

An event shall not hold any data. The following are the characteristics of a named event:
— It can be made to occur at any particular time.
— It has no time duration.
— Its occurrence can be recognized by using the event control

An event-controlled statement (for example, @trig rega = regb;) shall cause simulation of its
containing procedure to wait until some other procedure executes the appropriate event-triggering statement (for example, -> trig).

4). Level-sensitive event control:

The execution of a procedural statement can also be delayed until a condition becomes true. This is
accomplished using the wait statement, which is a special form of event control. The nature of the wait
statement is level-sensitive, as opposed to basic event control (specified by the @ character), which is edge sensitive.
The wait statement shall evaluate a condition; and, if it is false, the procedural statements following the wait statement shall remain blocked until that condition becomes true before continuing.
The following example shows the use of the wait statement to accomplish level-sensitive event control:

begin
     wait (!enable) #10 a = b;
     #10 c = d;
end

If the value of enable is 1 when the block is entered, the wait statement will delay the evaluation of the next statement (#10 a = b;) until the value of enable changes to 0. If enable is already 0 when the begin end block is entered, then the assignment “a = b;” is evaluated after a delay of 10 and no additional delay
occurs.

<< Previous | Next >>

Verilog Looping statements

There are four types of looping statements. These statements provide a means of controlling the execution of a statement zero, one, or more times.

forever Continuously executes a statement.
repeat Executes a statement a fixed number of times. If the expression evaluates to unknown or
high impedance, it shall be treated as zero, and no statement shall be executed.
while Executes a statement until an expression becomes false. If the expression starts out false,
the statement shall not be executed at all.
for Controls execution of its associated statement(s) by a three-step process, as follows:
a) Executes an assignment normally used to initialize a variable that controls the number
of loops executed.
b) Evaluates an expression. If the result is zero, the for loop shall exit. If it is not zero,
the for loop shall execute its associated statement(s) and then perform step c). If the
expression evaluates to an unknown or high-impedance value, it shall be treated as
zero.
c) Executes an assignment normally used to modify the value of the loop-control variable,
then repeats step b).

forever statement
| repeat ( expression ) statement
| while ( expression ) statement
| for ( variable_assignment ; expression ; variable_assignment ) statement

Example 1Repeat statement: In the following example of a repeat loop, add and shift operators implement a multiplier:

parameter size = 8, longsize = 16;
reg [size:1] opa, opb;
reg [longsize:1] result;
begin : mult
      reg [longsize:1] shift_opa, shift_opb;
      shift_opa = opa;
      shift_opb = opb;
      result = 0;
      repeat (size) begin
      if (shift_opb[1])
         result = result + shift_opa;
         shift_opa = shift_opa << 1; shift_opb = shift_opb >> 1;
      end
end

Example 2While statement: The following example counts the number of logic 1 values in rega:

begin : count1s
     reg [7:0] tempreg;
     count = 0;
     tempreg = rega;
     while (tempreg) begin
     if (tempreg[0])
        count = count + 1;
        tempreg = tempreg >> 1;
    end
end

<< Previous | Next >>

Verilog Case statement

The case statement is a multiway decision statement that tests whether an expression matches one of a
number of other expressions and branches accordingly. The case statement has the syntax shown in below-

case ( expression )
case_item { case_item } endcase
| casez ( expression )
case_item { case_item } endcase
| casex ( expression )
case_item { case_item } endcase

The case expression and the case item expression can be computed at run time; neither expression is
required to be a constant expression.
For Example 1:
The following example illustrates the use of a case statement to handle x and z values properly:

case (select[1:2])
2’b00: result = 0;
2’b01: result = flaga;
2’b0x,
2’b0z: result = flaga ? ‘bx : 0;
2’b10: result = flagb;
2’bx0,
2’bz0: result = flagb ? ‘bx : 0;
default result = ‘bx;
endcase

In above example, if select[1] is 0 and flaga is 0, then even if the value of select[2] is x or z, result should be 0—which is resolved by the third case.
The following example shows another way to use a case statement to detect x and z values.

case (sig)
1'bz: $display("signal is floating");
1'bx: $display("signal is unknown");
default: $display("signal is %b", sig);
endcase

Case statement with do-not-cares:

Two other types of case statements are provided to allow handling of do-not-care conditions in the case
comparisons. One of these treats high-impedance values (z) as do-not-cares, and the other treats both
high-impedance and unknown (x) values as do-not-cares.
These case statements can be used in the same way as the traditional case statement, but they begin with
keywords casez and casex, respectively.
Do-not-care values (z values for casez, z and x values for casex) in any bit of either the case expression or
the case items shall be treated as do-not-care conditions during the comparison, and that bit position shall not be considered. The do-not-care conditions in case expression can be used to control dynamically which bits should be compared at any time.

For Example —The following is an example of the casez statement. It demonstrates an instruction decode, where values of the most significant bits select which task should be called. If the most significant bit of reg_sel is a 1, then the task instruction1 is called, regardless of the values of the other bits of reg_sel.

reg [7:0] reg_sel;
casez (reg_sel)
    8'b1???????: instruction1(reg_sel);
    8'b01??????: instruction2(reg_sel);
    8'b00010???: instruction3(reg_sel);
    8'b000001??: instruction4(reg_sel);
endcase

<< Previous | Next >>

Verilog Conditional statement

The conditional statement (or if-else statement) is used to make a decision about whether a statement is
executed. Formally, the syntax is below

if ( expression ) statement_or_null
{ else if ( expression ) statement_or_null }
[ else statement_or_null ]

If the expression evaluates to true (that is, has a nonzero known value), the first statement shall be executed. If it evaluates to false (that is, has a zero value or the value is x or z), the first statement shall not execute. If there is an else statement and expression is false, the else statement shall be executed.

This sequence of if statements (known as an if-else-if construct) is the most general way of writing a
multiway decision. The expressions shall be evaluated in order. If any expression is true, the statement
associated with it shall be executed, and this shall terminate the whole chain. Each statement is either a
single statement or a block of statements.
The last else part of the if-else-if construct handles the none-of-the-above or default case where none of the other conditions were satisfied. Sometimes there is no explicit action for the default. In that case, the trailing else statement can be omitted, or it can be used for error checking to catch an impossible condition.

For example:
The following module fragment uses the if-else statement to test the variable index to decide whether one of three modify_segn regs has to be added to the memory address and which increment is to be added to the index reg. The first ten lines declare the regs and parameters.

// declare regs and parameters
reg [31:0] instruction, segment_area[255:0];
reg [7:0] index;
reg [5:0] modify_seg1,
modify_seg2,
modify_seg3;
parameter
segment1 = 0, inc_seg1 = 1,
segment2 = 20, inc_seg2 = 2,
segment3 = 64, inc_seg3 = 4,
data = 128;
// test the index variable
if (index < segment2) begin
instruction = segment_area [index + modify_seg1];
index = index + inc_seg1;
end
else if (index < segment3) begin
instruction = segment_area [index + modify_seg2];
index = index + inc_seg2;
end
else if (index < data) begin
instruction = segment_area [index + modify_seg3];
index = index + inc_seg3;
end
else
instruction = segment_area [index];

<< Previous | Next >>

Verilog nonblocking procedural assignment

The nonblocking procedural assignment allows assignment scheduling without blocking the procedural
flow. The nonblocking procedural assignment statement can be used whenever several variable assignments within the same time step can be made without regard to order or dependence upon each other.

The nonblocking assignment operator is the same operator as the less-than-or-equal-to relational operator. The interpretation shall be decided from the context in which <= appears. When <= is used in an expression, it shall be interpreted as a relational operator; and when it is used in a nonblocking procedural assignment, it shall be interpreted as an assignment operator.

The nonblocking procedural assignments shall be evaluated in two steps as discussed in Scheduling semantics(<add link>). These
two steps are shown in the following example:

Example 1:
module evaluates2 (out);
output out;
reg a, b, c;
initial begin
    a = 0;
    b = 1;
    c = 0;
end
always c = #5 ~c;
always @(posedge c) begin
    a <= b; // evaluates, schedules,
    b <= a; // and executes in two steps
end
endmodule

Below are steps to execute above example:
1) .At posedge c, the simulator evaluates the right-hand sides of the nonblocking assignments and schedules the assignments of the new values at the end of the nonblocking assign update events.
2). When the simulator activates the nonblocking assign update events, the simulator updates the left-hand side of each nonblocking assignment statement.

Example 2
//non_block1.v
module non_block1;
reg a, b, c, d, e, f;
//blocking assignments
initial begin
    a = #10 1; // a will be assigned 1 at time 10
    b = #2 0; // b will be assigned 0 at time 12
    c = #4 1; // c will be assigned 1 at time 16
end
//non-blocking assignments
initial begin
    d <= #10 1; // d will be assigned 1 at time 10
    e <= #2 0; // e will be assigned 0 at time 2
    f <= #4 1; // f will be assigned 1 at time 4
end
endmodule

<< Previous | Next >>

Verilog Blocking procedural assignments

A blocking procedural assignment statement shall be executed before the execution of the statements that follow it in a sequential block (<add link>). A blocking procedural assignment statement shall not prevent the execution of statements that follow it in a parallel block(<add link>).
The = assignment operator used by blocking procedural assignments is also used by procedural continuous assignments and continuous assignments.

For example:
The following examples show blocking procedural assignments:

rega = 0;
rega[3] = 1; // a bit-select
rega[3:5] = 7; // a part-select
mema[address] = 8'hff; // assignment to a mem element
{carry, acc} = rega + regb; // a concatenation

<< Previous | Next >>

Verilog Procedural continuous assignments

The procedural continuous assignments (using keywords assign and force) are procedural statements that allow expressions to be driven continuously onto variables or nets.
The left-hand side of the assignment in the assign statement shall be a variable reference or a concatenation of variables. It shall not be a memory word (array reference) or a bit-select or a part-select of a variable.
In contrast, the left-hand side of the assignment in the force statement can be a variable reference or a net reference. It can be a concatenation of any of the above. Bit-selects and part-selects of vector variables are not allowed.

The assign and deassign procedural statements:

The assign procedural continuous assignment statement shall override all procedural assignments to a
variable. The deassign procedural statement shall end a procedural continuous assignment to a variable. The value of the variable shall remain the same until the variable is assigned a new value through a procedural assignment or a procedural continuous assignment. The assign and deassign procedural statements allow, for example, modeling of asynchronous clear/preset on a D-type edge-triggered flip-flop, where the clock is inhibited when the clear or preset is active.
If the keyword assign is applied to a variable for which there is already a procedural continuous assignment, then this new procedural continuous assignment shall deassign the variable before making the new procedural continuous assignment.

For example:
The following example shows a use of the assign and deassign procedural statements in a behavioral
description of a D-type flip-flop with preset and clear inputs:

module dff (q, d, clear, preset, clock);
output q;
input d, clear, preset, clock;
reg q;
always @(clear or preset)
    if (!clear)
        assign q = 0;
    else if (!preset)
        assign q = 1;
    else
        deassign q;
always @(posedge clock)
    q = d;
endmodule

If either clear or preset is low, then the output q will be held continuously to the appropriate constant
value, and a positive edge on the clock will not affect q. When both the clear and preset are high, then
q is deassigned.

The force and release procedural statements:

Another form of procedural continuous assignment is provided by the force and release procedural
statements. These statements have a similar effect to the assign-deassign pair, but a force can be applied to nets as well as to variables. The left-hand side of the assignment can be a variable, a net, a constant bit-select of a vector net, a part-select of a vector net, or a concatenation. It cannot be a memory word (array reference) or a bit-select or a part-select of a vector variable.

A force procedural statement on a net shall override all drivers of the net—gate outputs, module outputs, and continuous assignments—until a release procedural statement is executed on the net. When released, the net shall immediately be assigned the value determined by the drivers of the net.

For example:

module test;
reg a, b, c, d;
wire e;
and and1 (e, a, b, c);
initial begin
    $monitor("%d d=%b,e=%b", $stime, d, e);
    assign d = a & b & c;
    a = 1;
    b = 0;
    c = 1;
   #10;
   force d = (a | b | c);
   force e = (a | b | c);
   #10;
   release d;
   release e;
   #10 $finish;
end
endmodule

In this example, an and gate instance and1 is “patched” to act like an or gate by a force procedural
statement that forces its output to the value of its ORed inputs, and an assign procedural statement of
ANDed values is “patched” to act like an assign statement of ORed values.
The right-hand side of a procedural continuous assignment or a force statement can be an expression. This shall be treated just as a continuous assignment; that is, if any variable on the right-hand side of the
assignment changes, the assignment shall be reevaluated while the assign or force is in effect.

<< Previous | Next >>

Verilog Behavioral modeling

Verilog behavioral models contain procedural statements that control the simulation and manipulate
variables of the data types previously described. These statements are contained within procedures. Each
procedure has an activity flow associated with it.
The activity starts at the control constructs initial and always. Each initial construct and each always
construct starts a separate activity flow. All of the activity flows are concurrent to model the inherent
concurrence of hardware.

The following example shows a complete Verilog behavioral model-

module behave;
reg [1:0] a, b;
initial begin
    a = 'b1;
    b = 'b0;
end
always begin
    #50 a = ~a;
end
always begin
    #100 b = ~b;
end
endmodule

During simulation of this model, all of the flows defined by the initial and always constructs start together at simulation time zero. The initial constructs execute once, and the always constructs execute repetitively.
In this model, the reg variables a and b initialize to 1 and 0, respectively, at simulation time zero. The initial construct is then complete and does not execute again during this simulation run. This initial construct contains a begin-end block (also called a sequential block) of statements. In this begin-end block, a is initialized first, followed by b.
The always constructs also start at time zero, but the values of the variables do not change until the times
specified by the delay controls (introduced by #) have elapsed. Thus, reg a inverts after 50 time units and
reg b inverts after 100 time units. Because the always constructs repeat, this model will produce two square waves. The reg a toggles with a period of 100 time units, and reg b toggles with a period of 200 time units.
The two always constructs proceed concurrently throughout the entire simulation run.

Procedural assignments:
Procedural assignments are used for updating reg, integer, time, real, realtime,
and memory data types. There is a significant difference between procedural assignments and continuous assignments:

Continuous assignments drive nets and are evaluated and updated whenever an input operand
changes value.
Procedural assignments update the value of variables under the control of the procedural flow
constructs that surround them.

The right-hand side of a procedural assignment can be any expression that evaluates to a value. The lefthand side shall be a variable that receives the assignment from the right-hand side. The left-hand side of a procedural assignment can take one of the following forms:
— reg, integer, real, realtime, or time data type: an assignment to the name reference of one of these
data types.
— Bit-select of a reg, integer, or time data type: an assignment to a single bit that leaves the other bits
untouched.
— Part-select of a reg, integer, or time data type: a part-select of one or more contiguous bits that
leaves the rest of the bits untouched.
— Memory word: a single word of a memory.
— Concatenation or nested concatenation of any of the above: a concatenation or nested concatenation
of any of the previous four forms. Such specification effectively partitions the result of the righthand
expression and assigns the partition parts, in order, to the various parts of the concatenation or
nested concatenation.

The Verilog HDL contains two types of procedural assignment statements:
Blocking procedural assignment statements
Nonblocking procedural assignment statements
Blocking and nonblocking procedural assignment statements specify different procedural flows in
sequential blocks.

<< Previous | Next >>