Digital VLSI Design Laboratory Manual
Digital VLSI Design Laboratory Manual
(3171003)
LABORATORY MANUAL
SEMESTER I
VLSI Design
[ DEPARTMENT OF
ELECTRONICS AND COMMUNICATION ]
L.D. COLLEGE OF ENGINEERING – AHMEDABAD
1|Page
List of Experiments
Sr. Lab
Title of the experiment Date Sign
No. Slot
1 Introduction to Programming Logic Devices: CPLD and FPGA 1
Introduction to Front-End designing EDA tool: VIVADO
2 1
installation and Designing steps
Introduction of Verilog hardware description language (HDL):
3 1
Modelling types and application of Verilog constructs
Implementation of Combinational Logic Designs using Verilog
2|Page
Implementation of Sequential Logic Designs using Verilog
3|Page
Implementation of transmission gate (TG) using switch level
40 6
modelling.
Implementation of 3-input NAND gate using switch level
41 6
modelling.
Implementation of 2-input XOR gate using switch level modelling. Self
42 Exerc
ise for
43 Implementation of 2-to-1 MUX using switch level modelling. slot-6
4|Page
PRACTICAL 1
AIM : Introduction to Programming Logic Devices: CPLD and FPGA
Programmable Logic Devices are integrated circuits that can be configured by a user to implement a
digital circuit design. Unlike traditional fixed-function logic chips (like AND, OR, or NOT gates),
PLDs are blank at the time of manufacturing and can be programmed to perform a specific function.
5|Page
PRACTICAL 2
AIM : Introduction to Front-End designing EDA tool : VIVADO installation and Designing
steps
7|Page
PRACTICAL 3
AIM : Introduction of Verilog hardware description language (HDL): Modeling types and
application of Verilog constructs
Verilog is a specialized programming language used to describe digital electronic circuits. Unlike
software programming languages, Verilog's main purpose is to model hardware, capturing concepts
like concurrency and timing. It allows a designer to create a circuit's description at a high level of
abstraction and then synthesize it into a physical circuit on an FPGA or ASIC.
There are three main ways to model a circuit in Verilog, each offering a different level of abstraction.
1. Structural Modeling
This is the lowest level of abstraction. Structural modeling describes a circuit in terms of its component
gates and how they are interconnected. It's like drawing a schematic in code, explicitly defining each
gate and wire. This is useful for understanding the physical implementation of a circuit.
Example: 2-to-1 Multiplexer (MUX) A MUX selects one of its multiple inputs and forwards it to a
single output. A structural model shows how to build it using AND, OR, and NOT gates.
• Code: The code would instantiate each gate (and, or, not) and connect them with wire
declarations.
2. Dataflow Modeling
This modeling style is more abstract than structural. It describes a circuit's functionality using
continuous assignments (assign). The output of a circuit is described as a function of its inputs. The
physical connections are implied by the expression. This is a very common and efficient way to write
combinational logic.
• Equation: The output Y is high if S is low and A is high, OR if S is high and B is high. This
can be expressed as: Y=(¬S⋅A)+(S⋅B).
• Code: The Verilog code uses the assign statement to implement this equation directly.
3. Behavioral Modeling
This is the highest level of abstraction. Behavioural modelling describes a circuit's behaviour using
procedural blocks, like the always block. It focuses on the algorithm or desired behaviour rather than
the specific gates. This is ideal for describing sequential logic (like flip-flops and counters) and for
complex combinational circuits.
8|Page
Example: 2-to-1 Multiplexer (MUX)
• Behaviour: The logic is described in an always block that executes whenever an input changes.
A conditional if-else or case statement is used to define the behaviour.
• Code: The always @(*) block tells the simulator to run the code whenever any input in the
sensitivity list changes. Inside, the if-else statement checks the value of the select signal S to
determine which input to assign to the output Y.
9|Page
PRACTICAL 4
AIM : Implementation of two simple Boolean Functions using Structural Modelling, Dataflow
Modelling, and Behavioural Modelling.
Boolean Function: Y = AB + BC + AC
CODE :
1. Structural Modelling:
2. Data-Flow Modelling
3. Behavioural Modelling
TESTBENCH:
module bool_impl_tb;
reg a;
reg b;
reg c;
wire y;
bool_impl uut(.a(a),.b(b),.c(c),.y(y));
initial begin
a=0;b=0;c=0; #1;
a=0;b=1;c=1; #1;
a=1;b=1;c=1; #1;
a=1;b=0;c=1; #1;
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
11 | P a g e
Boolean Function: Y = (A^B)C + AC
CODE :
1. Structural Modelling
3. Behavioural Modelling
12 | P a g e
TESTBENCH:
module bool_impl_tb;
reg a;
reg b;
reg c;
wire y;
bool_impl uut(.a(a),.b(b),.c(c),.y(y));
initial begin
a=0;b=0;c=0; #1;
a=0;b=1;c=1; #1;
a=1;b=1;c=1; #1;
a=1;b=0;c=1; #1;
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
13 | P a g e
PRACTICAL 5
HALF ADDER : A Half Adder (HA) is a basic combinational circuit that performs the arithmetic
addition of two single-bit binary numbers. It has two inputs, usually denoted as A and B, and two outputs:
Sum (S) and Carry (C).
Sum = a ^ b
Carry = a & b
Diagram :
CODE :
1. Structural Modelling
14 | P a g e
xor X1(sum,a,b);
and A1(carry,a,b);
endmodule
3. Behavioural Modelling
endmodule
TESTBENCH:
module half_adder_tb;
reg a;
reg b;
wire sum;
wire carry;
half_adder uut (
.a(a),
.b(b),
.sum(sum),
.carry(carry)
);
15 | P a g e
initial begin
// Test all combinations
a = 0; b = 0; #1;
a = 0; b = 1; #1;
a = 1; b = 0; #1;
a = 1; b = 1; #1;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
16 | P a g e
PRACTICAL 6
AIM : Implementation of 1-bit Full-Adder (FA) using 1-bit HA (Design Reuse Technique).
FULL ADDER : A Full Adder (FA) is a combinational circuit that performs the arithmetic addition of
three input bits: two significant bits (A and B) and a carry input (Cin). It generates two outputs: Sum (S)
and Carry (Cout).
The logic expressions for a 1-bit full adder Sum and Cout (output carry) can be given as:
Sum = A^B^Cin
Diagram :
CODE :
The module used here is Half Adder module which is included in project files (source files).
endmodule
TESTBENCH :
module full_adder_ha_tb;
reg A,B,Cin;
wire Sum,Cout;
full_adder_ha uut(.A(A),.B(B),.Cin(Cin),.Sum(Sum),.Cout(Cout));
initial begin
A=0;B=0;Cin=0; #5;
A=0;B=0;Cin=1; #5;
A=0;B=1;Cin=0; #5;
A=0;B=1;Cin=1; #5;
A=1;B=0;Cin=0; #5;
A=1;B=0;Cin=1; #5;
A=1;B=1;Cin=0; #5;
A=1;B=1;Cin=1; #5;
#10;
$finish();
end
endmodule
18 | P a g e
OUTPUT :
SCHEMATIC :
19 | P a g e
PRACTICAL 7
CODE :
1. Structural Modelling
2. Data-Flow Modelling
3. Behavioral Modelling
20 | P a g e
always @ (A,B,Cin)
begin
assign Sum = A^B^Cin;
assign Cout = (A&B)|(B&Cin)|(A&Cin);
end
endmodule
TESTBENCH :
module full_adder_ms_tb;
reg A,B,Cin;
wire Sum,Cout;
full_adder_ms uut(.A(A),.B(B),.Cin(Cin),.Sum(Sum),.Cout(Cout));
initial begin
A=0;B=0;Cin=0; #5;
A=0;B=0;Cin=1; #5;
A=0;B=1;Cin=0; #5;
A=0;B=1;Cin=1; #5;
A=1;B=0;Cin=0; #5;
A=1;B=0;Cin=1; #5;
A=1;B=1;Cin=0; #5;
A=1;B=1;Cin=1; #5;
#10;
$finish();
end
endmodule
OUTPUT :
21 | P a g e
SCHEMATIC :
22 | P a g e
PRACTICAL 8
AIM: Implementation of 4-bit Ripple Carry Adder (RCA) using 1-bit FA (Design Reuse
Technique). Implementation of 4-bit and 8-bit RCAs using dataflow modelling.
RIPPLE CARRY ADDER : A Ripple Carry Adder (RCA) is the simplest form of multi-bit adder,
constructed by connecting a series of 1-bit Full Adders in cascade. Each Full Adder takes two input bits
(Aᵢ, Bᵢ) and a carry input (Cᵢ) to produce a sum bit (Sᵢ) and a carry output (Cᵢ₊₁). In a 4-bit RCA, four full
adders are connected in sequence. The carry output of each stage “ripples” into the next stage as its carry
input. The first stage (least significant bit) receives an external carry input (Cin). The final stage
generates the overall carry output (Cout).
Si = Aᵢ ^ Bᵢ ^ Cᵢ
Cᵢ₊₁ = (Aᵢ & Bᵢ) | (Bᵢ & Cᵢ) | (Cᵢ & Aᵢ)
Diagram :
CODE :
TESTBENCH :
module rca_full_adder_tb;
reg [3:0] A,B;
reg Cin;
wire [3:0] Sum;
wire Cout;
initial begin
A = 4'b0001; B = 4'b0010; Cin = 0; #5;
A = 4'b1111; B = 4'b0001; Cin = 0; #5;
A = 4'b1010; B = 4'b0101; Cin = 1; #5;
A = 4'b1001; B = 4'b1001; Cin = 1; #5;
$finish;
end
endmodule
OUTPUT :
24 | P a g e
SCHEMATIC :
CODE :
TESTBENCH :
module rca_4bit_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;
25 | P a g e
rca_4bit uut (
.A(A),
.B(B),
.Cin(Cin),
.Sum(Sum),
.Cout(Cout)
);
initial begin
A = 4'b0000; B = 4'b0000; Cin = 0; #10;
A = 4'b0101; B = 4'b0011; Cin = 0; #10;
A = 4'b1111; B = 4'b0001; Cin = 0; #10;
A = 4'b1010; B = 4'b0101; Cin = 1; #10;
A = 4'b1111; B = 4'b1111; Cin = 1; #10;
$stop; // End simulation
end
endmodule
OUTPUT :
SCHEMATIC :
26 | P a g e
C. Implementation of 8-bit RCA
CODE :
endmodule
TESTBENCH :
module tb_rca_8bit;
reg [7:0] A, B;
reg Cin;
wire [7:0] Sum;
wire Cout;
rca_8bit uut (
.A(A),
.B(B),
.Cin(Cin),
.Sum(Sum),
.Cout(Cout)
);
initial begin
A = 8'b00000000; B = 8'b00000000; Cin = 0; #10;
A = 8'b00001111; B = 8'b00000001; Cin = 0; #10;
A = 8'b10101010; B = 8'b01010101; Cin = 0; #10;
A = 8'b11111111; B = 8'b00000001; Cin = 1; #10;
A = 8'b11110000; B = 8'b11110000; Cin = 0; #10;
$stop;
27 | P a g e
end
endmodule
OUTPUT :
SCHEMATIC :
28 | P a g e
PRACTICAL 9
AIM : Implement 4-bit universal adder (adder cum subtractor) using RCA technique and dataflow
modelling.
UNIVERSAL ADDER : When control bit CTRL decides whether to do addition or subtraction for two
4 bit integers A and B. The signal CTRL is attached to one of the inputs of the XOR gate and another
input is connected to B.
CTRL = 0: Addition is performed (A + B)
CTRL = 1: Subtraction is performed. XOR gate output becomes a complement of B. So, addition is
performed as A + (-B)
If Cout = 1, ignore it and sum S is the answer and if it is 0, Sum S represents 2’s complement of the
answer and the number is negative
Diagram :
CODE :
module univ_adder_4bit(A,B,M,Sum,Cout);
input [3:0] A,
input [3:0] B,
input M, // Mode: 0 = Addition, 1 = Subtraction
output [3:0] Sum,
output Cout
29 | P a g e
wire [3:0] B_mod;
wire Cin;
wire [2:0] carry;
endmodule
TESTBENCH :
module univ_adder_4bit_tb;
reg [3:0] A, B;
reg M;
wire [3:0] Sum;
wire Cout;
initial begin
M = 0; A = 4'b0011; B = 4'b0010; #5; // 3 + 2 = 5
M = 0; A = 4'b1111; B = 4'b0001; #5; // 15 + 1 = 16 -> Overflow
// Subtraction tests (M = 1)
M = 1; A = 4'b0101; B = 4'b0011; #5; // 5 - 3 = 2
30 | P a g e
M = 1; A = 4'b0011; B = 4'b0101; #5; // 3 - 5 = -2 (wraps around as 2's comp)
M = 1; A = 4'b1000; B = 4'b1000; #5; // 8 - 8 = 0
M = 1; A = 4'b0000; B = 4'b0001; #5; // 0 - 1 = -1 (in 2's comp, 1111)
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
31 | P a g e
PRACTICAL 10
CARRY LOOK AHEAD ADDER : A Carry Lookahead Adder (CLA) is an advanced adder circuit
designed to overcome the delay limitation of the Ripple Carry Adder (RCA). In an RCA, the carry output
of each full adder must propagate (or “ripple”) through all previous stages, causing linear delay. The
CLA reduces this delay by computing carries in parallel using additional logic.
Generate Gi = Aᵢ & Bᵢ
Propagate Pi = Aᵢ ^ Bᵢ
Diagram :
CODE :
// Sum
assign Sum[0] = P[0] ^ Cin;
assign Sum[1] = P[1] ^ c1;
assign Sum[2] = P[2] ^ c2;
assign Sum[3] = P[3] ^ c3;
endmodule
TESTBENCH :
module CLA_adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;
initial begin
A = 4'b0001; B = 4'b0011; Cin = 0; #5;
A = 4'b1111; B = 4'b0001; Cin = 0; #5;
A = 4'b1010; B = 4'b0101; Cin = 1; #5;
$finish;
end
endmodule
33 | P a g e
OUTPUT :
SCHEMATIC :
34 | P a g e
PRACTICAL 11
CSA : A Carry Select Adder is a combinational circuit designed to improve the speed of addition
compared to a Ripple Carry Adder (RCA). While the Ripple Carry Adder waits for each carry to ripple
through all previous stages, the CSLA reduces delay by pre-computing two possible results in parallel
for each block of bits:
Diagram :
CODE :
// Case 1: Cin = 0
35 | P a g e
assign sum0[0] = A[0] ^ B[0];
assign c0 = A[0] & B[0];
// Case 2: Cin = 1
assign sum1[0] = A[0] ^ B[0] ^ 1;
assign c1 = (A[0] & B[0]) | (A[0] & 1) | (B[0] & 1);
TESTBENCH :
module CSA_adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;
initial begin
$monitor("A=%b B=%b Cin=%b | Sum=%b Cout=%b", A, B, Cin, Sum, Cout);
36 | P a g e
A = 4'b0101; B = 4'b0101; Cin = 0; #5;
A = 4'b1111; B = 4'b0001; Cin = 1; #5;
A = 4'b1010; B = 4'b0011; Cin = 1; #5;
A = 4'b1100; B = 4'b0011; Cin = 1; #5;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
37 | P a g e
PRACTICAL 12
BCD ADDER : A BCD Adder is a combinational circuit that adds two Binary-Coded Decimal (BCD)
numbers and produces a BCD result. In BCD representation, each decimal digit (0–9) is represented by
its 4-bit binary equivalent. Normal binary addition works fine for sums ≤ 9 (1001). If the sum exceeds
1001 (decimal 9), the result is not a valid BCD digit.
Diagram :
Example:
This result is invalid for BCD number. So, in order to fix the addition result:
CODE :
38 | P a g e
input Cin;
output [3:0] Sum;
output Cout;
wire [4:0] temp_sum;
wire [4:0] corrected_sum;
wire carry_correction;
TESTBENCH :
module BCD_adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;
initial begin
$monitor("A=%b B=%b Cin=%b | Sum=%b Cout=%b", A, B, Cin, Sum, Cout);
39 | P a g e
OUTPUT :
SCHEMATIC :
40 | P a g e
PRACTICAL 13
For a 4-bit comparator, two 4-bit inputs (A[3:0] and B[3:0]) are compared, and the circuit produces three
outputs:
Diagram :
41 | P a g e
CODE :
module comparator_4bit(A,B,A_gt_B,A_eq_B,A_it_B);
input [3:0] A, B;
output reg A_gt_B, A_eq_B, A_lt_B;
endmodule
TESTBENCH :
module comparator_4bit_tb;
reg [3:0] A, B;
wire A_gt_B, A_eq_B, A_lt_B;
initial begin
A = 4'b0101; B = 4'b0110; #10; // A < B
A = 4'b0011; B = 4'b0011; #10; // A == B
A = 4'b0111; B = 4'b0110; #10; // A > B
A = 4'b0000; B = 4'b1111; #10; // A < B
A = 4'b1111; B = 4'b0000; #10; // A > B
A = 4'b1010; B = 4'b1010; #10; // A == B
42 | P a g e
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
43 | P a g e
PRACTICAL 14
Multiplexer : A multiplexer is a combinational circuit that has many data inputs and a single output,
depending on control or select inputs. For N input lines, log2(N) selection lines are required, or
equivalently, for 2n2n input lines, n selection lines are needed. Multiplexers are also known as “N-to-1
selectors,” parallel-to-serial converters, many-to-one circuits, and universal logic circuits. They are
mainly used to increase the amount of data that can be sent over a network within a certain amount of
time and bandwidth.
CODE :
module mux_2to1(a,b,sel,y);
input a, b;
input sel, y;
assign y = sel ? b : a;
endmodule
TESTBENCH :
module mux_2to1_tb;
reg a, b, sel;
wire y;
mux_2to1 uut(a, b, sel, y);
initial begin
a=0; b=1; sel=0; #10;
a=1; b=0; sel=0; #10;
a=1; b=0; sel=1; #10;
a=1; b=1; sel=1; #10;
$finish();
end
endmodule
44 | P a g e
OUTPUT :
SCHEMATIC :
CODE :
module mux_4to1(d,sel,out);
input [3:0] d;
input [1:0] sel;
output reg out;
always @ (*)
begin
case(sel)
2'b00 : out = d[0];
2'b01 : out = d[1];
2'b10 : out = d[2];
2'b11 : out = d[3];
default : out = d[0];
endcase
end
endmodule
45 | P a g e
TESTBENCH :
module mux_4to1_tb;
reg [3:0] d;
reg [1:0] sel;
wire y;
mux_4to1 uut(d, sel, y);
initial begin
d = 4'b1010; sel = 2'b00; #10;
sel = 2'b01; #10;
sel = 2'b10; #10;
sel = 2'b11; #10;
end
endmodule
OUTPUT :
SCHEMATIC :
46 | P a g e
C. Implementation of 8-to-1 Mux:
CODE :
module mux_8to1(d,sel,out);
input [7:0] d;
input [2:0] sel;
output reg out;
always @ (*)
begin
case (sel)
3'b000 : out = d[0];
3'b001 : out = d[1];
3'b010 : out = d[2];
3'b011 : out = d[3];
3'b100 : out = d[4];
3'b101 : out = d[5];
3'b110 : out = d[6];
3'b111 : out = d[7];
default : out = d[0];
endcase
end
endmodule
TESTBENCH :
module mux_8to1_tb;
reg [7:0] d;
reg [2:0] sel;
wire y;
mux_8to1 uut(d, sel, y);
initial begin
$monitor("d=%b sel=%b y=%b", d, sel, y);
d = 8'b11010101; sel = 3'b000; #10;
d = 8'b11010101; sel = 3'b001; #10;
d = 8'b11010101; sel = 3'b111; #10;
d = 8'b11010101; sel = 3'b101; #10;
d = 8'b11010101; sel = 3'b011; #10;
$finish();
end
47 | P a g e
endmodule
OUTPUT :
SCHEMATIC :
CODE :
module mux_16to1(d,sel,out);
input [15:0] d;
input [3:0] sel;
output reg out;
always @ (*)
begin
case (sel)
4'b0000 : out = d[0];
4'b0001 : out = d[1];
4'b0010 : out = d[2];
4'b0011 : out = d[3];
48 | P a g e
4'b0100 : out = d[4];
4'b0101 : out = d[5];
4'b0110 : out = d[6];
4'b0111 : out = d[7];
4'b1000 : out = d[8];
4'b1001 : out = d[9];
4'b1010 : out = d[10];
4'b1011 : out = d[11];
4'b1100 : out = d[12];
4'b1101 : out = d[13];
4'b1110 : out = d[14];
4'b1111 : out = d[15];
default: out = d[0];
endcase
end
endmodule
TESTBENCH :
module mux_16to1_tb;
reg [15:0] d;
reg [3:0] sel;
wire y;
mux_16to1 uut(d, sel, y);
initial begin
d = 16'b1010101010101010;
sel = 4'd0; #10;
sel = 4'd5; #10;
sel = 4'd10; #10;
sel = 4'd12; #10;
sel = 4'd8; #10;
$finish();
end
endmodule
49 | P a g e
OUTPUT :
SCHEMATIC :
50 | P a g e
PRACTICAL 15
AIM : Implementation of MUX: 4-to-1 using 2-to-1, 8-to-1 using 4-to 1 and 2-to-1 (Design Reuse
Technique).
CODE :
module mux_4to1_DR(d,sel,y);
input [3:0] d;
input [1:0] sel;
output y;
module mux_2to1();
input a, b;
input sel, y;
assign y = sel ? b : a;
endmodule
TESTBENCH :
module mux_4to1_DR_tb;
reg [3:0] d;
reg [1:0] sel;
wire y;
mux_4to1_DR uut(d, sel, y);
initial begin
d = 4'b1010; sel = 2'b00; #5;
sel = 2'b01; #5;
sel = 2'b10; #5;
sel = 2'b11; #5;
51 | P a g e
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
CODE :
module mux_8to1_DR(d,sel,y);
input [7:0] d;
input [2:0] sel;
output y;
52 | P a g e
The code for 4-to-1 Mux module used here is
module mux_4to1(d,sel,y);
input [3:0] d;
input [1:0] sel;
output y;
always @ (*)
begin
case(sel)
2'b00 : out = d[0];
2'b01 : out = d[1];
2'b10 : out = d[2];
2'b11 : out = d[3];
default : out = d[0];
endcase
end
endmodule
TESTBENCH :
module mux_8to1_DR_tb;
reg [7:0] d;
reg [2:0] sel;
wire y;
mux_8to1_DR uut(d, sel, y);
initial begin
d = 8'b10101010; sel = 3'b000; #10;
sel = 3'b001; #10;
sel = 3'b100; #10;
sel = 3'b111; #10;
sel = 3'b110; #10;
$finish();
end
endmodule
53 | P a g e
OUTPUT :
SCHEMATIC :
54 | P a g e
PRACTICAL 16
AIM : Implementation of Decoders: 2-to-4, 3-to-8, 4-to-16 using dataflow and behavioural
modelling.
DECODER :
In digital electronics, a combinational logic circuit that converts an N-bit binary input code into M
output channels in such a way that only one output channel is activated for each one of the possible
combinations of inputs is known as a decoder.
In other words, a combinational logic circuit which converts N input lines into a maximum of
2N output lines is called a decoder.
Diagram :
CODE :
55 | P a g e
endmodule
TESTBENCH :
module deco_2to4_tb;
reg [1:0]d;
wire [3:0]y;
deco_2to4 uut(.d(d),.y(y));
initial begin
$monitor("d = %b | y = %b",d,y);
d = 2'b00; #10;
d = 2'b01; #10;
d = 2'b10; #10;
d = 2'b11; #10;
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
56 | P a g e
B. Implementation of 3-to-8 Decoder
CODE :
module deco_3to8(d,y);
input [2:0] d;
output [7:0] y;
TESTBENCH :
module deco_8to1_tb;
reg [2:0] d;
wire [7:0] y;
deco_3to8 uut(.d(d), .y(y));
initial begin
$monitor("d = %b | y = %b",d,y);
d = 3'b000; #10;
d = 3'b001; #10;
d = 3'b010; #10;
d = 3'b011; #10;
d = 3'b100; #10;
d = 3'b101; #10;
d = 3'b110; #10;
d = 3'b111; #10;
$finish();
end
endmodule
57 | P a g e
OUTPUT :
SCHEMATIC :
CODE :
module deco_4to16(d,y);
input [3:0] d;
output [15:0] y;
58 | P a g e
assign y[2] = ~d[3] & ~d[2] & d[1] & ~d[0];
assign y[3] = ~d[3] & ~d[2] & d[1] & d[0];
assign y[4] = ~d[3] & d[2] & ~d[1] & ~d[0];
assign y[5] = ~d[3] & d[2] & ~d[1] & d[0];
assign y[6] = ~d[3] & d[2] & d[1] & ~d[0];
assign y[7] = ~d[3] & d[2] & d[1] & d[0];
assign y[8] = d[3] & ~d[2] & ~d[1] & ~d[0];
assign y[9] = d[3] & ~d[2] & ~d[1] & d[0];
assign y[10] = d[3] & ~d[2] & d[1] & ~d[0];
assign y[11] = d[3] & ~d[2] & d[1] & d[0];
assign y[12] = d[3] & d[2] & ~d[1] & ~d[0];
assign y[13] = d[3] & d[2] & ~d[1] & d[0];
assign y[14] = d[3] & d[2] & d[1] & ~d[0];
assign y[15] = d[3] & d[2] & d[1] & d[0];
endmodule
TESTBENCH :
module deco_4to16_tb;
reg [3:0] d;
wire [15:0] y;
deco_4to16 uut (
.d(d),
.y(y)
);
end
$finish();
end
endmodule
59 | P a g e
OUTPUT :
SCHEMATIC :
60 | P a g e
PRACTICAL 17
AIM : Implementation of Decoders: 3-to-8 using 2-to-4, 4-to-16 using 2-to-4 or 3-to-8 (Design
Reuse Technique).
CODE :
Testbench:
module deco_3to8_DR_tb;
reg [2:0] d;
wire [7:0] y;
// Stimulus
initial begin
//Apply all 8 combinations of d
d = 3'b000; #10;
d = 3'b001; #10;
d = 3'b010; #10;
61 | P a g e
d = 3'b011; #10;
d = 3'b100; #10;
d = 3'b101; #10;
d = 3'b110; #10;
d = 3'b111; #10;
OUTPUT :
SCHEMATIC :
CODE :
module deco_4to16_DR(d,y );
input [3:0] d;
output [15:0] y;
62 | P a g e
TESTBENCH :
module deco_4to16_DR_tb;
reg [3:0] d;
wire [15:0] y;
deco_4to16_DR uut (.d(d),.y(y));
initial begin
for (i = 0; i < 16; i = i + 1) begin
d = i;
#10; // Wait 10 ns
$display("%0dns\t%b\t%b", $time, d, y);
end
OUTPUT :
SCHEMATIC :
63 | P a g e
PRACTICAL 18
PRIORITY ENCODER :
The priority encoder is a combinational logic circuit that contains 2^n input lines and n output lines
and represents the highest priority input among all the input lines. When multiple input lines are
active high at the same time, then the input that has the highest priority is considered first to generate
the output.
It is used to solve the issues in binary encoders, which generate wrong output when more than one
input line is active high. If more than one input line is active high(1) at the same time, then this
encoder prioritizes every input level and allocates the priority level to each input.
Diagram :
CODE :
module prio_enco(in,out);
input [7:0] in;
output reg [2:0] out;
64 | P a g e
8’b000001xx: out = 3’b010;
8’b0000001x: out = 3’b001;
8’b00000001: out = 3’b000;
default: out = 3’b000;
endcase
end
endmodule
TESTBENCH:
module prio_enco_tb;
initial begin
in = 8’b00000001; #10;
in = 8’b00000100; #10;
in = 8’b10000000; #10;
in = 8’b10000111; #10;
$finish();
end
endmodule
OUTPUT :
SCHEMATIC :
65 | P a g e
PRACTICAL 19
MULTIPLIER :
A binary multiplier is a combinational logic circuit or digital device used for multiplying two binary
numbers. The two numbers are more specifically known as multiplicand and multiplier and the result
is known as a product.
The multiplicand & multiplier can be of various bit size. The product’s bit size depends on the bit
size of the multiplicand & multiplier. The bit size of the product is equal to the sum of the bit size of
multiplier & multiplicand.
Binary multiplication method is same as decimal multiplication. Binary multiplication of more than
1-bit numbers contains 2 steps. The 1st step is single bit-wise multiplication known as partial product
and the 2nd step is adding all partial products into a single product.
Partial products or single bit products can be obtained by using AND gates. However, to add these
partial products we need full adders & half adders.
The schematic design of a digital multiplier differs with bit size. The design becomes complex with
the increase in bit size of the multiplier.
Diagram :
66 | P a g e
CODE :
// internal registers
reg [WIDTH-1:0] A; // accumulator
reg [WIDTH-1:0] Q; // multiplier register
reg Q_1; // extra bit Q_{-1}
reg [WIDTH-1:0] M; // multiplicand (latched)
reg [WIDTH-1:0] negM; // -M (two's complement)
reg [$clog2(WIDTH+1)-1:0] cnt;// counter (enough bits to hold WIDTH)
reg [2*WIDTH:0] combined; // combined {A,Q,Q_1} for arithmetic shift
reg [1:0] state;
reg [WIDTH-1:0] tmpA;
// synchronous FSM
always @(posedge clk) begin
if (rst) begin
state <= IDLE;
A <= {WIDTH{1'b0}};
Q <= {WIDTH{1'b0}};
Q_1 <= 1'b0;
M <= {WIDTH{1'b0}};
negM <= {WIDTH{1'b0}};
cnt <= 0;
product <= {2*WIDTH{1'b0}};
done <= 1'b0;
end else begin
done <= 1'b0; // default: done only asserted for one cycle
case (state)
IDLE: begin
if (start) begin
// latch inputs and init registers
A <= {WIDTH{1'b0}};
67 | P a g e
Q <= multiplier;
M <= multiplicand;
negM <= (~multiplicand) + 1'b1; // two's complement negative
Q_1 <= 1'b0;
cnt <= WIDTH;
state<= CALC;
end
end
CALC: begin
tmpA = A;
case ({Q[0], Q_1})
2'b01: tmpA = tmpA + M; // 01 => add M
2'b10: tmpA = tmpA + negM; // 10 => subtract M
default: tmpA = tmpA; // 00 or 11 => no op
endcase
// decrement counter
if (cnt == 1) begin
product <= {combined[2*WIDTH:WIDTH+1], combined[WIDTH:1]};
done <= 1'b1;
state <= DONE;
end else begin
cnt <= cnt - 1'b1;
end
end
DONE: begin
if (!start) begin
state <= IDLE;
end else begin
state <= DONE;
end
end
68 | P a g e
end
end
endmodule
TESTBENCH :
module tb_booth;
parameter WIDTH = 4; // small width for easy viewing
reg clk, rst, start;
reg [WIDTH-1:0] multiplicand, multiplier;
wire [2*WIDTH-1:0] product;
wire done;
initial clk = 0;
always #5 clk = ~clk; // 100 MHz-ish for simulation
initial begin
rst = 1; start = 0;
multiplicand = 4'b0011; // +3
multiplier = 4'b1010; // -6 (two's complement)
#12 rst = 0;
#10 start = 1; // assert start
#10 start = 0; // deassert after one cycle
// wait for done
wait(done == 1);
#20 $finish;
end
endmodule
69 | P a g e
OUTPUT :
SCHEMATIC :
70 | P a g e
PRACTICAL 20
BARREL SHIFTER
Unlike simple shifters that move bits one at a time over multiple cycles, a barrel shifter can shift an
entire data word by any number of bits instantly. This capability is essential for high-speed processors
and digital circuits where timing and performance matter.
Barrel shifters support different types of shifts:
Diagram :
71 | P a g e
CODE :
module barrel_shifter_comb(data_in,shamt,dir,mode,data_out);
input wire [7:0] data_in; // Input word
input wire [2:0] shamt; // Shift amount (0-7)
input wire dir; // 0 = left, 1 = right
input wire [1:0] mode; // 00 = logical, 01 = rotate, 10 = arithmetic (only for right)
output reg [7:0] data_out; // Combinational output
always @(*) begin
if (shamt == 3’d0) begin
data_out = data_in;
end
else if (dir == 1’b0) begin // LEFT
if (mode == 2’b01) // Rotate Left
data_out = (data_in << shamt) | (data_in >> (8 – shamt));
else // Logical Left (same as Arithmetic Left)
data_out = data_in << shamt;
end
else begin // RIGHT
case (mode)
2’b00: data_out = data_in >> shamt; // Logical Right
2’b01: data_out = (data_in >> shamt) | (data_in << (8 – shamt)); // Rotate Right
2’b10: data_out = (data_in >> shamt) | ({8{data_in[7]}} << (8 – shamt)); // Arithmetic Right
default: data_out = data_in >> shamt;
endcase
end
end
endmodule
TESTBENCH :
module barrel_shifter_comb_tb;
// Instantiate DUT
barrel_shifter_comb uut (
.data_in(data_in),
72 | P a g e
.shamt(shamt),
.dir(dir),
.mode(mode),
.data_out(data_out)
);
initial begin
data_in = 8’b10110011; shamt = 3’d1; dir = 0; mode = 2’b00; #10;
shamt = 3’d2; dir = 0; mode = 2’b01; #10;
shamt = 3’d3; dir = 1; mode = 2’b00; #10;
shamt = 3’d4; dir = 1; mode = 2’b01; #10;
data_in = 8’b11110000; shamt = 3’d2; dir = 1; mode = 2’b10; #10;
data_in = 8’b01100100; shamt = 3’d2; dir = 1; mode = 2’b10; #10;
data_in = 8’b11001101; shamt = 3’d7; dir = 0; mode = 2’b01; #10;
shamt = 3’d0; dir = 0; mode = 2’b00; #10;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
73 | P a g e
PRACTICAL 21
ALU :
The Arithmetic Logic Unit (ALU) is the fundamental component in a computing system like a
computer. It is basically the actual data processing element within the central processing unit (CPU)
in a computing system. It performs all the arithmetic and logical operations and forms the backbone
of modern computer technology.
Arithmetic Logic Unit abbreviated as ALU is considered as the engine or heart of every central
processing unit (CPU). ALU is basically a combination logic circuit that can perform arithmetic
and logical operation on digital data (data in binary format). It can also execute instructions given
to a computing system like a digital computer.
Diagram :
CODE :
module ALU_8bit(A,B,opcode,result,zero,carry,overflow);
input [7:0] A;
input [7:0] B;
input [3:0] opcode;
output reg [7:0] result;
output reg zero;
output reg carry;
output reg overflow;
74 | P a g e
overflow = 1’b0;
tmp = 8’b0;
case (opcode)
4’b0000: begin // ADD
tmp_add = {1’b0, A} + {1’b0, B};
result = tmp_add[7:0];
carry = tmp_add[8];
overflow = (A[7] & B[7] & ~result[7]) | (~A[7] & ~B[7] & result[7]);
end
4’b0001: begin // SUB = A – B
tmp_add = {1’b0, A} – {1’b0, B};
result = tmp_add[7:0];
carry = tmp_add[8]; // note: interpretation depends on convention
overflow = (A[7] & ~B[7] & ~result[7]) | (~A[7] & B[7] & result[7]);
end
4’b0010: result = A & B;
4’b0011: result = A | B;
4’b0100: result = A ^ B;
4’b0101: result = A << B[2:0];
4’b0110: result = A >> B[2:0];
4’b0111: result = (A << B[2:0]) | (A >> (8 – B[2:0])); // ROL
4’b1000: result = (A >> B[2:0]) | (A << (8 – B[2:0])); // ROR
4’b1001: result = (A < B) ? 8’b1 : 8’b0; // SLT unsigned
default: result = A;
endcase
zero = (result == 8’b0);
end
endmodule
TESTBENCH :
module ALU_8bit_tb;
reg [7:0] A, B;
reg [3:0] opcode;
wire [7:0] result;
wire zero, carry, overflow;
initial begin
75 | P a g e
opcode = 4’b0001; #10; // SUB
opcode = 4’b0010; #10; // AND
opcode = 4’b0011; #10; // OR
opcode = 4’b0100; #10; // XOR
opcode = 4’b0101; B = 8’d2; A = 8’d3; #10; // SLL by 2
A = 8’b10010001; B = 8’d3; opcode = 4’b0111; #10; // ROL
A = 8’d3; B = 8’d7; opcode = 4’b1001; #10; // SLT
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
76 | P a g e
PRACTICAL 22
FLIP-FLOP : A latch is a fundamental sequential logic circuit that can store one bit of information.
Unlike combinational circuits, its output depends not only on the current inputs but also on the previous
state (memory).
It is a level-sensitive device, meaning its state changes when the control input (Enable/Clock) is active.
Latches are the building blocks of flip-flops, registers, and memory elements.
S-R LATCH : The SR latch is the simplest bistable multivibrator. It is a level-sensitive device that has
two inputs: S (Set) and R (Reset), and two complementary outputs: Q and Q̅.
Diagram of SR Latch:
CODE :
77 | P a g e
always @(*) begin
if (S & R) Q = 1'bx;
else if (S) Q = 1'b1;
else if (R) Q = 1'b0;
// else hold (behavioral)
end
endmodule
TESTBENCH :
module SR_latch_tb;
reg S, R;
wire Qsr, Qsrbar;
OUTPUT :
SCHEMATIC :
78 | P a g e
B. Implementation of D Latch
D LATCH : A D latch is derived from the SR latch to avoid the invalid condition. It has a single input
D (Data) and a control input (Enable/Clock). When Enable = 1: Output Q follows input D. When Enable
= 0: Output Q holds the last stored value.
CODE :
module D_latch(D,enable,Q);
input D, enable;
output reg Q;
TESTBENCH :
module D_latch_tb;
reg D, en;
wire Qd;
79 | P a g e
D_latch uut(.D(D), .enable(en), .Q(Qd));
initial begin
// D latch tests
D = 0; en = 0; #10;
D = 1; en = 1; #10; // Qd follows D
D = 0; en = 1; #10;
en = 0; D = 1; #10; // Qd holds previous
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
80 | P a g e
PRACTICAL 23
AIM : Implementation of D-latch using synchronous active high reset and active low preset.
D Latch : A D latch (Data latch) is a level-sensitive storage element that captures the input value D
whenever the clock (or enable) signal is active. Unlike flip-flops, which are edge-triggered, latches are
transparent when enabled and hold the last input value when disabled.
Functionality exhibited by D-Latch with synchronous active high reset and active low preset are:
CODE :
TESTBENCH :
module D_sync_reset_tb;
initial begin
// initial conditions
D = 0; reset_sync = 0; preset_n = 1; #10;
reset_sync = 1; #10;
D = 1; #10;
// async preset
preset_n = 0; #10; // Q should become 1 immediately (async)
preset_n = 1; #10;
D = 0; reset_sync = 1; #10;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
82 | P a g e
PRACTICAL 24
AIM : Implementation of D-latch using asynchronous active low reset and active high preset.
D Latch : A D-latch is a level-sensitive device where the output follows the input as long as the enable
signal is active. In this practical, two asynchronous control inputs are added: Active Low Reset forces
output Q = 0 immediately when asserted (independent of clock/enable). Active High Preset (P) forces
output Q = 1 immediately when asserted. These asynchronous inputs have the highest priority, ensuring
the latch can be initialized or forced into a known state regardless of data or enable.
CODE :
endmodule
TESTBENCH :
module D_async_reset_tb();
reg D, en, reset_n, preset;
wire Q;
D_aysnc_reset uut(.D(D), .enable(en), .reset_n(reset_n), .preset(preset), .Q(Q));
initial begin
reset_n = 1; preset = 0; en = 0; D = 0; #10;
en = 1; D = 1; #10; // transparent: Q=1
en = 0; D = 0; #10; // hold Q=1
preset = 1; #10; // async preset -> Q=1
preset = 0; #10;
reset_n = 0; #10; // async reset -> Q=0
reset_n = 1; #10;
en = 1; D = 1; #10; // Q follows D
83 | P a g e
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
84 | P a g e
PRACTICAL 25
AIM: Implementation of positive edge-triggered D-Flip Flop with asynchronous active high reset.
D Flip Flop : A D Flip-Flop is an edge-triggered memory element. Unlike the latch, it stores data only
on the positive (rising) edge of the clock pulse. Asynchronous Active High Reset forces output Q = 0
immediately when reset is asserted, regardless of the clock.
CODE :
TESTBENCH :
module D_FF_PE_tb;
reg clk, rst_n, D;
wire Q;
initial begin
initial begin
OUTPUT :
SCHEMATIC :
86 | P a g e
PRACTICAL 26
AIM : Implementation of negative edge-triggered D-Flip Flop with asynchronous active low reset
and active high preset.
D Flip Flop : This is a falling edge-triggered device, meaning it captures input D at the transition from
clock = 1 → 0. Active Low Reset immediately clears output Q = 0 when asserted. Active High Preset
immediately sets output Q = 1 when asserted.
CODE :
endmodule
TESTBENCH :
module dff_neg_edge_async_tb;
reg clk;
reg reset_n;
reg preset;
reg d;
wire q;
D_FF_NEG_EDGE uut (
.clk(clk),
.reset_n(reset_n),
.preset(preset),
.d(d),
.q(q)
);
87 | P a g e
initial begin
clk = 0;
forever #5 clk = ~clk;
end
initial begin
reset_n = 1; preset = 0; d = 0;
#2 reset_n = 0;
#5 reset_n = 1;
#3 preset = 1;
#5 preset = 0;
#5 d = 1;
#10 d = 0;
#10 d = 1;
#7 reset_n = 0;
#5 reset_n = 1;
#6 preset = 1;
#5 preset = 0;
#20 $finish;
end
endmodule
OUTPUT :
SCHEMATIC :
88 | P a g e
PRACTICAL 27
AIM : Implementation of synchronous positive edge-triggered D Flip Flop with active high reset
and active low preset.
D Flip Flop : This flip-flop samples input D on the rising edge of the clock. In this practical we have
used synchronous Active High Reset clears Q to 0 only on the rising clock edge when asserted and Active
Low Preset: Sets Q to 1 only on the rising clock edge when asserted. This synchronous control ensures
that state changes happen only in alignment with clock events, making the design more predictable and
avoiding asynchronous hazards. Such flip-flops are standard in synchronous counters, FSMs, and
pipeline registers.
CODE :
TESTBENCH :
module D_FF_sync_tb;
reg clk = 0;
reg rst = 0;
reg preset_n = 1;
reg d;
wire q;
D_FF_sync U(.clk(clk), .rst(rst), .preset_n(preset_n), .d(d), .q(q));
always #5 clk = ~clk;
initial begin
d = 0; #10; d = 1; #10;
rst = 1; #10; rst = 0; #10;
preset_n = 0; #10; preset_n = 1; #10;
$finish;
89 | P a g e
end
endmodule
OUTPUT :
SCHEMATIC :
90 | P a g e
PRACTICAL 28
Bidirectional SISO : A shift register is a sequential circuit that shifts data bits on every clock pulse. In
a 5-bit bidirectional SISO register, data can be shifted either left or right serially. Serial Input (SI): Data
enters bit-by-bit. Direction Control: Determines left/right shifting. Serial Output (SO): Outputs the last
shifted bit. This circuit is widely used in serial communication, time-delay generation, and data
movement between subsystems.
CODE :
TESTBENCH :
module SISO_BIDI_tb;
reg clk = 0;
reg rst;
reg en;
reg dir;
reg serial_in;
wire serial_out;
wire [4:0] q;
SISO_BIDI uut(.clk(clk), .rst(rst), .en(en), .dir(dir), .serial_in(serial_in), .serial_out(serial_out),
.q(q));
always #5 clk = ~clk;
91 | P a g e
initial begin
OUTPUT :
SCHEMATIC :
92 | P a g e
PRACTICAL 29
RAM : Random Access Memory (RAM) stores data in addressable locations. A 64-byte single port
RAM has:
1. Single Port: Same interface for read and write.
2. Address Lines: Select the storage location.
3. Data Input/Output Lines: Provide data to/from memory.
4. Control Signals (Read/Write/Enable): Determine operation.
CODE :
TESTBENCH :
module RAM_64x8_tb;
reg clk = 0;
reg we;
reg [5:0] addr;
reg [7:0] din;
wire [7:0] dout;
RAM_64x8 U(.clk(clk), .we(we), .addr(addr), .din(din), .dout(dout));
always #5 clk = ~clk;
initial begin
OUTPUT :
SCHEMATIC :
94 | P a g e
PRACTICAL 30
AIM : Implementation of 5-bit universal shift register with serial-in serial-out (SISO), serial-in-
parallel-out (SIPO), parallel-in parallel-out (PIPO), parallel-in-serial-out (PISO) options.
Universal Shift Register : A universal shift register can perform multiple operations:
CODE :
endmodule
95 | P a g e
TESTBENCH :
module univ_shift_reg_tb;
reg clk = 0;
reg rst;
reg [1:0] mode;
reg shift_en;
reg serial_in;
reg [4:0] parallel_in;
wire [4:0] parallel_out;
wire serial_out;
// Instantiate DUT
univ_shift_reg U (
.clk(clk),
.rst(rst),
.mode(mode),
.shift_en(shift_en),
.serial_in(serial_in),
.parallel_in(parallel_in),
.parallel_out(parallel_out),
.serial_out(serial_out)
);
initial begin
// Reset
rst = 1; shift_en = 0; mode = 2'b00; serial_in = 0; parallel_in = 5'b0;
#12 rst = 0;
mode = 2'b10; parallel_in = 5'b10101; #10; // load parallel_in into register
mode = 2'b11; shift_en = 1; #50; // shift-right, observe serial_out
mode = 2'b00; serial_in = 1; shift_en = 1;
#10 serial_in = 0;
#10 serial_in = 1;
#20;
mode = 2'b01; serial_in = 1; shift_en = 1; #10;
serial_in = 0; #10;
serial_in = 1; #10;
serial_in = 1; #10;
96 | P a g e
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
97 | P a g e
PRACTICAL 31
FIFO : FIFO(First-In-First-Out) is a basic memory structure that finds widespread application in VLSI
design to perform data buffering and communication between system blocks. FIFO permits data to be
read and written in the same order in which it was inputted, which makes it well-suited to those
applications where preserving the order of data is of paramount importance.
There are two primary types of FIFOs in VLSI design: synchronous FIFO and asynchronous FIFO
1. Synchronous FIFO: A synchronous FIFO has one clock domain in which read and write operations
are both driven by the same clock. This keeps the design simple since there is no requirement to
cross the clock domain.
2. Asynchronous FIFO: An asynchronous FIFO is utilized to support operations of writing and reading
in separate clock domains. This adds complexity because data transfer between clock domains has
to be done in a safe manner.
98 | P a g e
• Dual-Ported Memory: Permits read and write operations in different clock domains
simultaneously. Write Pointer (in write clock domain): Tracks where to write the data.
• Read Pointer (read clock domain): Keeps track of the location to read the data.
• Synchronization Logic: Synthesizes safely the pointers between the two clock domains.
• Control Logic: Handles full and empty flags.
CODE :
module FIFO #(
parameter DATA_W = 8,
parameter DEPTH = 8,
parameter PTR_W = 3
)
(
input wire clk,
input wire rst, // synchronous active-high reset
input wire wr_en,
input wire rd_en,
input wire [DATA_W-1:0] din,
output reg [DATA_W-1:0] dout,
output wire full,
output wire empty
);
99 | P a g e
wr_ptr <= 0; rd_ptr <= 0; count <= 0; dout <= 0;
for (i=0;i<DEPTH;i=i+1) mem[i] <= 0;
end else begin
if (wr_en && !full) begin
mem[wr_ptr] <= din;
wr_ptr <= wr_ptr + 1;
count <= count + 1;
end
if (rd_en && !empty) begin
dout <= mem[rd_ptr];
rd_ptr <= rd_ptr + 1;
count <= count - 1;
end
end
end
endmodule
TESTBENCH :
module FIFO_tb(
);
reg clk = 0;
reg rst;
reg wr_en, rd_en;
reg [7:0] din;
wire [7:0] dout;
wire full, empty;
FIFO #(.DATA_W(8), .DEPTH(8), .PTR_W(3)) U(.clk(clk), .rst(rst), .wr_en(wr_en), .rd_en(rd_en),
.din(din), .dout(dout), .full(full), .empty(empty));
always #5 clk = ~clk;
initial begin
100 | P a g e
end
endmodule
OUTPUT :
SCHEMATIC :
101 | P a g e
PRACTICAL 32
AIM : Implementation of 8-bit binary up/down counter with load and active high reset facilities.
Binary Up/Down Counter : A counter is a sequential circuit that advances through a sequence of states.
An 8-bit up/down counter:
CODE :
TESTBENCH :
module up_down_8bit_tb();
reg clk = 0;
reg rst;
reg load;
reg up;
reg [7:0] data_in;
wire [7:0] count;
up_down_8bit U(.clk(clk), .rst(rst), .load(load), .up(up), .data_in(data_in), .count(count));
102 | P a g e
always #5 clk = ~clk;
initial begin
up = 1; #50;
up = 0; #50;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
103 | P a g e
PRACTICAL 33
AIM: Implementation of modulo-47 up counter with load and active high reset facilities.
Modulo-N Counter : A Modulo-N counter counts up to N−1 and then rolls over to zero. For mod-47:
This design is commonly applied in frequency dividers, digital clocks (e.g., mod-60 for minutes), and
state machines requiring restricted count ranges.
CODE :
endmodule
TESTBENCH :
module mod_47_tb;
reg clk = 0;
reg rst;
reg load;
reg [5:0] data_in;
104 | P a g e
wire [5:0] count;
mod_47 U ( .clk(clk), .rst(rst), .load(load),.data_in(data_in),.count(count));
always #5 clk = ~clk;
initial begin
// Initialize inputs
rst = 0; load = 0; data_in = 6'd0;
#2 rst = 1;
#10 rst = 0; // release reset
repeat (10) @(posedge clk);
load = 1; data_in = 6'd10;
@(posedge clk);
load = 0;
repeat (50) @(posedge clk);
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
105 | P a g e
PRACTICAL 34
Clock Frequency Divider : A frequency divider reduces the frequency of an input clock signal by an
integer factor N. Divide-by-2 is achieved using a toggle flip-flop; output frequency is half of the input.
Divide-by-3, Divide-by-4 is implemented using counters that reset after counting N pulses. Frequency
dividers are essential in digital systems for clock generation, baud rate control, and multi-speed
operations in processors.
CODE :
106 | P a g e
TESTBENCH :
module clk_freq_div_tb;
reg clk = 0;
reg rst;
reg [1:0] divsel;
wire clk_out;
clk_freq_div U(.clk(clk), .rst(rst), .divsel(divsel), .clk_out(clk_out));
always #5 clk = ~clk;
initial begin
rst = 1; divsel = 2'b00; #12; rst = 0;
divsel = 2'b00; #100;
divsel = 2'b01; #120;
divsel = 2'b10; #120;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
107 | P a g e
PRACTICAL 35
AIM : Implementation of 010 non-overlapping sequence detector using Mealy finite-state machine
(FSM).
FSM : A Finite State Machine (FSM) is a sequential circuit model that transitions between a finite
number of states based on inputs and generates outputs. It is widely used to design control logic,
sequence detectors, and protocol controllers.
1. Mealy Machine: Output depends on present state + inputs. Faster response since output can change
immediately with input. Output may glitch if inputs change near clock edge.
2. Moore Machine: Output depends only on present state. More stable output (changes only on state
transitions). May require more states than Mealy for same function.
Overlapping Sequence: Detected sequence bits can be reused for the next detection (e.g., in 010101,
multiple detections occur).
CODE :
TESTBENCH :
module non_overlap_mealy_tb;
reg clk = 0;
reg rst;
reg in_bit;
wire detected;
non_overlap_mealy U(.clk(clk), .rst(rst), .in_bit(in_bit), .detected(detected));
always #5 clk = ~clk;
initial begin
rst = 1; in_bit = 0; #12; rst = 0;
in_bit = 0; #10; in_bit = 1; #10; in_bit = 0; #10;
in_bit = 0; #10; in_bit = 1; #10; in_bit = 0; #10;
in_bit = 1; #10; in_bit = 0; #10; in_bit = 1; #10;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
109 | P a g e
PRACTICAL 36
AIM : Implementation of 110 non-overlapping sequence detector using Moore finite-state machine
(FSM).
FSM : A Moore FSM produces outputs based only on the present state. For 110 detection, the FSM
changes states as inputs arrive and asserts detection output when the full sequence is matched. Non-
overlapping: After detection, the FSM resets to initial state before starting a new match.
This approach ensures stable outputs, as they change only on state transitions. Applications include
control circuits and data framing in communication.
Non-overlapping: Once a sequence is detected, the FSM resets before detecting again; bits are not
reused.
CODE :
110 | P a g e
TESTBENCH :
module non_overlap_moore_tb;
reg clk = 0;
reg rst;
reg in_bit;
wire detected;
non_overlap_moore U(.clk(clk), .rst(rst), .in_bit(in_bit), .detected(detected));
always #5 clk = ~clk;
initial begin
rst = 1; in_bit = 0; #12; rst = 0;
in_bit = 1; #10; in_bit = 1; #10; in_bit = 0; #10;
in_bit = 1; #10; in_bit = 1; #10; in_bit = 0; #10;
in_bit = 1; #10; in_bit = 1; #10; in_bit = 1; #10; in_bit = 0; #10;
$finish;
end
endmodule
OUTPUT :
SCHEMATIC :
111 | P a g e
PRACTICAL 37
AIM : Implementation of 0101 overlapping sequence detector using Mealy finite-state machine
(FSM).
CODE :
TESTBENCH :
module overlap_mealy_tb;
reg clk = 0;
reg rst;
reg in_bit;
wire detected;
112 | P a g e
overlap_mealy U(.clk(clk), .rst(rst), .in_bit(in_bit), .detected(detected));
always #5 clk = ~clk;
initial begin
OUTPUT :
SCHEMATIC :
113 | P a g e
PRACTICAL 38
AIM : Implementation of 1101 overlapping sequence detector using Moore finite-state machine
(FSM).
CODE :
TESTBENCH :
module overlap_moore_tb;
reg clk = 0;
reg rst;
114 | P a g e
reg in_bit;
wire detected;
overlap_moore U(.clk(clk), .rst(rst), .in_bit(in_bit), .detected(detected));
always #5 clk = ~clk;
initial begin
OUTPUT :
SCHEMATIC :
115 | P a g e
PRACTICAL 39
AIM : Implementation of nMOS and pMOS as pass transistors using switch level modelling.
THEORY :
Pass transistor logic (PTL) is a digital logic design technique that uses transistors as switches to
implement logic functions, offering advantages like reduced transistor count and lower power
consumption, but it also has limitations such as voltage level degradation.
Overview of Pass Transistor Logic: Pass transistor logic utilizes MOSFETs (Metal-Oxide-
Semiconductor Field-Effect Transistors) to transfer logic levels between nodes in a circuit. Unlike
traditional CMOS logic, which uses transistors to create strong logic levels (high and low), PTL relies
on the ability of transistors to pass signals, which can lead to voltage drops and weaker logic levels.
1. Advantages of PTL
• Reduced Transistor Count: PTL can implement logic functions using fewer transistors compared
to conventional CMOS logic. For example, an AND gate can be constructed with just one NMOS
transistor and a pull-down resistor, while a CMOS implementation typically requires six
transistors.
• Lower Power Consumption: Fewer transistors mean lower power usage, making PTL suitable
for low-power applications.
• Faster Operation: PTL circuits can operate faster due to the reduced capacitance from fewer
transistors, which can lead to quicker signal transitions.
2. Disadvantages of PTL
• Voltage Level Degradation: One of the main drawbacks of PTL is that it does not restore voltage
levels. The output voltage may be lower than the supply voltage (VDD) due to the resistance of
the pass transistors, leading to what is known as a "weak 1" or "weak 0".
• Increased RC Delay: The resistance of the pass transistors can introduce delays in charging the
next stage's input capacitance, which may affect performance in high-speed applications.
• Floating Outputs: When a pass transistor is turned off, the output can become floating, which
may lead to undefined logic levels unless additional circuitry (like pull-up or pull-down resistors)
is used.
3. Applications of PTL: Pass transistor logic is often used in applications where low power and
reduced area are critical, such as in multiplexers, latches, and certain types of memory cells. It is
116 | P a g e
particularly useful in designs where speed is essential, and the trade-offs of voltage degradation
can be managed effectively.
nMOS Transistor as Pass Transistor: An nMOS transistor is effective at passing a low voltage (Logic
'0') but is poor at passing a high voltage (Logic '1').
pMOS Transistor as Pass Transistor: An nMOS transistor is effective at passing a low voltage (Logic
'0') but is poor at passing a high voltage (Logic '1').
CODE :
117 | P a g e
TESTBENCH :
module tb_pass_transistors;
reg in, ctrl;
wire out_n, out_p;
// Instantiate DUT
pass_transistors U1 (.in(in), .ctrl(ctrl), .out_n(out_n), .out_p(out_p));
initial begin
$finish;
end
endmodule
OUTPUT :
118 | P a g e
PRACTICAL 40
THEORY :
A Transmission Gate (T-gate or TG or pass gate) is a bi-directional switch made up of an NMOS and
PMOS in parallel. A control signal is connected to the gate of the NMOS (C) and its complement is sent
to the gate of the PMOS (C’)
The T-gate is a bidirectional switch between A (input) and B (output) which is controlled by C (control
signal, select line, enable signal etc.).
Working of TG:
• When the control signal is HIGH (VDD): Both transistors are turned on, a low resistance path exists
between A and B and I/P A is transmitted to the O/P B.
• When the control signal is LOW (0v): Both transistors are off, the T-gate looks like an open circuit
This type of operation is commonly used in bus situations where only one gate can drive the bus line at
the same time. T-gates are put on the output of each gate on the bus. The circuit that drives will use a T-
gate to connect to the bus with a low impedance path. All other circuits that aren’t driving will switch
their T-gates to be a high-impedance.
CODE :
TESTBENCH :
module tb_transmission_gate;
reg in, en;
wire out;
transmission_gate U1 (out, in, en);
initial begin
in=0; en=0; #10;
in=1; en=0; #10;
in=0; en=1; #10;
in=1; en=1; #10;
in=0; en=1; #10;
$finish;
end
endmodule
OUTPUT :
120 | P a g e
PRACTICAL 41
THEORY :
A 3-input NAND gate in complementary CMOS is implemented using six transistors: three pMOS
transistors connected in parallel (the pull-up network) and three nMOS transistors connected in series
(the pull-down network).
This arrangement ensures that the output is always driven strongly to either Logic '1' or Logic '0',
eliminating the "weak" outputs seen in single-transistor logic.
The Boolean function for a 3-input NAND gate with inputs A, B, and C is:
• Implementation: Three nMOS transistors must be connected in series between the output and Ground
(GND). For the path to conduct, all three switches must be closed.
• pMOS transistors are ON (closed switch) when their gate is LOW (Logic '0').
• Implementation: Three pMOS transistors must be connected in parallel between and the output. For
the path to conduct, at least one switch must be closed.
121 | P a g e
Fig: 3- input NAND Gate
CODE :
122 | P a g e
TESTBENCH :
module nand3_switch_tb;
reg A, B, C;
wire Y;
nand3_switch U1 (Y, A, B, C);
initial begin
{A,B,C}=3'b000; #10;
{A,B,C}=3'b001; #10;
{A,B,C}=3'b010; #10;
{A,B,C}=3'b011; #10;
{A,B,C}=3'b100; #10;
{A,B,C}=3'b101; #10;
{A,B,C}=3'b110; #10;
{A,B,C}=3'b111; #10;
$finish;
end
endmodule
OUTPUT :
123 | P a g e
PRACTICAL 42
DIAGRAM :
CODE :
wire pu1;
pmos (pu1, Vdd, A); // A=0 -> ON
pmos (Y, pu1, nB); // B=1 -> ON
wire pu2;
pmos (pu2, Vdd, nA); // A=0 -> ON
pmos (Y, pu2, B); // B=0 -> ON
wire pd1;
nmos (pd1, Gnd, A);
nmos (Y, pd1, B);
124 | P a g e
wire pd2;
nmos (pd2, Gnd, nA);
nmos (Y, pd2, nB);
endmodule
TESTBENCH :
`timescale 1ns/1ps
module tb_xor2_switch;
reg A, B;
wire Y;
initial begin
A=0; B=0; #20; // Y=0
A=0; B=1; #20; // Y=1
A=1; B=0; #20; // Y=1
A=1; B=1; #20; // Y=0
$finish;
end
endmodule
OUTPUT :
125 | P a g e
PRACTICAL 43
DIAGRAM :
CODE :
output Y;
input D0;
input D1;
input S;
supply1 Vdd;
supply0 Gnd;
wire nS;
not (nS, S);
// ----------------------------------------
// Transmission gate for D0 (enabled when S=0)
// ----------------------------------------
// PMOS passes D0 strongly when S=0
pmos (Y, D0, S); // PMOS ON when S=0
126 | P a g e
nmos (Y, D0, nS); // NMOS ON when S'=1
// ----------------------------------------
// Transmission gate for D1 (enabled when S=1)
// ----------------------------------------
pmos (Y, D1, nS); // PMOS ON when S'=0
nmos (Y, D1, S); // NMOS ON when S=1
endmodule
TESTBENCH :
`timescale 1ns/1ps
module tb_mux2to1_switch;
initial begin
// Test patterns
D0=0; D1=1;
D0=1; D1=0;
S=0; #20; // Expect Y = D0 = 1
S=1; #20; // Expect Y = D1 = 0
$finish;
end
endmodule
OUTPUT :
127 | P a g e