Articles
Verilog Interview Questions: Blocking Assignments, Latches, and Simulation
Practise Verilog interview questions with blocking and nonblocking examples, pipeline traces, latch fixes, reset checks, and simulation pitfalls.
To answer Verilog interview questions well, separate three things: when a process runs, when a signal updates, and what hardware the code describes. A correct waveform prediction is not automatically a complete synthesis explanation. A piece of RTL can also look sensible in one simulation while containing a race or an unintended storage element.
This guide focuses on blocking versus nonblocking assignments, latch inference, and simulation reasoning. The examples are original exercises. State your Verilog or SystemVerilog version, tool assumptions, and intended hardware before applying a coding rule mechanically.
Key takeaways
- Blocking assignments affect subsequent statements in the same procedural execution immediately.
- Nonblocking assignments evaluate their right-hand sides when executed and schedule updates later in the simulation time step.
- A combinational process must assign every output on every path if storage is not intended.
- An omitted assignment in an edge-triggered process usually describes holding flip-flop state, not an inferred latch.
- Check simulation behavior and synthesis reports separately.
What is the difference between blocking and nonblocking assignments?
The practical convention is to use blocking = for combinational procedural logic and nonblocking <= for clocked state. The reason is predictable data dependency and scheduling, not that one operator is intrinsically faster hardware.
always @(posedge clk) begin
a <= b;
b <= a;
end
If a is 1 and b is 0 before the edge, the scheduled updates leave a at 0 and b at 1. Each right-hand side is evaluated before either nonblocking update takes effect. Replacing both operators with blocking assignments makes the second statement observe the newly assigned a, leaving both variables at the old b value.
| Before edge | Assignment style | After updates |
|---|---|---|
| a=1, b=0 | a <= b; b <= a; | a=0, b=1 |
| a=1, b=0 | a = b; b = a; | a=0, b=0 |
Do not explain nonblocking assignment as an automatic physical delay or “one extra clock cycle.” It changes simulation scheduling. Register stages and clock-cycle latency come from the described state and its connections.
How do I trace a two-stage pipeline?
always @(posedge clk) begin
if (rst) begin
q1 <= 0;
q2 <= 0;
end else begin
q1 <= d;
q2 <= q1;
end
end
Assume reset has established q1=0 and q2=0. At the first active edge after reset, let d be 5. After the nonblocking updates, q1 becomes 5 while q2 remains 0. At the next edge, with d=9, q1 becomes 9 and q2 becomes 5.
| Edge | d sampled | q1 after update | q2 after update |
|---|---|---|---|
| First | 5 | 5 | 0 |
| Second | 9 | 9 | 5 |
| Third | 2 | 2 | 9 |
The important phrase is “after update.” A testbench that samples in the same active event region as the design may observe the previous state. Agree on the observation point before declaring the waveform wrong.
The table forces you to commit to a prediction you can then verify.
Why does incomplete combinational logic infer a latch?
always @(*) begin
if (enable)
y = data;
end
When enable is false, this process does not assign y. To preserve its previous value, storage is needed. In a combinational-style process, that behavior describes a latch rather than a pure combinational function.
If the intended output is zero while disabled, write the missing branch:
always @(*) begin
y = 0;
if (enable)
y = data;
end
The default assignment covers every execution path, and the enabled branch overrides it. This repair changes the disabled behavior deliberately. Do not add an arbitrary default without confirming what the output should mean.
Does a missing else always infer a latch?
No. Context matters. In always @(posedge clk), assigning q only when enable is true normally describes a flip-flop that retains its value on other clock edges, often with an enable structure. It is still edge-triggered state. The incomplete-assignment warning applies differently to a block intended to be combinational.
A good interview answer names the event control before discussing storage. Ask: does the output follow data while a level is active, update only on an edge, or continuously compute from current inputs? These are different hardware behaviors.
How should I write a complete combinational case statement?
Assign sensible defaults before the case, then override outputs for each supported state. Review each output independently: assigning one output in every branch does not cover another output forgotten in one branch.
always @(*) begin
next_state = state;
request = 1'b0;
case (state)
IDLE: begin
if (start) next_state = BUSY;
end
BUSY: begin
request = 1'b1;
if (done) next_state = IDLE;
end
default: next_state = IDLE;
endcase
end
This is an illustrative state-machine fragment with constants and signal declarations omitted. The state itself belongs in a separate clocked process. Whether an illegal state should recover to IDLE, raise an error, or do something else is a design requirement. Do not claim a default branch by itself establishes functional safety.
What causes races between always blocks?
Concurrent processes do not execute in the visual order of the source file. If one clocked process uses a blocking assignment to change a variable while another reads it on the same edge, the reader may depend on scheduling order. That is a warning sign even if one simulation run looks stable.
Use clear ownership of each state variable and an established sequential coding style. Nonblocking state updates help prevent one clocked process from exposing its new state prematurely to another. They do not repair multiple conflicting drivers, wrong reset logic, or an incorrect clock-domain crossing.
Testbenches can race too. Drive synchronous inputs away from the sampling edge or use an appropriate SystemVerilog clocking strategy. Check results after the design's scheduled updates. Adding arbitrary delays until a test passes may conceal the actual scheduling mistake.
How do synchronous and asynchronous resets differ?
A synchronous reset is evaluated when the clocked process runs on its clock edge. An asynchronous reset is included in the event control so that assertion can change the state without waiting for that edge. For example, an active-low asynchronous reset typically uses posedge clk or negedge rst_n.
In an interview, cover polarity, reset values, assertion and release behavior, and the target technology's requirements. Reset deassertion near a clock edge can create recovery/removal concerns; a reset strategy must account for the clock domain. Do not assume simulation timing alone proves a physical implementation is safe.
Why can simulation and synthesis disagree?
Simulation follows the language's event semantics; synthesis recognises supported descriptions of hardware. An incomplete sensitivity list, unsafe procedural ordering, unsupported constructs, or a race can make the simulated result misleading. The keywords reg and wire are also not a shortcut for deciding whether a physical register exists.
Check the inferred hardware and warnings. A variable declared as reg can describe combinational output in classic Verilog. A true register requires a storage behavior that the synthesis tool recognises. Conversely, a design that compiles cleanly may still implement the wrong function.
A small verification checklist for every interview snippet
- Identify each process's trigger and whether it describes combinational or sequential behavior.
- Write initial values, including unknown values if no reset has established state.
- Record right-hand-side evaluations separately from scheduled updates.
- Check every combinational assignment path.
- Look for multiple drivers, inconsistent widths, signedness, and truncation.
- Compare simulation results with the intended inferred hardware.
For an 8-bit counter, test reset, enable low, a normal increment, and wraparound. For a mux, test every select value and decide how unknown inputs are handled. For a pipeline, test consecutive different inputs so that an accidental bypass cannot hide behind repeated values.
Questions to practise answering out loud
“Should I always use nonblocking assignments?” No. Explain the intended process and the project's coding convention. Combinational procedural calculations commonly use blocking assignments; clocked state commonly uses nonblocking assignments.
“How do I prove my latch fix worked?” Exercise the previously unassigned branch, inspect the waveform, and check lint and synthesis for unintended storage. Then verify that the new default is functionally correct.
“Why does q2 receive the old q1?” Because the nonblocking right-hand side is evaluated before the scheduled q1 update, not because the simulator reads lines slowly.
Reference: AMD's Vivado synthesis guidance on procedural assignments documents supported assignment styles. Verify tool-specific details against the version used in your environment.