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_cfggeneric and new derived seeds can be obtained by calling theget_seedfunction withrunner_cfgand 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). Thesaltparameter 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_setuphas been executed. To prevent race conditions, theget_seedprocedure will block execution untiltest_runner_setuphas completed.In the previous examples, the
get_seedsubprograms returned seeds as strings. However,get_seedsubprograms are also available forintegerseeds and 64-bit seeds ofunsignedandsignedtype. 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_seedprocedure is provided to support the standarduniformprocedure inieee.math_real. Theuniformprocedure requires twopositiveseeds,seed1andseed2, each with its own specific legal range that is smaller than the fullpositiverange.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
--seedoption: