AMBA AXI · Module 16
Constrained-Random AXI Traffic
Generate legal, stressful random AXI stimulus — a randomizable transaction class with constraints that keep bursts protocol-legal (size ≤ bus width, no 4 KB crossing, legal WRAP lengths, alignment), distribution weighting to bias toward stressful corners, and layered sequences that drive coverage toward closure while never emitting illegal traffic.
Coverage (16.5) tells you what to exercise; constrained-random stimulus is the engine that produces it. Instead of hand-writing every transaction, you declare a randomizable transaction class and a set of constraints that keep the random choices protocol-legal (a burst that crosses a 4 KB boundary or uses an illegal WRAP length is not a test, it's a malformed stimulus), then let the solver generate thousands of varied, legal transactions across many seeds — biased by distribution weighting toward the stressful corners that matter. This chapter builds that generator: the constraint set that encodes AXI's legality rules, the weighting that steers toward coverage holes, and the layered sequences that assemble transactions into realistic, stressful traffic — the bulk engine behind coverage closure.
1. The Randomizable Transaction and Its Constraints
The foundation is a transaction class with rand fields and constraints. The constraints fall into two kinds: legality (must always hold — these encode the protocol) and shaping (bias the distribution toward interesting traffic). Legality first:
class axi_txn extends uvm_sequence_item;
rand bit [ADDR_W-1:0] addr;
rand bit [7:0] len; // AWLEN/ARLEN (beats-1)
rand bit [2:0] size; // log2(bytes per beat)
rand bit [1:0] burst; // 0=FIXED 1=INCR 2=WRAP
rand bit [ID_W-1:0] id;
// --- LEGALITY constraints (always true; encode the protocol) ---
constraint c_burst_legal { burst inside {0, 1, 2}; } // no reserved
constraint c_size_legal { (1 << size) <= (DATA_W/8); } // ≤ bus width
constraint c_wrap_len { // WRAP: 2/4/8/16
(burst == 2) -> (len inside {1, 3, 7, 15});
}
constraint c_wrap_align { // WRAP start aligned
(burst == 2) -> ((addr % ((len+1) << size)) == 0);
}
constraint c_no_4k_cross { // INCR mustn't cross 4 KB
(burst == 1) ->
((addr % 4096) + ((len + 1) << size)) <= 4096;
}
endclassThese constraints make every randomized transaction a legal AXI burst: no reserved burst type, no transfer size beyond the bus, WRAP lengths restricted to 2/4/8/16 and aligned, and INCR bursts that never cross a 4 KB boundary. The solver respects all of them simultaneously when it picks values.
2. Shaping the Distribution Toward Stress
Pure uniform randomization wastes cycles on bland traffic and rarely hits corners. Shaping constraints (often dist weighting) bias toward the stressful cases: short and maximum-length bursts more often than mid, narrow transfers (smaller than the bus) regularly, the boundary-adjacent addresses, and a spread of IDs to force interleaving.
// --- SHAPING constraints (bias toward stressful corners) ---
constraint c_len_dist { // favor extremes (1-beat and max)
len dist { 0 := 30, [1:15] := 20, [16:254] := 20, 255 := 30 };
}
constraint c_size_dist { // exercise narrow transfers often
size dist { [0:1] := 40, [2:$clog2(DATA_W/8)] := 60 };
}
constraint c_id_spread { // many IDs → interleaving/ordering
id dist { 0 := 20, [1:(1<<ID_W)-1] := 80 };
}Shaping never relaxes legality — the dist only chooses among legal values. The weighting is the lever you turn during coverage closure (16.5): when a bin is unhit, you bias the distribution toward it.
3. Layered Sequences
Individual random transactions aren't enough — real stress comes from sequences that assemble them into scenarios: streams of back-to-back transactions, bursts of same-ID traffic (to stress ordering), mixed read/write, and targeted corner sequences. UVM sequences layer: a base random sequence, specialized sequences (e.g. "all-same-ID," "address-boundary stress," "max-outstanding"), and virtual sequences that coordinate multiple agents.
// Base random sequence — N legal random transactions
class axi_rand_seq extends uvm_sequence #(axi_txn);
rand int n = 100;
task body();
repeat (n) begin
axi_txn t = axi_txn::type_id::create("t");
start_item(t);
assert(t.randomize()); // constraints applied here
finish_item(t);
end
endtask
endclass
// Specialized: stress same-ID ordering (all transactions share one ID)
class axi_same_id_seq extends axi_rand_seq;
rand bit [ID_W-1:0] fixed_id;
task body();
repeat (n) begin
axi_txn t = axi_txn::type_id::create("t");
start_item(t);
assert(t.randomize() with { id == fixed_id; }); // extra inline constraint
finish_item(t);
end
endtask
endclassThe randomize() with { ... } adds inline constraints layered on top of the class constraints — a clean way to specialize a sequence (force an ID, a region, a burst type) without rewriting the legality rules, which always still apply.
4. The Generate–Measure–Refine Loop
Constrained-random stimulus is not "run random forever" — it's a closed loop with coverage (16.5): generate random traffic across many seeds, measure coverage, find the holes, then refine (tighten distributions, add specialized sequences, or write a directed test for the truly rare corner), and repeat until meaningful coverage closes. Many seeds matter — each seed explores a different region of the legal space, so broad seed sweeps find bugs and fill bins that a single run won't.
5. Common Misconceptions
6. Debugging Insight
7. Verification Insight
8. Interview Questions
9. Summary
Constrained-random is the engine that produces the legal, stressful traffic coverage demands. A randomizable transaction class carries rand fields and two kinds of constraints: legality constraints that encode the protocol and always hold (burst type legal, size ≤ bus width, WRAP length 2/4/8/16 and aligned, INCR no-4 KB-cross) so the generator can never emit illegal traffic, and shaping constraints (dist weighting) that bias the distribution toward stressful corners (extreme lengths, narrow transfers, spread IDs) among legal values only. Layered sequences assemble transactions into scenarios — a base random sequence for breadth, specialized sequences with inline with constraints for targeted stress (same-ID ordering, boundary clusters, max-outstanding), and virtual sequences coordinating agents — where inline constraints add to legality and never relax it (a conflict correctly makes randomize() fail rather than emit illegal traffic).
The method runs as a generate–measure–refine loop with coverage (16.5): generate legal shaped traffic across many seeds (each exploring a different slice of the legal space, every seed logged for replay), check with the scoreboard/assertions, measure coverage, and refine by re-weighting distributions, adding specialized sequences, or writing directed tests for the rare corners — repeating until coverage closes. The disciplines: legality as hard constraints, shaping for stress, seeds for breadth, coverage for direction. This coverage-driven flow turns simulation into a goal-directed campaign with a measurable endpoint, complementing directed tests (for precise corners) and formal (for provable properties). Next, we deliberately step outside the legal space — controlled error injection and negative testing — to verify the DUT's error handling.
10. What Comes Next
You can now generate legal stressful traffic; next we deliberately drive illegal/error scenarios:
- 16.7 — Negative & Error-Injection Testing (coming next) — driving illegal and error scenarios in controlled ways and verifying the DUT responds correctly (SLVERR/DECERR, error recovery) — the deliberate inverse of the legality constraints here.
Previous: 16.5 — AXI Functional Coverage. Related: 7.6 — The 4 KB Boundary Rule and 7.4 — WRAP Bursts for the legality rules encoded as constraints, and 8.2 — Transaction IDs for the ID spread that drives interleaving.