diff --git a/cores/dinofly/dinofly_cli/__main__.py b/cores/dinofly/dinofly_cli/__main__.py index 596d2f3..5217907 100644 --- a/cores/dinofly/dinofly_cli/__main__.py +++ b/cores/dinofly/dinofly_cli/__main__.py @@ -2,6 +2,7 @@ from pathlib import PurePath from power_fv.session import PowerFVSession from .core import DinoflyCore +from .check.storage import * class DinoflySession(PowerFVSession, core_cls=DinoflyCore): diff --git a/cores/dinofly/dinofly_cli/check/__init__.py b/cores/dinofly/dinofly_cli/check/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cores/dinofly/dinofly_cli/check/storage.py b/cores/dinofly/dinofly_cli/check/storage.py new file mode 100644 index 0000000..120885e --- /dev/null +++ b/cores/dinofly/dinofly_cli/check/storage.py @@ -0,0 +1,166 @@ +from amaranth import * +from amaranth.asserts import * +from amaranth.utils import log2_int + +from amaranth_soc import wishbone + +from power_fv.check.storage import * + +from ..core import * + + +__all__ = [ + "InsnStorageCheck_Dinofly", "InsnStorageTestbench_Dinofly", "InsnStorageModel_Dinofly", + "DataStorageCheck_Dinofly", "DataStorageTestbench_Dinofly", "DataStorageModel_Dinofly", +] + + +class InsnStorageCheck_Dinofly(InsnStorageCheck, name=("dinofly", "storage", "insn")): + def __init__(self, *, depth, skip, core, **kwargs): + if not isinstance(core, DinoflyCore): + raise TypeError("Core must be an instance of DinoflyCore, not {!r}" + .format(core)) + super().__init__(depth=depth, skip=skip, core=core, **kwargs) + + def testbench(self): + return InsnStorageTestbench_Dinofly(self) + + +class InsnStorageTestbench_Dinofly(InsnStorageTestbench): + def __init__(self, check): + if not isinstance(check, InsnStorageCheck_Dinofly): + raise TypeError("Check must be an instance of InsnStorageCheck_Dinofly, not {!r}" + .format(check)) + super().__init__(check) + + def storage(self): + return InsnStorageModel_Dinofly( + ibus_addr_width=self.check.dut.ibus.addr_width, + ibus_data_width=self.check.dut.ibus.data_width, + ibus_granularity=self.check.dut.ibus.granularity, + ) + + +class InsnStorageModel_Dinofly(InsnStorageModel, Elaboratable): + def __init__(self, *, ibus_addr_width=30, ibus_data_width=32, ibus_granularity=8): + self.addr = Signal(64) + self.data = Signal(32) + self._ibus = wishbone.Interface(addr_width=ibus_addr_width, data_width=ibus_data_width, + granularity=ibus_granularity) + + def connect(self, dut): + assert isinstance(dut, DinoflyWrapper) + assert dut.ibus.addr_width == self._ibus.addr_width + assert dut.ibus.data_width == self._ibus.data_width + assert dut.ibus.granularity == self._ibus.granularity + + return self._ibus.eq(dut.ibus) + + def elaborate(self, platform): + m = Module() + + with m.If(self._ibus.ack): + m.d.comb += [ + Assume(self._ibus.cyc & Past(self._ibus.cyc)), + Assume(self._ibus.stb & Past(self._ibus.stb)), + Assume(~Past(self._ibus.ack)), + ] + + gran_bits = log2_int(self._ibus.data_width // self._ibus.granularity) + + m.d.comb += [ + self.addr.eq(AnyConst(self._ibus.addr_width + gran_bits)), + self.data.eq(AnyConst(32)), + ] + + with m.If(self._ibus.cyc & self._ibus.stb & self._ibus.ack & ~ResetSignal("sync")): + if self._ibus.data_width == 32: + with m.If(self.addr == Cat(Const(0b00, 2), self._ibus.adr)): + m.d.comb += Assume(self._ibus.dat_r == self.data) + elif self._ibus.data_width == 64: + with m.If(self.addr == Cat(Const(0b000, 3), self._ibus.adr)): + m.d.comb += Assume(self._ibus.dat_r[:32] == self.data) + with m.If(self.addr == Cat(Const(0b100, 3), self._ibus.adr)): + m.d.comb += Assume(self._ibus.dat_r[32:] == self.data) + else: + assert False + + return m + + +class DataStorageCheck_Dinofly(DataStorageCheck, name=("dinofly", "storage", "data")): + def __init__(self, *, depth, skip, core, **kwargs): + if not isinstance(core, DinoflyCore): + raise TypeError("Core must be an instance of DinoflyCore, not {!r}" + .format(core)) + super().__init__(depth=depth, skip=skip, core=core, **kwargs) + + def testbench(self): + return DataStorageTestbench_Dinofly(self) + + +class DataStorageTestbench_Dinofly(DataStorageTestbench): + def __init__(self, check): + if not isinstance(check, DataStorageCheck_Dinofly): + raise TypeError("Check must be an instance of DataStorageCheck_Dinofly, not {!r}" + .format(check)) + super().__init__(check) + + def storage(self): + return DataStorageModel_Dinofly( + dbus_addr_width=self.check.dut.dbus.addr_width, + dbus_data_width=self.check.dut.dbus.data_width, + dbus_granularity=self.check.dut.dbus.granularity, + ) + + +class DataStorageModel_Dinofly(DataStorageModel, Elaboratable): + def __init__(self, *, dbus_addr_width=30, dbus_data_width=32, dbus_granularity=8): + self.addr = Signal(64) + self._dbus = wishbone.Interface(addr_width=dbus_addr_width, data_width=dbus_data_width, + granularity=dbus_granularity) + + def connect(self, dut): + assert isinstance(dut, DinoflyWrapper) + assert dut.dbus.addr_width == self._dbus.addr_width + assert dut.dbus.data_width == self._dbus.data_width + assert dut.dbus.granularity == self._dbus.granularity + + return self._dbus.eq(dut.dbus) + + def elaborate(self, platform): + m = Module() + + dbus_read = Signal() + dbus_write = Signal() + + m.d.comb += [ + dbus_read .eq(self._dbus.cyc & self._dbus.stb & self._dbus.ack), + dbus_write.eq(self._dbus.cyc & self._dbus.stb & self._dbus.ack & self._dbus.we), + ] + + with m.If(self._dbus.ack): + m.d.comb += [ + Assume(self._dbus.cyc & Past(self._dbus.cyc)), + Assume(self._dbus.stb & Past(self._dbus.stb)), + Assume(~Past(self._dbus.ack)), + ] + + gran_bits = log2_int(self._dbus.data_width // self._dbus.granularity) + addr_hit = Signal() + value = Signal(self._dbus.data_width) + + m.d.comb += [ + self.addr.eq(AnyConst(self._dbus.addr_width + gran_bits)), + addr_hit .eq(self._dbus.adr == self.addr[gran_bits:]), + ] + + with m.If(dbus_read & addr_hit & ~ResetSignal("sync")): + m.d.comb += Assume(self._dbus.dat_r == value) + + with m.If(dbus_write & addr_hit): + for i, sel_bit in enumerate(self._dbus.sel): + with m.If(sel_bit): + m.d.sync += value[i*8:i*8+8].eq(self._dbus.dat_w[i*8:i*8+8]) + + return m