From: Luke Kenneth Casson Leighton Date: Wed, 12 May 2021 14:07:09 +0000 (+0100) Subject: start doing virtual memory queries via PortInterface on LoadStore1 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0e60f56bfb715fdb02117450a4644b5ecc7d5117;p=soc.git start doing virtual memory queries via PortInterface on LoadStore1 --- diff --git a/src/soc/config/test/test_pi2ls.py b/src/soc/config/test/test_pi2ls.py index 3b34347e..f1807ccf 100644 --- a/src/soc/config/test/test_pi2ls.py +++ b/src/soc/config/test/test_pi2ls.py @@ -35,7 +35,7 @@ def wait_ldok(port): yield -def pi_st(port1, addr, data, datalen): +def pi_st(port1, addr, data, datalen, msr_pr=0): # have to wait until not busy yield from wait_busy(port1, no=False) # wait until not busy @@ -43,6 +43,7 @@ def pi_st(port1, addr, data, datalen): # set up a ST on the port. address first: yield port1.is_st_i.eq(1) # indicate ST yield port1.data_len.eq(datalen) # ST length (1/2/4/8) + yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real) yield port1.addr.data.eq(addr) # set address yield port1.addr.ok.eq(1) # set ok @@ -62,7 +63,7 @@ def pi_st(port1, addr, data, datalen): yield port1.addr.ok.eq(0) # set !ok -def pi_ld(port1, addr, datalen): +def pi_ld(port1, addr, datalen, msr_pr=0): # have to wait until not busy yield from wait_busy(port1, no=False) # wait until not busy @@ -70,6 +71,7 @@ def pi_ld(port1, addr, datalen): # set up a LD on the port. address first: yield port1.is_ld_i.eq(1) # indicate LD yield port1.data_len.eq(datalen) # LD length (1/2/4/8) + yield port1.msr_pr.eq(msr_pr) # MSR PR bit (1==>virt, 0==>real) yield port1.addr.data.eq(addr) # set address yield port1.addr.ok.eq(1) # set ok @@ -87,7 +89,7 @@ def pi_ld(port1, addr, datalen): return data -def pi_ldst(arg, dut): +def pi_ldst(arg, dut, msr_pr=0): # do two half-word stores at consecutive addresses, then two loads addr1 = 0x04 @@ -95,16 +97,16 @@ def pi_ldst(arg, dut): data = 0xbeef data2 = 0xf00f #data = 0x4 - yield from pi_st(dut, addr1, data, 2) - yield from pi_st(dut, addr2, data2, 2) - result = yield from pi_ld(dut, addr1, 2) - result2 = yield from pi_ld(dut, addr2, 2) + yield from pi_st(dut, addr1, data, 2, msr_pr) + yield from pi_st(dut, addr2, data2, 2, msr_pr) + result = yield from pi_ld(dut, addr1, 2, msr_pr) + result2 = yield from pi_ld(dut, addr2, 2, msr_pr) arg.assertEqual(data, result, "data %x != %x" % (result, data)) arg.assertEqual(data2, result2, "data2 %x != %x" % (result2, data2)) # now load both in a 32-bit load to make sure they're really consecutive data3 = data | (data2 << 16) - result3 = yield from pi_ld(dut, addr1, 4) + result3 = yield from pi_ld(dut, addr1, 4, msr_pr) arg.assertEqual(data3, result3, "data3 %x != %x" % (result3, data3)) diff --git a/src/soc/experiment/test/test_ldst_pi.py b/src/soc/experiment/test/test_ldst_pi.py new file mode 100644 index 00000000..82f56482 --- /dev/null +++ b/src/soc/experiment/test/test_ldst_pi.py @@ -0,0 +1,176 @@ +"""MMU PortInterface Test + +quite basic, goes directly to the MMU to assert signals (does not +yet use PortInterface) +""" + +from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal) +from nmigen.cli import main +from nmigen.cli import rtlil +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.config.test.test_loadstore import TestMemPspec +from soc.config.loadstore import ConfigMemoryPortInterface + +from soc.fu.ldst.loadstore import LoadStore1 +from soc.experiment.mmu import MMU + +from nmigen.compat.sim import run_simulation + + +stop = False + +def wb_get(wb): + """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 (wb.cyc) + stb = yield (wb.stb) + if cyc and stb: + break + yield + addr = (yield wb.adr) << 3 + if addr not in mem: + print (" WB LOOKUP NO entry @ %x, returning zero" % (addr)) + + data = mem.get(addr, 0) + yield wb.dat_r.eq(data) + print (" DCACHE get %x data %x" % (addr, data)) + yield wb.ack.eq(1) + yield + yield wb.ack.eq(0) + + +def mmu_lookup(dut, addr): + mmu = dut.submodules.mmu + global stop + + print("pi_ld") + yield from pi_ld(dut.submodules.ldst.pi, addr, 1, msr_pr=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 ldst_sim(dut): + mmu = dut.submodules.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(): + + pspec = TestMemPspec(ldst_ifacetype='mmu_cache_wb', + imem_ifacetype='', + addr_wid=48, + mask_wid=8, + reg_wid=64) + + m = Module() + comb = m.d.comb + cmpi = ConfigMemoryPortInterface(pspec) + m.submodules.ldst = ldst = cmpi.pi + m.submodules.mmu = mmu = MMU() + dcache = ldst.dcache + + l_in, l_out = mmu.l_in, mmu.l_out + d_in, d_out = dcache.d_in, dcache.d_out + wb_out, wb_in = dcache.wb_out, dcache.wb_in + + # link mmu and dcache together + m.d.comb += dcache.m_in.eq(mmu.d_out) # MMUToDCacheType + m.d.comb += mmu.d_in.eq(dcache.m_out) # DCacheToMMUType + + # link ldst and MMU together + comb += l_in.eq(ldst.m_out) + comb += ldst.m_in.eq(l_out) + + + # nmigen Simulation + sim = Simulator(m) + sim.add_clock(1e-6) + + sim.add_sync_process(wrap(ldst_sim(m))) + sim.add_sync_process(wrap(wb_get(cmpi.wb_bus()))) + with sim.write_vcd('test_ldst_pi.vcd'): + sim.run() + + +if __name__ == '__main__': + test_mmu() diff --git a/src/soc/fu/ldst/loadstore.py b/src/soc/fu/ldst/loadstore.py index c7732a11..e5815b16 100644 --- a/src/soc/fu/ldst/loadstore.py +++ b/src/soc/fu/ldst/loadstore.py @@ -160,7 +160,8 @@ class LoadStore1(PortInterfaceBase): m.submodules.dcache = dcache = self.dcache # temp vars - d_out, d_in, m_in, dbus = self.d_out, self.d_in, self.m_in, self.dbus + d_out, d_in, dbus = self.d_out, self.d_in, self.dbus + m_out, m_in = self.m_out, self.m_in exc = self.pi.exc_o exception = exc.happened mmureq = Signal() @@ -277,25 +278,25 @@ class LoadStore1(PortInterfaceBase): m.d.comb += d_out.byte_sel.eq(self.byte_sel) m.d.comb += d_out.addr.eq(self.addr) m.d.comb += d_out.nc.eq(self.nc) + m.d.comb += d_out.priv_mode.eq(self.priv_mode) + m.d.comb += d_out.virt_mode.eq(self.virt_mode) # XXX these should be possible to remove but for some reason # cannot be... yet. TODO, investigate m.d.comb += self.done.eq(d_in.valid) m.d.comb += self.load_data.eq(d_in.data) - ''' TODO: translate to nmigen. - -- Update outputs to MMU - m_out.valid <= mmureq; - m_out.iside <= v.instr_fault; - m_out.load <= r.load; + # Update outputs to MMU + m.d.comb += m_out.valid.eq(mmureq) + m.d.comb += m_out.iside.eq(self.instr_fault) + m.d.comb += m_out.load.eq(self.load) # m_out.priv <= r.priv_mode; TODO - m_out.tlbie <= v.tlbie; + m.d.comb += m_out.tlbie.eq(self.tlbie) # m_out.mtspr <= mmu_mtspr; # TODO # m_out.sprn <= sprn; # TODO - m_out.addr <= maddr; + m.d.comb += m_out.addr.eq(maddr) # m_out.slbia <= l_in.insn(7); # TODO: no idea what this is # m_out.rs <= l_in.data; # nope, probably not needed, TODO investigate - ''' return m