test_pysvp64dis: test shadd/shadduw instructions
[openpower-isa.git] / src / openpower / sv / sv_binutils_fptrans.py
1 import argparse as _argparse
2 import dataclasses as _dataclasses
3 import enum as _enum
4 import functools as _functools
5
6
7 from openpower.decoder.power_enums import (
8 FPTRANS_INSNS as _FPTRANS_INSNS,
9 find_wiki_dir as _find_wiki_dir,
10 )
11 from openpower.decoder.power_insn import (
12 Database as _Database,
13 StaticOperand as _StaticOperand,
14 WordInstruction as _WordInstruction,
15 )
16
17
18 @_dataclasses.dataclass(eq=True, frozen=True)
19 class StaticOperand:
20 name: str
21 value: int
22 span: tuple
23
24
25 @_dataclasses.dataclass(eq=True, frozen=True)
26 class DynamicOperand:
27 name: str
28 span: tuple
29
30
31 @_functools.total_ordering
32 @_dataclasses.dataclass(eq=True, frozen=True)
33 class Entry:
34 name: str
35 static_operands: tuple
36 dynamic_operands: tuple
37
38 def __lt__(self, other):
39 if not isinstance(other, self.__class__):
40 return NotImplemented
41 return ((self.PO, self.XO, self.Rc) <
42 (other.PO, other.XO, other.Rc))
43
44 @property
45 def PO(self):
46 for operand in self.static_operands:
47 if operand.name == "PO":
48 return operand.value
49 raise ValueError(self)
50
51 @property
52 def XO(self):
53 for operand in self.static_operands:
54 if operand.name == "XO":
55 return operand.value
56 raise ValueError(self)
57
58 @property
59 def Rc(self):
60 for operand in self.static_operands:
61 if operand.name == "Rc":
62 return operand.value
63 raise ValueError(self)
64
65
66 def collect(db):
67 fptrans = tuple(_FPTRANS_INSNS)
68 fptrans_Rc = tuple(map(lambda name: f"{name}.", fptrans))
69
70 def fptrans_match(insn):
71 return ((insn.name in fptrans) or (insn.name in fptrans_Rc))
72
73 for record in filter(fptrans_match, db):
74 if len(record.opcodes) > 1:
75 raise NotImplementedError(record.opcodes)
76 PO = record.section.opcode
77 if PO is None:
78 PO = tuple(record.ppc)[0].opcode
79 XO = None
80 else:
81 XO = tuple(record.ppc)[0].opcode
82
83 @_dataclasses.dataclass(eq=True, frozen=True)
84 class POStaticOperand(_StaticOperand):
85 def __init__(self, PO):
86 value = (PO.value & PO.mask)
87 return super().__init__(name="PO", value=value)
88
89 def span(self, record):
90 return tuple(range(0, 6))
91
92 @_dataclasses.dataclass(eq=True, frozen=True)
93 class XOStaticOperand(_StaticOperand):
94 def __init__(self, XO):
95 value = (XO.value & XO.mask)
96 return super().__init__(name="XO", value=value)
97
98 def span(self, record):
99 return tuple(record.section.bitsel)
100
101 static_operands = [POStaticOperand(PO=PO)]
102 if XO is not None:
103 static_operands.append(XOStaticOperand(XO=XO))
104 static_operands.extend(record.mdwn.operands.static)
105 dynamic_operands = record.mdwn.operands.dynamic
106
107 def static_operand(operand):
108 return StaticOperand(name=operand.name,
109 value=operand.value, span=operand.span(record=record))
110
111 def dynamic_operand(operand):
112 return DynamicOperand(name=operand.name,
113 span=operand.span(record=record))
114
115 static_operands = tuple(map(static_operand, static_operands))
116 dynamic_operands = tuple(map(dynamic_operand, dynamic_operands))
117
118 yield Entry(name=record.name,
119 static_operands=static_operands,
120 dynamic_operands=dynamic_operands)
121
122
123 def opcodes(entry):
124 operands = entry.dynamic_operands
125 operands = ", ".join(operand.name for operand in operands)
126 string = ",\t".join((
127 f"\"{entry.name}\"",
128 f"XRC({entry.PO},{entry.XO},{entry.Rc})",
129 "X_MASK",
130 "SVP64",
131 "PPCVLE",
132 f"{{{operands}}}",
133 ))
134 return f"{{{string}}},"
135
136
137 def asm(entry, binutils=False, regex=False):
138 operands = tuple(entry.dynamic_operands)
139 for (idx, operand) in enumerate(operands):
140 values = []
141 for each in operands:
142 if binutils and each.name in ("FRT", "FRA", "FRB"):
143 values.append("f0")
144 elif binutils and each.name in ("RT", "RA", "RB"):
145 values.append("r0")
146 else:
147 values.append("0")
148 value = str((1 << len(operand.span)) - 1)
149 if binutils and operand.name in ("FRT", "FRA", "FRB"):
150 value = f"f{value}"
151 elif binutils and operand.name in ("RT", "RA", "RB"):
152 value = f"r{value}"
153 values[idx] = value
154 sep = "\s+" if regex else " "
155 yield f"{entry.name}{sep}{','.join(values)}"
156
157
158 def dis(entry, binutils=True):
159 def objdump(byte):
160 return f"{byte:02x}"
161
162 asm_plain = tuple(asm(entry, binutils=binutils, regex=False))
163 asm_regex = tuple(asm(entry, binutils=binutils, regex=True))
164 for (idx, dynamic_operand) in enumerate(entry.dynamic_operands):
165 insn = _WordInstruction.integer(value=0)
166 for static_operand in entry.static_operands:
167 span = static_operand.span
168 insn[span] = static_operand.value
169 span = dynamic_operand.span
170 insn[span] = ((1 << len(span)) - 1)
171 if binutils:
172 big = " ".join(map(objdump, insn.bytes(byteorder="big")))
173 little = " ".join(map(objdump, insn.bytes(byteorder="little")))
174 yield f".*:\s+({big}|{little})\s+{asm_regex[idx]}"
175 else:
176 yield asm_plain[idx]
177
178
179 class Mode(_enum.Enum):
180 OPCODES = "opcodes"
181 ASM = "asm"
182 DIS = "dis"
183
184 def __str__(self):
185 return self.name.lower()
186
187
188 if __name__ == "__main__":
189 parser = _argparse.ArgumentParser()
190 parser.add_argument("mode", type=Mode, choices=Mode)
191 args = dict(vars(parser.parse_args()))
192
193 mode = args["mode"]
194 db = _Database(_find_wiki_dir())
195 entries = sorted(collect(db))
196
197 generator = {
198 Mode.OPCODES: opcodes,
199 Mode.ASM: asm,
200 Mode.DIS: dis,
201 }[mode]
202 if mode is Mode.DIS:
203 print("#as: -mlibresoc")
204 print("#objdump: -dr -Mlibresoc")
205 print("")
206 print(".*: file format .*")
207 print("")
208 print("")
209 print("Disassembly of section \\.text:")
210 print("0+ <\.text>:")
211
212 if mode in {Mode.ASM, Mode.DIS}:
213 for subgenerator in map(generator, entries):
214 for line in subgenerator:
215 print(line)
216 else:
217 for line in map(generator, entries):
218 print(line)