Sequential Logic in Verilog
Sequential logic remembers state. In an FPGA, that usually means flip-flops updated by a clock edge. This is where FPGA design begins to feel very different from ordinary programming: many registers update at the same instant.
Learning Objectives
You will learn to:
- write clocked logic in Verilog;
- distinguish combinational and sequential assignments;
- use enables and resets deliberately;
- understand why synchronous design is the default FPGA style.
Clocked Registers
always @(posedge clk) begin
q <= d;
end
This describes a flip-flop. On each active clock edge, q captures d.
Nonblocking Assignment
Inside clocked Verilog blocks, use nonblocking assignment:
q <= d;
Think of all registers in the block sampling first, then updating together. This matches flip-flop behavior.
Counter Example
module counter8 (
input wire clk,
input wire rst,
input wire en,
output reg [7:0] count
);
always @(posedge clk) begin
if (rst) begin
count <= 8'd0;
end else if (en) begin
count <= count + 8'd1;
end
end
endmodule
Reset Choices
| Reset type | Description | Beginner guidance |
|---|---|---|
| Synchronous reset | reset checked on clock edge | easiest for timing and most FPGA flows |
| Asynchronous reset | reset can affect register without clock | useful but must be released carefully |
| No reset | register powers up by configuration/init or is flushed by protocol | common in datapaths after you know why |
Do not reset every register by reflex. Control registers usually need known startup states. Large datapaths often do not.
Worked Example: Edge Detector
To detect a rising edge, store the previous input and compare it with the current synchronized input.
reg signal_d;
wire rising_edge_seen;
always @(posedge clk) begin
signal_d <= signal;
end
assign rising_edge_seen = signal & ~signal_d;
This creates a one-clock pulse when signal changes from 0 to 1, assuming signal is already in the same clock domain.
title "Illustrative one-clock edge detector"
time start=0 end=10 unit=cycles divisions=10
CLK: square label="clk" low=0 high=1 duty=50 cycles=5 unit=logic color=#2563eb
SIG: step label="signal" low=0 high=1 at=3 unit=logic color=#dc2626
PULSE: pulse label="rising_edge_seen" low=0 high=1 at=4 width=1 unit=logic color=#16a34a
marker EDGE at=4 label="one clock pulse"
The waveform is illustrative; real timing depends on the clock and implementation.
Exercise
Write a 4-bit counter with:
- synchronous reset;
- enable input;
- output
terminal_count, high when the count equals 15.
Then decide whether terminal_count should be combinational or registered and explain the tradeoff.
Common Mistakes
- Mixing blocking and nonblocking assignments without a reason.
- Using a signal from another clock domain directly.
- Creating derived clocks with ordinary logic.
- Resetting huge datapaths unnecessarily.
- Forgetting that registers update together, not line by line.
Summary
Sequential logic is built from clocked registers. Use clean clocked blocks, nonblocking assignments, deliberate reset strategy, and synchronization discipline. This is the foundation for counters, state machines, FIFOs, and real FPGA systems.
Next: Finite-State Machines in Verilog.
Further Reading
- Vendor HDL coding guidelines for synchronous design
- Clifford Cummings papers on nonblocking assignments and resets
- Project F FPGA tutorials on counters and clocks