How a chip counts with a clock
A counter in Verilog is a circuit that adds one to a stored number every time a clock signal rises. The clock is what turns a pile of gates into a machine that does one step at a time.
A stopwatch, a traffic light and a processor all rely on the same trick. Something remembers a value, and the clock says when it may change.
By the end of this lesson
Note
I can describe a counter that changes on a clock edge.
Key words
| Word | What it means | Example |
|---|---|---|
| Clock | a signal that goes up and down at a steady beat | clk |
| Rising edge | the instant the clock goes from 0 to 1 | |
| Flip-flop | a part that remembers one bit between edges | |
| Register | several flip-flops that hold one number | |
| Reset | a signal that puts the stored value back to 0 | rst |
| Counter | a register that adds one on each edge |
The cells students fill in are left blank in this preview.
A clock tells a circuit when to change
Gates alone change the moment their inputs change. A clock is a signal that goes 0, 1, 0, 1 at a steady beat.
A flip-flop looks at its input only at the rising edge, the instant the clock goes from 0 to 1. It stores what it saw and holds it until the next edge.
always at the rising edge describes a register
In Verilog, always @(posedge clk) means: do this at every rising edge of clk. The signals assigned inside it become flip-flops.
Inside it, <= means: take this new value at the edge. It is not the same as less than or equal. A reset sets the value back to 0, and a counter is a register that adds one each time.
The lab's 4-bit counter with a reset
// counter.v, given in the lab: a 4-bit counter with a reset.
module counter(input clk, input rst, output reg [3:0] q);
always @(posedge clk)
if (rst) q <= 4'd0;
else q <= q + 4'd1;
endmodule
A counter can wrap at any number
A 4-bit register holds 0 to 15, but a design can wrap earlier. Here a counter named count6 goes 0, 1, 2, 3, 4, 5 and back to 0.
Four Runs write it and a testbench into /tmp, compile them and run eight clock edges. The line initial q = 0; only gives the simulation a starting value. A chip would use a reset instead.
Write the counter
echo 'module count6(input clk, output reg [2:0] q); initial q = 0; always @(posedge clk) if (q == 5) q <= 0; else q <= q + 1; endmodule' > /tmp/count6.vShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the testbench
echo 'module count6_tb; reg clk = 0; wire [2:0] q; count6 dut(clk, q); always #5 clk = ~clk; initial begin repeat (8) begin @(posedge clk); #1 $display("after edge, q = %0d", q); end $finish; end endmodule' > /tmp/count6_tb.vShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Compile both files
iverilog -o /tmp/count6 /tmp/count6.v /tmp/count6_tb.vShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run eight clock edges
vvp /tmp/count6Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The same counter as a Python model
# A counter that runs from 0 to 5 and wraps, one step for each clock edge.
q = 0
for edge in range(8):
if q == 5:
q = 0
else:
q = q + 1
print("after edge", edge + 1, "q =", q)
# Change 5 to 3 and run again.
A common mistake
Warning
Many people think a counter counts the whole time the clock is 1. It counts once, at the rising edge. A clock that stays at 1 for a long time still adds only one. Count edges, not time.
Going further
Edit a copy of count6.v so it counts only while a new input en is 1. Add input en to the ports and test it.
Write down first what q should do at an edge when en is 0. Then check the simulation agrees.