From 83b0dcf5faf3c467364d18f3924f43f681dbedd7 Mon Sep 17 00:00:00 2001 From: Marek Materzok Date: Sat, 5 Oct 2024 16:55:05 +0200 Subject: [PATCH 1/2] Update Amaranth to after RFC 58 (#733) --- amaranth-stubs | 2 +- coreblocks/backend/retirement.py | 4 +- coreblocks/cache/icache.py | 27 +++--- coreblocks/core.py | 2 +- coreblocks/core_structs/rob.py | 8 +- coreblocks/frontend/fetch/fetch.py | 2 +- coreblocks/func_blocks/csr/csr.py | 2 +- coreblocks/func_blocks/fu/common/rs.py | 5 + .../func_blocks/fu/division/long_division.py | 2 +- .../fu/unsigned_multiplication/common.py | 5 + .../fu/unsigned_multiplication/pipelined.py | 2 +- .../fu/unsigned_multiplication/sequence.py | 4 +- .../fu/unsigned_multiplication/shift.py | 2 +- coreblocks/params/instr.py | 1 - coreblocks/peripherals/wishbone.py | 16 ++-- coreblocks/priv/csr/csr_instances.py | 10 +- coreblocks/priv/csr/csr_register.py | 6 +- coreblocks/priv/traps/interrupt_controller.py | 2 +- docs/conf.py | 12 +++ requirements.txt | 4 +- scripts/synthesize.py | 3 +- test/backend/test_annoucement.py | 8 +- test/backend/test_retirement.py | 10 +- test/cache/test_icache.py | 96 +++++++++---------- test/core_structs/test_rat.py | 4 +- test/core_structs/test_reorder_buffer.py | 22 ++--- test/frontend/test_decode_stage.py | 2 +- test/frontend/test_fetch.py | 24 ++--- test/frontend/test_rvc.py | 6 +- test/func_blocks/csr/test_csr.py | 24 ++--- test/func_blocks/fu/common/test_rs.py | 30 +++--- test/func_blocks/fu/functional_common.py | 12 +-- .../func_blocks/fu/test_pipelined_mul_unit.py | 4 +- test/func_blocks/fu/test_unsigned_mul_unit.py | 4 +- test/func_blocks/lsu/test_dummylsu.py | 24 ++--- test/func_blocks/lsu/test_pma.py | 4 +- test/peripherals/test_axi_lite.py | 28 +++--- test/peripherals/test_wishbone.py | 66 ++++++------- test/priv/traps/test_exception.py | 2 +- test/regression/cocotb.py | 4 +- test/regression/cocotb/benchmark.Makefile | 2 +- test/regression/cocotb/signature.Makefile | 2 +- test/regression/cocotb/test.Makefile | 2 +- test/regression/pysim.py | 20 ++-- test/scheduler/test_rs_selection.py | 28 +++--- test/scheduler/test_scheduler.py | 22 +++-- test/scheduler/test_wakeup_select.py | 6 +- test/test_core.py | 30 +++--- test/transactron/core/test_transactions.py | 27 +++--- test/transactron/lib/test_fifo.py | 10 +- test/transactron/lib/test_transaction_lib.py | 66 ++++++------- test/transactron/test_adapter.py | 2 +- test/transactron/test_assign.py | 13 ++- test/transactron/test_connectors.py | 6 +- test/transactron/test_methods.py | 20 ++-- test/transactron/test_metrics.py | 42 ++++---- test/transactron/test_simultaneous.py | 6 +- .../test_transactron_lib_storage.py | 14 +-- .../testing/test_infrastructure.py | 4 +- test/transactron/testing/test_log.py | 44 +++++---- .../testing/test_validate_arguments.py | 6 +- transactron/core/manager.py | 4 +- transactron/core/tmodule.py | 4 +- transactron/graph.py | 2 +- transactron/lib/adapters.py | 5 + transactron/lib/fifo.py | 8 +- transactron/lib/metrics.py | 12 ++- transactron/lib/storage.py | 14 +-- transactron/testing/gtkw_extension.py | 15 ++- transactron/testing/infrastructure.py | 35 ++++--- transactron/testing/logging.py | 2 +- transactron/testing/profiler.py | 2 +- transactron/testing/testbenchio.py | 14 +-- transactron/tracing.py | 6 +- .../utils/amaranth_ext/elaboratables.py | 2 +- transactron/utils/assign.py | 2 +- 76 files changed, 532 insertions(+), 462 deletions(-) diff --git a/amaranth-stubs b/amaranth-stubs index 8c580c76f..c0325b42e 160000 --- a/amaranth-stubs +++ b/amaranth-stubs @@ -1 +1 @@ -Subproject commit 8c580c76f0b52dc12d94f6269b8b082309eaed69 +Subproject commit c0325b42e4553def483a82ffed14fdc6bf353bdb diff --git a/coreblocks/backend/retirement.py b/coreblocks/backend/retirement.py index b03cb20ee..477b735c3 100644 --- a/coreblocks/backend/retirement.py +++ b/coreblocks/backend/retirement.py @@ -70,7 +70,7 @@ def elaborate(self, platform): m_csr = self.dependency_manager.get_dependency(GenericCSRRegistersKey()).m_mode m.submodules.instret_csr = self.instret_csr - side_fx = Signal(reset=1) + side_fx = Signal(init=1) def free_phys_reg(rp_dst: Value): # mark reg in Register File as free @@ -129,7 +129,7 @@ def flush_instr(rob_entry): cause_entry = Signal(self.gen_params.isa.xlen) - arch_trap = Signal(reset=1) + arch_trap = Signal(init=1) with m.If(cause_register.cause == ExceptionCause._COREBLOCKS_ASYNC_INTERRUPT): # Async interrupts are inserted only by JumpBranchUnit and conditionally by MRET and CSR diff --git a/coreblocks/cache/icache.py b/coreblocks/cache/icache.py index 8f645a766..957543683 100644 --- a/coreblocks/cache/icache.py +++ b/coreblocks/cache/icache.py @@ -3,6 +3,7 @@ from amaranth import * from amaranth.lib.data import View +import amaranth.lib.memory as memory from amaranth.utils import exact_log2 from transactron.core import def_method, Priority, TModule @@ -156,7 +157,7 @@ def elaborate(self, platform): with Transaction().body(m): self.perf_flushes.incr(m, cond=flush_finish) - with m.FSM(reset="FLUSH") as fsm: + with m.FSM(init="FLUSH") as fsm: with m.State("FLUSH"): with m.If(flush_finish): m.next = "LOOKUP" @@ -172,7 +173,7 @@ def elaborate(self, platform): m.next = "LOOKUP" # Replacement policy - way_selector = Signal(self.params.num_of_ways, reset=1) + way_selector = Signal(self.params.num_of_ways, init=1) with m.If(refill_finish): m.d.sync += way_selector.eq(way_selector.rotate_left(1)) @@ -329,27 +330,25 @@ def elaborate(self, platform): for i in range(self.params.num_of_ways): way_wr = self.way_wr_en[i] - tag_mem = Memory(width=len(Value.cast(self.tag_wr_data)), depth=self.params.num_of_sets) - tag_mem_rp = tag_mem.read_port() + tag_mem = memory.Memory(shape=self.tag_data_layout, depth=self.params.num_of_sets, init=[]) tag_mem_wp = tag_mem.write_port() - m.submodules[f"tag_mem_{i}_rp"] = tag_mem_rp - m.submodules[f"tag_mem_{i}_wp"] = tag_mem_wp + tag_mem_rp = tag_mem.read_port(transparent_for=[tag_mem_wp]) + m.submodules[f"tag_mem_{i}"] = tag_mem - m.d.comb += [ # remove Value.cast after Amaranth upgrade - assign(Value.cast(self.tag_rd_data[i]), tag_mem_rp.data), + m.d.comb += [ + assign(self.tag_rd_data[i], tag_mem_rp.data), tag_mem_rp.addr.eq(self.tag_rd_index), tag_mem_wp.addr.eq(self.tag_wr_index), - assign(tag_mem_wp.data, Value.cast(self.tag_wr_data)), + assign(tag_mem_wp.data, self.tag_wr_data), tag_mem_wp.en.eq(self.tag_wr_en & way_wr), ] - data_mem = Memory( - width=self.fetch_block_bits, depth=self.params.num_of_sets * self.params.fetch_blocks_in_line + data_mem = memory.Memory( + shape=self.fetch_block_bits, depth=self.params.num_of_sets * self.params.fetch_blocks_in_line, init=[] ) - data_mem_rp = data_mem.read_port() data_mem_wp = data_mem.write_port() - m.submodules[f"data_mem_{i}_rp"] = data_mem_rp - m.submodules[f"data_mem_{i}_wp"] = data_mem_wp + data_mem_rp = data_mem.read_port(transparent_for=[data_mem_wp]) + m.submodules[f"data_mem_{i}"] = data_mem # We address the data RAM using fetch blocks, so we have to # discard a few least significant bits from the address. diff --git a/coreblocks/core.py b/coreblocks/core.py index 3a14b6932..f909235e6 100644 --- a/coreblocks/core.py +++ b/coreblocks/core.py @@ -161,7 +161,7 @@ def elaborate(self, platform): ) # push all registers to FreeRF at reset. r0 should be skipped, stop when counter overflows to 0 - free_rf_reg = Signal(self.gen_params.phys_regs_bits, reset=1) + free_rf_reg = Signal(self.gen_params.phys_regs_bits, init=1) with Transaction(name="InitFreeRFFifo").body(m, request=(free_rf_reg.bool())): free_rf_fifo.write(m, free_rf_reg) m.d.sync += free_rf_reg.eq(free_rf_reg + 1) diff --git a/coreblocks/core_structs/rob.py b/coreblocks/core_structs/rob.py index 62d77bcdd..72a3b291d 100644 --- a/coreblocks/core_structs/rob.py +++ b/coreblocks/core_structs/rob.py @@ -1,5 +1,6 @@ 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 * from coreblocks.interface.layouts import ROBLayouts @@ -18,7 +19,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(width=layouts.data_layout.size, depth=2**self.params.rob_entries_bits) + self.data = memory.Memory(shape=layouts.data_layout.size, depth=2**self.params.rob_entries_bits, init=[]) self.get_indices = Method(o=layouts.get_indices, nonexclusive=True) self.perf_rob_wait_time = FIFOLatencyMeasurer( @@ -45,8 +46,9 @@ def elaborate(self, platform): peek_possible = start_idx != end_idx put_possible = (end_idx + 1)[0 : len(end_idx)] != start_idx - m.submodules.read_port = read_port = self.data.read_port() - m.submodules.write_port = write_port = self.data.write_port() + m.submodules.data = self.data + write_port = self.data.write_port() + read_port = self.data.read_port(transparent_for=[write_port]) m.d.comb += read_port.addr.eq(start_idx) diff --git a/coreblocks/frontend/fetch/fetch.py b/coreblocks/frontend/fetch/fetch.py index a53b506c8..21122199d 100644 --- a/coreblocks/frontend/fetch/fetch.py +++ b/coreblocks/frontend/fetch/fetch.py @@ -93,7 +93,7 @@ def elaborate(self, platform): def flush(): m.d.comb += flush_now.eq(1) - current_pc = Signal(self.gen_params.isa.xlen, reset=self.gen_params.start_pc) + current_pc = Signal(self.gen_params.isa.xlen, init=self.gen_params.start_pc) stalled_unsafe = Signal() stalled_exception = Signal() diff --git a/coreblocks/func_blocks/csr/csr.py b/coreblocks/func_blocks/csr/csr.py index 40cc1dd26..eb2664e24 100644 --- a/coreblocks/func_blocks/csr/csr.py +++ b/coreblocks/func_blocks/csr/csr.py @@ -129,7 +129,7 @@ def elaborate(self, platform): ) # Temporary, until privileged spec is implemented - priv_level = Signal(PrivilegeLevel, reset=PrivilegeLevel.MACHINE) + priv_level = Signal(PrivilegeLevel, init=PrivilegeLevel.MACHINE) exe_side_fx = Signal() diff --git a/coreblocks/func_blocks/fu/common/rs.py b/coreblocks/func_blocks/fu/common/rs.py index df8c7353b..16afaf9c2 100644 --- a/coreblocks/func_blocks/fu/common/rs.py +++ b/coreblocks/func_blocks/fu/common/rs.py @@ -1,3 +1,4 @@ +from abc import abstractmethod from collections.abc import Iterable from typing import Optional from amaranth import * @@ -59,6 +60,10 @@ def __init__( sample_width=self.rs_entries_bits + 1, ) + @abstractmethod + def elaborate(self, platform) -> TModule: + raise NotImplementedError + def _elaborate(self, m: TModule, selected_id: Value, select_possible: Value, take_vector: Value): m.submodules += [self.perf_rs_wait_time, self.perf_num_full] diff --git a/coreblocks/func_blocks/fu/division/long_division.py b/coreblocks/func_blocks/fu/division/long_division.py index efa140430..af439c950 100644 --- a/coreblocks/func_blocks/fu/division/long_division.py +++ b/coreblocks/func_blocks/fu/division/long_division.py @@ -144,7 +144,7 @@ def elaborate(self, platform): self.ipc, xlen, partial_remainder_count=self.partial_remainder_count ) - ready = Signal(1, reset=1) + ready = Signal(1, init=1) dividend = Signal(unsigned(xlen)) divisor = Signal(unsigned(xlen)) diff --git a/coreblocks/func_blocks/fu/unsigned_multiplication/common.py b/coreblocks/func_blocks/fu/unsigned_multiplication/common.py index 28c2cf977..013d22b0f 100644 --- a/coreblocks/func_blocks/fu/unsigned_multiplication/common.py +++ b/coreblocks/func_blocks/fu/unsigned_multiplication/common.py @@ -1,3 +1,4 @@ +from abc import abstractmethod from amaranth import * from coreblocks.params import GenParams @@ -35,6 +36,10 @@ def __init__(self, gen_params: GenParams, dsp_width: int = 32): self.issue = Method(i=layout.issue) self.accept = Method(o=layout.accept) + @abstractmethod + def elaborate(self, platform) -> TModule: + raise NotImplementedError() + class DSPMulUnit(Elaboratable): """ diff --git a/coreblocks/func_blocks/fu/unsigned_multiplication/pipelined.py b/coreblocks/func_blocks/fu/unsigned_multiplication/pipelined.py index 7fd4d8b9f..845b7e8e1 100644 --- a/coreblocks/func_blocks/fu/unsigned_multiplication/pipelined.py +++ b/coreblocks/func_blocks/fu/unsigned_multiplication/pipelined.py @@ -47,7 +47,7 @@ def __init__(self, dsp_width: int, dsp_number: int, n: int): self.ready = Signal() self.issue = Signal() - self.step = Signal(range(self.number_of_steps + 1), reset=self.number_of_steps) + self.step = Signal(range(self.number_of_steps + 1), init=self.number_of_steps) self.i1 = Signal(self.n_padding) self.i2 = Signal(self.n_padding) self.result = Signal(2 * n) diff --git a/coreblocks/func_blocks/fu/unsigned_multiplication/sequence.py b/coreblocks/func_blocks/fu/unsigned_multiplication/sequence.py index 41733027b..09648d6d7 100644 --- a/coreblocks/func_blocks/fu/unsigned_multiplication/sequence.py +++ b/coreblocks/func_blocks/fu/unsigned_multiplication/sequence.py @@ -42,7 +42,7 @@ def __init__(self, dsp: DSPMulUnit, n: int): self.i1 = Signal(unsigned(n)) self.i2 = Signal(unsigned(n)) self.result = Signal(unsigned(n * 2)) - self.confirm = Signal(reset=0) + self.confirm = Signal() self.reset = Signal() def elaborate(self, platform) -> TModule: @@ -135,7 +135,7 @@ def elaborate(self, platform): m.submodules.dsp = dsp = DSPMulUnit(self.dsp_width) m.submodules.multiplier = multiplier = RecursiveWithSingleDSPMul(dsp, self.gen_params.isa.xlen) - accepted = Signal(1, reset=1) + accepted = Signal(1, init=1) m.d.sync += multiplier.reset.eq(0) @def_method(m, self.issue, ready=accepted) diff --git a/coreblocks/func_blocks/fu/unsigned_multiplication/shift.py b/coreblocks/func_blocks/fu/unsigned_multiplication/shift.py index 77dbb19b2..5e8e1db94 100644 --- a/coreblocks/func_blocks/fu/unsigned_multiplication/shift.py +++ b/coreblocks/func_blocks/fu/unsigned_multiplication/shift.py @@ -22,7 +22,7 @@ def elaborate(self, platform): i1 = Signal(unsigned(self.gen_params.isa.xlen * 2)) i2 = Signal(unsigned(self.gen_params.isa.xlen)) - accepted = Signal(1, reset=1) + accepted = Signal(1, init=1) @def_method(m, self.issue, ready=accepted) def _(arg): diff --git a/coreblocks/params/instr.py b/coreblocks/params/instr.py index 9508bf42e..34b5aff2b 100644 --- a/coreblocks/params/instr.py +++ b/coreblocks/params/instr.py @@ -139,7 +139,6 @@ def encode(self) -> int: const = Const.cast(self.as_value()) return const.value # type: ignore - @ValueCastable.lowermethod def as_value(self) -> Value: parts: list[tuple[int, Value]] = [] diff --git a/coreblocks/peripherals/wishbone.py b/coreblocks/peripherals/wishbone.py index 8e52ae024..1d41dc56c 100644 --- a/coreblocks/peripherals/wishbone.py +++ b/coreblocks/peripherals/wishbone.py @@ -1,4 +1,5 @@ from amaranth import * +import amaranth.lib.memory as memory from amaranth.lib.wiring import PureInterface, Signature, In, Out, Component from functools import reduce from typing import Protocol, cast @@ -516,23 +517,24 @@ class WishboneMemorySlave(Component): def __init__(self, wb_params: WishboneParameters, **kwargs): super().__init__({"bus": In(WishboneSignature(wb_params))}) - if "width" not in kwargs: - kwargs["width"] = wb_params.data_width - if kwargs["width"] not in (8, 16, 32, 64): - raise RuntimeError("Memory width has to be one of: 8, 16, 32, 64") + if "shape" not in kwargs: + kwargs["shape"] = wb_params.data_width + if kwargs["shape"] not in (8, 16, 32, 64): + raise RuntimeError("Memory shape has to be one of: 8, 16, 32, 64") if "depth" not in kwargs: kwargs["depth"] = 2**wb_params.addr_width self.granularity = wb_params.granularity if self.granularity not in (8, 16, 32, 64): raise RuntimeError("Granularity has to be one of: 8, 16, 32, 64") - self.mem = Memory(**kwargs) + self.mem = memory.Memory(**kwargs) def elaborate(self, platform): m = TModule() - m.submodules.rdport = rdport = self.mem.read_port() - m.submodules.wrport = wrport = self.mem.write_port(granularity=self.granularity) + m.submodules.mem = self.mem + wrport = self.mem.write_port(granularity=self.granularity) + rdport = self.mem.read_port() with m.FSM(): with m.State("Start"): diff --git a/coreblocks/priv/csr/csr_instances.py b/coreblocks/priv/csr/csr_instances.py index 6c385f568..3fa8439e7 100644 --- a/coreblocks/priv/csr/csr_instances.py +++ b/coreblocks/priv/csr/csr_instances.py @@ -60,12 +60,12 @@ def _(): class MachineModeCSRRegisters(Elaboratable): def __init__(self, gen_params: GenParams): - self.mvendorid = CSRRegister(CSRAddress.MVENDORID, gen_params, reset=0) - self.marchid = CSRRegister(CSRAddress.MARCHID, gen_params, reset=gen_params.marchid) - self.mimpid = CSRRegister(CSRAddress.MIMPID, gen_params, reset=gen_params.mimpid) - self.mhartid = CSRRegister(CSRAddress.MHARTID, gen_params, reset=0) + self.mvendorid = CSRRegister(CSRAddress.MVENDORID, gen_params, init=0) + self.marchid = CSRRegister(CSRAddress.MARCHID, gen_params, init=gen_params.marchid) + self.mimpid = CSRRegister(CSRAddress.MIMPID, gen_params, init=gen_params.mimpid) + self.mhartid = CSRRegister(CSRAddress.MHARTID, gen_params, init=0) self.mscratch = CSRRegister(CSRAddress.MSCRATCH, gen_params) - self.mconfigptr = CSRRegister(CSRAddress.MCONFIGPTR, gen_params, reset=0) + self.mconfigptr = CSRRegister(CSRAddress.MCONFIGPTR, gen_params, init=0) self.mstatus = AliasedCSR(CSRAddress.MSTATUS, gen_params) diff --git a/coreblocks/priv/csr/csr_register.py b/coreblocks/priv/csr/csr_register.py index 99845e036..baa784d96 100644 --- a/coreblocks/priv/csr/csr_register.py +++ b/coreblocks/priv/csr/csr_register.py @@ -61,7 +61,7 @@ def __init__( *, width: Optional[int] = None, ro_bits: int = 0, - reset: int | Enum = 0, + init: int | Enum = 0, fu_write_priority: bool = True, fu_write_filtermap: Optional[Callable[[TModule, Value], tuple[ValueLike, ValueLike]]] = None, fu_read_map: Optional[Callable[[TModule, Value], ValueLike]] = None, @@ -83,7 +83,7 @@ def __init__( Note that this parameter is only required if there are some read-only bits in read-write register. Writes to read-only registers specified by upper 2 bits of CSR address set to `0b11` are discarded by `CSRUnit`. - reset: int | Enum + init: int | Enum Reset value of CSR. fu_write_priority: bool Priority of CSR instruction write over `write` method, if both are called at the same cycle. @@ -131,7 +131,7 @@ def __init__( self._fu_read = self.fu_read_map.method self._fu_write = self.fu_write_filter.method - self.value = Signal(self.width, reset=reset) + self.value = Signal(self.width, init=init) self.side_effects = Signal(StructLayout({"read": 1, "write": 1})) # append to global CSR list diff --git a/coreblocks/priv/traps/interrupt_controller.py b/coreblocks/priv/traps/interrupt_controller.py index 00996c681..8fa2db8db 100644 --- a/coreblocks/priv/traps/interrupt_controller.py +++ b/coreblocks/priv/traps/interrupt_controller.py @@ -66,7 +66,7 @@ def __init__(self, gen_params: GenParams): # MPIE bit - previous MIE - part of mstatus self.mstatus_mpie = CSRRegister(None, gen_params, width=1) # MPP bit - previous priv mode - part of mstatus - self.mstatus_mpp = CSRRegister(None, gen_params, width=2, ro_bits=0b11, reset=PrivilegeLevel.MACHINE) + self.mstatus_mpp = CSRRegister(None, gen_params, width=2, ro_bits=0b11, init=PrivilegeLevel.MACHINE) # TODO: filter xPP for only legal modes (when not read-only) mstatus = dm.get_dependency(GenericCSRRegistersKey()).m_mode.mstatus mstatus.add_field(3, self.mstatus_mie) diff --git a/docs/conf.py b/docs/conf.py index dc4becf6a..55c6f3ab6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ # Add any extenstions here. These could be both Sphinx or custom ones. extensions = [ "myst_parser", + "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx.ext.ifconfig", "sphinx.ext.extlinks", @@ -104,3 +105,14 @@ def setup(app): # Auto generate anchors for # - ### headers myst_heading_anchors = 3 + +# Compatibility with Amaranth docstrings +rst_prolog = """ +.. role:: py(code) + :language: python +""" + +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "amaranth": ("https://amaranth-lang.org/docs/amaranth/latest/", None), +} diff --git a/requirements.txt b/requirements.txt index 24ad24917..7d70b711d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ ./amaranth-stubs/ # can't use -e -- pyright doesn't see the stubs then :( -amaranth-yosys==0.35.0.0.post81 -git+https://github.com/amaranth-lang/amaranth@115954b4d957b4ba642ad056ab1670bf5d185fb6 +amaranth-yosys==0.40.0.0.post100 +git+https://github.com/amaranth-lang/amaranth@9bd536bbf96b07720d6e4a8709b30492af8ddd13 dataclasses-json==0.6.3 diff --git a/scripts/synthesize.py b/scripts/synthesize.py index 23db693ee..49afa1fff 100755 --- a/scripts/synthesize.py +++ b/scripts/synthesize.py @@ -6,6 +6,7 @@ import argparse from amaranth.build import Platform +from amaranth.build.res import PortGroup from amaranth import * from amaranth.lib.wiring import Component, Flow, Out, connect, flipped @@ -61,7 +62,7 @@ def elaborate(self, platform: Platform): m = Module() pins = platform.request(self.name, self.number) - assert isinstance(pins, Record) + assert isinstance(pins, PortGroup) for hier_name, member, v in self.interface.signature.flatten(self.interface): name = "__".join(str(x) for x in hier_name) diff --git a/test/backend/test_annoucement.py b/test/backend/test_annoucement.py index 698ab9d8d..e6fd56fa3 100644 --- a/test/backend/test_annoucement.py +++ b/test/backend/test_annoucement.py @@ -150,14 +150,14 @@ def test_one_out(self): self.fu_count = 1 self.initialize() with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.consumer) + sim.add_process(self.consumer) for i in range(self.fu_count): - sim.add_sync_process(self.generate_producer(i)) + sim.add_process(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_sync_process(self.consumer) + sim.add_process(self.consumer) for i in range(self.fu_count): - sim.add_sync_process(self.generate_producer(i)) + sim.add_process(self.generate_producer(i)) diff --git a/test/backend/test_retirement.py b/test/backend/test_retirement.py index 269cf4013..4dbfa57ab 100644 --- a/test/backend/test_retirement.py +++ b/test/backend/test_retirement.py @@ -142,14 +142,14 @@ def rat_process(self): wait_cycles += 1 if wait_cycles >= self.cycles + 10: assert False, "RAT entry was not updated" - yield + yield Tick() assert not self.submit_q assert not self.rf_free_q def precommit_process(self): yield from self.retc.precommit_adapter.call_init() while self.precommit_q: - yield + yield Tick() info = yield from self.retc.precommit_adapter.call_result() assert info is not None assert info["side_fx"] @@ -187,6 +187,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_sync_process(self.free_reg_process) - sim.add_sync_process(self.rat_process) - sim.add_sync_process(self.precommit_process) + sim.add_process(self.free_reg_process) + sim.add_process(self.rat_process) + sim.add_process(self.precommit_process) diff --git a/test/cache/test_icache.py b/test/cache/test_icache.py index b21258f6c..a52d75f35 100644 --- a/test/cache/test_icache.py +++ b/test/cache/test_icache.py @@ -3,7 +3,7 @@ import random from amaranth import Elaboratable, Module -from amaranth.sim import Passive, Settle +from amaranth.sim import Passive, Settle, Tick from amaranth.utils import exact_log2 from transactron.lib import AdapterTrans, Adapter @@ -107,9 +107,9 @@ def wishbone_slave(self): # Wishbone is addressing words, so we need to shift it a bit to get the real address. addr = (yield self.test_module.wb_ctrl.wb.adr) << exact_log2(self.cp.word_width_bytes) - yield + yield Tick() while random.random() < 0.5: - yield + yield Tick() err = 1 if addr in self.bad_addresses else 0 @@ -149,8 +149,8 @@ def refiller_process(self): def test(self): with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.wishbone_slave) - sim.add_sync_process(self.refiller_process) + sim.add_process(self.wishbone_slave) + sim.add_process(self.refiller_process) class ICacheBypassTestCircuit(Elaboratable): @@ -230,7 +230,7 @@ def wishbone_slave(self): addr = (yield self.m.wb_ctrl.wb.adr) << exact_log2(self.cp.word_width_bytes) while random.random() < 0.5: - yield + yield Tick() err = 1 if addr in self.bad_addrs else 0 @@ -248,7 +248,7 @@ def user_process(self): yield from self.m.issue_req.call(addr=req_addr) while random.random() < 0.5: - yield + yield Tick() ret = yield from self.m.accept_res.call() @@ -263,12 +263,12 @@ def user_process(self): assert ret["fetch_block"] == data while random.random() < 0.5: - yield + yield Tick() def test(self): with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.wishbone_slave) - sim.add_sync_process(self.user_process) + sim.add_process(self.wishbone_slave) + sim.add_process(self.user_process) class MockedCacheRefiller(Elaboratable, CacheRefillerInterface): @@ -421,7 +421,7 @@ def call_cache(self, addr: int): yield from self.send_req(addr) yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() def test_1_way(self): @@ -459,7 +459,7 @@ def cache_user_process(): assert len(self.refill_requests) == 0 with self.run_simulation(self.m) as sim: - sim.add_sync_process(cache_user_process) + sim.add_process(cache_user_process) def test_2_way(self): self.init_module(2, 4) @@ -477,7 +477,7 @@ def cache_process(): assert len(self.refill_requests) == 0 with self.run_simulation(self.m) as sim: - sim.add_sync_process(cache_process) + sim.add_process(cache_process) # Tests whether the cache is fully pipelined and the latency between requests and response is exactly one cycle. def test_pipeline(self): @@ -504,11 +504,11 @@ def cache_process(): assert (yield from self.m.issue_req.done()) # After a cycle the response should be ready - yield + yield Tick() yield from self.expect_resp() yield from self.m.issue_req.disable() - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(5) @@ -522,12 +522,12 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp() - yield + yield Tick() yield from self.expect_resp() yield from self.send_req(addr=0x0001000C) yield from self.expect_resp() - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(5) @@ -539,9 +539,9 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.expect_resp() - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(3) @@ -553,9 +553,9 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp() - yield + yield Tick() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(3) @@ -567,13 +567,13 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() with self.run_simulation(self.m) as sim: - sim.add_sync_process(cache_process) + sim.add_process(cache_process) def test_flush(self): self.init_module(2, 4) @@ -613,7 +613,7 @@ def cache_process(): yield from self.call_cache(0x00010000) self.expect_refill(0x00010000) - yield + yield Tick() # Try to execute issue_req and flush_cache methods at the same time yield from self.m.issue_req.call_init(addr=0x00010000) @@ -622,25 +622,25 @@ def cache_process(): yield Settle() assert not (yield from self.m.issue_req.done()) assert (yield from self.m.flush_cache.done()) - yield + yield Tick() yield from self.m.flush_cache.call_do() yield from self.m.issue_req.call_do() self.assert_resp((yield from self.m.accept_res.call())) self.expect_refill(0x00010000) - yield + yield Tick() # Schedule two requests and then flush yield from self.send_req(0x00000000 + self.cp.line_size_bytes) yield from self.send_req(0x00010000) yield from self.m.flush_cache.call_init() - yield + yield Tick() # We cannot flush until there are two pending requests assert not (yield from self.m.flush_cache.done()) - yield + yield Tick() yield from self.m.flush_cache.disable() - yield + yield Tick() # Accept the first response self.assert_resp((yield from self.m.accept_res.call())) @@ -656,7 +656,7 @@ def cache_process(): self.expect_refill(0x00010000) with self.run_simulation(self.m) as sim: - sim.add_sync_process(cache_process) + sim.add_process(cache_process) def test_errors(self): self.init_module(1, 4) @@ -684,7 +684,7 @@ def cache_process(): # Test how pipelining works with errors yield from self.m.accept_res.disable() - yield + yield Tick() # Schedule two requests, the first one causing an error yield from self.send_req(addr=0x00020000) @@ -693,9 +693,9 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(3) @@ -709,9 +709,9 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() yield from self.tick(3) @@ -723,11 +723,11 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.expect_resp(wait=True) - yield + yield Tick() yield from self.m.accept_res.disable() - yield + yield Tick() # The second request will cause an error yield from self.send_req(addr=0x00021004) @@ -738,7 +738,7 @@ def cache_process(): # Accept the first response yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() # Wait before accepting the second response yield from self.m.accept_res.disable() @@ -746,14 +746,14 @@ def cache_process(): yield from self.m.accept_res.enable() yield from self.expect_resp(wait=True) - yield + yield Tick() # This request should not cause an error yield from self.send_req(addr=0x00011000) yield from self.expect_resp(wait=True) with self.run_simulation(self.m) as sim: - sim.add_sync_process(cache_process) + sim.add_process(cache_process) def test_random(self): self.init_module(4, 8) @@ -780,19 +780,19 @@ def sender(): yield from self.send_req(random.randrange(0, max_addr, 4)) while random.random() < 0.5: - yield + yield Tick() def receiver(): for _ in range(iterations): while len(self.issued_requests) == 0: - yield + yield Tick() self.assert_resp((yield from self.m.accept_res.call())) while random.random() < 0.2: - yield + yield Tick() with self.run_simulation(self.m) as sim: - sim.add_sync_process(sender) - sim.add_sync_process(receiver) - sim.add_sync_process(refiller_ctrl) + sim.add_process(sender) + sim.add_process(receiver) + sim.add_process(refiller_ctrl) diff --git a/test/core_structs/test_rat.py b/test/core_structs/test_rat.py index 0d79d41d1..01809d677 100644 --- a/test/core_structs/test_rat.py +++ b/test/core_structs/test_rat.py @@ -44,7 +44,7 @@ def test_single(self): self.gen_input() with self.run_simulation(m) as sim: - sim.add_sync_process(self.do_rename) + sim.add_process(self.do_rename) class TestRetirementRegisterAliasTable(TestCaseWithSimulator): @@ -81,4 +81,4 @@ def test_single(self): self.gen_input() with self.run_simulation(m) as sim: - sim.add_sync_process(self.do_commit) + sim.add_process(self.do_commit) diff --git a/test/core_structs/test_reorder_buffer.py b/test/core_structs/test_reorder_buffer.py index c05cb0d8f..0589e7db1 100644 --- a/test/core_structs/test_reorder_buffer.py +++ b/test/core_structs/test_reorder_buffer.py @@ -1,4 +1,4 @@ -from amaranth.sim import Passive, Settle +from amaranth.sim import Passive, Settle, Tick from transactron.testing import TestCaseWithSimulator, SimpleTestCircuit @@ -14,7 +14,7 @@ class TestReorderBuffer(TestCaseWithSimulator): def gen_input(self): for _ in range(self.test_steps): while self.regs_left_queue.empty(): - yield + yield Tick() while self.rand.random() < 0.5: yield # to slow down puts @@ -31,7 +31,7 @@ def do_updates(self): while self.rand.random() < 0.5: yield # to slow down execution if len(self.to_execute_list) == 0: - yield + yield Tick() else: idx = self.rand.randint(0, len(self.to_execute_list) - 1) rob_id, executed = self.to_execute_list.pop(idx) @@ -43,7 +43,7 @@ def do_retire(self): while True: if self.retire_queue.empty(): self.m.retire.enable() - yield + yield Tick() is_ready = yield self.m.retire.adapter.done assert is_ready == 0 # transaction should not be ready if there is nothing to retire else: @@ -82,9 +82,9 @@ def test_single(self): self.log_regs = self.gen_params.isa.reg_cnt with self.run_simulation(m) as sim: - sim.add_sync_process(self.gen_input) - sim.add_sync_process(self.do_updates) - sim.add_sync_process(self.do_retire) + sim.add_process(self.gen_input) + sim.add_process(self.do_updates) + sim.add_process(self.do_retire) class TestFullDoneCase(TestCaseWithSimulator): @@ -97,7 +97,7 @@ def gen_input(self): def do_single_update(self): while len(self.to_execute_list) == 0: - yield + yield Tick() rob_id = self.to_execute_list.pop(0) yield from self.m.mark_done.call(rob_id) @@ -113,7 +113,7 @@ def do_retire(self): yield from self.m.retire.call() yield from self.m.retire.enable() - yield + yield Tick() res = yield self.m.retire.adapter.done assert res == 0 # should be disabled, since we have read all elements @@ -130,5 +130,5 @@ def test_single(self): self.phys_regs = 2**self.gen_params.phys_regs_bits with self.run_simulation(m) as sim: - sim.add_sync_process(self.gen_input) - sim.add_sync_process(self.do_retire) + sim.add_process(self.gen_input) + sim.add_process(self.do_retire) diff --git a/test/frontend/test_decode_stage.py b/test/frontend/test_decode_stage.py index 77d8a7974..8cfcb95fd 100644 --- a/test/frontend/test_decode_stage.py +++ b/test/frontend/test_decode_stage.py @@ -79,4 +79,4 @@ def decode_test_proc(self): def test(self): with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.decode_test_proc) + sim.add_process(self.decode_test_proc) diff --git a/test/frontend/test_fetch.py b/test/frontend/test_fetch.py index deb53bfec..33b216752 100644 --- a/test/frontend/test_fetch.py +++ b/test/frontend/test_fetch.py @@ -6,7 +6,7 @@ import random from amaranth import Elaboratable, Module -from amaranth.sim import Passive +from amaranth.sim import Passive, Tick from coreblocks.interface.keys import FetchResumeKey from transactron.core import Method @@ -138,10 +138,10 @@ def cache_process(self): while True: while len(self.input_q) == 0: - yield + yield Tick() while random.random() < 0.5: - yield + yield Tick() req_addr = self.input_q.popleft() & ~(self.gen_params.fetch_block_bytes - 1) @@ -194,7 +194,7 @@ def fetch_out_check(self): # Empty the pipeline yield from self.clean_fifo.call_try() - yield + yield Tick() resume_pc = instr["next_pc"] if access_fault: @@ -209,8 +209,8 @@ def fetch_out_check(self): def run_sim(self): with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.cache_process) - sim.add_sync_process(self.fetch_out_check) + sim.add_process(self.cache_process) + sim.add_process(self.fetch_out_check) def test_simple_no_jumps(self): for _ in range(50): @@ -389,8 +389,8 @@ def test_random(self): self.gen_branch(offset, taken=random.randrange(2) == 0) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.cache_process) - sim.add_sync_process(self.fetch_out_check) + sim.add_process(self.cache_process) + sim.add_process(self.fetch_out_check) @dataclass(frozen=True) @@ -636,7 +636,7 @@ def proc(): self.assert_resp(ret, mispredicted=False) with self.run_simulation(self.m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) def test_preceding_redirection(self): instr_width = self.gen_params.min_instr_width_bytes @@ -735,7 +735,7 @@ def proc(): ) with self.run_simulation(self.m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) def test_mispredicted_cfi_type(self): instr_width = self.gen_params.min_instr_width_bytes @@ -781,7 +781,7 @@ def proc(): ) with self.run_simulation(self.m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) def test_mispredicted_cfi_target(self): instr_width = self.gen_params.min_instr_width_bytes @@ -825,4 +825,4 @@ def proc(): ) with self.run_simulation(self.m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) diff --git a/test/frontend/test_rvc.py b/test/frontend/test_rvc.py index ad86a1f3d..fb62b4ed2 100644 --- a/test/frontend/test_rvc.py +++ b/test/frontend/test_rvc.py @@ -1,6 +1,6 @@ from parameterized import parameterized_class -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from amaranth import * from coreblocks.frontend.decoder.rvc import InstrDecompress @@ -291,7 +291,7 @@ def process(): yield Settle() assert (yield self.m.instr_out) == (yield expected) - yield + yield Tick() with self.run_simulation(self.m) as sim: - sim.add_sync_process(process) + sim.add_process(process) diff --git a/test/func_blocks/csr/test_csr.py b/test/func_blocks/csr/test_csr.py index ec0f04008..82851b6d6 100644 --- a/test/func_blocks/csr/test_csr.py +++ b/test/func_blocks/csr/test_csr.py @@ -153,7 +153,7 @@ def test_randomized(self): self.dut = CSRUnitTestCircuit(self.gen_params, self.csr_count) with self.run_simulation(self.dut) as sim: - sim.add_sync_process(self.process_test) + sim.add_process(self.process_test) exception_csr_numbers = [ 0xC00, # read_only @@ -201,7 +201,7 @@ def test_exception(self): self.dut = CSRUnitTestCircuit(self.gen_params, 0, only_legal=False) with self.run_simulation(self.dut) as sim: - sim.add_sync_process(self.process_exception_test) + sim.add_process(self.process_exception_test) class TestCSRRegister(TestCaseWithSimulator): @@ -234,7 +234,7 @@ def randomized_process_test(self): fu_read = True yield from self.dut._fu_read.enable() - yield + yield Tick() yield Settle() exp_read_data = exp_write_data if fu_write or write else previous_data @@ -266,7 +266,7 @@ def test_randomized(self): self.dut = SimpleTestCircuit(CSRRegister(0, self.gen_params, ro_bits=self.ro_mask)) with self.run_simulation(self.dut) as sim: - sim.add_sync_process(self.randomized_process_test) + sim.add_process(self.randomized_process_test) def filtermap_process_test(self): prev_value = 0 @@ -318,7 +318,7 @@ def write_filtermap(m: TModule, v: Value): ) with self.run_simulation(self.dut) as sim: - sim.add_sync_process(self.filtermap_process_test) + sim.add_process(self.filtermap_process_test) def comb_process_test(self): yield from self.dut.read.enable() @@ -329,19 +329,19 @@ def comb_process_test(self): yield from self.dut._fu_write.call_do() assert (yield from self.dut.read_comb.call_result())["data"] == 0xFFFF assert (yield from self.dut._fu_read.call_result())["data"] == 0xAB - yield + yield Tick() assert (yield from self.dut.read.call_result())["data"] == 0xFFFB assert (yield from self.dut._fu_read.call_result())["data"] == 0xFFFB - yield + yield Tick() yield from self.dut._fu_write.call_init({"data": 0x0FFF}) yield from self.dut.write.call_init({"data": 0xAAAA}) yield from self.dut._fu_write.call_do() yield from self.dut.write.call_do() assert (yield from self.dut.read_comb.call_result()) == {"data": 0x0FFF, "read": 1, "written": 1} - yield + yield Tick() assert (yield from self.dut._fu_read.call_result())["data"] == 0xAAAA - yield + yield Tick() # single cycle yield from self.dut._fu_write.call_init({"data": 0x0BBB}) @@ -349,7 +349,7 @@ def comb_process_test(self): update_val = (yield from self.dut.read_comb.call_result())["data"] | 0xD000 yield from self.dut.write.call_init({"data": update_val}) yield from self.dut.write.call_do() - yield + yield Tick() assert (yield from self.dut._fu_read.call_result())["data"] == 0xDBBB def test_comb(self): @@ -357,7 +357,7 @@ def test_comb(self): random.seed(4326) - self.dut = SimpleTestCircuit(CSRRegister(None, gen_params, ro_bits=0b1111, fu_write_priority=False, reset=0xAB)) + self.dut = SimpleTestCircuit(CSRRegister(None, gen_params, ro_bits=0b1111, fu_write_priority=False, init=0xAB)) with self.run_simulation(self.dut) as sim: - sim.add_sync_process(self.comb_process_test) + sim.add_process(self.comb_process_test) diff --git a/test/func_blocks/fu/common/test_rs.py b/test/func_blocks/fu/common/test_rs.py index 7dae1aa47..222041a2a 100644 --- a/test/func_blocks/fu/common/test_rs.py +++ b/test/func_blocks/fu/common/test_rs.py @@ -2,7 +2,7 @@ from collections import deque from parameterized import parameterized_class -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from transactron.testing import TestCaseWithSimulator, get_outputs, SimpleTestCircuit @@ -75,10 +75,10 @@ def test_rs(self): self.finished = False with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.select_process) - sim.add_sync_process(self.insert_process) - sim.add_sync_process(self.update_process) - sim.add_sync_process(self.take_process) + sim.add_process(self.select_process) + sim.add_process(self.insert_process) + sim.add_process(self.update_process) + sim.add_process(self.take_process) def select_process(self): for k in range(len(self.data_list)): @@ -90,7 +90,7 @@ def insert_process(self): for data in self.data_list: yield Settle() # so that select_process can insert into the queue while not self.select_queue: - yield + yield Tick() yield Settle() rs_entry_id = self.select_queue.pop() yield from self.m.insert.call({"rs_entry_id": rs_entry_id, "rs_data": data}) @@ -103,7 +103,7 @@ def update_process(self): while not self.finished: yield Settle() # so that insert_process can insert into the set if not self.regs_to_update: - yield + yield Tick() continue reg_id = random.choice(list(self.regs_to_update)) self.regs_to_update.discard(reg_id) @@ -124,11 +124,11 @@ def take_process(self): for k in range(len(self.data_list)): yield Settle() while not (yield from self.m.get_ready_list[0].done()): - yield + yield Tick() ready_list = (yield from self.m.get_ready_list[0].call_result())["ready_list"] possible_ids = [i for i in range(2**self.rs_entries_bits) if ready_list & (1 << i)] if not possible_ids: - yield + yield Tick() continue rs_entry_id = random.choice(possible_ids) k = self.rs_entries[rs_entry_id] @@ -171,7 +171,7 @@ def test_insert(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # After each insert, entry should be marked as full @@ -216,7 +216,7 @@ def test_select(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # In the beginning the select method should be ready and id should be selectable @@ -279,7 +279,7 @@ def test_update(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # Insert all reacords @@ -370,7 +370,7 @@ def test_take(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # After each insert, entry should be marked as full @@ -469,7 +469,7 @@ def test_get_ready_list(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # After each insert, entry should be marked as full @@ -525,7 +525,7 @@ def test_two_get_ready_lists(self): self.check_list = create_check_list(self.rs_entries_bits, self.insert_list) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.simulation_process) + sim.add_process(self.simulation_process) def simulation_process(self): # After each insert, entry should be marked as full diff --git a/test/func_blocks/fu/functional_common.py b/test/func_blocks/fu/functional_common.py index 2310e6e0f..40e90816c 100644 --- a/test/func_blocks/fu/functional_common.py +++ b/test/func_blocks/fu/functional_common.py @@ -6,7 +6,7 @@ from typing import Generic, TypeVar from amaranth import Elaboratable, Signal -from amaranth.sim import Passive +from amaranth.sim import Passive, Tick from coreblocks.params import GenParams from coreblocks.params.configurations import test_core_config @@ -177,7 +177,7 @@ def pipeline_verifier(self): while True: assert (yield self.m.issue.adapter.iface.ready) assert (yield self.m.issue.adapter.en) == (yield self.m.issue.adapter.done) - yield + yield Tick() def run_standard_fu_test(self, pipeline_test=False): if pipeline_test: @@ -186,8 +186,8 @@ def run_standard_fu_test(self, pipeline_test=False): self.max_wait = 10 with self.run_simulation(self.circ) as sim: - sim.add_sync_process(self.producer) - sim.add_sync_process(self.consumer) - sim.add_sync_process(self.exception_consumer) + sim.add_process(self.producer) + sim.add_process(self.consumer) + sim.add_process(self.exception_consumer) if pipeline_test: - sim.add_sync_process(self.pipeline_verifier) + sim.add_process(self.pipeline_verifier) diff --git a/test/func_blocks/fu/test_pipelined_mul_unit.py b/test/func_blocks/fu/test_pipelined_mul_unit.py index b569a9105..1c955c6b4 100644 --- a/test/func_blocks/fu/test_pipelined_mul_unit.py +++ b/test/func_blocks/fu/test_pipelined_mul_unit.py @@ -80,5 +80,5 @@ def producer(): yield from self.m.issue.call(req) with self.run_simulation(self.m) as sim: - sim.add_sync_process(producer) - sim.add_sync_process(consumer) + sim.add_process(producer) + sim.add_process(consumer) diff --git a/test/func_blocks/fu/test_unsigned_mul_unit.py b/test/func_blocks/fu/test_unsigned_mul_unit.py index c8b1fccee..06321672c 100644 --- a/test/func_blocks/fu/test_unsigned_mul_unit.py +++ b/test/func_blocks/fu/test_unsigned_mul_unit.py @@ -83,5 +83,5 @@ def producer(): yield from self.random_wait(self.waiting_time) with self.run_simulation(self.m) as sim: - sim.add_sync_process(producer) - sim.add_sync_process(consumer) + sim.add_process(producer) + sim.add_process(consumer) diff --git a/test/func_blocks/lsu/test_dummylsu.py b/test/func_blocks/lsu/test_dummylsu.py index afeab7913..1d92a50c3 100644 --- a/test/func_blocks/lsu/test_dummylsu.py +++ b/test/func_blocks/lsu/test_dummylsu.py @@ -1,7 +1,7 @@ import random from collections import deque -from amaranth.sim import Settle, Passive +from amaranth.sim import Settle, Passive, Tick from transactron.lib import Adapter from transactron.utils import int_to_signed, signed_to_int @@ -222,7 +222,7 @@ def inserter(self): for i in range(self.tests_number): req = self.instr_queue.pop() while req["rob_id"] not in self.free_rob_id: - yield + yield Tick() self.free_rob_id.remove(req["rob_id"]) yield from self.test_module.issue.call(req) yield from self.random_wait(self.max_wait) @@ -248,9 +248,9 @@ def exception_consumer(arg): assert arg == self.exception_queue.pop() with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.wishbone_slave) - sim.add_sync_process(self.inserter) - sim.add_sync_process(self.consumer) + sim.add_process(self.wishbone_slave) + sim.add_process(self.inserter) + sim.add_process(self.consumer) class TestDummyLSULoadsCycles(TestCaseWithSimulator): @@ -305,7 +305,7 @@ def exception_consumer(arg): assert False with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.one_instr_test) + sim.add_process(self.one_instr_test) class TestDummyLSUStores(TestCaseWithSimulator): @@ -400,7 +400,7 @@ def precommiter(self): yield Passive() while True: while len(self.precommit_data) == 0: - yield + yield Tick() rob_id = self.precommit_data[-1] # precommit is called continously until instruction is retired yield from self.test_module.precommit.call(rob_id=rob_id, side_fx=1) @@ -410,10 +410,10 @@ def exception_consumer(arg): assert False with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.wishbone_slave) - sim.add_sync_process(self.inserter) - sim.add_sync_process(self.get_resulter) - sim.add_sync_process(self.precommiter) + sim.add_process(self.wishbone_slave) + sim.add_process(self.inserter) + sim.add_process(self.get_resulter) + sim.add_process(self.precommiter) class TestDummyLSUFence(TestCaseWithSimulator): @@ -448,4 +448,4 @@ def exception_consumer(arg): assert False with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.process) + sim.add_process(self.process) diff --git a/test/func_blocks/lsu/test_pma.py b/test/func_blocks/lsu/test_pma.py index a59404b8f..81cacde33 100644 --- a/test/func_blocks/lsu/test_pma.py +++ b/test/func_blocks/lsu/test_pma.py @@ -40,7 +40,7 @@ def test_pma_direct(self): self.test_module = PMAChecker(self.gen_params) with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.process) + sim.add_process(self.process) class PMAIndirectTestCircuit(Elaboratable): @@ -127,4 +127,4 @@ def exception_consumer(arg): assert False with self.run_simulation(self.test_module) as sim: - sim.add_sync_process(self.process) + sim.add_process(self.process) diff --git a/test/peripherals/test_axi_lite.py b/test/peripherals/test_axi_lite.py index 17fe44d23..514e85ea9 100644 --- a/test/peripherals/test_axi_lite.py +++ b/test/peripherals/test_axi_lite.py @@ -14,7 +14,7 @@ def slave_ra_ready(self, rdy=1): def slave_ra_wait(self): while not (yield self.axi_lite.read_address.valid): - yield + yield Tick() def slave_ra_verify(self, exp_addr, prot): assert (yield self.axi_lite.read_address.valid) @@ -23,14 +23,14 @@ def slave_ra_verify(self, exp_addr, prot): def slave_rd_wait(self): while not (yield self.axi_lite.read_data.rdy): - yield + yield Tick() def slave_rd_respond(self, data, resp=0): assert (yield self.axi_lite.read_data.rdy) yield self.axi_lite.read_data.data.eq(data) yield self.axi_lite.read_data.resp.eq(resp) yield self.axi_lite.read_data.valid.eq(1) - yield + yield Tick() yield self.axi_lite.read_data.valid.eq(0) def slave_wa_ready(self, rdy=1): @@ -38,7 +38,7 @@ def slave_wa_ready(self, rdy=1): def slave_wa_wait(self): while not (yield self.axi_lite.write_address.valid): - yield + yield Tick() def slave_wa_verify(self, exp_addr, prot): assert (yield self.axi_lite.write_address.valid) @@ -50,7 +50,7 @@ def slave_wd_ready(self, rdy=1): def slave_wd_wait(self): while not (yield self.axi_lite.write_data.valid): - yield + yield Tick() def slave_wd_verify(self, exp_data, strb): assert (yield self.axi_lite.write_data.valid) @@ -59,13 +59,13 @@ def slave_wd_verify(self, exp_data, strb): def slave_wr_wait(self): while not (yield self.axi_lite.write_response.rdy): - yield + yield Tick() def slave_wr_respond(self, resp=0): assert (yield self.axi_lite.write_response.rdy) yield self.axi_lite.write_response.resp.eq(resp) yield self.axi_lite.write_response.valid.eq(1) - yield + yield Tick() yield self.axi_lite.write_response.valid.eq(0) @@ -201,12 +201,12 @@ def slave_process(): yield from slave.slave_ra_wait() for _ in range(2): - yield + yield Tick() yield from slave.slave_ra_ready(1) yield from slave.slave_ra_verify(1, 1) # wait for next rising edge - yield - yield + yield Tick() + yield Tick() yield from slave.slave_ra_wait() yield from slave.slave_ra_verify(2, 1) @@ -247,7 +247,7 @@ def result_process(): assert resp["resp"] == 0 for _ in range(5): - yield + yield Tick() resp = yield from almt.read_data_response_adapter.call() assert resp["data"] == 3 @@ -258,6 +258,6 @@ def result_process(): assert resp["resp"] == 1 with self.run_simulation(almt) as sim: - sim.add_sync_process(master_process) - sim.add_sync_process(slave_process) - sim.add_sync_process(result_process) + sim.add_process(master_process) + sim.add_process(slave_process) + sim.add_process(result_process) diff --git a/test/peripherals/test_wishbone.py b/test/peripherals/test_wishbone.py index 794f467b0..68b04c6a0 100644 --- a/test/peripherals/test_wishbone.py +++ b/test/peripherals/test_wishbone.py @@ -32,7 +32,7 @@ def master_verify(self, exp_data=0): def slave_wait(self): while not ((yield self.wb.stb) and (yield self.wb.cyc)): - yield + yield Tick() def slave_verify(self, exp_addr, exp_data, exp_we, exp_sel=0): assert (yield self.wb.stb) and (yield self.wb.cyc) @@ -50,14 +50,14 @@ def slave_respond(self, data, ack=1, err=0, rty=0): yield self.wb.ack.eq(ack) yield self.wb.err.eq(err) yield self.wb.rty.eq(rty) - yield + yield Tick() yield self.wb.ack.eq(0) yield self.wb.err.eq(0) yield self.wb.rty.eq(0) def wait_ack(self): while not ((yield self.wb.stb) and (yield self.wb.cyc) and (yield self.wb.ack)): - yield + yield Tick() class TestWishboneMaster(TestCaseWithSimulator): @@ -80,8 +80,8 @@ def process(): yield from twbm.requestAdapter.call(addr=2, data=0, we=0, sel=1) # read request after delay - yield - yield + yield Tick() + yield Tick() yield from twbm.requestAdapter.call(addr=1, data=0, we=0, sel=1) # write request @@ -124,7 +124,7 @@ def slave(): yield # consecutive request yield from wwb.slave_verify(3, 5, 1, 0) yield from wwb.slave_respond(0) - yield + yield Tick() yield # consecutive request yield from wwb.slave_verify(2, 0, 0, 0) @@ -137,9 +137,9 @@ def slave(): yield from wwb.slave_respond(1, ack=1, err=1, rty=0) with self.run_simulation(twbm) as sim: - sim.add_sync_process(process) - sim.add_sync_process(result_process) - sim.add_sync_process(slave) + sim.add_process(process) + sim.add_process(result_process) + sim.add_process(slave) class TestWishboneMuxer(TestCaseWithSimulator): @@ -153,34 +153,34 @@ def process(): # check full communiaction yield from wb_master.master_set(2, 0, 1) yield mux.sselTGA.eq(0b0001) - yield + yield Tick() yield from slaves[0].slave_verify(2, 0, 1) assert not (yield slaves[1].wb.stb) yield from slaves[0].slave_respond(4) yield from wb_master.master_verify(4) yield from wb_master.master_release(release_cyc=0) - yield + yield Tick() # select without releasing cyc (only on stb) yield from wb_master.master_set(3, 0, 0) yield mux.sselTGA.eq(0b0010) - yield + yield Tick() assert not (yield slaves[0].wb.stb) yield from slaves[1].slave_verify(3, 0, 0) yield from slaves[1].slave_respond(5) yield from wb_master.master_verify(5) yield from wb_master.master_release() - yield + yield Tick() # normal selection yield from wb_master.master_set(6, 0, 0) yield mux.sselTGA.eq(0b1000) - yield + yield Tick() yield from slaves[3].slave_verify(6, 0, 0) yield from slaves[3].slave_respond(1) yield from wb_master.master_verify(1) with self.run_simulation(mux) as sim: - sim.add_sync_process(process) + sim.add_process(process) class TestWishboneAribiter(TestCaseWithSimulator): @@ -199,7 +199,7 @@ def process(): yield from masters[0].master_verify() assert not (yield masters[1].wb.ack) yield from masters[0].master_release() - yield + yield Tick() # check if bus is granted to next master if previous ends cycle yield from slave.slave_wait() @@ -208,7 +208,7 @@ def process(): yield from masters[1].master_verify() assert not (yield masters[0].wb.ack) yield from masters[1].master_release() - yield + yield Tick() # check round robin behaviour (2 masters requesting *2) yield from masters[0].master_set(1, 0, 0) @@ -219,7 +219,7 @@ def process(): yield from masters[0].master_verify(3) yield from masters[0].master_release() yield from masters[1].master_release() - yield + yield Tick() assert not (yield slave.wb.cyc) yield from masters[0].master_set(1, 0, 0) @@ -231,7 +231,7 @@ def process(): # check if releasing stb keeps grant yield from masters[1].master_release(release_cyc=0) - yield + yield Tick() yield from masters[1].master_set(3, 0, 0) yield from slave.slave_wait() yield from slave.slave_verify(3, 0, 0) @@ -239,7 +239,7 @@ def process(): yield from masters[1].master_verify() with self.run_simulation(arb) as sim: - sim.add_sync_process(process) + sim.add_process(process) class TestPipelinedWishboneMaster(TestCaseWithSimulator): @@ -268,7 +268,7 @@ def request_process(): def verify_process(): for _ in range(requests): while random.random() < 0.8: - yield + yield Tick() result = yield from pwbm.result.call() cres = res_queue.pop() @@ -300,12 +300,12 @@ def slave_process(): yield wbw.stall.eq(random.random() < 0.3) - yield + yield Tick() with self.run_simulation(pwbm) as sim: - sim.add_sync_process(request_process) - sim.add_sync_process(verify_process) - sim.add_sync_process(slave_process) + sim.add_process(request_process) + sim.add_process(verify_process) + sim.add_process(slave_process) class WishboneMemorySlaveCircuit(Elaboratable): @@ -333,7 +333,7 @@ def setup_method(self): self.addr_width = (self.memsize - 1).bit_length() # nearest log2 >= log2(memsize) self.wb_params = WishboneParameters(data_width=32, addr_width=self.addr_width, granularity=16) - self.m = WishboneMemorySlaveCircuit(wb_params=self.wb_params, mem_args={"depth": self.memsize}) + self.m = WishboneMemorySlaveCircuit(wb_params=self.wb_params, mem_args={"depth": self.memsize, "init": []}) self.sel_width = self.wb_params.data_width // self.wb_params.granularity @@ -357,13 +357,13 @@ def request_process(): wr_queue.appendleft(req) while random.random() < 0.2: - yield + yield Tick() yield from self.m.request.call(req) def result_process(): for _ in range(self.iters): while random.random() < 0.2: - yield + yield Tick() res = yield from self.m.result.call() req = req_queue.pop() @@ -383,12 +383,12 @@ def write_process(): mem_state[req["addr"]] &= ~granularity_mask mem_state[req["addr"]] |= req["data"] & granularity_mask - yield + yield Tick() if req["we"]: - assert (yield self.m.mem_slave.mem[req["addr"]]) == mem_state[req["addr"]] + assert (yield Value.cast(self.m.mem_slave.mem.data[req["addr"]])) == mem_state[req["addr"]] with self.run_simulation(self.m, max_cycles=3000) as sim: - sim.add_sync_process(request_process) - sim.add_sync_process(result_process) - sim.add_sync_process(write_process) + sim.add_process(request_process) + sim.add_process(result_process) + sim.add_process(write_process) diff --git a/test/priv/traps/test_exception.py b/test/priv/traps/test_exception.py index d6d2a91bc..bdf342327 100644 --- a/test/priv/traps/test_exception.py +++ b/test/priv/traps/test_exception.py @@ -76,4 +76,4 @@ def process_rob_idx_mock(): return {"start": self.rob_id, "end": 0} with self.run_simulation(m) as sim: - sim.add_sync_process(process_test) + sim.add_process(process_test) diff --git a/test/regression/cocotb.py b/test/regression/cocotb.py index 444360d04..f877bc32e 100644 --- a/test/regression/cocotb.py +++ b/test/regression/cocotb.py @@ -153,9 +153,11 @@ def get_cocotb_handle(self, path_components: list[str]) -> ModifiableObject: # function instead of 'getattr' - this is required by cocotb. obj = obj._id(component, extended=False) except AttributeError: - # Try with escaped name + # Try with escaped or unescaped name if component[0] != "\\" and component[-1] != " ": obj = obj._id("\\" + component + " ", extended=False) + elif component[0] == "\\": + obj = obj._id(component[1:], extended=False) else: raise diff --git a/test/regression/cocotb/benchmark.Makefile b/test/regression/cocotb/benchmark.Makefile index cebf10693..5063df3a2 100644 --- a/test/regression/cocotb/benchmark.Makefile +++ b/test/regression/cocotb/benchmark.Makefile @@ -14,7 +14,7 @@ SIM_BUILD = build/benchmark # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) - EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST + EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST -Wno-LITENDIAN BUILD_ARGS += -j`nproc` endif diff --git a/test/regression/cocotb/signature.Makefile b/test/regression/cocotb/signature.Makefile index 29c318831..c00cff477 100644 --- a/test/regression/cocotb/signature.Makefile +++ b/test/regression/cocotb/signature.Makefile @@ -14,7 +14,7 @@ SIM_BUILD = build/signature # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) - EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST + EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST -Wno-LITENDIAN BUILD_ARGS += -j`nproc` endif diff --git a/test/regression/cocotb/test.Makefile b/test/regression/cocotb/test.Makefile index afeb10917..46e4a5bd8 100644 --- a/test/regression/cocotb/test.Makefile +++ b/test/regression/cocotb/test.Makefile @@ -14,7 +14,7 @@ SIM_BUILD = build/test # Yosys/Amaranth borkedness workaround ifeq ($(SIM),verilator) - EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST + EXTRA_ARGS += -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-UNSIGNED -Wno-CMPCONST -Wno-LITENDIAN BUILD_ARGS += -j`nproc` endif diff --git a/test/regression/pysim.py b/test/regression/pysim.py index e46db216d..a21b293fe 100644 --- a/test/regression/pysim.py +++ b/test/regression/pysim.py @@ -2,7 +2,7 @@ import os import logging -from amaranth.sim import Passive, Settle +from amaranth.sim import Passive, Settle, Tick from amaranth.utils import exact_log2 from amaranth import * @@ -83,7 +83,7 @@ def f(): rty = 1 for _ in range(delay): - yield + yield Tick() yield from wb_ctrl.slave_respond(resp_data, ack=ack, err=err, rty=rty) @@ -95,7 +95,7 @@ def _waiter(self, on_finish: Callable[[], TestGen[None]]): def f(): while self.running: self.cycle_cnt += 1 - yield + yield Tick() yield from on_finish() @@ -141,19 +141,23 @@ async def run(self, mem_model: CoreMemoryModel, timeout_cycles: int = 5000) -> S self.cycle_cnt = 0 sim = PysimSimulator(core, max_cycles=timeout_cycles, traces_file=self.traces_file) - sim.add_sync_process(self._wishbone_slave(mem_model, wb_instr_ctrl, is_instr_bus=True)) - sim.add_sync_process(self._wishbone_slave(mem_model, wb_data_ctrl, is_instr_bus=False)) + sim.add_process(self._wishbone_slave(mem_model, wb_instr_ctrl, is_instr_bus=True)) + sim.add_process(self._wishbone_slave(mem_model, wb_data_ctrl, is_instr_bus=False)) def on_error(): raise RuntimeError("Simulation finished due to an error") - sim.add_sync_process(make_logging_process(self.log_level, self.log_filter, on_error)) + sim.add_process(make_logging_process(self.log_level, self.log_filter, on_error)) + + # This enables logging in benchmarks. TODO: after unifying regression testing, remove. + logging.basicConfig() + logging.getLogger().setLevel(self.log_level) profile = None if "__TRANSACTRON_PROFILE" in os.environ: transaction_manager = DependencyContext.get().get_dependency(TransactionManagerKey()) profile = Profile() - sim.add_sync_process(profiler_process(transaction_manager, profile)) + sim.add_process(profiler_process(transaction_manager, profile)) metric_values: dict[str, dict[str, int]] = {} @@ -167,7 +171,7 @@ def on_sim_finish(): metric_name, reg_name ) - sim.add_sync_process(self._waiter(on_finish=on_sim_finish)) + sim.add_process(self._waiter(on_finish=on_sim_finish)) success = sim.run() self.pretty_dump_metrics(metric_values) diff --git a/test/scheduler/test_rs_selection.py b/test/scheduler/test_rs_selection.py index 8fb6a47a8..d00ac64f3 100644 --- a/test/scheduler/test_rs_selection.py +++ b/test/scheduler/test_rs_selection.py @@ -135,10 +135,10 @@ def test_base_functionality(self): """ with self.run_simulation(self.m, max_cycles=1500) as sim: - sim.add_sync_process(self.create_instr_input_process(100, _rs1_optypes.union(_rs2_optypes))) - sim.add_sync_process(self.create_rs_alloc_process(self.m.rs1_alloc, rs_id=0, rs_optypes=_rs1_optypes)) - sim.add_sync_process(self.create_rs_alloc_process(self.m.rs2_alloc, rs_id=1, rs_optypes=_rs2_optypes)) - sim.add_sync_process(self.create_output_process(100)) + sim.add_process(self.create_instr_input_process(100, _rs1_optypes.union(_rs2_optypes))) + sim.add_process(self.create_rs_alloc_process(self.m.rs1_alloc, rs_id=0, rs_optypes=_rs1_optypes)) + sim.add_process(self.create_rs_alloc_process(self.m.rs2_alloc, rs_id=1, rs_optypes=_rs2_optypes)) + sim.add_process(self.create_output_process(100)) def test_only_rs1(self): """ @@ -147,9 +147,9 @@ def test_only_rs1(self): """ with self.run_simulation(self.m, max_cycles=1500) as sim: - sim.add_sync_process(self.create_instr_input_process(100, _rs1_optypes.intersection(_rs2_optypes))) - sim.add_sync_process(self.create_rs_alloc_process(self.m.rs1_alloc, rs_id=0, rs_optypes=_rs1_optypes)) - sim.add_sync_process(self.create_output_process(100)) + sim.add_process(self.create_instr_input_process(100, _rs1_optypes.intersection(_rs2_optypes))) + sim.add_process(self.create_rs_alloc_process(self.m.rs1_alloc, rs_id=0, rs_optypes=_rs1_optypes)) + sim.add_process(self.create_output_process(100)) def test_only_rs2(self): """ @@ -158,9 +158,9 @@ def test_only_rs2(self): """ with self.run_simulation(self.m, max_cycles=1500) as sim: - sim.add_sync_process(self.create_instr_input_process(100, _rs1_optypes.intersection(_rs2_optypes))) - sim.add_sync_process(self.create_rs_alloc_process(self.m.rs2_alloc, rs_id=1, rs_optypes=_rs2_optypes)) - sim.add_sync_process(self.create_output_process(100)) + sim.add_process(self.create_instr_input_process(100, _rs1_optypes.intersection(_rs2_optypes))) + sim.add_process(self.create_rs_alloc_process(self.m.rs2_alloc, rs_id=1, rs_optypes=_rs2_optypes)) + sim.add_process(self.create_output_process(100)) def test_delays(self): """ @@ -169,11 +169,11 @@ def test_delays(self): """ with self.run_simulation(self.m, max_cycles=5000) as sim: - sim.add_sync_process(self.create_instr_input_process(300, _rs1_optypes.union(_rs2_optypes), random_wait=4)) - sim.add_sync_process( + sim.add_process(self.create_instr_input_process(300, _rs1_optypes.union(_rs2_optypes), random_wait=4)) + sim.add_process( self.create_rs_alloc_process(self.m.rs1_alloc, rs_id=0, rs_optypes=_rs1_optypes, random_wait=12) ) - sim.add_sync_process( + sim.add_process( self.create_rs_alloc_process(self.m.rs2_alloc, rs_id=1, rs_optypes=_rs2_optypes, random_wait=12) ) - sim.add_sync_process(self.create_output_process(300, random_wait=12)) + sim.add_process(self.create_output_process(300, random_wait=12)) diff --git a/test/scheduler/test_scheduler.py b/test/scheduler/test_scheduler.py index 461a26d82..293ce201f 100644 --- a/test/scheduler/test_scheduler.py +++ b/test/scheduler/test_scheduler.py @@ -4,7 +4,7 @@ from typing import Callable, Optional, Iterable from amaranth import * from amaranth.lib.data import View -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from parameterized import parameterized_class from coreblocks.interface.keys import CoreStateKey from coreblocks.interface.layouts import ROBLayouts, RetirementLayouts @@ -173,7 +173,7 @@ def queue_gather(self, queues: Iterable[deque]): return None else: # if no element available, wait and retry on the next clock cycle - yield + yield Tick() # merge queue element with all previous ones (dict merge) item = item | partial_item @@ -269,7 +269,11 @@ def queue_process(): def make_output_process(self, io: TestbenchIO, output_queues: Iterable[deque]): def check(got, expected): rl_dst = yield View( - self.gen_params.get(ROBLayouts).data_layout, self.m.rob.data[got["rs_data"]["rob_id"]] + self.gen_params.get(ROBLayouts).data_layout, + C( + (yield Value.cast(self.m.rob.data.data[got["rs_data"]["rob_id"]])), + self.gen_params.get(ROBLayouts).data_layout.size, + ), ).rl_dst s1 = self.rf_state[expected["rp_s1"]] s2 = self.rf_state[expected["rp_s2"]] @@ -379,12 +383,10 @@ def core_state_mock(): with self.run_simulation(self.m, max_cycles=1500) as sim: for i in range(self.rs_count): - sim.add_sync_process( + sim.add_process( self.make_output_process(io=self.m.rs_insert[i], output_queues=[self.expected_rs_entry_queue[i]]) ) - sim.add_sync_process(rs_alloc_process(self.m.rs_alloc[i], i)) - sim.add_sync_process( - self.make_queue_process(io=self.m.rob_done, input_queues=[self.free_ROB_entries_queue]) - ) - sim.add_sync_process(self.make_queue_process(io=self.m.free_rf_inp, input_queues=[self.free_regs_queue])) - sim.add_sync_process(instr_input_process) + sim.add_process(rs_alloc_process(self.m.rs_alloc[i], i)) + sim.add_process(self.make_queue_process(io=self.m.rob_done, input_queues=[self.free_ROB_entries_queue])) + sim.add_process(self.make_queue_process(io=self.m.free_rf_inp, input_queues=[self.free_regs_queue])) + sim.add_process(instr_input_process) diff --git a/test/scheduler/test_wakeup_select.py b/test/scheduler/test_wakeup_select.py index ae6275872..b51af3cd3 100644 --- a/test/scheduler/test_wakeup_select.py +++ b/test/scheduler/test_wakeup_select.py @@ -1,7 +1,7 @@ from typing import Optional, cast from amaranth import * from amaranth.lib.data import StructLayout -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from collections import deque from enum import Enum @@ -112,10 +112,10 @@ def process(self): if issued is not None: assert issued == self.taken.popleft() issued_count += 1 - yield + yield Tick() assert inserted_count != 0 assert inserted_count == issued_count def test(self): with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.process) + sim.add_process(self.process) diff --git a/test/test_core.py b/test/test_core.py index e988b1437..883cc4d42 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1,6 +1,6 @@ from amaranth import * from amaranth.lib.wiring import connect -from amaranth.sim import Passive +from amaranth.sim import Passive, Tick from transactron.utils import align_to_power_of_two @@ -30,10 +30,10 @@ def elaborate(self, platform): # Align the size of the memory to the length of a cache line. instr_mem_depth = align_to_power_of_two(len(self.instr_mem), self.gen_params.icache_params.line_bytes_log) self.wb_mem_slave = WishboneMemorySlave( - wb_params=self.gen_params.wb_params, width=32, depth=instr_mem_depth, init=self.instr_mem + wb_params=self.gen_params.wb_params, shape=32, depth=instr_mem_depth, init=self.instr_mem ) self.wb_mem_slave_data = WishboneMemorySlave( - wb_params=self.gen_params.wb_params, width=32, depth=len(self.data_mem), init=self.data_mem + wb_params=self.gen_params.wb_params, shape=32, depth=len(self.data_mem), init=self.data_mem ) self.core = Core(gen_params=self.gen_params) @@ -146,7 +146,7 @@ class TestCoreBasicAsm(TestCoreAsmSourceBase): def run_and_check(self): for _ in range(self.cycle_count): - yield + yield Tick() for reg_id, val in self.expected_regvals.items(): assert (yield from self.get_arch_reg_val(reg_id)) == val @@ -158,7 +158,7 @@ def test_asm_source(self): self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src["text"], data_mem=bin_src["data"]) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.run_and_check) + sim.add_process(self.run_and_check) # test interrupts with varying triggering frequency (parametrizable amount of cycles between @@ -204,14 +204,14 @@ def clear_level_interrupt_procsess(self): yield Passive() while True: while (yield self.m.core.csr_generic.csr_coreblocks_test.value) == 0: - yield + yield Tick() if (yield self.m.core.csr_generic.csr_coreblocks_test.value) == 2: assert False, "`fail` called" yield self.m.core.csr_generic.csr_coreblocks_test.value.eq(0) yield self.m.interrupt_level.eq(0) - yield + yield Tick() def run_with_interrupt_process(self): main_cycles = 0 @@ -220,7 +220,7 @@ def run_with_interrupt_process(self): # wait for interrupt enable while (yield self.m.core.interrupt_controller.mstatus_mie.value) == 0: - yield + yield Tick() def do_interrupt(): count = 0 @@ -232,7 +232,7 @@ def do_interrupt(): if (mie != 0b11 or trig & 2) and (yield self.m.interrupt_level) == 0 and not self.edge_only: yield self.m.interrupt_level.eq(1) count += 1 - yield + yield Tick() yield self.m.interrupt_edge.eq(0) return count @@ -248,28 +248,28 @@ def do_interrupt(): # wait for the interrupt to get registered while (yield self.m.core.interrupt_controller.mstatus_mie.value) == 1: - yield + yield Tick() # trigger interrupt during execution of ISR handler (blocked-pending) with some chance early_interrupt = random.random() < 0.4 if early_interrupt: # wait until interrupts are cleared, so it won't be missed while (yield self.m.core.interrupt_controller.mip.value) != 0: - yield + yield Tick() assert (yield from self.get_arch_reg_val(30)) == int_count int_count += yield from do_interrupt() else: while (yield self.m.core.interrupt_controller.mip.value) != 0: - yield + yield Tick() assert (yield from self.get_arch_reg_val(30)) == int_count handler_count += 1 # wait until ISR returns while (yield self.m.core.interrupt_controller.mstatus_mie.value) == 0: - yield + yield Tick() assert (yield from self.get_arch_reg_val(30)) == int_count assert (yield from self.get_arch_reg_val(27)) == handler_count @@ -283,5 +283,5 @@ def test_interrupted_prog(self): bin_src["data"][self.reg_init_mem_offset // 4 + reg_id] = val self.m = CoreTestElaboratable(self.gen_params, instr_mem=bin_src["text"], data_mem=bin_src["data"]) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.run_with_interrupt_process) - sim.add_sync_process(self.clear_level_interrupt_procsess) + sim.add_process(self.run_with_interrupt_process) + sim.add_process(self.clear_level_interrupt_procsess) diff --git a/test/transactron/core/test_transactions.py b/test/transactron/core/test_transactions.py index 5d68b7708..46ef5f6d7 100644 --- a/test/transactron/core/test_transactions.py +++ b/test/transactron/core/test_transactions.py @@ -1,3 +1,4 @@ +from abc import abstractmethod from unittest.case import TestCase import pytest from amaranth import * @@ -57,7 +58,7 @@ def count_test(self, sched, cnt): def sim_step(self, sched, request, expected_grant): yield sched.requests.eq(request) - yield + yield Tick() if request == 0: assert not (yield sched.valid) @@ -76,7 +77,7 @@ def process(): yield from self.sim_step(sched, 0, 0) with self.run_simulation(sched) as sim: - sim.add_sync_process(process) + sim.add_process(process) def test_multi(self): sched = Scheduler(4) @@ -100,7 +101,7 @@ def process(): yield from self.sim_step(sched, 0b0010, 0b0010) with self.run_simulation(sched) as sim: - sim.add_sync_process(process) + sim.add_process(process) class TransactionConflictTestCircuit(Elaboratable): @@ -136,7 +137,7 @@ def make_process( def process(): for i in src: while random.random() >= prob: - yield + yield Tick() tgt(i) r = yield from io.call(data=i) chk(r["data"]) @@ -192,9 +193,9 @@ def test_calls(self, name, prob1, prob2, probout): self.m = TransactionConflictTestCircuit(self.__class__.scheduler) with self.run_simulation(self.m, add_transaction_module=False) as sim: - sim.add_sync_process(self.make_in1_process(prob1)) - sim.add_sync_process(self.make_in2_process(prob2)) - sim.add_sync_process(self.make_out_process(probout)) + sim.add_process(self.make_in1_process(prob1)) + sim.add_process(self.make_in2_process(prob2)) + sim.add_process(self.make_out_process(probout)) assert not self.in_expected assert not self.out1_expected @@ -208,6 +209,10 @@ def __init__(self): self.t1 = Signal() self.t2 = Signal() + @abstractmethod + def elaborate(self, platform) -> TModule: + raise NotImplementedError + class PriorityTestCircuit(SchedulingTestCircuit): def __init__(self, priority: Priority, unsatisfiable=False): @@ -369,12 +374,12 @@ def process(): for r1, r2 in to_do: yield m.r1.eq(r1) yield m.r2.eq(r2) - yield + yield Tick() assert (yield m.t1) == r1 assert (yield m.t2) == r1 * r2 with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) class ScheduleBeforeTestCircuit(SchedulingTestCircuit): @@ -415,12 +420,12 @@ def process(): for r1, r2 in to_do: yield m.r1.eq(r1) yield m.r2.eq(r2) - yield + yield Tick() assert (yield m.t1) == r1 assert not (yield m.t2) with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) class SingleCallerTestCircuit(Elaboratable): diff --git a/test/transactron/lib/test_fifo.py b/test/transactron/lib/test_fifo.py index 1db7d44e8..39de8929a 100644 --- a/test/transactron/lib/test_fifo.py +++ b/test/transactron/lib/test_fifo.py @@ -1,5 +1,5 @@ from amaranth import * -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from transactron.lib import AdapterTrans, BasicFifo @@ -63,10 +63,10 @@ def source(): def target(): while not self.done or expq: if random.randint(0, 1): - yield + yield Tick() yield from fifoc.fifo_read.call_init() - yield + yield Tick() v = yield from fifoc.fifo_read.call_result() if v is not None: @@ -75,5 +75,5 @@ def target(): yield from fifoc.fifo_read.disable() with self.run_simulation(fifoc) as sim: - sim.add_sync_process(source) - sim.add_sync_process(target) + sim.add_process(source) + sim.add_process(target) diff --git a/test/transactron/lib/test_transaction_lib.py b/test/transactron/lib/test_transaction_lib.py index 2216e86c7..0b437b16b 100644 --- a/test/transactron/lib/test_transaction_lib.py +++ b/test/transactron/lib/test_transaction_lib.py @@ -3,7 +3,7 @@ import random from operator import and_ from functools import reduce -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from typing import Optional, TypeAlias from parameterized import parameterized from collections import deque @@ -56,8 +56,8 @@ def reader(): yield from self.random_wait(reader_rand) with self.run_simulation(m) as sim: - sim.add_sync_process(reader) - sim.add_sync_process(writer) + sim.add_process(reader) + sim.add_process(writer) class TestFIFO(TestFifoBase): @@ -92,7 +92,7 @@ def forward_check(x): yield Settle() assert (yield from m.read.call_result()) == {"data": x} assert (yield from m.write.call_result()) is not None - yield + yield Tick() def process(): # test forwarding behavior @@ -104,13 +104,13 @@ def process(): yield from m.write.call_init(data=42) yield Settle() assert (yield from m.write.call_result()) is not None - yield + yield Tick() # writes are not possible now yield from m.write.call_init(data=84) yield Settle() assert (yield from m.write.call_result()) is None - yield + yield Tick() # read from the overflow buffer, writes still blocked yield from m.read.enable() @@ -118,14 +118,14 @@ def process(): yield Settle() assert (yield from m.read.call_result()) == {"data": 42} assert (yield from m.write.call_result()) is None - yield + yield Tick() # forwarding now works again for x in range(4): yield from forward_check(x) with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) class TestPipe(TestFifoBase): @@ -193,9 +193,9 @@ def reader_resp(): max_cycles = test_count + 2 if pipeline_test else 100000 with self.run_simulation(m, max_cycles=max_cycles) as sim: - sim.add_sync_process(reader_req) - sim.add_sync_process(reader_resp) - sim.add_sync_process(writer) + sim.add_process(reader_req) + sim.add_process(reader_resp) + sim.add_process(writer) class TestAsyncMemoryBank(TestCaseWithSimulator): @@ -231,8 +231,8 @@ def reader(): yield from self.random_wait(reader_rand, min_cycle_cnt=1) with self.run_simulation(m) as sim: - sim.add_sync_process(reader) - sim.add_sync_process(writer) + sim.add_process(reader) + sim.add_process(writer) class ManyToOneConnectTransTestCircuit(Elaboratable): @@ -326,17 +326,17 @@ def test_one_out(self): self.count = 1 self.initialize() with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.consumer) + sim.add_process(self.consumer) for i in range(self.count): - sim.add_sync_process(self.generate_producer(i)) + sim.add_process(self.generate_producer(i)) def test_many_out(self): self.count = 4 self.initialize() with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.consumer) + sim.add_process(self.consumer) for i in range(self.count): - sim.add_sync_process(self.generate_producer(i)) + sim.add_process(self.generate_producer(i)) class MethodMapTestCircuit(Elaboratable): @@ -416,18 +416,18 @@ def target(self, data): def test_method_transformer(self): self.m = MethodMapTestCircuit(4, False, False) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.source) - sim.add_sync_process(self.target) + sim.add_process(self.source) + sim.add_process(self.target) def test_method_transformer_dicts(self): self.m = MethodMapTestCircuit(4, False, True) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.source) + sim.add_process(self.source) def test_method_transformer_with_methods(self): self.m = MethodMapTestCircuit(4, True, True) with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.source) + sim.add_process(self.source) class TestMethodFilter(TestCaseWithSimulator): @@ -461,7 +461,7 @@ def test_method_filter_with_methods(self, use_condition): ) m = ModuleConnector(test_circuit=self.tc, target=self.target, cmeth=self.cmeth) with self.run_simulation(m) as sim: - sim.add_sync_process(self.source) + sim.add_process(self.source) @parameterized.expand([(True,), (False,)]) def test_method_filter(self, use_condition): @@ -473,7 +473,7 @@ def condition(_, v): self.tc = SimpleTestCircuit(MethodFilter(self.target.adapter.iface, condition, use_condition=use_condition)) m = ModuleConnector(test_circuit=self.tc, target=self.target, cmeth=self.cmeth) with self.run_simulation(m) as sim: - sim.add_sync_process(self.source) + sim.add_process(self.source) class MethodProductTestCircuit(Elaboratable): @@ -530,13 +530,13 @@ def method_process(): for k in range(targets): method_en[k] = bool(i & (1 << k)) - yield + yield Tick() assert (yield from m.method.call_try(data=0)) is None # otherwise, the call succeeds for k in range(targets): method_en[k] = True - yield + yield Tick() data = random.randint(0, (1 << iosize) - 1) val = (yield from m.method.call(data=data))["data"] @@ -546,9 +546,9 @@ def method_process(): assert val == data with self.run_simulation(m) as sim: - sim.add_sync_process(method_process) + sim.add_process(method_process) for k in range(targets): - sim.add_sync_process(target_process(k)) + sim.add_process(target_process(k)) class TestSerializer(TestCaseWithSimulator): @@ -615,8 +615,8 @@ def f(): def test_serial(self): with self.run_simulation(self.m) as sim: for i in range(self.port_count): - sim.add_sync_process(self.requestor(i)) - sim.add_sync_process(self.responder(i)) + sim.add_process(self.requestor(i)) + sim.add_process(self.responder(i)) class TestMethodTryProduct(TestCaseWithSimulator): @@ -643,7 +643,7 @@ def method_process(): active_targets = sum(method_en) - yield + yield Tick() data = random.randint(0, (1 << iosize) - 1) val = yield from m.method.call(data=data) @@ -654,9 +654,9 @@ def method_process(): assert val == {} with self.run_simulation(m) as sim: - sim.add_sync_process(method_process) + sim.add_process(method_process) for k in range(targets): - sim.add_sync_process(target_process(k)) + sim.add_process(target_process(k)) class MethodTryProductTestCircuit(Elaboratable): @@ -758,4 +758,4 @@ def process(): assert selection in [c1, 2 * c2, 3 * c3] with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) diff --git a/test/transactron/test_adapter.py b/test/transactron/test_adapter.py index 9db3235c2..a5fa73264 100644 --- a/test/transactron/test_adapter.py +++ b/test/transactron/test_adapter.py @@ -59,4 +59,4 @@ def test_single(self): self.m = ModuleConnector(echo=self.echo, consumer=self.consumer) with self.run_simulation(self.m, max_cycles=100) as sim: - sim.add_sync_process(self.proc) + sim.add_process(self.proc) diff --git a/test/transactron/test_assign.py b/test/transactron/test_assign.py index dab0225bf..7398570fa 100644 --- a/test/transactron/test_assign.py +++ b/test/transactron/test_assign.py @@ -3,7 +3,7 @@ from amaranth import * from amaranth.lib import data from amaranth.lib.enum import Enum -from amaranth.hdl._ast import ArrayProxy, Slice +from amaranth.hdl._ast import ArrayProxy, SwitchValue, Slice from transactron.utils._typing import MethodLayout from transactron.utils import AssignType, assign @@ -143,11 +143,14 @@ def test_assign_a(self, name, layout1: MethodLayout, layout2: MethodLayout, atyp self.assertIs_AP(alist[0].rhs, self.extrr(rhs).a) def assertIs_AP(self, expr1, expr2): # noqa: N802 - if isinstance(expr1, ArrayProxy) and isinstance(expr2, ArrayProxy): + expr1 = Value.cast(expr1) + expr2 = Value.cast(expr2) + if isinstance(expr1, SwitchValue) and isinstance(expr2, SwitchValue): # new proxies are created on each index, structural equality is needed - self.assertIs(expr1.index, expr2.index) - assert len(expr1.elems) == len(expr2.elems) - for x, y in zip(expr1.elems, expr2.elems): + self.assertIs(expr1.test, expr2.test) + assert len(expr1.cases) == len(expr2.cases) + for (px, x), (py, y) in zip(expr1.cases, expr2.cases): + self.assertEqual(px, py) self.assertIs_AP(x, y) elif isinstance(expr1, Slice) and isinstance(expr2, Slice): self.assertIs_AP(expr1.value, expr2.value) diff --git a/test/transactron/test_connectors.py b/test/transactron/test_connectors.py index cb2e8324a..ac15a9f9d 100644 --- a/test/transactron/test_connectors.py +++ b/test/transactron/test_connectors.py @@ -1,7 +1,7 @@ import random from parameterized import parameterized_class -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from transactron.lib import StableSelectingNetwork from transactron.testing import TestCaseWithSimulator @@ -40,7 +40,7 @@ def process(): assert out == expected_output_prefix[i] assert (yield m.output_cnt) == total - yield + yield Tick() with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) diff --git a/test/transactron/test_methods.py b/test/transactron/test_methods.py index 40da46091..e03ae5f17 100644 --- a/test/transactron/test_methods.py +++ b/test/transactron/test_methods.py @@ -158,10 +158,10 @@ def test_process(): for k, method in enumerate(circuit.methods): val = random.randrange(0, 2**3) ret = yield from method.call(foo=val) - assert ret["foo"] == val + k % 2**3 + assert ret["foo"] == (val + k) % 2**3 with self.run_simulation(circuit) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) class AdapterCircuit(Elaboratable): @@ -398,7 +398,7 @@ def process(): assert out["data"] == n * 4 with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class ConditionalCallCircuit(Elaboratable): @@ -507,7 +507,7 @@ def process(): assert not (yield from circ.tb.done()) with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) @parameterized.expand( [ @@ -531,7 +531,7 @@ def process(): assert (yield from circ.tb.done()) with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class NonexclusiveMethodCircuit(Elaboratable): @@ -594,7 +594,7 @@ def process(): assert (yield from circ.t2.get_outputs()) == {"data": x} with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class TwoNonexclusiveConflictCircuit(Elaboratable): @@ -646,7 +646,7 @@ def process(): assert not (yield circ.running1) or not (yield circ.running2) with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class CustomCombinerMethodCircuit(Elaboratable): @@ -721,7 +721,7 @@ def process(): assert (yield from circ.t2.get_outputs()) == {"data": val1e ^ val2e} with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class DataDependentConditionalCircuit(Elaboratable): @@ -800,10 +800,10 @@ def process(): assert in1 != self.bad_number or not out_t1 assert in2 != self.bad_number or not out_t2 - yield + yield Tick() with self.run_simulation(self.circ, 100) as sim: - sim.add_sync_process(process) + sim.add_process(process) def test_random_arg(self): self.base_random(lambda arg: arg.data != self.bad_number) diff --git a/test/transactron/test_metrics.py b/test/transactron/test_metrics.py index 222706436..c7a0f0765 100644 --- a/test/transactron/test_metrics.py +++ b/test/transactron/test_metrics.py @@ -7,7 +7,7 @@ from parameterized import parameterized_class from amaranth import * -from amaranth.sim import Settle +from amaranth.sim import Settle, Tick from transactron.lib.metrics import * from transactron import * @@ -82,7 +82,7 @@ def test_process(): if call_now: yield from m.method.call() else: - yield + yield Tick() # Note that it takes one cycle to update the register value, so here # we are comparing the "previous" values. @@ -92,7 +92,7 @@ def test_process(): called_cnt += 1 with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) def test_counter_with_condition_in_method(self): m = SimpleTestCircuit(CounterWithConditionInMethodCircuit()) @@ -107,7 +107,7 @@ def test_process(): if call_now: yield from m.method.call(cond=condition) else: - yield + yield Tick() # Note that it takes one cycle to update the register value, so here # we are comparing the "previous" values. @@ -117,7 +117,7 @@ def test_process(): called_cnt += 1 with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) def test_counter_with_condition_without_method(self): m = CounterWithoutMethodCircuit() @@ -129,7 +129,7 @@ def test_process(): condition = random.randint(0, 1) yield m.cond.eq(condition) - yield + yield Tick() # Note that it takes one cycle to update the register value, so here # we are comparing the "previous" values. @@ -139,7 +139,7 @@ def test_process(): called_cnt += 1 with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) class OneHotEnum(IntFlag): @@ -193,14 +193,14 @@ def test_process(): yield m.cond.eq(1) yield m.tag.eq(tag) - yield + yield Tick() yield m.cond.eq(0) - yield + yield Tick() counts[tag] += 1 with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) def test_one_hot_enum(self): self.do_test_enum(OneHotEnum, [e.value for e in OneHotEnum]) @@ -283,9 +283,9 @@ def test_process(): buckets[i] += 1 break yield from m.method.call(data=value) - yield + yield Tick() else: - yield + yield Tick() histogram = m._dut.histogram # Skip the assertion if the min is still uninitialized @@ -306,7 +306,7 @@ def test_process(): assert total_count == (yield histogram.count.value) with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) class TestLatencyMeasurerBase(TestCaseWithSimulator): @@ -379,8 +379,8 @@ def consumer(): self.check_latencies(m, latencies) with self.run_simulation(m) as sim: - sim.add_sync_process(producer) - sim.add_sync_process(consumer) + sim.add_process(producer) + sim.add_process(consumer) @parameterized_class( @@ -417,7 +417,7 @@ def producer(): for _ in range(200): while not free_slots: - yield + yield Tick() continue yield Settle() @@ -437,7 +437,7 @@ def producer(): def consumer(): while not finish: while not used_slots: - yield + yield Tick() continue slot_id = random.choice(used_slots) @@ -458,8 +458,8 @@ def consumer(): self.check_latencies(m, latencies) with self.run_simulation(m) as sim: - sim.add_sync_process(producer) - sim.add_sync_process(consumer) + sim.add_process(producer) + sim.add_process(consumer) class MetricManagerTestCircuit(Elaboratable): @@ -533,7 +533,7 @@ def test_process(): rand = [random.randint(0, 1) for _ in range(3)] yield from m.incr_counters.call(counter1=rand[0], counter2=rand[1], counter3=rand[2]) - yield + yield Tick() for i in range(3): if rand[i] == 1: @@ -544,4 +544,4 @@ def test_process(): assert counters[2] == (yield metrics_manager.get_register_value("bar.baz.counter3", "count")) with self.run_simulation(m) as sim: - sim.add_sync_process(test_process) + sim.add_process(test_process) diff --git a/test/transactron/test_simultaneous.py b/test/transactron/test_simultaneous.py index eac74b84f..d0859301d 100644 --- a/test/transactron/test_simultaneous.py +++ b/test/transactron/test_simultaneous.py @@ -51,7 +51,7 @@ def process(): for k, n in enumerate(methods): enables[n] = bool(i & (1 << k)) yield from methods[n].set_enable(enables[n]) - yield + yield Tick() dones: dict[str, bool] = {} for n in methods: dones[n] = bool((yield from methods[n].done())) @@ -66,7 +66,7 @@ def process(): assert not any(dones.values()) with self.run_simulation(circ) as sim: - sim.add_sync_process(process) + sim.add_process(process) class UnsatisfiableTriangleTestCircuit(Elaboratable): @@ -169,4 +169,4 @@ def process(): assert result in possibles with self.run_simulation(m) as sim: - sim.add_sync_process(process) + sim.add_process(process) diff --git a/test/transactron/test_transactron_lib_storage.py b/test/transactron/test_transactron_lib_storage.py index 1f14922eb..404c14a2d 100644 --- a/test/transactron/test_transactron_lib_storage.py +++ b/test/transactron/test_transactron_lib_storage.py @@ -37,10 +37,10 @@ def f(): yield from self.multi_settle(4) elem = input_lst.pop() if isinstance(elem, OpNOP): - yield + yield Tick() continue if input_verification is not None and not input_verification(elem): - yield + yield Tick() continue response = yield from method.call(**elem) yield from self.multi_settle(settle_count) @@ -52,7 +52,7 @@ def f(): if state_change is not None: # It is standard python function by purpose to don't allow accessing circuit state_change(elem, response) - yield + yield Tick() return f @@ -129,7 +129,7 @@ def test_random(self, in_push, in_write, in_read, in_remove): with self.reinitialize_fixtures(): self.setUp() with self.run_simulation(self.circ, max_cycles=500) as sim: - sim.add_sync_process(self.push_process(in_push)) - sim.add_sync_process(self.read_process(in_read)) - sim.add_sync_process(self.write_process(in_write)) - sim.add_sync_process(self.remove_process(in_remove)) + sim.add_process(self.push_process(in_push)) + sim.add_process(self.read_process(in_read)) + sim.add_process(self.write_process(in_write)) + sim.add_process(self.remove_process(in_remove)) diff --git a/test/transactron/testing/test_infrastructure.py b/test/transactron/testing/test_infrastructure.py index 6df0e1002..cfd59ec87 100644 --- a/test/transactron/testing/test_infrastructure.py +++ b/test/transactron/testing/test_infrastructure.py @@ -24,8 +24,8 @@ def process(self): now = yield Now() assert k == now - yield + yield Tick() def test_random(self): with self.run_simulation(self.m, 50) as sim: - sim.add_sync_process(self.process) + sim.add_process(self.process) diff --git a/test/transactron/testing/test_log.py b/test/transactron/testing/test_log.py index d010d012e..6e6711d8e 100644 --- a/test/transactron/testing/test_log.py +++ b/test/transactron/testing/test_log.py @@ -1,5 +1,7 @@ import pytest +import re from amaranth import * +from amaranth.sim import Tick from transactron import * from transactron.testing import TestCaseWithSimulator @@ -70,51 +72,53 @@ def test_log(self, caplog): def proc(): for i in range(50): - yield + yield Tick() yield m.input.eq(i) with self.run_simulation(m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) - assert ( - "WARNING test_logger:logging.py:83 [test/transactron/testing/test_log.py:22] " - + "Log triggered under Amaranth If value+3=0x2d" - in caplog.text + assert re.search( + r"WARNING test_logger:logging\.py:\d+ \[test/transactron/testing/test_log\.py:\d+\] " + + r"Log triggered under Amaranth If value\+3=0x2d", + caplog.text, ) for i in range(0, 50, 2): - expected_msg = ( - "WARNING test_logger:logging.py:83 [test/transactron/testing/test_log.py:24] " - + f"Input is even! input={i}, counter={i + 2}" + assert re.search( + r"WARNING test_logger:logging\.py:\d+ \[test/transactron/testing/test_log\.py:\d+\] " + + f"Input is even! input={i}, counter={i + 1}", + caplog.text, ) - assert expected_msg in caplog.text def test_error_log(self, caplog): m = ErrorLogTest() def proc(): - yield + yield Tick() yield m.input.eq(1) with pytest.raises(AssertionError): with self.run_simulation(m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) - extected_out = ( - "ERROR test_logger:logging.py:83 [test/transactron/testing/test_log.py:41] " - + "Input is different than output! input=0x1 output=0x0" + assert re.search( + r"ERROR test_logger:logging\.py:\d+ \[test/transactron/testing/test_log\.py:\d+\] " + + "Input is different than output! input=0x1 output=0x0", + caplog.text, ) - assert extected_out in caplog.text def test_assertion(self, caplog): m = AssertionTest() def proc(): - yield + yield Tick() yield m.input.eq(1) with pytest.raises(AssertionError): with self.run_simulation(m) as sim: - sim.add_sync_process(proc) + sim.add_process(proc) - extected_out = "ERROR test_logger:logging.py:83 [test/transactron/testing/test_log.py:62] Output differs" - assert extected_out in caplog.text + assert re.search( + r"ERROR test_logger:logging\.py:\d+ \[test/transactron/testing/test_log\.py:\d+\] Output differs", + caplog.text, + ) diff --git a/test/transactron/testing/test_validate_arguments.py b/test/transactron/testing/test_validate_arguments.py index d4b793880..18066ff5d 100644 --- a/test/transactron/testing/test_validate_arguments.py +++ b/test/transactron/testing/test_validate_arguments.py @@ -54,6 +54,6 @@ def test_validate_arguments(self): self.m = ValidateArgumentsTestCircuit() self.accepted_val = 0 with self.run_simulation(self.m) as sim: - sim.add_sync_process(self.changer) - sim.add_sync_process(self.control_caller(self.m.caller1, self.m.method)) - sim.add_sync_process(self.control_caller(self.m.caller2, self.m.method)) + sim.add_process(self.changer) + sim.add_process(self.control_caller(self.m.caller1, self.m.method)) + sim.add_process(self.control_caller(self.m.caller2, self.m.method)) diff --git a/transactron/core/manager.py b/transactron/core/manager.py index a6ca787c2..cfbc6b17d 100644 --- a/transactron/core/manager.py +++ b/transactron/core/manager.py @@ -6,6 +6,8 @@ from amaranth.lib.wiring import Component, connect, flipped from itertools import chain, filterfalse, product +from amaranth_types import AbstractComponent + from transactron.utils import * from transactron.utils.transactron_helpers import _graph_ccs from transactron.graph import OwnershipGraph, Direction @@ -506,7 +508,7 @@ class TransactionComponent(TransactionModule, Component): def __init__( self, - component: Component, + component: AbstractComponent, dependency_manager: Optional[DependencyManager] = None, transaction_manager: Optional[TransactionManager] = None, ): diff --git a/transactron/core/tmodule.py b/transactron/core/tmodule.py index a9ee030b1..d4276dce7 100644 --- a/transactron/core/tmodule.py +++ b/transactron/core/tmodule.py @@ -242,9 +242,9 @@ def Default(self): # noqa: N802 yield @contextmanager - def FSM(self, reset: Optional[str] = None, domain: str = "sync", name: str = "fsm"): # noqa: N802 + def FSM(self, init: Optional[str] = None, domain: str = "sync", name: str = "fsm"): # noqa: N802 old_fsm = self.fsm - with self.main_module.FSM(reset, domain, name) as fsm: + with self.main_module.FSM(init, domain, name) as fsm: self.fsm = fsm with self.path_builder.enter(EnterType.PUSH): yield fsm diff --git a/transactron/graph.py b/transactron/graph.py index 024e9bb0b..709ba8724 100644 --- a/transactron/graph.py +++ b/transactron/graph.py @@ -58,7 +58,7 @@ def remember(self, owner: Elaboratable) -> int: self.remember_field(owner_id, field, obj) if isinstance(owner, Fragment): assert isinstance(owner, TracingFragment) - for obj, field in owner.subfragments: + for obj, field, _ in owner.subfragments: self.remember_field(owner_id, field, obj) try: owner = owner._elaborated # type: ignore diff --git a/transactron/lib/adapters.py b/transactron/lib/adapters.py index 611ef4fd9..81816b3c4 100644 --- a/transactron/lib/adapters.py +++ b/transactron/lib/adapters.py @@ -1,3 +1,4 @@ +from abc import abstractmethod from typing import Optional from amaranth import * from amaranth.lib.wiring import Component, In, Out @@ -27,6 +28,10 @@ def __init__(self, iface: Method, layout_in: StructLayout, layout_out: StructLay def debug_signals(self) -> SignalBundle: return [self.en, self.done, self.data_in, self.data_out] + @abstractmethod + def elaborate(self, platform) -> TModule: + raise NotImplementedError() + class AdapterTrans(AdapterBase): """Adapter transaction. diff --git a/transactron/lib/fifo.py b/transactron/lib/fifo.py index 5850cbb78..f9d43c30f 100644 --- a/transactron/lib/fifo.py +++ b/transactron/lib/fifo.py @@ -1,4 +1,5 @@ from amaranth import * +import amaranth.lib.memory as memory from transactron import Method, def_method, Priority, TModule from transactron.utils._typing import ValueLike, MethodLayout, SrcLoc, MethodStruct from transactron.utils.amaranth_ext import mod_incr @@ -48,7 +49,7 @@ def __init__(self, layout: MethodLayout, depth: int, *, src_loc: int | SrcLoc = self.clear = Method(src_loc=src_loc) self.head = Signal(from_method_layout(layout)) - self.buff = Memory(width=self.width, depth=self.depth) + self.buff = memory.Memory(shape=self.width, depth=self.depth, init=[]) self.write_ready = Signal() self.read_ready = Signal() @@ -68,8 +69,9 @@ def elaborate(self, platform): next_read_idx = Signal.like(self.read_idx) m.d.comb += next_read_idx.eq(mod_incr(self.read_idx, self.depth)) - m.submodules.buff_rdport = self.buff_rdport = self.buff.read_port(domain="sync", transparent=True) - m.submodules.buff_wrport = self.buff_wrport = self.buff.write_port() + m.submodules.buff = self.buff + self.buff_wrport = self.buff.write_port() + self.buff_rdport = self.buff.read_port(domain="sync", transparent_for=[self.buff_wrport]) m.d.comb += self.read_ready.eq(self.level != 0) m.d.comb += self.write_ready.eq(self.level != self.depth) diff --git a/transactron/lib/metrics.py b/transactron/lib/metrics.py index 17921e619..78f5c5e53 100644 --- a/transactron/lib/metrics.py +++ b/transactron/lib/metrics.py @@ -85,7 +85,7 @@ class HwMetricRegister(MetricRegisterModel): Amaranth signal representing the value of the register. """ - def __init__(self, name: str, width_bits: int, description: str = "", reset: int = 0): + def __init__(self, name: str, width_bits: int, description: str = "", init: int = 0): """ Parameters ---------- @@ -96,12 +96,12 @@ def __init__(self, name: str, width_bits: int, description: str = "", reset: int The bit-width of the register. description: str A brief description of the metric's purpose. - reset: int + init: int The reset value of the register. """ super().__init__(name, description, width_bits) - self.value = Signal(width_bits, reset=reset, name=name) + self.value = Signal(width_bits, init=init, name=name) @dataclass(frozen=True) @@ -175,6 +175,10 @@ def add_registers(self, regs: list[HwMetricRegister]): def metrics_enabled(self) -> bool: return DependencyContext.get().get_dependency(HwMetricsEnabledKey()) + # To restore hashability lost by dataclass subclassing + def __hash__(self): + return object.__hash__(self) + class HwCounter(Elaboratable, HwMetric): """Hardware Counter @@ -399,7 +403,7 @@ def __init__( "min", self.sample_width, "the minimum of all observed values", - reset=(1 << self.sample_width) - 1, + init=(1 << self.sample_width) - 1, ) self.max = HwMetricRegister("max", self.sample_width, "the maximum of all observed values") diff --git a/transactron/lib/storage.py b/transactron/lib/storage.py index 0deadbfcf..b6b0e2a9f 100644 --- a/transactron/lib/storage.py +++ b/transactron/lib/storage.py @@ -1,5 +1,6 @@ from amaranth import * from amaranth.utils import * +import amaranth.lib.memory as memory from transactron.utils.transactron_helpers import from_method_layout, make_layout from ..core import * @@ -78,9 +79,9 @@ def __init__( def elaborate(self, platform) -> TModule: m = TModule() - mem = Memory(width=self.width, depth=self.elem_count) - m.submodules.read_port = read_port = mem.read_port(transparent=self.transparent) - m.submodules.write_port = write_port = mem.write_port() + m.submodules.mem = mem = memory.Memory(shape=self.width, depth=self.elem_count, init=[]) + write_port = mem.write_port() + read_port = mem.read_port(transparent_for=[write_port] if self.transparent else []) read_output_valid = Signal() overflow_valid = Signal() overflow_data = Signal(self.width) @@ -271,9 +272,10 @@ def __init__( def elaborate(self, platform) -> TModule: m = TModule() - mem = Memory(width=self.width, depth=self.elem_count) - m.submodules.read_port = read_port = mem.read_port(domain="comb") - m.submodules.write_port = write_port = mem.write_port() + mem = memory.Memory(shape=self.width, depth=self.elem_count, init=[]) + m.submodules.mem = mem + write_port = mem.write_port() + read_port = mem.read_port(domain="comb") @def_method(m, self.read) def _(addr): diff --git a/transactron/testing/gtkw_extension.py b/transactron/testing/gtkw_extension.py index 835886273..db407ac9d 100644 --- a/transactron/testing/gtkw_extension.py +++ b/transactron/testing/gtkw_extension.py @@ -2,22 +2,21 @@ from contextlib import contextmanager from amaranth.lib.data import View from amaranth.sim.pysim import _VCDWriter +from amaranth.sim import Tick from amaranth import * from transactron.utils import flatten_signals class _VCDWriterExt(_VCDWriter): - def __init__(self, fragment, *, vcd_file, gtkw_file, traces): - super().__init__( - fragment=fragment, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=list(flatten_signals(traces)) - ) + def __init__(self, design, *, vcd_file, gtkw_file, traces): + super().__init__(design=design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=list(flatten_signals(traces))) self._tree_traces = traces def close(self, timestamp): def save_signal(value: Value): for signal in value._rhs_signals(): # type: ignore - if signal in self.gtkw_names: - for name in self.gtkw_names[signal]: + if signal in self.gtkw_signal_names: + for name in self.gtkw_signal_names[signal]: self.gtkw_save.trace(name) def gtkw_traces(traces): @@ -61,10 +60,10 @@ def gtkw_traces(traces): @contextmanager def write_vcd_ext(engine, vcd_file, gtkw_file, traces): - vcd_writer = _VCDWriterExt(engine._fragment, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces) + vcd_writer = _VCDWriterExt(engine._design, vcd_file=vcd_file, gtkw_file=gtkw_file, traces=traces) try: engine._vcd_writers.append(vcd_writer) - yield + yield Tick() finally: vcd_writer.close(engine.now) engine._vcd_writers.remove(vcd_writer) diff --git a/transactron/testing/infrastructure.py b/transactron/testing/infrastructure.py index 69ff04160..861428fc3 100644 --- a/transactron/testing/infrastructure.py +++ b/transactron/testing/infrastructure.py @@ -4,6 +4,7 @@ import os import random import functools +import warnings from contextlib import contextmanager, nullcontext from typing import TypeVar, Generic, Type, TypeGuard, Any, Union, Callable, cast, TypeAlias, Optional from abc import ABC @@ -22,6 +23,7 @@ from transactron.core import TransactionModule from transactron.utils import ModuleConnector, HasElaborate, auto_debug_signals, HasDebugSignals + T = TypeVar("T") _T_nested_collection: TypeAlias = T | list["_T_nested_collection[T]"] | dict[str, "_T_nested_collection[T]"] @@ -138,10 +140,13 @@ def _wrapping_function(self): # call orginal test process and catch data yielded by it in `command` variable command = org_coroutine.send(response) # If process wait for new cycle - if command is None: - self.current_cycle += 1 + if command is None or isinstance(command, Tick): + command = command or Tick() + # TODO: use of other domains can mess up the counter! + if command.domain == "sync": + self.current_cycle += 1 # forward to amaranth - yield + yield command elif isinstance(command, Now): response = self.current_cycle # Pass everything else to amaranth simulator without modifications @@ -179,7 +184,7 @@ def __init__( # TODO: try to merge with Amaranth. if isinstance(extra_signals, Callable): extra_signals = extra_signals() - clocks = [d.clk for d in cast(Any, self)._fragment.domains.values()] + clocks = [d.clk for d in cast(Any, self)._design.fragment.domains.values()] self.ctx = write_vcd_ext( cast(Any, self)._engine, @@ -192,9 +197,9 @@ def __init__( self.deadline = clk_period * max_cycles - def add_sync_process(self, f: Callable[[], TestGen]): + def add_process(self, f: Callable[[], TestGen]): f_wrapped = SyncProcessWrapper(f) - super().add_sync_process(f_wrapped._wrapping_function) + super().add_process(f_wrapped._wrapping_function) def run(self) -> bool: with self.ctx: @@ -210,18 +215,18 @@ class TestCaseWithSimulator: def configure_dependency_context(self): self.dependency_manager = DependencyManager() with DependencyContext(self.dependency_manager): - yield + yield Tick() def add_class_mocks(self, sim: PysimSimulator) -> None: for key in dir(self): val = getattr(self, key) if hasattr(val, "_transactron_testing_process"): - sim.add_sync_process(val) + sim.add_process(val) def add_local_mocks(self, sim: PysimSimulator, frame_locals: dict) -> None: for key, val in frame_locals.items(): if hasattr(val, "_transactron_testing_process"): - sim.add_sync_process(val) + sim.add_process(val) def add_all_mocks(self, sim: PysimSimulator, frame_locals: dict) -> None: self.add_class_mocks(sim) @@ -325,9 +330,13 @@ def run_simulation(self, module: HasElaborate, max_cycles: float = 10e4, add_tra for f in self._transactron_sim_processes_to_add: ret = f() if ret is not None: - sim.add_sync_process(ret) + sim.add_process(ret) - res = sim.run() + with warnings.catch_warnings(): + # TODO: figure out testing without settles! + warnings.filterwarnings("ignore", r"The `Settle` command is deprecated per RFC 27\.") + + res = sim.run() assert res, "Simulation time limit exceeded" def tick(self, cycle_cnt: int = 1): @@ -336,7 +345,7 @@ def tick(self, cycle_cnt: int = 1): """ for _ in range(cycle_cnt): - yield + yield Tick() def random_wait(self, max_cycle_cnt: int, *, min_cycle_cnt: int = 0): """ @@ -349,7 +358,7 @@ def random_wait_geom(self, prob: float = 0.5): Wait till the first success, where there is `prob` probability for success in each cycle. """ while random.random() > prob: - yield + yield Tick() def multi_settle(self, settle_count: int = 1): for _ in range(settle_count): diff --git a/transactron/testing/logging.py b/transactron/testing/logging.py index 65ca52b20..7c8edf1dc 100644 --- a/transactron/testing/logging.py +++ b/transactron/testing/logging.py @@ -99,7 +99,7 @@ def log_process(): while True: yield Tick("sync_neg") yield from handle_logs() - yield + yield Tick() _sim_cycle += 1 return log_process diff --git a/transactron/testing/profiler.py b/transactron/testing/profiler.py index b70119c7d..795c7f293 100644 --- a/transactron/testing/profiler.py +++ b/transactron/testing/profiler.py @@ -32,6 +32,6 @@ def process() -> TestGen: cprof = CycleProfile.make(samples, profile_data) profile.cycles.append(cprof) - yield + yield Tick() return process diff --git a/transactron/testing/testbenchio.py b/transactron/testing/testbenchio.py index 2d19f1b53..7611a1e6f 100644 --- a/transactron/testing/testbenchio.py +++ b/transactron/testing/testbenchio.py @@ -1,5 +1,5 @@ from amaranth import * -from amaranth.sim import Settle, Passive +from amaranth.sim import Settle, Passive, Tick from typing import Optional, Callable from transactron.lib import AdapterBase from transactron.lib.adapters import Adapter @@ -33,7 +33,7 @@ def done(self) -> TestGen[int]: def wait_until_done(self) -> TestGen[None]: while (yield self.adapter.done) != 1: - yield + yield Tick() def set_inputs(self, data: RecordValueDict = {}) -> TestGen[None]: yield from assign(self.adapter.data_in, data) @@ -58,7 +58,7 @@ def call_result(self) -> TestGen[Optional[RecordIntDictRet]]: def call_do(self) -> TestGen[RecordIntDict]: while (outputs := (yield from self.call_result())) is None: - yield + yield Tick() yield from self.disable() return outputs @@ -70,7 +70,7 @@ def call_try( if not data: data = kwdata yield from self.call_init(data) - yield + yield Tick() outputs = yield from self.call_result() yield from self.disable() return outputs @@ -81,7 +81,7 @@ def call(self, data: RecordIntDict = {}, /, **kwdata: int | RecordIntDict) -> Te if not data: data = kwdata yield from self.call_init(data) - yield + yield Tick() return (yield from self.call_do()) # Operations for Adapter @@ -117,7 +117,7 @@ def handle_validate_arguments(): yield Settle() yield from handle_validate_arguments() while (arg := (yield from self.method_argument())) is None: - yield + yield Tick() yield from self.set_enable(enable()) for _ in range(extra_settle_count + 1): @@ -126,7 +126,7 @@ def handle_validate_arguments(): ret_out = mock_def_helper(self, function, arg) yield from self.method_return(ret_out or {}) - yield + yield Tick() def method_handle_loop( self, diff --git a/transactron/tracing.py b/transactron/tracing.py index 6c6ccddba..6f9c709f1 100644 --- a/transactron/tracing.py +++ b/transactron/tracing.py @@ -7,6 +7,8 @@ from amaranth.hdl import Elaboratable, Fragment, Instance from amaranth.hdl._xfrm import FragmentTransformer from amaranth.hdl import _dsl, _ir, _mem, _xfrm +from amaranth.lib import memory # type: ignore +from amaranth_types import SrcLoc from transactron.utils import HasElaborate from . import core @@ -16,7 +18,7 @@ # List of Fragment subclasses which should be patched to inherit from TracingFragment. # The first element of the tuple is a subclass name to patch, and the second element # of the tuple is tuple with modules in which the patched subclass should be installed. -fragment_subclasses_to_patch = [("MemoryInstance", (_mem, _xfrm))] +fragment_subclasses_to_patch = [("MemoryInstance", (memory, _mem, _xfrm))] DIAGNOSTICS = False orig_on_fragment = FragmentTransformer.on_fragment @@ -79,7 +81,7 @@ def on_fragment(self: FragmentTransformer, fragment): class TracingFragment(Fragment): _tracing_original: Elaboratable - subfragments: list[tuple[Elaboratable, str]] + subfragments: list[tuple[Elaboratable, str, SrcLoc]] if DIAGNOSTICS: diff --git a/transactron/utils/amaranth_ext/elaboratables.py b/transactron/utils/amaranth_ext/elaboratables.py index 7feed52ef..ed6b57122 100644 --- a/transactron/utils/amaranth_ext/elaboratables.py +++ b/transactron/utils/amaranth_ext/elaboratables.py @@ -162,7 +162,7 @@ def __init__(self, count: int): self.count = count self.requests = Signal(count) - self.grant = Signal(count, reset=1) + self.grant = Signal(count, init=1) self.valid = Signal() def elaborate(self, platform): diff --git a/transactron/utils/assign.py b/transactron/utils/assign.py index 7b0b3eab7..4257d2df6 100644 --- a/transactron/utils/assign.py +++ b/transactron/utils/assign.py @@ -217,7 +217,7 @@ def has_explicit_shape(val: ValueLike): if valuelike_shape(lhs) != valuelike_shape(rhs): raise ValueError( "Shapes not matching: lhs: {} {} rhs: {} {}".format( - valuelike_shape(lhs), lhs, valuelike_shape(rhs), rhs + valuelike_shape(lhs), repr(lhs), valuelike_shape(rhs), repr(rhs) ) ) From 87cb8f5134d793390ec582c0027b4a8ac6d0e3c8 Mon Sep 17 00:00:00 2001 From: Marek Materzok Date: Sun, 6 Oct 2024 00:41:03 +0200 Subject: [PATCH 2/2] More uses of av_comb, slight refactor of RF (#722) --- coreblocks/core_structs/rf.py | 19 +++++++------- coreblocks/func_blocks/fu/alu.py | 8 +++--- coreblocks/func_blocks/fu/div_unit.py | 34 ++++++++++++------------- coreblocks/func_blocks/fu/mul_unit.py | 34 ++++++++++++------------- coreblocks/func_blocks/fu/shift_unit.py | 8 +++--- coreblocks/func_blocks/fu/zbc.py | 30 +++++++++++----------- coreblocks/func_blocks/fu/zbs.py | 8 +++--- 7 files changed, 70 insertions(+), 71 deletions(-) diff --git a/coreblocks/core_structs/rf.py b/coreblocks/core_structs/rf.py index d6d5e76e8..cb2f32ccd 100644 --- a/coreblocks/core_structs/rf.py +++ b/coreblocks/core_structs/rf.py @@ -15,7 +15,10 @@ def __init__(self, *, gen_params: GenParams): layouts = gen_params.get(RFLayouts) self.internal_layout = make_layout(("reg_val", gen_params.isa.xlen), ("valid", 1)) self.read_layout = layouts.rf_read_out - self.entries = Array(Signal(self.internal_layout) for _ in range(2**gen_params.phys_regs_bits)) + self.entries = Array( + Signal(self.internal_layout, reset={"reg_val": 0, "valid": k == 0}) + for k in range(2**gen_params.phys_regs_bits) + ) self.read1 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out) self.read2 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out) @@ -43,15 +46,10 @@ def elaborate(self, platform): being_written = Signal(self.gen_params.phys_regs_bits) written_value = Signal(self.gen_params.isa.xlen) - # Register 0 always valid (this field won't be updated in methods below) - not sure - # how to set 0th entry valid signal at initialization stage so doing it here instead - # with a 1-cycle delay. I believe this has to be in sync domain like every other - # RF entry or else bad things will happen. - m.d.sync += self.entries[0].valid.eq(1) - @def_method(m, self.read1) def _(reg_id: Value): - forward = being_written == reg_id + forward = Signal() + m.d.av_comb += forward.eq((being_written == reg_id) & (reg_id != 0)) return { "reg_val": Mux(forward, written_value, self.entries[reg_id].reg_val), "valid": Mux(forward, 1, self.entries[reg_id].valid), @@ -59,7 +57,8 @@ def _(reg_id: Value): @def_method(m, self.read2) def _(reg_id: Value): - forward = being_written == reg_id + forward = Signal() + m.d.av_comb += forward.eq((being_written == reg_id) & (reg_id != 0)) return { "reg_val": Mux(forward, written_value, self.entries[reg_id].reg_val), "valid": Mux(forward, 1, self.entries[reg_id].valid), @@ -69,7 +68,7 @@ def _(reg_id: Value): def _(reg_id: Value, reg_val: Value): zero_reg = reg_id == 0 m.d.comb += being_written.eq(reg_id) - m.d.comb += written_value.eq(Mux(zero_reg, 0, reg_val)) + m.d.av_comb += written_value.eq(reg_val) with m.If(~(zero_reg)): m.d.sync += self.entries[reg_id].reg_val.eq(reg_val) m.d.sync += self.entries[reg_id].valid.eq(1) diff --git a/coreblocks/func_blocks/fu/alu.py b/coreblocks/func_blocks/fu/alu.py index d5962ec26..1b359586f 100644 --- a/coreblocks/func_blocks/fu/alu.py +++ b/coreblocks/func_blocks/fu/alu.py @@ -240,11 +240,11 @@ def _(): @def_method(m, self.issue) def _(arg): - m.d.comb += decoder.exec_fn.eq(arg.exec_fn) - m.d.comb += alu.fn.eq(decoder.decode_fn) + m.d.av_comb += decoder.exec_fn.eq(arg.exec_fn) + m.d.av_comb += alu.fn.eq(decoder.decode_fn) - m.d.comb += alu.in1.eq(arg.s1_val) - m.d.comb += alu.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) + m.d.av_comb += alu.in1.eq(arg.s1_val) + m.d.av_comb += alu.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) self.perf_instr.incr(m, decoder.decode_fn) diff --git a/coreblocks/func_blocks/fu/div_unit.py b/coreblocks/func_blocks/fu/div_unit.py index af8032bed..d47159650 100644 --- a/coreblocks/func_blocks/fu/div_unit.py +++ b/coreblocks/func_blocks/fu/div_unit.py @@ -84,7 +84,7 @@ def _(): @def_method(m, self.issue) def _(arg): - m.d.comb += decoder.exec_fn.eq(arg.exec_fn) + m.d.av_comb += decoder.exec_fn.eq(arg.exec_fn) i1, i2 = get_input(arg) flip_sign = Signal(1) # if result is negative number @@ -98,27 +98,27 @@ def _abs(s: Value) -> Value: with OneHotSwitch(m, decoder.decode_fn) as OneHotCase: with OneHotCase(DivFn.Fn.DIVU): - m.d.comb += flip_sign.eq(0) - m.d.comb += rem_res.eq(0) - m.d.comb += dividend.eq(i1) - m.d.comb += divisor.eq(i2) + m.d.av_comb += flip_sign.eq(0) + m.d.av_comb += rem_res.eq(0) + m.d.av_comb += dividend.eq(i1) + m.d.av_comb += divisor.eq(i2) with OneHotCase(DivFn.Fn.DIV): # quotient is negative if divisor and dividend have different signs - m.d.comb += flip_sign.eq(i1[sign_bit] ^ i2[sign_bit]) - m.d.comb += rem_res.eq(0) - m.d.comb += dividend.eq(_abs(i1)) - m.d.comb += divisor.eq(_abs(i2)) + m.d.av_comb += flip_sign.eq(i1[sign_bit] ^ i2[sign_bit]) + m.d.av_comb += rem_res.eq(0) + m.d.av_comb += dividend.eq(_abs(i1)) + m.d.av_comb += divisor.eq(_abs(i2)) with OneHotCase(DivFn.Fn.REMU): - m.d.comb += flip_sign.eq(0) - m.d.comb += rem_res.eq(1) - m.d.comb += dividend.eq(i1) - m.d.comb += divisor.eq(i2) + m.d.av_comb += flip_sign.eq(0) + m.d.av_comb += rem_res.eq(1) + m.d.av_comb += dividend.eq(i1) + m.d.av_comb += divisor.eq(i2) with OneHotCase(DivFn.Fn.REM): # sign of remainder is equal to sign of dividend - m.d.comb += flip_sign.eq(i1[sign_bit]) - m.d.comb += rem_res.eq(1) - m.d.comb += dividend.eq(_abs(i1)) - m.d.comb += divisor.eq(_abs(i2)) + m.d.av_comb += flip_sign.eq(i1[sign_bit]) + m.d.av_comb += rem_res.eq(1) + m.d.av_comb += dividend.eq(_abs(i1)) + m.d.av_comb += divisor.eq(_abs(i2)) params_fifo.write(m, rob_id=arg.rob_id, rp_dst=arg.rp_dst, flip_sign=flip_sign, rem_res=rem_res) diff --git a/coreblocks/func_blocks/fu/mul_unit.py b/coreblocks/func_blocks/fu/mul_unit.py index 9767d2915..e6c9f0947 100644 --- a/coreblocks/func_blocks/fu/mul_unit.py +++ b/coreblocks/func_blocks/fu/mul_unit.py @@ -143,7 +143,7 @@ def _(): @def_method(m, self.issue) def _(arg): - m.d.comb += decoder.exec_fn.eq(arg.exec_fn) + m.d.av_comb += decoder.exec_fn.eq(arg.exec_fn) i1, i2 = get_input(arg) value1 = Signal(self.gen_params.isa.xlen) # input value for multiplier submodule @@ -161,25 +161,25 @@ def _(arg): # In this case we care only about lower part of number, so it does not matter if it is # interpreted as binary number or U2 encoded number, so we set result to be interpreted as # non-negative number. - m.d.comb += negative_res.eq(0) - m.d.comb += high_res.eq(0) - m.d.comb += value1.eq(i1) - m.d.comb += value2.eq(i2) + m.d.av_comb += negative_res.eq(0) + m.d.av_comb += high_res.eq(0) + m.d.av_comb += value1.eq(i1) + m.d.av_comb += value2.eq(i2) with OneHotCase(MulFn.Fn.MULH): - m.d.comb += negative_res.eq(i1[sign_bit] ^ i2[sign_bit]) - m.d.comb += high_res.eq(1) - m.d.comb += value1.eq(Mux(i1[sign_bit], -i1, i1)) - m.d.comb += value2.eq(Mux(i2[sign_bit], -i2, i2)) + m.d.av_comb += negative_res.eq(i1[sign_bit] ^ i2[sign_bit]) + m.d.av_comb += high_res.eq(1) + m.d.av_comb += value1.eq(Mux(i1[sign_bit], -i1, i1)) + m.d.av_comb += value2.eq(Mux(i2[sign_bit], -i2, i2)) with OneHotCase(MulFn.Fn.MULHU): - m.d.comb += negative_res.eq(0) - m.d.comb += high_res.eq(1) - m.d.comb += value1.eq(i1) - m.d.comb += value2.eq(i2) + m.d.av_comb += negative_res.eq(0) + m.d.av_comb += high_res.eq(1) + m.d.av_comb += value1.eq(i1) + m.d.av_comb += value2.eq(i2) with OneHotCase(MulFn.Fn.MULHSU): - m.d.comb += negative_res.eq(i1[sign_bit]) - m.d.comb += high_res.eq(1) - m.d.comb += value1.eq(Mux(i1[sign_bit], -i1, i1)) - m.d.comb += value2.eq(i2) + m.d.av_comb += negative_res.eq(i1[sign_bit]) + m.d.av_comb += high_res.eq(1) + m.d.av_comb += value1.eq(Mux(i1[sign_bit], -i1, i1)) + m.d.av_comb += value2.eq(i2) # Prepared for RV64 # # with OneHotCase(MulFn.Fn.MULW): diff --git a/coreblocks/func_blocks/fu/shift_unit.py b/coreblocks/func_blocks/fu/shift_unit.py index 9477aed13..499d67956 100644 --- a/coreblocks/func_blocks/fu/shift_unit.py +++ b/coreblocks/func_blocks/fu/shift_unit.py @@ -98,11 +98,11 @@ def _(): @def_method(m, self.issue) def _(arg): - m.d.comb += decoder.exec_fn.eq(arg.exec_fn) - m.d.comb += shift_alu.fn.eq(decoder.decode_fn) + m.d.av_comb += decoder.exec_fn.eq(arg.exec_fn) + m.d.av_comb += shift_alu.fn.eq(decoder.decode_fn) - m.d.comb += shift_alu.in1.eq(arg.s1_val) - m.d.comb += shift_alu.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) + m.d.av_comb += shift_alu.in1.eq(arg.s1_val) + m.d.av_comb += shift_alu.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) fifo.write(m, rob_id=arg.rob_id, result=shift_alu.out, rp_dst=arg.rp_dst, exception=0) diff --git a/coreblocks/func_blocks/fu/zbc.py b/coreblocks/func_blocks/fu/zbc.py index 6fcf06e44..ca80e07a6 100644 --- a/coreblocks/func_blocks/fu/zbc.py +++ b/coreblocks/func_blocks/fu/zbc.py @@ -201,7 +201,7 @@ def _(): @def_method(m, self.issue) def _(exec_fn, imm, s1_val, s2_val, rob_id, rp_dst, pc): - m.d.comb += decoder.exec_fn.eq(exec_fn) + m.d.av_comb += decoder.exec_fn.eq(exec_fn) i1 = s1_val i2 = Mux(imm, imm, s2_val) @@ -213,28 +213,28 @@ def _(exec_fn, imm, s1_val, s2_val, rob_id, rp_dst, pc): with OneHotSwitch(m, decoder.decode_fn) as OneHotCase: with OneHotCase(ZbcFn.Fn.CLMUL): - m.d.comb += high_res.eq(0) - m.d.comb += rev_res.eq(0) - m.d.comb += value1.eq(i1) - m.d.comb += value2.eq(i2) + m.d.av_comb += high_res.eq(0) + m.d.av_comb += rev_res.eq(0) + m.d.av_comb += value1.eq(i1) + m.d.av_comb += value2.eq(i2) with OneHotCase(ZbcFn.Fn.CLMULH): - m.d.comb += high_res.eq(1) - m.d.comb += rev_res.eq(0) - m.d.comb += value1.eq(i1) - m.d.comb += value2.eq(i2) + m.d.av_comb += high_res.eq(1) + m.d.av_comb += rev_res.eq(0) + m.d.av_comb += value1.eq(i1) + m.d.av_comb += value2.eq(i2) with OneHotCase(ZbcFn.Fn.CLMULR): # clmulr is equivalent to bit-reversing the inputs, # performing a clmul, # then bit-reversing the output. - m.d.comb += high_res.eq(0) - m.d.comb += rev_res.eq(1) - m.d.comb += value1.eq(i1[::-1]) - m.d.comb += value2.eq(i2[::-1]) + m.d.av_comb += high_res.eq(0) + m.d.av_comb += rev_res.eq(1) + m.d.av_comb += value1.eq(i1[::-1]) + m.d.av_comb += value2.eq(i2[::-1]) params_fifo.write(m, rob_id=rob_id, rp_dst=rp_dst, high_res=high_res, rev_res=rev_res) - m.d.comb += clmul.i1.eq(value1) - m.d.comb += clmul.i2.eq(value2) + m.d.av_comb += clmul.i1.eq(value1) + m.d.av_comb += clmul.i2.eq(value2) m.d.comb += clmul.reset.eq(1) return m diff --git a/coreblocks/func_blocks/fu/zbs.py b/coreblocks/func_blocks/fu/zbs.py index 545aa6d3c..90fd6bcdb 100644 --- a/coreblocks/func_blocks/fu/zbs.py +++ b/coreblocks/func_blocks/fu/zbs.py @@ -117,11 +117,11 @@ def _(arg): @def_method(m, self.issue) def _(arg): - m.d.comb += decoder.exec_fn.eq(arg.exec_fn) + m.d.av_comb += decoder.exec_fn.eq(arg.exec_fn) - m.d.comb += zbs.function.eq(decoder.decode_fn) - m.d.comb += zbs.in1.eq(arg.s1_val) - m.d.comb += zbs.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) + m.d.av_comb += zbs.function.eq(decoder.decode_fn) + m.d.av_comb += zbs.in1.eq(arg.s1_val) + m.d.av_comb += zbs.in2.eq(Mux(arg.imm, arg.imm, arg.s2_val)) result_fifo.write(m, rob_id=arg.rob_id, result=zbs.result, rp_dst=arg.rp_dst, exception=0)