0% found this document useful (0 votes)
47 views127 pages

Digital VLSI Design Laboratory Manual

The document is a laboratory manual for Digital VLSI Design, detailing various experiments related to programming logic devices, Verilog HDL, and digital circuit design. It includes a list of experiments, practical aims, and modeling techniques such as structural, dataflow, and behavioral modeling. Additionally, it outlines installation steps for the Vivado EDA tool and provides examples of implementing Boolean functions using different modeling styles.

Uploaded by

alkasinghr2003
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)
47 views127 pages

Digital VLSI Design Laboratory Manual

The document is a laboratory manual for Digital VLSI Design, detailing various experiments related to programming logic devices, Verilog HDL, and digital circuit design. It includes a list of experiments, practical aims, and modeling techniques such as structural, dataflow, and behavioral modeling. Additionally, it outlines installation steps for the Vivado EDA tool and provides examples of implementing Boolean functions using different modeling styles.

Uploaded by

alkasinghr2003
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

Digital VLSI Design

(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

Implementation of any two simple Boolean functions


4 (minimum 03 input) with the help of structural, dataflow, and 2
behavioural modelling styles.
Implementation of 1-bit Half-Adder (HA) using three modelling
5 2
styles.
Implementation of 1-bit Full-Adder (FA) using 1-bit HA (Design
6 2
Reuse Technique).
Implementation of 1-bit Full-Adder (FA) using three modelling
7 2
styles.
Implementation of 4-bit Ripple Carry Adder (RCA) using 1-bit FA
8 (Design Reuse Technique). Implementation of 4-bit and 8bit RCAs 2
using dataflow modelling.
Implement 4-bit universal adder (adder cum subtractor) using RCA
9
technique and dataflow modelling.
Self-
10 Implementation of 4-bit Carry Look-Ahead Adder (CLA) Exerci
11 Implementation of 4-bit Carry Select Adder (CSA) se for
slot-2
12 Implementation of BCD Adder
13 Implementation of 4-bit Comparator 3
Implementation of Multiplexers: 2-to-1, 4-to-1, 8-to-1, 16-to-1
14 3
using dataflow and behavioural modelling.
Implementation of MUX: 4-to-1 using 2-to-1, 8-to-1 using 4-to1
15 3
and 2-to-1 (Design Reuse Technique).
Implementation of Decoders: 2-to-4, 3-to-8, 4-to-16 using
16 3
dataflow and behavioural modelling.
Implementation of Decoders: 3-to-8 using 2-to-4, 4-to-16 using 2-
17 3
to-4 or 3-to-8 (Design Reuse Technique).
18 Implementation of a Priority Encoder 3
19 Implementation of a 4-bit Multiplier Self
Exerci
20 Implementation of 8-bit barrel shifter se for
21 Implementation of 8-bit ALU slot-3

2|Page
Implementation of Sequential Logic Designs using Verilog

Implementation of S-R and D-latches using behavioural


22 4
modelling
Implementation of D-latch using synchronous active high reset and
23 4
active low preset.
Implementation of D-latch using asynchronous active low reset
24 4
and active high preset.
Implementation of positive edge-triggered D-Flipflop with
25 4
asynchronous active high reset.
Implementation of negative edge-triggered D-Flipflop with
26 4
asynchronous active low reset and active high preset.
Implementation of synchronous positive edge-triggered Flipflop
27 4
with active high reset and active low preset.
Implementation of 5-bit bidirectional serial-in-serial-out
28 4
(SISO) shift register.
Implementation of 64-byte single port random-access memory
29
(RAM).
Implementation of 5-bit universal shift register with serial-in Self
Exerci
30 serial-out (SISO), serial-in-parallel-out (SIPO), parallel-in se for
parallel-out (PIPO), parallel-in-serial-out (PISO) options. slot-4

Implementation of single clock first-in-first-out (FIFO) structure.


31

Implementation of 8-bit binary up/down counter with load and


32 5
active high reset facilities.
Implementation of modulo-47 up counter with load and active high
33 5
reset facilities.
Implementation of clock frequency divider: divide-by-2, divideby-
34 5
3, divide-by-4.
Implementation of 010 non-overlapping sequence detector using
35 5
Mealy finite-state machine (FSM).
Implementation of 110 non-overlapping sequence detector using
36 5
Moore finite-state machine (FSM).
Implementation of 0101 overlapping sequence detector using
37 Self
Mealy finite-state machine (FSM). Exerci
se for
Implementation of 1101 overlapping sequence detector using
38 slot-5
Moore finite-state machine (FSM).
Implementation of Logic Designs using Switch Level Modelling in Verilog
Implementation of nMOS and pMOS as pass transistors using
39 6
switch level modelling.

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.

There are two main types of PLDs:

• CPLD (Complex Programmable Logic Device): A CPLD is composed of a group of logic


blocks that are interconnected by a programmable interconnection matrix. Each logic block is
essentially a macrocell containing a sum-of-products logic and a flip-flop. CPLDs have a more
predictable timing characteristic due to their structured, coarse-grained architecture. They are
well-suited for smaller designs, implementing glue logic, and simple control applications.
• FPGA (Field-Programmable Gate Array): An FPGA is a more advanced PLD with a higher
density of logic. Its architecture consists of a large array of configurable logic blocks (CLBs),
I/O blocks, and a vast network of programmable interconnects. FPGAs are highly flexible and
can be used to implement complex, high-performance designs, including entire system-on-
chips (SoCs). They are ideal for applications requiring parallel processing and high-speed data
manipulation.

5|Page
PRACTICAL 2
AIM : Introduction to Front-End designing EDA tool : VIVADO installation and Designing
steps

Part A: Vivado Installation


1. Download: Navigate to the official Xilinx (now AMD) website. Locate the Vivado Design
Suite download page. Choose the appropriate version for your operating system (Windows or
Linux). You will likely need to create a free account to download the software.
2. Installer: Run the downloaded installer. Select the Vivado Design Suite option. The installer
will guide you through the process.
3. Component Selection: During installation, you will be prompted to select which components
to install. To save disk space, it's recommended to select only the Vivado HL Design Edition
and the device families relevant to your lab (e.g., Artix-7, Kintex-7, etc.).
4. License: Vivado offers a free Vivado WebPACK license, which is sufficient for many student
projects and supports a wide range of devices. The installer will prompt you to obtain this
license and link it to your account.
5. Completion: Follow the on-screen instructions to complete the installation. Vivado is a large
program, so the installation may take a significant amount of time.

Part B: Vivado Design Steps


The Vivado design flow is a systematic process for taking a digital circuit design from concept to a
working hardware implementation.

1. Create a New Project:


• Launch Vivado and select "Create Project".
• Provide a project name and location.
• Choose RTL Project and ensure "Do not specify sources at this time" is checked.
• In the Default Part window, select the specific FPGA device you are using for your
experiment.
2. Add Design Sources:
• In the Sources pane, click the + button to add design sources.
• Select "Create File" and choose Verilog as the file type. Give it a logical name (e.g.,
half_adder.v).
• Write your Verilog code for the circuit (e.g., a half-adder, full-adder, etc.).
6|Page
3. Add Constraints File:
• Click the + button in the Sources pane again and select "Add or Create Constraints".
• Create a new XDC (Xilinx Design Constraints) file. This file specifies how your top-level
signals (input, output) connect to the physical pins on the FPGA board.
4. Simulation:
• Create a testbench file (e.g., tb_half_adder.v) by adding a new Verilog source.
• In the Flow Navigator pane on the left, click "Run Simulation" -> "Run Behavioral
Simulation". This will open the Vivado Simulator, where you can view waveforms and check
if your circuit logic is correct.
5. Synthesis:
• Once the simulation passes, go to the Flow Navigator and click "Run Synthesis".
• Vivado will translate your Verilog code into a gate-level netlist optimized for the target FPGA.
6. Implementation:
• After synthesis completes, click "Run Implementation" in the Flow Navigator.
• This step includes Placing the logic onto the FPGA's resources and Routing the
interconnections between them.
7. Generate Bitstream:
• After implementation, click "Generate Bitstream".
• This process creates the .bit file, which is the final configuration file that will be loaded onto
the physical FPGA device.
8. Program the Device:
• Connect your FPGA board to your computer via a USB cable.
• In Vivado, click "Open Hardware Manager".
• Click "Open Target" and select your connected board.
• Finally, right-click the device in the hardware window and select "Program Device". Choose
the .bit file you generated to program the FPGA. The design is now running on the physical
hardware.

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.

Example: 2-to-1 Multiplexer (MUX)

• 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:

module bool_impl( a, b, c, y);


input a;
input b;
input c;
output y;
//Gate-Level Modelling //Structural-Level Modelling
wire w1,w2,w3,w4;
and A1(w1,a,b);
and A2(w2,b,c);
and A3(w3,a,c);
or O1(w4,w1,w2);
or O2(y,w3,w4);
endmodule

2. Data-Flow Modelling

module bool_impl1( a, b, c, y);


input a;
input b;
input c;
output y
//Data-Flow Modelling
assign y = (a&b)|(b&c)|(a&c);
endmodule

3. Behavioural Modelling

module bool_impl2( a, b, c, y);


input a;
input b;
input c;
output reg y;
always @ (*)
10 | P a g e
begin
y = (a&b) | (b&c) | (a&c);
endmodule

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

module bool_impl(a, b, c, y);


input a;
input b;
input c;
output y;
wire w1,w2,w3;
xor x1(w1,a,b);
and A1(w2,c,w1);
and A2(w3,a,c);
or O1(y,w2,w3);
endmodule

2. Data Flow Modelling

module bool_impl(a, b, c, y);


input a;
input b;
input c;
output y;
assign y = ((a^b)&c) | (a&c);
endmodule

3. Behavioural Modelling

module bool_impl(a, b, c, y);


input a;
input b;
input c;
output reg y;
always @ (*)
begin
y = ((a^b)&c) | (a&c);
end
endmodule

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

AIM : Implementation of 1-bit Half-Adder (HA) using three modelling styles.

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).

Expression for sum and carry:

Sum = a ^ b
Carry = a & b

The truth table for half adder can be given as:

Diagram :

CODE :

1. Structural Modelling

module half_adder(a, b, sum, carry);


input a;
input b;
output sum;
output carry;

14 | P a g e
xor X1(sum,a,b);
and A1(carry,a,b);
endmodule

2. Data Flow Modelling

module half_adder(a, b, sum, carry);


input a;
input b;
output sum;
output carry;
assign sum = a^b;
assign carry = a&b;
endmodule

3. Behavioural Modelling

module half_adder(a, b, sum, carry);


input a;
input b;
output reg sum,carry;
always @ (*)
begin
sum = a^b;
carry = a&b;
end

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

Cout = (A&B) | (A^B)Cin

The truth table for a full adder can be given as:

Diagram :

CODE :

module full_adder_ha(A, B, Cin, Sum, Cout);


wire s1,c1,c2;
half_adder HA1(A,B,s1,c1);
half_adder HA2(s1,Cin,Sum,c2);
17 | P a g e
assign Cout = c1 | c2;
endmodule

The module used here is Half Adder module which is included in project files (source files).

module half_adder( a,b,sum,carry);


input a,
input b,
output sum,
output carry

assign sum = a^b;


assign carry = a&b;

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

AIM : Implementation of 1-bit Full-Adder (FA) using three modelling styles.

CODE :

1. Structural Modelling

module full_adder_ms(A, B, Cin, Sum, Cout);


input A;
input B;
input Cin;
output Sum;
output Cout;
wire w1,w2;
xor X1(w1,A,B);
xor X2(Sum,w1,Cin);
and a1(w2,A,B);
and a2(Cout,w1,Cin);
endmodule

2. Data-Flow Modelling

module full_adder_ms(A, B, Cin, Sum, Cout);


input A;
input B;
input Cin;
output Sum;
output Cout;
assign Sum = A^B^Cin;
assign Cout = (A&B)|(B&Cin)|(A&Cin);
endmodule

3. Behavioral Modelling

module full_adder_ms(A, B, Cin, Sum, Cout);


input A;
input B;
input Cin;
output Sum;
output Cout;
reg Sum,Cout;

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).

The Boolean expressions for i-th bit are:

Si = Aᵢ ^ Bᵢ ^ Cᵢ

Cᵢ₊₁ = (Aᵢ & Bᵢ) | (Bᵢ & Cᵢ) | (Cᵢ & Aᵢ)
Diagram :

A. 4-bit RCA using 1 bit FA

CODE :

module rca_full_adder(A, B, Cin, Sum, Cout);


input [3:0] A;
input [3:0] B;
input Cin;
output [3:0] Sum;
output Cout;
wire c1,c2,c3;
full_adder_ms FA0(.A(A[0]), .B(B[0]), .Cin(Cin), .Sum(Sum[0]), .Cout(c1));
23 | P a g e
full_adder_ms FA1(.A(A[1]), .B(B[1]), .Cin(c1), .Sum(Sum[1]), .Cout(c2));
full_adder_ms FA2(.A(A[2]), .B(B[2]), .Cin(c2), .Sum(Sum[2]), .Cout(c3));
full_adder_ms FA3(.A(A[3]), .B(B[3]), .Cin(c3), .Sum(Sum[3]), .Cout(Cout));
endmodule

TESTBENCH :

module rca_full_adder_tb;
reg [3:0] A,B;
reg Cin;
wire [3:0] Sum;
wire Cout;

rca_full_adder uut(.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(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 :

B. Implementation of 4-bit RCA using data-flow modelling

CODE :

module rca_4bit (A, B, Cin, Sum, Cout);


input [3:0] A;
input [3:0] B;
input Cin;
output [3:0] Sum;
output Cout;
wire c1, c2, c3; // Internal carry wires
assign {c1, Sum[0]} = A[0] + B[0] + Cin;
assign {c2, Sum[1]} = A[1] + B[1] + c1;
assign {c3, Sum[2]} = A[2] + B[2] + c2;
assign {Cout, Sum[3]} = A[3] + B[3] + c3;
endmodule

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 :

module rca_8bit (A, B, Cin, Sum, Cout);


input [7:0] A;
input [7:0] B;
input Cin;
output [7:0] Sum;
output Cout;
wire c1, c2, c3, c4, c5, c6, c7; // Internal carry wires
assign {c1, Sum[0]} = A[0] + B[0] + Cin;
assign {c2, Sum[1]} = A[1] + B[1] + c1;
assign {c3, Sum[2]} = A[2] + B[2] + c2;
assign {c4, Sum[3]} = A[3] + B[3] + c3;
assign {c5, Sum[4]} = A[4] + B[4] + c4;
assign {c6, Sum[5]} = A[5] + B[5] + c5;
assign {c7, Sum[6]} = A[6] + B[6] + c6;
assign {Cout, Sum[7]} = A[7] + B[7] + c7;

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;

assign B_mod = B ^ {4{M}}; // If M=1, B is 1's complemented //Replication Operator


assign Cin = M; // Add 1 if subtraction

assign Sum[0] = A[0] ^ B_mod[0] ^ Cin;


assign carry[0] = (A[0] & B_mod[0]) | (B_mod[0] & Cin) | (A[0] & Cin);

assign Sum[1] = A[1] ^ B_mod[1] ^ carry[0];


assign carry[1] = (A[1] & B_mod[1]) | (B_mod[1] & carry[0]) | (A[1] & carry[0]);
assign Sum[2] = A[2] ^ B_mod[2] ^ carry[1];
assign carry[2] = (A[2] & B_mod[2]) | (B_mod[2] & carry[1]) | (A[2] & carry[1]);

assign Sum[3] = A[3] ^ B_mod[3] ^ carry[2];


assign Cout = (A[3] & B_mod[3]) | (B_mod[3] & carry[2]) | (A[3] & carry[2]);

endmodule

TESTBENCH :

module univ_adder_4bit_tb;

reg [3:0] A, B;
reg M;
wire [3:0] Sum;
wire Cout;

// Instantiate the Unit Under Test (UUT)


univ_adder_4bit uut (
.A(A),
.B(B),
.M(M),
.Sum(Sum),
.Cout(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

AIM : Implementation of 4-bit Carry Look-Ahead Adder (CLA).

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.

Expressions for Generate and Propagate logic can be given as:

Generate Gi = Aᵢ & Bᵢ

Propagate Pi = Aᵢ ^ Bᵢ

The carry expression at each stage can be given as:


C1 = G0 + (P0 & C0)

Diagram :

CODE :

module CLA_adder(A, B, Cin, Sum, Cout);


input [3:0] A;
input [3:0] B;
32 | P a g e
input Cin;
output [3:0] Sum;
output Cout;
wire [3:0] G, P;
wire c1, c2, c3;
assign G = A & B;
assign P = A ^ B;

// Carry Lookahead Logic


assign c1 = G[0] | (P[0] & Cin);
assign c2 = G[1] | (P[1] & G[0]) | (P[1] & P[0] & Cin);
assign c3 = G[2] | (P[2] & G[1]) | (P[2] & P[1] & G[0]) | (P[2] & P[1] & P[0] & Cin);
assign Cout = G[3] | (P[3] & G[2]) | (P[3] & P[2] & G[1]) | (P[3] & P[2] & P[1] & G[0]) (P[3] &
P[2] & P[1] & P[0] & Cin);

// 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;

CLA_adder uut (.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(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

AIM: Implementation of 4-bit Carry Select Adder (CSA).

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:

1. One sum and carry assuming the carry-in = 0.


2. Another sum and carry assuming the carry-in = 1.

Diagram :

CODE :

module CSA_adder(A, B, Cin, Sum, Cout);


input [3:0] A,
input [3:0] B,
input Cin,
output [3:0] Sum,
output Cout
wire [3:0] sum0, sum1;
wire c0, c1;

// Case 1: Cin = 0

35 | P a g e
assign sum0[0] = A[0] ^ B[0];
assign c0 = A[0] & B[0];

assign sum0[1] = A[1] ^ B[1] ^ c0;


wire c01 = (A[1] & B[1]) | (A[1] & c0) | (B[1] & c0);

assign sum0[2] = A[2] ^ B[2] ^ c01;


wire c02 = (A[2] & B[2]) | (A[2] & c01) | (B[2] & c01);

assign sum0[3] = A[3] ^ B[3] ^ c02;


wire c03 = (A[3] & B[3]) | (A[3] & c02) | (B[3] & c02);

// Case 2: Cin = 1
assign sum1[0] = A[0] ^ B[0] ^ 1;
assign c1 = (A[0] & B[0]) | (A[0] & 1) | (B[0] & 1);

assign sum1[1] = A[1] ^ B[1] ^ c1;


wire c11 = (A[1] & B[1]) | (A[1] & c1) | (B[1] & c1);

assign sum1[2] = A[2] ^ B[2] ^ c11;


wire c12 = (A[2] & B[2]) | (A[2] & c11) | (B[2] & c11);

assign sum1[3] = A[3] ^ B[3] ^ c12;


wire c13 = (A[3] & B[3]) | (A[3] & c12) | (B[3] & c12);

// Select based on actual Cin


assign Sum = (Cin == 1'b0) ? sum0 : sum1;
assign Cout = (Cin == 1'b0) ? c03 : c13;
endmodule

TESTBENCH :

module CSA_adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;

CSA_adder uut (.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(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

AIM: Implementation of BCD Adder.

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:

1001 (9)+0101 (5)=111010

This result is invalid for BCD number. So, in order to fix the addition result:

1. Perform 4-bit binary addition of the two BCD digits + carry-in.


2. If the result is greater than 1001 (9) or has a carry out of the 4-bit sum, then add 0110 (6) to the result.

CODE :

module BCD_adder(A, B, Cin, Sum, Cout);


input [3:0] A;
input [3:0] B;

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;

assign temp_sum = A + B + Cin;

// Check if correction needed


assign carry_correction = (temp_sum > 9) ? 1'b1 : 1'b0;

assign corrected_sum = carry_correction ? (temp_sum + 5'd6) : temp_sum;

assign Sum = corrected_sum[3:0];


assign Cout = corrected_sum[4]; // Carry to next BCD digit
endmodule

TESTBENCH :

module BCD_adder_tb;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;

BCD_adder uut (.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(Cout));

initial begin
$monitor("A=%b B=%b Cin=%b | Sum=%b Cout=%b", A, B, Cin, Sum, Cout);

A = 4'b0011; B = 4'b0100; Cin = 0; #5; // 3 + 4 = 7 (no correction)


A = 4'b0101; B = 4'b0110; Cin = 0; #5; // 5 + 6 = 11 → corrected to 1 with carry
A = 4'b1001; B = 4'b1001; Cin = 0; #5; // 9 + 9 = 18 → corrected
$finish;
end
endmodule

39 | P a g e
OUTPUT :

SCHEMATIC :

40 | P a g e
PRACTICAL 13

AIM : Implementation of 4-bit Comparator.

4-BIT COMPARATOR : SA comparator is a combinational circuit used to compare the magnitudes of


two binary numbers and determine the relationship between them.

For a 4-bit comparator, two 4-bit inputs (A[3:0] and B[3:0]) are compared, and the circuit produces three
outputs:

A > B → High when A is greater than B.


A = B → High when A is equal to B.
A < B → High when A is less than B.

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;

always @(*) begin


if (A > B) begin
A_gt_B = 1;
A_eq_B = 0;
A_lt_B = 0;
end else if (A < B) begin
A_gt_B = 0;
A_eq_B = 0;
A_lt_B = 1;
end else begin
A_gt_B = 0;
A_eq_B = 1;
A_lt_B = 0;
end
end

endmodule

TESTBENCH :

module comparator_4bit_tb;

reg [3:0] A, B;
wire A_gt_B, A_eq_B, A_lt_B;

comparator_4bit uut(A, B, 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

AIM : Implementation of Multiplexers:


a. 2-to-1
b. 4-to-1
c. 8-to-1
d. 16-to-1

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.

A. Implementation of 2-to-1 Mux

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 :

B. Implementation of 4-to-1 Mux

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 :

D. Implementation of 16-to-1 Mux:

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).

A. Implementation of 4-to-1 Mux using 2-to-1 Mux

CODE :

module mux_4to1_DR(d,sel,y);
input [3:0] d;
input [1:0] sel;
output y;

wire w1, w2;


mux_2to1 m1(d[0], d[1], sel[0], w1);
mux_2to1 m2(d[2], d[3], sel[0], w2);
mux_2to1 m3(w1, w2, sel[1], y);
endmodule

The code for 2-to-1 Mux module used here is:

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 :

B. Implementation of 8-to-1 Mux using 4-to-1 Mux

CODE :

module mux_8to1_DR(d,sel,y);
input [7:0] d;
input [2:0] sel;
output y;

wire w1, w2;


mux_4to1 m1(d[3:0], sel[1:0], w1);
mux_4to1 m2(d[7:4], sel[1:0], w2);
mux_2to1 m3(w1, w2, sel[2], y);
endmodule

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.

Therefore, a decoder is a combination logic circuit that is capable of identifying or detecting a


particular code. The operation that a decoder performs is referred to as decoding.

Diagram :

A. Implementation of 2-to-4 Decoder

CODE :

module deco_2to4( d,y);


input [1:0] d;
output [3:0] y;

assign y[0] = ~d[1] & ~d[0]; // 00 → y0 high


assign y[1] = ~d[1] & d[0]; // 01 → y1 high
assign y[2] = d[1] & ~d[0]; // 10 → y2 high
assign y[3] = d[1] & d[0]; // 11 → y3 high

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;

assign y[0] = ~d[2] & ~d[1] & ~d[0];


assign y[1] = ~d[2] & ~d[1] & d[0];
assign y[2] = ~d[2] & d[1] & ~d[0];
assign y[3] = ~d[2] & d[1] & d[0];
assign y[4] = d[2] & ~d[1] & ~d[0];
assign y[5] = d[2] & ~d[1] & d[0];
assign y[6] = d[2] & d[1] & ~d[0];
assign y[7] = d[2] & d[1] & d[0];
endmodule

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 :

C. Implementation of 4-to-16 Decoder

CODE :

module deco_4to16(d,y);
input [3:0] d;
output [15:0] y;

assign y[0] = ~d[3] & ~d[2] & ~d[1] & ~d[0];


assign y[1] = ~d[3] & ~d[2] & ~d[1] & d[0];

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)
);

// Apply all possible input combinations


integer i;
initial begin
for (i = 0; i < 16; i = i + 1)
begin
d = i;
#10;

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).

A. Implementation of 3-to-8 Decoders

CODE :

module deco_3to8_DR( d,y);


input [2:0] d;
output [7:0] y;

wire [3:0] y_low, y_high;

// Lower 4 outputs (when MSB = 0)


deco_2to4 dec0(.d(d[1:0]), .y(y_low));

// Higher 4 outputs (when MSB = 1)


deco_2to4 dec1(.d(d[1:0]), .y(y_high));

assign y = (d[2] == 1'b0) ? {4'b0000, y_low} : {y_high, 4'b0000};


endmodule

Testbench:

module deco_3to8_DR_tb;
reg [2:0] d;
wire [7:0] y;

// Instantiate the Unit Under Test (UUT)


deco_3to8_DR uut (
.d(d),
.y(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;

$stop; // End simulation


end
endmodule

OUTPUT :

SCHEMATIC :

B. Implementation of 4-to-16 Decoder using 3-to-8 Decoder

CODE :

module deco_4to16_DR(d,y );
input [3:0] d;
output [15:0] y;

wire [7:0] y_low, y_high;

deco_3to8 dec0(.d(d[2:0]), .y(y_low));


deco_3to8 dec1(.d(d[2:0]), .y(y_high));

assign y = (d[3] == 1'b0) ? {8'b00000000, y_low} : {y_high, 8'b00000000};


endmodule

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));

integer i; // loop variable

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

$stop; // End simulation


end
endmodule

OUTPUT :

SCHEMATIC :

63 | P a g e
PRACTICAL 18

AIM : Implementation of a Priority Encoder

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;

always @(*) begin


casex(in)
8’b1xxxxxxx: out = 3’b111;
8’b01xxxxxx: out = 3’b110;
8’b001xxxxx: out = 3’b101;
8’b0001xxxx: out = 3’b100;
8’b00001xxx: out = 3’b011;

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;

reg [7:0] in;


wire [2:0] out;
prio_enco uut(in, out);

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

AIM : Implementation of a 4-bit Multiplier.

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 :

module booth_multiplier #(parameter WIDTH = 8)(clk,rst,start,multiplicand,multiplier,product,done);


input wire clk;
input wire rst; // synchronous active-high reset
input wire start; // pulse to start multiplication
input wire [WIDTH-1:0] multiplicand;// two's-complement
input wire [WIDTH-1:0] multiplier; // two's-complement
output reg [2*WIDTH-1:0] product; // two's-complement 2*WIDTH result
output reg done; // goes high for 1 cycle when product ready

// 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;

localparam IDLE = 2'b00, CALC = 2'b01, DONE = 2'b10;

// 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

combined = {tmpA, Q, Q_1}; // width = 2*WIDTH + 1


combined = {combined[2*WIDTH], combined[2*WIDTH:1]};
A <= combined[2*WIDTH:WIDTH+1];
Q <= combined[WIDTH:1];
Q_1 <= combined[0];

// 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

default: state <= IDLE;


endcase

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;

booth_multiplier #(WIDTH) uut (


.clk(clk), .rst(rst), .start(start),
.multiplicand(multiplicand), .multiplier(multiplier),
.product(product), .done(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

AIM : Implementation of 8-bit barrel shifter

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:

• Logical shifts (left or right, filling with zeros)


• Arithmetic shifts (preserving the sign bit for signed numbers)
• Rotate shifts (bits rotated around the word)

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;

reg [7:0] data_in;


reg [2:0] shamt;
reg dir;
reg [1:0] mode; // 00=logical, 01=rotate, 10=arithmetic right
wire [7:0] data_out;

// 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

AIM : Implementation of 8-bit ALU.

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;

reg [8:0] tmp_add;


reg [7:0] tmp;
always @(*) begin
carry = 1’b0;

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;

ALU_8bit uut(.A(A), .B(B), .opcode(opcode), .result(result), .zero(zero), .carry(carry),


.overflow(overflow));

initial begin

A = 8’d15; B = 8’d10; opcode = 4’b0000; #10; // ADD

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

AIM : Implementation of S-R and D-latches using behavioural modelling.

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.

A. Implementation of S-R Latch

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:

Truth-Table for SR Latch:

CODE :

module SR_latch(S, R, Q, Qbar);


input S, R;
output reg Q;
output Qbar;
assign Qbar = ~Q;

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;

SR_latch uut1(.S(S), .R(R), .Q(Qsr), .Qbar(Qsrbar));


initial begin
S = 0; R = 0; #10;
S = 1; R = 0; #10;
S = 0; R = 1; #10;
S = 1; R = 1; #10; // invalid
S = 0; R = 0; #10;
$finish;
end
endmodule

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.

Diagram for D Latch can be given as:

Truth -table for D Latch can be given as:

CODE :

module D_latch(D,enable,Q);
input D, enable;
output reg Q;

always @(*) begin


if (enable) Q = D;
// else hold (behavioral)
end
endmodule

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:

1. Input D: Carries the data to be stored.


2. Clock/Enable → Controls when the latch is transparent.
3. Reset (Active High, Synchronous) → Forces the output Q to 0, but only at the active clock level.
4. Preset (Active Low, Synchronous) → Forces the output Q to 1, but only at the active clock level.

CODE :

module D_sync_reset(clk, D, reset_sync, preset_n, Q);


input clk;
input D;
input reset_sync;
input preset_n;
output reg Q;
always @(posedge clk or negedge preset_n) begin
if (!preset_n) Q <= 1'b1; // async preset (active low)
else if (reset_sync) Q <= 1'b0; // synchronous reset on posedge
else Q <= D;
end
endmodule

TESTBENCH :

module D_sync_reset_tb;

reg clk, D, reset_sync, preset_n;


wire Q;

D_sync_reset uut(.clk(clk), .D(D), .reset_sync(reset_sync), .preset_n(preset_n), .Q(Q));

initial begin

clk = 0; forever #5 clk = ~clk;


end
81 | P a g e
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 :

module D_aysnc_reset(D, enable, reset_n, preset, Q);


input D;
input enable;
input reset_n;
input preset;
output reg Q;
always @(*) begin
if (!reset_n) Q = 1'b0; // async reset
else if (preset) Q = 1'b1; // async preset
else if (enable) Q = D; // transparent when enable=1
// else hold previous Q (behavioral)
end

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 :

module D_FF_PE(clk, rst_n, D, Q);


input clk;
input rst_n;
input D;
output reg Q;
always @(posedge clk or negedge rst_n)
begin
if (!rst_n) Q <= 1'b0;
else Q <= D;
end
endmodule

TESTBENCH :

module D_FF_PE_tb;
reg clk, rst_n, D;
wire Q;

D_FF_PE uut(.clk(clk), .rst_n(rst_n), .D(D), .Q(Q));

initial begin

clk = 0; forever #5 clk = ~clk;


end

initial begin

rst_n = 0; D = 0; #10; // async reset active


rst_n = 1; #10;
D = 1; #10;
D = 0; #10;
D = 1; #10;
rst_n = 0; #10; // assert reset async
85 | P a g e
rst_n = 1; #10;
$finish;
end
endmodule

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 :

module D_FF_NEG_EDGE(clk, reset_n, preset, d, q);


input wire clk;
input wire reset_n;
input wire preset;
input wire d;
output reg q;
always @(negedge clk or negedge reset_n or posedge preset) begin
if (!reset_n) // Active-low reset
q <= 1'b0;
else if (preset) // Active-high preset
q <= 1'b1;
else
q <= d;
end

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 :

module D_FF_sync(clk, rst, preset_n, d, q);


input wire clk;
input wire rst;
input wire preset_n;
input wire d;
output reg q;
always @(posedge clk) begin
if (rst) q <= 1'b0;
else if (!preset_n) q <= 1'b1;
else q <= d;
end
endmodule

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

AIM : Implementation of 5-bit bidirectional serial-in-serial-out (SISO) shift register.

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 :

module SISO_BIDI(clk, rst, en, dir, serial_in, serial_out);


input wire clk;
input wire rst; // synchronous active-high reset
input wire en; // shift enable
input wire dir;
input wire serial_in;
output wire serial_out;
output reg [4:0] q;
assign serial_out = dir ? q[0] : q[4];
always @(posedge clk) begin
if (rst) q <= 5'b0;
else if (en) begin
if (dir) q <= {serial_in, q[4:1]}; // shift right
else q <= {q[3:0], serial_in}; // shift left
end
end
endmodule

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

rst = 1; en = 0; dir = 0; serial_in = 0; #12;


rst = 0; #10;
en = 1; dir = 0; serial_in = 1; #10; serial_in = 0; #10; serial_in = 1; #10; serial_in = 1; #10;
serial_in = 0; #10;
dir = 1; serial_in = 0; #10; serial_in = 1; #10;
en = 0; #10;
$finish;
end
endmodule

OUTPUT :

SCHEMATIC :

92 | P a g e
PRACTICAL 29

AIM : Implementation of 64-byte single port random-access memory (RAM).

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 :

module RAM_64x8(clk, we, addr, din, dout);


input wire clk;
input wire we; // write enable
input wire [5:0] addr; // 6-bit address for 64 bytes
input wire [7:0] din;
output reg [7:0] dout;
reg [7:0] mem [0:63];
integer i;
initial for (i=0;i<64;i=i+1) mem[i]=8'h00;

always @(posedge clk) begin


if (we) mem[addr] <= din;
dout <= mem[addr]; // synchronous read
end
endmodule

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

we = 1; addr = 6'd10; din = 8'hAA; #10;


addr = 6'd11; din = 8'h55; #10;
93 | P a g e
we = 0; addr = 6'd10; #10;
addr = 6'd11; #10;
we = 1; addr = 6'd10; din = 8'hFF; #10;
we = 0; addr = 6'd10; #10;
$finish;
end
endmodule

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:

1. SISO (Serial-in Serial-out): Shifts serially.


2. SIPO (Serial-in Parallel-out): Accepts serial input but outputs all bits together.
3. PIPO (Parallel-in Parallel-out): Loads and outputs all bits simultaneously.
4. PISO (Parallel-in Serial-out): Loads parallel data and shifts out serially.

CODE :

module univ_shift_reg(clk, rst, mode, shift_en, serial_in, parallel_in, parallel_out, serial_out);


input wire clk,
input wire rst, // synchronous active-high reset
input wire [1:0] mode, // 00=SISO, 01=SIPO, 10=PIPO, 11=PISO
input wire shift_en, // shift enable for shift modes
input wire serial_in,
input wire [4:0] parallel_in,
output reg [4:0] parallel_out,
output wire serial_out

reg [4:0] sr;


assign serial_out = sr[0];

always @(posedge clk) begin


if (rst)
sr <= 5'b0;
else begin
case (mode)
2'b00: if (shift_en) sr <= {sr[3:0], serial_in}; // SISO: shift-left, serial input enters LSB
2'b01: if (shift_en) sr <= {sr[3:0], serial_in}; // SIPO: shift-left, serial input enters LSB
2'b10: sr <= parallel_in; // PIPO: load all at once
2'b11: if (shift_en) sr <= {1'b0, sr[4:1]}; // PISO: shift-right, MSB outputs first
endcase
end
end

always @(*) parallel_out = sr;

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)
);

// Clock generator (10ns period)


always #5 clk = ~clk;

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

AIM : Implementation of single clock first-in-first-out (FIFO) structure.

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.

Some of the components of a synchronous FIFO include

• Data Storage Array: Contains the data.


• Write Pointer: Refers to the next point to which data is to be written.
• Read Pointer: Indicates the next place data will be read.
• Control Logic: Handles the full and empty status flags.

A simple basic Synchronous FIFO will look like this.

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.

An asynchronous FIFO has the following components:

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
);

localparam ADDR_W = PTR_W;


reg [DATA_W-1:0] mem [0:DEPTH-1];
reg [ADDR_W-1:0] wr_ptr, rd_ptr;
reg [PTR_W:0] count;
integer i;
assign full = (count == DEPTH);
assign empty = (count == 0);

always @(posedge clk) begin


if (rst) begin

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

rst = 1; wr_en = 0; rd_en = 0; din = 0; #12;


rst = 0;
wr_en = 1; din = 8'hA0; #10; din = 8'hA1; #10; din = 8'hA2; #10; din = 8'hA3; #10; din = 8'hA4;
#10;
wr_en = 0; #10;
rd_en = 1; #30; rd_en = 0; #10;
wr_en = 1; din = 8'hB0; #10; din = 8'hB1; #10; din = 8'hB2; #10; din = 8'hB3; #10; wr_en = 0;
rd_en = 1; #100;
$finish;

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:

• Up Mode: Counts from 0 → 255.


• Down Mode: Counts from 255 → 0.
• Load Function: Allows a preset value to be directly loaded.
• Active High Reset: Immediately clears count to zero.

CODE :

module up_down_8bit(clk, rst, load, up, data_in, count);


input wire clk;
input wire rst; // active-high synchronous reset
input wire load; // synchronous load
input wire up; // 1 = up, 0 = down
input wire [7:0] data_in;
output reg [7:0] count;
always @(posedge clk) begin
if (rst)
count <= 8'b0; // Reset
else if (load)
count <= data_in; // Load input value
else if (up)
count <= count + 1; // Count up
else
count <= count - 1; // Count down
end
endmodule

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

rst = 1; load = 0; up = 1; data_in = 8'h00; #12;


rst = 0;

load = 1; data_in = 8'h10; #10; load = 0;

up = 1; #50;

up = 0; #50;

rst = 1; #10; rst = 0; #10;

$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:

• Counts 0 to 46, then resets to 0.


• Load Function: Allows initialization with a chosen value.
• Active High Reset: Forces count = 0 at any time.

This design is commonly applied in frequency dividers, digital clocks (e.g., mod-60 for minutes), and
state machines requiring restricted count ranges.

CODE :

module mod_47(clk, rst, load, data_in, count);


input wire clk;
input wire rst;
input wire load;
input wire [5:0] data_in;
output reg [5:0] count;
always @(posedge clk) begin
if (rst)
count <= 6'd0; // reset to 0
else if (load)
count <= (data_in % 47); // load value (ensure within 0-46)
else if (count == 6'd46)
count <= 6'd0; // wrap around at 46
else
count <= count + 1; // normal increment
end

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

AIM : Implementation of clock frequency divider: divide-by-2, divide by-3, divide-by-4.

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 :

module clk_freq_div(clk, rst, divsel, clk_out);


input wire clk;
input wire rst;
input wire [1:0] divsel; // 00 => /2, 01 => /3, 10 => /4
output reg clk_out;
reg [1:0] cnt2;
reg [1:0] cnt3;
reg [1:0] cnt4;
always @(posedge clk) begin
if (rst) begin
cnt2 <= 0; cnt3 <= 0; cnt4 <= 0; clk_out <= 0;
end else begin
case (divsel)
2'b00: begin // /2: toggle every 1 input edge
cnt2 <= cnt2 + 1;
if (cnt2 == 1) begin clk_out <= ~clk_out; cnt2 <= 0; end
end
2'b01: begin // /3: toggle on 3 input edges (approx)
cnt3 <= cnt3 + 1;
if (cnt3 == 2) begin clk_out <= ~clk_out; cnt3 <= 0; end
end
2'b10: begin // /4: toggle every 2 input edges (approx)
cnt4 <= cnt4 + 1;
if (cnt4 == 1) begin clk_out <= ~clk_out; cnt4 <= 0; end
end
default: clk_out <= clk_out;
endcase
end
end
endmodule

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.

There are two types of FSM:

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 :

module non_overlap_mealy(clk, rst, in_bit, detected);


input wire clk;
input wire rst;
input wire in_bit;
output reg detected;
reg [1:0] state, next;
localparam S0 = 2'd0;
localparam S1 = 2'd1;
localparam S2 = 2'd2;
always @(posedge clk) begin
if (rst) state <= S0; else state <= next;
end
always @(*) begin
next = state; detected = 1'b0;
case (state)
S0: begin if (in_bit==1'b0) next = S1; else next = S0; end
S1: begin if (in_bit==1'b1) next = S2; else next = S1; end
S2: begin
if (in_bit==1'b0) begin detected = 1'b1; next = S0; end
else next = S0;
end
endcase
108 | P a g e
end
endmodule

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 :

module non_overlap_moore(clk, rst, in_bit, detected);


input wire clk;
input wire rst;
input wire in_bit;
output reg detected;
reg [1:0] state, next;
localparam S0 = 2'd0;
localparam S1 = 2'd1;
localparam S2 = 2'd2;
localparam S3 = 2'd3;
always @(posedge clk) begin
if (rst) state <= S0; else state <= next;
end
always @(*) begin
next = state; detected = 1'b0;
case (state)
S0: if (in_bit) next = S1; else next = S0;
S1: if (in_bit) next = S2; else next = S0;
S2: if (!in_bit) next = S3; else next = S2;
S3: begin
if (in_bit) next = S1; else next = S0;
end
endcase
if (state == S3) detected = 1'b1;
end
endmodule

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 :

module overlap_mealy(clk, rst, in_bit, detected);


input wire clk;
input wire rst;
input wire in_bit;
output reg detected;
reg [1:0] state, next;
localparam S0 = 2'd0;
localparam S1 = 2'd1;
localparam S2 = 2'd2;
localparam S3 = 2'd3;

always @(posedge clk) begin


if (rst) state <= S0; else state <= next;
end

always @(*) begin


next = state; detected = 1'b0;
case (state)
S0: if (in_bit==0) next = S1; else next = S0;
S1: if (in_bit==1) next = S2; else next = S1;
S2: if (in_bit==0) next = S3; else next = S0;
S3: begin
if (in_bit==1) begin detected = 1'b1; next = S2; end
else next = S1;
end
endcase
end
endmodule

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

rst = 1; in_bit = 0; #12; rst = 0;


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 :

113 | P a g e
PRACTICAL 38

AIM : Implementation of 1101 overlapping sequence detector using Moore finite-state machine
(FSM).

CODE :

module overlap_moore(clk, rst, in_bit, detected);


input wire clk;
input wire rst;
input wire in_bit;
output reg detected;
reg [2:0] state, next;
localparam S0 = 3'd0;
localparam S1 = 3'd1;
localparam S2 = 3'd2;
localparam S3 = 3'd3;
localparam S4 = 3'd4;

always @(posedge clk) begin


if (rst) state <= S0; else state <= next;
end

always @(*) begin


next = state; detected = 1'b0;
case (state)
S0: if (in_bit) next = S1; else next = S0;
S1: if (in_bit) next = S2; else next = S0;
S2: if (!in_bit) next = S3; else next = S2;
S3: if (in_bit) next = S4; else next = S0;
S4: begin
if (in_bit) next = S1; else next = S0;
end
endcase
if (state == S4) detected = 1'b1;
end
endmodule

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

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 = 1; #10; in_bit = 0; #10; in_bit = 1; #10;
$finish;
end
endmodule

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').

Control Voltage (VG) State Function


Logic ‘1’ (VDD) ON Passes input to the output.
Logic ‘0’ OFF Output is isolated from the input.

Signal Degradation (Problem with Logic '1'):

When the nMOS attempts to pass a Logic '1' Vin = VDD.

1. The gate voltage is VG = VDD.


2. The transistor needs a gate-to-source voltage VGS greater than the threshold voltage to stay 'ON'.
3. As the source voltage Vout rises, VGS = VDD – Vout decreases.
4. The transistor turns OFF when Vout reaches VDD – Vtn.
5. Therefore, the output voltage is Vout = VDD – Vtn. This is a degraded '1', making it difficult to drive
subsequent logic gates. This is known as a 'weak 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').

Control Voltage (VG) State Function


Logic ‘1’ (VDD) OFF Output is isolated from the input.
Logic ‘0’ ON Passes input to the output.

CODE :

module pass_transistors (in, ctrl, out_n, out_p );


input in; // data input
input ctrl; // control signal
output out_n; // output through NMOS
output out_p; // output through PMOS

// NMOS pass transistor (conducts when ctrl = 1)


nmos (out_n, in, ctrl);
// PMOS pass transistor (conducts when ctrl = 0)
pmos (out_p, in, ctrl);
endmodule

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

in=0; ctrl=0; #10;


in=1; ctrl=0; #10;
in=0; ctrl=1; #10;
in=1; ctrl=1; #10;

$finish;
end
endmodule

OUTPUT :

118 | P a g e
PRACTICAL 40

AIM : Implementation of transmission gate (TG) using switch level modelling.

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.

Fig. 4 types of TG representation of TG

CODE :

module transmission_gate (out, in, en);


output out;
input in;
input en;
wire nctrl;
not (nctrl, en);
119 | P a g e
cmos (out, in, en, nctrl); // NMOS+PMOS combo
endmodule

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

AIM : Implementation of 3-input NAND gate using switch level modelling.

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.

Switch-Level Model for 3-Input NAND Gate:

The Boolean function for a 3-input NAND gate with inputs A, B, and C is:

Y = (A & B & C)’

1. Pull-Down Network (PDN) - nMOS


The PDN connects the output Y to Ground (GND), pulling the output LOW (Y=0) when the function's
inputs are all HIGH.

• The NAND function is LOW only when A=B=C=1.


• nMOS transistors are ON (closed switch) when their gate is HIGH (Logic '1').

• 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.

2. Pull-Up Network (PUN) - pMOS


The PUN connects the output Y to the Power Supply, pulling the output HIGH when the function's inputs
are not all HIGH.

• The NAND function is HIGH when A=0 or B=0 or C=0.

• 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 :

module nand3_switch (Y, A, B, C);


output Y;
input A;
input B;
input C;
supply1 Vdd;
supply0 Gnd;
wire w1, w2;

// Pull-down network (NMOS in series)


nmos (w1, Gnd, A);
nmos (w2, w1, B);
nmos (Y, w2, C);

// Pull-up network (PMOS in parallel)


pmos (Y, Vdd, A);
pmos (Y, Vdd, B);
pmos (Y, Vdd, C);
endmodule

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

AIM : Implementation of 2-input XOR gate using switch level modelling.

DIAGRAM :

CODE :

module xor2_switch(Y, A, B);


output Y;
input A;
input B;
supply1 Vdd;
supply0 Gnd;

wire nA, nB;


not (nA, A);
not (nB, B);

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;

xor2_switch dut (.Y(Y), .A(A), .B(B));

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

AIM : Implementation of 2-to-1 MUX using switch level modelling.

DIAGRAM :

CODE :

module mux2to1_switch (Y, D0, D1, S);

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

// NMOS passes D0 strongly 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;

reg D0, D1, S;


wire Y;

mux2to1_switch dut (.Y(Y), .D0(D0), .D1(D1), .S(S));

initial begin
// Test patterns
D0=0; D1=1;

S=0; #20; // Expect Y = D0 = 0


S=1; #20; // Expect Y = 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

You might also like