Added support for dynamic seed generation. #1089
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds a unique base seed to every simulation from which new unique seed can be generated for the random number generators in the testbench. The feature doesn't not require any specific randomization solution, it works with OSVVM, UVVM,
ieee.math_real.uniform
. Some more details below:Seeds for Random Number Generation¶
The Python test runner automatically generates a 64-bit base seed, which serves as the foundation for deriving new seeds to initialize one or more random number generators (RNGs) within the simulation. This base seed is calculated using the system time and a thread identifier, ensuring that it varies between simulations. This variability enhances test coverage since randomized test will cover different areas in each simulation. By running the same randomized test in several parallel threads but with different base seeds we can also shorten the execution time while maintaining the same level of test coverage.
Note
VHDL-2019 introduces an interface for obtaining the system time. However, as of this writing, support for this feature is limited, and where available, it only offers second-level resolution. If used for base seed generation, simulations in parallel threads would receive the same base seed when started simultaneously.
To address this, the Python test runner uses system time with microsecond resolution combined with an additional thread identifier as the source of entropy. This approach ensures the uniqueness of base seeds across parallel threads.
The base seed is provided via the
runner_cfg
generic and new derived seeds can be obtained by calling theget_seed
function withrunner_cfg
and a salt string. The salt string is hashed together with the base seed to ensure the uniqueness of each derived seed (with very high probability). Thesalt
parameter can be omitted if only a single seed is needed:A seed can also be obtained without referencing
runner_cfg
, which is particularly useful when the seed is created within a process that is not part of the top-level testbench. However, this is only possible aftertest_runner_setup
has been executed. To prevent race conditions, theget_seed
procedure will block execution untiltest_runner_setup
has completed.In the previous examples, the
get_seed
subprograms returned seeds as strings. However,get_seed
subprograms are also available forinteger
seeds and 64-bit seeds ofunsigned
andsigned
type. To avoid any ambiguity that may arise, the following function aliases are defined:get_string_seed
,get_integer_seed
,get_unsigned_seed
, andget_signed_seed
. Additionally, theget_uniform_seed
procedure is provided to support the standarduniform
procedure inieee.math_real
. Theuniform
procedure requires twopositive
seeds,seed1
andseed2
, each with its own specific legal range that is smaller than the fullpositive
range.Reproducibility¶
The seed used for a test is logged in the test output file (
<output path>/output.txt
) and, in the event of a test failure, it is also displayed on the console:To reproduce the failing test setup and verify a bug fix, the failing seed can be specified using the
--seed
option: