Skip to content

Commit

Permalink
Fork implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Lekcyjna committed Nov 19, 2023
1 parent 04a6015 commit 6bbeb5a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 5 deletions.
25 changes: 25 additions & 0 deletions test/common/_test/test_infrastructure.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from amaranth import *
from amaranth.sim import Settle
from test.common import *


Expand Down Expand Up @@ -29,3 +30,27 @@ def process(self):
def test_random(self):
with self.run_simulation(self.m, 50) as sim:
sim.add_sync_process(self.process)


class TestFork(TestCaseWithSimulator):
def setUp(self):
self.m = SimpleTestCircuit(EmptyCircuit())
self.data = 0

def subproces(self):
self.assertEqual(self.data, 0)
self.data = 1
yield
yield
self.assertEqual(self.data, 2)

def process(self):
yield Fork(self.subproces)
yield
yield Settle()
self.assertEqual(self.data, 1)
self.data = 2

def test(self):
with self.run_simulation(self.m, 20) as sim:
sim.add_sync_process(self.process)
38 changes: 33 additions & 5 deletions test/common/infrastructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,15 @@ class Now(CoreblocksCommand):
pass


class Fork(CoreblocksCommand):
def __init__(self, f: Callable[[], TestGen[None]]):
self.f = f


class SyncProcessWrapper:
def __init__(self, f):
def __init__(self, sim: "PysimSimulator", f: Callable[[], TestGen[None]]):
self.org_process = f
self.sim = sim
self.current_cycle = 0

def _wrapping_function(self):
Expand All @@ -126,11 +132,18 @@ def _wrapping_function(self):
self.current_cycle += 1
# forward to amaranth
yield
# Do early forward to amaranth
if not isinstance(command, CoreblocksCommand):
# Pass everything else to amaranth simulator without modifications
response = yield command
elif isinstance(command, Now):
response = self.current_cycle
# Pass everything else to amaranth simulator without modifications
elif isinstance(command, Fork):
f = command.f
self.sim.one_shot_callbacks.append(lambda: self.sim.add_sync_process(f))
response = None
else:
response = yield command
raise RuntimeError(f"Unrecognized command: {command}")
except StopIteration:
pass

Expand Down Expand Up @@ -168,14 +181,29 @@ def __init__(self, module: HasElaborate, max_cycles: float = 10e4, add_transacti
self.ctx = nullcontext()

self.deadline = clk_period * max_cycles
self.one_shot_callbacks = []

def add_sync_process(self, f: Callable[[], TestGen]):
f_wrapped = SyncProcessWrapper(f)
f_wrapped = SyncProcessWrapper(self, f)
super().add_sync_process(f_wrapped._wrapping_function)

def run_until_with_callbacks(self, deadline, *, run_passive=False):
"""Run the simulation until it advances to `deadline` executing callbacks after each iteration.
This function is based on `run_until` from amaranth Simulator class. After each `advance` step
it calls all registred one shot callbacks. After execution of all one shot callbacks there are
removed from the list before starting the next iteration.
"""
# Convert deadline in seconds into internal amaranth 1 ps units
deadline = deadline * 1e12
while cast(Any, self)._engine.now < deadline and (self.advance() or run_passive):
for callback in self.one_shot_callbacks:
callback()
self.one_shot_callbacks.clear()

def run(self) -> bool:
with self.ctx:
self.run_until(self.deadline)
self.run_until_with_callbacks(self.deadline)

return not self.advance()

Expand Down

0 comments on commit 6bbeb5a

Please sign in to comment.