"""MMU PortInterface Test quite basic, calls pi_ld to get data via PortInterface. this test shouldn't really exist, it's superceded by test_ldst_pi.py """ from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal) from nmigen.cli import main from nmigen.cli import rtlil from nmutil.iocontrol import RecordObject from nmutil.byterev import byte_reverse from nmutil.mask import Mask, masked from nmutil.util import Display if True: from nmigen.back.pysim import Simulator, Delay, Settle else: from nmigen.sim.cxxsim import Simulator, Delay, Settle from nmutil.util import wrap from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst from soc.experiment.mem_types import (LoadStore1ToMMUType, MMUToLoadStore1Type, MMUToDCacheType, DCacheToMMUType, MMUToICacheType) from soc.experiment.mmu import MMU from soc.experiment.dcache import DCache #more imports from soc.experiment.l0_cache import L0CacheBuffer2 from nmigen import Module, Signal, Mux, Elaboratable, Cat, Const from nmigen.cli import rtlil from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst from soc.experiment.pimem import PortInterfaceBase from nmigen.compat.sim import run_simulation, Settle # guess: those four need to be connected #class DCacheToLoadStore1Type(RecordObject): dcache.d_out #class LoadStore1ToDCacheType(RecordObject): dcache.d_in #class LoadStore1ToMMUType(RecordObject): mmu.l_in #class MMUToLoadStore1Type(RecordObject): mmu.l_out # will take at least one week (10.10.2020) # many unconnected signals class TestMicrowattMemoryPortInterface(PortInterfaceBase): """TestMicrowattMemoryPortInterface This is a Test Class for MMU and DCache conforming to PortInterface """ def __init__(self, mmu, dcache, regwid=64, addrwid=4): super().__init__(regwid, addrwid) self.mmu = mmu self.dcache = dcache def set_wr_addr(self, m, addr, mask, misalign, msr_pr): m.d.comb += self.dcache.d_in.addr.eq(addr) m.d.comb += self.mmu.l_in.addr.eq(addr) m.d.comb += self.mmu.l_in.load.eq(0) m.d.comb += self.mmu.l_in.priv.eq(1) # TODO put msr_pr here m.d.comb += self.mmu.l_in.valid.eq(1) def set_rd_addr(self, m, addr, mask, misalign, msr_pr): m.d.comb += self.dcache.d_in.addr.eq(addr) m.d.comb += self.mmu.l_in.addr.eq(addr) m.d.comb += self.mmu.l_in.load.eq(1) m.d.comb += self.mmu.l_in.priv.eq(1) # TODO put msr_pr here m.d.comb += self.mmu.l_in.valid.eq(1) def set_wr_data(self, m, data, wen): m.d.comb += self.dcache.d_in.data.eq(data) # write st to mem m.d.comb += self.dcache.d_in.load.eq(~wen) # enable writes st_ok = Const(1, 1) return st_ok # LoadStore1ToDCacheType # valid # dcbz # nc # reserve # virt_mode # addr # TODO # byte_sel(8) def get_rd_data(self, m): # get data from dcache ld_ok = self.mmu.l_out.done data = self.dcache.d_out.data return data, ld_ok # DCacheToLoadStore1Type NC # store_done # error # cache_paradox return None def elaborate(self, platform): m = super().elaborate(platform) m.submodules.mmu = self.mmu m.submodules.dcache = self.dcache # link mmu and dcache together m.d.comb += self.dcache.m_in.eq(self.mmu.d_out) m.d.comb += self.mmu.d_in.eq(self.dcache.m_out) return m def ports(self): yield from super().ports() # TODO: memory ports stop = False def wb_get(dc): """simulator process for getting memory load requests """ global stop def b(x): return int.from_bytes(x.to_bytes(8, byteorder='little'), byteorder='big', signed=False) mem = {0x10000: # PARTITION_TABLE_2 # PATB_GR=1 PRTB=0x1000 PRTS=0xb b(0x800000000100000b), 0x30000: # RADIX_ROOT_PTE # V = 1 L = 0 NLB = 0x400 NLS = 9 b(0x8000000000040009), 0x40000: # RADIX_SECOND_LEVEL # V = 1 L = 1 SW = 0 RPN = 0 # R = 1 C = 1 ATT = 0 EAA 0x7 b(0xc000000000000187), 0x1000000: # PROCESS_TABLE_3 # RTS1 = 0x2 RPDB = 0x300 RTS2 = 0x5 RPDS = 13 b(0x40000000000300ad), } while not stop: while True: # wait for dc_valid if stop: return cyc = yield (dc.wb_out.cyc) stb = yield (dc.wb_out.stb) if cyc and stb: break yield addr = (yield dc.wb_out.adr) << 3 if addr not in mem: print (" WB LOOKUP NO entry @ %x, returning zero" % (addr)) data = mem.get(addr, 0) yield dc.wb_in.dat.eq(data) print (" DCACHE get %x data %x" % (addr, data)) yield dc.wb_in.ack.eq(1) yield yield dc.wb_in.ack.eq(0) def mmu_lookup(dut, addr): mmu = dut.mmu global stop print("pi_ld") yield from pi_ld(dut.pi, addr, 1) print("pi_ld done") """ # original test code kept for reference while not stop: # wait for dc_valid / err print("waiting for mmu") l_done = yield (mmu.l_out.done) l_err = yield (mmu.l_out.err) l_badtree = yield (mmu.l_out.badtree) l_permerr = yield (mmu.l_out.perm_error) l_rc_err = yield (mmu.l_out.rc_error) l_segerr = yield (mmu.l_out.segerr) l_invalid = yield (mmu.l_out.invalid) if (l_done or l_err or l_badtree or l_permerr or l_rc_err or l_segerr or l_invalid): break yield """ phys_addr = yield mmu.d_out.addr pte = yield mmu.d_out.pte l_done = yield (mmu.l_out.done) l_err = yield (mmu.l_out.err) l_badtree = yield (mmu.l_out.badtree) print ("translated done %d err %d badtree %d addr %x pte %x" % \ (l_done, l_err, l_badtree, phys_addr, pte)) yield yield mmu.l_in.valid.eq(0) return phys_addr def mmu_sim(dut): mmu = dut.mmu global stop yield mmu.rin.prtbl.eq(0x1000000) # set process table yield addr = 0x10000 data = 0 print("pi_st") # TODO mmu_lookup using port interface # set inputs phys_addr = yield from mmu_lookup(dut, 0x10000) assert phys_addr == 0x40000 phys_addr = yield from mmu_lookup(dut, 0x10000) assert phys_addr == 0x40000 stop = True def test_mmu(): mmu = MMU() dcache = DCache() dut = TestMicrowattMemoryPortInterface(mmu, dcache) m = Module() m.submodules.dut = dut # nmigen Simulation sim = Simulator(m) sim.add_clock(1e-6) sim.add_sync_process(wrap(mmu_sim(dut))) sim.add_sync_process(wrap(wb_get(dcache))) with sim.write_vcd('test_mmu_pi.vcd'): sim.run() if __name__ == '__main__': test_mmu()