T Flip-Flop Verilog Code with Async Reset

A T flip-flop (toggle flip-flop) is a one-bit memory element with a single control input, T: when T is high it flips its stored value on the active clock edge, and when T is low it keeps the value it already holds. This page gives you clean, synthesizable T flip-flop Verilog code — a behavioral, positive-edge model with an asynchronous reset — plus a self-checking testbench so you can watch the toggle and hold behaviour in simulation right away. Everything below compiles and runs with the free Icarus Verilog toolchain.

The T flip-flop in Verilog

Here is the complete design together with its testbench in one file. Build it with iverilog -g2005 -o sim t_ff_tb.v and run it with vvp sim. The design module comes first and the testbench is last.

// T flip-flop: behavioral, positive-edge clock, active-low async reset.
// t = 1 -> toggle Q on the clock edge; t = 0 -> hold Q.
module t_ff (
    input  wire clk,     // clock
    input  wire rst_n,   // active-low asynchronous reset
    input  wire t,       // toggle enable: 1 = toggle, 0 = hold
    output reg  q        // stored state
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;   // async clear, independent of clk
        else if (t)
            q <= ~q;     // toggle
        else
            q <= q;      // hold
    end
endmodule

// Testbench: shows reset, toggling, holding, then an async reset mid-run.
module t_ff_tb;
    reg  clk, rst_n, t;
    wire q;

    t_ff dut (.clk(clk), .rst_n(rst_n), .t(t), .q(q));

    // 10 ns clock period
    initial clk = 1'b0;
    always #5 clk = ~clk;

    initial begin
        $display("  time rst_n t q   note");
        $monitor("%5t    %b   %b %b", $time, rst_n, t, q);
        rst_n = 1'b0; t = 1'b0;          // hold in async reset
        #12 rst_n = 1'b1;                // release reset between edges
        $display(">> t=1: expect Q to toggle every rising edge");
        t = 1'b1;
        #40;                             // ~4 clock edges of toggling
        $display(">> t=0: expect Q to hold its value");
        t = 1'b0;
        #20;                             // 2 edges, no change
        $display(">> t=1 again: resume toggling");
        t = 1'b1;
        #20;
        $display(">> async reset asserted (not on a clock edge)");
        rst_n = 1'b0;                    // clears Q immediately
        #8;
        $finish;
    end
endmodule
time rst_n t q   note
    0    0   0 0
>> t=1: expect Q to toggle every rising edge
   12    1   1 0
   15    1   1 1
   25    1   1 0
   35    1   1 1
   45    1   1 0
>> t=0: expect Q to hold its value
   52    1   0 0
>> t=1 again: resume toggling
   72    1   1 0
   75    1   1 1
   85    1   1 0
>> async reset asserted (not on a clock edge)
   92    0   1 0
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpk54ze3ua/t_ff_tb.v:47: $finish called at 100 (1s)

How the code works

The design is deliberately small, so every line earns its place. Walking through it:

  • module t_ff (...) declares four ports. clk, rst_n and t are inputs; q is the stored output. q is declared output reg because it is assigned inside an always block — reg here means “a variable that holds state in procedural code”, not literally a hardware register.
  • always @(posedge clk or negedge rst_n) is the sensitivity list. Including negedge rst_n next to the clock is exactly what makes the reset asynchronous: the block wakes up the moment reset falls, without waiting for a clock edge.
  • if (!rst_n) q <= 1'b0; gives reset the highest priority. Because this branch is checked first, a low rst_n forces q to 0 no matter what clk or t are doing. rst_n is active-low, so !rst_n is true when reset is asserted.
  • else if (t) q <= ~q; is the toggle itself. ~q is the bitwise NOT of the current value, so each qualifying clock edge flips 0 to 1 and 1 to 0.
  • else q <= q; is the hold case. It is optional — leaving it out keeps the same behaviour because an unassigned reg retains its value — but writing it makes the intent explicit and documents that nothing happens when t is 0.
  • The non-blocking assignment <= is used throughout. In clocked logic this models flip-flop behaviour correctly: all right-hand sides are sampled, then the updates happen together at the end of the time step.

Toggle, hold and reset at a glance

The whole truth of this flip-flop fits in three rows:

rst_nTRising clock edge?Next Q
0xirrelevant0 (asynchronous clear)
10yesQ (unchanged — hold)
11yesNOT Q (toggle)

In the simulation log, follow the q column. While t = 1, q alternates on every rising edge. The instant t drops to 0, q freezes and sits at its last value across the next edges. When rst_n is pulled low partway through, q snaps to 0 between clock edges — proof that the reset really is asynchronous.

Building a counter from T flip-flops

The most common use of a T flip-flop is counting. A single T flip-flop with T tied high divides the clock by two; chain the toggle inputs with AND gates and you get a synchronous binary up-counter. The next example reuses the exact same t_ff cell to build a 3-bit counter where bit n toggles only when all lower bits are 1. Every flip-flop shares one clock, which keeps it glitch-free and synthesis-friendly.

// Reusable T flip-flop (same core cell as before).
module t_ff (
    input  wire clk,
    input  wire rst_n,
    input  wire t,
    output reg  q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;
        else if (t)
            q <= ~q;
    end
endmodule

// 3-bit synchronous UP counter built from T flip-flops.
// All FFs share one clock. A bit toggles only when all lower bits are 1.
module counter3 (
    input  wire clk,
    input  wire rst_n,
    output wire [2:0] q
);
    t_ff b0 (.clk(clk), .rst_n(rst_n), .t(1'b1),         .q(q[0]));
    t_ff b1 (.clk(clk), .rst_n(rst_n), .t(q[0]),         .q(q[1]));
    t_ff b2 (.clk(clk), .rst_n(rst_n), .t(q[0] & q[1]),  .q(q[2]));
endmodule

module counter3_tb;
    reg  clk, rst_n;
    wire [2:0] q;

    counter3 dut (.clk(clk), .rst_n(rst_n), .q(q));

    initial clk = 1'b0;
    always #5 clk = ~clk;

    initial begin
        rst_n = 1'b0;
        #12 rst_n = 1'b1;
        $display("  time | q2 q1 q0 = decimal");
        $monitor("%5t  |  %b  %b  %b  =  %0d", $time, q[2], q[1], q[0], q);
        #90;                   // let it count a full 0->7->0 wrap
        $finish;
    end
endmodule
time | q2 q1 q0 = decimal
   12  |  0  0  0  =  0
   15  |  0  0  1  =  1
   25  |  0  1  0  =  2
   35  |  0  1  1  =  3
   45  |  1  0  0  =  4
   55  |  1  0  1  =  5
   65  |  1  1  0  =  6
   75  |  1  1  1  =  7
   85  |  0  0  0  =  0
   95  |  0  0  1  =  1
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmp48ul26w5/counter_tb.v:43: $finish called at 102 (1s)

The log should walk cleanly from 0 up to 7 and wrap back to 0. Notice that b1 only toggles when q[0] is 1, and b2 only when both lower bits are 1 — that is the toggle-and-hold rule doing the counting for you.

Common mistakes

  • Blocking instead of non-blocking. Writing q = ~q (blocking) inside a clocked block invites race conditions and simulation-versus-synthesis mismatches. Use <= for every assignment driven by a clock edge.
  • Leaving negedge rst_n out of the sensitivity list. Without it the reset becomes synchronous — it only takes effect on a clock edge — which is a different circuit from the asynchronous reset most designs expect.
  • Declaring q as wire. Anything assigned inside an always block must be a reg (or logic in SystemVerilog). A wire here is a compile error.
  • Confusing reset polarity. This model uses active-low rst_n with negedge. If your reset is active-high, use posedge rst and test if (rst) instead. Mixing the two silently breaks reset.
  • Clocking counter stages from data signals. It is tempting to build a ripple counter by feeding one flip-flop’s q into the next flip-flop’s clock. That creates clock skew and timing headaches. The synchronous style above — one shared clock, toggle inputs gated by AND — is the preferred approach.
  • Driving q from two always blocks. A single reg must be assigned in exactly one procedural block, or the result is a multi-driver conflict.

Quick check

Why is negedge rst_n in the sensitivity list instead of just posedge clk?

It makes the reset asynchronous. The always block then runs the moment rst_n falls, clearing q immediately rather than waiting for the next rising clock edge.

What does the flip-flop do when T = 0 on a clock edge?

Nothing changes — it holds. The else branch keeps q at its current value, so hold is simply “do not toggle”.

Why use non-blocking <= rather than blocking = for q?

Non-blocking assignment models edge-triggered flip-flops correctly: every right-hand side is evaluated first, then all updates apply together. Blocking assignments in clocked logic can cause ordering races and simulation/synthesis mismatches.

In the 3-bit counter, when does q[2] toggle?

Only when its toggle input q[0] & q[1] is 1 — that is, when both lower bits are already 1 (count value 3 or 7). On that edge the two lower bits roll over and q[2] flips.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD