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 Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
    • Testbench Anatomy & Layering
    • Stimulus: Generators, Transactions & Drivers
      • Transaction Design for Stimulus
      • Layered Constraint Architecture
      • Shaping Stimulus with Knobs and Policies
      • Protocol Legality and Error Injection
      • Randomizing Scenarios, Not Just Items
      • Generator Patterns
      • Driver Design
      • Mixing Directed and Random Stimulus
    • Monitors, Scoreboards & Reference Models
    • Self-Checking Tests & Regression
    • From Hand-Built TB to UVM
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Stimulus: Generators, Transactions & Drivers
  1. Topics
  2. SystemVerilog
  3. Testbench Architecture in SystemVerilog
  4. Stimulus: Generators, Transactions & Drivers
  5. Protocol Legality and Error Injection

Part 6 · Testbench Architecture · Intermediate

Protocol Legality and Error Injection

Spec tables as constraints, plus single-dimension error injection and checking.

On this page

    From spec table to constraint block

    Protocol specs state legality as tables, and each table row becomes one constraint line with a spec citation. Legality lives in one block in one class, so a spec revision diffs exactly one block.

    Spec row

    Constraint line

    Size within bus width

    size <= log2(bus bytes), so size <= 2 on a 32-bit bus

    Align to transfer size

    addr % (1 << size) == 0

    WRAP length 2, 4, 8, 16

    (btype == WRAP) turns on the length set

    No 4KB crossing

    page offset plus bytes bounded by 4096

    Exclusive: power-of-2 bytes up to 128, aligned to the total

    gated size and alignment rules

    These are full-AXI burst rules: single-beat AXI4-Lite has no bursts, lengths, or wrap modes. The worked example below is therefore AXI4-style burst legality.

    AXI4 burst legality with width discipline

    The next listing is not run in this course's checks. It is classes only, with no top module.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // not-run: classes only, no top module
    typedef enum bit [1:0] {FIXED = 2'd0, INCR = 2'd1, WRAP = 2'd2} btype_e;
    class axi_txn;
      rand bit [31:0] addr;
      rand bit [2:0]  size;
      rand bit [4:0]  len_p1;
      rand btype_e    btype;
      rand bit [2:0]  opc;
      rand bit        excl;
      constraint valid_c {
        size <= 3'd2;
        addr % (32'd1 << size) == 0;
        len_p1 inside {[1:16]};
        (btype == WRAP) -> len_p1 inside {2, 4, 8, 16};
        // WRAP start aligns to one transfer (the line above), not to the
        // whole burst: a start inside the wrap window is what makes it wrap.
        (32'(addr[11:0]) + (32'(len_p1) << size)) <= 32'd4096;
        !(opc inside {3'h6, 3'h7});
        excl -> ((32'(len_p1) << size) inside {1, 2, 4, 8, 16, 32, 64, 128});
        excl -> (addr % (32'(len_p1) << size) == 0);
      }
    endclass
    
    class axi_corner_txn extends axi_txn;
      constraint corner_bias_c {
        soft addr dist { [32'h0000_0000:32'h0000_0FFF] :/ 3,
                         [32'hFFFF_F000:32'hFFFF_FFFF] :/ 3,
                         [32'h0000_1000:32'hFFFF_EFFF] :/ 4 };
        soft len_p1 dist { 16 := 3, [1:15] :/ 7 };
      }
    endclass

    Every shift widens before shifting: a 5-bit length shifted in 5 bits truncates, so the cast to 32 bits comes first. Corner pressure stays out of valid_c in its own soft block over whole variables, never over a part select.

    • Constrain in natural units such as beats and bytes, and convert wire encodings at the driver.

    • Legal, likely, and measured stay separate: valid_c, soft bias or policy, and a monitor covergroup.

    • A procedural re-check of each rule at bring-up catches flipped relationals in seconds.

    Error injection with a scoreboard handshake

    The next listing is not run in this course's checks. It is classes only, with no top module.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // not-run: classes only, no top module
    typedef enum bit [1:0] {ERR_NONE, ERR_CRC, ERR_LEN} ekind_e;
    class eth_txn;
      rand bit [13:0] length;
      rand bit [13:0] actual_len;
      bit [31:0]      crc;          // computed in post_randomize, so not rand
      rand bit        inj;
      rand ekind_e    kind;
      bit [31:0]     payload_hash;
      int unsigned   err_pct = 0;
      constraint rate_c {
        inj dist { 1 := err_pct, 0 := (100 - err_pct) };
        (inj == 0) -> kind == ERR_NONE;
        (inj == 1) -> kind != ERR_NONE;
      }
      constraint len_ok_c {
        (kind != ERR_LEN) -> (length == actual_len);
        actual_len inside {[64:1518]};
      }
      constraint len_bad_c {
        (kind == ERR_LEN) -> (length != actual_len && length inside {[64:1518]});
      }
      function void post_randomize();
        crc = compute_crc(actual_len);
        payload_hash = compute_crc(actual_len);
        if (kind == ERR_CRC) crc = crc ^ 32'h0000_0001;
      endfunction
      function bit [31:0] compute_crc(bit [13:0] n);
        return {18'h0, n} * 32'h9E37_79B9;
      endfunction
    endclass
    
    class eth_mon_txn;
      bit dut_flagged;
      bit [31:0] payload_hash;
    endclass

    Field violations use gated constraints so the frame is wrong in exactly one dimension and plausible elsewhere. Computed-field violations corrupt the golden value in post_randomize with a single-bit flip. Flags travel in the transaction so the scoreboard expects rejection instead of excusing anything.

    Common mistakes

    Common pitfall

    Disabling all of valid_c to inject one error makes stimulus illegal in unintended dimensions. Gate exactly the rule under attack and keep every other rule enforced.

    Interview

    Likely question: how do you inject protocol errors cleanly?

    Rate comes from a knob-fed share on a flag, targeting from partitioned legality, CRC from golden-then-flip, and checking from flags that drive expectation of rejection.

    Check yourself Why flip one CRC bit instead of randomizing garbage?

    One flipped bit targets the CRC checker precisely. Garbage may collide with a valid code or trip unrelated decode paths.

    Check yourself The scoreboard sees an injected frame the DUT accepted. What is the verdict?

    A real failure of the DUT check, counted on the negative path. Injected flags demand rejection, never exemption.

    Testbench

    A legality checker and a CRC compare stand in for the DUT's receive check. The testbench sends one clean frame, one legal WRAP that starts mid-window, and two frames each wrong in one dimension, and compares the checker's flag with the expected verdict.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    module tb_legal_violation;
      reg [31:0] addr;
      reg [2:0]  size;
      reg [4:0]  len_p1;
      reg [1:0]  btype;
      reg [31:0] off;
      reg [31:0] beats;
      reg        ok;
      reg [31:0] golden;
      reg        expect_reject;
      reg        dut_flag;
      integer    problems;
      task automatic check_legal;
        begin
          off = addr[11:0];
          beats = len_p1;
          ok = 1;
          if (size > 2) ok = 0;
          if ((addr % (32'd1 << size)) != 0) ok = 0;
          if (len_p1 < 1 || len_p1 > 16) ok = 0;
          if (btype == 2 && !(len_p1 == 2 || len_p1 == 4 || len_p1 == 8 || len_p1 == 16)) ok = 0;
          if ((off + (beats << size)) > 4096) ok = 0;
        end
      endtask
      // Receiver stand-in: flags an illegal shape or a CRC that misses the golden value.
      task automatic receive(input [31:0] crc_in);
        begin
          check_legal;
          dut_flag = !ok || (crc_in != golden);
          if (dut_flag !== expect_reject) problems = problems + 1;
        end
      endtask
      initial begin
        problems = 0;
        golden = 32'd100 * 32'h9E37_79B9;
        // clean INCR frame
        addr = 32'h1000; size = 2; len_p1 = 4; btype = 1;
        expect_reject = 0; receive(golden);
        // legal WRAP that starts mid-window, so it really wraps
        addr = 32'h2004; size = 2; len_p1 = 4; btype = 2;
        expect_reject = 0; receive(golden);
        // wrong in one dimension: WRAP length 3
        addr = 32'h2000; size = 2; len_p1 = 3; btype = 2;
        expect_reject = 1; receive(golden);
        // wrong in the other dimension: legal shape, one CRC bit flipped
        addr = 32'h1000; size = 2; len_p1 = 4; btype = 1;
        expect_reject = 1; receive(golden ^ 32'h0000_0001);
        if (problems == 0) $display("PASS: clean and mid-window WRAP accepted, bad length and bad CRC rejected");
        else $fatal(1, "FAIL: found %0d unexpected verdicts", problems);
        $finish;
      end
    endmodule

    Related topics

    • Shaping Stimulus with Knobs and Policies

    • Randomizing Scenarios, Not Just Items

    Previous

    170 / 259

    Next: Randomizing Scenarios, Not Just Items

    Up next

    Up nextRandomizing Scenarios, Not Just Items

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Transaction Design for Stimulus
    • Layered Constraint Architecture
    • Generator Patterns