1 from nmigen
import Module
, Signal
2 from nmigen
.sim
import Simulator
, Delay
, Settle
6 from openpower
.decoder
.power_decoder
import create_pdecode
7 from openpower
.decoder
.power_decoder2
import (PowerDecode2
)
8 from openpower
.simulator
.program
import Program
9 from openpower
.decoder
.selectable_int
import SelectableInt
10 from openpower
.decoder
.orderedset
import OrderedSet
11 from openpower
.decoder
.isa
.all
import ISA
12 from openpower
.util
import log
13 from openpower
.simulator
.qemu
import run_program
16 def read_data(fname
, offset
=0):
17 """reads binary data and returns a dictionary of address: contents,
18 each entry is 8 bytes: input file *must* contain a multiple of 8 bytes.
19 data to be considered *binary* (raw)
22 with
open(fname
, "rb") as f
:
28 res
[offset
] = struct
.unpack('<Q', b
)[0] # unsigned long
31 def write_data(mem
, fname
, offset
, sz
):
32 """writes binary data to a file, each entry must be 8 bytes
34 with
open(fname
, "wb") as f
:
35 for i
in range(0, sz
, 8):
38 f
.write(struct
.pack('>Q', val
)) # unsigned long
40 def sim_check_data(simulator
, qemu
, check_addr
, msg
):
41 addr
= check_addr
& ~
0x7 # align
42 sim_data
= simulator
.mem
.ld(addr
, 8, swap
=False)
43 qdata
= qemu
.get_mem(addr
, 8)[0]
44 log ("last", msg
, hex(check_addr
), hex(sim_data
), hex(qdata
))
46 log("expect mem %x, %x got %x" % (addr
, qdata
, sim_data
))
49 def convert_to_num(num
):
53 if num
.startswith("0b"):
54 return int(num
[2:], 2)
55 if num
.startswith("0x"):
56 return int(num
[2:], 16)
60 def read_entries(fname
, listqty
=None):
61 """read_entries: reads values from a file of the format "x: y", per line
62 can be used for memory, or regfiles (GPR, SPR, FP). regs and entries may
63 start with "0x" or "0b" for hex or binary
67 with
open(fname
) as f
:
68 for line
in f
.readlines():
70 if line
.startswith("#"):
72 line
= line
.split("#")[0]
73 # split line "x : y" into ["x", "y"], remove spaces
74 line
= list(map(str.strip
, line
.strip().split(":")))
75 assert len(line
) == 2, "regfile line must be formatted 'x : y'"
76 # check and convert format
78 reg
= convert_to_num(reg
)
79 val
= convert_to_num(val
)
80 assert reg
not in regs
, "duplicate entry %s" % (repr(reg
))
81 allints
= allints
and isinstance(reg
, int)
88 # post-process into a list.
91 result
= [0] * listqty
92 for reg
, value
in regs
.items():
93 assert isinstance(reg
, int), "list must be int, %s found" % reg
94 assert reg
< listqty
, "entry %s too large for list %s" % (reg
, listqty
)
100 def qemu_register_compare(sim
, q
, regs
, fprs
):
101 qpc
, qxer
, qcr
, qlr
= q
.get_pc(), q
.get_xer(), q
.get_cr(), q
.get_lr()
102 sim_cr
= sim
.cr
.value
103 sim_pc
= sim
.pc
.CIA
.value
104 sim_xer
= sim
.spr
['XER'].value
105 sim_lr
= sim
.spr
['LR'].value
106 print("qemu pc", hex(qpc
))
107 print("qemu cr", hex(qcr
))
108 print("qemu lr", hex(qlr
))
109 print("qemu xer", bin(qxer
))
110 print("sim nia", hex(sim
.pc
.NIA
.value
))
111 print("sim pc", hex(sim
.pc
.CIA
.value
))
112 print("sim cr", hex(sim_cr
))
113 print("sim xer", hex(sim_xer
))
114 print("sim lr", hex(sim_lr
))
115 #self.assertEqual(qpc, sim_pc)
117 qemu_val
= q
.get_gpr(reg
)
118 sim_val
= sim
.gpr(reg
).value
119 if qemu_val
!= sim_val
:
120 log("expect gpr %d %x got %x" % (reg
, qemu_val
, sim_val
))
121 #self.assertEqual(qemu_val, sim_val,
122 # "expect %x got %x" % (qemu_val, sim_val))
124 qemu_val
= q
.get_fpr(fpr
)
125 sim_val
= sim
.fpr(fpr
).value
126 if qemu_val
!= sim_val
:
127 log("expect fpr %d %x got %x" % (fpr
, qemu_val
, sim_val
))
128 #self.assertEqual(qemu_val, sim_val,
129 # "expect %x got %x" % (qemu_val, sim_val))
130 #self.assertEqual(qcr, sim_cr)
133 def run_tst(args
, generator
, qemu
,
135 initial_sprs
=None, svstate
=0, mmu
=False,
136 initial_cr
=0, mem
=None,
139 if initial_regs
is None:
140 initial_regs
= [0] * 32
141 if initial_sprs
is None:
145 log("qemu program", generator
.binfile
.name
)
146 qemu
= run_program(generator
, initial_mem
=mem
,
147 bigendian
=False, start_addr
=initial_pc
,
148 continuous_run
=False, initial_sprs
=initial_sprs
,
149 initial_regs
=initial_regs
, initial_fprs
=initial_fprs
)
150 for reg
, val
in qemu
._get
_registers
().items():
151 log ("qemu reg", reg
, hex(val
))
153 offs
, length
= 0x200000, 0x200
154 qmem
= qemu
.get_mem(offs
, length
)
155 log("qemu mem pre-dump", hex(offs
), length
)
156 for i
, data
in enumerate(qmem
):
157 log(hex(offs
+i
*8), hex(data
))
161 instruction
= Signal(32)
163 pdecode
= create_pdecode(include_fp
=initial_fprs
is not None)
165 gen
= list(generator
.generate_instructions())
166 log ("instructions gen", gen
)
167 insncode
= generator
.assembly
.splitlines()
169 instructions
= list(zip(gen
, insncode
))
173 log ("instructions", instructions
)
175 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
176 simulator
= ISA(pdecode2
, initial_regs
, initial_sprs
, initial_cr
,
177 initial_insns
=(initial_pc
, gen
), respect_pc
=True,
178 initial_svstate
=svstate
,
180 initial_pc
=initial_pc
,
181 fpregfile
=initial_fprs
,
182 disassembly
=insncode
,
185 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
190 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
191 pc
= simulator
.pc
.CIA
.value
194 # rather awkward: qemu will go wonky if stepped over the
195 # last instruction. use ISACaller to check if this is
196 # the last instruction, and leave qemu pointing at it
197 # rather than trigger an exception in the remote-qemu program
199 _pc
, _ins
= simulator
.get_next_insn()
200 except KeyError: # indicates instruction not in imem: stop
203 while not simulator
.halted
:
205 yield from simulator
.setup_next_insn(_pc
, _ins
)
209 ins
= instructions
[index
]
210 if isinstance(ins
, list):
212 log(" 0x{:X}".format(ins
& 0xffffffff))
213 opname
= code
.split(' ')[0]
216 log(" 0x{:X}".format(ins
& 0xffffffff))
218 # ask the decoder to decode this binary data (endian'd)
219 yield from simulator
.execute_one()
220 #pc = simulator.pc.CIA.value
225 _pc
, _ins
= simulator
.get_next_insn()
226 except KeyError: # indicates instruction not in imem: stop
230 # check qemu co-sim: run one instruction, but first check
231 # in ISACaller if there *is* a next instruction. if there
232 # is, "recover" qemu by switching bigendian back
234 _pc
, _ins
= simulator
.get_next_insn()
235 except KeyError: # indicates instruction not in imem: stop
236 _pc
, _insn
= (None, None)
238 if not _pc
or simulator
.halted
:
239 qemu
.set_endian(False)
240 qemu_register_compare(simulator
, qemu
, range(32), range(32))
241 # check last store address
243 if simulator
.last_st_addr
is not None:
244 check_addr
= simulator
.last_st_addr
246 if simulator
.last_ld_addr
is not None:
247 check_addr
= simulator
.last_ld_addr
249 if check_addr
is not None:
250 sim_check_data(simulator
, qemu
, check_addr
, msg
)
251 sim_check_data(simulator
, qemu
, 0x600800, "dbgld")
255 sim
.add_process(process
)
258 return simulator
, qemu
262 print ("-i --binary= raw (non-ELF) bare metal executable, loaded at 0x0")
263 print ("-a --listing= file containing bare-metal assembler (no macros)")
264 print ("-g --intregs= colon-separated file with GPR values")
265 print ("-f --fpregs= colon-separated file with FPR values")
266 print ("-s --spregs= colon-separated file with SPR values")
267 print ("-l --load= filename:address to load binary into memory")
268 print ("-d --dump= filename:address:len to binary save from memory")
269 print ("-q --qemu= run qemu co-simulation")
270 print ("-p --pc= set initial program counter")
271 print ("-h --help prints this message")
273 print ("load and dump may be given multiple times")
274 print ("load and dump must be 8-byte aligned sizes")
275 print ("loading SPRs accepts SPR names (e.g. LR, CTR, SRR0)")
276 print ("numbers may be integer, binary (0bNNN) or hex (0xMMM) but not FP")
277 print ("running ELF binaries: load SPRs, LR set to 0xffffffffffffffff")
278 print ("TODO: dump registers")
279 print ("TODO: load/dump PC, MSR, CR")
280 print ("TODO: print exec and sub-exec counters at end")
284 def run_a_simulation(binaryname
, bigendian
, prog
,
285 qemu_cosim
, initial_regs
,
286 initial_sprs
, svstate
, mmu
,
287 initial_cr
, initial_mem
,
288 initial_fprs
, initial_pc
):
290 log ("binaryname", binaryname
)
291 log ("bigendian", bigendian
)
293 log ("qemu_cosim", qemu_cosim
)
294 log ("initial_regs", initial_regs
)
295 log ("initial_sprs", initial_sprs
)
296 log ("svstate", svstate
)
298 log ("initial_cr", initial_cr
)
299 log ("initial_mem", initial_mem
)
300 log ("initial_fprs", initial_fprs
)
301 log ("initial_pc", initial_pc
)
303 with
open(binaryname
, "rb") as f
:
306 with
Program(binary
, bigendian
=bigendian
, orig_filename
=None) as prog
:
307 simulator
, qemu
= run_tst(None, prog
, qemu_cosim
,
309 initial_sprs
=initial_sprs
,
310 svstate
=svstate
, mmu
=mmu
,
311 initial_cr
=initial_cr
, mem
=initial_mem
,
312 initial_fprs
=initial_fprs
,
313 initial_pc
=initial_pc
)
315 #simulator.gpr.dump()
317 #simulator.mem.dump()
321 def run_simulation():
324 initial_regs
= [0]*128
325 initial_fprs
= [0]*128
334 opts
, args
= getopt
.getopt(sys
.argv
[1:], "qhi:a:g:f:s:l:d:p:",
335 ["qemu", "help", "pc=",
336 "binary=", "listing=",
337 "intregs=", "fpregs=", "sprs=",
341 sys
.stderr
.write("Command-line Error\n")
344 for opt
, arg
in opts
:
345 if opt
in ['-h', '--help']:
347 elif opt
in ['-q', '--qemu']:
349 elif opt
in ['-i', '--binary']:
351 elif opt
in ['-p', '--pc']:
352 initial_pc
= convert_to_num(arg
)
353 elif opt
in ['-a', '--listing']:
355 elif opt
in ['-g', '--intregs']:
356 initial_regs
= read_entries(arg
, 128)
357 elif opt
in ['-f', '--fpregs']:
358 initial_fprs
= read_entries(arg
, 128)
359 elif opt
in ['-s', '--sprs']:
360 initial_sprs
= read_entries(arg
, 32)
361 elif opt
in ['-l', '--load']:
362 arg
= list(map(str.strip
, arg
.split(":")))
364 fname
, offs
= arg
[0], 0
367 offs
= convert_to_num(offs
)
368 log ("offs load", fname
, hex(offs
))
369 mem
= read_data(fname
, offs
)
370 initial_mem
.update(mem
)
371 elif opt
in ['-d', '--dump']:
372 arg
= list(map(str.strip
, arg
.split(":")))
373 assert len(arg
) == 3, \
374 "dump '%s' must contain file:offset:length" % repr(arg
)
375 fname
, offs
, length
= arg
376 offs
= convert_to_num(offs
)
377 length
= convert_to_num(length
)
378 assert length
% 8 == 0, "length %d must align on 8-byte" % length
379 log ("dump", fname
, offs
, length
)
380 write_to
.append((fname
, offs
, length
))
384 if binaryname
is None and lst
is None:
385 sys
.stderr
.write("Must give binary or listing\n")
389 with
open(lst
, "r") as f
:
390 lst
= list(map(str.strip
, f
.readlines()))
393 with
open(binaryname
, "rb") as f
:
396 with
Program(lst
, bigendian
=False, orig_filename
=binaryname
) as prog
:
397 simulator
, qemu
= run_tst(None, prog
, qemu_cosim
,
399 initial_sprs
=initial_sprs
,
400 svstate
=0, mmu
=False,
401 initial_cr
=0, mem
=initial_mem
,
402 initial_fprs
=initial_fprs
,
403 initial_pc
=initial_pc
)
411 simulator
.mem
.dump(asciidump
=True)
413 for fname
, offs
, length
in write_to
:
414 write_data(simulator
.mem
, fname
, offs
, length
)
416 qmem
= qemu
.get_mem(offs
, length
)
417 log("qemu mem", hex(offs
), length
)
418 for i
, mem
in enumerate(qmem
):
419 log(hex(offs
+i
*8), hex(mem
))
421 log("final complete qemu reg dump")
422 for reg
, val
in qemu
._get
_registers
().items():
423 log ("qemu reg", reg
, hex(val
))
429 if __name__
== "__main__":