Introduction
Most testbenches require two types of component to operate:
-
Drivers stimulate interfaces on the design according to the implementation's signalling protocols. They convert transactions from the representation used by the testbench into the state of the different signals on the boundary of the design.
-
Monitors act in the opposite way to drivers, monitoring the signals wiggling on the boundary of the design and capturing those into transactions that the testbench analyses.
Different interfaces will require custom drivers and monitors, but there is a common core of shared functionality - this is why Forastero provides two base classes BaseDriver and BaseMonitor.
Events
The Component class inherits from the EventEmitter class, which supports the publishing of and subscription to events. This mechanism can be used to drive models, co-ordinate stimulus, or generally observe the state of monitors and drivers.
The documentation for Drivers and Monitors will go further into how these mechanisms can be used.
Logging
Both BaseDriver
and BaseMonitor
inherit from Component
, and this root class
provides a number of utility features. One of the most useful is a hierarchical
log specific to the driver or monitor.
- All drivers will be given a logging context of
tb.driver.<NAME>
; - All monitors will be given a logging context of
tb.monitor.<NAME>
.
These logs can be accessed using self.log
, for example:
class StreamMonitor(BaseMonitor):
async def monitor(self, capture) -> None:
while True:
await RisingEdge(self.clk)
if self.rst.value == 1:
continue
if self.io.get("valid", 1) and self.io.get("ready", 1):
self.log.debug("Hello! I saw a transaction!")
capture(StreamTransaction(data=self.io.get("data", 0)))
In the simulation log, you will see the logging context appear along with the timestamp, verbosity, and log message - for example:
1229.00ns INFO tb.driver.driver_a Starting to send transaction
1230.00ns INFO tb.driver.driver_b Finished sending a transaction
1231.00ns INFO tb.monitor.monitor_a Hello! I saw a transaction!
More details on logging can be found here.
forastero.component.Component
Bases: EventEmitter
Base component type for working with BaseIO interfaces, can be extended to form drivers, monitors, and other signalling protocol aware components.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
tb
|
Any
|
Handle to the testbench |
required |
io
|
BaseIO
|
Handle to the BaseIO interface |
required |
clk
|
ModifiableObject
|
Clock signal to use when driving/sampling the interface |
required |
rst
|
ModifiableObject
|
Reset signal to use when driving/sampling the interface |
required |
random
|
Random | None
|
Random number generator to use (optional) |
None
|
name
|
str | None
|
Unique name for this component instance (optional) |
None
|
blocking
|
bool
|
Whether this component should block shutdown (default: True) |
True
|
busy
property
Determine if the component is currently busy
idle()
async
Blocks until the component is no longer busy
lock()
async
Lock the component's internal lock
release()
Release the component's internal lock
seed(random)
Set up the random seed (used by testbench when registering a component)
Parameters:
Name | Type | Description | Default |
---|---|---|---|
random
|
Random
|
The random instance to seed from |
required |
forastero.event.EventEmitter
Core support for publishing events and subscribing to them
publish(event, obj)
Publish an event and deliver it to any registered subscribers.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event
|
Enum
|
Enumerated event |
required |
obj
|
Any
|
Object associated to the event |
required |
subscribe(event, callback)
Subscribe to an event being published by this component.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event
|
Enum
|
Enumerated event |
required |
callback
|
Callable
|
Method to call when the event occurs, this must accept arguments of component, event type, and an associated object |
required |
subscribe_all(callback)
Subscribe to all events published by this component.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
callback
|
Callable
|
Method to call when the event occurs, this must accept arguments of component, event type, and an associated object |
required |
unsubscribe_all(event=None)
De-register all subscribers for a given event (when event is not None), or all subscribers from all events (when event is None).
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event
|
Enum | None
|
Optional enumerated event to unsubscribe, or None to unsubscribe all subscribers for all events |
None
|
wait_for(event)
async
Wait for a specific enumerated event to occur and return the data that was associated to it.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event
|
Enum
|
Enumerated event trigger |
required |
Returns:
Type | Description |
---|---|
Any
|
Data associated with the event |