transactron.testing package
Submodules
transactron.testing.functions module
- transactron.testing.functions.data_const_to_dict(c: data.Const[data.Layout])
transactron.testing.input_generation module
- transactron.testing.input_generation.generate_based_on_layout(layout: MethodLayout) SearchStrategy[NameIntDict]
- transactron.testing.input_generation.generate_method_input(args: list[tuple[str, MethodLayout]]) SearchStrategy[dict[str, NameIntDict]]
- transactron.testing.input_generation.generate_nops_in_list(max_nops: int, generate_list: SearchStrategy[list[T]]) SearchStrategy[list[T | OpNOP]]
- transactron.testing.input_generation.generate_process_input(elem_count: int, max_nops: int, layouts: list[tuple[str, MethodLayout]]) SearchStrategy[list[dict[str, NameIntDict] | OpNOP]]
- transactron.testing.input_generation.generate_shrinkable_list(length: int, generator: SearchStrategy) SearchStrategy[list[T]]
Trick based on https://github.com/HypothesisWorks/hypothesis/blob/ 6867da71beae0e4ed004b54b92ef7c74d0722815/hypothesis-python/src/hypothesis/stateful.py#L143
transactron.testing.logging module
- class transactron.testing.logging.HDLLogWrapper
Bases:
ElaboratableWrapper for a module to enable utils.logging backend for printing in HDL simulation.
- class transactron.testing.logging.HDLLogWrapperComponent
Bases:
HDLLogWrapper,ComponentHDLLogWrapper variant for use with Component.
transactron.testing.method_mock module
- class transactron.testing.method_mock.MethodMock
Bases:
object- __init__(adapter: ~transactron.lib.adapters.AdapterBase, function: ~typing.Callable[[...], NameIntDict | None], *, validate_arguments: ~typing.Callable[[...], bool] | None = None, enable: ~typing.Callable[[], bool] = <function MethodMock.<lambda>>, delay: float = 0, **kwargs: ~typing.Unpack[~transactron.core.body.AdapterBodyParams])
- async effect_process(sim: SimulatorContext) None
- async output_process(sim: SimulatorContext) None
- async validate_arguments_process(sim: SimulatorContext) None
- transactron.testing.method_mock.def_method_mock(tb_getter: Callable[[], TestbenchIO] | Callable[[Any], TestbenchIO], **kwargs) Callable[[Callable[[...], NameIntDict | None]], Callable[[], MethodMock]]
Decorator function to create method mock handlers. It should be applied on a function which describes functionality which we want to invoke on method call. This function will be called on every clock cycle when the method is active, and also on combinational changes to inputs.
The decorated function can have a single argument arg, which receives the arguments passed to a method as a data.Const, or multiple named arguments, which correspond to named arguments of the method.
This decorator can be applied to function definitions or method definitions. When applied to a method definition, lambdas passed to def_method_mock need to take a self argument, which should be the first.
Mocks defined at class level or at test level are automatically discovered and don’t need to be manually added to the simulation.
Any side effects (state modification, assertions, etc.) need to be guarded using the MethodMock.effect decorator.
Make sure to defer accessing state, since decorators are evaluated eagerly during function declaration.
- Parameters:
- tb_getterCallable[[], TestbenchIO] | Callable[[Any], TestbenchIO]
Function to get the TestbenchIO of the mocked method.
- enableCallable[[], bool] | Callable[[Any], bool]
Function which decides if the method is enabled in a given clock cycle.
- validate_argumentsCallable[…, bool]
Function which validates call arguments. This applies only to Adapters with with_validate_arguments set to True.
- delayfloat
Simulation time delay for method mock calling. Used for synchronization between different mocks and testbench processes.
transactron.testing.profiler module
- transactron.testing.profiler.profiler_process(transaction_manager: TransactionManager, profile: Profile)
transactron.testing.simulator module
- class transactron.testing.simulator.PysimSimulator
Bases:
Simulator- __init__(module: HasElaborate, max_cycles: float = 100000.0, add_transaction_module=True, traces_file=None, clk_period=1e-06)
- add_mock(val: MethodMock)
- async transactron.testing.simulator.random_wait(ctx: SimulatorContext, max_cycle_cnt: int, *, min_cycle_cnt: int = 0)
Wait for a random amount of cycles in range [min_cycle_cnt, max_cycle_cnt]
- async transactron.testing.simulator.random_wait_geom(ctx: SimulatorContext, prob: float = 0.5, max_cycle_cnt: int = 65536)
Wait till the first success, where there is prob probability for success in each cycle.
- async transactron.testing.simulator.tick(ctx: SimulatorContext, cycle_cnt: int = 1)
Waits for the given number of cycles.
transactron.testing.test_case module
- class transactron.testing.test_case.TestCaseWithSimulatorBase
Bases:
object- ctx_testing_env_next()
- dependency_manager: DependencyManager
- async static random_wait(ctx: SimulatorContext, max_cycle_cnt: int, *, min_cycle_cnt: int = 0)
Wait for a random amount of cycles in range [min_cycle_cnt, max_cycle_cnt]
- async static random_wait_geom(ctx: SimulatorContext, prob: float = 0.5, max_cycle_cnt: int = 65536)
Wait till the first success, where there is prob probability for success in each cycle.
- async static tick(ctx: SimulatorContext, cycle_cnt: int = 1)
Waits for the given number of cycles.
- static wrap_testing_env_next(func: Callable[[Concatenate[S, P]], T])
transactron.testing.test_case_pytest module
- class transactron.testing.test_case_pytest.TestCaseWithSimulator
Bases:
TestCaseWithSimulatorBase- fixture_initialize_testing_env(request)
transactron.testing.test_circuit module
transactron.testing.testbenchio module
- class transactron.testing.testbenchio.CallTrigger
Bases:
objectA trigger which allows to call multiple methods and sample signals.
The call() and call_try() methods on a TestbenchIO always wait at least one clock cycle. It follows that these methods can’t be used to perform calls to multiple methods in a single clock cycle. Usually this is not a problem, as different methods can be called from different simulation processes. But in cases when more control over the time when different calls happen is needed, this trigger class allows to call many methods in a single clock cycle.
- __init__(sim: SimulatorContext, _calls: Iterable[Value | int | Enum | ValueCastable | tuple[TestbenchIO, dict[str, Any] | None]] = ())
- Parameters:
- sim: SimulatorContext
Amaranth simulator context.
- call(tbio: TestbenchIO, data: dict[str, Any] = {}, /, **kwdata)
Call a method and sample its result.
Adds a method call to the trigger. The method result is sampled on a clock edge. If the call did not succeed, the sampled value is None.
- Parameters:
- tbio: TestbenchIO
The method to call.
- data: dict[str, Any]
Method call arguments stored in a dict.
- **kwdata: Any
Method call arguments passed as keyword arguments. If keyword arguments are used, the data argument should not be provided.
- sample(*values: Value | int | Enum | ValueCastable | TestbenchIO)
Sample a signal or a method result on a clock edge.
Values are sampled like in standard Amaranth TickTrigger. Sampling a method result works like call(), but the method is not called - another process can do that instead. If the method was not called, the sampled value is None.
- Parameters:
- *values: ValueLike | TestbenchIO
Value or method to sample.
- async until_done() Any
Wait until at least one of the calls succeeds.
The CallTrigger normally acts like TickTrigger, e.g. awaiting on it advances the clock to the next clock edge. It is possible that none of the calls could not be performed, for example because the called methods were not enabled. In case we only want to focus on the cycles when one of the calls succeeded, until_done can be used. This works like until() in TickTrigger.
- class transactron.testing.testbenchio.TestbenchIO
Bases:
Elaboratable- __init__(adapter: AdapterBase)
- async call(sim: SimulatorContext, data={}, /, **kwdata) data.Const[data.StructLayout]
- async call_do(sim: SimulatorContext) data.Const[data.StructLayout]
- call_init(sim: SimulatorContext, data={}, /, **kwdata)
- async call_result(sim: SimulatorContext) data.Const[data.StructLayout] | None
- async call_try(sim: SimulatorContext, data={}, /, **kwdata) data.Const[data.StructLayout] | None
- disable(sim: SimulatorContext)
- property done
- enable(sim: SimulatorContext)
- get_call_result(sim: TestbenchContext) data.Const[data.StructLayout] | None
- get_done(sim: TestbenchContext)
- get_outputs(sim: TestbenchContext) data.Const[data.StructLayout]
- property outputs
- sample_outputs(sim: SimulatorContext)
- sample_outputs_done(sim: SimulatorContext)
- sample_outputs_until_done(sim: SimulatorContext)
- set_enable(sim: SimulatorContext, en)
- set_inputs(sim: SimulatorContext, data)
transactron.testing.tick_count module
- transactron.testing.tick_count.make_tick_count_process()
Module contents
- class transactron.testing.CallTrigger
Bases:
objectA trigger which allows to call multiple methods and sample signals.
The call() and call_try() methods on a TestbenchIO always wait at least one clock cycle. It follows that these methods can’t be used to perform calls to multiple methods in a single clock cycle. Usually this is not a problem, as different methods can be called from different simulation processes. But in cases when more control over the time when different calls happen is needed, this trigger class allows to call many methods in a single clock cycle.
- __init__(sim: SimulatorContext, _calls: Iterable[Value | int | Enum | ValueCastable | tuple[TestbenchIO, dict[str, Any] | None]] = ())
- Parameters:
- sim: SimulatorContext
Amaranth simulator context.
- call(tbio: TestbenchIO, data: dict[str, Any] = {}, /, **kwdata)
Call a method and sample its result.
Adds a method call to the trigger. The method result is sampled on a clock edge. If the call did not succeed, the sampled value is None.
- Parameters:
- tbio: TestbenchIO
The method to call.
- data: dict[str, Any]
Method call arguments stored in a dict.
- **kwdata: Any
Method call arguments passed as keyword arguments. If keyword arguments are used, the data argument should not be provided.
- sample(*values: Value | int | Enum | ValueCastable | TestbenchIO)
Sample a signal or a method result on a clock edge.
Values are sampled like in standard Amaranth TickTrigger. Sampling a method result works like call(), but the method is not called - another process can do that instead. If the method was not called, the sampled value is None.
- Parameters:
- *values: ValueLike | TestbenchIO
Value or method to sample.
- async until_done() Any
Wait until at least one of the calls succeeds.
The CallTrigger normally acts like TickTrigger, e.g. awaiting on it advances the clock to the next clock edge. It is possible that none of the calls could not be performed, for example because the called methods were not enabled. In case we only want to focus on the cycles when one of the calls succeeded, until_done can be used. This works like until() in TickTrigger.
- class transactron.testing.MethodMock
Bases:
object- __init__(adapter: ~transactron.lib.adapters.AdapterBase, function: ~typing.Callable[[...], NameIntDict | None], *, validate_arguments: ~typing.Callable[[...], bool] | None = None, enable: ~typing.Callable[[], bool] = <function MethodMock.<lambda>>, delay: float = 0, **kwargs: ~typing.Unpack[~transactron.core.body.AdapterBodyParams])
- async effect_process(sim: SimulatorContext) None
- async output_process(sim: SimulatorContext) None
- async validate_arguments_process(sim: SimulatorContext) None
- class transactron.testing.ProcessContext
Bases:
SimulatorContext- get(expr: ValueLike) Never
Sample the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable, its numeric value is converted to a higher-level representation usingfrom_bits()and then returned.If it is a
Valueor aValueCastablewhose shape is aShape, the numeric value is returned as anint.
This method is only available in testbenches.
- Raises:
TypeErrorIf the caller is a process.
- set(expr, value)
Update the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable,valueis converted to a numeric representation usingconst()and then assigned.If it is a
Valueor aValueCastablewhose shape is aShape,valueis assigned as-is.
This method is available in both processes and testbenches.
When used in a testbench, this method runs all processes that wait (directly or indirectly) for the signals in
exprto change, and returns only after the change propagates through the simulated circuits.
- class transactron.testing.PysimSimulator
Bases:
Simulator- __init__(module: HasElaborate, max_cycles: float = 100000.0, add_transaction_module=True, traces_file=None, clk_period=1e-06)
- add_mock(val: MethodMock)
- class transactron.testing.SimulatorContext
Bases:
objectSimulator context.
Simulator processes and testbenches are
asyncPython functions that interact with the simulation using the only argument they receive: the context. Using a context, it is possible to sample or update signals and wait for events to occur in the simulation.The context has two kinds of methods:
asyncmethods and non-asyncmethods. Calling anasyncmethod may cause the caller to be preempted (be paused such that the simulation time can advance), while calling non-asyncmethods never causes that.Note
While a testbench or process is executing without calling
asyncmethods, no other testbench or process will run, with one exception: if a testbench callsset(), all processes that wait (directly or indirectly) for the updated signals to change will execute before the call returns.- __init__(design, engine: BaseEngine, process: BaseProcess)
- changed(*signals) TriggerCombination
Asynchronously wait until one of the signals change.
This method returns a
TriggerCombinationobject that, when awaited, pauses the execution of the calling process or testbench until any of thesignalschange. The returned object may be used to wait for multiple events.The values captured by this trigger are the values of
signalsat the time the wait has completed.Warning
The simulation may produce glitches: transient changes to signals (e.g. from 0 to 1 and back to 0) during combinational propagation that are invisible in testbenches or waveform captures. Glitches will wake up both processes and testbenches that use this method to wait for a signal to change, and both processes and testbenches must be prepared to handle such spurious wakeups. The presence, count, and sequence in which glitches occur may also vary between simulation runs.
Testbenches that wait for a signal to change using an
awaitstatement might only observe the final value of the signal, and testbenches that wait for changes using anasync forloop will crash with aBrokenTriggerexception if they encounter a glitch.Processes will observe all of the transient values of the signal.
- critical()
Context manager that temporarily makes the caller critical.
Testbenches and processes may be background or critical, where critical ones prevent
Simulator.run()from finishing. Processes are always created background, while testbenches are created critical by default, but may also be created background. This context manager makes the caller critical for the span of thewithstatement.This may be useful in cases where an operation (for example, a bus transaction) takes multiple clock cycles to complete, and must be completed after starting, but the testbench or process performing it never finishes, always waiting for the next operation to arrive. In this case, the caller would elevate itself to become critical only for the duration of the operation itself using this context manager, for example:
async def testbench_bus_transaction(ctx): # On every cycle, check whether the bus has an active transaction... async for clk_edge, rst_active, bus_active_value in ctx.tick().sample(bus.active): if bus_active_value: # ... if it does... with ctx.critical(): # ... make this testbench critical... addr_value = ctx.get(bus.r_addr) ctx.set(bus.r_data, ...) # ... perform the access... await ctx.tick() ctx.set(bus.done, 1) await ctx.tick() ctx.set(bus.done, 0) # ... and complete the transaction later. # The `run()` method could return at this point, but not before.
- delay(interval) TriggerCombination
Wait until a time interval has elapsed.
This method returns a
TriggerCombinationobject that, when awaited, pauses the execution of the calling process or testbench byintervalseconds. The returned object may be used to wait for multiple events.The value captured by this trigger is
Trueif the delay has expired when the wait has completed, andFalseotherwise.The
intervalmay be zero, in which case the caller will be scheduled for execution immediately after all of the processes and testbenches scheduled for the current time step finish executing. In other words, if a call toSimulator.advance()schedules a process or testbench and it performsawait ctx.delay(0), this process or testbench will continue execution only during the next call toSimulator.advance().Note
Although the behavior of
await ctx.delay(0)is well-defined, it may make waveforms difficult to understand and simulations hard to reason about.- Raises:
ValueErrorIf
delayis negative.
- edge(signal, polarity) TriggerCombination
Asynchronously wait until a low-to-high or high-to-low transition of a signal occurs.
This method returns a
TriggerCombinationobject that, when awaited, pauses the execution of the calling process or testbench until the value ofsignal(a single-bit signal or a single-bit slice of a signal) changes fromnot polaritytopolarity. The returned object may be used to wait for multiple events.The value captured by this trigger is
Trueif the relevant transition has occurred at the time the wait has completed, andFalseotherwise.Warning
In most cases, this method should not be used to wait for a status signal to be asserted or deasserted in a testbench because it is likely to introduce a race condition. Whenever a suitable clock domain is available, use
await ctx.tick().until(signal == polarity)instead.- Raises:
TypeErrorIf
signalis neither a single-bitSignalnor a single-bit slice of aSignal.TypeErrorIf the shape of
signalis aShapeCastable.ValueErrorIf
polarityis neither 0 nor 1.
- get(expr)
Sample the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable, its numeric value is converted to a higher-level representation usingfrom_bits()and then returned.If it is a
Valueor aValueCastablewhose shape is aShape, the numeric value is returned as anint.
This method is only available in testbenches.
- Raises:
TypeErrorIf the caller is a process.
- negedge(signal) TriggerCombination
Asynchronously wait until a signal is deasserted.
Equivalent to
edge(signal, 0).
- posedge(signal) TriggerCombination
Asynchronously wait until a signal is asserted.
Equivalent to
edge(signal, 1).
- set(expr, value)
Update the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable,valueis converted to a numeric representation usingconst()and then assigned.If it is a
Valueor aValueCastablewhose shape is aShape,valueis assigned as-is.
This method is available in both processes and testbenches.
When used in a testbench, this method runs all processes that wait (directly or indirectly) for the signals in
exprto change, and returns only after the change propagates through the simulated circuits.
- tick(domain='sync', *, context=None)
Wait until an active clock edge or an asynchronous reset occurs.
This method returns a
TickTriggerobject that, when awaited, pauses the execution of the calling process or testbench until the active edge of the clock, or the asynchronous reset (if applicable), occurs. The returned object may be used to repeatedly wait for one of these events until a condition is satisfied or a specific number of times. See the tick trigger reference for more details.The
domainmay be either aClockDomainor astr. If it is astr, a clock domain with this name is looked up in the elaboratablecontext, or intoplevelifcontextis not provided.- Raises:
ValueErrorIf
domainis"comb".ValueErrorIf
domainis aClockDomainandcontextis provided and notNone.ValueErrorIf
contextis an elaboratable that is not a direct or indirect submodule oftoplevel.NameErrorIf
domainis astr, but there is no clock domain with this name incontextortoplevel.
- class transactron.testing.TestCaseWithSimulatorBase
Bases:
object- ctx_testing_env_next()
- dependency_manager: DependencyManager
- async static random_wait(ctx: SimulatorContext, max_cycle_cnt: int, *, min_cycle_cnt: int = 0)
Wait for a random amount of cycles in range [min_cycle_cnt, max_cycle_cnt]
- async static random_wait_geom(ctx: SimulatorContext, prob: float = 0.5, max_cycle_cnt: int = 65536)
Wait till the first success, where there is prob probability for success in each cycle.
- async static tick(ctx: SimulatorContext, cycle_cnt: int = 1)
Waits for the given number of cycles.
- static wrap_testing_env_next(func: Callable[[Concatenate[S, P]], T])
- class transactron.testing.TestbenchContext
Bases:
SimulatorContext- get(expr)
Sample the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable, its numeric value is converted to a higher-level representation usingfrom_bits()and then returned.If it is a
Valueor aValueCastablewhose shape is aShape, the numeric value is returned as anint.
This method is only available in testbenches.
- Raises:
TypeErrorIf the caller is a process.
- set(expr, value)
Update the value of an expression.
The behavior of this method depends on the type of
expr:If it is a
ValueCastablewhose shape is aShapeCastable,valueis converted to a numeric representation usingconst()and then assigned.If it is a
Valueor aValueCastablewhose shape is aShape,valueis assigned as-is.
This method is available in both processes and testbenches.
When used in a testbench, this method runs all processes that wait (directly or indirectly) for the signals in
exprto change, and returns only after the change propagates through the simulated circuits.
- class transactron.testing.TestbenchIO
Bases:
Elaboratable- __init__(adapter: AdapterBase)
- async call(sim: SimulatorContext, data={}, /, **kwdata) data.Const[data.StructLayout]
- async call_do(sim: SimulatorContext) data.Const[data.StructLayout]
- call_init(sim: SimulatorContext, data={}, /, **kwdata)
- async call_result(sim: SimulatorContext) data.Const[data.StructLayout] | None
- async call_try(sim: SimulatorContext, data={}, /, **kwdata) data.Const[data.StructLayout] | None
- disable(sim: SimulatorContext)
- property done
- enable(sim: SimulatorContext)
- get_call_result(sim: TestbenchContext) data.Const[data.StructLayout] | None
- get_done(sim: TestbenchContext)
- get_outputs(sim: TestbenchContext) data.Const[data.StructLayout]
- property outputs
- sample_outputs(sim: SimulatorContext)
- sample_outputs_done(sim: SimulatorContext)
- sample_outputs_until_done(sim: SimulatorContext)
- set_enable(sim: SimulatorContext, en)
- set_inputs(sim: SimulatorContext, data)
- transactron.testing.data_const_to_dict(c: data.Const[data.Layout])
- transactron.testing.data_layout(val: Shape | int | range | type[Enum] | ShapeCastable) MethodLayout
- transactron.testing.def_method_mock(tb_getter: Callable[[], TestbenchIO] | Callable[[Any], TestbenchIO], **kwargs) Callable[[Callable[[...], NameIntDict | None]], Callable[[], MethodMock]]
Decorator function to create method mock handlers. It should be applied on a function which describes functionality which we want to invoke on method call. This function will be called on every clock cycle when the method is active, and also on combinational changes to inputs.
The decorated function can have a single argument arg, which receives the arguments passed to a method as a data.Const, or multiple named arguments, which correspond to named arguments of the method.
This decorator can be applied to function definitions or method definitions. When applied to a method definition, lambdas passed to def_method_mock need to take a self argument, which should be the first.
Mocks defined at class level or at test level are automatically discovered and don’t need to be manually added to the simulation.
Any side effects (state modification, assertions, etc.) need to be guarded using the MethodMock.effect decorator.
Make sure to defer accessing state, since decorators are evaluated eagerly during function declaration.
- Parameters:
- tb_getterCallable[[], TestbenchIO] | Callable[[Any], TestbenchIO]
Function to get the TestbenchIO of the mocked method.
- enableCallable[[], bool] | Callable[[Any], bool]
Function which decides if the method is enabled in a given clock cycle.
- validate_argumentsCallable[…, bool]
Function which validates call arguments. This applies only to Adapters with with_validate_arguments set to True.
- delayfloat
Simulation time delay for method mock calling. Used for synchronization between different mocks and testbench processes.