GATE LEVEL MODELLING, MUX AND ADDERS
GATE LEVEL MODELING
In introduction we discussed the four levels of abstraction used to describe hardware, briefly. Gate
Level is a low level of abstraction. Most digital design is now done at gate level or higher levels of
abstraction. At gate level, the circuit is described in terms of gates (e.g., and, nand). Hardware design
at this level is intuitive for a user with a basic knowledge of digital logic design because it is possible
to see a one-to-one correspondence between the logic circuit diagram and the Verilog description.
Actually, the lowest level of abstraction is switch- (transistor-) level modeling. However, with
designs getting very complex, very few hardware designers work at switch level.
Gate Types
A logic circuit can be designed by use of logic gates. Verilog supports basic logic gates as predefined
primitives. These primitives are instantiated like modules except that they are predefined in Verilog
and do not need a module definition. All logic circuits can be designed by using basic gates. There
are two classes of basic gates: and/or gates and buf/not gates.
And/Or Gates
And/or gates have one scalar output and multiple scalar inputs. The first terminal in the list of gate
terminals is an output and the other terminals are inputs. The output of a gate is evaluated as soon as
one of the inputs changes. The and/or gates available in Verilog are shown below. The corresponding
logic symbols for these gates are shown in Figure below. We consider gates with two inputs. The
output terminal is denoted by out. Input terminals are denoted by i1 and i2.
and or xor
nand nor xnor
These gates are instantiated to build logic circuits in Verilog. Examples of gate instantiations are
shown below. In fallowing example, for all instances, OUT is connected to the output out, and IN1
and IN2 are connected to the two inputs i1 and i2 of the gate primitives. Note that the instance name
does not need to be specified for primitives. This lets the designer instantiate hundreds of gates
without giving them a name. More than two inputs can be specified in a gate instantiation. Gates
with more than two inputs are instantiated by simply adding more input ports in the gate
instantiation. Verilog automatically instantiates the appropriate gate.
Example Gate Instantiation of And/Or Gates
wire OUT, IN1, IN2;
// basic gate instantiations.
and a1(OUT, IN1, IN2);
nand na1(OUT, IN1, IN2);
or or1(OUT, IN1, IN2);
nor nor1(OUT, IN1, IN2);
xor x1(OUT, IN1, IN2);
xnor nx1(OUT, IN1, IN2);
// More than two inputs; 3 input nand gate
nand na1_3inp(OUT, IN1, IN2, IN3);
// gate instantiation without instance name
and (OUT, IN1, IN2); // legal gate instantiation
Example Gate Instantiations of Buf/Not Gates
// basic gate instantiations.
buf b1(OUT1, IN);
not n1(OUT1, IN);
// More than two outputs
buf b1_2out(OUT1, OUT2, IN);
// gate instantiation without instance name
not (OUT1, IN); // legal gate instantiation
More than two inputs can be specified in a gate instantiation. Gates with more than two inputs are
instantiated by simply adding more input ports in the gate instantiation (see Example 5-1). Verilog
automatically instantiates the appropriate gate.
Example 5-1 Gate Instantiation of And/Or Gates
wire OUT, IN1, IN2;
// basic gate instantiations.
and a1(OUT, IN1, IN2);
nand na1(OUT, IN1, IN2);
or or1(OUT, IN1, IN2);
nor nor1(OUT, IN1, IN2);
xor x1(OUT, IN1, IN2);
xnor nx1(OUT, IN1, IN2);
// More than two inputs; 3 input nand gate
nand na1_3inp(OUT, IN1, IN2, IN3);
// gate instantiation without instance name
and (OUT, IN1, IN2); // legal gate instantiation
Array of Instances
There are many situations when repetitive instances are required. These instances differ from each
other only by the index of the vector to which they are connected. To simplify specification of such
instances, Verilog HDL allows an array of primitive instances to be defined.[1] Example 5-4 shows
an example of an array of instances.
Example 5-4 Simple Array of Primitive Instances
wire [7:0] OUT, IN1, IN2;
// basic gate instantiations.
nand n_gate[7:0](OUT, IN1, IN2);
// This is equivalent to the following 8 instantiations
nand n_gate0(OUT[0], IN1[0], IN2[0]);
nand n_gate1(OUT[1], IN1[1], IN2[1]);
nand n_gate2(OUT[2], IN1[2], IN2[2]);
nand n_gate3(OUT[3], IN1[3], IN2[3]);
nand n_gate4(OUT[4], IN1[4], IN2[4]);
nand n_gate5(OUT[5], IN1[5], IN2[5]);
nand n_gate6(OUT[6], IN1[6], IN2[6]);
nand n_gate7(OUT[7], IN1[7], IN2[7]);
Examples
Having understood the various types of gates available in Verilog, we will discuss a real example
that illustrates design of gate-level digital circuits.
Gate-level multiplexer:
We will design a 4-to-1 multiplexer with 2 select signals. Multiplexers serve a useful purpose in
logic design. They can connect two or more sources to a single destination. They can also be used to
implement boolean functions.
4-to-1 Multiplexer Truth Table
Logic Diagram for Multiplexer:
Verilog Description of Multiplexer
// Module 4-to-1 multiplexer. Port list is taken exactly from
// the I/O diagram.
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;
// Internal wire declarations
wire s1n, s0n;
wire y0, y1, y2, y3;
// Gate instantiations
// Create s1n and s0n signals.
not (s1n, s1);
not (s0n, s0);
// 3-input and gates instantiated
and (y0, i0, s1n, s0n);
and (y1, i1, s1n, s0);
and (y2, i2, s1, s0n);
and (y3, i3, s1, s0);
// 4-input or gate instantiated
or (out, y0, y1, y2, y3);
endmodule
Stimulus for Multiplexer
// Define the stimulus module (no ports)
module stimulus;
// Declare variables to be connected
// to inputs
reg IN0, IN1, IN2, IN3;
reg S1, S0;
// Declare output wire
wire OUTPUT;
// Instantiate the multiplexer
mux4_to_1 mymux(OUTPUT, IN0, IN1, IN2, IN3, S1, S0);
// Stimulate the inputs
// Define the stimulus module (no ports)
initial
begin
// set input lines
IN0 = 1; IN1 = 0; IN2 = 1; IN3 = 0;
#1 $display("IN0= %b, IN1= %b, IN2= %b, IN3= %b\n",IN0,IN1,IN2,IN3);
// choose IN0
S1 = 0; S0 = 0;
#1 $display("S1 = %b, S0 = %b, OUTPUT = %b \n", S1, S0, OUTPUT);
// choose IN1
S1 = 0; S0 = 1;
#1 $display("S1 = %b, S0 = %b, OUTPUT = %b \n", S1, S0, OUTPUT);
// choose IN2
S1 = 1; S0 = 0;
#1 $display("S1 = %b, S0 = %b, OUTPUT = %b \n", S1, S0, OUTPUT);
// choose IN3
S1 = 1; S0 = 1;
#1 $display("S1 = %b, S0 = %b, OUTPUT = %b \n", S1, S0, OUTPUT);
end
endmodule
The output of the simulation is shown below. Each combination of the select signals is tested:
IN0= 1, IN1= 0, IN2= 1, IN3= 0
S1 = 0, S0 = 0, OUTPUT = 1
S1 = 0, S0 = 1, OUTPUT = 0
S1 = 1, S0 = 0, OUTPUT = 1
S1 = 1, S0 = 1, OUTPUT = 0
Half Adder
In this we will implement gate level half adder.
1-bit Full Adder diagram is shown below:
Verilog Description for 1-bit Full Adder
// Define a 1-bit full adder
module fulladd(sum, c_out, a, b, c_in);
// I/O port declarations
output sum, c_out;
input a, b, c_in;
// Internal nets
wire s1, c1, c2;
// Instantiate logic gate primitives
xor (s1, a, b);
and (c1, a, b);
xor (sum, s1, c_in);
and (c2, s1, c_in);
xor (c_out, c2, c1);
endmodule
A 4-bit ripple carry full adder can be constructed from four 1-bit full adders, as shown in fallowing
Figure. Notice that fa0, fa1, fa2, and fa3 are instances of the module fulladd (1-bit full adder).
4-bit Ripple Carry Full Adder
This structure can be translated to Verilog as shown in Example 5-8. Note that the port names used
in a 1-bit full adder and a 4-bit full adder are the same but they represent different elements. The
element sum in a 1-bit adder is a scalar quantity and the element sum in the 4-bit full adder is a 4-bit
vector quantity. Verilog keeps names local to a module. Names are not visible outside the module
unless hierarchical name referencing is used. Also note that instance names must be specified when
defined modules are instantiated, but when instantiating Verilog primitives, the instance names are
optional.
Verilog Description for 4-bit Ripple Carry Full Adder
// Define a 4-bit full adder
module fulladd4(sum, c_out, a, b, c_in);
// I/O port declarations
output [3:0] sum;
output c_out;
input[3:0] a, b;
input c_in;
// Internal nets
wire c1, c2, c3;
// Instantiate four 1-bit full adders.
fulladd fa0(sum[0], c1, a[0], b[0], c_in);
fulladd fa1(sum[1], c2, a[1], b[1], c1);
fulladd fa2(sum[2], c3, a[2], b[2], c2);
fulladd fa3(sum[3], c_out, a[3], b[3], c3);
endmodule
Finally, the design must be checked by applying stimulus, as shown in Example 5-9. The module
stimulus stimulates the 4-bit full adder by applying a few input combinations and monitors the
results.
Example 5-9 Stimulus for 4-bit Ripple Carry Full Adder
// Define the stimulus (top level module)
module stimulus;
// Set up variables
reg [3:0] A, B;
reg C_IN;
wire [3:0] SUM;
wire C_OUT;
// Instantiate the 4-bit full adder. call it FA1_4
fulladd4 FA1_4(SUM, C_OUT, A, B, C_IN);
// Set up the monitoring for the signal values
initial
begin
$monitor($time," A= %b, B=%b, C_IN= %b, --- C_OUT= %b, SUM= %b\n",
A, B, C_IN, C_OUT, SUM);
end
// Stimulate inputs
initial
begin
A = 4'd0; B = 4'd0; C_IN = 1'b0;
#5 A = 4'd3; B = 4'd4;
#5 A = 4'd2; B = 4'd5;
#5 A = 4'd9; B = 4'd9;
#5 A = 4'd10; B = 4'd15;
#5 A = 4'd10; B = 4'd5; C_IN = 1'b1;
end
endmodule
The output of the simulation is shown below:
0 A= 0000, B=0000, C_IN= 0, --- C_OUT= 0, SUM= 0000
5 A= 0011, B=0100, C_IN= 0, --- C_OUT= 0, SUM= 0111
10 A= 0010, B=0101, C_IN= 0, --- C_OUT= 0, SUM= 0111
15 A= 1001, B=1001, C_IN= 0, --- C_OUT= 1, SUM= 0010
20 A= 1010, B=1111, C_IN= 0, --- C_OUT= 1, SUM= 1001
25 A= 1010, B=0101, C_IN= 1,, C_OUT= 1, SUM= 0000
Simulation Control
$finish Specifies when simulation ends
$stop Suspends the simulation and enters interactive mode
$display Prints output using format similar to C and creates a new line
$monitor Similar to $display but active all the time
Home Task
Implement 8 bit 4x1 MUX