1
DEPARTMENT OF ELECTRICAL AND ELECTRONIC ENGINEERING
CHITTAGONG UNIVERSITY OF ENGINEERING AND TECHNOLOGY
CHATTOGRAM – 4349, BANGLADESH
Experiment No. 6
Implementation of Design Under Test and Test Bench of Combinational Logic
PRECAUTIONS:
• Students must carefully read the lab manual before coming to the lab to avoid any
inconveniences.
• Students must carry a flash drive to transfer files and lab manuals.
• Use of mobile phones in the lab is strictly prohibited and punishable offence.
• Experiment files must be uploaded to GitHub including home tasks.
OBJECTIVES:
• To implement combinational logic circuits using a Hardware Description Language
(HDL).
• To develop comprehensive testbenches for the functional verification of combinational
logic designs.
• To analyze simulation results to ensure the correctness of implemented combinational
logic circuits.
THEORY:
Combinational logic forms the bedrock of digital circuit design, where the output of a
circuit depends solely on its current inputs. Unlike sequential logic, combinational circuits do not
possess memory elements, meaning their behavior is entirely governed by the instantaneous values
applied to their input terminals. Fundamental building blocks include basic logic gates such as
AND, OR, NOT, NAND, NOR, XOR, and XNOR, which can be combined to perform complex
Boolean functions. These circuits are essential for operations like arithmetic calculations, data
selection, and code conversion, and are often designed using Hardware Description Languages
(HDLs) like Verilog or VHDL, which allow for a high-level abstraction of the circuit's behavior
and structure.
In the design and verification flow of digital circuits, the term Device Under Test (DUT)
refers to the specific circuit or component that is being designed and evaluated for its functional
correctness and performance. The DUT embodies the combinational logic circuit that has been
designed and implemented, perhaps using an HDL. It is the core intellectual property (IP) whose
behavior needs to be rigorously confirmed against its specifications. The DUT is isolated from the
test environment and interacts solely through its defined input and output ports.
To ensure the reliability and proper functioning of the DUT, a Testbench (TB) is
developed. A testbench is a separate piece of HDL code specifically written to simulate the
environment in which the DUT will operate. Its primary role is to generate appropriate input
stimuli for the DUT, apply these stimuli over time, and then monitor and compare the DUT's
outputs against expected reference values. This process, known as functional verification, helps
identify any design flaws or inconsistencies before the circuit is fabricated. A well-designed
2
testbench is crucial for comprehensive verification, providing confidence that the combinational
logic circuit will perform as intended in a real-world application.
IMPLEMENTATION:
Simple Module:
A module declaration in an HDL (Hardware Description Language) serves as the
fundamental building block for organizing and encapsulating digital circuit designs. It defines the
interface of a specific component, specifying its inputs, outputs, and internal signals. This
structured approach allows for hierarchical design, where complex systems are built by
interconnecting smaller, well-defined modules.
DUT:
module sillyfunction(input logic a, b, c,
output logic y);
assign y = ~a & ~b & ~c |
a & ~b & ~c |
a & ~b & c;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic a, b, c;
logic y;
// Instantiate the design
sillyfunction uut (
.a(a), .b(b), .c(c), .y(y)
);
initial begin
$dumpfile("wave.vcd"); // waveform dump file
$dumpvars(0, testbench); // dump everything in testbench
for (int i = 0; i < 8; i++) begin
{a, b, c} = i;
#5; // give time for wave to show change
end
$finish;
end
endmodule
Waveform:
32 Bit Adder:
A simple 32-bit adder is a fundamental arithmetic logic unit designed to perform the binary
addition of two 32-bit numbers. Typically implemented by cascading multiple 1-bit full adders, it
computes the sum and carry-out for each bit position. This component is crucial in central
processing units (CPUs) and various digital signal processing applications for its role in
performing essential arithmetic operations.
DUT:
3
module adder(
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] y
);
assign y = a + b;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [31:0] a, b;
logic [31:0] y;
// Instantiate the adder
adder uut (
.a(a), .b(b), .y(y)
);
initial begin
$dumpfile("wave.vcd"); // Enable waveform dumping
$dumpvars(0, testbench); // Dump all variables in
testbench
a = 32'd10; b = 32'd5; #5;
a = 32'd100; b = 32'd200; #5;
a = 32'd0; b = 32'd0; #5;
a = 32'hFFFF_FFFF; b = 32'd1; #5; // check overflow wrap-
around
$finish;
end
endmodule
Waveform:
Inverter:
Bitwise operations are fundamental digital operations that process individual bits of binary
numbers independently, such as AND, OR, XOR, and NOT, forming the basis of all digital
computation. First, an inverter is explored.
DUT:
module inv(
input logic [3:0] a,
output logic [3:0] y
);
assign y = ~a;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] a;
logic [3:0] y;
4
// Instantiate the inverter
inv uut (
.a(a), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
a = 4'b0000; #5;
a = 4'b1010; #5;
a = 4'b1111; #5;
a = 4'b0101; #5;
$finish;
end
endmodule
Waveform:
Basic Gates:
Other basic gates are now explored.
DUT:
module gates(
input logic [3:0] a, b,
output logic [3:0] y1, y2, y3, y4, y5
);
// Five different two-input logic gates acting on 4-bit buses
assign y1 = a & b; // AND
assign y2 = a | b; // OR
assign y3 = a ^ b; // XOR
assign y4 = ~(a & b); // NAND
assign y5 = ~(a | b); // NOR
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] a, b;
logic [3:0] y1, y2, y3, y4, y5;
// Instantiate the gates module
gates uut (
.a(a), .b(b),
.y1(y1), .y2(y2), .y3(y3), .y4(y4), .y5(y5)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
5
// Test vectors
a = 4'b0000; b = 4'b0000; #5;
a = 4'b1010; b = 4'b1100; #5;
a = 4'b1111; b = 4'b0000; #5;
a = 4'b0101; b = 4'b1010; #5;
$finish;
end
endmodule
Waveform:
Reduction Operators:
Reduction operators in hardware description languages, such as Verilog, are powerful
constructs that perform a bitwise operation across all bits of a single vector (or "bus") and produce
a single-bit result. Essentially, they simulate a large, multi-input gate where all inputs are derived
from the individual bits of the given bus.
DUT:
module and8(
input logic [7:0] a,
output logic y
);
assign y = &a;
// &a is the reduction AND of all bits
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [7:0] a;
logic y;
// Instantiate the and8 module
and8 uut (
.a(a), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
a = 8'b00000000; #5;
a = 8'b11111111; #5;
a = 8'b11111110; #5;
a = 8'b10101010; #5;
a = 8'b00001111; #5;
$finish;
end
endmodule
Waveform:
6
Conditional Assignment:
Conditional assignments, often implemented using the ternary operator or if-else structures
in HDLs, enable the selection of an output value from a set of alternatives. This selection is directly
controlled by an input signal or expression referred to as "the condition." If the condition evaluates
to true, one output is chosen; otherwise, a different output is assigned, allowing for the
implementation of multiplexers or other data-selection logic.
DUT:
module mux2(
input logic [3:0] d0, d1,
input logic s,
output logic [3:0] y
);
assign y = s ? d1 : d0;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] d0, d1;
logic s;
logic [3:0] y;
// Instantiate the mux2 module
mux2 uut (
.d0(d0), .d1(d1), .s(s), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
d0 = 4'b0001; d1 = 4'b1110; s = 0; #5;
s = 1; #5;
d0 = 4'b1010; d1 = 4'b0101; s = 0; #5;
s = 1; #5;
$finish;
end
endmodule
Waveform:
DUT:
module mux4(
input logic [3:0] d0, d1, d2, d3,
input logic [1:0] s,
output logic [3:0] y
);
assign y = s[1] ? (s[0] ? d3 : d2)
: (s[0] ? d1 : d0);
endmodule
7
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] d0, d1, d2, d3;
logic [1:0] s;
logic [3:0] y;
// Instantiate the mux4 module
mux4 uut (
.d0(d0), .d1(d1), .d2(d2), .d3(d3),
.s(s), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
// Set inputs
d0 = 4'b0001;
d1 = 4'b0010;
d2 = 4'b0100;
d3 = 4'b1000;
// Test each select value
s = 2'b00; #5; // y should be d0
s = 2'b01; #5; // y should be d1
s = 2'b10; #5; // y should be d2
s = 2'b11; #5; // y should be d3
$finish;
end
endmodule
Waveform:
Internal Variables:
In digital design, especially when implementing complex functions within a module, it is
often beneficial to declare internal variables (also known as "wires" or "registers" in HDLs). These
variables serve as intermediate nodes, allowing a complex function to be broken down into
simpler, manageable steps. By assigning intermediate results to these internal variables, designers
can improve code readability, facilitate debugging, and sometimes optimize the synthesized
hardware by preventing redundant logic.
DUT:
module fulladder(
input logic a, b, cin,
output logic s, cout
);
logic p, g;
assign p = a ^ b;
assign g = a & b;
assign s = p ^ cin;
assign cout = g | (p & cin);
endmodule
8
TB:
`timescale 1ns/1ps
module testbench;
logic a, b, cin;
logic s, cout;
// Instantiate the full adder
fulladder uut (
.a(a), .b(b), .cin(cin),
.s(s), .cout(cout)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
// Test all input combinations (a, b, cin)
for (int i = 0; i < 8; i++) begin
{a, b, cin} = i;
#5;
end
$finish;
end
endmodule
Waveform:
Tristate:
Tristate buffers are essential digital components that can assume three states: logic 0, logic
1, and a high-impedance (floating) state, denoted by 'z' in Hardware Description Languages
(HDLs). This 'z' state signifies that the output is effectively disconnected, neither driving a logic
high nor a logic low. Tristate buffers are particularly useful for designing shared bus architectures,
where multiple drivers can connect to a single bus, but only one tristate buffer is actively enabled
at any given time to drive the bus, preventing contention.
DUT:
module tristate(
input logic [3:0] a,
input logic en,
output tri [3:0] y
);
assign y = en ? a : 4'bz;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] a;
logic en;
tri [3:0] y;
9
// Instantiate the tristate module
tristate uut (
.a(a), .en(en), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
a = 4'b1010;
en = 0; #5; // y should be high-impedance (z)
en = 1; #5; // y should reflect a
a = 4'b1100; #5;
en = 0; #5; // back to high-impedance
$finish;
end
endmodule
Waveform:
Bit Swizzling:
Bit swizzling refers to the manipulation of bits within or across buses, often involving extracting
a subset of bits or combining individual signals or smaller buses into a larger one. These operations,
such as concatenation or part-selects, are commonly used in hardware description languages to
correctly align data for various circuit functionalities. They are fundamental for efficiently
organizing and transferring data between different components of a digital design.
DUT:
module mul(
input logic [7:0] a, b,
output logic [7:0] upper, lower
);
assign {upper, lower} = a * b; // product gets auto-expanded
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [7:0] a, b;
logic [7:0] upper, lower;
mul uut (
.a(a), .b(b),
.upper(upper), .lower(lower)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
a = 8'd15; b = 8'd10; #5; // 150 = 0x0096
a = 8'd255; b = 8'd255; #5; // 65025 = 0xFE01
a = 8'd16; b = 8'd4; #5; // 64 = 0x0040
$finish;
10
end
endmodule
Waveform:
Delay:
Delays can be associated with statements to model the time taken for signals to propagate
through a circuit. These delays are crucial during simulation for two main reasons: they help
predict the actual speed and performance of the circuit by reflecting real-world timing
characteristics, and they significantly aid in debugging by illustrating the cause-and-effect
relationships between signals, making it easier to pinpoint the source of errors when signals change
sequentially rather than simultaneously.
DUT:
`timescale 1ns/1ps
module example(
input logic a, b, c,
output logic y
);
logic ab, bb, cb, n1, n2, n3;
assign #1 {ab, bb, cb} = ~{a, b, c}; // Invert a, b, c with
1ns delay
assign #2 n1 = ab & bb & cb; // n1 = ~a & ~b & ~c
assign #2 n2 = a & bb & cb; // n2 = a & ~b & ~c
assign #2 n3 = a & bb & c; // n3 = a & ~b & c
assign #4 y = n1 | n2 | n3; // y = n1 | n2 | n3
(final output with 4ns delay)
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic a, b, c;
logic n1, n2, n3, y;
example uut (
.a(a), .b(b), .c(c), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
// Test different input combinations
a = 0; b = 0; c = 0; #20;
a = 1; b = 0; c = 0; #20;
a = 1; b = 0; c = 1; #20;
a = 1; b = 1; c = 1; #20;
$finish;
end
endmodule
11
Waveform:
Structural Modeling:
Structural modeling in hardware description languages involves describing a digital circuit
by instantiating and interconnecting lower-level components. This approach focuses on how gates
and modules are physically connected, representing the circuit's netlist rather than its behavior,
much like drawing a schematic in code.
DUT:
module mux4(
input logic [3:0] d0, d1, d2, d3,
input logic [1:0] s,
output logic [3:0] y
);
logic [3:0] low, high;
mux2 lowmux(d0, d1, s[0], low);
mux2 highmux(d2, d3, s[0], high);
mux2 finalmux(low, high, s[1], y);
endmodule
module mux2(
input logic [3:0] d0, d1,
input logic s,
output logic [3:0] y
);
tri [3:0] y_tri;
tristate t0(d0, ~s, y_tri);
tristate t1(d1, s, y_tri);
assign y = y_tri; // resolve tri to logic for final output
endmodule
module tristate(
input logic [3:0] a,
input logic en,
output tri [3:0] y
);
assign y = en ? a : 4'bz;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [3:0] d0, d1, d2, d3;
logic [1:0] s;
logic [3:0] y;
mux4 uut (
.d0(d0), .d1(d1), .d2(d2), .d3(d3),
.s(s), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
12
d0 = 4'b0001;
d1 = 4'b0010;
d2 = 4'b0100;
d3 = 4'b1000;
s = 2'b00; #5; // expect d0
s = 2'b01; #5; // expect d1
s = 2'b10; #5; // expect d2
s = 2'b11; #5; // expect d3
$finish;
end
endmodule
Waveform:
DUT:
module mux2_8(
input logic [7:0] d0, d1,
input logic s,
output logic [7:0] y
);
mux2 lsbmux(d0[3:0], d1[3:0], s, y[3:0]);
mux2 msbmux(d0[7:4], d1[7:4], s, y[7:4]);
endmodule
module mux2(
input logic [3:0] d0, d1,
input logic s,
output logic [3:0] y
);
assign y = s ? d1 : d0;
endmodule
TB:
`timescale 1ns/1ps
module testbench;
logic [7:0] d0, d1;
logic s;
logic [7:0] y;
mux2_8 uut (
.d0(d0), .d1(d1), .s(s), .y(y)
);
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, testbench);
d0 = 8'b00001111;
d1 = 8'b11110000;
s = 0; #5; // y = d0
s = 1; #5; // y = d1
13
$finish;
end
endmodule
Waveform:
14
Rubrics:
Criteria Below Average (1) Average (2) Good (3)
All sections (objectives,
theory, code, etc.) are
Some formatting
clearly delineated,
inconsistencies, minor
consistent
Formatting deviations from
headings/subheadings,
expected structure, or
appropriate use of bullet
occasional untidiness.
points/lists, and overall
neatness.
Clear, concise, and
Generally clear, but
professional language
with minor
used throughout.
Writing grammatical errors,
Excellent grammar,
typos, or occasional
spelling, and punctuation
awkward phrasing.
with no errors.
Comprehensive and
accurate explanation of
Basic understanding of Good explanation of
theoretical concepts
concepts, with concepts, but may lack
(combinational logic,
significant gaps or depth in certain areas or
DUT, TB, etc.).
Explanation inaccuracies in have minor inaccuracies.
Demonstrates a deep
explanation. Poor or Interpretation of results is
understanding of the
missing interpretation generally correct but
experiment's principles
of results. could be more thorough.
and results are clearly
interpreted.
All diagrams (e.g., truth
Most diagrams are clear
tables, block diagrams,
Diagrams are unclear, and relevant, but may
waveforms) are relevant,
poorly labeled, have minor labeling
Diagrams clear, correctly labeled,
irrelevant, or contain issues, slight
and accurately represent
significant errors. inaccuracies, or some
the described concepts or
missing elements.
code.
Better dead than dull.