Difficulty: Medium · Puzzle 1 of 6 · Topic: Real Interview Rounds: End-to-End Debug Walkthrough
Interviewer: 'Our reset-recovery test hangs in about 1 run in 20, always right after the mid-test reset pulse. Walk me through it.' The interface logic clears awvalid when rst_n falls, and the slave raises awready only after it has seen awvalid (it is not always ready). Log tail: UVM_INFO @ 41190ns [DRV] drive_req id=57 addr=0x1f40, awaiting awready UVM_INFO @ 41200ns [TEST] asserting mid-test reset (8 clocks) UVM_INFO @ 41330ns [TEST] reset released (nothing further; UVM_FATAL [TIMEOUT] at 5ms) Give hypotheses, how you would confirm each, the root cause and the fix.
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive_req(req);
seq_item_port.item_done();
end
endtask
task drive_req(my_item req);
vif.awaddr <= req.addr;
vif.awvalid <= 1;
@(posedge vif.clk iff vif.awready); // waits for the DUT
vif.awvalid <= 0;
endtask
// test
task do_reset();
vif.rst_n <= 0; repeat (8) @(posedge vif.clk); vif.rst_n <= 1;
endtaskWhich statement is the last one that ran for item 57, and what did the reset do to awvalid, which the slave needs to see before it raises the awready the driver is waiting for?
1) Symptom: a liveness hang that needs the reset to land mid-transfer (about 1 in 20 because the pulse must overlap a transfer).
2) Ranked hypotheses: (a) the driver is mid-transfer and the reset erased the handshake it waits for; (b) a sequence killed by reset left its objection raised; (c) a scoreboard holding expectations for requests the DUT dropped (this fails at the end, it does not hang).
3) Confirm (a): the last DRV line has no matching 'done id=57'; print vif.awvalid after reset (it is 0, so the DUT will never raise awready for a request it no longer sees); a waveform of awvalid/awready around 41200ns shows awvalid falling and no awready. Confirm (b): +UVM_OBJECTION_TRACE shows the holder: if it is the driver/test objection, (b) is out. Check (c) by comparing outstanding counts at end.
4) Root cause (a): drive_req waits unconditionally for awready, but reset cleared awvalid.
5) Fix: make the driver reset-aware: wrap the handshake in fork begin fork drive_req(req); wait(!vif.rst_n); join_any disable fork; end join; if reset won, finish the item with item_done (flagging the item as aborted) and wait for reset release; flush the monitor and scoreboard expectations on the reset event. Validate with a test that sweeps the reset pulse over every cycle of a transfer.Answer: Root cause: the driver waits for awready in the middle of a transfer, but the reset cleared awvalid, so the handshake it waits for can never complete and item_done is never called. Fix: a reset-aware driver (race the transfer against reset inside an isolated fork/join, abort and item_done on reset), plus flushing monitor/scoreboard state on reset, verified by sweeping the reset across every transfer cycle.
Checked by running the code in Verilator 5; the printed output supports the answer above. Plain-SV model of the mid-transfer reset, not the UVM library: the unguarded driver waits forever, the reset-aware one aborts and carries on.
The reset test only hangs when reset hits mid-transfer, so a few passing seeds do not prove the driver is fine; sweep the reset position systematically. Also remember the disable fork must be inside its own fork..join or it kills unrelated threads.
After the fix, what else must be reset-aware besides the driver? Model answer: The monitor (drop the partial transaction), the scoreboard/predictor (flush expected entries for requests the DUT dropped, or mark them aborted), the sequences in flight (stop_sequences on the sequencer or let them complete via aborted items), and any background pollers; each needs an explicit reset event and a test that resets in the middle of its activity.
The hang only happens when reset lands mid-transfer, so I sweep the reset position across the transfer cycles to reproduce it. The root cause is that the driver waits for awready in the middle of a transfer, but the reset cleared awvalid, so that handshake can never complete and item_done is never called. I confirm it in the waveform and with the sweep. The fix is a reset-aware driver that races the transfer against reset in an isolated fork and join, aborts and calls item_done, and flushes monitor and scoreboard state on reset.