RTL DEBUGGING GUIDE
MUST TRY PRACTICAL DEBUG
SCENARIOS FOR INTERVIEWS
VLSI Debugging-Based Interview Problems
(Advanced, Interview-Grade)
This document contains moderate-to-large RTL debugging problems similar to what engineers face in
real projects and interviews. Each problem includes a realistic module, observed failure, root cause analysis,
and corrected implementation.
Debug Problem 1: Pipelined Packet Register – Data/Control
Corruption
Problem Statement
You are given a 3-stage pipeline that passes packet data and a valid signal. During simulation, output
packets are sometimes marked valid with wrong data.
Buggy Code
module packet_pipe (
input logic clk,
input logic rst_n,
input logic [31:0] din,
input logic vin,
output logic [31:0] dout,
output logic vout
);
logic [31:0] d1, d2, d3;
logic v1, v2, v3;
always_ff @(posedge clk) begin
if (!rst_n) begin
d1 <= 0; d2 <= 0; d3 <= 0;
v1 <= 0; v2 <= 0; v3 <= 0;
end else begin
d1 <= din;
d2 <= d1;
d3 <= d2;
v1 <= vin;
v2 <= vin; // BUG
v3 <= v2;
end
1
end
assign dout = d3;
assign vout = v3;
endmodule
Observed Failure
Random cycles show vout=1 while dout belongs to an older packet.
Root Cause
v2 is driven directly from vin instead of being pipelined from v1 . Control and data are misaligned.
Fix
v2 <= v1;
Explanation
In pipelines, all control signals must be registered exactly like data. Any mismatch causes packet
corruption.
Debug Problem 2: Synchronous FIFO – Full/Empty and Write
Corruption
Problem Statement
A small FIFO drops data and occasionally overwrites unread entries.
Buggy Code
module sync_fifo #(parameter DEPTH=8, WIDTH=8) (
input logic clk,
input logic rst_n,
input logic wr_en,
input logic rd_en,
input logic [WIDTH-1:0] wdata,
output logic [WIDTH-1:0] rdata,
output logic full,
output logic empty
);
2
logic [$clog2(DEPTH)-1:0] wr_ptr, rd_ptr;
logic [WIDTH-1:0] mem [0:DEPTH-1];
always_ff @(posedge clk) begin
if (!rst_n) begin
wr_ptr <= 0;
rd_ptr <= 0;
end else begin
if (wr_en && !full) begin
mem[wr_ptr] <= wdata;
wr_ptr <= wr_ptr + 1'b1;
end
if (rd_en && !empty) begin
rdata <= mem[rd_ptr];
rd_ptr <= rd_ptr + 1'b1;
end
end
end
assign empty = (wr_ptr == rd_ptr);
assign full = (wr_ptr == rd_ptr); // BUG
endmodule
Observed Failure
FIFO becomes full and empty at the same time, causing overwrites.
Root Cause
full and empty use identical logic. FIFO cannot distinguish wrap-around state.
Fix
logic [$clog2(DEPTH):0] wr_ptr_ex, rd_ptr_ex;
assign empty = (wr_ptr_ex == rd_ptr_ex);
assign full = (wr_ptr_ex[$clog2(DEPTH)] != rd_ptr_ex[$clog2(DEPTH)]) &&
(wr_ptr_ex[$clog2(DEPTH)-1:0] == rd_ptr_ex[$clog2(DEPTH)-1:0]);
Explanation
FIFO pointers need an extra MSB to differentiate full vs empty after wrap-around.
3
Debug Problem 3: FSM Controller – Missing Defaults and X
Propagation
Problem Statement
An FSM-based controller sometimes jumps to illegal states after reset.
Buggy Code
typedef enum logic [1:0] {IDLE, LOAD, EXEC, DONE} state_t;
state_t state, next;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
state <= next;
end
always_comb begin
if (start)
next = LOAD;
else if (state == LOAD)
next = EXEC;
else if (state == EXEC)
next = DONE;
end
Observed Failure
Simulation shows next = X and FSM locks up.
Root Cause
Not all paths assign next . Also, logic ignores current state in IDLE properly.
Fix
always_comb begin
next = state;
case (state)
IDLE : if (start) next = LOAD;
LOAD : next = EXEC;
EXEC : next = DONE;
DONE : next = IDLE;
4
default: next = IDLE;
endcase
end
Explanation
FSM combinational logic must cover all states and assign defaults to prevent latch and X-propagation.
Debug Problem 4: Clock Enable vs Gated Clock Timing Failure
Problem Statement
Design fails STA with large skew and glitches.
Buggy Code
always @(posedge (clk & en)) begin
q1 <= d1;
end
always @(posedge (clk & en)) begin
q2 <= q1;
end
Observed Failure
Timing reports show unconstrained paths and glitches on gated clock.
Root Cause
RTL clock gating produces glitchy clocks and breaks STA assumptions.
Fix
always_ff @(posedge clk) begin
if (en) begin
q1 <= d1;
q2 <= q1;
end
end
5
Explanation
Never gate clocks in RTL. Use clock enable logic or proper clock-gating cells inserted by synthesis.
Debug Problem 5: CDC Handshake – Lost Pulse
Problem Statement
A pulse generated in clkA domain is randomly missed in clkB domain.
Buggy Code
always_ff @(posedge clkA)
pulseA <= req;
always_ff @(posedge clkB)
pulseB <= pulseA;
Observed Failure
Some requests never reach clkB domain.
Root Cause
Single-flop CDC of a pulse causes metastability and pulse shrinking.
Fix
logic s1, s2;
always_ff @(posedge clkB) begin
s1 <= pulseA;
s2 <= s1;
end
assign pulseB = s2;
Explanation
CDC requires two-flop synchronizers or proper handshake / toggle logic for pulses.
6
Debug Problem 6: Pipeline Stall / Flush Logic Bug
Problem Statement
A 2-stage pipeline supports stall and flush. During branch flush, wrong data leaks to output.
Buggy Code
always_ff @(posedge clk) begin
if (!rst_n) begin
s1_data <= 0; s1_v <= 0;
s2_data <= 0; s2_v <= 0;
end else begin
if (!stall) begin
s1_data <= din;
s1_v <= vin;
end
if (flush) begin
s2_v <= 1'b0; // BUG: data not cleared
end else if (!stall) begin
s2_data <= s1_data;
s2_v <= s1_v;
end
end
end
Observed Failure
After flush, s2_v=0 but old s2_data propagates later incorrectly.
Root Cause
Flush clears only valid but not data, allowing stale data reuse.
Fix
if (flush) begin
s2_data <= '0;
s2_v <= 1'b0;
end
Explanation
Flush must invalidate both control and data to avoid ghost packets.
7
Debug Problem 7: Scoreboard Compare Mismatch (Verification
Logic Bug)
Problem Statement
Scoreboard reports mismatches even when DUT is correct.
Buggy Code
always @(posedge clk) begin
if (mon_valid)
exp_q.push_back(mon_data);
if (dut_valid) begin
if (exp_q.pop_front() != dut_data)
$error("Mismatch");
end
end
Observed Failure
Under backpressure, compare happens with empty queue.
Root Cause
No protection for queue empty condition.
Fix
if (dut_valid) begin
if (exp_q.size()==0)
$error("Unexpected DUT data");
else if (exp_q.pop_front() != dut_data)
$error("Mismatch");
end
Explanation
Verification logic must handle ordering and backpressure correctly.
8
Debug Problem 8: AXI Write Channel Protocol Bug
Problem Statement
AXI master violates protocol during burst writes.
Buggy Code
if (awvalid) begin
wvalid <= 1'b1;
wdata <= data;
wlast <= 1'b1; // BUG
end
Observed Failure
Slave errors because every beat asserts WLAST .
Root Cause
WLAST must assert only on final beat of burst.
Fix
wlast <= (beat_cnt == burst_len-1);
Explanation
Protocol control must follow burst counters, not single-cycle assumptions.
Debug Problem 9: Reset Sequencing Across Clock Domains
Problem Statement
Two clock domains share reset but sometimes one domain comes up earlier and misbehaves.
Buggy Code
always_ff @(posedge clkA or negedge rst_n)
if (!rst_n) qa <= 0; else qa <= da;
9
always_ff @(posedge clkB or negedge rst_n)
if (!rst_n) qb <= 0; else qb <= db;
Observed Failure
CDC paths break during reset release.
Root Cause
Async reset deassertion is unsynchronized per domain.
Fix
Synchronize reset per clock domain using two flops before usage.
Explanation
Reset must be asynchronously asserted but synchronously released per domain.
Debug Problem 10: Arbitration Deadlock Bug
Problem Statement
Two requesters and one grant logic cause system hang.
Buggy Code
always_comb begin
if (req0 && !busy) grant0 = 1;
if (req1 && !busy) grant1 = 1; // BUG: both can assert
end
Observed Failure
Both grants assert simultaneously, corrupting shared resource.
Root Cause
Mutual exclusion not enforced.
10
Fix
always_comb begin
grant0 = 0; grant1 = 0;
if (req0 && !busy) grant0 = 1;
else if (req1 && !busy) grant1 = 1;
end
Explanation
Arbitration must guarantee single winner per cycle.
Debug Problem 11: Multi-Cycle Path Treated as Single Cycle
Problem Statement
A datapath fails timing although logically correct.
Buggy Code
always_ff @(posedge clk)
stage2 <= stage1 + stage0;
Observed Failure
STA shows negative slack though design intended 2 cycles.
Root Cause
No pipeline register or multicycle constraint defined.
Fix
Insert extra register or declare multicycle path in constraints.
Explanation
RTL intent and STA constraints must match pipeline behavior.
11
Debug Problem 12: Width Truncation in Accumulator
Problem Statement
Accumulator saturates early.
Buggy Code
reg [7:0] sum;
always_ff @(posedge clk)
sum <= sum + data;
Observed Failure
Overflow silently truncates.
Root Cause
No extended precision.
Fix
reg [15:0] sum;
Explanation
Datapaths must allocate sufficient bit growth.
Debug Problem 13: Blocking in Sequential Pipeline
Buggy Code
always_ff @(posedge clk) begin
a = b;
b = c;
end
Issue
Pipeline collapses into same-cycle behavior.
12
Fix
always_ff @(posedge clk) begin
a <= b;
b <= c;
end
Explanation
Sequential logic must use non-blocking assignments.
Debug Problem 14: Async FIFO Pointer Sync Bug
Buggy Code
always_ff @(posedge rd_clk)
rd_sync <= wr_ptr;
Issue
Binary pointer CDC breaks full/empty.
Fix
Use Gray-coded pointer + two-flop sync per bit.
Explanation
Async FIFOs require gray pointer synchronization.
Debug Problem 15: X-Propagation in Comparator
Buggy Code
if (a == b)
hit = 1;
Issue
If X exists, comparison yields X and no assignment.
13
Fix
hit = (a === b);
Explanation
Case equality avoids X optimism issues.
Debug Problem 16: Handshake Ready/Valid Violation
Buggy Code
if (valid)
data <= next_data;
Issue
Data updates without ready, breaking protocol.
Fix
if (valid && ready)
data <= next_data;
Explanation
Transfers occur only when both ready and valid assert.
Debug Problem 17: Register Enable Missing Hold
Buggy Code
always_ff @(posedge clk)
if (en) q <= d;
Issue
When en=0, q becomes X in some sims.
14
Fix
always_ff @(posedge clk)
if (en) q <= d; else q <= q;
Explanation
Explicit hold avoids unintended latch/X behavior in some tools.
Debug Problem 18: Memory Read-During-Write Ambiguity
Buggy Code
if (wr_en) mem[addr] <= wdata;
rdata <= mem[addr];
Issue
Read-during-write undefined behavior.
Fix
Add bypass logic when wr_en && rd_en && same addr.
Explanation
Memories need explicit RAW forwarding logic.
Debug Problem 19: Counter Rollover Bug
Buggy Code
if (cnt == MAX) cnt <= 0;
else cnt <= cnt + 1;
Issue
If MAX mismatches width, overflow happens early.
15
Fix
Ensure MAX matches counter width and range.
Explanation
Counters must align constant sizing with register width.
Debug Problem 20: Pipeline Backpressure Loss
Buggy Code
if (in_valid)
buf <= in_data;
Issue
Overwrites buffer when downstream not ready.
Fix
if (in_valid && in_ready)
buf <= in_data;
Explanation
Backpressure must gate storage updates.
Debug Problem 21: Pipeline Flush With Branch Redirect Bug
Problem Statement
A CPU-like pipeline redirects PC on branch, but wrong instruction commits after flush.
Buggy Code
always_ff @(posedge clk) begin
if (!rst_n) begin
pc1<=0; v1<=0;
pc2<=0; v2<=0;
end else begin
16
if (!stall) begin
pc1 <= pc_in;
v1 <= vin;
end
if (flush) begin
v2 <= 1'b0; // BUG: pc2 not cleared
end else if (!stall) begin
pc2 <= pc1;
v2 <= v1;
end
end
end
Observed Failure
After branch, stale pc2 is committed with new valid later.
Root Cause
Flush invalidates only control, not datapath.
Fix
if (flush) begin
pc2 <= '0;
v2 <= 1'b0;
end
Explanation
Flush must reset both data and valid to avoid ghost instructions.
Debug Problem 22: Credit-Based Flow Control Leak
Problem Statement
Transmitter uses credits but overflows receiver buffer.
Buggy Code
always_ff @(posedge clk) begin
if (!rst_n) credit <= 4'd8;
17
else begin
if (send) credit <= credit - 1'b1;
if (recv) credit <= credit + 1'b1; // BUG
end
end
Observed Failure
Credits exceed maximum and allow illegal sends.
Root Cause
No saturation and simultaneous send/recv mishandled.
Fix
if (send && !recv) credit <= credit - 1'b1;
else if (!send && recv) credit <= credit + 1'b1;
Explanation
Flow control counters must be mutually exclusive and bounded.
Debug Problem 23: AXI Read Data Channel Reordering Bug
Problem Statement
AXI master returns data out of order under multiple outstanding reads.
Buggy Code
if (rvalid && rready) begin
resp_q.pop_front();
end
Observed Failure
Returned data mismatches original address order.
Root Cause
No transaction ID tracking for multiple outstanding reads.
18
Fix
Track AXI IDs and reorder using ID-based queues.
Explanation
AXI requires maintaining ordering per ID, not simple FIFO pop.
Debug Problem 24: Multi-Clock Handshake Toggle Loss
Problem Statement
Toggle-based CDC occasionally misses events.
Buggy Code
always_ff @(posedge clkA)
if (send) toggleA <= ~toggleA;
always_ff @(posedge clkB)
toggleB <= toggleA; // BUG
Observed Failure
Some toggles not detected in clkB.
Root Cause
No 2-flop synchronizer on toggle signal.
Fix
always_ff @(posedge clkB) begin
s1 <= toggleA;
s2 <= s1;
end
assign toggleB = s2;
Explanation
CDC toggles must be synchronized before edge detect.
19
Debug Problem 25: DMA Descriptor Fetch Corruption
Problem Statement
DMA engine fetches wrong descriptor under backpressure.
Buggy Code
if (desc_valid)
cur_desc <= mem_desc;
Observed Failure
Descriptor updates even when downstream not ready.
Root Cause
No ready/valid handshake protection.
Fix
if (desc_valid && desc_ready)
cur_desc <= mem_desc;
Explanation
Storage updates must respect handshake to prevent overwrite.
Debug Problem 26: Speculative Execute Not Squashed
Problem Statement
Speculative operations commit after mispredict.
Buggy Code
if (issue)
exe_reg <= op;
Observed Failure
Wrong-path instructions modify state.
20
Root Cause
No squash control on mispredict.
Fix
if (flush)
exe_reg <= '0;
else if (issue)
exe_reg <= op;
Explanation
Speculative pipelines must squash state on redirect.
Debug Problem 27: Cache Line Fill Partial Write Bug
Problem Statement
Cache line fill overwrites valid words incorrectly.
Buggy Code
if (fill_en)
cache[line_idx] <= fill_data;
Observed Failure
Unrelated words lost during partial fills.
Root Cause
Whole line overwritten instead of masked update.
Fix
cache[line_idx][word_sel] <= fill_data;
Explanation
Caches must update per-word with masks, not whole-line blindly.
21
Debug Problem 28: Timer Interrupt Double Trigger
Problem Statement
Timer generates two interrupts per expiry.
Buggy Code
if (cnt == 0)
irq <= 1'b1;
Observed Failure
IRQ stays high for multiple cycles.
Root Cause
No one-shot or clear mechanism.
Fix
if (cnt == 0 && !irq_sent)
irq <= 1'b1;
Explanation
Interrupt logic must be edge-like, not level stuck.
Debug Problem 29: Register File Write-After-Read Hazard
Problem Statement
Read returns old data when read and write same address.
Buggy Code
if (we) rf[waddr] <= wdata;
rdata <= rf[raddr];
Observed Failure
RAW hazard not forwarded.
22
Root Cause
No bypass for same-cycle read/write.
Fix
if (we && waddr==raddr) rdata <= wdata;
else rdata <= rf[raddr];
Explanation
Register files require forwarding to resolve hazards.
Debug Problem 30: Performance Counter Overflow Bug
Problem Statement
Performance counter wraps silently and reports wrong stats.
Buggy Code
cnt <= cnt + event;
Observed Failure
Overflow corrupts measurement.
Root Cause
No saturation or width planning.
Fix
if (!cnt_max)
cnt <= cnt + event;
Explanation
Counters for metrics should saturate or widen to avoid overflow.
23
Debug Problem 31: Out-of-Order Completion Queue Bug
Problem Statement
A completion queue returns responses to software, but occasionally responses mismatch the issued
transaction.
Buggy Code
typedef struct packed {logic [7:0] id; logic [31:0] data;} resp_t;
resp_t cq[$];
always_ff @(posedge clk) begin
if (issue_valid)
cq.push_back('{issue_id, issue_data});
if (resp_valid && resp_ready)
cq.pop_front(); // BUG
end
Observed Failure
Returned response does not match original ID.
Root Cause
Completion pops FIFO order, but responses may return out-of-order by ID.
Fix
int idx;
if (resp_valid && resp_ready) begin
idx = cq.find_index(x) with ([Link] == resp_id);
if (idx >= 0) [Link](idx);
end
Explanation
OOO systems must match by transaction ID, not FIFO position.
24
Debug Problem 32: Write Buffer Merge Corruption
Problem Statement
Write buffer merges stores to same cache line but corrupts data.
Buggy Code
if (wr_en) begin
buf_line <= wr_data; // BUG: overwrites whole line
end
Observed Failure
Partial writes destroy unrelated bytes.
Root Cause
No byte-enable masking when merging.
Fix
buf_line <= (buf_line & ~wr_mask) | (wr_data & wr_mask);
Explanation
Write buffers must merge using byte masks, not full overwrite.
Debug Problem 33: Load-Store Queue Dependency Bug
Problem Statement
A load reads stale data when a prior store targets same address.
Buggy Code
if (ld_issue)
ld_data <= mem[ld_addr];
Observed Failure
Load bypass from store queue not applied.
25
Root Cause
No store-to-load forwarding.
Fix
if (stq_hit)
ld_data <= stq_data;
else
ld_data <= mem[ld_addr];
Explanation
Modern pipelines must forward from store queue before memory.
Debug Problem 34: NoC Router Credit Underflow
Problem Statement
Network router sends flits even when downstream buffer is full.
Buggy Code
if (send)
credit <= credit - 1'b1;
Observed Failure
Credit counter underflows and wraps.
Root Cause
Send allowed without checking credit availability.
Fix
if (send && credit != 0)
credit <= credit - 1'b1;
Explanation
Credit-based systems must never transmit when credit is zero.
26
Debug Problem 35: Reorder Buffer Commit Bug
Problem Statement
CPU commits wrong instruction after exception.
Buggy Code
if (commit_en) begin
arch_reg <= rob_head_data;
rob_head <= rob_head + 1;
end
Observed Failure
Instructions after fault still commit.
Root Cause
No exception check before commit.
Fix
if (commit_en && !rob_head_exc) begin
arch_reg <= rob_head_data;
rob_head <= rob_head + 1;
end
Explanation
ROB must stop commit on exception and flush younger entries.
Debug Problem 36: AXI Burst Counter Desync
Problem Statement
AXI master ends burst early causing protocol violation.
27
Buggy Code
if (wvalid && wready)
beat_cnt <= beat_cnt + 1'b1;
Observed Failure
WLAST asserted at wrong time.
Root Cause
Counter not reset on new address phase.
Fix
if (aw_fire)
beat_cnt <= 0;
else if (w_fire)
beat_cnt <= beat_cnt + 1'b1;
Explanation
Burst counters must align with AW channel handshake.
Debug Problem 37: Pipeline Register Enable Skew
Problem Statement
One pipeline stage advances while next stage stalls.
Buggy Code
if (!stall1) s1 <= din;
if (!stall2) s2 <= s1;
Observed Failure
Data duplication and loss.
Root Cause
Stages use independent stall without coupling.
28
Fix
if (!stall2) begin
if (!stall1) s1 <= din;
s2 <= s1;
end
Explanation
Pipeline control must propagate backpressure consistently.
Debug Problem 38: Power Gating State Loss
Problem Statement
After power gating, block resumes with corrupted state.
Buggy Code
always_ff @(posedge clk)
state <= next_state;
Observed Failure
State undefined after power-up.
Root Cause
No save/restore around power collapse.
Fix
if (!pwr_good)
state <= RESET_STATE;
else
state <= next_state;
Explanation
Power-aware designs must reinitialize or restore state after gating.
29
Debug Problem 39: Watchdog Timer False Trigger
Problem Statement
Watchdog fires even when system is alive.
Buggy Code
if (kick)
wdt_cnt <= 0;
else
wdt_cnt <= wdt_cnt + 1'b1;
Observed Failure
Kick missed when asserted near clock edge.
Root Cause
Kick not synchronized to watchdog clock.
Fix
kick_sync1 <= kick;
kick_sync2 <= kick_sync1;
Explanation
Control inputs to timers must be synchronized before use.
Debug Problem 40: Bus Bridge Width Adaptation Bug
Problem Statement
Bridge converts 64-bit bus to 32-bit, but upper data lost.
Buggy Code
out_data <= in_data[31:0]; // BUG
30
Observed Failure
Upper half of payload never transferred.
Root Cause
No beat-splitting for width conversion.
Fix
if (beat_sel==0) out_data <= in_data[31:0];
else out_data <= in_data[63:32];
Explanation
Bus width adapters must serialize wide words across multiple beats.
End of Advanced Debugging Set (Large-Code Style).
31
Excellence in World class
VLSI Training & Placements
Do follow for updates & enquires
+91- 9182280927