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.
📘 New to the concept? Read the theory first: T Flip-Flop: truth table, working & timing.
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_nandtare inputs;qis the stored output.qis declaredoutput regbecause it is assigned inside analwaysblock —reghere 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. Includingnegedge rst_nnext 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 lowrst_nforcesqto 0 no matter whatclkortare doing.rst_nis active-low, so!rst_nis true when reset is asserted.else if (t) q <= ~q;is the toggle itself.~qis 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 unassignedregretains its value — but writing it makes the intent explicit and documents that nothing happens whentis 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_n | T | Rising clock edge? | Next Q |
|---|---|---|---|
| 0 | x | irrelevant | 0 (asynchronous clear) |
| 1 | 0 | yes | Q (unchanged — hold) |
| 1 | 1 | yes | NOT 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_nout 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
qaswire. Anything assigned inside analwaysblock must be areg(orlogicin SystemVerilog). Awirehere is a compile error. - Confusing reset polarity. This model uses active-low
rst_nwithnegedge. If your reset is active-high, useposedge rstand testif (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
qinto 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
qfrom two always blocks. A singleregmust 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.
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