diff --git a/test/cache/test_icache.py b/test/cache/test_icache.py index 88d44450a..8fc3d32e1 100644 --- a/test/cache/test_icache.py +++ b/test/cache/test_icache.py @@ -9,8 +9,6 @@ from coreblocks.cache.icache import ICache, ICacheBypass, CacheRefillerInterface from coreblocks.params import GenParams from coreblocks.interface.layouts import ICacheLayouts -from coreblocks.peripherals.wishbone import WishboneMaster, WishboneParameters -from coreblocks.peripherals.bus_adapter import WishboneMasterAdapter from coreblocks.params.configurations import test_core_config from coreblocks.cache.refiller import SimpleCommonBusCacheRefiller @@ -18,7 +16,7 @@ from transactron.testing.functions import MethodData from transactron.testing.method_mock import MethodMock from transactron.testing.testbenchio import CallTrigger -from ..peripherals.test_wishbone import WishboneInterfaceWrapper +from ..peripherals.bus_mock import BusMockParameters, MockMasterAdapter class SimpleCommonBusCacheRefillerTestCircuit(Elaboratable): @@ -29,12 +27,11 @@ def __init__(self, gen_params: GenParams): def elaborate(self, platform): m = Module() - wb_params = WishboneParameters( + bus_mock_params = BusMockParameters( data_width=self.gen_params.isa.xlen, addr_width=self.gen_params.isa.xlen, ) - self.wb_master = WishboneMaster(wb_params) - self.bus_master_adapter = WishboneMasterAdapter(self.wb_master) + self.bus_master_adapter = MockMasterAdapter(bus_mock_params) self.refiller = SimpleCommonBusCacheRefiller( self.gen_params.get(ICacheLayouts), self.cp, self.bus_master_adapter @@ -43,14 +40,11 @@ def elaborate(self, platform): self.start_refill = TestbenchIO(AdapterTrans(self.refiller.start_refill)) self.accept_refill = TestbenchIO(AdapterTrans(self.refiller.accept_refill)) - m.submodules.wb_master = self.wb_master m.submodules.bus_master_adapter = self.bus_master_adapter m.submodules.refiller = self.refiller m.submodules.start_refill = self.start_refill m.submodules.accept_refill = self.accept_refill - self.wb_ctrl = WishboneInterfaceWrapper(self.wb_master.wb_master) - return m @@ -100,12 +94,12 @@ def setup_method(self) -> None: self.bad_addresses.add(bad_addr) self.bad_fetch_blocks.add(bad_addr & ~(self.cp.fetch_block_bytes - 1)) - async def wishbone_slave(self, sim: TestbenchContext): + async def bus_mock(self, sim: TestbenchContext): while True: - adr, *_ = await self.test_module.wb_ctrl.slave_wait(sim) + req = await self.test_module.bus_master_adapter.request_read_mock.call(sim) - # Wishbone is addressing words, so we need to shift it a bit to get the real address. - addr = adr << exact_log2(self.cp.word_width_bytes) + # Bus model is addressing words, so we need to shift it a bit to get the real address. + addr = req.addr << exact_log2(self.cp.word_width_bytes) await self.random_wait_geom(sim, 0.5) @@ -114,7 +108,7 @@ async def wishbone_slave(self, sim: TestbenchContext): data = random.randrange(2**self.gen_params.isa.xlen) self.mem[addr] = data - await self.test_module.wb_ctrl.slave_respond(sim, data, err=err) + await self.test_module.bus_master_adapter.get_read_response_mock.call(sim, data=data, err=err) async def refiller_process(self, sim: TestbenchContext): while self.requests: @@ -145,7 +139,7 @@ async def refiller_process(self, sim: TestbenchContext): def test(self): with self.run_simulation(self.test_module) as sim: - sim.add_testbench(self.wishbone_slave, background=True) + sim.add_testbench(self.bus_mock, background=True) sim.add_testbench(self.refiller_process) @@ -157,21 +151,18 @@ def __init__(self, gen_params: GenParams): def elaborate(self, platform): m = Module() - wb_params = WishboneParameters( + bus_mock_params = BusMockParameters( data_width=self.gen_params.isa.xlen, addr_width=self.gen_params.isa.xlen, ) - m.submodules.wb_master = self.wb_master = WishboneMaster(wb_params) - m.submodules.bus_master_adapter = self.bus_master_adapter = WishboneMasterAdapter(self.wb_master) + m.submodules.bus_master_adapter = self.bus_master_adapter = MockMasterAdapter(bus_mock_params) m.submodules.bypass = self.bypass = ICacheBypass( self.gen_params.get(ICacheLayouts), self.cp, self.bus_master_adapter ) m.submodules.issue_req = self.issue_req = TestbenchIO(AdapterTrans(self.bypass.issue_req)) m.submodules.accept_res = self.accept_res = TestbenchIO(AdapterTrans(self.bypass.accept_res)) - self.wb_ctrl = WishboneInterfaceWrapper(self.wb_master.wb_master) - return m @@ -216,12 +207,12 @@ def load_or_gen_mem(self, addr: int): self.mem[addr] = random.randrange(2**self.gen_params.isa.ilen) return self.mem[addr] - async def wishbone_slave(self, sim: TestbenchContext): + async def bus_mock(self, sim: TestbenchContext): while True: - adr, *_ = await self.m.wb_ctrl.slave_wait(sim) + req = await self.m.bus_master_adapter.request_read_mock.call(sim) - # Wishbone is addressing words, so we need to shift it a bit to get the real address. - addr = adr << exact_log2(self.cp.word_width_bytes) + # Bus model is addressing words, so we need to shift it a bit to get the real address. + addr = req.addr << exact_log2(self.cp.word_width_bytes) await self.random_wait_geom(sim, 0.5) @@ -231,7 +222,7 @@ async def wishbone_slave(self, sim: TestbenchContext): if self.gen_params.isa.xlen == 64: data = self.load_or_gen_mem(addr + 4) << 32 | data - await self.m.wb_ctrl.slave_respond(sim, data, err=err) + await self.m.bus_master_adapter.get_read_response_mock.call(sim, data=data, err=err) async def user_process(self, sim: TestbenchContext): while self.requests: @@ -256,7 +247,7 @@ async def user_process(self, sim: TestbenchContext): def test(self): with self.run_simulation(self.m) as sim: - sim.add_testbench(self.wishbone_slave, background=True) + sim.add_testbench(self.bus_mock, background=True) sim.add_testbench(self.user_process) diff --git a/test/func_blocks/lsu/test_dummylsu.py b/test/func_blocks/lsu/test_dummylsu.py index 3a13149dc..dd236ffc3 100644 --- a/test/func_blocks/lsu/test_dummylsu.py +++ b/test/func_blocks/lsu/test_dummylsu.py @@ -1,20 +1,19 @@ import random from collections import deque +from amaranth import * -from transactron.lib import Adapter -from transactron.testing.method_mock import MethodMock +from transactron.lib import Adapter, AdapterTrans from transactron.utils import int_to_signed, signed_to_int +from transactron.utils.dependencies import DependencyContext +from transactron.testing.method_mock import MethodMock +from transactron.testing import CallTrigger, TestbenchIO, TestCaseWithSimulator, def_method_mock, TestbenchContext from coreblocks.params import GenParams from coreblocks.func_blocks.fu.lsu.dummyLsu import LSUDummy from coreblocks.params.configurations import test_core_config from coreblocks.arch import * from coreblocks.interface.keys import CoreStateKey, ExceptionReportKey, InstructionPrecommitKey -from transactron.utils.dependencies import DependencyContext from coreblocks.interface.layouts import ExceptionRegisterLayouts, RetirementLayouts -from coreblocks.peripherals.wishbone import * -from transactron.testing import TestbenchIO, TestCaseWithSimulator, def_method_mock, TestbenchContext -from coreblocks.peripherals.bus_adapter import WishboneMasterAdapter -from test.peripherals.test_wishbone import WishboneInterfaceWrapper +from ...peripherals.bus_mock import BusMockParameters, MockMasterAdapter def generate_aligned_addr(max_reg_val: int) -> int: @@ -69,13 +68,9 @@ def __init__(self, gen: GenParams): def elaborate(self, platform): m = Module() - wb_params = WishboneParameters( - data_width=self.gen.isa.ilen, - addr_width=32, - ) + bus_mock_params = BusMockParameters(data_width=self.gen.isa.ilen, addr_width=32) - self.bus = WishboneMaster(wb_params) - self.bus_master_adapter = WishboneMasterAdapter(self.bus) + self.bus_master_adapter = MockMasterAdapter(bus_mock_params) m.submodules.exception_report = self.exception_report = TestbenchIO( Adapter(i=self.gen.get(ExceptionRegisterLayouts).report) @@ -101,9 +96,7 @@ def elaborate(self, platform): m.submodules.issue_mock = self.issue = TestbenchIO(AdapterTrans(func_unit.issue)) m.submodules.accept_mock = self.accept = TestbenchIO(AdapterTrans(func_unit.accept)) - self.io_in = WishboneInterfaceWrapper(self.bus.wb_master) m.submodules.bus_master_adapter = self.bus_master_adapter - m.submodules.bus = self.bus return m @@ -198,7 +191,7 @@ def setup_method(self) -> None: self.generate_instr(2**7, 2**7) self.max_wait = 10 - async def wishbone_slave(self, sim: TestbenchContext): + async def bus_mock(self, sim: TestbenchContext): while self.mem_data_queue: generated_data = self.mem_data_queue.pop() @@ -207,7 +200,9 @@ async def wishbone_slave(self, sim: TestbenchContext): mask = generated_data["mask"] sign = generated_data["sign"] - await self.test_module.io_in.slave_wait_and_verify(sim, generated_data["addr"], 0, 0, mask) + req = await self.test_module.bus_master_adapter.request_read_mock.call(sim) + assert req.addr == generated_data["addr"] + assert req.sel == mask await self.random_wait(sim, self.max_wait) resp_data = int((generated_data["rnd_bytes"][:4]).hex(), 16) @@ -221,7 +216,9 @@ async def wishbone_slave(self, sim: TestbenchContext): data = int_to_signed(signed_to_int(data, size), 32) if not generated_data["err"]: self.returned_data.appendleft(data) - await self.test_module.io_in.slave_respond(sim, resp_data, err=generated_data["err"]) + await self.test_module.bus_master_adapter.get_read_response_mock.call( + sim, data=resp_data, err=generated_data["err"] + ) async def inserter(self, sim: TestbenchContext): for i in range(self.tests_number): @@ -263,7 +260,7 @@ def core_state_process(): return {"flushing": 0} with self.run_simulation(self.test_module) as sim: - sim.add_testbench(self.wishbone_slave, background=True) + sim.add_testbench(self.bus_mock, background=True) sim.add_testbench(self.inserter) sim.add_testbench(self.consumer) @@ -286,12 +283,12 @@ def generate_instr(self, max_reg_val, max_imm_val): "pc": 0, } - wish_data = { + data = { "addr": (s1_val + imm) >> 2, "mask": 0xF, "rnd_bytes": bytes.fromhex(f"{random.randint(0, 2**32-1):08x}"), } - return instr, wish_data + return instr, data def setup_method(self) -> None: random.seed(14) @@ -299,17 +296,22 @@ def setup_method(self) -> None: self.test_module = DummyLSUTestCircuit(self.gen_params) async def one_instr_test(self, sim: TestbenchContext): - instr, wish_data = self.generate_instr(2**7, 2**7) + instr, data = self.generate_instr(2**7, 2**7) await self.test_module.issue.call(sim, instr) - mask = wish_data["mask"] - await self.test_module.io_in.slave_wait_and_verify(sim, wish_data["addr"], 0, 0, mask) - data = wish_data["rnd_bytes"][:4] + mask = data["mask"] + req = await self.test_module.bus_master_adapter.request_read_mock.call(sim) + assert req.addr == data["addr"] + assert req.sel == mask + data = data["rnd_bytes"][:4] data = int(data.hex(), 16) - await self.test_module.io_in.slave_respond(sim, data) - - v = await self.test_module.accept.call(sim) + r, v = ( + await CallTrigger(sim) + .call(self.test_module.bus_master_adapter.get_read_response_mock, data=data, err=0) + .call(self.test_module.accept) + ) + assert r is not None and v is not None assert v["result"] == data def test(self): @@ -378,7 +380,7 @@ def setup_method(self) -> None: self.generate_instr(2**7, 2**7) self.max_wait = 8 - async def wishbone_slave(self, sim: TestbenchContext): + async def bus_mock(self, sim: TestbenchContext): for i in range(self.tests_number): generated_data = self.mem_data_queue.pop() @@ -391,10 +393,13 @@ async def wishbone_slave(self, sim: TestbenchContext): data = (int(generated_data["data"][-2:].hex(), 16) & 0xFFFF) << h_dict[mask] else: data = int(generated_data["data"][-4:].hex(), 16) - await self.test_module.io_in.slave_wait_and_verify(sim, generated_data["addr"], data, 1, mask) + req = await self.test_module.bus_master_adapter.request_write_mock.call(sim) + assert req.addr == generated_data["addr"] + assert req.data == data + assert req.sel == generated_data["mask"] await self.random_wait(sim, self.max_wait) - await self.test_module.io_in.slave_respond(sim, 0) + await self.test_module.bus_master_adapter.get_write_response_mock.call(sim, err=0) async def inserter(self, sim: TestbenchContext): for i in range(self.tests_number): @@ -428,7 +433,7 @@ def eff(): assert False with self.run_simulation(self.test_module) as sim: - sim.add_testbench(self.wishbone_slave) + sim.add_testbench(self.bus_mock) sim.add_testbench(self.inserter) sim.add_testbench(self.get_resulter) @@ -440,9 +445,6 @@ def get_instr(self, exec_fn): async def push_one_instr(self, sim: TestbenchContext, instr): await self.test_module.issue.call(sim, instr) - if instr["exec_fn"]["op_type"] == OpType.LOAD: - await self.test_module.io_in.slave_wait(sim) - await self.test_module.io_in.slave_respond(sim, 1) v = await self.test_module.accept.call(sim) if instr["exec_fn"]["op_type"] == OpType.LOAD: assert v.result == 1 @@ -469,5 +471,23 @@ def eff(): def precommiter(rob_id): return {"side_fx": 1} + pending_req = False + + @def_method_mock(lambda: self.test_module.bus_master_adapter.request_read_mock, enable=lambda: not pending_req) + def request_read(addr, sel): + @MethodMock.effect + def eff(): + nonlocal pending_req + pending_req = True + + @def_method_mock(lambda: self.test_module.bus_master_adapter.get_read_response_mock, enable=lambda: pending_req) + def read_response(): + @MethodMock.effect + def eff(): + nonlocal pending_req + pending_req = False + + return {"data": 1, "err": 0} + with self.run_simulation(self.test_module) as sim: sim.add_testbench(self.process) diff --git a/test/func_blocks/lsu/test_pma.py b/test/func_blocks/lsu/test_pma.py index 16e8aec4b..aaee59bd7 100644 --- a/test/func_blocks/lsu/test_pma.py +++ b/test/func_blocks/lsu/test_pma.py @@ -1,7 +1,7 @@ -import random from coreblocks.func_blocks.fu.lsu.pma import PMAChecker, PMARegion -from transactron.lib import Adapter +from amaranth import * +from transactron.lib import Adapter, AdapterTrans from coreblocks.params import GenParams from coreblocks.func_blocks.fu.lsu.dummyLsu import LSUDummy from coreblocks.params.configurations import test_core_config @@ -10,10 +10,8 @@ from transactron.testing.method_mock import MethodMock from transactron.utils.dependencies import DependencyContext from coreblocks.interface.layouts import ExceptionRegisterLayouts, RetirementLayouts -from coreblocks.peripherals.wishbone import * -from transactron.testing import TestbenchIO, TestCaseWithSimulator, def_method_mock, TestbenchContext -from coreblocks.peripherals.bus_adapter import WishboneMasterAdapter -from test.peripherals.test_wishbone import WishboneInterfaceWrapper +from transactron.testing import CallTrigger, TestbenchIO, TestCaseWithSimulator, def_method_mock, TestbenchContext +from ...peripherals.bus_mock import BusMockParameters, MockMasterAdapter class TestPMADirect(TestCaseWithSimulator): @@ -50,13 +48,9 @@ def __init__(self, gen: GenParams): def elaborate(self, platform): m = Module() - wb_params = WishboneParameters( - data_width=self.gen.isa.ilen, - addr_width=32, - ) + bus_mock_params = BusMockParameters(data_width=self.gen.isa.ilen, addr_width=32) - self.bus = WishboneMaster(wb_params) - self.bus_master_adapter = WishboneMasterAdapter(self.bus) + self.bus_master_adapter = MockMasterAdapter(bus_mock_params) m.submodules.exception_report = self.exception_report = TestbenchIO( Adapter(i=self.gen.get(ExceptionRegisterLayouts).report) @@ -82,8 +76,6 @@ def elaborate(self, platform): m.submodules.issue_mock = self.issue = TestbenchIO(AdapterTrans(func_unit.issue)) m.submodules.accept_mock = self.accept = TestbenchIO(AdapterTrans(func_unit.accept)) - self.io_in = WishboneInterfaceWrapper(self.bus.wb_master) - m.submodules.bus = self.bus m.submodules.bus_master_adapter = self.bus_master_adapter return m @@ -102,17 +94,21 @@ def get_instr(self, addr): async def verify_region(self, sim: TestbenchContext, region: PMARegion): for addr in range(region.start, region.end + 1): + self.precommit_enabled = False instr = self.get_instr(addr) await self.test_module.issue.call(sim, instr) if region.mmio is True: - wb = self.test_module.io_in.wb - for i in range(100): # 100 cycles is more than enough - wb_requested = sim.get(wb.stb) and sim.get(wb.cyc) - assert not wb_requested - - await self.test_module.io_in.slave_wait(sim) - await self.test_module.io_in.slave_respond(sim, (addr << (addr % 4) * 8)) - v = await self.test_module.accept.call(sim) + for i in range(10): # 10 cycles is more than enough + ret = await self.test_module.bus_master_adapter.request_read_mock.call_try(sim) + assert ret is None + self.precommit_enabled = True + await self.test_module.bus_master_adapter.request_read_mock.call(sim) + _, v = ( + await CallTrigger(sim) + .call(self.test_module.bus_master_adapter.get_read_response_mock, data=addr << (addr % 4) * 8, err=0) + .call(self.test_module.accept) + .until_done() + ) assert v.result == addr async def process(self, sim: TestbenchContext): @@ -127,6 +123,7 @@ def test_pma_indirect(self): ] self.gen_params = GenParams(test_core_config.replace(pma=self.pma_regions)) self.test_module = PMAIndirectTestCircuit(self.gen_params) + self.precommit_enabled = False @def_method_mock(lambda: self.test_module.exception_report) def exception_consumer(arg): @@ -137,7 +134,7 @@ def eff(): @def_method_mock( lambda: self.test_module.precommit, validate_arguments=lambda rob_id: rob_id == 1, - enable=lambda: random.random() < 0.5, + enable=lambda: self.precommit_enabled, ) def precommiter(rob_id): return {"side_fx": 1} diff --git a/test/peripherals/bus_mock.py b/test/peripherals/bus_mock.py new file mode 100644 index 000000000..bf74f44ce --- /dev/null +++ b/test/peripherals/bus_mock.py @@ -0,0 +1,41 @@ +from amaranth import * +from dataclasses import dataclass +from transactron import TModule +from transactron.testing import TestbenchIO +from transactron.lib.adapters import Adapter +from coreblocks.peripherals.bus_adapter import BusParametersInterface, BusMasterInterface, CommonBusMasterMethodLayout + + +__all__ = ["BusMockParameters", "MockMasterAdapter"] + + +@dataclass +class BusMockParameters(BusParametersInterface): + data_width: int + addr_width: int + granularity: int = 8 + + +class MockMasterAdapter(Elaboratable, BusMasterInterface): + def __init__(self, params: BusMockParameters): + self.params = params + self.method_layouts = CommonBusMasterMethodLayout(params) + + self.request_read_mock = TestbenchIO(Adapter(i=self.method_layouts.request_read_layout)) + self.request_write_mock = TestbenchIO(Adapter(i=self.method_layouts.request_write_layout)) + self.get_read_response_mock = TestbenchIO(Adapter(o=self.method_layouts.read_response_layout)) + self.get_write_response_mock = TestbenchIO(Adapter(o=self.method_layouts.write_response_layout)) + self.request_read = self.request_read_mock.adapter.iface + self.request_write = self.request_write_mock.adapter.iface + self.get_read_response = self.get_read_response_mock.adapter.iface + self.get_write_response = self.get_write_response_mock.adapter.iface + + def elaborate(self, platform): + m = TModule() + + m.submodules.request_read_mock = self.request_read_mock + m.submodules.request_write_mock = self.request_write_mock + m.submodules.get_read_response = self.get_read_response_mock + m.submodules.get_write_response = self.get_write_response_mock + + return m