DDTH Unit2
DDTH Unit2
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.
The AND gate primitive in Verilog is instantiated with the following statement:
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.
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:
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.
• 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:
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:
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.
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.
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);
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);
nor g3(o,o1,o2); //The nor gate has one instantiation with assigned name g3.
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);
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.
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
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
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.
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.
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
and #(5) a1(out, i1, i2); //Delay of 5 for all transitions and #(4,6) a2(out, i1, i2); // Rise
= 4, Fall = 6
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
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
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.
wire out;
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.
assign out = i1 & i2; //Note that out was not declared as a wire
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.
Figure: Delays
When signals in1 and in2 go high at time 20, out goes to a high 10 time units
later (time = 30).
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.
//same as
wire out;
The declaration above has the same effect as defining a wire out and
declaring a continuous assignment on out.
//Net Delays
wire # 10 out;
wire out;
Expressions
Expressions are constructs that combine operators and operands to produce a result.
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).
real a, b, c;
reg ret_value;
Operators act on the operands to produce desired results. Verilog provides various
types of operators.
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.
* multiply two
/ divide two
+ add two
Arithmetic
- subtract two
% modulus two
|| logical or two
Relational
== equality two
!= inequality two
Equality
| reduction or one
Reduction
Shift
Arithmetic Operators
Binary operators
Binary arithmetic operators are multiply (*), divide (/), add (+), subtract (-), power
(**), and modulus (%). Binary operators take two operands.
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;
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
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
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 operations A = 3;
B = 0;
Unknowns
A = 2'b0x; B = 2'b10;
Relational Operators
A = 4, B = 3
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 0, 1, x
A = 4, B = 3
X = 4'b1010, Y = 4'b1101
A == B // Results in logical 0
X != Y // Results in logical 1
X == Z // Results in x
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.
X = 4'b1010, Y = 4'b1101
Z = 4'b10x1
// X = 4'b1010, Y = 4'b0000
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
//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
a = 0;
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
Y = {B , C} // Result Y is 4'b0010
Replication Operator
reg A;
reg [1:0] B, C;
reg [2:0] D;
Conditional Operator
Operator Precedence
Highest
Unary +-!~ precedence
Add, Subtract +-
&, ~&
Reduction ^ ^~
|, ~|
&&
Logical
||