0% found this document useful (0 votes)
44 views26 pages

DDTH Unit2

The document discusses gate level modeling in Verilog. It describes how basic logic gates like AND, OR, NAND, etc. are available as primitives in Verilog and can be instantiated directly. It provides the syntax for instantiating different gate primitives and describes their truth tables. It also discusses modeling more complex circuits using combinations of gate primitives, as well as concepts like arrays of instances and specifying delays.

Uploaded by

sruchakradar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views26 pages

DDTH Unit2

The document discusses gate level modeling in Verilog. It describes how basic logic gates like AND, OR, NAND, etc. are available as primitives in Verilog and can be instantiated directly. It provides the syntax for instantiating different gate primitives and describes their truth tables. It also discusses modeling more complex circuits using combinations of gate primitives, as well as concepts like arrays of instances and specifying delays.

Uploaded by

sruchakradar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Unit-2

Gate Level Modeling

Introduction

Digital designers are normally familiar with all the common logic gates, their symbols, and their
working. Flip-flops are built from the logic gates. All other functionally complex and more
involved circuits can also be built using the basic gates. All the basic gates are available as
“Primitives” in Verilog. Primitives are generalized modules that already exist in Verilog [IEEE].
They can be instantiated directly in other modules.

And Gate Primitive

The AND gate primitive in Verilog is instantiated with the following statement:

and g1 (O, I1, I2, . . ., In);

Here ‘and’ is the keyword signifying an AND gate. g1 is the name assigned to the specific
instantiation. O is the gate output; I1, I2, etc., are the gate inputs. The following are
noteworthy:

• The AND module has only one output. The first port in the argument list is the output
port.
• An AND gate instantiation can take any number of inputs — the upper limit is compiler-
specific.
• A name need not be necessarily assigned to the AND gate instantiation; this is true of all
the gate primitives available in Verilog.

Truth Table of AND Gate Primitive

The truth table for a two-input AND gate is shown in Table below It can be directly extended to
AND gate instantiations with multiple inputs. The following observations are in order here:

Truth table of AND gate primitive

Input 1
0 1 X z
0 0 0 0 0
Input 2 1 0 1 X x
x 0 x X x
z 0 x X x
• If any one of the inputs to the AND gate instantiation is in the 0 state, its output is also
in the 0 state. It is irrespective of whether the other inputs are at the 0, 1, x or z state.

• The output is at 1 state if and only if every one of the inputs is at 1 state.

• For all other cases the output is at the x state.

• Note that the output is never at the z state – the high impedance state. This is true of all
other gate primitives as well.

Module Structure

In a general case a module can be more elaborate. A lot of flexibility is available in the
definition of the body of the module. However, a few rules need to be followed:

• The first statement of a module starts with the keyword module; it may be followed by
the name of the module and the port list if any.

• All the variables in the ports-list are to be identified as inputs, outputs, or inouts. The
corresponding declarations have the form shown below:

ƒ Input a1, a2;


ƒ Output b1, b2;
ƒ Inout c1, c2;

The port-type declarations here follow the module declaration mentioned above.

• The ports and the other variables used within the body of the module are to be
identified as nets or registers with specific types in each case. The respective declaration
statements follow the port-type declaration statements.

Examples:

wire a1, a2, c;


reg b1, b2;

The type declaration must necessarily precede the first use of any variable or signal in the
module.
• The executable body of the module follows the declaration indicated above.

• The last statement in any module definition is the keyword “endmodule”.

• Comments can appear anywhere in the module definition.


Other Gate Primitives

All other basic gates are also available as primitives in Verilog. Details of the facilities and
instantiations in each case are given in Table below. The following points are noteworthy here:

• In all cases of instantiations, one need not necessarily assign a name to the
instantiation. It need be done only when felt necessary – say for clarity of circuit
description.

• In all the cases the output port(s) is (are) declared first and the input port(s) is (are)
declared subsequently.

• The buffer and the inverter have only one input each. They can have any number of
outputs; the upper limit is compiler-specific. All other gates have one output each but
can have any number of inputs; the upper limit is again compiler-specific.

Table for Basic gate primitives in Verilog with details

Gate Mode of instantiation Output port(s) Input port(s)


AND and ga ( o, i1, i2, . . . i8); o i1, i2, . .
OR or gr ( o, i1, i2, . . . i8); o i1, i2, . .
NAND nand gna ( o, i1, i2, . . . i8); o i1, i2, . .
NOR nor gnr ( o, i1, i2, . . . i8); o i1, i2, . .
XOR xor gxr ( o, i1, i2, . . . i8); o i1, i2, . .
XNOR xnor gxn ( o, i1, i2, . . . i8); o i1, i2, . .
BUF buf gb ( o1, o2, …. i); o1, o2, o3, . . i
NOT not gn (o1, o2, o3, . . . i); o1, o2, o3, . . i
Example for a typical A-O-I gate circuit

The commonly used A-O-I gate is shown in Figure 1 for a simple case. The module and the test
bench for the same are given in Figure 2. The circuit has been realized here by instantiating the
AND and NOR gate primitives. The names of signals and gates used in the instantiations in the
module of Figure 2 remain the same as those in the circuit of Figure 1. The module aoi_gate in
the figure has input and output ports since it describes a circuit with signal inputs and an
output. The module aoi_st is a stimulus module. It generates inputs to the aoi_gate module and
gets its output. It has no input or output ports.

/*module for the aoi-gate of figure 1 instantiating the gate primitives – fig 2*/

module aoi_gate(o,a1,a2,b1,b2);

input a1,a2,b1,b2; // a1,a2,b1,b2 form the input //ports of the module

output o; //o is the single output port of the module

wire o1,o2; //o1 and o2 are intermediate signals //within the module

and g1(o1,a1,a2); //The AND gate primitive has two and g2(o2,b1,b2);

// instantiations with assigned //names g1 & g2.

nor g3(o,o1,o2); //The nor gate has one instantiation with assigned name g3.

endmodule

//Test-bench for the aoi_gate above


module aoi_st;
reg a1,a2,b1,b2;

//specific values will be assigned to a1,a2,b1, // and b2 and these connected


//to input ports of the gate insatntiations;
//hence these variables are declared as reg
wire o;
initial
begin
a1 = 0;
a2 = 0;
b1 = 0;
b2 = 0;
#3 a1 = 1;
#3 a2 = 1;
#3 b1 = 1;
#3 b2 = 0;
#3 a1 = 1;
#3 a2 = 0;
#3 b1 = 0;
end
initial #100 $stop;//the simulation ends after //running for 100 tu's.
initial $monitor($time , " o = %b , a1 = %b , a2 = %b , b1 = %b ,b2 = %b ",o,a1,a2,b1,b2);
aoi_gate gg(o,a1,a2,b1,b2);
endmodule

Tri-State Gates

Four types of tri-state buffers are available in Verilog as primitives. Their outputs can be turned
ON or OFF by a control signal. The direct buffer is instantiated as
Bufif1 nn (out, in, control);

The symbol of the buffer is shown in Figure


1. We have
• out as the single output variable
• in as the single input variable and
• control as the single control signal
variable.
When
control = 1,
out = in.

When
control = 0,
out=tri-stated
out is cut off from the input and tri-stated. The output, input and control signals should
appear in the instantiation in the same order as above. Details of bufif1 as well as the other
tri-state type primitives are shown in Table 1.
In all the cases shown in Table 1, out is the output; in is the input, and control, the control
variable.

Array of Instances of Primitives

The primitives available in Verilog can also be instantiated as arrays. A judicious use of such
array instantiations often leads to compact design descriptions. A typical array instantiation
has the form

and gate [7 : 4 ] (a, b, c);

where a, b, and c are to be 4 bit vectors. The above instantiation is equivalent to combining
the following 4 instantiations:

and gate [7] (a[3], b[3], c[3]), gate [6] (a[2], b[2], c[2]), gate [5] (a[1], b[1], c[1]), gate [4]
(a[0], b[0], c[0]);

The assignment of different bits of input vectors to respective gates is implicit in the basic
declaration itself. A more general instantiation of array type has the form

and gate[mm : nn](a, b, c);


where mm and nn can be expressions involving previously defined parameters, integers and
algebra with them. The range for the gate is 1+ (mm-nn); mm and nn do not have
restrictions of sign; either can be larger than the other.

Gate Delays

Until now, we described circuits without any delays (i.e., zero delay). In real circuits, logic
gates have delays associated with them. Gate delays allow the Verilog user to specify delays
through the logic circuits. Pin-to-pin delays can also be specified in Verilog.

Rise, Fall, and Turn-off Delays

There are three types of delays from the inputs to the output of a primitive gate.

Rise delay

The rise delay is associated with a gate output transition to a 1 from another value.

Fall delay

The fall delay is associated with a gate output transition to a 0 from another value.

Turn-off delay

The turn-off delay is associated with a gate output transition to the high impedance
value (z) from another value.

If the value changes to x, the minimum of the three delays is considered.

Three types of delay specifications are allowed. If only one delay is specified, this
value is used for all transitions. If two delays are specified, they refer to the rise and
fall delay values. The turn-off delay is the minimum of the two delays. If all three
delays are specified, they refer to rise, fall, and turn-off delay values. If no delays are
specified, the default value is zero.
Example--Types of Delay Specification

//Delay of delay_time for all transitions


and #(delay_time) a1(out, i1, i2);

// Rise and Fall Delay Specification.

and #(rise_val, fall_val) a2(out, i1, i2);

// Rise, Fall, and Turn-off Delay Specification

bufif0 #(rise_val, fall_val, turnoff_val) b1 (out, in, control);

Examples of delay specification are shown below.

and #(5) a1(out, i1, i2); //Delay of 5 for all transitions and #(4,6) a2(out, i1, i2); // Rise
= 4, Fall = 6

bufif0 #(3,4,5) b1 (out, in, control); // Rise = 3, Fall = 4, Turn-off = 5

Dataflow Modeling

Introduction
For small circuits, the gate-level modeling approach works very well because the
number of gates is limited and the designer can instantiate and connect every gate
individually. Also, gate-level modeling is very intuitive to a designer with a basic
knowledge of digital logic design. However, in complex designs the number of gates is
very large. Thus, designers can design more effectively if they concentrate on
implementing the function at a level of abstraction higher than gate level. Dataflow
modeling provides a powerful way to implement a design. Verilog allows a circuit to
be designed in terms of the data flow between registers and how a design processes
data rather than instantiation of individual gates. Later in this chapter, the benefits of
dataflow modeling will become more apparent.

With gate densities on chips increasing rapidly, dataflow modeling has assumed great
importance. No longer can companies devote engineering resources to handcrafting
entire designs with gates. Currently, automated tools are used to create a gate-level
circuit from a dataflow design description. This process is called logic synthesis.
Dataflow modeling has become a popular design approach as logic synthesis tools
have become sophisticated. This approach allows the designer to concentrate on
optimizing the circuit in terms of data flow. For maximum flexibility in the design
process, designers typically use a Verilog description style that combines the concepts
of gate-level, data flow, and behavioral design. In the digital design community, the
term RTL (Register Transfer Level) design is commonly used for a combination of
dataflow modeling and behavioral modeling.
Continuous Assignments

A continuous assignment is the most basic statement in dataflow modeling, used to


drive a value onto a net. This assignment replaces gates in the description of the
circuit and describes the circuit at a higher level of abstraction. The assignment
statement starts with the keyword assign. The syntax of an assign statement is as
follows.

continuous_assign ::= assign [ drive_strength ] [ delay3 ]


list_of_net_assignments ;

list_of_net_assignments ::= net_assignment { , net_assignment }


net_assignment ::= net_lvalue = expression

Notice that drive strength is optional and can be specified in terms of strength levels
The default value for drive strength is strong1 and strong0. The delay value is also
optional and can be used to specify delay on the assign statement. This is like
specifying delays for gates. Delay specification is discussed in this chapter.
Continuous assignments have the following characteristics:

1. The left hand side of an assignment must always be a scalar or vector net or a
concatenation of scalar and vector nets. It cannot be a scalar or vector register.
2. Continuous assignments are always active. The assignment expression is
evaluated as soon as one of the right-hand-side operands changes and the value is
assigned to the left-hand-side net.
3. The operands on the right-hand side can be registers or nets or function calls.
Registers or nets can be scalars or vectors.
4. Delay values can be specified for assignments in terms of time units. Delay values are
used to control the time when a net is assigned the evaluated value. This feature is
similar to specifying delays for gates. It is very useful in modeling timing behavior in real
circuits.
Examples of Continuous Assignment

Continuous assign. out is a net. i1 and i2 are nets. assign out = i1


& i2;

Continuous assign for vector nets. addr is a 16-bit vector net

addr1 and addr2 are 16-bit vector registers.

assign addr[15:0] = addr1_bits[15:0] ^ addr2_bits[15:0];


Concatenation. Left-hand side is a concatenation of a scalar

net and a vector net.

assign {c_out, sum[3:0]} = a[3:0] + b[3:0] + c_in;

Implicit Continuous Assignment

Instead of declaring a net and then writing a continuous assignment on the net,
Verilog provides a shortcut by which a continuous assignment can be placed on a
net when it is declared. There can be only one implicit declaration assignment per
net because a net is declared only once.

In the example below, an implicit continuous assignment is contrasted with a


regular continuous assignment.

//Regular continuous assignment

wire out;

assign out = in1 & in2;

//Same effect is achieved by an implicit continuous assignment wire out =


in1 & in2;

Implicit Net Declaration

If a signal name is used to the left of the continuous assignment, an implicit net
declaration will be inferred for that signal name. If the net is connected to a module
port, the width of the inferred net is equal to the width of the module port.

wire i1, i2;

assign out = i1 & i2; //Note that out was not declared as a wire

//but an implicit wire declaration for out //is done


by the simulator

Delays

Delay values control the time between the change in a right-hand-side operand and
when the new value is assigned to the left-hand side. Three ways of specifying delays
in continuous assignment statements are regular assignment delay, implicit
continuous assignment delay, and net declaration delay.

Regular Assignment Delay

The first method is to assign a delay value in a continuous assignment statement.


The delay value is specified after the keyword assign. Any change in values of in1 or
in2 will result in a delay of 10 time units before recomputation of the expression in1
& in2, and the result will be assigned to out. If in1 or in2 changes value again before
10 time units when the result propagates to out, the values of in1 and in2 at the
time of recomputation are considered. This property is called inertial delay. An input
pulse that is shorter than the delay of the assignment statement does not propagate
to the output.

assign #10 out = in1 & in2; // Delay in a continuous assign

Figure: Delays

The above waveform is generated by simulating the above assign statement. It


shows the delay on signal out. Note the following change:

When signals in1 and in2 go high at time 20, out goes to a high 10 time units
later (time = 30).

When in1 goes low at 60, out changes to low at 70.

However, in1 changes to high at 80, but it goes down to low before 10 time
units have elapsed.
Hence, at the time of recomputation, 10 units after time 80, in1 is 0. Thus, out gets the
value 0. A pulse of width less than the specified assignment delay is not propagated to
the output.

Implicit Continuous Assignment Delay

An equivalent method is to use an implicit continuous assignment to specify both a


delay and an assignment on the net.

//implicit continuous assignment delay

wire #10 out = in1 & in2;

//same as

wire out;

assign #10 out = in1 & in2;

The declaration above has the same effect as defining a wire out and
declaring a continuous assignment on out.

Net Declaration Delay

A delay can be specified on a net when it is declared without putting a continuous


assignment on the net. If a delay is specified on a net out, then any value change
applied to the net out is delayed accordingly. Net declaration delays can also be used
in gate-level modeling.

//Net Delays

wire # 10 out;

assign out = in1 & in2;

//The above statement has the same effect as the following.

wire out;

assign #10 out = in1 & in2;


Expressions, Operators, and Operands

Dataflow modeling describes the design in terms of expressions instead of


primitive gates. Expressions, operators, and operands form the basis of
dataflow modeling.

Expressions

Expressions are constructs that combine operators and operands to produce a result.

Examples of expressions. Combines operands and operators a ^ b

addr1[20:17] + addr2[20:17] in1 | in2 ;

Operands

Some constructs will take only certain types of operands. Operands can be
constants, integers, real numbers, nets, registers, times, bit-select (one bit of vector
net or a vector register), part-select (selected bits of the vector net or register
vector), and memories or function calls (functions are discussed later).

integer count, final_count;

final_count = count + 1;//count is an integer operand

real a, b, c;

c = a - b; //a and b are real operands

reg [15:0] reg1, reg2;

reg [3:0] reg_out;

reg_out = reg1[3:0] ^ reg2[3:0];//reg1[3:0] and reg2[3:0] are //part-select


register operands

reg ret_value;

ret_value = calculate_parity(A, B);//calculate_parity is a //function


type operand
Operators

Operators act on the operands to produce desired results. Verilog provides various
types of operators.

d1 && d2 // && is an operator on operands d1 and d2 !a[0]


// ! is an operator on operand a[0]

B >> 1 // >> is an operator on operands B and 1

Operator Types

Verilog provides many different operator types. Operators can be arithmetic, logical,
relational, equality, bitwise, reduction, shift, concatenation, or conditional. Some of
these operators are similar to the operators used in the C programming language.
Each operator type is denoted by a symbol. The following table shows the complete
listing of operator symbols classified by category.

Table: Operator Types and Symbols

Operator Type Operator Symbol Operation Performed Number of Operands

* multiply two

/ divide two

+ add two

Arithmetic

- subtract two

% modulus two

** power (exponent) two

! logical negation one

Logical && logical and two

|| logical or two

> greater than two


< less than two

Relational

>= greater than or equal two

<= less than or equal two

== equality two

!= inequality two

Equality

=== case equality two

!== case inequality two

~ bitwise negation one

& bitwise and two

Bitwise | bitwise or two

^ bitwise xor two

^~ or ~^ bitwise xnor two

& reduction and one

~& reduction nand one

| reduction or one

Reduction

~| reduction nor one

^ reduction xor one

^~ or ~^ reduction xnor one


>> Right shift Two

<< Left shift Two

Shift

>>> Arithmetic right shift Two

<<< Arithmetic left shift Two

Concatenation { } Concatenation Any number

Replication {{}} Replication Any number

Conditional ?: Conditional Three

Let us now discuss each operator type in detail.

Arithmetic Operators

There are two types of arithmetic operators: binary and unary.

Binary operators

Binary arithmetic operators are multiply (*), divide (/), add (+), subtract (-), power
(**), and modulus (%). Binary operators take two operands.

A = 4'b0011; B = 4'b0100; // A and B are register vectors D = 6; E =


4; F=2// D and E are integers

A * B // Multiply A and B. Evaluates to 4'b1100

D / E // Divide D by E. Evaluates to 1. Truncates any fractional part. A + B // Add A


and B. Evaluates to 4'b0111
B - A // Subtract A from B. Evaluates to 4'b0001 F = E **
F; //E to the power F, yields 16

If any operand bit has a value x, then the result of the entire expression is x. This
seems intuitive because if an operand value is not known precisely, the result
should be an unknown.

in1 = 4'b101x;

in2 = 4'b1010;

sum = in1 + in2; // sum will be evaluated to the value 4'bx

Modulus operators produce the remainder from the division of two numbers.
They operate similarly to the modulus operator in the C programming
language.

13 % 3 // Evaluates to 1

16 % 4 // Evaluates to 0

-7 % 2 // Evaluates to -1, takes sign of the first operand

7 % -2 // Evaluates to +1, takes sign of the first operand

Unary operators

The operators + and - can also work as unary operators. They are used to specify
the positive or negative sign of the operand. Unary + or ? operators have higher
precedence than the binary + or ? operators.

-4 // Negative 4

+5 // Positive 5

Negative numbers are represented as 2's complement internally in Verilog. It is


advisable to use negative numbers only of the type integer or real in expressions.
Designers should avoid negative numbers of the type <sss> '<base> <nnn> in
expressions because they are converted to unsigned 2's complement numbers and
hence yield unexpected results.
//Advisable to use integer or real numbers -10 /
5// Evaluates to -2

//Do not use numbers of type <sss> '<base> <nnn>

-'d10 / 5// Is equivalent (2's complement of 10)/5 = (232 - 10)/5

where 32 is the default machine word width.

This evaluates to an incorrect and unexpected result

Logical Operators

Logical operators are logical-and (&&), logical-or (||) and logical- not (!). Operators
&& and || are binary operators. Operator ! is a unary operator. Logical operators
follow these conditions:

Logical operators always evaluate to a 1-bit value, 0 (false), 1 (true), or x


ambiguous).If an operand is not equal to zero, it is equivalent to a logical 1 (true
condition). If it is 01equal to zero, it is equivalent to a logical 0 (false condition).
If any operand bit is x or z, it is equivalent to x (ambiguous condition) and is
normally treated by simulators as a false condition.Logical operators take
variables or expressions as operands.Use of parentheses to group logical
operations is highly recommended to improve readability. Also, the user does
not have to remember the precedence of operators.

Logical operations A = 3;
B = 0;

A && B // Evaluates to 0. Equivalent to (logical-1 && logical-0) A || B //


Evaluates to 1. Equivalent to (logical-1 || logical-0) !A// Evaluates to 0.
Equivalent to not(logical-1)

!B// Evaluates to 1. Equivalent to not(logical-0)

Unknowns

A = 2'b0x; B = 2'b10;

A && B // Evaluates to x. Equivalent to (x && logical 1)


// Expressions

(a == 2) && (b == 3) // Evaluates to 1 if both a == 2 and b == 3 are true.

// Evaluates to 0 if either is false.

Relational Operators

Relational operators are greater-than (>), less-than (<), greater-than-or-equal-to (>=),


and less-than-or-equal-to (<=). If relational operators are used in an expression, the
expression returns a logical value of 1 if the expression is true and 0 if the expression is
false. If there are any unknown or z bits in the operands, the expression takes a value x.
These operators function exactly as the corresponding operators in the C programming
language.

A = 4, B = 3

X = 4'b1010, Y = 4'b1101, Z = 4'b1xxx

A <= B // Evaluates to a logical 0

A > B // Evaluates to a logical 1

Y >= X // Evaluates to a logical 1

Y < Z // Evaluates to an x

Equality Operators

Equality operators are logical equality (==), logical inequality (!=), case equality (===),
and case inequality (!==) . When used in an expression, equality operators return logical
value 1 if true, 0 if false. These operators compare the two operands bit by bit, with
zero filling if the operands are of unequal length. Table below lists the operators.

It is important to note the difference between the logical equality operators (==, !=) and
case equality operators (===, !==). The logical equality operators (==, !=) will yield an x if
either operand has x or z in its bits. However, the case equality operators ( ===, !== )
compare both operands bit by bit and compare all bits, including x and z. The result is 1 if
the operands match exactly, including x and z bits. The result is 0 if the operands do not
match exactly. Case equality operators never result in an x.
Table: Equality Operators

Possible Logical

Expression Description

Value

a == b a equal to b, result unknown if x or z in a or b 0, 1, x

a not equal to b, result unknown if x or z in a or

a != b 0, 1, x

a === b a equal to b, including x and z 0, 1

a !== b a not equal to b, including x and z 0, 1

A = 4, B = 3

X = 4'b1010, Y = 4'b1101

Z = 4'b1xxz, M = 4'b1xxz, N = 4'b1xxx

A == B // Results in logical 0

X != Y // Results in logical 1

X == Z // Results in x

Z === M // Results in logical 1 (all bits match, including x and z)

Z === N // Results in logical 0 (least significant bit does not match) M !== N //
Results in logical 1
Bitwise Operators

Bitwise operators are negation (~), and(&), or (|), xor (^), xnor (^~, ~^). Bitwise
operators perform a bit-by-bit operation on two operands. They take each bit in one
operand and perform the operation with the corresponding bit in the other operand.
If one operand is shorter than the other, it will be bit-extended with zeros to match
the length of the longer operand. Logic tables for the bit-by-bit computation are
shown in Table. A z is treated as an x in a bitwise operation. The exception is the
unary negation operator (~), which takes only one operand and operates on the bits
of the single operand.

Table: Truth Tables for Bitwise Operators

Examples of bitwise operators are shown below.

X = 4'b1010, Y = 4'b1101

Z = 4'b10x1

~X // Negation. Result is 4'b0101

X&Y // Bitwise and. Result is 4'b1000

X|Y // Bitwise or. Result is 4'b1111


X^Y // Bitwise xor. Result is 4'b0111

X ^~ Y // Bitwise xnor. Result is 4'b1000

X&Z // Result is 4'b10x0

It is important to distinguish bitwise operators ~, &, and | from logical operators !,


&&, ||. Logical operators always yield a logical value 0, 1, x, whereas bitwise
operators yield a bit-by-bit value. Logical operators perform a logical operation, not a
bit-by-bit operation.

// X = 4'b1010, Y = 4'b0000

X | Y // bitwise operation. Result is 4'b1010

X || Y // logical operation. Equivalent to 1 || 0. Result is 1.

Reduction Operators

Reduction operators are and (&), nand (~&), or (|), nor (~|), xor (^), and xnor (~^, ^~).
Reduction operators take only one operand. Reduction operators perform a bitwise
operation on a single vector operand and yield a 1-bit result. The difference is that
bitwise operations are on bits from two different operands, whereas reduction
operations are on the bits of the same operand. Reduction operators work bit by bit
from right to left. Reduction nand, reduction nor, and reduction xnor are computed
by inverting the result of the reduction and, reduction or, and reduction xor,
respectively.

// X = 4'b1010

&X //Equivalent to 1 & 0 & 1 & 0. Results in 1'b0


|X//Equivalent to 1 | 0 | 1 | 0. Results in 1'b1
^X//Equivalent to 1 ^ 0 ^ 1 ^ 0. Results in 1'b0

//A reduction xor or xnor can be used for even or odd parity
//generation of a vector.
The use of a similar set of symbols for logical (!, &&, ||), bitwise (~, &, |, ^), and
reduction operators (&, |, ^) is somewhat confusing initially. The difference lies in
the number of operands each operator takes and also the value of results
computed.

Shift Operators

Shift operators are right shift ( >>), left shift (<<), arithmetic right shift (>>>), and
arithmetic left shift (<<<). Regular shift operators shift a vector operand to the right
or the left by a specified number of bits. The operands are the vector and the
number of bits to shift. When the bits are shifted, the vacant bit positions are filled
with zeros. Shift operations do not wrap around. Arithmetic shift operators use the
context of the expression to determine the value with which to fill the vacated bits.

// X = 4'b1100

Y = X >> 1; //Y is 4'b0110. Shift right 1 bit. 0 filled in MSB position.

Y = X << 1; //Y is 4'b1000. Shift left 1 bit. 0 filled in LSB position.

Y = X << 2; //Y is 4'b0000. Shift left 2 bits.

integer a, b, c; //Signed data types

a = 0;

b = -10; // 00111...10110 binary

c = a + (b >>> 3); //Results in -2 decimal, due to arithmetic shift

Shift operators are useful because they allow the designer to model shift operations,
shift-and-add algorithms for multiplication, and other useful operations.

Concatenation Operator

The concatenation operator ( {, } ) provides a mechanism to append multiple


operands. The operands must be sized. Unsized operands are not allowed because
the size of each operand must be known for computation of the size of the result.
Concatenations are expressed as operands within braces, with commas separating
the operands. Operands can be scalar nets or registers, vector nets or registers, bit-
select, part-select, or sized constants.
// A = 1'b1, B = 2'b00, C = 2'b10, D = 3'b110

Y = {B , C} // Result Y is 4'b0010

Y = {A , B , C , D , 3'b001} // Result Y is 11'b10010110001

Y = {A , B[0], C[1]} // Result Y is 3'b101

Replication Operator

Repetitive concatenation of the same number can be expressed by using a


replication constant. A replication constant specifies how many times to replicate
the number inside the brackets ( { } ).

reg A;

reg [1:0] B, C;

reg [2:0] D;

A = 1'b1; B = 2'b00; C = 2'b10; D = 3'b110;

Y = { 4{A} } // Result Y is 4'b1111

Y = { 4{A} , 2{B} } // Result Y is 8'b11110000

Y = { 4{A} , 2{B} , C } // Result Y is 8'b1111000010

Conditional Operator

The conditional operator(?:) takes three operands.

Usage: condition_expr ? true_expr : false_expr ;

The condition expression (condition_expr) is first evaluated. If the result is true


(logical 1), then the true_expr is evaluated. If the result is false (logical 0), then the
false_expr is evaluated. If the result is x (ambiguous), then both true_expr and false_
expr are evaluated and their results are compared, bit by bit, to return for each bit
position an x if the bits are different and the value of the bits if they are the same.

The action of a conditional operator is similar to a multiplexer. Alternately, it can


be compared to the if-else expression.
Conditional operators are frequently used in dataflow modeling to model
conditional assignments. The conditional expression acts as a switching control.

//model functionality of a tristate buffer

assign addr_bus = drive_enable ? addr_out : 36'bz;

//model functionality of a 2-to-1 mux

assign out = control ? in1 : in0;

Conditional operations can be nested. Each true_expr or false_expr can itself be a


conditional operation. In the example that follows, convince yourself that (A==3)
and control are the two select signals of 4-to-1 multiplexer with n, m, y, x as the
inputs and out as the output signal.

assign out = (A == 3) ? ( control ? x : y ): ( control ? m : n) ;

Operator Precedence

Having discussed the operators, it is now important to discuss operator precedence.


If no parentheses are used to separate parts of expressions, Verilog enforces the
following precedence. Operators listed in Table are in order from highest precedence
to lowest precedence. It is recommended that parentheses be used to separate
expressions except in case of unary operators or when there is no ambiguity.
Table: Operator Precedence

Operators Operator Symbols Precedence

Highest
Unary +-!~ precedence

Multiply, Divide, Modulus * / %

Add, Subtract +-

Shift << >>

Relational < <= > >=

Equality == != === !==

&, ~&

Reduction ^ ^~

|, ~|

&&

Logical

||

Conditional ?: Lowest precedence

You might also like