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
# 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
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
# 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
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
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))
--- /dev/null
+"""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()
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()
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