From a6b44dadcc5867d683849e3420708babfd237364 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 27 May 2021 09:51:05 +0100 Subject: [PATCH] get qemu operational single-step mode, use in pypowersim --- src/openpower/decoder/isa/pypowersim.py | 92 +++++++++++++++++++------ src/openpower/simulator/program.py | 7 +- src/openpower/simulator/qemu.py | 40 +++++++---- 3 files changed, 102 insertions(+), 37 deletions(-) diff --git a/src/openpower/decoder/isa/pypowersim.py b/src/openpower/decoder/isa/pypowersim.py index 606d5c89..14a4c53c 100644 --- a/src/openpower/decoder/isa/pypowersim.py +++ b/src/openpower/decoder/isa/pypowersim.py @@ -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") diff --git a/src/openpower/simulator/program.py b/src/openpower/simulator/program.py index 96747e1b..c2b4adbe 100644 --- a/src/openpower/simulator/program.py +++ b/src/openpower/simulator/program.py @@ -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 diff --git a/src/openpower/simulator/qemu.py b/src/openpower/simulator/qemu.py index c4511e12..8a0625df 100644 --- a/src/openpower/simulator/qemu.py +++ b/src/openpower/simulator/qemu.py @@ -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 -- 2.30.2