get qemu operational single-step mode, use in pypowersim
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 27 May 2021 08:51:05 +0000 (09:51 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 27 May 2021 09:04:53 +0000 (10:04 +0100)
src/openpower/decoder/isa/pypowersim.py
src/openpower/simulator/program.py
src/openpower/simulator/qemu.py

index 606d5c89c5cb5ea1644156bdfdca82a3f52f5754..14a4c53c40a280ca1915a4599e38c41ff6b76e02 100644 (file)
@@ -10,6 +10,7 @@ from openpower.decoder.selectable_int import SelectableInt
 from openpower.decoder.orderedset import OrderedSet
 from openpower.decoder.isa.all import ISA
 from openpower.util import log
+from openpower.simulator.qemu import run_program
 
 
 def read_data(fname, offset=0):
@@ -87,16 +88,45 @@ def read_entries(fname, listqty=None):
 
     return result
 
-
-def run_tst(args, generator, initial_regs,
+def qemu_register_compare(sim, qemu, regs):
+    qpc, qxer, qcr = qemu.get_pc(), qemu.get_xer(), qemu.get_cr()
+    sim_cr = sim.cr.value
+    sim_pc = sim.pc.CIA.value
+    sim_xer = sim.spr['XER'].value
+    print("qemu pc", hex(qpc))
+    print("qemu cr", hex(qcr))
+    print("qemu xer", bin(qxer))
+    print("sim nia", hex(sim.pc.NIA.value))
+    print("sim pc", hex(sim.pc.CIA.value))
+    print("sim cr", hex(sim_cr))
+    print("sim xer", hex(sim_xer))
+    #self.assertEqual(qpc, sim_pc)
+    for reg in regs:
+        qemu_val = qemu.get_register(reg)
+        sim_val = sim.gpr(reg).value
+        log("expect %x got %x" % (qemu_val, sim_val))
+        #self.assertEqual(qemu_val, sim_val,
+        #                 "expect %x got %x" % (qemu_val, sim_val))
+    #self.assertEqual(qcr, sim_cr)
+
+
+def run_tst(args, generator, qemu,
+                             initial_regs,
                              initial_sprs=None, svstate=0, mmu=False,
                              initial_cr=0, mem=None,
-                             initial_fprs=None):
+                             initial_fprs=None,
+                             initial_pc=0):
     if initial_regs is None:
         initial_regs = [0] * 32
     if initial_sprs is None:
         initial_sprs = {}
 
+    if qemu:
+        log("qemu program", generator.binfile.name)
+        qemu = run_program(generator, initial_mem=mem, 
+                bigendian=False, start_addr=initial_pc,
+                continuous_run=False)
+
     m = Module()
     comb = m.d.comb
     instruction = Signal(32)
@@ -115,9 +145,10 @@ def run_tst(args, generator, initial_regs,
 
     m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
     simulator = ISA(pdecode2, initial_regs, initial_sprs, initial_cr,
-                    initial_insns=gen, respect_pc=True,
+                    initial_insns=(initial_pc, gen), respect_pc=True,
                     initial_svstate=svstate,
                     initial_mem=mem,
+                    initial_pc=initial_pc,
                     fpregfile=initial_fprs,
                     disassembly=insncode,
                     bigendian=0,
@@ -130,7 +161,7 @@ def run_tst(args, generator, initial_regs,
         yield pdecode2.dec.bigendian.eq(0)  # little / big?
         pc = simulator.pc.CIA.value
         index = pc//4
-        while index < len(instructions) and not simulator.halted:
+        while not simulator.halted:
             log("instr pc", pc)
             try:
                 yield from simulator.setup_one()
@@ -138,19 +169,31 @@ def run_tst(args, generator, initial_regs,
                 break
             yield Settle()
 
-            ins = instructions[index]
-            if isinstance(ins, list):
-                ins, code = ins
-                log("    0x{:X}".format(ins & 0xffffffff))
-                opname = code.split(' ')[0]
-                log(code, opname)
-            else:
-                log("    0x{:X}".format(ins & 0xffffffff))
+            if False:
+                ins = instructions[index]
+                if isinstance(ins, list):
+                    ins, code = ins
+                    log("    0x{:X}".format(ins & 0xffffffff))
+                    opname = code.split(' ')[0]
+                    log(code, opname)
+                else:
+                    log("    0x{:X}".format(ins & 0xffffffff))
 
             # ask the decoder to decode this binary data (endian'd)
             yield from simulator.execute_one()
-            pc = simulator.pc.CIA.value
-            index = pc//4
+            #pc = simulator.pc.CIA.value
+            #index = pc//4
+
+            if not qemu:
+                continue
+
+            # check qemu co-sim: run one instruction
+            qemu.step()
+            qemu_register_compare(simulator, qemu, range(32))
+
+        # cleanup
+        if qemu:
+            qemu.exit()
 
     sim.add_process(process)
     sim.run()
@@ -166,6 +209,8 @@ def help():
     print ("-s --spregs=   colon-separated file with SPR values")
     print ("-l --load=     filename:address to load binary into memory")
     print ("-d --dump=     filename:address:len to binary save from memory")
+    print ("-q --qemu=     run qemu co-simulation")
+    print ("-p --pc=       set initial program counter")
     print ("-h --help      prints this message")
     print ("notes:")
     print ("load and dump may be given multiple times")
@@ -186,12 +231,14 @@ def run_simulation():
     initial_fprs = [0]*32
     initial_sprs = None
     initial_mem = {}
+    initial_pc = 0x0
     lst = None
+    qemu_cosim = False
     write_to = []
 
     try:
-        opts, args = getopt.getopt(sys.argv[1:], "hi:a:g:f:s:l:d:",
-                                   ["help",
+        opts, args = getopt.getopt(sys.argv[1:], "qhi:a:g:f:s:l:d:p:",
+                                   ["qemu", "help", "pc=",
                                     "binary=", "listing=",
                                     "intregs=", "fpregs=", "sprs=",
                                     "load=", "dump="])
@@ -203,8 +250,12 @@ def run_simulation():
     for opt, arg in opts:
         if opt in ['-h', '--help']:
             help()
+        elif opt in ['-q', '--qemu']:
+            qemu_cosim = True
         elif opt in ['-i', '--binary']:
             binaryname = arg
+        elif opt in ['-p', '--pc']:
+            initial_pc = convert_to_num(arg)
         elif opt in ['-a', '--listing']:
             lst = arg
         elif opt in ['-g', '--intregs']:
@@ -248,13 +299,14 @@ def run_simulation():
         with open(binaryname, "rb") as f:
             lst = f.read()
 
-    with Program(lst, bigendian=False) as prog:
-        simulator = run_tst(None, prog,
+    with Program(lst, bigendian=False, orig_filename=binaryname) as prog:
+        simulator = run_tst(None, prog, qemu_cosim,
                             initial_regs,
                             initial_sprs=initial_sprs,
                             svstate=0, mmu=False,
                             initial_cr=0, mem=initial_mem,
-                            initial_fprs=initial_fprs)
+                            initial_fprs=initial_fprs,
+                            initial_pc=initial_pc)
         print ("GPRs")
         simulator.gpr.dump()
         print ("FPRs")
index 96747e1b56d618860ad5948700e0b2f1112b7a91..c2b4adbe1f6acdd1360629e6ac343eb4a9c19881 100644 (file)
@@ -22,7 +22,7 @@ memmap = os.path.join(filedir, "memmap")
 
 
 class Program:
-    def __init__(self, instructions, bigendian):
+    def __init__(self, instructions, bigendian, orig_filename=None):
         self.bigendian = bigendian
         if self.bigendian:
             self.endian_fmt = "elf64-big"
@@ -35,7 +35,10 @@ class Program:
 
         if isinstance(instructions, bytes):  # actual bytes
             self.binfile = BytesIO(instructions)
-            self.binfile.name = "assembly"
+            if orig_filename is None:
+                self.binfile.name = "bytes"
+            else:
+                self.binfile.name = orig_filename
             self.assembly = ''  # noo disassemble number fiiive
             print("binary", self.binfile)
         elif isinstance(instructions, str):  # filename
index c4511e122eb85d9bb3d8519d9f2175fc6fdba3eb..8a0625dff6e88e51b8a518cdb715554b4cf75fba 100644 (file)
@@ -106,7 +106,7 @@ class QemuController:
         return self._get_register('x {}'.format(num))
 
     def step(self):
-        return self.gdb.write('-exec-next-instruction')
+        return self.gdb.write('-exec-step-instruction')
 
     def gdb_continue(self):
         return self.gdb.write('-exec-continue')
@@ -121,22 +121,29 @@ class QemuController:
         self.qemu_popen.stdout.close()
         self.qemu_popen.stdin.close()
 
+    def upload_mem(self, initial_mem):
+        for addr, (v, wid) in initial_mem.items():
+            for i in range(wid):
+                # sigh byte-level loads, veery slow
+                self.set_byte(addr+i, (v >> i*8) & 0xff)
+
 
 def run_program(program, initial_mem=None, extra_break_addr=None,
-                bigendian=False):
+                bigendian=False, start_addr=0x20000000, init_endian=True,
+                continuous_run=True):
     q = QemuController(program.binfile.name, bigendian)
     q.connect()
-    q.set_endian(True)  # easier to set variables this way
-
-    # Run to the start of the program
+    q.set_endian(init_endian)  # easier to set variables this way
     if initial_mem:
-        for addr, (v, wid) in initial_mem.items():
-            for i in range(wid):
-                q.set_byte(addr+i, (v >> i*8) & 0xff)
+        q.upload_mem(initial_mem)
 
-    # set breakpoint at start
-    q.break_address(0x20000000)
+    # Run to the start of the program
+    q.gdb_eval('$pc=%d' % start_addr)
+    pc = q.get_pc()
+    print("pc", bigendian, hex(pc))
+    q.break_address(start_addr) # set breakpoint at start
     q.gdb_continue()
+
     # set the MSR bit 63, to set bigendian/littleendian mode
     msr = q.get_msr()
     print("msr", bigendian, hex(msr))
@@ -151,14 +158,17 @@ def run_program(program, initial_mem=None, extra_break_addr=None,
     q.gdb_eval('$cr=0')
     # delete the previous breakpoint so loops don't screw things up
     q.delete_breakpoint()
-    # run to completion
-    q.break_address(0x20000000 + program.size())
-    # or to trap
+    # allow run to end
+    q.break_address(start_addr + program.size())
+    # or to trap (not ideal)
     q.break_address(0x700)
     # or to alternative (absolute) address)
-    if extra_break_addr:
+    if extra_break_addr is not None:
         q.break_address(extra_break_addr)
-    q.gdb_continue()
+    if continuous_run:
+        q.gdb_continue()
+    else:
+        q.step()
     q.set_endian(bigendian)
 
     return q