Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 36 (async/await testing) #742

Merged
merged 52 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
f7cf56e
Towards async testing support
tilk Oct 25, 2024
e4ce832
Some tests converted to async
tilk Oct 28, 2024
006664b
More async tests
tilk Oct 29, 2024
ed5ac0e
Fix lint
tilk Oct 29, 2024
fec97f2
Towards async mocking
tilk Oct 30, 2024
02ce706
More work towards async mocks
tilk Oct 30, 2024
0e36451
First working mock
tilk Oct 31, 2024
924a8cc
Scheduler test using async mocks
tilk Oct 31, 2024
3d8d6c8
Async core tests
tilk Nov 4, 2024
82267d7
Async Wishbone tests
tilk Nov 5, 2024
5ffa31f
Silence useless warning
tilk Nov 6, 2024
d260186
Async instruction cache tests
tilk Nov 6, 2024
46c626b
Async tests for fetch unit
tilk Nov 6, 2024
e35efcf
Async test for instruction decoding
tilk Nov 7, 2024
4b4d00b
More async tests
tilk Nov 7, 2024
d6c7f11
Even more async tests
tilk Nov 7, 2024
8fc1e5c
Async RS tests
tilk Nov 8, 2024
53e9552
Even more async tests
tilk Nov 8, 2024
d1ed250
Fix
tilk Nov 8, 2024
4e37df7
Async FU tests
tilk Nov 9, 2024
7dfd57d
Async log and validate arguments test
tilk Nov 9, 2024
6cd2e14
Async exception test
tilk Nov 9, 2024
7525530
Async tests for transactron parts and decode stage
tilk Nov 10, 2024
6da7fee
Async RAT tests
tilk Nov 10, 2024
d88a7da
New abstraction: CallTrigger
tilk Nov 10, 2024
61f12c7
Simpler CallTrigger.await
tilk Nov 11, 2024
e46de1c
Async wakeup select test
tilk Nov 11, 2024
9a8db08
Retirement test
tilk Nov 12, 2024
d068792
Merge remote-tracking branch 'origin/master' into tilk/async-tests
tilk Nov 12, 2024
4f2c296
Async announcement test (incorrect, but it was like this before)
tilk Nov 12, 2024
f05b5d6
Async pysim regression tests
tilk Nov 12, 2024
3994aca
AsyncWishbone... is now just Wishbone...
tilk Nov 12, 2024
5f4f659
Async axi lite test
tilk Nov 13, 2024
d3034c9
Renamings
tilk Nov 13, 2024
50cb3f2
Use infrastructure timer
tilk Nov 13, 2024
07b7394
Remove missed debug prints
tilk Nov 13, 2024
65df3d6
Fix regression
tilk Nov 13, 2024
1c0ab96
Merge remote-tracking branch 'origin/master' into tilk/async-tests
tilk Nov 13, 2024
5822a49
Async FPU test
tilk Nov 13, 2024
3a98e42
Use infrastructure cycle counter
tilk Nov 13, 2024
63d1bd5
Rename sugar to method_mock
tilk Nov 13, 2024
4a1be3c
Changed def_method_mock docstring
tilk Nov 13, 2024
f02a910
Renaming
tilk Nov 13, 2024
8adc8c2
Fix docstring
tilk Nov 13, 2024
c14ff5c
Clean up context imports
tilk Nov 14, 2024
4252935
Update transactron/testing/testbenchio.py
tilk Nov 18, 2024
0ecd627
Docstring fix
tilk Nov 18, 2024
0917b69
Removed redundant tick
tilk Nov 18, 2024
86a7286
Method mock docstring
tilk Nov 18, 2024
d1d631a
Simplifications in mocking
tilk Nov 18, 2024
25aac7b
Some docstrings for `CallTrigger`
tilk Nov 18, 2024
245b28e
Merge branch 'master' into tilk/async-tests
tilk Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions coreblocks/core_structs/rob.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from amaranth import *
from amaranth.lib.data import View
import amaranth.lib.memory as memory
from transactron import Method, Transaction, def_method, TModule
from transactron.lib.metrics import *
Expand All @@ -19,7 +18,7 @@ def __init__(self, gen_params: GenParams) -> None:
self.retire = Method()
self.done = Array(Signal() for _ in range(2**self.params.rob_entries_bits))
self.exception = Array(Signal() for _ in range(2**self.params.rob_entries_bits))
self.data = memory.Memory(shape=layouts.data_layout.size, depth=2**self.params.rob_entries_bits, init=[])
self.data = memory.Memory(shape=layouts.data_layout, depth=2**self.params.rob_entries_bits, init=[])
self.get_indices = Method(o=layouts.get_indices, nonexclusive=True)

self.perf_rob_wait_time = FIFOLatencyMeasurer(
Expand Down Expand Up @@ -54,8 +53,8 @@ def elaborate(self, platform):

@def_method(m, self.peek, ready=peek_possible)
def _():
return { # remove View after Amaranth upgrade
"rob_data": View(self.params.get(ROBLayouts).data_layout, read_port.data),
return {
"rob_data": read_port.data,
"rob_id": start_idx,
"exception": self.exception[start_idx],
}
Expand Down
1 change: 1 addition & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ testpaths =
tests
norecursedirs = '*.egg', '.*', 'build', 'dist', 'venv', '__traces__', '__pycache__'
filterwarnings =
ignore:cannot collect test class 'TestbenchContext':pytest.PytestCollectionWarning
ignore:cannot collect test class 'TestbenchIO':pytest.PytestCollectionWarning
ignore:No files were found in testpaths:pytest.PytestConfigWarning:
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
./amaranth-stubs/ # can't use -e -- pyright doesn't see the stubs then :(
amaranth-yosys==0.40.0.0.post100
git+https://github.com/amaranth-lang/amaranth@5e59189c2b8689a453891e17e378bf73806efdd3
git+https://github.com/amaranth-lang/amaranth@994fa815995b1ac5b3c708915dcece2a45796569
dataclasses-json==0.6.3
35 changes: 18 additions & 17 deletions test/backend/test_annoucement.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from coreblocks.interface.layouts import *
from coreblocks.params import GenParams
from coreblocks.params.configurations import test_core_config
from transactron.testing import TestCaseWithSimulator, TestbenchIO
from transactron.testing import TestCaseWithSimulator, TestbenchIO, TestbenchContext


class BackendTestCircuit(Elaboratable):
Expand Down Expand Up @@ -104,32 +104,33 @@ def generate_producer(self, i: int):
results to its output FIFO. This records will be next serialized by FUArbiter.
"""

def producer():
async def producer(sim: TestbenchContext):
inputs = self.fu_inputs[i]
for rob_id, result, rp_dst in inputs:
io: TestbenchIO = self.m.fu_fifo_ins[i]
yield from io.call_init(rob_id=rob_id, result=result, rp_dst=rp_dst)
yield from self.random_wait(self.max_wait)
io.call_init(sim, rob_id=rob_id, result=result, rp_dst=rp_dst)
await self.random_wait(sim, self.max_wait)
self.producer_end[i] = True

return producer

def consumer(self):
yield from self.m.rs_announce_val_tbio.enable()
yield from self.m.rob_mark_done_tbio.enable()
async def consumer(self, sim: TestbenchContext):
# TODO: this test doesn't do anything, fix it!
self.m.rs_announce_val_tbio.enable(sim)
self.m.rob_mark_done_tbio.enable(sim)
while reduce(and_, self.producer_end, True):
# All 3 methods (in RF, RS and ROB) need to be enabled for the result
# announcement transaction to take place. We want to have at least one
# method disabled most of the time, so that the transaction is performed
# only when we enable it inside the loop. Otherwise the transaction could
# get executed at any time, particularly when we wouldn't be monitoring it
yield from self.m.rf_announce_val_tbio.enable()
self.m.rf_announce_val_tbio.enable(sim)

rf_result = yield from self.m.rf_announce_val_tbio.method_argument()
rs_result = yield from self.m.rs_announce_val_tbio.method_argument()
rob_result = yield from self.m.rob_mark_done_tbio.method_argument()
rf_result = self.m.rf_announce_val_tbio.get_outputs(sim)
rs_result = self.m.rs_announce_val_tbio.get_outputs(sim)
rob_result = self.m.rob_mark_done_tbio.get_outputs(sim)

yield from self.m.rf_announce_val_tbio.disable()
self.m.rf_announce_val_tbio.disable(sim)

assert rf_result is not None
assert rs_result is not None
Expand All @@ -144,20 +145,20 @@ def consumer(self):
del self.expected_output[t]
else:
self.expected_output[t] -= 1
yield from self.random_wait(self.max_wait)
await self.random_wait(sim, self.max_wait)

def test_one_out(self):
self.fu_count = 1
self.initialize()
with self.run_simulation(self.m) as sim:
sim.add_process(self.consumer)
sim.add_testbench(self.consumer)
for i in range(self.fu_count):
sim.add_process(self.generate_producer(i))
sim.add_testbench(self.generate_producer(i))

def test_many_out(self):
self.fu_count = 4
self.initialize()
with self.run_simulation(self.m) as sim:
sim.add_process(self.consumer)
sim.add_testbench(self.consumer)
for i in range(self.fu_count):
sim.add_process(self.generate_producer(i))
sim.add_testbench(self.generate_producer(i))
39 changes: 23 additions & 16 deletions test/backend/test_retirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from coreblocks.params import GenParams
from coreblocks.interface.layouts import ROBLayouts, RFLayouts, SchedulerLayouts
from coreblocks.params.configurations import test_core_config
from transactron.lib.adapters import AdapterTrans

from transactron.testing import *
from collections import deque
Expand Down Expand Up @@ -120,42 +121,48 @@ def setup_method(self):
# (and the retirement code doesn't have any special behaviour to handle these cases), but in this simple
# test we don't care to make sure that the randomly generated inputs are correct in this way.

@def_method_mock(lambda self: self.retc.mock_rob_retire, enable=lambda self: bool(self.submit_q), sched_prio=1)
@def_method_mock(lambda self: self.retc.mock_rob_retire, enable=lambda self: bool(self.submit_q))
def retire_process(self):
self.submit_q.popleft()
@MethodMock.effect
def eff():
self.submit_q.popleft()

@def_method_mock(lambda self: self.retc.mock_rob_peek, enable=lambda self: bool(self.submit_q))
def peek_process(self):
return self.submit_q[0]
if self.submit_q:
return self.submit_q[0]

def free_reg_process(self):
async def free_reg_process(self, sim: TestbenchContext):
while self.rf_exp_q:
reg = yield from self.retc.free_rf_adapter.call()
reg = await self.retc.free_rf_adapter.call(sim)
assert reg["reg_id"] == self.rf_exp_q.popleft()

def rat_process(self):
async def rat_process(self, sim: TestbenchContext):
while self.rat_map_q:
current_map = self.rat_map_q.popleft()
wait_cycles = 0
# this test waits for next rat pair to be correctly set and will timeout if that assignment fails
while (yield self.retc.rat.entries[current_map["rl_dst"]]) != current_map["rp_dst"]:
while sim.get(self.retc.rat.entries[current_map["rl_dst"]]) != current_map["rp_dst"]:
wait_cycles += 1
if wait_cycles >= self.cycles + 10:
assert False, "RAT entry was not updated"
yield Tick()
await sim.tick()
assert not self.submit_q
assert not self.rf_free_q

def precommit_process(self):
async def precommit_process(self, sim: TestbenchContext):
await sim.tick() # TODO mocks inactive during first cycle
while self.precommit_q:
info = yield from self.retc.precommit_adapter.call_try(rob_id=self.precommit_q[0])
info = await self.retc.precommit_adapter.call_try(sim, rob_id=self.precommit_q[0])
assert info is not None
assert info["side_fx"]
self.precommit_q.popleft()

@def_method_mock(lambda self: self.retc.mock_rf_free, sched_prio=2)
@def_method_mock(lambda self: self.retc.mock_rf_free)
def rf_free_process(self, reg_id):
assert reg_id == self.rf_free_q.popleft()
@MethodMock.effect
def eff():
assert reg_id == self.rf_free_q.popleft()

@def_method_mock(lambda self: self.retc.mock_exception_cause)
def exception_cause_process(self):
Expand All @@ -174,7 +181,7 @@ def mock_trap_entry_process(self):
pass

@def_method_mock(lambda self: self.retc.mock_fetch_continue)
def mock_fetch_continue_process(self):
def mock_fetch_continue_process(self, pc):
pass

@def_method_mock(lambda self: self.retc.mock_async_interrupt_cause)
Expand All @@ -184,6 +191,6 @@ def mock_async_interrupt_cause(self):
def test_rand(self):
self.retc = RetirementTestCircuit(self.gen_params)
with self.run_simulation(self.retc) as sim:
sim.add_process(self.free_reg_process)
sim.add_process(self.rat_process)
sim.add_process(self.precommit_process)
sim.add_testbench(self.free_reg_process)
sim.add_testbench(self.rat_process)
sim.add_testbench(self.precommit_process)
Loading