Top SystemVerilog Coding Questions Asked in VLSI Interviews

SystemVerilog interviews are often more practical than candidates expect. Knowing the syntax of logic, always_ff, classes, constraints, or assertions is useful, but interviewers frequently ask candidates to write code, modify existing code, identify a bug, or explain what the code actually does.

For RTL design and functional verification roles, coding questions can range from simple sequential logic to SystemVerilog-specific features such as interfaces, queues, randomization, constraints, assertions, functional coverage, and object-oriented programming.

The important point is that an interviewer is usually evaluating more than whether the code compiles. They want to know whether you understand hardware behavior, simulation semantics, synthesizability, corner cases, and verification intent.

This article covers practical SystemVerilog coding questions commonly relevant to VLSI interviews, with examples and the kinds of follow-up questions you should expect.

1. Write SystemVerilog code for a D flip-flop with reset

This is one of the simplest questions, but it tests whether you understand sequential logic and SystemVerilog procedural blocks.

Example

module dff (

    input  logic clk,

    input  logic rst_n,

    input  logic d,

    output logic q

);

 

    always_ff @(posedge clk) begin

        if (!rst_n)

            q <= 1’b0;

        else

            q <= d;

    end

 

endmodule

 

The interviewer may immediately ask:

Why did you use always_ff and <=?

always_ff clearly communicates that the block represents flip-flop-based sequential logic. The nonblocking assignment models the simultaneous update behavior expected from sequential elements.

They may then change the requirement:

“Make the reset asynchronous.”

The sensitivity list would become:

always_ff @(posedge clk or negedge rst_n)

 

The important skill is not memorizing both versions. You should be able to modify the code when the specification changes.

 

2. Write a parameterized counter

A common coding exercise is to write a counter that can be configured for different widths.

Example

module counter #(

    parameter int WIDTH = 8

) (

    input  logic             clk,

    input  logic             rst_n,

    input  logic             enable,

    output logic [WIDTH-1:0] count

);

 

    always_ff @(posedge clk) begin

        if (!rst_n)

            count <= ‘0;

        else if (enable)

            count <= count + 1’b1;

    end

 

endmodule

 

The interviewer may ask:

  • What happens when the counter reaches its maximum value?
  • How would you create a down counter?
  • How would you make it saturate instead of wrap around?
  • What does ‘0 do?
  • Why is the counter parameterized?

For an N-bit unsigned counter, normal binary arithmetic naturally wraps when the maximum representable value is exceeded.

A good candidate should also recognize that parameterization makes the RTL reusable rather than hard-coding an 8-bit implementation.

 

3. Write a 2:1 multiplexer using always_comb

This tests basic combinational RTL coding.

module mux2 (

    input  logic a,

    input  logic b,

    input  logic sel,

    output logic y

);

 

    always_comb begin

        if (sel)

            y = b;

        else

            y = a;

    end

 

endmodule

 

A follow-up question may be:

“Why use always_comb instead of always @(*)?”

always_comb is a SystemVerilog construct specifically intended for combinational logic. It makes design intent clearer and provides additional language-level checking compared with traditional Verilog procedural blocks.

The interviewer may then intentionally remove the else statement:

always_comb begin

    if (sel)

        y = b;

end

 

You should identify the problem: when sel is false, y is not assigned in that procedural execution, potentially causing latch inference.

This type of modification question is often more valuable than simply asking you to write a mux from scratch.

 

4. What is wrong with this sequential code?

Consider:

always_ff @(posedge clk) begin

    q1 = d;

    q2 = q1;

end

 

An interviewer may ask whether this is correct.

The preferred sequential coding style is:

always_ff @(posedge clk) begin

    q1 <= d;

    q2 <= q1;

end

 

With nonblocking assignments, both registers update based on their values before the clock event.

Therefore:

Before clock:

q1 = 0

q2 = 0

d  = 1

 

After clock:

q1 = 1

q2 = 0

 

On the next clock, q2 can receive the previous value of q1.

This is a classic interview question because it tests whether you understand simulation scheduling and sequential hardware behavior, rather than simply knowing assignment syntax.

 

5. Write an FSM using SystemVerilog

Finite-state-machine coding is another common RTL exercise.

For example, suppose an FSM has three states:

IDLE → ACTIVE → DONE

  ↑              |

  └──────────────┘

 

A SystemVerilog implementation can separate state storage from next-state logic.

typedef enum logic [1:0] {

    IDLE,

    ACTIVE,

    DONE

} state_t;

 

state_t state, next_state;

 

always_ff @(posedge clk or negedge rst_n) begin

    if (!rst_n)

        state <= IDLE;

    else

        state <= next_state;

end

 

always_comb begin

    next_state = state;

 

    case (state)

        IDLE: begin

            if (start)

                next_state = ACTIVE;

        end

 

        ACTIVE: begin

            if (complete)

                next_state = DONE;

        end

 

        DONE: begin

            next_state = IDLE;

        end

 

        default:

            next_state = IDLE;

    endcase

end

 

The interviewer may ask:

  • Why use typedef enum?
  • Why separate state and next-state logic?
  • What happens if an illegal state occurs?
  • Why assign next_state = state initially?
  • Could this code infer a latch?

This question tests coding style, FSM understanding, reset behavior, and completeness of combinational assignments.

 

6. Write a SystemVerilog constraint for random values

SystemVerilog coding interviews for verification roles often move beyond RTL into constrained randomization.

Suppose you need to generate an 8-bit address between 0 and 255, but only even addresses are allowed.

class transaction;

 

    rand bit [7:0] addr;

 

    constraint addr_c {

        addr[0] == 1’b0;

    }

 

endclass

 

The least significant bit of an even number is zero, so this constraint restricts the generated addresses accordingly.

You could also express a range:

constraint addr_range {

    addr inside {[8’h20:8’h7F]};

}

 

A likely follow-up question is:

What happens if the constraints conflict?

For example:

constraint c1 {

    addr inside {[0:10]};

}

 

constraint c2 {

    addr > 20;

}

 

There is no valid value satisfying both constraints, so randomization fails.

A verification engineer should know how to detect and debug such situations rather than assuming randomize() always succeeds.

 

7. Write a class with a constructor and method

SystemVerilog supports object-oriented programming, which is particularly important in verification environments.

Example

class packet;

 

    bit [7:0] addr;

    bit [31:0] data;

 

    function new(bit [7:0] addr,

                 bit [31:0] data);

        this.addr = addr;

        this.data = data;

    endfunction

 

    function void display();

        $display(“ADDR = %0h DATA = %0h”, addr, data);

    endfunction

 

endclass

 

An interviewer may ask:

Why use this.addr instead of simply addr?

this refers to the current object. Here, it distinguishes the class property from the constructor argument having the same name.

They may then ask you to create an object:

packet p;

 

initial begin

    p = new(8’h20, 32’h1234_ABCD);

    p.display();

end

 

This is a basic example, but it tests whether you understand object creation, constructors, class properties, and methods.

 

8. How would you use a SystemVerilog interface?

Interfaces are frequently discussed in verification-oriented SystemVerilog interviews because they group related signals and simplify communication between the DUT and testbench.

Example

interface bus_if(input logic clk);

 

    logic        valid;

    logic        ready;

    logic [31:0] data;

 

endinterface

 

The interface can then be connected to a DUT or used by verification components.

A common follow-up question is:

What problem does an interface solve?

Instead of passing many related signals individually between components, the interface groups them into a single reusable communication structure.

SystemVerilog testbench guidance also highlights interfaces as an important way of simplifying signal connectivity in larger verification environments.

For a verification interview, you should also be prepared for questions about modports and virtual interfaces.

 

9. Write a SystemVerilog assertion for a request-acknowledge protocol

Assertions are another important coding area.

Suppose the requirement is:

Whenever req is asserted, ack must be asserted in the next cycle.

A simple concurrent assertion is:

property req_ack;

    @(posedge clk)

    req |=> ack;

endproperty

 

assert property (req_ack);

 

If the requirement instead says that the acknowledgement must occur within one to three cycles, you could express a temporal window:

property req_ack_window;

    @(posedge clk)

    req |-> ##[1:3] ack;

endproperty

 

assert property (req_ack_window);

 

The interviewer may ask about the difference between |-> and |=>.

You should be able to explain that they differ in when the consequent begins relative to the antecedent.

SystemVerilog Assertions are particularly useful for checking temporal behavior such as handshakes, FIFO conditions, pipeline relationships, reset behavior, and protocol rules.

 

10. Write a functional coverage model

A coding interview for a verification role may ask you to write a small coverage model.

For example:

covergroup bus_cg @(posedge clk);

 

    cp_valid: coverpoint valid;

 

    cp_ready: coverpoint ready;

 

    cp_data: coverpoint data {

        bins low  = {[0:63]};

        bins mid  = {[64:191]};

        bins high = {[192:255]};

    }

 

endgroup

 

You can create an instance:

bus_cg cg = new();

 

The purpose is not merely to prove that the signal changed. Functional coverage should represent meaningful scenarios derived from the verification plan.

For example, if a bus protocol has different operating modes, you may want to cover combinations of those modes rather than simply measuring whether each signal toggled.

SystemVerilog functional coverage uses constructs such as covergroups, coverpoints and bins to describe functional scenarios.

 

11. Write a FIFO status condition

An interviewer may give you a small FIFO problem and ask you to write the empty/full logic.

For a simple counter-based FIFO, the conceptual conditions might be:

assign empty = (count == 0);

assign full  = (count == DEPTH);

 

The interviewer may then change the requirement:

“Can read and write happen in the same cycle?”

That changes the design considerations.

You need to determine:

  • What happens when the FIFO is empty?
  • Can a read and write occur simultaneously?
  • What happens when it is full?
  • Does a simultaneous read/write maintain the same occupancy?
  • What should happen to count?

For example:

always_ff @(posedge clk) begin

    case ({wr_en, rd_en})

        2’b10: count <= count + 1’b1;

        2’b01: count <= count – 1’b1;

        default: count <= count;

    endcase

end

 

This is a useful interview exercise because the candidate has to think about boundary conditions and simultaneous events, not just syntax.

 

12. Find the bug in this randomization code

Consider:

class packet;

 

    rand bit [7:0] length;

 

    constraint c_length {

        length > 10;

        length < 5;

    }

 

endclass

 

The constraints are contradictory.

There is no value that is simultaneously greater than 10 and less than 5.

Therefore:

packet p = new();

 

if (!p.randomize())

    $display(“Randomization failed”);

 

is an important pattern to understand.

An interviewer may then ask:

How would you debug a randomization failure?

Start by checking:

  1. Whether constraints are contradictory.
  2. Whether a constraint is unintentionally too restrictive.
  3. Whether rand variables are declared correctly.
  4. Whether randomize() is returning failure.
  5. Whether inline constraints conflict with class constraints.

This type of question tests debugging ability, not just SystemVerilog syntax.

 

13. What is the difference between a dynamic array, queue and associative array?

This is a popular SystemVerilog coding discussion because all three are useful but serve different purposes.

Dynamic array

int data[];

 

Its size can be allocated dynamically.

data = new[10];

 

Queue

int q[$];

 

Queues support operations such as adding and removing elements.

q.push_back(10);

q.push_front(20);

 

int value;

value = q.pop_front();

 

Associative array

int memory[int];

 

The array is indexed by a key, which can be useful for sparse data structures.

The interviewer may ask:

Which one would you use for a transaction FIFO?

A queue is often a natural choice because transactions can be inserted and removed in order.

The correct answer, however, depends on the actual data structure and access requirements.

 

14. Write a simple scoreboard comparison

For a basic verification environment, an interviewer may ask how you would compare expected and actual data.

A simplified example is:

if (actual_data !== expected_data) begin

    $error(“Mismatch: expected=%0h actual=%0h”,

           expected_data, actual_data);

end

 

Notice the use of !== rather than !=.

Four-state simulation includes X and Z, so case inequality can be useful when you want unknown values to participate in the comparison rather than being treated like ordinary two-state values.

A follow-up question could be:

“Why might == produce unexpected behavior when X values are present?”

You should be able to explain the difference between logical equality and case equality in four-state simulation.

 

15. What SystemVerilog coding mistakes should you look for before submitting your solution?

After completing an interview coding problem, do not immediately say, “Done.”

Take a few seconds to review your code.

Check:

1. Assignment type

Did you use blocking and nonblocking assignments appropriately?

2. Reset behavior

Does the reset meet the stated requirement?

3. Combinational completeness

Did you assign outputs in every relevant condition?

4. Widths

Could an arithmetic operation overflow or truncate unexpectedly?

5. Boundary conditions

What happens at zero, maximum value, empty, full, or simultaneous operations?

6. Synthesizability

Does the RTL describe hardware that can actually be synthesized?

7. Simulation behavior

Could race conditions, unknown values, or scheduling semantics affect the result?

8. Scalability

Could the code be parameterized or simplified without making it harder to understand?

These checks are consistent with practical RTL interview preparation guidance: candidates are often evaluated on reset behavior, assignment types, latch avoidance, synthesizability, corner cases, and whether they can explain the hardware created by their code.

How to Prepare for SystemVerilog Coding Interviews

The best way to prepare is to code rather than simply read SystemVerilog interview questions.

Start with small exercises:

  • Flip-flop
  • Counter
  • Shift register
  • MUX
  • Decoder
  • FSM
  • FIFO
  • Arbiter

Then move into verification-oriented exercises:

  • Classes
  • Randomization
  • Constraints
  • Queues
  • Interfaces
  • Assertions
  • Functional coverage
  • Scoreboards
  • Basic testbench components

For each problem, follow the same process:

Understand the requirement → identify the hardware or verification behavior → write the simplest implementation → test corner cases → explain your code.

For verification roles, practice writing small SystemVerilog testbench components instead of memorizing UVM code. SystemVerilog testbench development commonly involves drivers, monitors, scoreboards, stimulus generation, assertions, interfaces, and coverage.

You should also practice explaining why you chose a particular construct.

For example, if asked to write a counter, do not stop after producing the code. Explain:

“I used always_ff because this is clocked sequential logic, used a nonblocking assignment for the register update, and used a parameter so the counter width can be changed without rewriting the module.”

That explanation demonstrates considerably more understanding than the code alone.

Final Takeaway

SystemVerilog coding interviews are designed to test whether you can translate a specification into correct, maintainable RTL or verification code.

The most important areas to practice include:

  • Sequential and combinational RTL
  • always_ff and always_comb
  • Blocking and nonblocking assignments
  • FSM implementation
  • Parameterized designs
  • Classes and constructors
  • Randomization and constraints
  • Dynamic arrays and queues
  • Interfaces
  • Assertions
  • Functional coverage
  • Scoreboards and testbench coding
  • Debugging incorrect SystemVerilog

Do not focus on writing the shortest possible solution. Focus on writing code that clearly communicates your design or verification intent.

A strong interview candidate can write the code, explain why it works, identify its limitations, and modify it when the interviewer changes the requirement.

That is the difference between knowing SystemVerilog syntax and being able to use SystemVerilog effectively in a VLSI engineering environment.

Leave a Reply

Your email address will not be published. Required fields are marked *