-from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal)
+from nmigen import (C, Module, Signal, Elaboratable, Mux, Cat, Repl, Signal,
+ Const)
from nmigen.cli import main
from nmigen.cli import rtlil
from nmutil.mask import Mask, masked
from nmigen.sim import Simulator, Delay, Settle
from nmutil.util import wrap
-from soc.config.test.test_pi2ls import pi_ld, pi_st, pi_ldst, wait_busy
+from soc.config.test.test_pi2ls import (pi_ld, pi_st, pi_ldst, wait_busy,
+ get_exception_info)
#from soc.config.test.test_pi2ls import pi_st_debug
from soc.config.test.test_loadstore import TestMemPspec
from soc.config.loadstore import ConfigMemoryPortInterface
test_random = True
+def _test_loadstore1_ifetch(dut, mem):
+ """test_loadstore1_ifetch
+
+ this is quite a complex multi-step test.
+
+ * first (just because, as a demo) read in priv mode, non-virtual.
+ just like in experiment/icache.py itself.
+
+ * second, using the (usual) PTE for these things (which came originally
+ from gem5-experimental experiment/radix_walk_example.txt) do a
+ virtual-memory read through the *instruction* cache.
+ this is expected to FAIL
+
+ * third: mess about with the MMU, setting "iside" (instruction-side),
+ requesting an MMU RADIX LOOKUP. this triggers an itlb_load
+ (instruction-cache TLB entry-insertion)
+
+ * fourth and finally: retry the read of the instruction through i-cache.
+ this is now expected to SUCCEED
+
+ a lot going on.
+ """
+
+ mmu = dut.submodules.mmu
+ ldst = dut.submodules.ldst
+ pi = ldst.pi
+ icache = dut.submodules.ldst.icache
+ wbget.stop = False
+
+ print("=== test loadstore instruction (real) ===")
+
+ i_in = icache.i_in
+ i_out = icache.i_out
+ i_m_in = icache.m_in
+
+ # first virtual memory test
+
+ print ("set process table")
+ yield mmu.rin.prtbl.eq(0x1000000) # set process table
+ yield
+
+ # set address to zero, update mem[0] to 01234
+ addr = 8
+ expected_insn = 0x1234
+ mem[addr] = expected_insn
+
+ yield i_in.priv_mode.eq(1)
+ yield i_in.req.eq(0)
+ yield i_in.nia.eq(addr)
+ yield i_in.stop_mark.eq(0)
+ yield i_m_in.tlbld.eq(0)
+ yield i_m_in.tlbie.eq(0)
+ yield i_m_in.addr.eq(0)
+ yield i_m_in.pte.eq(0)
+ yield
+ yield
+ yield
+
+ # miss, stalls for a bit
+ yield i_in.req.eq(1)
+ yield i_in.nia.eq(addr)
+ yield
+ valid = yield i_out.valid
+ while not valid:
+ yield
+ valid = yield i_out.valid
+ yield i_in.req.eq(0)
+
+ nia = yield i_out.nia
+ insn = yield i_out.insn
+ yield
+ yield
+
+ print ("fetched %x from addr %x" % (insn, nia))
+ assert insn == expected_insn
+
+ print("=== test loadstore instruction (virtual) ===")
+
+ # look up i-cache expecting it to fail
+
+ # set address to 0x10200, update mem[] to 5678
+ virt_addr = 0x10200
+ real_addr = virt_addr
+ expected_insn = 0x5678
+ mem[real_addr] = expected_insn
+
+ yield i_in.priv_mode.eq(1)
+ yield i_in.virt_mode.eq(1)
+ yield i_in.req.eq(0)
+ yield i_in.nia.eq(virt_addr)
+ yield i_in.stop_mark.eq(0)
+ yield i_m_in.tlbld.eq(0)
+ yield i_m_in.tlbie.eq(0)
+ yield i_m_in.addr.eq(0)
+ yield i_m_in.pte.eq(0)
+ yield
+ yield
+ yield
+
+ # miss, stalls for a bit
+ yield i_in.req.eq(1)
+ yield i_in.nia.eq(virt_addr)
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ while not valid and not failed:
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ yield i_in.req.eq(0)
+
+ print ("failed?", "yes" if failed else "no")
+ assert failed == 1
+ yield
+ yield
+
+ print("=== test loadstore instruction (instruction fault) ===")
+
+ virt_addr = 0x10200
+
+ yield ldst.priv_mode.eq(1)
+ yield ldst.instr_fault.eq(1)
+ yield ldst.maddr.eq(virt_addr)
+ #ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr_pr=1)
+ yield
+ yield ldst.instr_fault.eq(0)
+ while True:
+ done = yield (ldst.done)
+ exc_info = yield from get_exception_info(pi.exc_o)
+ if done or exc_info.happened:
+ break
+ yield
+ assert exc_info.happened == 0 # assert just before doing the fault set zero
+ yield ldst.instr_fault.eq(0)
+ yield
+ yield
+ yield
+
+ print("=== test loadstore instruction (try instruction again) ===")
+ # set address to 0x10200, update mem[] to 5678
+ virt_addr = 0x10200
+ real_addr = virt_addr
+ expected_insn = 0x5678
+
+ yield i_in.priv_mode.eq(1)
+ yield i_in.virt_mode.eq(1)
+ yield i_in.req.eq(0)
+ yield i_in.nia.eq(virt_addr)
+ yield i_in.stop_mark.eq(0)
+ yield i_m_in.tlbld.eq(0)
+ yield i_m_in.tlbie.eq(0)
+ yield i_m_in.addr.eq(0)
+ yield i_m_in.pte.eq(0)
+ yield
+ yield
+ yield
+
+ # miss, stalls for a bit
+ yield i_in.req.eq(1)
+ yield i_in.nia.eq(virt_addr)
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ while not valid and not failed:
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ yield i_in.req.eq(0)
+ nia = yield i_out.nia
+ insn = yield i_out.insn
+ yield
+ yield
+
+ print ("failed?", "yes" if failed else "no")
+ assert failed == 0
+
+ print ("fetched %x from addr %x" % (insn, nia))
+ assert insn == expected_insn
+
+ wbget.stop = True
+
+
def _test_loadstore1_invalid(dut, mem):
mmu = dut.submodules.mmu
pi = dut.submodules.ldst.pi
wbget.stop = True
+def _test_loadstore1_ifetch_invalid(dut, mem):
+ mmu = dut.submodules.mmu
+ ldst = dut.submodules.ldst
+ pi = ldst.pi
+ icache = dut.submodules.ldst.icache
+ wbget.stop = False
+
+ print("=== test loadstore instruction (invalid) ===")
+
+ i_in = icache.i_in
+ i_out = icache.i_out
+ i_m_in = icache.m_in
+
+ # first virtual memory test
+
+ print ("set process table")
+ yield mmu.rin.prtbl.eq(0x1000000) # set process table
+ yield
+
+ # set address to zero, update mem[0] to 01234
+ addr = 8
+ expected_insn = 0x1234
+ mem[addr] = expected_insn
+
+ yield i_in.priv_mode.eq(1)
+ yield i_in.req.eq(0)
+ yield i_in.nia.eq(addr)
+ yield i_in.stop_mark.eq(0)
+ yield i_m_in.tlbld.eq(0)
+ yield i_m_in.tlbie.eq(0)
+ yield i_m_in.addr.eq(0)
+ yield i_m_in.pte.eq(0)
+ yield
+ yield
+ yield
+
+ # some more cycles for gtkwave debugging
+ yield
+ yield
+ yield
+
+ wbget.stop = True
+ return
+ # TODO: implement rest
+
+ # miss, stalls for a bit
+ yield i_in.req.eq(1)
+ yield i_in.nia.eq(addr)
+ yield
+ valid = yield i_out.valid
+ while not valid:
+ yield
+ valid = yield i_out.valid
+ yield i_in.req.eq(0)
+
+ nia = yield i_out.nia
+ insn = yield i_out.insn
+ yield
+ yield
+
+ print ("fetched %x from addr %x" % (insn, nia))
+ assert insn == expected_insn
+
+ print("=== test loadstore instruction (virtual) ===")
+
+ # look up i-cache expecting it to fail
+
+ # set address to 0x10200, update mem[] to 5678
+ virt_addr = 0x10200
+ real_addr = virt_addr
+ expected_insn = 0x5678
+ mem[real_addr] = expected_insn
+
+ yield i_in.priv_mode.eq(1)
+ yield i_in.virt_mode.eq(1)
+ yield i_in.req.eq(0)
+ yield i_in.nia.eq(virt_addr)
+ yield i_in.stop_mark.eq(0)
+ yield i_m_in.tlbld.eq(0)
+ yield i_m_in.tlbie.eq(0)
+ yield i_m_in.addr.eq(0)
+ yield i_m_in.pte.eq(0)
+ yield
+ yield
+ yield
+
+ # miss, stalls for a bit
+ yield i_in.req.eq(1)
+ yield i_in.nia.eq(virt_addr)
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ while not valid and not failed:
+ yield
+ valid = yield i_out.valid
+ failed = yield i_out.fetch_failed
+ yield i_in.req.eq(0)
+
+ print ("failed?", "yes" if failed else "no")
+ assert failed == 1
+ yield
+ yield
+
+
+def test_loadstore1_ifetch():
+
+ m, cmpi = setup_mmu()
+
+ mem = pagetables.test1
+
+ # nmigen Simulation
+ sim = Simulator(m)
+ sim.add_clock(1e-6)
+
+ icache = m.submodules.ldst.icache
+ sim.add_sync_process(wrap(_test_loadstore1_ifetch(m, mem)))
+ # add two wb_get processes onto the *same* memory dictionary.
+ # this shouuuld work.... cross-fingers...
+ sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
+ sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
+ with sim.write_vcd('test_loadstore1_ifetch.vcd'):
+ sim.run()
+
+
def test_loadstore1():
m, cmpi = setup_mmu()
with sim.write_vcd('test_loadstore1_invalid.vcd'):
sim.run()
+def test_loadstore1_ifetch_invalid():
+ m, cmpi = setup_mmu()
+
+ mem = {}
+
+ # nmigen Simulation
+ sim = Simulator(m)
+ sim.add_clock(1e-6)
+
+ icache = m.submodules.ldst.icache
+ sim.add_sync_process(wrap(_test_loadstore1_ifetch_invalid(m, mem)))
+ # add two wb_get processes onto the *same* memory dictionary.
+ # this shouuuld work.... cross-fingers...
+ sim.add_sync_process(wrap(wb_get(cmpi.wb_bus(), mem)))
+ sim.add_sync_process(wrap(wb_get(icache.bus, mem)))
+ with sim.write_vcd('test_loadstore1_ifetch_invalid.vcd'):
+ sim.run()
+
+
if __name__ == '__main__':
- test_loadstore1()
- test_loadstore1_invalid()
+ #test_loadstore1()
+ #test_loadstore1_invalid()
+ #test_loadstore1_ifetch()
+ test_loadstore1_ifetch_invalid()