Difficulty: Hard · Puzzle 4 of 6 · Topic: Real Interview Rounds: End-to-End Debug Walkthrough
Interviewer: 'The directed config test hangs every time. The bus is quiet and no errors.' Log tail: UVM_INFO @ 9000ns [CFG_VSEQ] lock(cpu_seqr) acquired, waiting for dma_done UVM_INFO @ 9005ns [DMA_SEQ] start_item blocked: waiting for grant on cpu_seqr (nothing further; +UVM_OBJECTION_TRACE: cfg_vseq and dma_seq both hold the run_phase objection) dma_seq is started by the test in a separate fork, not as a child of cfg_vseq. Diagnose and fix.
class cfg_vseq extends uvm_sequence;
virtual task body();
lock(cpu_seqr); // want exclusive CPU port for the config burst
program_dma_regs(); // writes through cpu_seqr
wait (dma_done); // DMA completion flag set by dma_seq
read_status(); // reads through cpu_seqr
unlock(cpu_seqr);
endtask
endclass
// test: both started in parallel
fork
cfg_vseq.start(null);
dma_seq.start(cpu_seqr); // must issue the DMA transfer through the same CPU port
joinWho must make progress for dma_done to be set, and who is allowed to use the sequencer while it is locked?
1) Symptom: permanent hang, bus idle, no errors; both sequences hold objections.
2) Ranked hypotheses: (a) circular wait: the lock holder waits for something that needs the locked sequencer; (b) an unlock skipped on an error path (not applicable: no error logged, and a sequence's lock is released when the sequence exits); (c) driver not pulling (the log says dma_seq is waiting for a grant, not the driver).
3) Confirm (a): print the lock state at the hang (is_blocked(dma_seq)/current_grabber on the sequencer, if your UVM version has it): cfg_vseq holds the lock, dma_seq is queued behind it. Then trace who sets dma_done: dma_seq, which cannot run.
4) Root cause: cfg_vseq holds the lock while waiting for dma_done, and dma_done can only be produced by dma_seq, which needs a grant on the locked sequencer: circular wait through the lock.
5) Fix: never wait on something that needs the locked resource while holding it. Lock only around the register burst, unlock, then wait for dma_done, then lock again for read_status; or start dma_seq as a child of cfg_vseq (children of the lock holder are allowed through). Validate by running with both start orders and a randomized start delay.Answer: Root cause: cfg_vseq holds lock(cpu_seqr) while waiting for dma_done, which only dma_seq can set, and dma_seq cannot get a grant on the locked sequencer: a circular wait through the sequencer lock. Fix: lock only around the register burst and wait for dma_done outside the lock (or run the DMA as a child of the lock holder).
Not run here: Needs the UVM sequencer arbitration and lock queue: the deadlock is dma_seq's start_item being queued behind cfg_vseq's lock(cpu_seqr); a plain-SV semaphore would not reproduce uvm_sequencer's lock/grab and child-of-holder rules.. The answer follows the language rules and the solution steps above.
Locks are held across waits more often than across code you see; the question to ask in the interview is 'who must run for the thing I am waiting on to happen, and can they run while I hold this?'
What is the difference between lock and grab, and when would you use each? Model answer: lock waits in the normal arbitration queue and gives exclusive access once granted (other sequences' requests are blocked until unlock); grab jumps to the front of the queue and takes exclusive access at the next arbitration, so it is for urgent interrupts or error handling. Both block everyone else, so keep the held region short and never wait inside it on a dependency that needs that sequencer.
I ask who must run for the thing I am waiting on to happen, and whether they can run while I hold this. The root cause is that cfg_vseq holds lock on cpu_seqr while waiting for dma_done, which only dma_seq can set, and dma_seq cannot get a grant on the locked sequencer. That is a circular wait through the sequencer lock. I confirm it by looking at the lock owner and the pending requests. The fix is to lock only around the register burst and wait for dma_done outside the lock.