⚡ Digital Design Blog

Part 3 of 10

Sequential Circuits

Circuits with memory - the building blocks of registers

By Praveen Kumar Vagala

1,018 views

Sequential vs Combinational

CombinationalSequential
No memoryHas memory (storage)
Output = f(inputs)Output = f(inputs + state)
No clock neededUsually clocked
MUX, Adder, DecoderFlip-flop, Counter, FSM

Latch vs Flip-Flop

Both store 1 bit, but behave differently:

LatchFlip-Flop
Level-sensitiveEdge-sensitive
Transparent when enabledSamples only on clock edge
Simpler, less areaMore predictable timing
Avoid in synchronous designPreferred for synchronous design

SR Latch

Set-Reset latch. Basic memory element.

┌─────────┐ S ────┤ ├──── Q │ SR │ R ────┤ Latch ├──── Q' └─────────┘ S R │ Q(next) │ Action ─────┼──────────┼───────── 0 0 │ Q │ Hold 0 1 │ 0 │ Reset 1 0 │ 1 │ Set 1 1 │ Invalid! │ Both outputs go 0
S=R=1 is forbidden - creates invalid state!

D Latch

Data latch. Avoids invalid state of SR latch.

┌─────────┐ D ────┤ ├──── Q │ D Latch │ EN ───┤ ├──── Q' └─────────┘ When EN=1: Q follows D (transparent) When EN=0: Q holds last value (latched)
// D Latch (avoid in synchronous designs!)
module d_latch (
    input  d, en,
    output reg q
);
    always @(*) begin
        if (en)
            q = d;  // Transparent when enabled
    end
endmodule

D Flip-Flop

The most important sequential element!

Samples D input only at the rising (or falling) edge of clock.

┌─────────┐ D ────┤ ├──── Q │ D FF │ CLK ──┤ > ├──── Q' └─────────┘ CLK ──────────┬───────────┬─────── │ │ ▲ ▲ Sample Sample D here D here
// D Flip-Flop (preferred!)
module dff (
    input      clk,
    input      d,
    output reg q
);
    always @(posedge clk) begin
        q <= d;  // Sample D at rising edge only
    end
endmodule

// With async reset
module dff_reset (
    input      clk,
    input      rst_n,  // Active-low reset
    input      d,
    output reg q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;  // Async reset
        else
            q <= d;
    end
endmodule

JK Flip-Flop

Like SR, but J=K=1 toggles output (no invalid state).

J K │ Q(next) │ Action ─────┼──────────┼───────── 0 0 │ Q │ Hold 0 1 │ 0 │ Reset 1 0 │ 1 │ Set 1 1 │ Q' │ Toggle

T Flip-Flop

Toggle flip-flop. Toggles on every clock when T=1.

T │ Q(next) │ Action ──┼──────────┼───────── 0 │ Q │ Hold 1 │ Q' │ Toggle
// T Flip-Flop
module tff (
    input      clk, rst_n,
    input      t,
    output reg q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;
        else if (t)
            q <= ~q;  // Toggle
    end
endmodule

Register

Multiple flip-flops grouped together. Stores multi-bit data.

// 8-bit Register
module register8 (
    input            clk, rst_n,
    input            load,
    input      [7:0] d,
    output reg [7:0] q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 8'b0;
        else if (load)
            q <= d;
    end
endmodule

Shift Register

Data shifts through flip-flops on each clock.

Serial In ──► [FF0] ──► [FF1] ──► [FF2] ──► [FF3] ──► Serial Out Clock 1: Din→FF0, FF0→FF1, FF1→FF2, FF2→FF3 Clock 2: New Din→FF0, old FF0→FF1, ...
// 8-bit Shift Register
module shift_reg (
    input            clk, rst_n,
    input            serial_in,
    output           serial_out,
    output reg [7:0] parallel_out
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            parallel_out <= 8'b0;
        else
            parallel_out <= {parallel_out[6:0], serial_in};  // Shift left
    end
    
    assign serial_out = parallel_out[7];  // MSB out
endmodule

Counter

Counts up or down on each clock.

Binary Counter

// 4-bit Up Counter
module counter4 (
    input            clk, rst_n,
    input            enable,
    output reg [3:0] count
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 4'b0;
        else if (enable)
            count <= count + 1;
    end
endmodule

// Up/Down Counter
module updown_counter (
    input            clk, rst_n,
    input            enable, up,
    output reg [3:0] count
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 4'b0;
        else if (enable) begin
            if (up)
                count <= count + 1;
            else
                count <= count - 1;
        end
    end
endmodule

Ring Counter

Only one bit is 1, rotates through positions: 0001 → 0010 → 0100 → 1000 → 0001 → ...

Johnson Counter

Twisted ring counter (inverted feedback): 0000 → 1000 → 1100 → 1110 → 1111 → 0111 → 0011 → 0001 → 0000

Edge Detection

Detect rising or falling edge of a signal.

// Rising Edge Detector
module edge_detect (
    input      clk, rst_n,
    input      signal,
    output     rise,
    output     fall
);
    reg signal_d;  // Delayed version
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            signal_d <= 1'b0;
        else
            signal_d <= signal;
    end
    
    assign rise = signal & ~signal_d;   // Was 0, now 1
    assign fall = ~signal & signal_d;   // Was 1, now 0
endmodule
signal ─────┐ ┌─────────────┐ ┌─── │ │ │ │ └─────┘ └─────┘ signal_d ──────┐ ┌─────────────┐ ┌── │ │ │ │ └─────┘ └─────┘ rise ──────┐ ┌─────────────────┐ ┌────── │ │ │ │ ─────┴─┴─────────────────┴─┴────── The pulse lasts exactly one clock cycle!

Summary

ElementBehaviorUse Case
LatchLevel-sensitiveAvoid if possible
D FFEdge-sensitiveStandard storage
RegisterMulti-bit storageData holding
Shift RegSerial ↔ ParallelSerial comm
CounterCount up/downTiming, addressing