from abc import ABCMeta, abstractmethod from amaranth import * from amaranth.asserts import * from power_fv.check import PowerFVCheck __all__ = ["DataStorageCheck", "DataStorageModel", "DataStorageTestbench"] # TODO: add support for restricting addresses to non-cachable/write-through regions. class DataStorageCheck(PowerFVCheck): pass class DataStorageModel(metaclass=ABCMeta): @abstractmethod def connect(self, dut): raise NotImplementedError @abstractmethod def elaborate(self, platform): raise NotImplementedError class DataStorageTestbench(Elaboratable, metaclass=ABCMeta): def __init__(self, check): if not isinstance(check, DataStorageCheck): raise TypeError("Check must be an instance of DataStorageCheck, not {!r}" .format(check)) self.check = check self.name = "storage_data_tb" @abstractmethod def storage(self): raise NotImplementedError def elaborate(self, platform): m = Module() m.submodules.dut = dut = self.check.dut m.submodules.storage = storage = self.storage() written = Signal(64 // 8) shadow = Signal(64) m.d.comb += storage.connect(dut) with m.If(dut.pfv.stb & dut.pfv.skip): m.d.comb += [ Assert(~dut.pfv.mem.r_mask.any()), Assert(~dut.pfv.mem.w_mask.any()), ] with m.If(dut.pfv.stb & (dut.pfv.mem.addr == storage.addr)): for i, byte_written in enumerate(written): byte_shadow = shadow[i*8:i*8+8] byte_w_stb = dut.pfv.mem.w_mask[i] byte_w_data = dut.pfv.mem.w_data[i*8:i*8+8] byte_r_stb = dut.pfv.mem.r_mask[i] byte_r_data = dut.pfv.mem.r_data[i*8:i*8+8] with m.If(byte_w_stb): m.d.sync += [ byte_written.eq(1), byte_shadow .eq(byte_w_data), ] with m.If(byte_r_stb & byte_written): m.d.comb += Assert(byte_r_data == byte_shadow) return m