bug 1228: dcbt* to match against nop, not dc* in ISACaller
[openpower-isa.git] / src / openpower / test / util.py
1 # SPDX-License-Identifier: LGPL-3-or-later
2 # Copyright 2023 Jacob Lifshay programmerjake@gmail.com
3
4 # Funded by NLnet Assure Programme 2021-02-052, https://nlnet.nl/assure part
5 # of Horizon 2020 EU Programme 957073.
6
7 import re
8 from openpower.insndb.asm import SVP64Asm
9 from openpower.simulator.program import Program
10 from functools import lru_cache
11
12
13 def assemble(instructions, start_pc=0, bigendian=False):
14 """ assemble `instructions`, handling labels.
15 returns a Program instance
16 """
17 return __cached_assemble(tuple(instructions), start_pc, bigendian)
18
19
20 @lru_cache(maxsize=10000)
21 def __cached_assemble(instructions, start_pc, bigendian):
22 pc = start_pc
23 labels = {}
24 out_instructions = []
25 for instr in instructions:
26 m = re.fullmatch(r" *([a-zA-Z0-9_.$]+): *(#.*)?", instr)
27 if m is not None:
28 name = m.group(1)
29 if name in labels:
30 raise ValueError(f"label {name!r} defined multiple times")
31 labels[name] = pc
32 continue
33 m = re.fullmatch(r" *sv\.[a-zA-Z0-9_].*", instr)
34 if m is not None:
35 pc += 8
36 else:
37 pc += 4
38 out_instructions.append((pc, instr))
39 last_pc = pc
40
41 for (idx, (pc, instr)) in enumerate(tuple(out_instructions)):
42 need_replace = True
43
44 def replace(match):
45 nonlocal need_replace
46 label = match.group(1)
47 target = labels.get(label)
48 if target is not None:
49 need_replace = True
50 if pc < target:
51 sign = ""
52 addr = (target - pc + 4)
53 else:
54 sign = "-"
55 addr = (pc - target - 4)
56 return f"{sign}0x{addr:X}"
57 return label
58
59 while need_replace:
60 need_replace = False
61 # gas symbols start with any alphabetic or _ . $
62 start = "[a-zA-Z_.$]"
63 # gas symbols continue with any alphanumeric or _ . $
64 cont = "[a-zA-Z0-9_.$]"
65 # look for symbols that don't have preceding/succeeding `cont`
66 instr = re.sub(f"({start}{cont}*)", replace, instr)
67 out_instructions[idx] = instr
68
69 for k, v in labels.items():
70 out_instructions.append(f".set {k}, . - 0x{last_pc - v:X} # 0x{v:X}")
71
72 return Program(list(SVP64Asm(out_instructions)), bigendian)