pysvp64dis: refactor inheritance model
[openpower-isa.git] / src / openpower / sv / trans / pysvp64dis.py
1 import argparse as _argparse
2 import enum as _enum
3 import functools as _functools
4 import sys as _sys
5
6 from openpower.decoder.power_enums import find_wiki_dir as _find_wiki_dir
7 from openpower.decoder.power_insn import Database as _Database
8 from openpower.decoder.selectable_int import SelectableInt as _SelectableInt
9 from openpower.decoder.isa.caller import SVP64PrefixFields as _SVP64PrefixFields
10 from openpower.decoder.isa.caller import SVP64RMFields as _SVP64RMFields
11
12
13 class ByteOrder(_enum.Enum):
14 LITTLE = "little"
15 BIG = "big"
16
17 def __str__(self):
18 return self.name.lower()
19
20
21 DATABASE = _Database(_find_wiki_dir())
22
23
24 class Instruction(_SelectableInt):
25 def __init__(self, value, byteorder=ByteOrder.LITTLE, bits=32):
26 if isinstance(value, _SelectableInt):
27 value = value.value
28 elif isinstance(value, bytes):
29 value = int.from_bytes(value, byteorder=str(byteorder))
30
31 if not isinstance(value, int):
32 raise ValueError(value)
33 if not isinstance(bits, int) or (bits not in {32, 64}):
34 raise ValueError(bits)
35
36 return super().__init__(value=value, bits=bits)
37
38 def __repr__(self):
39 return f"{self.__class__.__name__}({self.value:08x})"
40
41 def disassemble(self):
42 if self.dbrecord is None:
43 yield f".long 0x{self.value:08x}"
44 else:
45 yield f".long 0x{self.value:08x} # {self.dbrecord.name}"
46
47 @property
48 def major(self):
49 return self[0:6]
50
51 @property
52 def dbrecord(self):
53 try:
54 return DATABASE[int(self)]
55 except KeyError:
56 return None
57
58
59 class PrefixedInstruction(Instruction):
60 def __init__(self, prefix, suffix, byteorder=ByteOrder.LITTLE):
61 insn = _functools.partial(Instruction, byteorder=byteorder)
62 (prefix, suffix) = map(insn, (prefix, suffix))
63 value = ((prefix.value << 32) | suffix.value)
64 return super().__init__(value=value, bits=64)
65
66 def __repr__(self):
67 return f"{self.__class__.__name__}({self.value:016x})"
68
69 def disassemble(self):
70 if self.dbrecord is None:
71 yield f".llong 0x{self.value:08x}"
72 else:
73 yield f".llong 0x{self.value:08x} # {self.dbrecord.name}"
74
75 @property
76 def prefix(self):
77 return Instruction(self[0:32])
78
79 @property
80 def suffix(self):
81 return Instruction(self[32:64])
82
83 @property
84 def major(self):
85 return self.suffix.major
86
87 @property
88 def dbrecord(self):
89 return self.suffix.dbrecord
90
91
92 class SVP64Instruction(PrefixedInstruction):
93 class PrefixError(ValueError):
94 pass
95
96 class Prefix(_SVP64PrefixFields, Instruction):
97 class RM(_SVP64RMFields):
98 @property
99 def sv_mode(self):
100 return (self.mode & 0b11)
101
102 @property
103 def rm(self):
104 return self.__class__.RM(super().rm)
105
106 class Suffix(Instruction):
107 pass
108
109 def __init__(self, prefix, suffix, byteorder=ByteOrder.LITTLE):
110 if SVP64Instruction.Prefix(prefix).pid != 0b11:
111 raise SVP64Instruction.PrefixError(prefix)
112 return super().__init__(prefix, suffix, byteorder)
113
114 def disassemble(self):
115 if self.dbrecord is None:
116 yield f".llong 0x{self.value:08x}"
117 else:
118 yield f".llong 0x{self.value:08x} # sv.{self.dbrecord.name}"
119
120 @property
121 def prefix(self):
122 return self.__class__.Prefix(super().prefix)
123
124 @property
125 def suffix(self):
126 return self.__class__.Suffix(super().suffix)
127
128
129 def load(ifile, byteorder, **_):
130 def load(ifile):
131 prefix = ifile.read(4)
132 length = len(prefix)
133 if length == 0:
134 return None
135 elif length < 4:
136 raise IOError(prefix)
137 prefix = Instruction(prefix, byteorder)
138 if prefix.major != 0x1:
139 return Instruction(prefix, byteorder)
140
141 suffix = ifile.read(4)
142 length = len(suffix)
143 if length == 0:
144 return prefix
145 elif length < 4:
146 raise IOError(suffix)
147 try:
148 return SVP64Instruction(prefix, suffix, byteorder)
149 except SVP64Instruction.PrefixError:
150 return PrefixedInstruction(prefix, suffix, byteorder)
151
152 while True:
153 insn = load(ifile)
154 if insn is None:
155 break
156 yield insn
157
158
159 def dump(insns, ofile, **_):
160 for insn in insns:
161 yield from insn.disassemble()
162
163
164 def main():
165 parser = _argparse.ArgumentParser()
166 parser.add_argument("ifile", nargs="?",
167 type=_argparse.FileType("rb"), default=_sys.stdin.buffer)
168 parser.add_argument("ofile", nargs="?",
169 type=_argparse.FileType("w"), default=_sys.stdout)
170 parser.add_argument("-b", "--byteorder",
171 type=ByteOrder, default=ByteOrder.LITTLE)
172
173 args = dict(vars(parser.parse_args()))
174 ifile = args["ifile"]
175 ofile = args["ofile"]
176 byteorder = args["byteorder"]
177
178 insns = load(ifile, byteorder)
179 for line in dump(insns, byteorder):
180 print(line, file=ofile)
181
182
183 if __name__ == "__main__":
184 main()