try to get multi test running
[soc.git] / src / soc / experiment / test / test_loadstore1.py
index 4e7ee7fe885ea0047dc1404ce668ff058150c94a..bafa51d936d6a1b7b681c6fea0dcd220199a59fb 100644 (file)
@@ -22,6 +22,10 @@ from nmigen.compat.sim import run_simulation
 from random import random
 from openpower.test.wb_get import wb_get
 from openpower.test import wb_get as wbget
+from openpower.exceptions import LDSTExceptionTuple
+
+from soc.config.test.test_fetch import read_from_addr
+from openpower.decoder.power_enums import MSRSpec
 
 
 def setup_mmu():
@@ -56,14 +60,149 @@ def setup_mmu():
     comb += l_in.eq(ldst.m_out)
     comb += ldst.m_in.eq(l_out)
 
+    # add a debug status Signal: use "msg.str = "blah"
+    # then toggle with yield msg.eq(0); yield msg.eq(1)
+    debug_status = Signal(8, decoder=lambda _ : debug_status.str)
+    m.debug_status = debug_status
+    debug_status.str = ''
+
     return m, cmpi
 
 
+def icache_read(dut,addr,priv,virt):
+
+    icache = dut.submodules.ldst.icache
+    i_in = icache.i_in
+    i_out  = icache.i_out
+
+    yield i_in.priv_mode.eq(priv)
+    yield i_in.virt_mode.eq(virt)
+    yield i_in.req.eq(1)
+    yield i_in.nia.eq(addr)
+    yield i_in.stop_mark.eq(0)
+
+    yield i_in.req.eq(1)
+    yield i_in.nia.eq(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
+
+    return nia, insn, valid, failed
+
+
 test_exceptions = True
 test_dcbz = True
 test_random = True
 
 
+def debug(dut, msg):
+    print ("set debug message", msg)
+    dut.debug_status.str = msg # set the message
+    yield dut.debug_status.eq(0) # trigger an update
+    yield dut.debug_status.eq(1)
+
+
+def _test_loadstore1_ifetch_iface(dut, mem):
+    """test_loadstore1_ifetch_iface
+
+    read in priv mode, non-virtual.  tests the FetchUnitInterface
+
+    """
+
+    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
+
+    yield from debug(dut, "real mem instruction")
+    # set address to 0x8, update mem[0x8] to 01234 | 0x5678<<32
+    # (have to do 64-bit writes into the dictionary-memory-emulated-thing)
+    addr = 8
+    addr2 = 12
+    expected_insn2 = 0x5678
+    expected_insn = 0x1234
+    mem[addr] = expected_insn | expected_insn2<<32
+
+    yield i_in.priv_mode.eq(1)
+    insn = yield from read_from_addr(icache, addr, stall=False)
+
+    nia   = yield i_out.nia  # NO, must use FetchUnitInterface
+    print ("fetched %x from addr %x" % (insn, nia))
+    assert insn == expected_insn
+
+    print("=== test loadstore instruction (2nd, real) ===")
+    yield from debug(dut, "real mem 2nd (addr 0xc)")
+
+    insn2 = yield from read_from_addr(icache, addr2, stall=False)
+
+    nia   = yield i_out.nia  # NO, must use FetchUnitInterface
+    print ("fetched %x from addr2 %x" % (insn2, nia))
+    assert insn2 == expected_insn2
+
+    print("=== test loadstore instruction (done) ===")
+
+    yield from debug(dut, "test done")
+    yield
+    yield
+
+    print ("fetched %x from addr %x" % (insn, nia))
+    assert insn == expected_insn
+
+    wbget.stop = True
+
+def _test_loadstore1_ifetch_multi(dut, mem):
+    mmu = dut.submodules.mmu
+    ldst = dut.submodules.ldst
+    pi = ldst.pi
+    icache = dut.submodules.ldst.icache
+    wbget.stop = False
+
+    i_in = icache.i_in
+    i_out  = icache.i_out
+    i_m_in = icache.m_in
+
+    yield from debug(dut, "TODO")
+    yield
+    yield
+    yield
+    # TODO fetch instructions from multiple addresses
+    # should cope with some addresses being invalid
+    addrs = [0,4,8,0,0x10200,0x10204,0x10208,0x10200]
+
+    mem[0x10200]=0xFF00FF00EE00EE00EE
+    mem[0]=0xFF00FF00EE00EE00EE
+
+    yield i_in.priv_mode.eq(1)
+
+    for addr in addrs:
+        yield from debug(dut, "BROKEN_fetch_from "+hex(addr))
+        # use the new interface in this test
+
+        #broken: does not use wishbone yet - investigate
+        insn = yield from read_from_addr(icache, addr, stall=False)
+
+        nia   = yield i_out.nia  # NO, must use FetchUnitInterface
+        print ("TEST_MULTI: fetched %x from addr %x == %x" % (insn, nia,addr))
+
+    wbget.stop = True
+
 def _test_loadstore1_ifetch(dut, mem):
     """test_loadstore1_ifetch
 
@@ -102,9 +241,11 @@ def _test_loadstore1_ifetch(dut, mem):
     # first virtual memory test
 
     print ("set process table")
+    yield from debug(dut, "set prtble")
     yield mmu.rin.prtbl.eq(0x1000000) # set process table
     yield
 
+    yield from debug(dut, "real mem instruction")
     # set address to zero, update mem[0] to 01234
     addr = 8
     expected_insn = 0x1234
@@ -122,7 +263,11 @@ def _test_loadstore1_ifetch(dut, mem):
     yield
     yield
 
-    # miss, stalls for a bit
+    # miss, stalls for a bit -- this one is different here
+    ##nia, insn, valid, failed = yield from icache_read(dut,addr,0,0)
+    ##assert(valid==0)
+    ##assert(failed==1)
+
     yield i_in.req.eq(1)
     yield i_in.nia.eq(addr)
     yield
@@ -144,6 +289,7 @@ def _test_loadstore1_ifetch(dut, mem):
 
     # look up i-cache expecting it to fail
 
+    yield from debug(dut, "virtual instr req")
     # set address to 0x10200, update mem[] to 5678
     virt_addr = 0x10200
     real_addr = virt_addr
@@ -182,12 +328,16 @@ def _test_loadstore1_ifetch(dut, mem):
 
     print("=== test loadstore instruction (instruction fault) ===")
 
+    yield from debug(dut, "instr fault")
+
     virt_addr = 0x10200
 
     yield ldst.priv_mode.eq(0)
     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)
+    # still broken -- investigate
+    # msr = MSRSpec(pr=?, dr=?, sf=0)
+    # ld_data, exctype, exc = yield from pi_ld(pi, virt_addr, 8, msr=msr)
     yield
     yield ldst.instr_fault.eq(0)
     while True:
@@ -203,6 +353,7 @@ def _test_loadstore1_ifetch(dut, mem):
     yield
 
     print("=== test loadstore instruction (try instruction again) ===")
+    yield from debug(dut, "instr virt retry")
     # set address to 0x10200, update mem[] to 5678
     virt_addr = 0x10200
     real_addr = virt_addr
@@ -222,6 +373,7 @@ def _test_loadstore1_ifetch(dut, mem):
     yield
 
     # miss, stalls for a bit
+    """
     yield i_in.req.eq(1)
     yield i_in.nia.eq(virt_addr)
     yield
@@ -234,6 +386,12 @@ def _test_loadstore1_ifetch(dut, mem):
     yield i_in.req.eq(0)
     nia   = yield i_out.nia
     insn  = yield i_out.insn
+    """
+
+    ## part 4
+    nia, insn, valid, failed = yield from icache_read(dut,virt_addr,0,1)
+
+    yield from debug(dut, "test done")
     yield
     yield
 
@@ -254,7 +412,8 @@ def _test_loadstore1_invalid(dut, mem):
     print("=== test invalid ===")
 
     addr = 0
-    ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+    msr = MSRSpec(pr=1, dr=0, sf=0) # set problem-state
+    ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
     print("ld_data", ld_data, exctype, exc)
     assert (exctype == "slow")
     invalid = exc.invalid
@@ -278,23 +437,24 @@ def _test_loadstore1(dut, mem):
     data = 0xf553b658ba7e1f51
 
     if test_dcbz:
-        yield from pi_st(pi, addr, data, 8, msr_pr=1)
+        msr = MSRSpec(pr=0, dr=0, sf=0)
+        yield from pi_st(pi, addr, data, 8, msr=msr)
         yield
 
-        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
         assert ld_data == 0xf553b658ba7e1f51
         assert exctype is None
 
-        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
         assert ld_data == 0xf553b658ba7e1f51
         assert exctype is None
 
         print("do_dcbz ===============")
-        yield from pi_st(pi, addr, data, 8, msr_pr=1, is_dcbz=1)
+        yield from pi_st(pi, addr, data, 8, msr=msr, is_dcbz=1)
         print("done_dcbz ===============")
         yield
 
-        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
         print("ld_data after dcbz")
         print(ld_data)
         assert ld_data == 0
@@ -303,7 +463,7 @@ def _test_loadstore1(dut, mem):
     if test_exceptions:
         print("=== alignment error (ld) ===")
         addr = 0xFF100e0FF
-        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
         if exc:
             alignment = exc.alignment
             happened = exc.happened
@@ -330,7 +490,7 @@ def _test_loadstore1(dut, mem):
 
         print("=== alignment error (st) ===")
         addr = 0xFF100e0FF
-        exctype, exc = yield from pi_st(pi, addr,0, 8, msr_pr=1)
+        exctype, exc = yield from pi_st(pi, addr,0, 8, msr=msr)
         if exc:
             alignment = exc.alignment
             happened = exc.happened
@@ -349,7 +509,7 @@ def _test_loadstore1(dut, mem):
     if True:
         print("=== no alignment error (ld) ===")
         addr = 0x100e0
-        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+        ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
         print("ld_data", ld_data, exctype, exc)
         if exc:
             alignment = exc.alignment
@@ -366,19 +526,19 @@ def _test_loadstore1(dut, mem):
 
         for addr in addrs:
             print("== RANDOM addr ==",hex(addr))
-            ld_data, exctype, exc  = yield from pi_ld(pi, addr, 8, msr_pr=1)
+            ld_data, exctype, exc  = yield from pi_ld(pi, addr, 8, msr=msr)
             print("ld_data[RANDOM]",ld_data,exc,addr)
             assert (exctype == None)
 
         for addr in addrs:
             print("== RANDOM addr ==",hex(addr))
-            exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr_pr=1)
+            exc = yield from pi_st(pi, addr,0xFF*addr, 8, msr=msr)
             assert (exctype == None)
 
         # readback written data and compare
         for addr in addrs:
             print("== RANDOM addr ==",hex(addr))
-            ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr_pr=1)
+            ld_data, exctype, exc = yield from pi_ld(pi, addr, 8, msr=msr)
             print("ld_data[RANDOM_READBACK]",ld_data,exc,addr)
             assert (exctype == None)
             assert (ld_data == 0xFF*addr)
@@ -404,9 +564,11 @@ def _test_loadstore1_ifetch_invalid(dut, mem):
     # first virtual memory test
 
     print ("set process table")
+    yield from debug(dut, "set prtbl")
     yield mmu.rin.prtbl.eq(0x1000000) # set process table
     yield
 
+    yield from debug(dut, "real mem instruction")
     # set address to zero, update mem[0] to 01234
     addr = 8
     expected_insn = 0x1234
@@ -424,20 +586,12 @@ def _test_loadstore1_ifetch_invalid(dut, mem):
     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
+    nia   = yield i_out.nia
     while not valid:
         yield
         valid = yield i_out.valid
@@ -445,6 +599,7 @@ def _test_loadstore1_ifetch_invalid(dut, mem):
 
     nia   = yield i_out.nia
     insn  = yield i_out.insn
+
     yield
     yield
 
@@ -452,6 +607,7 @@ def _test_loadstore1_ifetch_invalid(dut, mem):
     assert insn == expected_insn
 
     print("=== test loadstore instruction (virtual) ===")
+    yield from debug(dut, "virtual instr req")
 
     # look up i-cache expecting it to fail
 
@@ -491,6 +647,77 @@ def _test_loadstore1_ifetch_invalid(dut, mem):
     yield
     yield
 
+    print("=== test invalid loadstore instruction (instruction fault) ===")
+
+    yield from debug(dut, "instr fault (perm err expected)")
+    virt_addr = 0x10200
+
+    yield ldst.priv_mode.eq(0)
+    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=msr)
+    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 == 1 # different here as expected
+
+    # TODO: work out what kind of exception occurred and check it's
+    # the right one.  we *expect* it to be a permissions error because
+    # the RPTE leaf node in pagetables.test2 is marked as "non-executable"
+    # but we also expect instr_fault to be set because it is an instruction
+    # (iside) lookup
+    print ("   MMU lookup exception type?")
+    for fname in LDSTExceptionTuple._fields:
+        print ("   fname %20s %d" % (fname, getattr(exc_info, fname)))
+
+    # ok now printed them out and visually inspected: check them with asserts
+    assert exc_info.instr_fault == 1 # instruction fault (yes!)
+    assert exc_info.perm_error == 1 # permissions (yes!)
+    assert exc_info.rc_error == 0
+    assert exc_info.alignment == 0
+    assert exc_info.invalid == 0
+    assert exc_info.segment_fault == 0
+    assert exc_info.rc_error == 0
+
+    yield from debug(dut, "test done")
+    yield ldst.instr_fault.eq(0)
+    yield
+    yield
+    yield
+
+    wbget.stop = True
+
+
+def test_loadstore1_ifetch_unit_iface():
+
+    m, cmpi = setup_mmu()
+
+    mem = pagetables.test1
+
+    # set this up before passing to Simulator (which calls elaborate)
+    icache = m.submodules.ldst.icache
+    icache.use_fetch_interface() # this is the function which converts
+                                 # to FetchUnitInterface. *including*
+                                 # rewiring the Wishbone Bus to ibus
+
+    # nmigen Simulation
+    sim = Simulator(m)
+    sim.add_clock(1e-6)
+
+    sim.add_sync_process(wrap(_test_loadstore1_ifetch_iface(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.ibus, mem))) # ibus not bus
+    with sim.write_vcd('test_loadstore1_ifetch_iface.vcd',
+                      traces=[m.debug_status]): # include extra debug
+        sim.run()
+
 
 def test_loadstore1_ifetch():
 
@@ -508,7 +735,8 @@ def test_loadstore1_ifetch():
     # 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'):
+    with sim.write_vcd('test_loadstore1_ifetch.vcd',
+                      traces=[m.debug_status]): # include extra debug
         sim.run()
 
 
@@ -560,13 +788,37 @@ def test_loadstore1_ifetch_invalid():
     # 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'):
+    with sim.write_vcd('test_loadstore1_ifetch_invalid.vcd',
+                      traces=[m.debug_status]): # include extra debug
         sim.run()
 
+def test_loadstore1_ifetch_multi():
+    m, cmpi = setup_mmu()
+
+    # this is a specially-arranged page table which has the permissions
+    # barred for execute on the leaf node (EAA=0x2 instead of EAA=0x3)
+    mem = pagetables.test1
 
+    # nmigen Simulation
+    sim = Simulator(m)
+    sim.add_clock(1e-6)
+
+    icache = m.submodules.ldst.icache
+    icache.use_fetch_interface() # see test_loadstore1_ifetch_unit_iface():
+
+    sim.add_sync_process(wrap(_test_loadstore1_ifetch_multi(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.ibus, mem))) # ibus not bus
+    with sim.write_vcd('test_loadstore1_ifetch_multi.vcd',
+                      traces=[m.debug_status]): # include extra debug
+        sim.run()
 
 if __name__ == '__main__':
-    #test_loadstore1()
-    #test_loadstore1_invalid()
-    #test_loadstore1_ifetch()
+    test_loadstore1()
+    test_loadstore1_invalid()
+    test_loadstore1_ifetch() #FIXME
     test_loadstore1_ifetch_invalid()
+    test_loadstore1_ifetch_multi()
+    test_loadstore1_ifetch_unit_iface()