Open Intuity opened 7 months ago
Alternative (not necessarily exclusive) syntax with context managers - nice thing is that it could prevent a lock not getting released nicely.
# Declare a sequence
@forastero.sequence()
# List the drivers/monitors this test case will use
@forastero.requires("drv_a")
@forastero.requires("drv_b")
@forastero.requires("mon_a")
async def my_sequence(tb: Testbench, drv_a: DriverA, drv_b: DriverB, mon_a: MonitorA, my_option: int=123):
# Lock some (but not all) of drivers/monitors
async with forastero.lock(drv_a, mon_a) as (drv_lk_a, mon_lk_a):
# Enqueue transactions into the driver
drv_a.enqueue(TransactionA(some_value=my_option))
drv_a.enqueue(TransactionA(...))
# Release the driver early
drv_lk_a.release()
# Wait for a monitor event
rsp = await mon_a.wait_for(MonitorEvent.CAPTURE)
# Release monitor automatically on context exit
# Request all the locks
async with forastero.lock(drv_a, drv_b, mon_a):
# ...do other stuff...
# Release all locks on context exit
I may be missing something but isn't this: https://docs.python.org/3/library/asyncio-task.html#asyncio.gather or https://docs.python.org/3/library/asyncio-task.html#asyncio.wait ?
A few more ideas that have arisen:
@forastero.lock(“some_resource”)
- this allows two related sequences to simply co-ordinate with one another. These are otherwise claimed/released using the same syntax as drivers and monitors;random
instance rather than reusing tb.random
directly - this will allow a sequence to produce stable output while another sequence is being edited;
Introduction
Forastero currently provides drivers, monitors, and scoreboards but provides no infrastructure for generating sequences of transactions to push through drivers and monitors.
The proposal is to add two features to the library:
Any number of sequences can interface with an arbiter, this creates an issue where a sequence may expect to have sole control of a DUT but ends up fighting with other sequences for control. The proposed solution for this is to introduce the concept of locking.
A sequence may request to lock any number of drivers and monitors to gain the sole ability to enqueue/dequeue transactions. The sequence may then release locks as it completes various tasks, allowing other sequences to be interleaved.
One issue with locking is that it can lead to deadlock where sequence A first locks driver X then attempts to lock Y, while sequence B first locks driver Y then attempts to lock driver X. The proposed solution to this is to only allow a sequence to request locks if it holds no outstanding locks - i.e. in a single request a sequence may lock any number of drivers/monitors, it can then release these locks at any level of granularity, and may then only request more locks once its number of held locks reaches zero.
The arbiter will be responsible for servicing lock requests and balancing the competing priorities of servicing easy lock requests where few drivers/monitors are locked against difficult lock requests where many drivers/monitors are locked. Not correctly balancing these priorities will either over emphasise or deprioritise difficult lock requests, and hence starve certain sequences.
The diagram below shows how three sequences interface with an arbiter to provide stimulus, in this example:
SEQUENCE_A
and grants locks todrv_a
,drv_b
, andmon_a
- which prevents sequencesB
andC
from being scheduled;SEQUENCE_A
completes and releases locks, the arbiter allows both sequencesB
andC
to start as their locks can be satisfied in parallel.Syntax
I would suggest the following syntax for sequences and test cases.
Sequences
Testcases
BaseBench
will need to be extended to have a built in arbiter for sequences, then test cases can attach sequences onto it:Compact Wait Conditions
One chunk of code that seems to be repeated a lot is waiting for a given condition to be reached across multiple drivers, monitors, internal probes, etc. For example, we might want to wait for a given transaction to be submitted into the DUT and then the internal FSM state to reach a particular value (i.e. leaving IDLE). It would be nice to have a compact syntax for describing this that the arbiter can then track and satisfy:
NOTE The syntax here is entirely up for debate, but the concept of a concise expression that's checked on various conditions is the key - a bit like SVA implication operators I guess? In essence I'm trying to avoid lots of repetitions of: