VLSI Testing
VLSI Testing
(ME02000181)
LABORATORY MANUAL
SEMESTER II
VLSI Design
[ DEPARTMENT OF
Certificate
Lab In-Charge
Prof. Dhaval Patel
INDEX
Sr. Title of Experiment Pg. No. Date Sign
No.
1. To develop an exhaustive testbench for 4
lower-level combinational designs:
(1) Adder
(2) Subtractor
(3) Multiplexer
(4) Demultiplexer
EXPERIMENT 1
Half Adder:
Theory: A half-adder is a basic digital circuit used for adding two single-bit binary numbers. It
consists of two inputs, A and B, and two outputs, Sum and Carry.
Sum: Represents the least significant bit of the addition result. It is obtained by performing an
XOR operation on the inputs A and B.
Carry: Represents the most significant bit, which indicates if there is an overflow from the
addition. It is obtained by performing an AND operation on the inputs A and B.
DESIGN CODE:
Dataflow Modeling
module half_adder (
input a, b,
output sum, carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
Behavioral modeling
always@(*) begin
sum = a ^ b; carry = a & b;
end
endmodule
Structural Modeling
TESTBENCH:
module tb_half_adder;
reg a, b;
wire sum, carry;
half_adder uut ( a, b, sum, carry);
initial begin
$dumpfile("half_adder.vcd");
$dumpvars(0, tb_half_adder);
$monitor("At time %t, a = %b, b = %b, sum = %b, carry = %b", $time, a, b, sum, carry);
// test cases
a = 0; b = 0; #10;
a = 0; b = 1; #10;
a = 1; b = 0; #10;
a = 1; b = 1; #10;
a = 0; b = 0; #10;
$finish;
end
endmodule
OUTPUT WAVEFORM:
5
250280763009 ME02000181
CODE COVERAGE:
Full Adder:
Theory: A full-adder is a digital circuit used to add three single-bit binary numbers: two significant
bits (A and B) and a carry-in bit (Cin) from a previous addition. It has three inputs and two
outputs:
Sum: The least significant bit of the addition result, calculated using the XOR operation on all
three inputs (A, B, and Cin).
Carry-out (Cout): Indicates if there is a carry-over to the next higher bit position, determined by
the majority function of the inputs (A, B, and Cin). It is calculated using the OR operation on the
AND operations of the inputs.
DESIGN CODE:
Dataflow Modeling
);
assign sum = a ^ b ^ cin;
assign carry = (a & b) | (b & cin) | (cin & a);
endmodule
Behavioral modeling
Structural Modeling
TESTBENCH:
7
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
Half Subtractor:
Theory: A half-subtractor is a basic digital circuit used for subtracting two single-bit binary
numbers. It consists of two inputs, A and B, and two outputs, Difference and Borrow.
Difference: Represents the least significant bit of the addition result. It is obtained by
performing an XOR operation on the inputs A and B.
Borrow: Represents the most significant bit, which indicates if there is an overflow from the
addition. It is obtained by performing an AND operation on the inputs ~A and B.
8
250280763009 ME02000181
DESIGN CODE:
Dataflow Modeling
Behavioral modeling
Structural Modeling
TESTBENCH:
module tb_half_subtractor;
reg a, b;
wire diff, borrow;
half_subtractor uut ( a, b, diff, bout);
initial begin
$dumpfile("half_subtractor.vcd");
$dumpvars(0, tb_half_subtractor);
$monitor("At time %t, a = %b, b = %b, diff = %b, = %b", $time, a, b, diff, borrow);
// test cases
a = 0; b = 1; #10;
a = 1; b = 1; #10;
9
250280763009 ME02000181
a = 0; b = 0; #10;
a = 1; b = 0; #10;
a = 0; b = 1; #10;
$finish;
end
Endmodule
OUTPUT WAVEFORM:
CODE COVERAGE:
FULL SUBTRACTOR
Theory: A full subtractor is a digital circuit used to subtract three single-bit binary numbers: two
significant bits (A and B) and a borrow-in bit (Bin) from a previous subtraction. It has three inputs
and two outputs:
Difference: The result of subtracting B and Bin from A, calculated using the XOR operation on all
three inputs (A, B, and Bin).
Borrow-out (Bout): Indicates if a borrow is needed for the next higher bit position, determined
by checking if A is less than the combination of B and Bin. It is calculated using the OR and
AND operations on the inputs.
10
250280763009 ME02000181
DESIGN CODE:
Dataflow Modeling
Behavioral modeling
Structural Modeling
11
250280763009 ME02000181
TESTBENCH:
OUTPUT WAVEFORM:
CODE COVERAGE:
12
250280763009 ME02000181
Multiplexer
Theory: Multiplexer is a digital logic device which is used to perform multiplexing of data. Where,
multiplexing simply means sharing of data. Technically, when a particular data is selected from
multiple input data sources and transmitted the selected data to a single output channel, it is called
multiplexing.
There are two types of multiplexing namely, frequency multiplexing and time multiplexing. When
multiple devices are connected to a single transmission line in a system. At any point of time, only one
device is using the line to transmit data, then this is called time multiplexing.
On the other hand, when multiple devices share a common line to transmit data but at different
frequencies, it is called frequency multiplexing.
4*1 MULTIPLEXER
4×1 Multiplexer has four data inputs I3, I2, I1 & I0, two selection lines s1 & s0 and one output Y. One of
these 4 inputs will be connected to the output based on the combination of inputs present at these two
selection lines. Truth table of 4×1 Multiplexer is shown below
DESIGN CODE:
Dataflow Modeling
module mux4to1 ( input wire [3:0] I, input wire [1:0] sel, output wire y
);
assign y = (I[0] & ~sel[1] & ~sel[0]) | (I[1] & ~sel[1] & sel[0]) | (I[2] & sel[1] & ~sel[0]) | (I[3] &
sel[1] & sel[0]);
endmodule
Behavioral modeling
module mux4to1 ( input wire [3:0] I, input wire [1:0] sel, output reg y
);
always @(*) begin
13
250280763009 ME02000181
case (sel)
2'b00: y = I[0];
2'b01: y = I[1];
2'b10: y = I[2];
2'b11: y = I[3];
default: y = I[0];
endcase
end
endmodule
Structural Modeling
TESTBENCH:
module tb_mux4to1;
reg [3:0] I;
reg [1:0] sel;
wire y;
mux4to1 uut (.I(I), .sel(sel),.y(y));
initial begin
$dumpfile("[Link]");
$dumpvars(0, tb_mux4to1);
// TEST CONDITIONS
I = 4'b1111; sel = 2'bxx; #10;
I = 4'b1010; sel = 2'b00; #10;
I = 4'b0101; sel = 2'b00; #10;
OUTPUT WAVEFORM:
CODE COVERAGE:
When S1 is set to HIGH it will select i1 and i3 now if s0 is LOW output will have i1 otherwise i3 and
similar for i0 and i2.
DESIGN CODE:
module mux2to1 ( input wire a, input wire b, input wire sel, output wire y
);
assign y = sel ? b : a;
endmodule module mux4to1 (
input wire [3:0] I, input wire [1:0] sel, output wire y
);
wire mux1_out, mux2_out;
mux2to1 mux1 (.a(I[0]), .b(I[1]), .sel(sel[0]), .y(mux1_out));
mux2to1 mux2 (.a(I[2]), .b(I[3]), .sel(sel[0]), .y(mux2_out));
mux2to1 mux3 (.a(mux1_out), .b(mux2_out), .sel(sel[1]), .y(y));
endmodule
TESTBENCH:
OUTPUT WAVEFORM:
CODE COVERAGE:
DEMULTIPLEXER
Theory: A demultiplexer (DEMUX) is a digital logic device used to route a single input data source
to one of multiple output channels based on select signals. Essentially, it performs the reverse
function of a multiplexer, allowing data from one source to be distributed to various destinations.
There are two types of Demultiplexing namely, frequency Demultiplexing and time Demultiplexing. when
a single data source transmits data to multiple devices at different time intervals At any given moment,
only one device receives the data while others remain inactive. This method optimizes the use of
communication channels.
On the other hand, a single source transmits multiple signals over a common channel at different
frequencies. The demultiplexer separates these frequencies, directing the appropriate signal to its
corresponding output.
17
250280763009 ME02000181
1X4 DEMULTIPLEXER:
A 1×4 Demultiplexer has one data input I, two selection lines s1 & s0, and four outputs Y3, Y2, Y1, and
Y0. The single input will be routed to one of these 4 outputs based on the combination of inputs present at
the two selection lines. The truth table of the 1×4 Demultiplexer is shown below:
DESIGN CODE:
Dataflow Modeling
Behavioral modeling
endmodule
Structural Modeling
TESTBENCH:
19
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
20
250280763009 ME02000181
DESIGN CODE:
Dataflow Modeling
module demux1to2 ( input wire sel, input wire din, output wire y0, output wire y1
);
assign y0 = (~sel) ? din : 0; assign y1 = sel ? din : 0;
endmodule
module demux1to4 ( input wire din, input wire [1:0] sel, output wire [3:0] y
);
wire demux1_out1, demux1_out2;
demux1to2 demux1 (.sel(sel[1]), .din(din), .y0(demux1_out1), .y1(demux1_out2));
demux1to2 demux2 (.sel(sel[0]), .din(demux1_out1), .y0(y[0]), .y1(y[1]));
demux1to2 demux3 (.sel(sel[0]), .din(demux1_out2), .y0(y[2]), .y1(y[3]));
endmodule
TESTBENCH:
module tb_demux1to4;
reg din;
reg [1:0] sel;
wire [3:0] y;
demux1to4 uut (
.din(din),
.sel(sel),
.y(y)
);
initial begin
$dumpfile("demux1to4_using_1to2.vcd");
$dumpvars(0, tb_demux1to4);
21
250280763009 ME02000181
//TEST CONDITIONS
din = 0; sel = 2'b00; #10;
din = 1; sel = 2'b01; #10;
din = 1; sel = 2'b10; #10;
din = 1; sel = 2'b11; #10;
din = 0; sel = 2'b00; #10;
din = 0; sel = 2'b01; #10;
din = 0; sel = 2'b10; #10;
din = 0; sel = 2'b11; #10;
$display("Time: %0t | din = %b | sel = %b | y = %b", $time, din, sel, y);
$finish;
end
endmodule
OUTPUT WAVEFORM:
CODE COVERAGE:
22
250280763009 ME02000181
EXPERIMENT 2
Flip-Flop
A flip-flop is a type of sequential logic circuit that stores a single bit of data (0 or 1). Unlike latches, flip-
flops are edge-triggered devices, meaning they change state only at specific moments (on the rising or
falling edge of a clock signal). Flip-flops are widely used in digital electronics for data storage,
synchronization, and sequential logic operations.
Applications of Flip-Flops:
Data Storage: Registers and memory elements in processors and other digital systems.
Synchronization: Flip-flops are used in synchronous circuits where all operations are synchronized
to a clock.
Counters and Dividers: Used in building counters, frequency dividers, and state machines.
Control Systems: Flip-flops help in holding states and ensuring data is only latched on specific
clock edges.
D Flip Flop
A D flip- flop stands for data or delay flip-flop. The outputs of this flip-flop are equal to the inputs.
DESIGN CODE:
Behavioral Code:
module d_flip_flop (
input wire D, // Data input
input wire CLK, // Clock input
output reg Q, // Output
output reg Qn // Inverted output
); always @(posedge CLK) begin
Q <= D; // Capture the data on the clock edge end
always @(*) begin
23
250280763009 ME02000181
24
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
SR Flip Flop
DESIGN CODE:
Dataflow Modeling:
assign SR = ~(S & clk); assign RQ = ~(R & clk); assign Q = ~(SR & Q_bar); assign Q_bar = ~(RQ & Q);
endmodule
Behavioral Code:
Structural Modeling:
TESTBENCH:
module tb_sr_ff;
reg S, R, clk;
wire Q, Q_bar;
26
250280763009 ME02000181
.Q(Q),
.Q_bar(Q_bar));
initial begin
$monitor("Time = %0d: S = %b, R = %b, clk = %b, Q = %b, Q_bar = %b",
$time, S, R, clk, Q, Q_bar);
end
endmodule
OUTPUT WAVEFORM:
27
250280763009 ME02000181
CODE COVERAGE:
JK Flip Flop
DESIGN CODE:
Dataflow Modeling:
Behavioral Code:
// Toggle
endcase end
end
endmodule
Structural Modeling:
TESTBENCH:
module jk_flipflop_tb;
reg clk, j, k, rst;
wire q_behavioral;
// Clock generation
always #5 clk = ~clk;
// Test sequence
initial begin
// Initialize signals
clk = 0;
rst = 0;
29
250280763009 ME02000181
j = 0;
k = 0;
// Test cases
#10 j = 1; k = 0; // Set
#10 j = 1'bx; k = 1'bx;
#10 j = 0; k = 1; // Reset
#10 j = 1; k = 1; // Toggle
#10 j = 0; k = 0; // No change
#10 j = 1; k = 0; // Set
#10 j = 0; k = 1; // Reset
#10 j = 1; k = 1; // Toggle
#10 $finish;
end
OUTPUT WAVEFORM:
30
250280763009 ME02000181
CODE COVERAGE:
T Flip Flop
DESIGN CODE:
Behavioral Code:
module t_flip_flop (
input wire clk, // Clock signal
input wire rst, // Reset signal (active high) input wire T, // Toggle control inputoutput reg
Q // Output
);
31
250280763009 ME02000181
TESTBENCH:
module tb_t_flip_flop;
// Inputs
reg clk;
reg rst;
reg T;
// Output
wire Q;
// Instantiate the T flip-flop
t_flip_flop uut (
.clk(clk),
.rst(rst),
.T(T),
.Q(Q)
);
// Clock generation
initial begin
clk = 0;
forever #5 clk = ~clk; // Clock period is 10 time units
end
// Test sequence
initial begin
// Initialize inputs
rst = 1; T = 0;
#10 rst = 0; // Release reset
// Finish simulation
$finish;
end
// Monitor changes
initial begin
$monitor("Time=%0t | clk=%b | rst=%b | T=%b | Q=%b", $time, clk, rst, T, Q);
end
endmodule
32
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
33
250280763009 ME02000181
EXPERIMENT 3
Counters:
A counter is a sequential circuit that counts the number of clock pulses. Counters are widely used in digital
electronics for counting events, generating time delays, or dividing the frequency of a signal. They can
be designed to count up, count down, or perform both functions, depending on the design.
Ring Counter
DESIGN CODE:
Behavioral Code:
34
250280763009 ME02000181
TESTBENCH:
module ring_counter_tb;
parameter WIDTH = 4;
reg clk;
reg rstn;
wire [WIDTH-1:0] out;
initial begin
{clk, rstn} <= 0;
OUTPUT WAVEFORM:
35
250280763009 ME02000181
CODE COVERAGE:
Johnson Counter
DESIGN CODE:
Behavioral Code:
TESTBENCH:
module johnson_counter_tb;
parameter WIDTH = 4;
36
250280763009 ME02000181
reg clk;
reg rstn;
wire [WIDTH-1:0] out;
initial begin
{clk,rstn} <= 0;
OUTPUT WAVEFORM:
CODE COVERAGE:
37
250280763009 ME02000181
EXPERIMENT 4
Write a HDLcode and testbench to realize functioning of Linear Feedback Shift Register
(LFSR).
A Linear-feedback shift register (LFSR) is another variation of shift register whose input bit is a
linear function (typically XOR operation) of its previous state. It is generally used as a pseudo-
random number generator, whitening sequence, pseudo-noise sequence, etc.
The bit positions that act as an input to a linear function to affect the next state are known as taps.
At every step,
1. Q[3] xor Q[2]
2. Q = Q << 1
3. The result of the XOR operation is fed to the LSB (0th bit) In the above pseudo-random sequence
generator, taps are 4 and 3.
Working Of LFSR:
Initial State (Seed): The LFSR starts with an initial state, often referred to as the seed. This state is
typically a non-zero value, as an all-zero state can lead the LFSR to remain stuck at zero in many
configurations.
Shifting: On each clock cycle, all the bits in the LFSR shift to the right (or left, depending on
design). The bit in the least significant position (LSB) is discarded, and a new bit is introduced
into the most significant position (MSB) through the feedback mechanism.
Feedback Mechanism: The feedback bit is generated by XOR-ing the bits from specific
positions in the register. These positions are referred to as taps. The output of the XOR operation
is used as the new input bit at the MSB position.
For example, in a 4-bit LFSR with taps at positions 4 and 3, the feedback bit is calculated as:
feedback= bit3 ⊕ bit2
This feedback value is then shifted into the MSB of the LFSR.
Repeat: This process of shifting and applying feedback continues on each clock cycle, and the
register evolves into different states over time. The sequence of states produced is determined by
the positions of the taps.
Periodicity: If the taps are chosen correctly (following the characteristic polynomial), the LFSR
38
250280763009 ME02000181
can produce a maximal-length sequence. In a maximal-length LFSR, the register goes through
all possible non-zero states (for an n-bit LFSR, there are 2n−12^n - 12n−1 states) before
repeating itself. This makes the sequence appear "random," but it is entirely deterministic.
Advantages:
1. Simplicity: LFSRs are simple to implement in both hardware and software, requiring minimal
resources.
2. Fast Operation: They can generate pseudorandom sequences quickly due to their simple shifting
and feedback operations.
3. Deterministic Output: LFSRs produce predictable output sequences from a given initial state,
making them useful for applications requiring repeatability.
4. Good Statistical Properties: LFSRs can produce long sequences with good statistical properties,
making them suitable for cryptography and error detection.
5. Efficient Memory Usage: They use very little memory, as they only need to store the current state
and feedback polynomial coefficients.
Disadvantages:
1. Linear Nature: The linear feedback mechanism can make LFSRs vulnerable to certain types of
attacks in cryptographic applications, particularly if the polynomial is not chosen carefully.
2. Limited Period: The maximum length of the sequence generated is limited by the number of
flip-flops and the feedback polynomial, which can lead to periodicity.
3. Sensitivity to Initial State: The output is highly sensitive to the initial state; poor choice can result in
predictable sequences.
4. Not Truly Random: While they can approximate randomness, the sequences produced are
deterministic and not truly random, which can be a limitation in some applications.
5. Complexity in Polynomial Selection: Selecting the correct feedback polynomial to achieve maximum
length and desired properties can be complex and requires expertise.
DESIGN CODE:
Behavioral Modeling:
module lfsr (
input clk,
(* dont_touch = "true" *) input rst, // FORCES VIVADO TO TRACK THIS PORT
output reg [3:0] op
);
reg feedback;
end
end
endmodule
TESTBENCH:
module lfsr_tb;
reg clk = 0;
reg rst = 0;
wire [3:0] op;
initial begin
// 1. Establish the baseline
clk = 0;
rst = 0;
#25;
#20 $finish;
end
endmodule
OUTPUT WAVEFORM:
40
250280763009 ME02000181
CODE COVERAGE:
41
250280763009 ME02000181
EXPERIMENT 5
ALU is the fundamental building block of the processor, which is responsible for
carrying out the arithmetic and logic functions. ALU comprises of combinatorial logic that
implements arithmetic operations such as Addition, Subtraction and Multiplication, and logic
operations such as AND, OR, NOT. The ALU gets operands from the register file or memory. The
block diagram of a typical ALU is shown in Figure 1.
The ALU reads two input operands In A and In B. The operation to perform on these input operands is
selected using the control input OpDESIGN CODE. The ALU performs the selected operation on
the input operands In A and In B and produces the output, Out. The ALU also updates different flag
signals after performing the selected function. Note that the ALU is purely combinatorial logic and
contains no registers or latches.
Flags: ALU updates the conditional flags, which are used by the processor to perform other
operations like condition checking and branching. In this example two flags are implemented. They
are:
Flags:
Zero Flag (Z): Since the result is not zero, this flag is cleared (set to 0).
Carry Flag (C): No carry occurs as the sum fits within 8 bits, so the carry flag is cleared.
Overflow Flag (V): In unsigned arithmetic, no overflow occurs.
42
250280763009 ME02000181
Negative Flag (N): In signed arithmetic, the result is negative because the most significant
bit (MSB) is 1.
1. Inputs:
oOperand A: 10101010₂ (170 in decimal)
oOperand B: 00111001₂ (57 in decimal)
oOpcode: Suppose the opcode 0001 is used to represent addition.
2. Operation:
o The ALU receives the opcode 0001 indicating it should perform addition.
o The binary addition of A and B is performed.
DESIGN CODE:
Behavioral Modeling:
module alu(
input [7:0] A, // input A
input [7:0] B, // input ,B
input [3:0] select, // input select
output reg [7:0] result, // output result
output reg carry_flag, // output carry_flag
output reg overflow_flag, // output overflow_flag
output reg zero_flag, // output zero_flag
output reg negative_flag // output negative_flag
);
always@(*)begin
carry_flag = 0;
overflow_flag = 0;
zero_flag = 0;
negative_flag = 0;
case(select)
4'b0000:begin
{carry_flag,result} = A+B;
overflow_flag =(A[7] == B[7])&&(A[7]!=result[7]);
end
4'b0001:begin
{carry_flag,result} = A-B;
overflow_flag = (A[7] != B[7])&&(A[7]!=result[7]);
end
4'b0010:result = A*B;
43
250280763009 ME02000181
4'b0011:begin
if(B!=0)begin
result = A/B;
end
else begin
result = 8'b00000000;
end
end
// conditon
4'b0100:result = A&B;
4'b0101:result = A|B;
4'b0110:result = ~(A&B);
4'b0111:result = ~(A|B);
4'b1000:result = A^B;
4'b1001:result = A~^B;
4'b1010:result = ~A;
default:result = 8'b00000000; endcase
if(result == 8'b00000000) zero_flag = 1;
else zero_flag = 0;
if(result[7] == 1) negative_flag = 1;
else negative_flag = 0;
end
endmodule
TESTBENCH:
module alu_tb();
reg [7:0] A,B; // input A,B
reg [3:0] select; // input select
wire [7:0] result; // output result
wire carry_flag; // output carry_flag
wire overflow_flag; // output overflow_flag
wire zero_flag; // output zero_flag
wire negative_flag; // output negative_flag
integer i;
alu uut(A,B,select,result,carry_flag,overflow_flag,zero_flag,negative_flag);
initial begin
A = 0; B = 0; select = 0; // Initialize everything
#10;
// dumpfile for OUTPUT WAVEFORM form
$dumpfile("alu_tb.vcd");
$dumpvars(0,alu_tb);
// conditon
for(i=0;i<12;i=i+1) begin
44
250280763009 ME02000181
select = i;
A = i;B = i+1; #10;
end
OUTPUT WAVEFORM:
CODE COVERAGE:
45
250280763009 ME02000181
EXPERIMENT 6
RAM (Random Access Memory) is a type of volatile memory used to store data temporarily in digital
systems like microprocessors, microcontrollers, and FPGAs/ASICs. It allows both read and write operations.
Functional Blocks
Operation
Write Operation (we = 1):
On rising edge of clk, data_inis stored at addr.
Read Operation (we = 0):
On rising edge of clk, the content of addris placed on data_out.
Applications
DESIGN CODE:
module ram_32bit # (
parameter DATA_WIDTH = 32, // Width of each data word (32-bit)
parameter ADDR_WIDTH = 6, // 6 bits allows 64 memory locations (2^6)
parameter DEPTH = 64 // Total number of memory slots
)(
input clk, // System clock
input write_enable, // 1 = Write mode, 0 = Read mode
46
250280763009 ME02000181
endmodule
TESTBENCH:
module ram_32bit_tb;
reg clk;
reg write_enable;
reg [ADDR_WIDTH-1:0] address;
reg [DATA_WIDTH-1:0] data_in;
wire [DATA_WIDTH-1:0] data_out;
integer i;
initial begin
// --- STEP 1: INITIAL STATE SETTING ---
clk = 0;
write_enable = 0;
address = 0;
data_in = 0;
// Wait 5ns to move completely away from the posedge clk boundaries
#5;
// --- STEP 2: CLEAR ALL 'X' BY FILLING ENTIRE ARRAY WITH 0s ---
// Every input change happens cleanly on the NEGEDGE of the clock
for (i = 0; i < DEPTH; i = i + 1) begin
@(negedge clk);
write_enable = 1;
address = i;
data_in = {DATA_WIDTH{1'b0}};
end
#40;
// --- STEP 4: TOGGLE ALL INDIVIDUAL ADDRESS BITS ---
@(negedge clk);
write_enable = 0; // Keep in read mode to test clean address changes
for (i = 0; i < ADDR_WIDTH; i = i + 1) begin
address = (1 << i);
@(negedge clk);
address = 0;
end
#40;
// --- STEP 5: WRITE ALL 1s TO ALL SLOTS (0 -> 1 Toggle) ---
for (i = 0; i < DEPTH; i = i + 1) begin
@(negedge clk);
write_enable = 1;
address = i;
data_in = {DATA_WIDTH{1'b1}};
end
48
250280763009 ME02000181
#40;
// --- STEP 6: READ ALL 1s (Forces data_out 0 -> 1 Toggle) ---
for (i = 0; i < DEPTH; i = i + 1) begin
@(negedge clk);
write_enable = 0;
address = i;
end
#40;
// --- STEP 7: WRITE ALL 0s TO ALL SLOTS (1 -> 0 Toggle) ---
for (i = 0; i < DEPTH; i = i + 1) begin
@(negedge clk);
write_enable = 1;
address = i;
data_in = {DATA_WIDTH{1'b0}};
end
#40;
// --- STEP 8: READ ALL 0s (Forces data_out 1 -> 0 Toggle) ---
for (i = 0; i < DEPTH; i = i + 1) begin
@(negedge clk);
write_enable = 0;
address = i;
end
endmodule
OUTPUT WAVEFORM:
49
250280763009 ME02000181
CODE COVERAGE
:
50
250280763009 ME02000181
EXPERIMENT 7
Observation Point Insertion (OPI) is a crucial technique in digital design that allows for easier debugging
and testing by adding specific points in the circuit where internal signals can be monitored. This
technique can be especially useful during simulation and on-chip debugging processes. Below, I present
a detailed theory and a practical Verilog HDL code example to illustrate the functioning of the
Observation Point Insertion Technique.
Application:
Debugging: To facilitate the debugging process by providing visibility into the internal signals of a
digital circuit.
Testing: To enhance the testing capabilities by
allowing specific points in the circuit to be observed during various test scenarios.
Simulation: During the simulation phase, observation points help in monitoring and verifying the
internal signal states without affecting the circuit's functionality.
Hardware Debugging: On-chip observation points can be routed to debug interfaces to observe real-
time signal states during hardware testing.
DESIGN CODE:
module ObservationPointCircuit (
input wire a, // Input signal a
input wire b, // Input signal b
output wire y, // Output signal y
output wire obs // Observation point output
);
// Step 1: G1 - OR gate operation
wire g1_out;
assign g1_out = a | b;
// Step 2: Observation point assignment
assign obs = g1_out;
// Step 3: G2 - AND gate operation
assign y = g1_out & a;
endmodule
51
250280763009 ME02000181
TESTBENCH:
module Testbench;
reg a, b;
wire y, obs;
ObservationPointCircuit uut (
.a(a),
.b(b),
.y(y),
.obs(obs)
);
initial begin
a = 0; b = 0;
#10 a = 1; b = 0;
#10 a = 1; b = 1;
#10 a = 0; b = 1;
#10 a = 1; b = 1;
#10 a = 0; b = 0;
#10 $finish;
end
initial begin
$monitor("At time %t: a = %b, b = %b, obs = %b, y = %b",
$time, a, b, obs, y);
end
endmodule
OUTPUT WAVEFORM:
52
250280763009 ME02000181
CODE COVERAGE:
53
250280763009 ME02000181
EXPERIMENT 8
In digital circuit design, particularly for Design for Testability (DFT), Control Point Insertion (CPI) is a
technique where additional logic is inserted into a circuit to improve its controllability during testing.
The goal is to make internal nodes easily set to a known value (0 or 1) during scan testing without affecting
the normal functional behavior.
In CPI:
Typically, this is implemented using a 2:1 multiplexer that selects between normal output and a forced value
based on a test_mode signal.
Advantages:
Increases fault coverage.
Reduces test pattern generation complexity.
Enhances circuit testability without significantly affecting performance.
DESIGN CODE:
module control_point_insertion (
input wire a,
input wire b,
input wire test_mode, // 1 for test mode, 0 for normal operation
input wire control_value, // Forced value in test mode
output wire y
);
wire normal_output;
// Original functional logic
assign normal_output = a & b;
// Control point logic
assign y = (test_mode) ? control_value : normal_output;
54
250280763009 ME02000181
endmodule
TESTBENCH:
module control_point_insertion_tb;
// Testbench signals
reg a, b;
reg test_mode;
reg control_value;
wire y;
55
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
56
250280763009 ME02000181
EXPERIMENT 9
Write HDL code for MUX-D scan cell and Level Sensitive/Edge Triggered MUXED-D scan cell.
A MUX-D Scan Cell is a type of flip-flop used in scan chains during digital circuit testing, particularly in
the context of scan-based testing and design-for-testability (DFT). This flip-flop combines both normal
data storage (as in a standard flip-flop) and the ability to participate in scan chains used for easier testing
and debugging of digital circuits.
Key Concepts:
1. Multiplexer (MUX): A multiplexer is a combinational circuit that selects one of many inputs
based on control signals and outputs it. In the case of a scan cell, a multiplexer is used to select
between the normal data input (d) and the scan input (scan_in). This allows the flip-flop to
behave as a regular flip-flop when the scan mode is not enabled, but when the scan mode is
enabled, the scan input can be passed through to the output.
2. Scan Mode: In scan-based testing, the normal behavior of a flip-flop is overridden by the scan
chain, which is used to shift in test vectors and shift out captured data. When the scan_enable
signal is activated, the scan input (scan_in) takes precedence over the normal data input (d). This
enables the testing of the circuit by manipulating the flip-flops in a controlled sequence.
3. Flip-Flop: A flip-flop is a fundamental memory element that stores a single bit of data. It
typically has two stable states: 0 and 1. A flip-flop is triggered on a specific edge of a clock signal
(positive or negative) and can have an asynchronous reset that forces the output to a known value
(e.g., 0) when the reset signal is asserted.
DESIGN CODE:
module MUX_D_Scan_Cell (
input wire clk, // Clock signal
input wire rst_n, // Active-low reset signal
input wire scan_in, // Scan input for testing
input wire scan_enable, // Control signal to enable scan mode
input wire d, // Normal data input
output reg q // Output of the scan cell (change to reg)
);
57
250280763009 ME02000181
wire mux_out;
// Multiplexer that selects between normal data (D) and scan data (scan_in)
assign mux_out = scan_enable ? scan_in : d;
endmodule
TESTBENCH:
module tb_MUX_D_Scan_Cell;
// Testbench signals
reg clk;
reg rst_n;
reg scan_in;
reg scan_enable;
reg d;
wire q;
// Test sequence
initial begin
$dumpfile("[Link]");
$dumpvars(0, tb_MUX_D_Scan_Cell);
58
250280763009 ME02000181
initial begin
$monitor("Time = %0t, rst_n = %b, scan_in = %b, scan_enable = %b, d = %b, q = %b",
$time, rst_n, scan_in, scan_enable, d, q);
end
endmodule
59
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
60
250280763009 ME02000181
DESIGN CODE:
module level_edge_Scan_Cell (
input wire clk, // Clock signal
input wire rst_n, // Active-low reset signal
input wire scan_in, // Scan input for testing
input wire scan_enable, // Control signal to enable scan mode
input wire d, // Normal data input
output reg q // Output of the scan cell
);
wire mux_out;
// Multiplexer to select between normal data (D) and scan data (scan_in)
assign mux_out = scan_enable ? scan_in : d;
endmodule
TESTBENCH:
module tb_level_edge_Scan_Cell;
// Testbench signals
reg clk;
reg rst_n;
reg scan_in;
reg scan_enable;
reg d;
wire q;
// Clock generation
always begin
#5 clk = ~clk; // Generate clock with a period of 10 time units
end
// Test sequence
initial begin
// Initialize signals
clk = 0;
rst_n = 0;
scan_in = 0;
scan_enable = 0;
d = 0;
// Apply reset
#10 rst_n = 1;
// End simulation
#10 $finish;
end
// Display output
initial begin
$monitor("Time = %0t, rst_n = %b, scan_in = %b, scan_enable = %b, d = %b, q = %b",
$time, rst_n, scan_in, scan_enable, d, q);
end
endmodule
62
250280763009 ME02000181
OUTPUT WAVEFORM:
CODE COVERAGE:
63
250280763009 ME02000181
EXPERIMENT 10
Write a HDL code to realize functioning of clocked scan cell and LSSD scan cell design.
Clocked Scan
A Clocked Scan Cell (CSC) is a specialized type of flip-flop used primarily in scan-based testing for
digital circuits. In this context, it allows for efficient testing of a circuit's internal nodes by enabling easier
control and observation of flip-flops during the testing phase.
Key Features:
1. Scan Input and Normal Input: The CSC can capture data either from a normal input (D) or a scan
input (Scan) depending on a control signal. The control signal, typically referred to as
scan_enable, dictates whether the CSC is functioning in normal mode or scan mode.
2. Scan Mode: In scan mode (when scan_enable is active), the CSC connects its scan input to its
data input, enabling the insertion of test vectors into the flip-flop chain, which is crucial for
functional and structural testing.
3. Normal Mode: When scan_enable is inactive, the CSC operates as a standard flip-flop, capturing
data from the normal data input.
4. Shift and Capture Operations: The CSC is often part of a shift-register chain that allows for serial
shifting of test data (in scan mode) and capturing of output data during the testing process.
Applications:
Scan-Based Testing: Essential for Design for Testability (DFT), where multiple CSCs are
connected to form a scan chain. This allows for easier test pattern application and fault detection
in the circuit's sequential logic.
Improved Fault Coverage: By using scan chains and CSCs, complex logic circuits can be
tested more effectively, improving fault detection capabilities.
DESIGN CODE:
module CSC_Scan_Cell (
input wire clk, // Clock signal
input wire rst_n, // Active-low reset signal
input wire scan_in, // Scan input for testing
input wire scan_enable, // Control signal to enable scan mode
input wire d, // Normal data input
output reg q // Output of the scan cell
);
64
250280763009 ME02000181
wire mux_out;
// Multiplexer that selects between normal data (D) and scan data (scan_in)
assign mux_out = scan_enable ? scan_in : d;
TESTBENCH:
module tb_CSC_Scan_Cell;
// Testbench signals
reg clk;
reg rst_n;
reg scan_in;
reg scan_enable;
reg d;
wire q;
// Clock generation
always begin
#5 clk = ~clk; // Generate a clock with a period of 10 time units
end
// Test sequence
initial begin
$dumpfile("[Link]"); $dumpvars;
// Initialize signals
clk = 0;
rst_n = 0;
scan_in = 0;
65
250280763009 ME02000181
scan_enable = 0;
d = 0;
// Apply reset
#10 rst_n = 1;
// End simulation
#10 $finish;
end
// Display output
initial begin
$monitor("Time = %0t, rst_n = %b, scan_in = %b, scan_enable = %b, d = %b, q = %b",
$time, rst_n, scan_in, scan_enable, d, q);
end
endmodule
OUTPUT WAVEFORM:
66
250280763009 ME02000181
CODE COVERAGE:
The LSSD Scan Cell (Level-Sensitive Scan Design) is a type of flip-flop used in scan-based testing and is
commonly employed in Design for Testability (DFT). It allows for controlled access to the internal flip-
flop states during testing, making it easier to test sequential logic in digital circuits. The LSSD Scan Cell
can operate in two modes:
1. Scan Mode: When the scan_enable signal is active, the cell bypasses the normal data input (D)
and instead accepts the data from the scan_in input. This allows test patterns to be shifted into the
circuit, enabling fault detection and easier debugging.
2. Normal Mode: When scan_enable is inactive, the LSSD Scan.
Cell behaves like a regular flip-flop, capturing the data from the normal input (D).
The LSSD Scan Cell has a level-sensitive latch mechanism that responds to the clock (clk) and active-low
reset (rst_n) signals. It latches data based on the control signal, scan_enable, and stores the output in the q
register.
Clock: The latch captures the data on the rising edge of the clock.
Reset (rst_n): When the reset is active-low, the output q is reset to 0.
Scan Input (scan_in): Used for testing purposes, when scan_enable is high.
Data Input (d): Used in normal operation, when scan_enable is low.
67
250280763009 ME02000181
DESIGN CODE:
module LSSD_Scan_Cell (
input wire clk, // Clock signal
input wire rst_n, // Active-low reset signal
input wire scan_in, // Scan input for testing
input wire scan_enable, // Control signal to enable scan mode
input wire d, // Normal data input
output reg q // Output of the scan cell
);
// Multiplexer that selects between normal data (D) and scan data (scan_in)
wire mux_out;
assign mux_out = scan_enable ? scan_in : d;
endmodule
TESTBENCH:
module tb_LSSD_Scan_Cell;
// Testbench signals
reg clk;
reg rst_n;
reg scan_in;
reg scan_enable;
reg d;
wire q;
68
250280763009 ME02000181
// Clock generation
always begin
#5 clk = ~clk; // 10ns period
end
// Test sequence
initial begin
$dumpfile("[Link]");
$dumpvars(0, tb_LSSD_Scan_Cell);
// 8. End simulation with a final delay to ensure all toggles are recorded
#20 $finish;
end
// Display output
initial begin
$monitor("Time = %0t, rst_n = %b, scan_in = %b, scan_enable = %b, d = %b, q = %b",
$time, rst_n, scan_in, scan_enable, d, q);
end
69
250280763009 ME02000181
endmodule
OUTPUT WAVEFORM:
CODE COVERAGE:
70
250280763009 ME02000181
EXPERIMENT 11
Write a HDL code to realize functioning of LSSD double latch design.
Level Sensitive Scan Design (LSSD) is a testing technique used in digital circuits to facilitate easy testing
and diagnosis of faults. It uses a combination of scan chains and special latch structures to allow test
signals to be inserted into the circuit and test results to be observed.
The LSSD Double Latch design is part of this testing framework, and it specifically involves two latches
that are used together to enhance testability. The primary goal is to create a mechanism that supports both
normal functional operation of the circuit and its scan-based operation for testing
Key Features:
1. Two Latches:
o Latch1 captures input data, while Latch2 holds and propagates it, forming a pipeline for
data flow.
2. Scan Mode vs Normal Mode:
o Scan Mode: Captures test vectors for boundary scan testing.
o Normal Mode: Holds functional data in the latches for regular operation.
3. Testability:
o Part of a scan chain, allowing external test equipment to control and observe internal
states, improving fault detection.
4. Operation:
o In Normal Mode, data flows from Latch1 to Latch2. In Scan Mode, scan inputs are used to
load and shift test data.
5. Advantages:
o Fault Isolation and Test Efficiency: Enables better control and faster testing by utilizing
scan chains and latches.
DESIGN CODE:
module lssd_double_latch (
input wire clk, // Clock signal
input wire rst_n, // Active-low reset signal
input wire data_in, // Input data to be latched
input wire scan_in, // Scan input for test purposes
input wire scan_mode, // Scan mode control (1 for scan mode, 0 for normal operation)
output reg data_out // Output data from the latch
);
71
250280763009 ME02000181
TESTBENCH:
module tb_lssd_double_latch;
// Declare inputs and outputs for the testbench
reg clk;
reg rst_n;
reg data_in;
reg scan_in;
reg scan_mode;
wire data_out;
// Test sequence
initial begin
$dumpfile("[Link]"); $dumpvars;
// Synchronize with the clock edge to avoid setup/hold race conditions in simulation
@(posedge clk);
#2; // Small delay after clock edge to mimic physical signal settling
// We need multiple clock cycles to push the '1' through latch1, then latch2, then data_out
@(posedge clk); #2; // latch1 becomes 1
@(posedge clk); #2; // latch2 and data_out become 1
// Run for two more clock cycles to make sure XSIM processes the final evaluation
@(posedge clk);
@(posedge clk);
end
// Display output
initial begin
$monitor("Time = %0t, rst_n = %b, data_in = %b, scan_in = %b, scan_mode = %b, data_out = %b",
$time, rst_n, data_in, scan_in, scan_mode, data_out);
end
endmodule
OUTPUT WAVEFORM:
CODE COVERAGE:
74
250280763009 ME02000181
EXPERIMENT 12
Write a HDL code to realize functioning of fixing bus contention in scan design rules.
Bus Arbitration is a mechanism used in digital systems to ensure that multiple devices (or drivers) do not
attempt to drive the same bus at the same time, which would lead to bus contention and potentially cause
data corruption or hardware damage.
Arbitration Methods:
Priority-based Arbitration: Devices are assigned priorities, and the device with the highest
priority gains access to the bus first. This can be implemented using a simple priority encoder.
Round-Robin Arbitration: Each device gets a fair chance to access the bus in a cyclic order,
preventing starvation of lower-priority devices.
First-Come-First-Served (FCFS): The first device requesting access to the bus is granted
permission to drive the bus, and the order is maintained.
75
250280763009 ME02000181
In a scan-based design, this arbitration prevents issues like bus contention, ensuring that scan chains (used
for testing) are properly driven during testing phases.
DESIGN CODE:
TESTBENCH:
module tb_bus_arbitration;
// Declare testbench signals
reg clk;
reg reset;
reg scan_mode; reg driver_a_valid; reg driver_b_valid; reg driver_c_valid;
reg [7:0] driver_a_data;
reg [7:0] driver_b_data;
reg [7:0] driver_c_data;
wire [7:0] bus_data;
// Instantiate the bus_arbitration module
bus_arbitration uut (
.clk(clk),
.reset(reset),
.scan_mode(scan_mode),
.driver_a_valid(driver_a_valid),
.driver_b_valid(driver_b_valid),
.driver_c_valid(driver_c_valid),
.driver_a_data(driver_a_data),
76
250280763009 ME02000181
.driver_b_data(driver_b_data),
.driver_c_data(driver_c_data),
.bus_data(bus_data)
);
// Clock generation
always begin
#5 clk = ~clk; // 100MHz clock (period = 10ns)
end
// Apply reset
#10 reset = 0;
#10 reset = 1;
#10 reset = 0;
// Start scan mode
#10 scan_mode = 0;
#10 scan_mode = 1;
#10;
$display("Bus Data: %b (Expected: 00110011)", bus_data);
// Test case 5: Driver A and Driver B are both valid, but A has priority
driver_a_valid = 1;
driver_b_valid = 1;
driver_a_data = 8'b01010101;
driver_b_data = 8'b00001111;
driver_c_valid = 0;
#10;
$display("Bus Data: %b (Expected: 01010101)", bus_data); // A has priority over B
// Test case 9: All drivers are valid (only A should drive the bus)
driver_a_valid = 1;
driver_b_valid = 1;
78
250280763009 ME02000181
driver_c_valid = 1;
driver_a_data = 8'b10101010;
driver_b_data = 8'b00000000;
driver_c_data = 8'b10101010;
#10;
$display("Bus Data: %b (Expected: 10101010)", bus_data); // A has priority over others
#10 scan_mode = 0;
#10;
$display("Bus Data: %b (Expected: 00000000)", bus_data);
// End simulation
$finish; // Ensure this is inside the initial block
end
endmodule
OUTPUT WAVEFORM:
79
250280763009 ME02000181
CODE COVERAGE:
80