Basic Logic Gates
AND Gate
Outputs 1 only if both inputs are 1.
and_gate.v
// 2-input AND gate
module and_gate(
input a, b,
output y
);
assign y = a & b;
endmodule
tb_and_gate.v
module tb_and_gate;
reg a, b;
wire y;
and_gate uut (.a(a), .b(b), .y(y));
initial begin
$monitor("A=%b, B=%b, Y=%b", a, b, y);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
OR Gate
Outputs 1 if at least one input is 1.
or_gate.v
// 2-input OR gate
module or_gate(
input a, b,
output y
);
assign y = a | b;
endmodule
tb_or_gate.v
module tb_or_gate;
reg a, b;
wire y;
or_gate uut (.a(a), .b(b), .y(y));
initial begin
$monitor("A=%b, B=%b, Y=%b", a, b, y);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
XOR Gate
Outputs 1 only if inputs are different.
xor_gate.v
// 2-input XOR gate
module xor_gate(
input a, b,
output y
);
assign y = a ^ b;
endmodule
tb_xor_gate.v
module tb_xor_gate;
reg a, b;
wire y;
xor_gate uut (.a(a), .b(b), .y(y));
initial begin
$monitor("A=%b, B=%b, Y=%b", a, b, y);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
NOT Gate (Inverter)
Outputs the inverse of the input.
not_gate.v
// NOT gate (inverter)
module not_gate(
input a,
output y
);
assign y = ~a;
endmodule
tb_not_gate.v
module tb_not_gate;
reg a;
wire y;
not_gate uut (.a(a), .y(y));
initial begin
$monitor("A=%b, Y=%b", a, y);
a=0; #10;
a=1; #10;
$finish;
end
endmodule
NAND Gate
Outputs 0 only if both inputs are 1 (inverse of AND).
nand_gate.v
// 2-input NAND gate
module nand_gate(
input a, b,
output y
);
assign y = ~(a & b);
endmodule
tb_nand_gate.v
module tb_nand_gate;
reg a, b;
wire y;
nand_gate uut (.a(a), .b(b), .y(y));
initial begin
$monitor("A=%b, B=%b, Y=%b", a, b, y);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
XNOR Gate
Outputs 1 only if both inputs are the same.
xnor_gate.v
// 2-input XNOR gate
module xnor_gate(
input a, b,
output y
);
assign y = ~(a ^ b);
endmodule
tb_xnor_gate.v
module tb_xnor_gate;
reg a, b;
wire y;
xnor_gate uut (.a(a), .b(b), .y(y));
initial begin
$monitor("A=%b, B=%b, Y=%b", a, b, y);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
Adders
Half Adder
Adds two single bits, producing a sum and a carry.
half_adder.v
module half_adder(
input a, b,
output sum, carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
tb_half_adder.v
module tb_half_adder;
reg a, b;
wire sum, carry;
half_adder uut (.a(a), .b(b), .sum(sum), .carry(carry));
initial begin
$monitor("A=%b, B=%b, | Sum=%b, Carry=%b", a, b, sum, carry);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
Full Adder
Adds three single bits (including a carry-in), producing a sum and a carry-out.
full_adder.v
module full_adder(
input a, b, cin,
output sum, cout
);
assign {cout, sum} = a + b + cin;
endmodule
tb_full_adder.v
module tb_full_adder;
reg a, b, cin;
wire sum, cout;
full_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=0;b=0;cin=0;#10;
a=0;b=0;cin=1;#10;
a=0;b=1;cin=0;#10;
a=0;b=1;cin=1;#10;
a=1;b=0;cin=0;#10;
a=1;b=0;cin=1;#10;
a=1;b=1;cin=0;#10;
a=1;b=1;cin=1;#10;
$finish;
end
endmodule
Full Adder using two Half Adders
A structural model of a full adder built from two half adders and an OR gate.
full_adder_from_ha.v
// Assumes you have the 'half_adder' module defined.
module full_adder_from_ha(
input a, b, cin,
output sum, cout
);
wire s1, c1, c2;
// First half adder
half_adder ha1 (.a(a), .b(b), .sum(s1), .carry(c1));
// Second half adder
half_adder ha2 (.a(s1), .b(cin), .sum(sum), .carry(c2));
// Combine the carries
assign cout = c1 | c2;
endmodule
tb_full_adder_from_ha.v
module tb_full_adder_from_ha;
reg a, b, cin;
wire sum, cout;
full_adder_from_ha 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=0;b=0;cin=0;#10;
a=0;b=0;cin=1;#10;
a=0;b=1;cin=0;#10;
a=0;b=1;cin=1;#10;
a=1;b=0;cin=0;#10;
a=1;b=0;cin=1;#10;
a=1;b=1;cin=0;#10;
a=1;b=1;cin=1;#10;
$finish;
end
endmodule
Subtractors
Half Subtractor
Subtracts two single bits, producing a difference and a borrow.
half_subtractor.v
module half_subtractor(
input a, b,
output diff, borrow
);
assign diff = a ^ b;
assign borrow = ~a & b;
endmodule
tb_half_subtractor.v
module tb_half_subtractor;
reg a, b;
wire diff, borrow;
half_subtractor uut (.a(a), .b(b), .diff(diff), .borrow(borrow));
initial begin
$monitor("A=%b, B=%b, | Diff=%b, Borrow=%b", a, b, diff, borrow);
a=0; b=0; #10;
a=0; b=1; #10;
a=1; b=0; #10;
a=1; b=1; #10;
$finish;
end
endmodule
Full Subtractor
Subtracts three single bits (including a borrow-in), producing a difference and a borrow-out.
full_subtractor.v
module full_subtractor(
input a, b, bin,
output diff, bout
);
assign diff = a ^ b ^ bin;
assign bout = (~a & b) | (~(a ^ b) & bin);
endmodule
tb_full_subtractor.v
module tb_full_subtractor;
reg a, b, bin;
wire diff, bout;
full_subtractor uut (.a(a), .b(b), .bin(bin), .diff(diff), .bout(bout));
initial begin
$monitor("A=%b, B=%b, Bin=%b | Diff=%b, Bout=%b", a,b,bin,diff,bout);
a=0;b=0;bin=0;#10;
a=0;b=0;bin=1;#10;
a=0;b=1;bin=0;#10;
a=0;b=1;bin=1;#10;
a=1;b=0;bin=0;#10;
a=1;b=0;bin=1;#10;
a=1;b=1;bin=0;#10;
a=1;b=1;bin=1;#10;
$finish;
end
endmodule
4-Bit Adders
4-Bit Adder with Full Adders
A 4-bit Ripple Carry Adder built by chaining four 1-bit full adders. This example uses named port mapping for better readability.
four_bit_adder_fa.v
// Assumes you have the 'full_adder' module defined.
module four_bit_adder_fa(
input [3:0] A,
input [3:0] B,
input Cin,
output [3:0] Sum,
output Cout
);
wire c1, c2, c3;
full_adder fa0 (.a(A[0]), .b(B[0]), .cin(Cin), .sum(Sum[0]), .cout(c1));
full_adder fa1 (.a(A[1]), .b(B[1]), .cin(c1), .sum(Sum[1]), .cout(c2));
full_adder fa2 (.a(A[2]), .b(B[2]), .cin(c2), .sum(Sum[2]), .cout(c3));
full_adder fa3 (.a(A[3]), .b(B[3]), .cin(c3), .sum(Sum[3]), .cout(Cout));
endmodule
tb_four_bit_adder.v
module tb_four_bit_adder;
reg [3:0] A, B;
reg Cin;
wire [3:0] Sum;
wire Cout;
four_bit_adder_fa uut (.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(Cout));
initial begin
$monitor("A=%b, B=%b, Cin=%b | Cout=%b, Sum=%b", A, B, Cin, Cout, Sum);
A=4'b0000; B=4'b0000; Cin=0; #10; // 0 + 0 + 0 = 0
A=4'b0011; B=4'b0101; Cin=0; #10; // 3 + 5 + 0 = 8
A=4'b1001; B=4'b1000; Cin=1; #10; // 9 + 8 + 1 = 18
A=4'b1111; B=4'b0001; Cin=0; #10; // 15 + 1 + 0 = 16
A=4'b1111; B=4'b1111; Cin=1; #10; // 15 + 15 + 1 = 31
$finish;
end
endmodule
Multiplexer & Demultiplexer
2x1 Multiplexer (Mux)
Selects one of two inputs to pass to the output based on a select line.
mux_2x1.v
module mux_2x1(
input d0, d1, sel,
output y
);
assign y = sel ? d1 : d0;
endmodule
tb_mux_2x1.v
module tb_mux_2x1;
reg d0, d1, sel;
wire y;
mux_2x1 uut (.d0(d0), .d1(d1), .sel(sel), .y(y));
initial begin
d0=1; d1=0;
$monitor("sel=%b, d0=%b, d1=%b | y=%b", sel, d0, d1, y);
sel=0; #10;
sel=1; #10;
$finish;
end
endmodule
4x1 Multiplexer (Mux)
Selects one of four inputs using a 2-bit select line.
mux_4x1.v
module mux_4x1(
input [3:0] d,
input [1:0] sel,
output reg y
);
always @(*) begin
case(sel)
2'b00: y = d[0];
2'b01: y = d[1];
2'b10: y = d[2];
2'b11: y = d[3];
default: y = 1'bx;
endcase
end
endmodule
tb_mux_4x1.v
module tb_mux_4x1;
reg [3:0] d;
reg [1:0] sel;
wire y;
mux_4x1 uut (.d(d), .sel(sel), .y(y));
initial begin
d = 4'b1011; // d3=1, d2=0, d1=1, d0=1
$monitor("sel=%b, y=%b", sel, y);
sel=2'b00; #10;
sel=2'b01; #10;
sel=2'b10; #10;
sel=2'b11; #10;
$finish;
end
endmodule
8x1 Multiplexer (Mux)
Selects one of eight inputs using a 3-bit select line.
mux_8x1.v
module mux_8x1(
input [7:0] d,
input [2:0] sel,
output reg y
);
always @(*) begin
y = d[sel];
end
endmodule
tb_mux_8x1.v
module tb_mux_8x1;
reg [7:0] d;
reg [2:0] sel;
wire y;
mux_8x1 uut (.d(d), .sel(sel), .y(y));
initial begin
d = 8'b11010101;
$monitor("sel=%b, y=%b", sel, y);
sel=3'b000; #10; sel=3'b001; #10;
sel=3'b010; #10; sel=3'b011; #10;
sel=3'b100; #10; sel=3'b101; #10;
sel=3'b110; #10; sel=3'b111; #10;
$finish;
end
endmodule
Structural 4x1 Mux using 2x1 Muxes
A common lab problem is building a larger mux from smaller ones.
mux_4x1_structural.v
// Assumes you have the 'mux_2x1' module defined
module mux_4x1_structural(
input [3:0] d,
input [1:0] sel,
output y
);
wire out1, out2;
// First stage of muxes
mux_2x1 m1 (.d0(d[0]), .d1(d[1]), .sel(sel[0]), .y(out1));
mux_2x1 m2 (.d0(d[2]), .d1(d[3]), .sel(sel[0]), .y(out2));
// Final stage mux
mux_2x1 m3 (.d0(out1), .d1(out2), .sel(sel[1]), .y(y));
endmodule
tb_mux_4x1_structural.v
module tb_mux_4x1_structural;
reg [3:0] d;
reg [1:0] sel;
wire y;
// Instantiate the structural model
mux_4x1_structural uut (.d(d), .sel(sel), .y(y));
initial begin
d = 4'b1011; // d3=1, d2=0, d1=1, d0=1
$monitor("sel=%b, y=%b", sel, y);
sel=2'b00; #10;
sel=2'b01; #10;
sel=2'b10; #10;
sel=2'b11; #10;
$finish;
end
endmodule
1x4 Demultiplexer (Demux)
Routes a single data input to one of four outputs based on a 2-bit select line.
demux_1x4.v
module demux_1x4(
input din,
input [1:0] sel,
output reg [3:0] y
);
always @(*) begin
y = 4'b0000; // Default assignment
case(sel)
2'b00: y[0] = din;
2'b01: y[1] = din;
2'b10: y[2] = din;
2'b11: y[3] = din;
endcase
end
endmodule
tb_demux_1x4.v
module tb_demux_1x4;
reg din;
reg [1:0] sel;
wire [3:0] y;
demux_1x4 uut (.din(din), .sel(sel), .y(y));
initial begin
din = 1;
$monitor("sel=%b, din=%b | y=%b", sel, din, y);
sel=2'b00; #10;
sel=2'b01; #10;
sel=2'b10; #10;
sel=2'b11; #10;
$finish;
end
endmodule
1x8 Demultiplexer (Demux)
Routes a single data input to one of eight outputs based on a 3-bit select line.
demux_1x8.v
module demux_1x8(
input din,
input [2:0] sel,
output reg [7:0] y
);
always @(*) begin
y = 8'b00000000; // Default assignment
y[sel] = din;
end
endmodule
tb_demux_1x8.v
module tb_demux_1x8;
reg din;
reg [2:0] sel;
wire [7:0] y;
demux_1x8 uut (.din(din), .sel(sel), .y(y));
initial begin
din = 1;
$monitor("sel=%b, din=%b | y=%b", sel, din, y);
sel=3'b000; #10; sel=3'b001; #10;
sel=3'b010; #10; sel=3'b011; #10;
sel=3'b100; #10; sel=3'b101; #10;
sel=3'b110; #10; sel=3'b111; #10;
$finish;
end
endmodule