Asynchronous Counter

module t_ff (
    input wire clk,
    input wire reset,
    input wire T,
    output reg Q,
    output wire Q_bar
);
    assign Q_bar = ~Q;
    
    always @(negedge clk or posedge reset) begin
        if (reset)
            Q <=  1'b0;
        else if (T)
            Q <=  ~Q;
    end
endmodule

// --- Main Module: Asynchronous Up/Down Counter ---
module async_mod4_updown (
    input wire clk,
    input wire reset,
    input wire M,      // M = 0 for UP, M = 1 for DOWN
    output wire [1:0] Q
);
    wire q0_bar, q1_bar;
    wire clk1;

    // Flip-Flop 0 (LSB): Clocked continuously by the external clock
    t_ff ffA (
        .clk(clk), 
        .reset(reset), 
        .T(1'b1), 
        .Q(Q[0]), 
        .Q_bar(q0_bar)
    );

    // Clock Steering Logic (2-to-1 Multiplexer)
    // If M=0 (UP), clock FF1 with Q[0]. 
    // If M=1 (DOWN), clock FF1 with ~Q[0].
    assign clk1 = (M == 1'b0) ? Q[0] : q0_bar;
// Modified logic with a 3ns propagation delay injected:
      // assign #3 clk1 = (M == 1'b0) ? Q[0] : q0_bar;
    // Flip-Flop 1 (MSB): Clocked by the output of the steering logic
    t_ff ffB (
        .clk(clk1), 
        .reset(reset), 
        .T(1'b1), 
        .Q(Q[1]), 
        .Q_bar(q1_bar)
    );

endmodule

Synchronous Counter

module sync_mod4_updown (
    input wire clk,
    input wire reset,
    input wire M,      // M = 0 for UP, M = 1 for DOWN
    output reg [1:0] Q // 2-bit output
);

    // Synchronous design: All state changes happen on the rising edge of the master clock
    always @(posedge clk or posedge reset) begin
        if (reset) begin
            Q <= 2'b00;
        end else begin
            if (M == 1'b0)
                Q <= Q + 1'b1; // Count Up
            else
                Q <= Q - 1'b1; // Count Down
        end
    end

endmodule

Test Bench

module tb_counters();

    // Testbench signals
    reg clk;
    reg reset;
    reg M;
    
    // Outputs from the counters
    wire [1:0] q_sync;
    wire [1:0] q_async;

    // Instantiate the Synchronous Counter
    sync_mod4_updown uut_sync (
        .clk(clk), 
        .reset(reset), 
        .M(M), 
        .Q(q_sync)
    );

    // Instantiate the Asynchronous Counter
    async_mod4_updown uut_async (
        .clk(clk), 
        .reset(reset), 
        .M(M), 
        .Q(q_async)
    );

    // Clock Generation (10ns period -> 100MHz)
    initial begin
        clk = 0;
        forever #5 clk = ~clk; 
    end

    // Test Sequence
    initial begin
        // 1. Initialize Inputs
        reset = 1;
        M = 0;
        
        // 2. Release Reset after a short delay
        #12 reset = 0;

        // 3. Test UP Counting (Let it run for a few clock cycles)
        // Expected sequence: 0 -> 1 -> 2 -> 3 -> 0
        #50;

        // 4. Test DOWN Counting
        // Expected sequence: 0 -> 3 -> 2 -> 1 -> 0
        M = 1;
        #50;

        // End simulation
        $finish;
    end
initial begin
            // Name of the output waveform file
            $dumpfile("dump.vcd"); 
            
            // The '0' tells the simulator to dump all signals 
            // across ALL levels of the hierarchy within tb_counters
            $dumpvars(0, tb_counters); 
        end
        // Console Output Monitor
            initial begin
                $display("Time | Mode | clk1 (FF1 Clock) | q0_bar | q1_bar | Final Output (Q)");
                $display("-------------------------------------------------------------------");
                
                // Using dot notation to pull wires from inside uut_async
                $monitor("%0t   |  %b   |       %b          |   %b    |   %b    |      %b", 
                         $time, 
                         M, 
                         uut_async.clk1,   // The steered clock signal
                         uut_async.q0_bar, // Inverted Q0
                         uut_async.q1_bar, // Inverted Q1
                         q_async);         // The top-level output
            end
    // Console Output Monitor
    initial begin
        $display("Time\\t Mode(M)\\t Sync_Q\\t Async_Q");
        $display("-----------------------------------------");
        $monitor("%0t\\t   %b\\t\\t   %b\\t   %b", $time, M, q_sync, q_async);
    end

endmodule