Verilog Lab Hub

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