5cd9353a80629ea7fe546966b1c44efac210fdf5
1 from nmigen
import Module
, Signal
2 from nmigen
.back
.pysim
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
41 def convert_to_num(num
):
45 if num
.startswith("0b"):
46 return int(num
[2:], 2)
47 if num
.startswith("0x"):
48 return int(num
[2:], 16)
52 def read_entries(fname
, listqty
=None):
53 """read_entries: reads values from a file of the format "x: y", per line
54 can be used for memory, or regfiles (GPR, SPR, FP). regs and entries may
55 start with "0x" or "0b" for hex or binary
59 with
open(fname
) as f
:
60 for line
in f
.readlines():
62 if line
.startswith("#"):
64 line
= line
.split("#")[0]
65 # split line "x : y" into ["x", "y"], remove spaces
66 line
= list(map(str.strip
, line
.strip().split(":")))
67 assert len(line
) == 2, "regfile line must be formatted 'x : y'"
68 # check and convert format
70 reg
= convert_to_num(reg
)
71 val
= convert_to_num(val
)
72 assert reg
not in regs
, "duplicate entry %s" % (repr(reg
))
73 allints
= allints
and isinstance(reg
, int)
80 # post-process into a list.
83 result
= [0] * listqty
84 for reg
, value
in regs
.items():
85 assert isinstance(reg
, int), "list must be int, %s found" % reg
86 assert reg
< listqty
, "entry %s too large for list %s" % (reg
, listqty
)
91 def qemu_register_compare(sim
, qemu
, regs
, fprs
):
92 qpc
, qxer
, qcr
= qemu
.get_pc(), qemu
.get_xer(), qemu
.get_cr()
94 sim_pc
= sim
.pc
.CIA
.value
95 sim_xer
= sim
.spr
['XER'].value
96 print("qemu pc", hex(qpc
))
97 print("qemu cr", hex(qcr
))
98 print("qemu xer", bin(qxer
))
99 print("sim nia", hex(sim
.pc
.NIA
.value
))
100 print("sim pc", hex(sim
.pc
.CIA
.value
))
101 print("sim cr", hex(sim_cr
))
102 print("sim xer", hex(sim_xer
))
103 #self.assertEqual(qpc, sim_pc)
105 qemu_val
= qemu
.get_gpr(reg
)
106 sim_val
= sim
.gpr(reg
).value
107 if qemu_val
!= sim_val
:
108 log("expect gpr %d %x got %x" % (reg
, qemu_val
, sim_val
))
109 #self.assertEqual(qemu_val, sim_val,
110 # "expect %x got %x" % (qemu_val, sim_val))
112 qemu_val
= qemu
.get_fpr(fpr
)
113 sim_val
= sim
.fpr(fpr
).value
114 if qemu_val
!= sim_val
:
115 log("expect fpr %d %x got %x" % (fpr
, qemu_val
, sim_val
))
116 #self.assertEqual(qemu_val, sim_val,
117 # "expect %x got %x" % (qemu_val, sim_val))
118 #self.assertEqual(qcr, sim_cr)
121 def run_tst(args
, generator
, qemu
,
123 initial_sprs
=None, svstate
=0, mmu
=False,
124 initial_cr
=0, mem
=None,
127 if initial_regs
is None:
128 initial_regs
= [0] * 32
129 if initial_sprs
is None:
133 log("qemu program", generator
.binfile
.name
)
134 qemu
= run_program(generator
, initial_mem
=mem
,
135 bigendian
=False, start_addr
=initial_pc
,
136 continuous_run
=False)
138 if initial_regs
is not None:
139 for reg
, val
in enumerate(initial_regs
):
140 qemu
.set_gpr(reg
, val
)
141 if initial_fprs
is not None:
142 for fpr
, val
in enumerate(initial_fprs
):
143 qemu
.set_fpr(fpr
, val
)
144 for reg
, val
in qemu
._get
_registers
().items():
149 instruction
= Signal(32)
151 pdecode
= create_pdecode(include_fp
=initial_fprs
is not None)
153 gen
= list(generator
.generate_instructions())
154 log ("instructions gen", gen
)
155 insncode
= generator
.assembly
.splitlines()
157 instructions
= list(zip(gen
, insncode
))
161 log ("instructions", instructions
)
163 m
.submodules
.pdecode2
= pdecode2
= PowerDecode2(pdecode
)
164 simulator
= ISA(pdecode2
, initial_regs
, initial_sprs
, initial_cr
,
165 initial_insns
=(initial_pc
, gen
), respect_pc
=True,
166 initial_svstate
=svstate
,
168 initial_pc
=initial_pc
,
169 fpregfile
=initial_fprs
,
170 disassembly
=insncode
,
173 comb
+= pdecode2
.dec
.raw_opcode_in
.eq(instruction
)
178 yield pdecode2
.dec
.bigendian
.eq(0) # little / big?
179 pc
= simulator
.pc
.CIA
.value
182 # rather awkward: qemu will go wonky if stepped over the
183 # last instruction. use ISACaller to check if this is
184 # the last instruction, and leave qemu pointing at it
185 # rather than trigger an exception in the remote-qemu program
187 _pc
, _ins
= simulator
.get_next_insn()
188 except KeyError: # indicates instruction not in imem: stop
191 while not simulator
.halted
:
193 yield from simulator
.setup_next_insn(_pc
, _ins
)
197 ins
= instructions
[index
]
198 if isinstance(ins
, list):
200 log(" 0x{:X}".format(ins
& 0xffffffff))
201 opname
= code
.split(' ')[0]
204 log(" 0x{:X}".format(ins
& 0xffffffff))
206 # ask the decoder to decode this binary data (endian'd)
207 yield from simulator
.execute_one()
208 #pc = simulator.pc.CIA.value
213 _pc
, _ins
= simulator
.get_next_insn()
214 except KeyError: # indicates instruction not in imem: stop
218 # check qemu co-sim: run one instruction, but first check
219 # in ISACaller if there *is* a next instruction. if there
220 # is, "recover" qemu by switching bigendian back
222 _pc
, _ins
= simulator
.get_next_insn()
223 except KeyError: # indicates instruction not in imem: stop
224 _pc
, _insn
= (None, None)
226 if not _pc
or simulator
.halted
:
227 qemu
.set_endian(False)
228 qemu_register_compare(simulator
, qemu
, range(32), range(32))
236 sim
.add_process(process
)
243 print ("-i --binary= raw (non-ELF) bare metal executable, loaded at 0x0")
244 print ("-a --listing= file containing bare-metal assembler (no macros)")
245 print ("-g --intregs= colon-separated file with GPR values")
246 print ("-f --fpregs= colon-separated file with FPR values")
247 print ("-s --spregs= colon-separated file with SPR values")
248 print ("-l --load= filename:address to load binary into memory")
249 print ("-d --dump= filename:address:len to binary save from memory")
250 print ("-q --qemu= run qemu co-simulation")
251 print ("-p --pc= set initial program counter")
252 print ("-h --help prints this message")
254 print ("load and dump may be given multiple times")
255 print ("load and dump must be 8-byte aligned sizes")
256 print ("loading SPRs accepts SPR names (e.g. LR, CTR, SRR0)")
257 print ("numbers may be integer, binary (0bNNN) or hex (0xMMM) but not FP")
258 print ("running ELF binaries: load SPRs, LR set to 0xffffffffffffffff")
259 print ("TODO: dump registers")
260 print ("TODO: load/dump PC, MSR, CR")
261 print ("TODO: print exec and sub-exec counters at end")
265 def run_simulation():
268 initial_regs
= [0]*32
269 initial_fprs
= [0]*32
278 opts
, args
= getopt
.getopt(sys
.argv
[1:], "qhi:a:g:f:s:l:d:p:",
279 ["qemu", "help", "pc=",
280 "binary=", "listing=",
281 "intregs=", "fpregs=", "sprs=",
285 sys
.stderr
.write("Command-line Error\n")
288 for opt
, arg
in opts
:
289 if opt
in ['-h', '--help']:
291 elif opt
in ['-q', '--qemu']:
293 elif opt
in ['-i', '--binary']:
295 elif opt
in ['-p', '--pc']:
296 initial_pc
= convert_to_num(arg
)
297 elif opt
in ['-a', '--listing']:
299 elif opt
in ['-g', '--intregs']:
300 initial_regs
= read_entries(arg
, 32)
301 elif opt
in ['-f', '--fpregs']:
302 initial_fprs
= read_entries(arg
, 32)
303 elif opt
in ['-s', '--sprs']:
304 initial_sprs
= read_entries(arg
, 32)
305 elif opt
in ['-l', '--load']:
306 arg
= list(map(str.strip
, arg
.split(":")))
308 fname
, offs
= arg
[0], 0
311 offs
= convert_to_num(offs
)
312 log ("offs load", fname
, offs
)
313 mem
= read_data(fname
, offs
)
314 initial_mem
.update(mem
)
315 elif opt
in ['-d', '--dump']:
316 arg
= list(map(str.strip
, arg
.split(":")))
317 assert len(arg
) == 3, \
318 "dump '%s' must contain file:offset:length" % repr(arg
)
319 fname
, offs
, length
= arg
320 offs
= convert_to_num(offs
)
321 length
= convert_to_num(length
)
322 assert length
% 8 == 0, "length %d must align on 8-byte" % length
323 log ("dump", fname
, offs
, length
)
324 write_to
.append((fname
, offs
, length
))
328 if binaryname
is None and lst
is None:
329 sys
.stderr
.write("Must give binary or listing\n")
333 with
open(lst
, "r") as f
:
334 lst
= list(map(str.strip
, f
.readlines()))
337 with
open(binaryname
, "rb") as f
:
340 with
Program(lst
, bigendian
=False, orig_filename
=binaryname
) as prog
:
341 simulator
= run_tst(None, prog
, qemu_cosim
,
343 initial_sprs
=initial_sprs
,
344 svstate
=0, mmu
=False,
345 initial_cr
=0, mem
=initial_mem
,
346 initial_fprs
=initial_fprs
,
347 initial_pc
=initial_pc
)
357 for fname
, offs
, length
in write_to
:
358 write_data(simulator
.mem
, fname
, offs
, length
)
361 if __name__
== "__main__":