Part 10 · Advanced Topics · Intermediate
Simulator Seed Control
Tool-specific random seed controls, deterministic launch patterns, and policy boundaries between test logic and regression launcher.
Why control belongs to the launcher
A test should define scenario intent ; the launcher should define seed identity. Keeping these concerns separate avoids hard-coded seeds in test code and allows matrix runs without recompiling.
Most teams standardize on a launcher contract such as --seed <int>|random and map it to vendor-specific simulator arguments. The contract should be stable even when simulator flavor changes.
[REG] launcher contract -> tool mapping
User intent:
--seed 12345
--seed random
Mapping:
VCS -> +ntb_random_seed=<value>
Xcelium -> -svseed <value>
Questa -> -sv_seed <value>
Riviera -> -sv_seed <value>
Rule:
random means simulator generates a seed
but launcher must still capture the chosen valuePortable command snippets
# VCS
simv +UVM_TESTNAME=axi_random_test +ntb_random_seed=821734 \
+UVM_VERBOSITY=UVM_LOW
# Xcelium
xrun -R -uvm -svseed 821734 \
+UVM_TESTNAME=axi_random_test +UVM_VERBOSITY=UVM_LOW
# Questa
vsim -c work.top -sv_seed 821734 \
+UVM_TESTNAME=axi_random_test -do "run -all; quit -f"Do not combine multiple seed options in one command.
Do not rely on simulator default seed behavior.
Record the final chosen numeric seed, even in random mode.
Seed propagation inside UVM
The simulator seed initializes the random stream, then object-level randomization proceeds through sequence items and classes. Debug often needs both top-level seed and object-local random state snapshots.
class seed_probe_test extends uvm_test;
`uvm_component_utils(seed_probe_test)
function void start_of_simulation_phase(uvm_phase phase);
super.start_of_simulation_phase(phase);
// Print enough metadata for deterministic replay.
`uvm_info(
"SEED",
$sformatf(
"test=%s sim_seed=%0d build=%s",
get_type_name(),
$get_initial_random_seed(),
`GIT_SHA
),
UVM_NONE
)
endfunction
endclassIf your simulator does not support $get_initial_random_seed(), pull the seed from the launch manifest and print that value via plusarg parsing.
Plusarg fallback pattern
function int get_seed_from_plusarg();
string s;
if ($value$plusargs("DC_SEED=%s", s))
return s.atoi();
return -1; // unknown
endfunctionKey takeaways
Keep seed policy in launcher, not in test source code.
Map one stable interface to simulator-specific options.
Always emit the effective numeric seed in runtime logs.
Treat random mode as random selection plus deterministic recording.
Common pitfalls
Hard-coding seed constants in sequences.
Using tool defaults and expecting consistency across versions.
Forgetting to persist selected seed when random mode is used.
Regression-friendly launch wrappers
A thin wrapper script can normalize seed handling and reduce command drift across teams.
#!/usr/bin/env bash
set -euo pipefail
SIM="${SIM:-vcs}"
TEST="${1:-axi_random_test}"
SEED="${2:-random}"
case "$SIM" in
vcs)
if [[ "$SEED" == "random" ]]; then
CMD=(simv +UVM_TESTNAME="$TEST" +ntb_random_seed=random)
else
CMD=(simv +UVM_TESTNAME="$TEST" +ntb_random_seed="$SEED")
fi
;;
xrun)
if [[ "$SEED" == "random" ]]; then
CMD=(xrun -R -uvm +UVM_TESTNAME="$TEST" -svseed random)
else
CMD=(xrun -R -uvm +UVM_TESTNAME="$TEST" -svseed "$SEED")
fi
;;
*)
echo "unsupported SIM=$SIM" >&2
exit 2
;;
esac
echo "[REG] launch sim=$SIM test=$TEST seed=$SEED"
"${CMD[@]}"[REG] wrapper responsibilities
must:
- accept explicit seed or random mode
- print launch tuple (sim, test, seed mode)
- write manifest json row per run
- preserve additional plusargs
should:
- detect duplicate run-id collisions
- include tool version and compile hash