Verilog Interview Questions (RTL Design) Interview Prep
The Verilog/SystemVerilog interview questions RTL candidates actually get: blocking vs non-blocking, synthesizable RTL, FSMs, CDC, FIFOs, and reset/clocking.
Quick answer
Verilog interviews test whether you can reason about synthesizable hardware -- not whether you can recite syntax.
RTL interviewers ask these questions because the cost of a misunderstanding is enormous: a design that simulates correctly but synthesizes to different hardware, an accidental latch, or an unsynchronized clock crossing can survive into silicon and cause a failure that is expensive or impossible to fix after tape-out.
Editorial review
Written by
CompoundLearn editorial team
Wireless / RF / hardware engineering
Reviewed by
CompoundLearn editorial team
Wireless / RF / hardware engineering
Last reviewed
Built from curated topic maps, editorial validation, and subject-matter review so the page stays aligned with the interview intent and the current content pipeline.
Key points
- Start with assignment semantics: non-blocking (<=) in clocked/sequential always blocks, blocking (=) in combinational always @(*) blocks, and never mix the two in one block -- this single rule drives most beginner mistakes.
- Next, master flop vs latch inference: an edge-triggered block infers a flip-flop; an incomplete combinational block (if with no else, case with no default) accidentally infers a latch. Default every output and use always_comb so the tool catches it.
- Then learn FSM coding: Moore vs Mealy (output timing tradeoff), one-hot vs binary encoding (flops vs decode logic), with next-state, state register, and output logic in separate always blocks plus a safe default for illegal states.
- Then reset and clocking: synchronous vs asynchronous reset, the recovery/removal timing risk on async de-assertion, and the asynchronous-assert / synchronous-de-assert reset synchronizer.
- Finally, clock domain crossing and classic design problems: two-flop synchronizer for one bit, Gray code for single-bit-stepping counters/pointers but a bundled-data handshake or dual-clock FIFO for arbitrary data buses, and be able to code a synchronous FIFO (full/empty via an extra pointer bit), an arbiter, an edge detector, and a debouncer -- then lint and simulate each.
What it is
Verilog interviews test whether you can reason about synthesizable hardware -- not whether you can recite syntax. A "Verilog interview" for an RTL, digital-design, ASIC, or FPGA role checks that you write code describing the hardware you actually intend, and that you understand how the simulator's event model and the synthesizer's inference rules turn your text into a clocked netlist. (Verilog, and its superset SystemVerilog, is the hardware description language used to write RTL -- register-transfer-level descriptions of digital logic that synthesis tools turn into gates and flip-flops on an ASIC or FPGA.) The questions cluster into a predictable set. Assignment semantics: blocking (=) versus non-blocking (<=) and why sequential logic uses non-blocking while combinational logic uses blocking. Synthesizable versus non-synthesizable constructs: which language features describe real hardware versus which are effectively simulation-only (delays, most loops over time, and initial blocks -- noting that many FPGA flows DO synthesize initial register/RAM values from the bitstream, whereas ASIC flows generally cannot rely on them and need an explicit reset). Inference: when an always @(posedge clk) block infers a flip-flop versus when an incomplete always @(*) block accidentally infers a latch. Finite state machines: Moore versus Mealy, one-hot versus binary encoding, and clean separation of next-state and output logic. Reset and clocking: synchronous versus asynchronous reset and the reset-synchronizer pattern. Parameterization: parameter, localparam, and generate for reusable, width-flexible blocks. On top of those fundamentals sit the classic design problems -- a synchronous FIFO with correct full/empty flags, counters, arbiters, a debouncer, an edge detector -- and the system-level hazards: clock domain crossing, metastability, race conditions, and simulation-versus-synthesis mismatch. SystemVerilog adds the constructs interviewers increasingly expect: the four-state logic type, always_ff and always_comb that declare your intent so the tool can check it, and interfaces.
Why interviewers ask
RTL interviewers ask these questions because the cost of a misunderstanding is enormous: a design that simulates correctly but synthesizes to different hardware, an accidental latch, or an unsynchronized clock crossing can survive into silicon and cause a failure that is expensive or impossible to fix after tape-out. They are screening for engineers whose mental model is the hardware, not the text -- people who read always @(posedge clk) and see a bank of flip-flops, and who read an if without an else and immediately worry about a latch. The blocking-versus-non-blocking question is the single most common discriminator because the wrong answer ("they are basically the same") reveals that the candidate does not understand the simulation scheduling model or how statement ordering maps to pipeline stages. The latch-inference and reset questions test whether the candidate writes defensively -- defaulting outputs, covering every case branch, and reasoning about reset assertion and release timing rather than copying a template. Clock domain crossing and FIFO questions test system-level judgment: whether the candidate knows that a single flop does not cure metastability, that a two-flop synchronizer only works for one bit, and that multi-bit crossings need Gray coding only for single-bit-stepping counters/pointers, otherwise a bundled-data handshake or dual-clock FIFO. FSM, arbiter, and counter exercises test whether the candidate can take a behavioral spec and produce clean, synthesizable, lint-passing RTL with separated next-state and output logic. Across all of them, interviewers are also listening for how you talk about verification -- whether you would lint and simulate the block with a self-checking testbench, which signals that you have shipped working hardware rather than just passed a class.
Common mistakes
The most common mistake is misusing blocking and non-blocking assignments. The strong-versus-weak calibration here is sharp. A weak answer treats = and <= as interchangeable and says "the simulator just runs the lines in order." A strong answer explains that non-blocking assignments evaluate all right-hand sides first and update all left-hand sides together at end of the time step (modeling flops that all clock on the same edge), that blocking assignments in a clocked block collapse intended pipeline stages and create simulation-versus-synthesis mismatch, and states the rule: non-blocking in sequential blocks, blocking in combinational blocks, never mixed. The second frequent mistake is accidental latch inference. A weak candidate writes a combinational always @(*) with an if and no else, or a case with no default, and is surprised by the synthesis warning -- or ignores it. A strong candidate assigns a default to every output at the top of the block, always provides an else and a case default, treats latch-inference warnings as errors, and uses SystemVerilog always_comb so the tool flags incomplete assignment automatically. They can explain WHY the latch appears: the output must retain its old value on the uncovered path, which requires a level-sensitive storage element. The third mistake is ignoring clock domain crossing and reset timing. A weak answer synchronizes a multi-bit bus with parallel two-flop synchronizers (which can latch a value that never existed because bits resolve on different cycles) or asserts and releases an asynchronous reset with no thought to recovery/removal timing. A strong answer uses a two-flop synchronizer only for single bits, reaches for Gray coding only where one bit changes per step (a counter or FIFO pointer) and a bundled-data handshake or dual-clock FIFO for an arbitrary data bus, and uses an asynchronous-assert, synchronous-de-assert reset synchronizer. The unifying weak signal is treating RTL as software; the unifying strong signal is reasoning about real flip-flops, clocks, and timing.
Classic Verilog/RTL interview questions: the common trap and what a strong answer demonstrates
| Question / construct | Common trap | What a strong answer shows |
|---|---|---|
| Blocking (=) vs non-blocking (<=) | Treating them as interchangeable; using = in a clocked block | Non-blocking in sequential, blocking in combinational; explains scheduling/update phases and sim-vs-synth mismatch |
| always @(posedge clk) vs always @(*) | Incomplete sensitivity list or mixing sequential and combinational in one block | Edge-triggered infers flops; uses always_ff / always_comb to declare and let the tool check intent |
| Flip-flop vs accidental latch | if with no else, or case with no default, in a combinational block | Defaults every output, covers all branches, treats latch warnings as errors and can explain why the latch appears |
| Synchronous vs asynchronous reset | Picking one by keyword without considering reset release timing | Names recovery/removal timing risk; uses async-assert, sync-de-assert reset synchronizer |
| FSM: Moore vs Mealy, one-hot vs binary | One giant always block mixing state, next-state, and output logic | Separate next-state/register/output blocks; states latency-vs-states and flops-vs-decode tradeoffs; handles illegal states |
| Clock domain crossing (CDC) | One flop "to be safe", or parallel two-flop synchronizers on a bus | Two-flop synchronizer for one bit; Gray code or handshake / async FIFO for multi-bit; explains metastability MTBF |
| Synchronous FIFO full/empty | Cannot distinguish full from empty when pointers are equal | Extra pointer MSB (wrap bit) or occupancy counter; generates full in write domain, empty in read domain |
| Parameterization (parameter / generate) | Hardcoding widths; using localparam where a parameter belongs (or vice versa) | parameter for instance-time config, localparam for derived constants, generate for replicated structure |
Frequently asked questions
- Why does sequential logic use non-blocking assignments (<=) and combinational logic use blocking assignments (=)?
- Non-blocking assignments (<=) schedule their right-hand sides to be evaluated, then all the left-hand sides update together at the end of the time step. That models hardware flip-flops correctly: every flop in an always @(posedge clk) block samples its input on the same clock edge, so order between statements should not matter. If you used blocking (=) in a clocked block, statement order would change behavior and you can accidentally chain flops into a single combinational path (or create a shift register you did not intend). The mirror rule is that purely combinational logic in an always @(*) block should use blocking (=) so each intermediate value is computed and reused immediately within the same evaluation, like wires settling. The interview-safe rule of thumb is: non-blocking (<=) in clocked/sequential always blocks, blocking (=) in combinational always blocks, and never mix the two styles in one block.
- What is the difference between an inferred flip-flop and an accidental latch, and how do I avoid the latch?
- A flip-flop is inferred when you assign a signal inside an edge-triggered block, e.g. always @(posedge clk) q <= d. A latch is inferred when a combinational block (always @(*)) does NOT assign a value to a signal on every possible path -- the synthesizer keeps the old value, which requires a level-sensitive latch. The classic cause is an if without an else, or a case that does not cover all inputs and has no default, where the output is therefore "remembered" on the missing branches. To avoid it: assign a default value to every output at the top of the combinational block, always include an else, always include a default in case statements, and treat synthesis latch-inference warnings as errors. In SystemVerilog, declaring the block always_comb makes the tool flag incomplete assignments for you, which is why interviewers like to see always_comb instead of always @(*).
- What is clock domain crossing (CDC) and why does a single flip-flop not fix metastability?
- A clock domain crossing happens when a signal generated in one clock domain is sampled by a register in another, asynchronous clock domain. Because the source can change arbitrarily close to the destination clock edge, it can violate the destination flop setup/hold window and drive the flop into a metastable state where its output hovers between 0 and 1 before resolving unpredictably. A single flip-flop cannot fix this -- it only moves the metastable event to its own output. The standard single-bit fix is a two-flop (sometimes three-flop) synchronizer: the first flop may go metastable, but it is given a full clock period to settle before the second flop samples it, making the probability of propagated metastability (the mean-time-between-failures) acceptably low. Crucially, a synchronizer is only valid for a single bit. Multi-bit buses cannot use parallel two-flop synchronizers because the bits can resolve on different cycles and produce a value that never existed; multi-bit crossings need a different scheme. Gray coding works only where exactly one bit changes per step, such as a counter or FIFO pointer; an arbitrary multi-bit data bus is not Gray-natured, so it needs a bundled-data handshake (hold the data stable while a synchronized valid signals it is safe to sample) or a dual-clock (asynchronous) FIFO instead.
- How do I design a synchronous FIFO and correctly generate full and empty flags?
- A synchronous FIFO is a dual-port memory plus a write pointer and a read pointer that share one clock. You write at wr_ptr on a write when not full, read at rd_ptr on a read when not empty, and increment the respective pointer each time. The subtlety interviewers probe is distinguishing full from empty, because both occur when the pointers are equal. The standard trick is to make each pointer one bit wider than the address it indexes: empty is when the pointers are exactly equal (same wrap bit and same address), and full is when the addresses are equal but the wrap (MSB) bits differ. An alternative is to keep a separate occupancy counter that increments on write, decrements on read, and defines full and empty directly -- simpler to reason about but an extra adder. Because a synchronous FIFO has one clock, full and empty come from directly comparing the read and write pointers in that single domain -- no synchronizers are involved -- and you should note the simultaneous read-and-write case, where both pointers advance in the same cycle so occupancy is unchanged. The read-domain / write-domain split and Gray-coded pointer synchronization belong to the asynchronous FIFO: when read and write live in different clock domains you cannot compare pointers directly, so you Gray-code each pointer, synchronize it into the other domain with a two-flop synchronizer, then compare -- and there empty is generated in the read domain and full in the write domain. A strong answer states the extra-MSB pointer scheme for the synchronous case and keeps the cross-domain machinery scoped to the asynchronous FIFO.
- STRONG vs WEAK answer: "What happens if you use blocking assignment in a clocked always block?"
- WEAK answer: "It still works, blocking and non-blocking are basically the same, the simulator just runs the lines in order." This is wrong and is an instant red flag -- it shows the candidate does not understand the simulation event model or how RTL maps to flip-flops. STRONG answer: "It can create a simulation-vs-synthesis mismatch and unintended logic. With blocking (=) in always @(posedge clk), the statements execute top to bottom within the same time step, so b = a; c = b; makes c take the NEW value of a in the same cycle -- that collapses what should be two pipeline flops into one, or builds a combinational chain instead of a register stage. With non-blocking (<=), a and b are sampled first and all flops update together, giving the two-cycle pipeline the RTL intended. Synthesis infers flops from the edge sensitivity either way, so the gate-level netlist may differ from what RTL simulation showed -- the dreaded sim/synth mismatch. That is why the rule is non-blocking in sequential blocks." The strong answer names the mechanism (scheduling/update phases), the consequence (collapsed pipeline + sim/synth mismatch), and the rule.
- How should I practice for a Verilog / RTL interview?
- Practice by writing and simulating small, classic RTL blocks until they are reflexive -- do not just read about them. A high-yield drill set: (1) code a parameterizable synchronous FIFO and prove your full/empty flags with a testbench that fills and drains it; (2) code a one-hot FSM (e.g. a traffic light or a simple bus arbiter) with clean next-state and output logic in separate always blocks, Moore first then Mealy; (3) code a two-flop clock-domain-crossing synchronizer for a single bit and explain why it would be wrong for a bus; (4) code a round-robin or fixed-priority arbiter; (5) code utility blocks interviewers love -- a rising/falling edge detector, a switch debouncer, a parameterized counter, and a Gray-code counter. For each one: lint it (catch latch inference, incomplete sensitivity lists, width mismatches), simulate it with a self-checking testbench, and be ready to draw the schematic it synthesizes to. Then practice explaining the design out loud in two minutes, because RTL interviews are as much about clear reasoning -- reset strategy, clocking, failure modes -- as about syntax. Use always_ff / always_comb in SystemVerilog so the tool enforces your intent.
- What is the difference between synchronous and asynchronous reset, and how do interviewers expect you to reason about it?
- A synchronous reset is sampled only on the active clock edge: always @(posedge clk) if (!rst_n) q <= 0; else q <= d. It keeps the reset inside the timing-analyzed clock path and, because it is only sampled at the active clock edge, it ignores reset pulses that fall between edges -- but it does not robustly filter glitches, since a glitch present at the sampling edge still takes effect; it also DOES need a running clock to take effect. An asynchronous reset takes effect immediately, independent of the clock: always @(posedge clk or negedge rst_n) if (!rst_n) q <= 0; else q <= d. It resets even with no clock, but its release (de-assertion) can violate the flop recovery/removal timing and cause metastability if it de-asserts near a clock edge. The widely-used compromise is asynchronous assertion, synchronous de-assertion -- a "reset synchronizer" that asserts reset immediately but releases it synchronized to the clock so all flops leave reset on the same edge. A strong answer names the recovery/removal timing risk and the reset-synchronizer pattern rather than just stating which keyword goes in the sensitivity list.
- What is the difference between a Moore and a Mealy FSM, and one-hot versus binary state encoding?
- A Moore machine output depends only on the current state, so it reacts one cycle later; that output is glitch-free only if it is registered, because a purely combinational decode of the state bits can still glitch as those bits settle. A Mealy machine output depends on the current state AND the current inputs, so it can react in the same cycle (fewer states, lower latency) but its outputs can glitch with the inputs and are harder to time. Interviewers like you to state the latency-versus-states tradeoff and to register Mealy outputs when you need clean timing. On encoding: binary encoding uses ceil(log2 N) flops for N states -- fewer flops, but more combinational decode logic. One-hot uses one flop per state with exactly one bit set -- more flops but trivial, fast next-state and output decode (just check one bit), which is why it is often preferred in FPGAs that are flop-rich. A strong answer also keeps next-state logic, state register, and output logic in clearly separated always blocks (combinational next-state in always_comb, the register in always_ff) and includes a safe default/recovery for illegal states.
Related topics
Essential AI-Native Skills for Verilog Interview Questions (RTL Design)
Modern engineering work increasingly uses AI tools for design and code review, debugging, documentation, test and testbench generation, and workflow automation. The goal is not to let AI replace engineering judgment — it is to move faster while keeping verification discipline.
- Use AI to explain unfamiliar code, logs, waveforms, datasheets, or test failures.
- Break large problems into small, reviewable steps you can verify independently.
- Ask AI for hypotheses, then validate them against tests, measurements, simulations, or lab data.
- Version-control your analysis scripts, testbenches, and configs — keep changes small and reviewable.
- Document your assumptions, design tradeoffs, and debugging decisions.
- Verify AI output before trusting it: run the checks that fit the domain — unit tests, linters, simulations, or bench/lab measurements.
- Review AI output for correctness, edge cases, and real-world consequences.