From b76bef1f8d6bb95a8a48875bc346199ac2d0443a Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 26 Jun 2020 13:14:47 +0100 Subject: [PATCH] code-morph which redirects lsmem unit test through new ConfigLoadStoreUnit this to allow wishbone-SRAM test version to be tested with the same unit test --- src/soc/bus/test/test_minerva.py | 2 +- src/soc/config/loadstore.py | 8 +- src/soc/config/test/test_loadstore.py | 103 +++++++++++++++++++++++++ src/soc/experiment/lsmem.py | 105 +++----------------------- src/soc/minerva/units/loadstore.py | 8 +- src/soc/minerva/wishbone.py | 4 +- 6 files changed, 124 insertions(+), 106 deletions(-) create mode 100644 src/soc/config/test/test_loadstore.py diff --git a/src/soc/bus/test/test_minerva.py b/src/soc/bus/test/test_minerva.py index e009c62a..93ed702c 100644 --- a/src/soc/bus/test/test_minerva.py +++ b/src/soc/bus/test/test_minerva.py @@ -1,6 +1,6 @@ from nmigen_soc.wishbone.sram import SRAM from nmigen import Memory, Signal, Module -from soc.minerva.units.loadstore import BareLoadStoreUnit, CacheLoadStoreUnit +from soc.minerva.units.loadstore import BareLoadStoreUnit, CachedLoadStoreUnit class TestSRAMBareLoadStoreUnit(BareLoadStoreUnit): diff --git a/src/soc/config/loadstore.py b/src/soc/config/loadstore.py index 37e2bf38..e7d52ff0 100644 --- a/src/soc/config/loadstore.py +++ b/src/soc/config/loadstore.py @@ -3,14 +3,14 @@ allows the type of LoadStoreUnit to be run-time selectable """ -from soc.experiment.pimem import TestMemoryLoadStoreUnit +from soc.experiment.lsmem import TestMemLoadStoreUnit from soc.bus.test.test_minerva import TestSRAMBareLoadStoreUnit -class ConfigureableLoadStoreUnit: +class ConfigLoadStoreUnit: def __init__(self, pspec): - lsidict = {'testmem': TestMemoryLoadStoreUnit, - 'test_bare_wb': TestBareLoadStoreUnit, + lsidict = {'testmem': TestMemLoadStoreUnit, + 'test_bare_wb': TestSRAMBareLoadStoreUnit, #'test_cache_wb': TestCacheLoadStoreUnit } lsikls = lsidict[pspec.ldst_ifacetype] diff --git a/src/soc/config/test/test_loadstore.py b/src/soc/config/test/test_loadstore.py new file mode 100644 index 00000000..b0add592 --- /dev/null +++ b/src/soc/config/test/test_loadstore.py @@ -0,0 +1,103 @@ +from soc.minerva.units.loadstore import LoadStoreUnitInterface +from nmigen import Signal, Module, Elaboratable, Mux +from nmigen.utils import log2_int +import random +from nmigen.back.pysim import Simulator, Settle +from soc.config.loadstore import ConfigLoadStoreUnit +from collections import namedtuple + + +def write_to_addr(dut, addr, value): + yield dut.x_addr_i.eq(addr) + yield dut.x_st_data_i.eq(value) + yield dut.x_st_i.eq(1) + yield dut.x_mask_i.eq(-1) + yield dut.x_valid_i.eq(1) + yield dut.x_stall_i.eq(1) + yield + yield + + yield dut.x_stall_i.eq(0) + yield + yield dut.x_st_i.eq(0) + while (yield dut.x_stall_i): + yield + + +def read_from_addr(dut, addr): + yield dut.x_addr_i.eq(addr) + yield dut.x_ld_i.eq(1) + yield dut.x_valid_i.eq(1) + yield dut.x_stall_i.eq(1) + yield + yield dut.x_stall_i.eq(0) + yield + yield dut.x_ld_i.eq(0) + yield Settle() + while (yield dut.x_stall_i): + yield + assert (yield dut.x_valid_i) + return (yield dut.m_ld_data_o) + + +def write_byte(dut, addr, val): + offset = addr & 0x3 + yield dut.x_addr_i.eq(addr) + yield dut.x_st_i.eq(1) + yield dut.x_st_data_i.eq(val << (offset * 8)) + yield dut.x_mask_i.eq(1 << offset) + yield dut.x_valid_i.eq(1) + + yield + yield dut.x_st_i.eq(0) + while (yield dut.x_stall_i): + yield + + +def read_byte(dut, addr): + offset = addr & 0x3 + yield dut.x_addr_i.eq(addr) + yield dut.x_ld_i.eq(1) + yield dut.x_valid_i.eq(1) + yield + yield dut.x_ld_i.eq(0) + yield Settle() + while (yield dut.x_stall_i): + yield + assert (yield dut.x_valid_i) + val = (yield dut.m_ld_data_o) + return (val >> (offset * 8)) & 0xff + + +if __name__ == '__main__': + m = Module() + Pspec = namedtuple('Pspec', ['ldst_ifacetype', + 'addr_wid', 'mask_wid', 'reg_wid']) + pspec = Pspec(ldst_ifacetype='testmem', addr_wid=64, mask_wid=3, reg_wid=64) + dut = ConfigLoadStoreUnit(pspec).lsi + m.submodules.dut = dut + + sim = Simulator(m) + sim.add_clock(1e-6) + + def process(): + + values = [random.randint(0, (1<<32)-1) for x in range(16)] + + for addr, val in enumerate(values): + yield from write_to_addr(dut, addr << 2, val) + for addr, val in enumerate(values): + x = yield from read_from_addr(dut, addr << 2) + assert x == val + + values = [random.randint(0, 255) for x in range(16*4)] + for addr, val in enumerate(values): + yield from write_byte(dut, addr, val) + for addr, val in enumerate(values): + x = yield from read_byte(dut, addr) + assert x == val + + sim.add_sync_process(process) + with sim.write_vcd("test_loadstore_tm.vcd", traces=[]): + sim.run() + diff --git a/src/soc/experiment/lsmem.py b/src/soc/experiment/lsmem.py index 68b4d0fc..e9260176 100644 --- a/src/soc/experiment/lsmem.py +++ b/src/soc/experiment/lsmem.py @@ -2,24 +2,23 @@ from soc.minerva.units.loadstore import LoadStoreUnitInterface from nmigen import Signal, Module, Elaboratable, Mux from nmigen.utils import log2_int from soc.experiment.testmem import TestMemory # TODO: replace with TMLSUI -import random - -from nmigen.back.pysim import Simulator, Settle +from nmigen.cli import rtlil class TestMemLoadStoreUnit(LoadStoreUnitInterface, Elaboratable): - def __init__(self, regwid, addrwid, mask_wid=4): + def __init__(self, addr_wid=32, mask_wid=4, data_wid=32): super().__init__() - self.regwid = regwid - self.addrwid = addrwid + self.regwid = data_wid + self.addrwid = addr_wid self.mask_wid = mask_wid def elaborate(self, platform): m = Module() regwid, addrwid, mask_wid = self.regwid, self.addrwid, self.mask_wid - adr_lsb = log2_int(mask_wid) + adr_lsb = self.adr_lsbs - m.submodules.mem = mem = TestMemory(regwid, addrwid, granularity=8) + # limit TestMemory to 2^6 entries of regwid size + m.submodules.mem = mem = TestMemory(regwid, 6, granularity=8) do_load = Signal() # set when doing a load while valid and not stalled do_store = Signal() # set when doing a store while valid and not stalled @@ -42,93 +41,9 @@ class TestMemLoadStoreUnit(LoadStoreUnitInterface, Elaboratable): return m -def write_to_addr(dut, addr, value): - yield dut.x_addr_i.eq(addr) - yield dut.x_st_data_i.eq(value) - yield dut.x_st_i.eq(1) - yield dut.x_mask_i.eq(-1) - yield dut.x_valid_i.eq(1) - yield dut.x_stall_i.eq(1) - yield - yield - - yield dut.x_stall_i.eq(0) - yield - yield dut.x_st_i.eq(0) - while (yield dut.x_stall_i): - yield - - -def read_from_addr(dut, addr): - yield dut.x_addr_i.eq(addr) - yield dut.x_ld_i.eq(1) - yield dut.x_valid_i.eq(1) - yield dut.x_stall_i.eq(1) - yield - yield dut.x_stall_i.eq(0) - yield - yield dut.x_ld_i.eq(0) - yield Settle() - while (yield dut.x_stall_i): - yield - assert (yield dut.x_valid_i) - return (yield dut.m_ld_data_o) - - -def write_byte(dut, addr, val): - offset = addr & 0x3 - yield dut.x_addr_i.eq(addr) - yield dut.x_st_i.eq(1) - yield dut.x_st_data_i.eq(val << (offset * 8)) - yield dut.x_mask_i.eq(1 << offset) - yield dut.x_valid_i.eq(1) - - yield - yield dut.x_st_i.eq(0) - while (yield dut.x_stall_i): - yield - - -def read_byte(dut, addr): - offset = addr & 0x3 - yield dut.x_addr_i.eq(addr) - yield dut.x_ld_i.eq(1) - yield dut.x_valid_i.eq(1) - yield - yield dut.x_ld_i.eq(0) - yield Settle() - while (yield dut.x_stall_i): - yield - assert (yield dut.x_valid_i) - val = (yield dut.m_ld_data_o) - return (val >> (offset * 8)) & 0xff - - if __name__ == '__main__': - m = Module() dut = TestMemLoadStoreUnit(regwid=32, addrwid=4) - m.submodules.dut = dut - - sim = Simulator(m) - sim.add_clock(1e-6) - - def process(): - - values = [random.randint(0, (1<<32)-1) for x in range(16)] - - for addr, val in enumerate(values): - yield from write_to_addr(dut, addr << 2, val) - for addr, val in enumerate(values): - x = yield from read_from_addr(dut, addr << 2) - assert x == val - - values = [random.randint(0, 255) for x in range(16*4)] - for addr, val in enumerate(values): - yield from write_byte(dut, addr, val) - for addr, val in enumerate(values): - x = yield from read_byte(dut, addr) - assert x == val + vl = rtlil.convert(dut, ports=[]) # TODOdut.ports()) + with open("test_lsmem.il", "w") as f: + f.write(vl) - sim.add_sync_process(process) - with sim.write_vcd("lsmem.vcd", "lsmem.gtkw", traces=[]): - sim.run() diff --git a/src/soc/minerva/units/loadstore.py b/src/soc/minerva/units/loadstore.py index c74f6042..c91769c9 100644 --- a/src/soc/minerva/units/loadstore.py +++ b/src/soc/minerva/units/loadstore.py @@ -3,7 +3,7 @@ from nmigen.utils import log2_int from nmigen.lib.fifo import SyncFIFO from soc.minerva.cache import L1Cache -from soc.minerva.wishbone import wishbone_layout, WishboneArbiter, Cycle +from soc.minerva.wishbone import make_wb_layout, WishboneArbiter, Cycle __all__ = ["LoadStoreUnitInterface", "BareLoadStoreUnit", @@ -12,12 +12,12 @@ __all__ = ["LoadStoreUnitInterface", "BareLoadStoreUnit", class LoadStoreUnitInterface: def __init__(self, addr_wid=32, mask_wid=4, data_wid=32): - self.dbus = Record(mk_wb_layout(addr_wid, mask_wid, data_wid)) + self.dbus = Record(make_wb_layout(addr_wid, mask_wid, data_wid)) self.mask_wid = mask_wid self.addr_wid = addr_wid self.data_wid = data_wid - self.adr_lsbs = log2_int_mask_wid) # LSBs of addr covered by mask - badwid = addr_wid-log2_int(self.adr_lsbs) # TODO: is this correct? + self.adr_lsbs = log2_int(mask_wid) # LSBs of addr covered by mask + badwid = addr_wid-self.adr_lsbs # TODO: is this correct? # INPUTS self.x_addr_i = Signal(addr_wid) # address used for loads/stores diff --git a/src/soc/minerva/wishbone.py b/src/soc/minerva/wishbone.py index fa6bca3e..1f56619f 100644 --- a/src/soc/minerva/wishbone.py +++ b/src/soc/minerva/wishbone.py @@ -15,8 +15,8 @@ class Cycle: def make_wb_layout(addr_wid, mask_wid, data_wid): - adr_lsbs = log2_int_mask_wid) # LSBs of addr covered by mask - badwid = addr_wid-log2_int(adr_lsbs) # MSBs (not covered by mask) + adr_lsbs = log2_int(mask_wid) # LSBs of addr covered by mask + badwid = addr_wid-adr_lsbs # MSBs (not covered by mask) return [ ("adr", badwid , DIR_FANOUT), -- 2.30.2