Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
    • Verification Architecture and Planning
    • UVM with SVA and Formal
    • Leadership and Senior Judgment
    • Interview Bank
      • Concept Round: Phases, Objections and End of Test
      • Concept Round: Factory and config_db
      • Concept Round: TLM and Analysis
      • Concept Round: Sequences, Sequencers and Drivers
      • Concept Round: Agents, Drivers and Monitors
      • Concept Round: Register Layer and Checking
      • Closure and Sign-off Questions
      • Behavioural Round
      • Coding Round: Whiteboard Drills
      • Debug Round: Find the Bug in This Log
      • Architecture Round: Design the Verification
      • High-Frequency Question Index
      • The Senior DV Interview Loop
Loading lesson

‹Interview Bank
  1. Topics
  2. UVM Verification
  3. Senior Prep: Architecture, Leadership and Interviews
  4. Interview Bank
  5. Concept Round: Sequences, Sequencers and Drivers

Part 13/Senior PrepIntermediate

Concept Round: Sequences, Sequencers and Drivers

Ten high-frequency questions on the item handshake, item_done(rsp) and the response queue, pipelined drivers, lock versus grab, arbitration, virtual sequences, reset and randomization scope.

On this page

    The sequences round is where interviewers dig for hands-on scars. "Explain start_item and finish_item" is a warm-up; the real questions are about what the sequencer does when you get the handshake slightly wrong: a missing item_done, a response nobody reads, a lock that waits behind the wrong thing, a reset that leaves a zombie sequence.

    Senior answers name the handshake step by step, give the library's exact reaction (often a specific message), and know where UVM 1.2 and IEEE 1800.2 differ. The DMA bench supplies the examples: a virtual sequence with no virtual sequencer, an interrupt handler that grabs the APB sequencer, and a driver that forgets item_done on purpose.

    The questions

    Walk me through start_item, finish_item, get_next_item and item_done.

    Weak answer: start_item sends the item and finish_item waits for the driver.

    Strong answer: start_item waits for the sequencer's arbitration to grant this sequence. Randomize after the grant, so constraints see current state. finish_item hands the item to the driver and blocks until the driver calls item_done. On the other side get_next_item blocks until an item is granted, and item_done releases finish_item. If the driver forgets item_done, the next get_next_item reports Get_next_item called twice without item_done or get in between and the sequence stays blocked: dma_hang_noack_test shows exactly that, ending in PH_TIMEOUT.

    Follow-up: “What does get() do differently?” get() takes the item and calls item_done for you, so the sequence is released immediately; use it when the driver finishes the item later and responds separately.

    Home lesson: get_next_item and item_done

    The driver calls item_done(rsp) for every read. What can go wrong?

    Weak answer: Nothing; item_done(rsp) is how read data gets back to the sequence.

    Strong answer: item_done(rsp) puts the response on the sequence's response queue, which holds 8 by default. If the sequence never calls get_response(), the 9th overflows. UVM 1.2 reports a UVM_ERROR; the IEEE 1800.2-2020 reference library starts with that report disabled, so overflowed responses are dropped silently unless you call set_response_queue_error_report_disabled(0). For reads that return data in the request, call item_done() with no argument and read req.rdata after finish_item returns; that is what the DMA bench's APB driver does, and why its register adapter sets provides_responses = 0.

    Follow-up: “What must a separate response object carry?” The request's IDs: rsp.set_id_info(req). A response with no sequence ID is a fatal, SQRPUT, response with null sequence_id.

    Home lesson: Responses and pipelined drivers

    How does a pipelined driver return responses out of the handshake?

    Weak answer: Fork a thread in the driver for each item.

    Strong answer: Accept with get_next_item and call item_done as soon as the request phase is done, so the sequence can send the next one; track outstanding requests; when each completes, send a response built with set_id_info(req) through put_response. The sequence collects with get_response() (by transaction ID when order varies) or registers use_response_handler(1). Depth is the protocol's outstanding limit, and for AXI, responses with the same ID still return in order.

    Follow-up: “Why not just keep finish_item blocked until the response?” Then only one transaction is ever in flight and the pipeline is never exercised.

    Home lesson: Pipelined drivers

    lock() versus grab(): what is the difference?

    Weak answer: grab is a lock with higher priority; a lock waits for all the queued items to finish first.

    Strong answer: lock() puts a lock request at the back of the arbitration queue and grab() at the front. The sequencer grants the first lock or grab that nothing blocks, ahead of plain item requests, so a lock waits only behind other lock and grab requests (and an existing holder), not behind items already queued. The item already in the driver finishes first. Both hold the sequencer until unlock()/ungrab(), and child sequences of the holder may still send. On the DMA bench, dma_irq_seq grabs the APB sequencer so the interrupt handler runs ahead of the background poller: handler has the APB sequencer.

    Follow-up: “The reference manual says a lock is arbitrated like any request. Who is right?” The source (grant_queued_locks) grants locks ahead of items; the manual's wording is looser. State the rule and mention the wording.

    Home lesson: lock versus grab

    You raised one sequence's priority and nothing changed. Why?

    Weak answer: Priority always decides who goes first.

    Strong answer: The default arbitration, UVM_SEQ_ARB_FIFO, ignores priority. UVM_SEQ_ARB_STRICT_FIFO serves the highest priority first (FIFO among equals), UVM_SEQ_ARB_WEIGHTED picks at random weighted by priority, and UVM_SEQ_ARB_RANDOM ignores it. Change it with sqr.set_arbitration(...). The strict modes are where starvation comes from: background traffic at low priority never runs while a high-priority sequence keeps requesting.

    Follow-up: “How do you avoid starvation but still prefer urgent traffic?” WEIGHTED, or a short lock or grab around the urgent part instead of a permanent priority.

    Home lesson: Layering, libraries and arbitration

    Do you need a virtual sequencer to run a virtual sequence?

    Weak answer: Yes; a virtual sequence runs on a virtual sequencer.

    Strong answer: No. A virtual sequencer is only a container of handles. dma_vseq is started with start(null), and the test gives it handles to the agent sequencers; it runs apb_poll_seq in the background and dma_irq_seq with grab(). p_sequencer exists only when a sequence declares it with the uvm_declare_p_sequencer macro, and starting such a sequence on the wrong sequencer type is a DCLPSQ fatal from the cast.

    Follow-up: “When is a virtual sequencer still useful?” When you want a component context for the sequence: config_db scope, default sequences per phase, or one place a large SoC env publishes all its sequencer handles.

    Home lesson: Virtual sequences without a virtual sequencer

    A reset hits mid-test. How do you stop the running sequences?

    Weak answer: Call stop_sequences(); it ends them gracefully.

    Strong answer: stop_sequences() is not graceful: it kills every sequence on the sequencer and clears the request queue, including the item the driver holds, so the driver's reset path calling item_done for it is a fatal, SQRBADITMDN, Item_done() called with no outstanding requests. It also leaves automatic objections raised. The cleaner split: kill() the running sequences (which removes their requests and locks but leaves the driver's item), let the driver release its item with item_done, then start new sequence objects that reprogram the DUT.

    Follow-up: “And if you stop nothing at all?” A zombie: the sequence blocked in finish_item is released by the driver's item_done and carries on after reset, sending the rest of a packet that now starts mid-way.

    Home lesson: Stopping sequences at reset

    A sequence does `req.randomize() with { len == len; }` and len is random every time. Why?

    Weak answer: The constraint solver ignored the inline constraint.

    Strong answer: Inside a with block, names resolve to the object being randomized first, so len == len compares the item's field with itself: always true. Use local::len to refer to the sequence's variable. Always check the return value of randomize() too: a failed randomization leaves the old values and keeps running.

    Follow-up: “Why randomize between start_item and finish_item?” Late randomization: after the grant, constraints can use the current state of the bench, which matters for reactive and register-dependent stimulus.

    Home lesson: Constraints and randomize() with

    A child sequence's pre_body never runs. Why?

    Weak answer: pre_body only runs for virtual sequences.

    Strong answer: start(sqr, parent, priority, call_pre_post) calls pre_body/post_body only when call_pre_post is 1, the default. The uvm_do family of macros starts child sequences with 0, so their pre_body and post_body are skipped; pre_start and post_start always run. Put per-start logic in pre_start, or avoid the macros and call start() yourself.

    Follow-up: “Why do many teams avoid the uvm_do macros?” They hide create, randomize, start and these flags behind one line, which makes exactly this kind of behaviour hard to see in review.

    Home lesson: Sequence lifecycle hooks

    How should a test pass configuration to a sequence?

    Weak answer: Put everything in config_db and let the sequence read it.

    Strong answer: The simplest strong pattern is the creator setting fields (or a config object handle) before start(): explicit, typed and visible in the test. When a value must reach sequences you do not create, such as default sequences or library sequences, a sequence reads config_db with get(null, get_full_name(), ...); its full name is its sequencer's path plus its own name. The DMA bench randomizes a dma_job_cfg in the test and drives the job from it.

    Follow-up: “What breaks if the sequence reads config in its constructor?” It has no sequencer yet, so get_full_name() is just its own name and path-scoped sets do not match. Read in body() or pre_start().

    Home lesson: Configuring sequences

    Rapid fire

    Check yourself A register sequence does 20 reads through a driver that calls item_done(rsp) and never calls get_response(). It passes on one simulator and errors on another. Why?

    The response queue holds 8. UVM 1.2 reports the overflow from the 9th response; the IEEE 1800.2-2020 reference library has the report disabled by default and drops the overflow silently. Either read every response or call item_done() with no argument and read data from the request.

    Check yourself Background traffic and a lock request are both waiting on the APB sequencer, and the background items were queued first. Who goes next once the driver finishes its current item?

    The lock request. Locks and grabs are granted ahead of plain item requests, so the lock waits only for the item already in the driver, not for the queued items.

    Check yourself A virtual sequence uses p_sequencer.apb_sqr and is started with start(null). What happens?

    There is no sequencer, so p_sequencer is never set and the first access dereferences a null handle. (DCLPSQ is the fatal for the other mistake: starting it on a sequencer of the wrong type.) A sequence started with start(null) must use handles it was given.

    Next: Concept Round: Agents, Drivers and Monitors: the same agent at block level and at chip level; what must not change?

    Previous

    271 / 280

    Next: Concept Round: Agents, Drivers and Monitors

    Up next

    Up nextConcept Round: Agents, Drivers and Monitors

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Concept Round: Phases, Objections and End of Test
    • Concept Round: Factory and config_db
    • Concept Round: Register Layer and Checking