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
    • Agent Architecture
    • Reusable VIP: Active, Passive and Protocol Agents
    • Error and Fault Injection
      • Sequence-Directed Faults
      • Driver Injection Hooks
      • Callbacks versus Factory Overrides
      • Checking Expected Faults
    • Agent Patterns: Slaves, Reset, Interrupts and Pipelines
  • 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
Loading lesson

‹Error and Fault Injection
  1. Topics
  2. UVM Verification
  3. UVM Agents & Protocol VIP
  4. Error and Fault Injection
  5. Sequence-Directed Faults

Part 6 · Agents & Protocol IP · Intermediate

Sequence-Directed Faults

The DMA's error responses, faults that a legal sequence item can express, fault intent carried in item fields, and the clear that must follow.

On this page

    The test plan has two error rows for the DMA. An APB access to an unmapped address must answer with PSLVERR. A packet that ends with TLAST before LEN words must end the job early, set STATUS.ERR and raise the interrupt. A colleague has already started a new driver class with an inject_error knob. Before anyone writes it, ask the question that saves most error-injection code: can an ordinary, legal sequence item already ask for this fault?

    The idea: legal-but-wrong is just stimulus

    Faults come in two kinds. Some are legal transactions with a wrong meaning: a perfectly formed APB write to an address the DUT does not decode, a perfectly formed stream packet that is shorter than the job. The bus protocol is obeyed; it is the content that breaks the DUT's rules. Others are protocol violations: TVALID dropped before TREADY, PENABLE without a setup phase, X on the data lines. No legal item can express those, because the driver's job is to obey the protocol.

    Think of a restaurant. Ordering a dish that is not on the menu is a legal request the kitchen must handle politely. The waiter dropping the plate on the way out is a failure of the delivery itself. The first needs nothing but a different order (a sequence). Only the second needs a different waiter (a driver hook, override or callback), which is the next lesson.

    The picture: where does this fault belong?

    Decision flowchart: if a legal item can express the fault, use a sequence; otherwise, if existing sequences must stay unchanged, use a driver hook, else add a fault field to the item; all paths end in checking the DUT's error response.
    Start with the cheapest place a fault can live. Every path ends in the same place: checking what the DUT did.

    Build it: two faults with no new component

    PSLVERR from an unmapped address

    The DMA decodes five registers, 0x00 to 0x10, and answers any other address with PSLVERR in the access phase. The bench's apb_rw_seq already returns slverr from the driver, so the fault is one sequence call with a different address:

    design.sv
    1
    2
    3
    4
    5
    // snippet: a test step, using the bench's apb_rw_seq
    apb_rw_seq s = apb_rw_seq::type_id::create("s");
    s.addr = 8'h14; s.write = 1; s.data = 32'h1234_5678;   // 0x14 is not decoded
    s.start(env.apb.sqr);
    if (s.slverr !== 1'b1) `uvm_error("SLVERR", "unmapped write was accepted")

    Notice what the bench's scoreboard already does with it. write_apb updates its KEY only for t.write && !t.slverr && t.addr == KEY. A write the DUT rejected must not change the scoreboard's model of the DUT, so error responses are part of normal checking, not a special case bolted on later.

    STATUS.ERR from a short packet

    The stream fault needs no new class either. The bench's run_job helper programs LEN from the job object and sends however many words it is told. Program LEN = 8, send 4, and the fourth word carries TLAST, because axis_pkt_seq always puts TLAST on its last word:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // snippet: a short-packet test, no override needed
    class dma_short_pkt_test extends dma_base_test;
      `uvm_component_utils(dma_short_pkt_test)
      function new(string name, uvm_component parent);
        super.new(name, parent);
      endfunction
      task run_phase(uvm_phase phase);
        dma_job_cfg job = dma_job_cfg::type_id::create("job");
        bit [31:0] status;
        phase.raise_objection(this);
        if (!job.randomize() with { len == 8; }) `uvm_fatal("RAND", "dma_job_cfg randomize failed")
        run_job(job, 4, status);                 // LEN=8, but the packet ends after 4 words
        if (status[2:1] !== 2'b10) `uvm_error("STATUS", $sformatf("expected ERR only, STATUS=%08h", status))
        #100ns;
        phase.drop_objection(this);
      endtask
    endclass

    run_job also clears STATUS with a write of 0x6 after reading it, which matters more than it looks; the war story below is about forgetting it.

    What the DMA does with a short packet

    It helps to know exactly what the spec promises, because every one of these is something to check:

    Effect

    Where you see it

    The word with early TLAST is still moved, XORed with KEY, and sent out with TLAST

    Output monitor: a 4-word packet; the data scoreboard still matches

    BUSY falls and ERR is set; DONE stays clear

    STATUS read = 0x4

    The interrupt rises if IRQ_EN is set

    irq line, or the irq agent's event

    COUNT shows the words actually moved

    COUNT read = 4

    ERR stays set until software writes 1 to bit 2

    irq stays high until the clear

    When the fault does need intent in the item

    Some faults are legal in the item format but must be chosen per transaction by the sequence, randomly, across a whole regression. Then the intent travels as an item or sequence field with a soft default of "no fault", and a fault test turns it on with an inline constraint. Unconstrained, a random fault field would make most traffic faulty, so the default must be explicit:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // snippet: fault intent as a sequence field with a clean default
    class dma_err_pkt_seq extends axis_pkt_seq;
      `uvm_object_utils(dma_err_pkt_seq)
      rand int unsigned early_last;              // index of the beat that carries TLAST
      constraint c_clean { soft early_last == n - 1; }   // default: TLAST on the last word
      constraint c_range { early_last < n; }
      function new(string name = "dma_err_pkt_seq");
        super.new(name);
      endfunction
      task body();
        for (int i = 0; i <= early_last; i++) begin
          axis_item it = axis_item::type_id::create("it");
          start_item(it);
          if (!it.randomize() with { last == (i == early_last); })
            `uvm_fatal("RAND", "axis_item randomize failed")
          finish_item(it);
        end
      endtask
    endclass
    // A fault test: if (!pkt.randomize() with { n == 8; early_last == 2; }) ...

    Because it extends axis_pkt_seq, a test can also swap it in for every packet sequence in the bench with a factory override, which is taught in Overriding items and sequences.

    Watch it run

    A scratch run of the short-packet test, with a write to the unmapped address 0x14 first and a scoreboard that predicts ERR (built in the last lesson of this topic):

    Diagram
    UVM_INFO scratch_tb.sv(412) @ 75000: uvm_test_top [SLVERR] write to unmapped 0x14: slverr=1
    UVM_INFO scratch_tb.sv(415) @ 425000: uvm_test_top [SHORT] LEN=8, 4 words sent: STATUS=00000004
    UVM_INFO dma_tb.sv(411) @ 525000: uvm_test_top.env.sb [SB] 4 words matched, 0 mismatched
    UVM_INFO scratch_tb.sv(368) @ 525000: uvm_test_top.env.sb [SB_ERR] 1 job(s) ended in ERR as predicted, 0 in DONE as predicted
    UVM_ERROR :    0
    • slverr=1: the DUT rejected the unmapped write, and the scoreboard's KEY did not change.

    • STATUS=00000004: ERR set, DONE clear, BUSY clear. The job ended early as the spec says.

    • 4 words matched: the data path still behaved correctly for the words it was given. Data checking and error checking are separate questions.

    What breaks: the ERR nobody cleared

    A team wrote its short-packet test by copying a clean test and deleting what looked like noise, including the STATUS write after the read. The short-packet job passed. The next job in the same test failed with an ERR status on a perfectly good packet, and sometimes, depending on the seed, it passed while reading STATUS before the job had even finished.

    The DMA's interrupt is IRQ_EN & (DONE | ERR), and ERR is write-1-to-clear. Nobody cleared it, so the interrupt line simply stayed high. When the next job started, wait (irq_vif.irq === 1'b1) returned at once, the test read STATUS in the middle of the job, and it saw the stale ERR from the job before. The fix is one line, the W1C write of the bits that were read. The lesson is wider: an injected fault leaves state behind, and a fault test owns cleaning it up, or checking that the DUT's own recovery did.

    Interview

    "How do you decide whether an error scenario needs a new driver or agent variant?"

    A weak answer: "Error tests always need an error-injecting driver with knobs." That builds machinery for faults a sequence could already create, and grows a driver nobody can maintain.

    A strong answer: "First I ask whether a legal transaction can express it. An unmapped address or a packet shorter than the programmed length is just stimulus, so it is a sequence or a constraint. Only protocol violations, or faults that must hit existing sequences unchanged, go into the driver, through a virtual hook with an override or a callback. Whichever path, the intent defaults to clean with a soft constraint, the scoreboard predicts the DUT's error response from observed traffic, and the test cleans up the error state, such as W1C status bits, before the next scenario."

    Follow-ups to expect: How does the scoreboard avoid learning from a rejected write? (it ignores transfers with an error response) and Why soft constraints for fault fields? (clean by default; a test turns faults on explicitly).

    Check yourself A colleague proposes a driver knob that forces TLAST early, to test the DMA's ERR path. You show that a short packet does the same. Is there still a reason to have the driver version?

    Yes, when existing sequences must stay unchanged: a regression variant that cuts every packet of every sequence in the library, without editing or re-randomizing any of them. That is what the next lesson's axis_truncating_driver does. For a single directed test, the short packet is simpler and needs no new class.

    Check yourself dma_err_pkt_seq has rand int unsigned early_last with no constraints at all. What happens in a regression that randomizes it?

    Almost every packet would be faulty or out of range: an unconstrained 32-bit value is nearly always far beyond the packet length, and the loop would try to send billions of beats. The c_range constraint keeps it inside the packet and the soft c_clean constraint keeps packets clean unless a test asks otherwise.

    Check yourself After a short-packet job, the test clears STATUS with a write of 0x2. What does the next job see?

    0x2 clears DONE, which was not set; ERR stays set. The interrupt stays high, so the next job's wait for the interrupt returns at once, before the job has finished. Write back the bits you read (0x4 here) or 0x6 to clear both.

    Next: a sequence can create a short packet, but it cannot cut short the packets of forty existing sequences without touching them. Driver injection hooks does that from the driver.

    Related topics

    • The DMA spec

    • Overriding items and sequences

    • Driver injection hooks

    Previous

    107 / 280

    Next: Driver Injection Hooks

    Up next

    Up nextDriver Injection Hooks

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Callbacks versus Factory Overrides
    • Checking Expected Faults