Part 15: Sequential Logic Using Verilog
2025-06-04 | By DWARAKAN RAMANATHAN
Introduction:
Sequential logic circuits are those in which the output depends not only on the current inputs but also on the history of previous inputs. Unlike combinational logic, sequential circuits have memory elements (like flip-flops or registers) that store the past states. Verilog, a hardware description language (HDL), allows us to model and implement these sequential systems efficiently. In this blog, we will explore the concepts of sequential logic using Verilog, followed by 5 detailed examples, including RTL (Register Transfer Level) code and test benches.
The memory elements of sequential logic circuits allow the circuit to "remember" previous states. The output is a function of both the current inputs and the past state of the system. These circuits often use clock signals to synchronize operations and typically include devices like flip-flops, registers, counters, and finite state machines (FSMs).
Key Characteristics of Sequential Logic:
Memory Elements: Sequential circuits store past inputs or states.
Clock Dependency: Many of the sequential circuits depend on some clock signal, which determines when they should update their state.
Finite State Machines: Sequential logic often gets implemented by finite state machines (FSMs), where on the basis of inputs and its current state, the system moves on from one state to another.
Sequential Logic in Verilog
Sequential circuits can be modeled in Verilog in two fundamental ways:
always Block: Uses a clock signal or other events for modeling state changes.
flip-flops: The basic building blocks for sequential logic (e.g., D-flip-flop, T-flip-flop, etc.).
Below are 5 examples illustrating different facets of sequential logic in Verilog.
Example 1: D Flip-Flop (Basic Memory Element)
Verilog Code:
module d_flip_flop(input clk, input reset, input d, output reg q); always @(posedge clk or posedge reset) begin if (reset) q <= 0; // Reset the output to 0 else q <= d; // On rising edge of clock, latch the value of d end endmodule
Testbench:
module tb_d_flip_flop; reg clk, reset, d; wire q; // Instantiate the D Flip-Flop d_flip_flop uut(clk, reset, d, q); always #5 clk = ~clk; // Generate clock signal with period of 10 time units initial begin $monitor("clk = %b, reset = %b, d = %b, q = %b", clk, reset, d, q); clk = 0; reset = 0; d = 0; #10; reset = 1; #10; // Reset the flip-flop reset = 0; d = 1; #10; // Set input d to 1 d = 0; #10; // Change d to 0 d = 1; #10; // Change d back to 1 $finish; end endmodule
Explanation:
A D flip-flop (Data or Delay flip-flop) is a simple sequential circuit that stores and holds a binary value depending on a clock signal. It has two primary inputs: D (data input) and CLK (clock signal), with an output Q and its complement Q'. The D flip-flop ensures that the output Q follows the input D, but only at the rising edge (or falling edge) of the clock signal. This characteristic eliminates the issue of random states that exist in other flip-flops, like the SR flip-flop. When the clock shifts from low to high (rising edge-triggered), the flip-flop captures the value of D and holds it until the next clock cycle, regardless of any following changes in D. This makes it apt for use in synchronizing data, registers, and memory storage elements. D flip-flops are widely used in shift registers, data buffers, and pipeline registers in microprocessors to suitably synchronize signals in different clock domains.
Testbench: The testbench generates a clock signal and tests the behavior of the flip-flop in terms of reset and input d.
Example 2: 4-bit Synchronous Counter
Verilog Code:
module counter_4bit(input clk, input reset, output reg [3:0] count); always @(posedge clk or posedge reset) begin if (reset) count <= 4'b0000; // Reset the counter to 0 else count <= count + 1; // Increment the counter at each clock cycle end endmodule
Testbench:
module tb_counter_4bit; reg clk, reset; wire [3:0] count; // Instantiate the 4-bit counter counter_4bit uut(clk, reset, count); always #5 clk = ~clk; // Generate clock signal with period of 10 time units initial begin $monitor("clk = %b, reset = %b, count = %b", clk, reset, count); clk = 0; reset = 0; #10; reset = 1; #10; // Reset the counter to 0 reset = 0; #50; // Run the counter for a few clock cycles $finish; end endmodule
Explanation:
A 4-bit synchronous counter is a sequence circuit that counts in binary from 0000 (0) to 1111 (15) and back to zero, incrementing its value on each clock pulse. As opposed to an asynchronous counter, where flip-flops are triggered at different times, a synchronous counter triggers all flip-flops simultaneously, which reduces propagation delay and maximizes speed of operation. The counter is typically implemented using four JK or T flip-flops, each corresponding to one of the counter bits. The least significant bit (LSB) toggles on each clock pulse, and higher-order bits toggle based on the previous bit's state. For example, the second bit toggles when the first bit toggles from 1 to 0, the third bit toggles when the first two bits together toggle from 11 to 00, and so on. Synchronous counters have widespread application in digital clocks, frequency dividers, event counting applications, and microcontrollers to produce accurate timing and sequencing operations.
Testbench: The testbench produces the clock signal and applies a reset for testing the counter behavior.
Example 3: T Flip-Flop (Toggle Flip-Flop)
Verilog Code:
module t_flip_flop(input clk, input reset, input t, output reg q); always @(posedge clk or posedge reset) begin if (reset) q <= 0; // Reset the output to 0 else if (t) q <= ~q; // Toggle output if t is 1 end endmodule
Testbench:
module tb_t_flip_flop; reg clk, reset, t; wire q; // Instantiate the T Flip-Flop t_flip_flop uut(clk, reset, t, q); always #5 clk = ~clk; // Generate clock signal with period of 10 time units initial begin $monitor("clk = %b, reset = %b, t = %b, q = %b", clk, reset, t, q); clk = 0; reset = 0; t = 0; #10; reset = 1; #10; // Reset the flip-flop reset = 0; t = 1; #10; // Toggle q with t = 1 t = 0; #10; // Keep t = 0, no toggle t = 1; #10; // Toggle again $finish; end endmodule
Explanation:
A T flip-flop (Toggle flip-flop) is a sequential circuit whose output state is toggled for each clock pulse when the T input (toggle enable) is 1. If T = 0, the output does not toggle from its previous state. Mathematically, the next state Q(n+1) can be represented as Q(n) ⊕ T, i.e., if T is 1, the output toggles 0 and 1 with each clock pulse. T flip-flops are generally realized from JK flip-flops by connecting both J and K inputs together, actually toggling them with each clock pulse. This flip-flop is widely used in counters, frequency dividers, and toggle circuits, where the output is to be toggled sequentially. For example, in a frequency divider circuit, a T flip-flop can be utilized to divide the input clock frequency by half and thus is utilized in clock generation and digital timing circuits. Moreover, it plays a central role in constructing binary counters and minimizing state transitions in finite state machines (FSMs). Testbench: The testbench tests the toggle behavior by applying different values of t and observing the toggling of the output q.
Example 4: 2-bit Johnson Counter
Verilog Code:
module johnson_counter(input clk, input reset, output reg [1:0] count); always @(posedge clk or posedge reset) begin if (reset) count <= 2'b00; // Reset the counter else count <= {count[0], ~count[1]}; // Johnson counter logic end endmodule
Testbench:
module tb_johnson_counter; reg clk, reset; wire [1:0] count; // Instantiate the Johnson counter johnson_counter uut(clk, reset, count); always #5 clk = ~clk; // Generate clock signal with period of 10 time units initial begin $monitor("clk = %b, reset = %b, count = %b", clk, reset, count); clk = 0; reset = 0; #10; reset = 1; #10; // Reset the counter reset = 0; #50; // Run the counter for a few clock cycles $finish; end endmodule
Explanation:
A 2-bit Johnson counter, or twisted ring counter, is a shift register counter that counts through a special set of states. Unlike a standard ring counter, where the last bit is fed back directly into the first flip-flop, a Johnson counter feeds back the inverted output of the last flip-flop to the first input, doubling the number of states. A 2-bit Johnson counter can be implemented with two D flip-flops connected in series; the inverted output of the last flip-flop given to the input of the first. The counter cycles through four distinct states: 00 → 10 → 11 → 01 → 00, effectively generating a mod-4 counting sequence. This characteristic makes Johnson counters highly efficient in pattern generation, sequence controllers, and digital timing circuits, as they employ fewer flip-flops than standard binary counters for the same number of states. They're applied in LED chasers, frequency division circuits, and state transition designs.
Testbench: The testbench verifies the correct behavior of the Johnson counter by executing a number of clock cycles.
Example 5: Simple Finite State Machine (FSM)
Verilog Code:
module fsm(input clk, input reset, input x, output reg z); reg [1:0] state, next_state; // State encoding parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10; // State transition logic always @(posedge clk or posedge reset) begin if (reset) state <= S0; // Reset to initial state else state <= next_state; // Transition to next state end // Next state logic always @(state or x) begin case (state) S0: next_state = (x) ? S1 : S0; S1: next_state = (x) ? S2 : S0; S2: next_state = (x) ? S1 : S0; default: next_state = S0; endcase end // Output logic always @(state) begin case (state) S0: z = 0; S1: z = 1; S2: z = 0; default: z = 0; endcase end endmodule
Testbench:
module tb_fsm; reg clk, reset, x; wire z; // Instantiate the FSM fsm uut(clk, reset, x, z); always #5 clk = ~clk; // Generate clock signal with period of 10 time units initial begin $monitor("clk = %b, reset = %b, x = %b, z = %b", clk, reset, x, z); clk = 0; reset = 0; x = 0; #10; reset = 1; #10; // Reset the FSM reset = 0; x = 1; #10; // Test state transitions x = 0; #10; x = 1; #10; $finish; end endmodule
Explanation:
A finite state machine (FSM) is a sequential logic circuit that changes states according to inputs and clock pulses. An FSM has a finite number of states, a present state, a next state, inputs, and outputs. FSMs can be classified as Moore machines, where the output is a function of the current state alone, and Mealy machines, where the output is a function of the current state and also of the inputs. A basic FSM works by storing its current state in flip-flops and changing to a new state according to specified conditions. For instance, in a traffic light controller, an FSM goes through states Green → Yellow → Red → Green, changing as a function of timing inputs. The FSM logic enables the transitions to be controlled, and thus it is necessary to control circuits, digital protocol design, vending machines, elevator systems, and embedded system automation. FSMs offer a systematic approach to sequential decision-making in hardware and software systems.
Testbench: The testbench simulates the FSM operation by applying different inputs and monitoring the output z.
Conclusion
Sequential logic in Verilog enables designers to implement systems that have a memory of previous states, like counters, flip-flops, and finite state machines. The following examples illustrate several different types of sequential elements and how they can be represented in Verilog. The testbenches are also an important part of verifying the correct functionality of the sequential circuits: they must respond as desired to any sequence of inputs and states.