EE1D2 Lecture 2 — SystemVerilog Study Guide


📚 Key Concepts

1. Combinational Logic in SystemVerilog (always_comb)

The always_comb block is used to describe combinational (stateless) logic. It re-evaluates whenever any input signal changes.

Important rules:

always_comb begin
    z = '0;          // safe default
    next_state = S0; // safe default
    unique case (state)
        ...
    endcase
end

Common operators:

Operator Meaning Example
& Bitwise AND u = a & b
| Bitwise OR v = b | c
^ Bitwise XOR s = a ^ b
+ Addition w = a + b
{a,b} Concatenation z = {u,v}
&var Reduction AND s = &tmp
|var Reduction OR s = |tmp

2. Latches vs. No Latches

A latch is inferred when a signal in an always_comb block is not assigned on every branch.

// ⚠️  LATCH INFERRED — z is unassigned when add=0 and sub=0
always_comb
    if (add)       z = x + y;
    else if (sub)  z = x - y;
    // missing else!

The unique case keyword tells the compiler the case is complete and mutually exclusive, preventing a latch even if not all values are listed:

always_comb begin
    unique case (ctrl)
        2'b00: z = x;
        2'b01: z = x + y;
        2'b10: z = x - y;
        // 2'b11 not listed — unique guarantees no latch
    endcase
end

3. Generate Blocks

Generate blocks allow you to instantiate hardware structures in a loop — useful for parameterised designs.

generate
    genvar i;
    for (i = 0; i < N; i = i + 1)
        and g1 (tmp[i], a[i], b[i]);
endgenerate

assign s = |tmp;  // reduction OR across all bits

Key points:


4. Module Instantiation & Port Maps

Modules are connected using port maps. When using positional mapping, the order of signals in the instantiation must exactly match the order in the module's port declaration.

// Module declaration
module half_adder (input logic a, b, output logic sum, c_out);

// Correct instantiation (positional)
half_adder adder_0 (a[0], b[0], sum[0], s1);
//                  ^a    ^b    ^sum    ^c_out

For a ripple-carry adder, the carry-out of each stage connects to the carry-in of the next:

[half_adder: a[0],b[0]] --c_out=s1--> [full_adder: a[1],b[1],c_in=s1] --c_out=s2--> [full_adder: a[2],b[2],c_in=s2]

5. Flip-Flops (always_ff)

Flip-flops are sequential elements sensitive to clock edges. The sensitivity list determines the behaviour.

// Negative-edge triggered FF with synchronous reset
always_ff @(negedge clk)
    if (reset) q <= 0;
    else       q <= d;

// Positive-edge triggered FF with ASYNCHRONOUS reset
always_ff @(posedge clk, posedge reset)
    if (reset) q <= 0;
    else       q <= d;

Key distinctions:

Synchronous Reset Asynchronous Reset
Reset triggers on Clock edge only Reset signal edge (any time)
Sensitivity list @(posedge clk) @(posedge clk, posedge reset)

⚠️ If the sensitivity list is only @(posedge reset), the block describes combinational logic driven by reset — not a flip-flop at all.


6. Finite State Machines (FSMs)

Moore FSM

Output depends only on the current state.

typedef enum logic [1:0] {S0, S1, S2, S3} state_t;
state_t state, next_state;

// State register
always_ff @(posedge clk)
    if (reset) state <= S0;
    else       state <= next_state;

// Next-state and output logic
always_comb begin
    next_state = S0;   // default
    y = 1'b0;          // default output
    unique case (state)
        S0: if (x) next_state = S1;
        S1: if (~x) next_state = S2;
        S2: if (x) next_state = S3;
        S3: y = 1'b1;
    endcase
end

Mealy FSM

Output depends on both the current state and the current input. Transitions and outputs are typically written together in the always_comb block.

Common mistakes in FSM code


✏️ Exercises

Exercise 1 — Bitwise Operations & Concatenation

Given the SystemVerilog code below, with inputs a = 101, b = 001, c = 100, what is the output z?

module random_function (
    input  logic [2:0] a, b, c,
    output logic [5:0] z
);
    logic [2:0] u, v, w, x;
    always_comb begin
        u = a & b;
        v = b | c;
        w = a + b;
        x = b + c;
        if (w < x)
            z = {u, v};
        else
            z = {v, u};
    end
endmodule

Options:

How to approach it

  1. Evaluate each intermediate signal by substituting the input values.
  2. Determine the condition of the if statement.
  3. Apply the correct concatenation.

Step-by-step:

Answer: b


Exercise 2 — Generate Block & Parameterised Design

The code below implements the N-bit AND-then-OR circuit shown. Fill in the three missing locations.

module and_or_n #(parameter N = 4) (
    input  logic [N-1:0] a, b,
    output logic s
);
    logic <??1>;

    generate
        genvar i;
        for <??2>
            and g_1 (tmp[i], a[i], b[i]);
    endgenerate

    assign <??3>;
endmodule

Options:

How to approach it

Since only b is fully correct on its own, the answer is b.

Answer: b


Exercise 3 — Latches & the unique case Keyword

Given two codes and two statements, determine which are true:

  1. Code 1 can create a latch during synthesis.
  2. Code 2 can create a latch during synthesis.
// Code 1
always_comb
    if (add)      z = x + y;
    else if (sub) z = x - y;
    // No else — z is unassigned when add=0, sub=0
// Code 2
always_comb begin
    unique case (ctrl)
        2'b00: z = x;
        2'b01: z = x + y;
        2'b10: z = x - y;
        // 2'b11 not covered
    endcase
end

Options:

How to approach it

Answer: a


Exercise 4 — Module Instantiation (Port Maps)

The code implements a 3-bit ripple-carry adder. How should the port maps be initialised?

module adder_3bit (
    input  logic [2:0] a, b,
    output logic [2:0] sum,
    output logic c_out
);
    logic s1, s2;
    <???>
endmodule

Options:

How to approach it

  1. The first stage has no carry in → use a half adder.
  2. Stages 1 and 2 take a carry in from the previous stage → use full adders.
  3. Individual bits must be selected: a[0], b[0], etc. (not the whole bus).
  4. Port order must match the module declaration exactly (positional mapping).
  5. The carry chain: s1 connects adder_0's carry-out to adder_1's carry-in; s2 connects adder_1 to adder_2.

Answer: c


Exercise 5 — D Flip-Flop Types

Given two codes and two statements:

  1. Code 1 describes a negative-edge triggered D-FF with synchronous reset.
  2. Code 2 describes a positive-edge triggered D-FF with asynchronous reset.
// Code 1
always_ff @(negedge clk)
    if (reset) q = 0;
    else       q = d;

// Code 2
always_ff @(posedge reset)
    if (reset) q = 0;
    else       q = d;

How to approach it

Answer: a


Exercise 6 — Moore FSM Implementation

The code below implements a Moore FSM that detects the sequence 101 in input x. What should be written at the three marked locations?

module detect_101 (
    input  logic clk, reset, x,
    output logic y
);
    <??1>
    state_t state, next_state;

    always_ff @(posedge clk)
        if (reset) <??2>
        else       state <= next_state;

    always_comb begin
        <??3>
        unique case (state)
            S0: if (x)  next_state = S1;
            S1: if (~x) next_state = S2;
            S2: if (x)  next_state = S3;
            S3: y = 1'b1;
        endcase
    end
endmodule

Options:

How to approach it

Answer: d


Exercise 7 — Mealy FSM Diagram

The always_comb block below describes a Mealy machine. Which FSM diagram (a–d) matches it?

always_comb begin
    next_state = S2;  // default
    y = 0;            // default

    unique case (state)
        S0: if (x)  next_state = S1;
            else    y = 1;
        S1: if (x)  y = 1;
            else    next_state = S0;
        S2: if (x)  next_state = S0;
            else    y = 1;
    endcase
end

How to approach it

Build a transition table from the code. For each state, determine (next_state, y) for both x=0 and x=1, using the defaults where not overridden:

State x=0 x=1
S0 stay S0, y=1 go to S1, y=0
S1 go to S0, y=0 stay S2 (default), y=1
S2 stay S2 (default), y=1 go to S0, y=0

Match this table to the FSM diagram where each arc is labelled input/output. Diagram a reflects these transitions correctly.

Answer: a


🧠 Quick-Reference Cheat Sheet

Concept Watch out for
always_comb Assign every output on every path, or use defaults at the top
Latches Any unassigned output path → latch inferred
unique case Tells compiler case is complete — suppresses latch, enables warnings
Generate loop genvar for loop variable; tmp must be [N-1:0] not [N:0]
Reduction OR |var OR all bits together into one bit
Port map (positional) Order must exactly match module declaration
always_ff sensitivity list Must include posedge clk (and optionally posedge reset for async)
Synchronous reset Only in sensitivity list as posedge clk
Asynchronous reset Add posedge reset to sensitivity list
FSM defaults Always set next_state and all outputs before the case
Moore FSM Output depends on state only
Mealy FSM Output depends on state and input