Randomization¶
cpptb separates random value generation from constrained transaction solving. Both use deterministic, test-owned random streams, but they solve different authoring problems:
Need |
Use |
|---|---|
Compare complete cpptb and pure-SV authoring styles |
|
Pick values, shuffle data, or generate packed bits |
|
Describe legal relationships between transaction fields |
|
Add membership, weighting, defaults, or runtime modes |
|
Prove coupled constraints or diagnose an unsatisfiable model |
|
Measure exercised behavior with explicit sampling |
|
Reproduce failures across concurrent processes |
Randomization is stimulus construction only. It does not drive a signal, start a clock, wait for an edge, or advance simulation time.
Start with values¶
For most sequences, ordinary value generation is the smallest useful API:
enum : uint8_t { Read, Write, Flush, Fence };
Task<void> packet_sequence(Dut dut, TestContext& test) {
auto& random = test.random();
constexpr std::array<uint8_t, 4> opcodes{Read, Write, Flush, Fence};
constexpr std::array length_mix{
weighted(64u, 5), weighted(256u, 3), weighted(1500u, 1)};
for (uint32_t transaction = 0; transaction < 1000; ++transaction) {
const uint32_t address =
random.randint<uint32_t>(0x1000, 0x1fff);
const uint8_t opcode = random.choice(opcodes);
const uint32_t length = random.weighted_choice(length_mix);
const Bits<256> payload = random.randbits<256>();
co_await drive_packet(dut, address, opcode, length, payload);
}
}
Use this style when values can be generated directly and legality is easy to see in the sequence. See Random value generation for the complete API.
Feature guide¶
Feature |
API |
Guide |
|---|---|---|
Runnable framework comparison |
Exact cpptb and pure-SV peers |
|
Inclusive integral range |
|
|
Select or shuffle values |
|
|
Arbitrary-width packed value |
|
|
Scalar randomized field |
||
Nonrepeating finite cycle |
||
Per-call legality |
||
Values and ranges |
|
|
Weighted solve policy |
|
|
Preferred default |
|
|
Runtime mode switch |
||
Nested transaction |
||
Fixed array or packed field |
||
Adaptive dependency-free solving |
|
|
Direct sampling control |
|
|
Coupled constraint solving |
|
|
Functional coverage |
||
Seed and process replay |
|
Design boundaries¶
The randomization layer is intentionally independent of the simulator and scheduler. It can be used in a coroutine, reference model, monitor helper, or plain C++ unit test. Solver dependencies are optional, and selecting another backend does not change the authored transaction class.
The current composite fields are fixed RandArray<T, N> arrays and
RandBits<Width> packed values constrained through 32-bit words. Dynamic
random arrays, a complete clone of the SystemVerilog constraint language,
coverage-guided solving, and solve before ordering are not currently part of
the API. Functional coverage is deliberately separate from stimulus and does
not steer randomization.
Performance qualification¶
Random APIs have exact C++ and pure-SystemVerilog benchmark peers. The pairs consume the same versioned random stream, drive the same DUT transactions, and must produce the same response checksum before timing is considered:
make feature-test FEATURE=random_stimulus
make feature-test FEATURE=constrained_packet
make feature-test FEATURE=constraint_extensions
make feature-test FEATURE=coverage_sampling
See Performance for current
measurements and the 1.10x C++/pure-SV guard.