Module 4 — Randomization
Constrained-random stimulus generation: rand vs randc, constraint blocks, soft and inline constraints, how the constraint solver actually works, and the pre/post_randomize hooks.
📑 Table of Contents
36rand
Declaring a class property rand marks it as randomizable — its value is chosen by the constraint solver whenever randomize() is called on the object, uniformly across its legal range (subject to constraints).
randomize() returns 0 if the constraints are unsatisfiable (over-constrained). Not checking the return value is a frequent bug source — a silently failed randomize() leaves the old (or default) values in place, and the test proceeds with unintended data.
37randc
randc (random-cyclic) guarantees every value in the variable's range is produced exactly once before any value repeats — useful for exhaustively cycling through a small set of IDs or opcodes without collisions.
| Aspect | rand | randc |
|---|---|---|
| Repetition | Can repeat any time | No repeats until full cycle exhausted |
| Best For | Data fields, addresses, general stimulus | Small enumerated sets: IDs, opcodes, priorities |
| Practical Limit | Any width | Typically kept small (≤ a few bits) — cycle grows exponentially with width |
randc is only supported on class properties (not module-level variables) and works best on small-width fields — a 16-bit randc would need to track 65536 values per cycle, which is impractical.
38Constraints
A constraint block restricts the legal solution space for rand variables — the solver picks values that satisfy every active constraint simultaneously.
-> is a soft implication used inside a constraint block (constraint-level implication), distinct from the assertion implication operators covered in Module 6. Both mean "if left side true, right side must hold," but they apply in very different contexts.
39Soft Constraints
A soft constraint expresses a default/preferred value that can be silently overridden by any other hard constraint (or another soft constraint with higher priority) — useful for providing sensible defaults without hard-locking a field.
When multiple soft constraints on the same variable conflict, the last one declared/applied wins (in textual/inheritance order) — hard constraints always take priority over any soft constraint regardless of order.
40Inline Constraints
The randomize() with {...} syntax adds extra constraints for just that one call, without modifying the class definition — useful for test-specific scenario tweaks.
Inline constraints are the standard way UVM sequences customize a transaction per test — e.g. req.randomize() with { addr == cfg.base_addr; } — without having to write a new transaction subclass for every scenario.
41Constraint Solver
SystemVerilog's constraint solver treats all active hard constraints as a system of equations/inequalities and finds a solution satisfying all of them simultaneously — it does not simply try constraints one at a time.
Internally, the solver converts constraints to a normalized form and uses techniques based on constraint satisfaction / SAT-like solving to find a valid assignment, rather than naive trial-and-error. This is why deeply nested or highly cross-dependent constraints can slow down randomization noticeably as the solver space grows.
If constraints are mutually contradictory (e.g. a < b and b < a both active), randomize() returns 0. Debugging this typically means using the simulator's constraint solver diagnostics/tracing to identify which constraint block is unsatisfiable.
42pre_randomize
pre_randomize() is a built-in callback automatically invoked immediately before the solver runs — useful for setting up state or dynamically enabling/disabling constraints ahead of randomization.
You never call pre_randomize() yourself — the simulator calls it automatically as part of every randomize() invocation. Overriding it in a subclass is common when a derived transaction needs extra setup before its fields are chosen.
43post_randomize
post_randomize() is the counterpart callback, automatically invoked immediately after a successful randomization — typically used to derive/compute non-random fields (like a CRC/checksum) from the values the solver just chose.
Use pre_randomize() to influence what gets randomized (setup/constraint toggling); use post_randomize() to react to what was chosen (derived fields, logging, sanity checks). Both must be declared as functions taking no arguments and returning void.
🎯 Module 4 Recap
randallows repeats;randccycles through every value once before repeating — best for small ID/opcode sets.constraintblocks are solved jointly, not sequentially — the solver finds one assignment satisfying all active hard constraints at once.softconstraints set overridable defaults; any hard constraint (or a later soft one) wins over an earlier soft constraint.- Inline
randomize() with {...}adds test-specific constraints for a single call without touching the class definition. solve...beforeinfluences the order variables are resolved for better distribution on dependent fields — it doesn't fully decouple the system.pre_randomize()/post_randomize()are automatic callbacks for setup-before and derive-after logic around every randomize() call.
📚 Next up — Module 5: Functional Coverage (covergroup, coverpoint, cross coverage, bins, ignore bins, illegal bins)
↑ Back to Table of Contents
Comments
Post a Comment