add test cases for ca/ov outputs of a bunch of add-like ops covered by pia
[openpower-isa.git] / src / openpower / test / alu / alu_cases.py
1 import random
2 from openpower.test.common import TestAccumulatorBase
3 from openpower.endian import bigendian
4 from openpower.simulator.program import Program
5 from openpower.decoder.selectable_int import SelectableInt
6 from openpower.decoder.power_enums import XER_bits
7 from openpower.decoder.isa.caller import special_sprs
8 from openpower.decoder.helpers import exts
9 from openpower.test.state import ExpectedState
10 from openpower.util import log
11 from pathlib import Path
12 import gzip
13 import json
14 import sys
15 from hashlib import sha256
16 from functools import lru_cache
17
18 # output-for-v0.2.0-7-g95fdd1c.json.gz generated from:
19 # https://salsa.debian.org/Kazan-team/power-instruction-analyzer/-/commit/95fdd1c4edbd91c0a02b772ba02aa2045101d2b0
20 # running on POWER9
21 PIA_OUTPUT_URL = "https://ftp.libre-soc.org/power-instruction-analyzer/output-for-v0.2.0-7-g95fdd1c.json.gz"
22 PIA_OUTPUT_SHA256 = "2ad50464eb6c9b6bf2dad2ee16b6820a34024bc008ea86818845cf14f7f457ad"
23 PIA_OUTPUT_PATH = Path(__file__).parent / PIA_OUTPUT_URL.rpartition('/')[2]
24
25
26 def download_pia_output():
27 from urllib.request import urlopen
28 from shutil import copyfileobj
29 with PIA_OUTPUT_PATH.open("wb") as f:
30 print(f"downloading {PIA_OUTPUT_URL} to {PIA_OUTPUT_PATH}",
31 file=sys.stderr, flush=True)
32 with urlopen(PIA_OUTPUT_URL) as response:
33 copyfileobj(response, f)
34
35
36 @lru_cache(maxsize=None)
37 def read_pia_output(filter_fn=lambda _: True):
38 tried_download = False
39 while True:
40 try:
41 file_bytes = PIA_OUTPUT_PATH.read_bytes()
42 digest = sha256(file_bytes).hexdigest()
43 if digest != PIA_OUTPUT_SHA256:
44 raise Exception(f"{PIA_OUTPUT_PATH} has wrong hash, expected "
45 f"{PIA_OUTPUT_SHA256} got {digest}")
46 file_bytes = gzip.decompress(file_bytes)
47 test_cases = json.loads(file_bytes)['test_cases']
48 return list(filter(filter_fn, test_cases))
49 except:
50 if tried_download:
51 raise
52 pass
53 tried_download = True
54 download_pia_output()
55
56
57 @lru_cache(maxsize=None)
58 def get_addmeo_subfmeo_reference_cases():
59 return read_pia_output(lambda i: i['instr'] in ("addmeo", "subfmeo"))
60
61
62 def check_addmeo_subfmeo_matches_reference(instr, case_filter, out):
63 case_filter = {
64 'instr': instr,
65 'ra': '0x0', 'ca': False, 'ca32': False,
66 'so': False, 'ov': False, 'ov32': False,
67 **case_filter
68 }
69 for case in get_addmeo_subfmeo_reference_cases():
70 skip = False
71 for k, v in case_filter.items():
72 if case[k] != v:
73 skip = True
74 break
75 if skip:
76 continue
77 reference_outputs = case['native_outputs']
78 for k, v in out.items():
79 assert reference_outputs[k] == v, (
80 f"{instr} outputs don't match reference:\n"
81 f"case_filter={case_filter}\nout={out}\n"
82 f"reference_outputs={reference_outputs}")
83 log(f"PIA reference successfully matched: {case_filter}")
84 return True
85 log(f"PIA reference not found: {case_filter}")
86 return False
87
88
89 class ALUTestCase(TestAccumulatorBase):
90
91 def case_1_regression(self):
92 lst = [f"add. 3, 1, 2"]
93 initial_regs = [0] * 32
94 initial_regs[1] = 0xc523e996a8ff6215
95 initial_regs[2] = 0xe1e5b9cc9864c4a8
96 e = ExpectedState(pc=4)
97 e.intregs[1] = 0xc523e996a8ff6215
98 e.intregs[2] = 0xe1e5b9cc9864c4a8
99 e.intregs[3] = 0xa709a363416426bd
100 e.crregs[0] = 0x8
101 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
102
103 def case_2_regression(self):
104 lst = [f"extsw 3, 1"]
105 initial_regs = [0] * 32
106 initial_regs[1] = 0xb6a1fc6c8576af91
107 e = ExpectedState(pc=4)
108 e.intregs[1] = 0xb6a1fc6c8576af91
109 e.intregs[3] = 0xffffffff8576af91
110 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
111
112 lst = [f"subf 3, 1, 2"]
113 initial_regs = [0] * 32
114 initial_regs[1] = 0x3d7f3f7ca24bac7b
115 initial_regs[2] = 0xf6b2ac5e13ee15c2
116 e = ExpectedState(pc=4)
117 e.intregs[1] = 0x3d7f3f7ca24bac7b
118 e.intregs[2] = 0xf6b2ac5e13ee15c2
119 e.intregs[3] = 0xb9336ce171a26947
120 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
121
122 lst = [f"subf 3, 1, 2"]
123 initial_regs = [0] * 32
124 initial_regs[1] = 0x833652d96c7c0058
125 initial_regs[2] = 0x1c27ecff8a086c1a
126 e = ExpectedState(pc=4)
127 e.intregs[1] = 0x833652d96c7c0058
128 e.intregs[2] = 0x1c27ecff8a086c1a
129 e.intregs[3] = 0x98f19a261d8c6bc2
130 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
131
132 lst = [f"extsb 3, 1"]
133 initial_regs = [0] * 32
134 initial_regs[1] = 0x7f9497aaff900ea0
135 e = ExpectedState(pc=4)
136 e.intregs[1] = 0x7f9497aaff900ea0
137 e.intregs[3] = 0xffffffffffffffa0
138 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
139
140 lst = [f"add 3, 1, 2"]
141 initial_regs = [0] * 32
142 initial_regs[1] = 0x2e08ae202742baf8
143 initial_regs[2] = 0x86c43ece9efe5baa
144 e = ExpectedState(pc=4)
145 e.intregs[1] = 0x2e08ae202742baf8
146 e.intregs[2] = 0x86c43ece9efe5baa
147 e.intregs[3] = 0xb4cceceec64116a2
148 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
149
150 def case_rand(self):
151 insns = ["add", "add.", "subf"]
152 for i in range(40):
153 choice = random.choice(insns)
154 lst = [f"{choice} 3, 1, 2"]
155 initial_regs = [0] * 32
156 initial_regs[1] = random.randint(0, (1 << 64)-1)
157 initial_regs[2] = random.randint(0, (1 << 64)-1)
158
159 e = ExpectedState(pc=4)
160 e.intregs[1] = initial_regs[1]
161 e.intregs[2] = initial_regs[2]
162 if choice == "add":
163 result = initial_regs[1] + initial_regs[2]
164 e.intregs[3] = result & ((2**64)-1)
165 elif choice == "add.":
166 result = initial_regs[1] + initial_regs[2]
167 e.intregs[3] = result & ((2**64)-1)
168 eq = 0
169 gt = 0
170 le = 0
171 if (e.intregs[3] & (1 << 63)) != 0:
172 le = 1
173 elif e.intregs[3] == 0:
174 eq = 1
175 else:
176 gt = 1
177 e.crregs[0] = (eq << 1) | (gt << 2) | (le << 3)
178 elif choice == "subf":
179 result = ~initial_regs[1] + initial_regs[2] + 1
180 e.intregs[3] = result & ((2**64)-1)
181
182 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
183
184 def case_addme_ca_0(self):
185 insns = ["addme", "addme.", "addmeo", "addmeo."]
186 for choice in insns:
187 lst = [f"{choice} 6, 16"]
188 for value in [0x7ffffffff,
189 0xffff80000]:
190 initial_regs = [0] * 32
191 initial_regs[16] = value
192 initial_sprs = {}
193 xer = SelectableInt(0, 64)
194 xer[XER_bits['CA']] = 0 # input carry is 0 (see test below)
195 initial_sprs[special_sprs['XER']] = xer
196
197 # create expected results. pc should be 4 (one instruction)
198 e = ExpectedState(pc=4)
199 # input value should not be modified
200 e.intregs[16] = value
201 # carry-out should always occur
202 e.ca = 0x3
203 # create output value
204 if value == 0x7ffffffff:
205 e.intregs[6] = 0x7fffffffe
206 else:
207 e.intregs[6] = 0xffff7ffff
208 # CR version needs an expected CR
209 if '.' in choice:
210 e.crregs[0] = 0x4
211 self.add_case(Program(lst, bigendian),
212 initial_regs, initial_sprs,
213 expected=e)
214
215 def case_addme_ca_1(self):
216 insns = ["addme", "addme.", "addmeo", "addmeo."]
217 for choice in insns:
218 lst = [f"{choice} 6, 16"]
219 for value in [0x7ffffffff, # fails, bug #476
220 0xffff80000]:
221 initial_regs = [0] * 32
222 initial_regs[16] = value
223 initial_sprs = {}
224 xer = SelectableInt(0, 64)
225 # input carry is 1 (differs from above)
226 xer[XER_bits['CA']] = 1
227 initial_sprs[special_sprs['XER']] = xer
228 e = ExpectedState(pc=4)
229 e.intregs[16] = value
230 e.ca = 0x3
231 if value == 0x7ffffffff:
232 e.intregs[6] = 0x7ffffffff
233 else:
234 e.intregs[6] = 0xffff80000
235 if '.' in choice:
236 e.crregs[0] = 0x4
237 self.add_case(Program(lst, bigendian),
238 initial_regs, initial_sprs, expected=e)
239
240 def case_addme_ca_so_4(self):
241 """test of SO being set
242 """
243 lst = ["addmeo. 6, 16"]
244 initial_regs = [0] * 32
245 initial_regs[16] = 0x7fffffffffffffff
246 initial_sprs = {}
247 xer = SelectableInt(0, 64)
248 xer[XER_bits['CA']] = 1
249 initial_sprs[special_sprs['XER']] = xer
250 e = ExpectedState(pc=4)
251 e.intregs[16] = 0x7fffffffffffffff
252 e.intregs[6] = 0x7fffffffffffffff
253 e.ca = 0x3
254 e.crregs[0] = 0x4
255 self.add_case(Program(lst, bigendian),
256 initial_regs, initial_sprs, expected=e)
257
258 def case_addme_ca_so_3(self):
259 """bug where SO does not get passed through to CR0
260 """
261 lst = ["addme. 6, 16"]
262 initial_regs = [0] * 32
263 initial_regs[16] = 0x7ffffffff
264 initial_sprs = {}
265 xer = SelectableInt(0, 64)
266 xer[XER_bits['CA']] = 1
267 xer[XER_bits['SO']] = 1
268 initial_sprs[special_sprs['XER']] = xer
269 e = ExpectedState(pc=4)
270 e.intregs[16] = 0x7ffffffff
271 e.intregs[6] = 0x7ffffffff
272 e.crregs[0] = 0x5
273 e.so = 0x1
274 e.ca = 0x3
275 self.add_case(Program(lst, bigendian),
276 initial_regs, initial_sprs, expected=e)
277
278 def case_addme_subfme_ca_propagation(self):
279 for flags in range(1 << 2):
280 ca_in = bool(flags & 1)
281 is_sub = (flags >> 1) & 1
282 if is_sub:
283 prog = Program(["subfmeo 3, 4"], bigendian)
284 else:
285 prog = Program(["addmeo 3, 4"], bigendian)
286 for i in range(-2, 3):
287 ra = i % 2 ** 64
288 with self.subTest(ra=hex(ra), ca=ca_in, is_sub=is_sub):
289 initial_regs = [0] * 32
290 initial_regs[4] = ra
291 initial_sprs = {}
292 xer = SelectableInt(0, 64)
293 xer[XER_bits['CA']] = ca_in
294 initial_sprs[special_sprs['XER']] = xer
295 e = ExpectedState(pc=4)
296 e.intregs[4] = ra
297 rb = 2 ** 64 - 1 # add 0xfff...fff *not* -1
298 expected = ca_in + rb
299 expected32 = ca_in + (rb % 2 ** 32)
300 inv_ra = ra
301 if is_sub:
302 # 64-bit bitwise not
303 inv_ra = ~ra % 2 ** 64
304 expected += inv_ra
305 expected32 += inv_ra % 2 ** 32
306 rt_out = expected % 2 ** 64
307 e.intregs[3] = rt_out
308 ca = bool(expected >> 64)
309 ca32 = bool(expected32 >> 32)
310 e.ca = (ca32 << 1) | ca
311 # use algorithm from microwatt's calc_ov
312 # https://github.com/antonblanchard/microwatt/blob/5c6d57de3056bd08fdc1f656bc8656635a77512b/execute1.vhdl#L284
313 axb = inv_ra ^ rb
314 emsb = (expected >> 63) & 1
315 ov = ca ^ emsb and not (axb >> 63) & 1
316 e32msb = (expected32 >> 31) & 1
317 ov32 = ca32 ^ e32msb and not (axb >> 31) & 1
318 e.ov = (ov32 << 1) | ov
319 check_addmeo_subfmeo_matches_reference(
320 instr='subfmeo' if is_sub else 'addmeo',
321 case_filter={
322 'ra': f'0x{ra:X}', 'ca': ca_in,
323 }, out={
324 'rt': f'0x{rt_out:X}', 'ca': ca,
325 'ca32': ca32, 'ov': ov, 'ov32': ov32,
326 })
327 self.add_case(prog, initial_regs, initial_sprs,
328 expected=e)
329
330 def case_addze(self):
331 insns = ["addze", "addze.", "addzeo", "addzeo."]
332 for choice in insns:
333 lst = [f"{choice} 6, 16"]
334 initial_regs = [0] * 32
335 initial_regs[16] = 0x00ff00ff00ff0080
336 e = ExpectedState(pc=4)
337 e.intregs[16] = 0xff00ff00ff0080
338 e.intregs[6] = 0xff00ff00ff0080
339 if '.' in choice:
340 e.crregs[0] = 0x4
341 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
342
343 def case_addis_nonzero_r0_regression(self):
344 lst = [f"addis 3, 0, 1"]
345 print(lst)
346 initial_regs = [0] * 32
347 initial_regs[0] = 5
348 e = ExpectedState(initial_regs, pc=4)
349 e.intregs[3] = 0x10000
350 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
351
352 def case_addis_nonzero_r0(self):
353 for i in range(10):
354 imm = random.randint(-(1 << 15), (1 << 15)-1)
355 lst = [f"addis 3, 0, {imm}"]
356 print(lst)
357 initial_regs = [0] * 32
358 initial_regs[0] = random.randint(0, (1 << 64)-1)
359 e = ExpectedState(pc=4)
360 e.intregs[0] = initial_regs[0]
361 e.intregs[3] = (imm << 16) & ((1 << 64)-1)
362 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
363
364 def case_rand_imm(self):
365 insns = ["addi", "addis", "subfic"]
366 for i in range(10):
367 choice = random.choice(insns)
368 imm = random.randint(-(1 << 15), (1 << 15)-1)
369 lst = [f"{choice} 3, 1, {imm}"]
370 print(lst)
371 initial_regs = [0] * 32
372 initial_regs[1] = random.randint(0, (1 << 64)-1)
373
374 e = ExpectedState(pc=4)
375 e.intregs[1] = initial_regs[1]
376 if choice == "addi":
377 result = initial_regs[1] + imm
378 e.intregs[3] = result & ((2**64)-1)
379 elif choice == "addis":
380 result = initial_regs[1] + (imm << 16)
381 e.intregs[3] = result & ((2**64)-1)
382 elif choice == "subfic":
383 result = ~initial_regs[1] + imm + 1
384 value = (~initial_regs[1]+2**64) + (imm) + 1
385 if imm < 0:
386 value += 2**64
387 carry_out = value & (1 << 64) != 0
388 value = (~initial_regs[1]+2**64 & 0xffff_ffff) + imm + 1
389 if imm < 0:
390 value += 2**32
391 carry_out32 = value & (1 << 32) != 0
392 e.intregs[3] = result & ((2**64)-1)
393 e.ca = carry_out | (carry_out32 << 1)
394
395 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
396
397 def case_0_adde(self):
398 lst = ["adde. 5, 6, 7"]
399 for i in range(10):
400 initial_regs = [0] * 32
401 initial_regs[6] = random.randint(0, (1 << 64)-1)
402 initial_regs[7] = random.randint(0, (1 << 64)-1)
403 initial_sprs = {}
404 xer = SelectableInt(0, 64)
405 xer[XER_bits['CA']] = 1
406 initial_sprs[special_sprs['XER']] = xer
407 # calculate result *including carry* and mask it to 64-bit
408 # (if it overflows, we don't care, because this is not addeo)
409 result = 1 + initial_regs[6] + initial_regs[7]
410 # detect 65th bit as carry-out?
411 carry_out = result & (1 << 64) != 0
412 carry_out32 = (initial_regs[6] & 0xffff_ffff) + \
413 (initial_regs[7] & 0xffff_ffff) & (1 << 32) != 0
414 result = result & ((1 << 64)-1) # round
415 eq = 0
416 gt = 0
417 le = 0
418 if (result & (1 << 63)) != 0:
419 le = 1
420 elif result == 0:
421 eq = 1
422 else:
423 gt = 1
424 # now construct the state
425 e = ExpectedState(pc=4)
426 e.intregs[6] = initial_regs[6] # should be same as initial
427 e.intregs[7] = initial_regs[7] # should be same as initial
428 e.intregs[5] = result
429 # carry_out goes into bit 0 of ca, carry_out32 into bit 1
430 e.ca = carry_out | (carry_out32 << 1)
431 # eq goes into bit 1 of CR0, gt into bit 2, le into bit 3.
432 # SO goes into bit 0 but overflow doesn't occur here [we hope]
433 e.crregs[0] = (eq << 1) | (gt << 2) | (le << 3)
434
435 self.add_case(Program(lst, bigendian),
436 initial_regs, initial_sprs, expected=e)
437
438 def case_cmp(self):
439 lst = ["subf. 1, 6, 7",
440 "cmp cr2, 1, 6, 7"]
441 initial_regs = [0] * 32
442 initial_regs[6] = 0x10
443 initial_regs[7] = 0x05
444 e = ExpectedState(pc=8)
445 e.intregs[6] = 0x10
446 e.intregs[7] = 0x5
447 e.intregs[1] = 0xfffffffffffffff5
448 e.crregs[0] = 0x8
449 e.crregs[2] = 0x4
450 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
451
452 def case_cmp2(self):
453 lst = ["cmp cr2, 0, 2, 3"]
454 initial_regs = [0] * 32
455 initial_regs[2] = 0xffffffffaaaaaaaa
456 initial_regs[3] = 0x00000000aaaaaaaa
457 e = ExpectedState(pc=4)
458 e.intregs[2] = 0xffffffffaaaaaaaa
459 e.intregs[3] = 0xaaaaaaaa
460 e.crregs[2] = 0x2
461 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
462
463 lst = ["cmp cr2, 0, 4, 5"]
464 initial_regs = [0] * 32
465 initial_regs[4] = 0x00000000aaaaaaaa
466 initial_regs[5] = 0xffffffffaaaaaaaa
467 e = ExpectedState(pc=4)
468 e.intregs[4] = 0xaaaaaaaa
469 e.intregs[5] = 0xffffffffaaaaaaaa
470 e.crregs[2] = 0x2
471 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
472
473 def case_cmp3(self):
474 lst = ["cmp cr2, 1, 2, 3"]
475 initial_regs = [0] * 32
476 initial_regs[2] = 0xffffffffaaaaaaaa
477 initial_regs[3] = 0x00000000aaaaaaaa
478 e = ExpectedState(pc=4)
479 e.intregs[2] = 0xffffffffaaaaaaaa
480 e.intregs[3] = 0xaaaaaaaa
481 e.crregs[2] = 0x8
482 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
483
484 lst = ["cmp cr2, 1, 4, 5"]
485 initial_regs = [0] * 32
486 initial_regs[4] = 0x00000000aaaaaaaa
487 initial_regs[5] = 0xffffffffaaaaaaaa
488 e = ExpectedState(pc=4)
489 e.intregs[4] = 0xaaaaaaaa
490 e.intregs[5] = 0xffffffffaaaaaaaa
491 e.crregs[2] = 0x4
492 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
493
494 def case_cmpl_microwatt_0(self):
495 """microwatt 1.bin:
496 115b8: 40 50 d1 7c .long 0x7cd15040 # cmpl 6, 0, 17, 10
497 register_file.vhdl: Reading GPR 11 000000000001C026
498 register_file.vhdl: Reading GPR 0A FEDF3FFF0001C025
499 cr_file.vhdl: Reading CR 35055050
500 cr_file.vhdl: Writing 35055058 to CR mask 01 35055058
501 """
502
503 lst = ["cmpl 6, 0, 17, 10"]
504 initial_regs = [0] * 32
505 initial_regs[0x11] = 0x1c026
506 initial_regs[0xa] = 0xFEDF3FFF0001C025
507 XER = 0xe00c0000
508 CR = 0x35055050
509
510 e = ExpectedState(pc=4)
511 e.intregs[10] = 0xfedf3fff0001c025
512 e.intregs[17] = 0x1c026
513 e.crregs[0] = 0x3
514 e.crregs[1] = 0x5
515 e.crregs[3] = 0x5
516 e.crregs[4] = 0x5
517 e.crregs[6] = 0x5
518 e.so = 0x1
519 e.ov = 0x3
520 e.ca = 0x3
521
522 self.add_case(Program(lst, bigendian), initial_regs,
523 initial_sprs={'XER': XER},
524 initial_cr=CR, expected=e)
525
526 def case_cmpl_microwatt_0_disasm(self):
527 """microwatt 1.bin: disassembled version
528 115b8: 40 50 d1 7c .long 0x7cd15040 # cmpl 6, 0, 17, 10
529 register_file.vhdl: Reading GPR 11 000000000001C026
530 register_file.vhdl: Reading GPR 0A FEDF3FFF0001C025
531 cr_file.vhdl: Reading CR 35055050
532 cr_file.vhdl: Writing 35055058 to CR mask 01 35055058
533 """
534
535 dis = ["cmpl 6, 0, 17, 10"]
536 lst = bytes([0x40, 0x50, 0xd1, 0x7c]) # 0x7cd15040
537 initial_regs = [0] * 32
538 initial_regs[0x11] = 0x1c026
539 initial_regs[0xa] = 0xFEDF3FFF0001C025
540 XER = 0xe00c0000
541 CR = 0x35055050
542
543 e = ExpectedState(pc=4)
544 e.intregs[10] = 0xfedf3fff0001c025
545 e.intregs[17] = 0x1c026
546 e.crregs[0] = 0x3
547 e.crregs[1] = 0x5
548 e.crregs[3] = 0x5
549 e.crregs[4] = 0x5
550 e.crregs[6] = 0x5
551 e.so = 0x1
552 e.ov = 0x3
553 e.ca = 0x3
554
555 p = Program(lst, bigendian)
556 p.assembly = '\n'.join(dis)+'\n'
557 self.add_case(p, initial_regs,
558 initial_sprs={'XER': XER},
559 initial_cr=CR, expected=e)
560
561 def case_cmplw_microwatt_1(self):
562 """microwatt 1.bin:
563 10d94: 40 20 96 7c cmplw cr1,r22,r4
564 gpr: 00000000ffff6dc1 <- r4
565 gpr: 0000000000000000 <- r22
566 """
567
568 lst = ["cmpl 1, 0, 22, 4"]
569 initial_regs = [0] * 32
570 initial_regs[4] = 0xffff6dc1
571 initial_regs[22] = 0
572 XER = 0xe00c0000
573 CR = 0x50759999
574
575 e = ExpectedState(pc=4)
576 e.intregs[4] = 0xffff6dc1
577 e.crregs[0] = 0x5
578 e.crregs[1] = 0x9
579 e.crregs[2] = 0x7
580 e.crregs[3] = 0x5
581 e.crregs[4] = 0x9
582 e.crregs[5] = 0x9
583 e.crregs[6] = 0x9
584 e.crregs[7] = 0x9
585 e.so = 0x1
586 e.ov = 0x3
587 e.ca = 0x3
588
589 self.add_case(Program(lst, bigendian), initial_regs,
590 initial_sprs={'XER': XER},
591 initial_cr=CR, expected=e)
592
593 def case_cmpli_microwatt(self):
594 """microwatt 1.bin: cmpli
595 123ac: 9c 79 8d 2a cmpli cr5,0,r13,31132
596 gpr: 00000000301fc7a7 <- r13
597 cr : 0000000090215393
598 xer: so 1 ca 0 32 0 ov 0 32 0
599
600 """
601
602 lst = ["cmpli 5, 0, 13, 31132"]
603 initial_regs = [0] * 32
604 initial_regs[13] = 0x301fc7a7
605 XER = 0xe00c0000
606 CR = 0x90215393
607
608 e = ExpectedState(pc=4)
609 e.intregs[13] = 0x301fc7a7
610 e.crregs[0] = 0x9
611 e.crregs[2] = 0x2
612 e.crregs[3] = 0x1
613 e.crregs[4] = 0x5
614 e.crregs[5] = 0x5
615 e.crregs[6] = 0x9
616 e.crregs[7] = 0x3
617 e.so = 0x1
618 e.ov = 0x3
619 e.ca = 0x3
620
621 self.add_case(Program(lst, bigendian), initial_regs,
622 initial_sprs={'XER': XER},
623 initial_cr=CR, expected=e)
624
625 def case_extsb(self):
626 insns = ["extsb", "extsh", "extsw"]
627 for i in range(10):
628 choice = random.choice(insns)
629 lst = [f"{choice} 3, 1"]
630 print(lst)
631 initial_regs = [0] * 32
632 initial_regs[1] = random.randint(0, (1 << 64)-1)
633
634 e = ExpectedState(pc=4)
635 e.intregs[1] = initial_regs[1]
636 if choice == "extsb":
637 e.intregs[3] = exts(initial_regs[1], 8) & ((1 << 64)-1)
638 elif choice == "extsh":
639 e.intregs[3] = exts(initial_regs[1], 16) & ((1 << 64)-1)
640 else:
641 e.intregs[3] = exts(initial_regs[1], 32) & ((1 << 64)-1)
642
643 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
644
645 def case_cmpeqb(self):
646 lst = ["cmpeqb cr1, 1, 2"]
647 for i in range(20):
648 initial_regs = [0] * 32
649 initial_regs[1] = i
650 initial_regs[2] = 0x0001030507090b0f
651
652 e = ExpectedState(pc=4)
653 e.intregs[1] = i
654 e.intregs[2] = 0x1030507090b0f
655 matlst = [0x00, 0x01, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0f]
656 for j in matlst:
657 if j == i:
658 e.crregs[1] = 0x4
659
660 self.add_case(Program(lst, bigendian), initial_regs, expected=e)
661
662 def case_pia_ca_ov_cases(self):
663 wanted_outputs = 'ca', 'ca32', 'ov', 'ov32', 'so'
664 wanted_instrs = {
665 'addi', 'paddi', 'addis', 'add', 'addic', 'subf', 'subfic', 'addc',
666 'subfc', 'adde', 'subfe', 'addme', 'subfme', 'addze', 'subfze',
667 'addex', 'neg',
668 }
669 wanted_instrs |= {i + 'o' for i in wanted_instrs}
670 # intentionally don't test Rc=1 instrs
671 unary_inputs = {
672 '0x0', '0x1', '0x2',
673 '0xFFFFFFFFFFFFFFFF', '0xFFFFFFFFFFFFFFFE',
674 '0x7FFFFFFFFFFFFFFE', '0x7FFFFFFFFFFFFFFF',
675 '0x8000000000000000', '0x8000000000000001',
676 '0x123456787FFFFFFE', '0x123456787FFFFFFF',
677 '0x1234567880000000', '0x1234567880000001',
678 }
679 imm_inputs = {
680 '0x0', '0x1', '0x2',
681 '0xFFFFFFFFFFFFFFFF', '0xFFFFFFFFFFFFFFFE',
682 '0xFFFFFFFFFFFF8000', '0xFFFFFFFFFFFF8001',
683 '0x7FFE', '0x7FFF', '0x8000', '0x8001',
684 }
685 binary_inputs32 = {
686 '0x0', '0x1', '0x2',
687 '0x12345678FFFFFFFF', '0x12345678FFFFFFFE',
688 '0x123456787FFFFFFE', '0x123456787FFFFFFF',
689 '0x1234567880000000', '0x1234567880000001',
690 }
691 binary_inputs64 = {
692 '0x0', '0x1', '0x2',
693 '0xFFFFFFFFFFFFFFFF', '0xFFFFFFFFFFFFFFFE',
694 '0x7FFFFFFFFFFFFFFE', '0x7FFFFFFFFFFFFFFF',
695 '0x8000000000000000', '0x8000000000000001',
696 }
697
698 def matches(case, **kwargs):
699 for k, v in kwargs.items():
700 if case[k] not in v:
701 return False
702 return True
703
704 programs = {}
705
706 for case in read_pia_output():
707 instr = case['instr']
708 if instr not in wanted_instrs:
709 continue
710 if not any(i in case['native_outputs'] for i in wanted_outputs):
711 continue
712 if case.get('so') == True:
713 continue
714 if case.get('ov32') == True:
715 continue
716 if case.get('ca32') == True:
717 continue
718 initial_regs = [0] * 32
719 initial_sprs = {}
720 xer = SelectableInt(0, 64)
721 xer[XER_bits['CA']] = case.get('ca', False)
722 xer[XER_bits['OV']] = case.get('ov', False)
723 initial_sprs[special_sprs['XER']] = xer
724 e = ExpectedState(pc=4)
725 e.intregs[3] = int(case['native_outputs']['rt'], 0)
726 ca_out = case['native_outputs'].get('ca', False)
727 ca32_out = case['native_outputs'].get('ca32', False)
728 ov_out = case['native_outputs'].get('ov', False)
729 ov32_out = case['native_outputs'].get('ov32', False)
730 e.ca = ca_out | (ca32_out << 1)
731 e.ov = ov_out | (ov32_out << 1)
732 e.so = int(case['native_outputs'].get('so', False))
733 if 'rb' in case: # binary op
734 pass32 = matches(case, ra=binary_inputs32, rb=binary_inputs32)
735 pass64 = matches(case, ra=binary_inputs64, rb=binary_inputs64)
736 if not pass32 and not pass64:
737 continue
738 asm = f'{instr} 3, 4, 5'
739 if instr == 'addex':
740 asm += ', 0'
741 e.intregs[4] = initial_regs[4] = int(case['ra'], 0)
742 e.intregs[5] = initial_regs[5] = int(case['rb'], 0)
743 elif 'immediate' in case:
744 pass32 = matches(case, ra=binary_inputs32,
745 immediate=imm_inputs)
746 pass64 = matches(case, ra=binary_inputs64,
747 immediate=imm_inputs)
748 if not pass32 and not pass64:
749 continue
750 immediate = int(case['immediate'], 16)
751 if immediate >> 63:
752 immediate -= 1 << 64
753 asm = f'{instr} 3, 4, {immediate}'
754 e.intregs[4] = initial_regs[4] = int(case['ra'], 0)
755 else: # unary op
756 if not matches(case, ra=unary_inputs):
757 continue
758 asm = f'{instr} 3, 4'
759 e.intregs[4] = initial_regs[4] = int(case['ra'], 0)
760 with self.subTest(case=repr(case)):
761 if asm not in programs:
762 programs[asm] = Program([asm], bigendian)
763 self.add_case(programs[asm], initial_regs,
764 initial_sprs=initial_sprs, expected=e)