pysvp64dis: introduce disassemble routine
[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):
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) or (value < 0) or (value > ((1 << 32) - 1)):
32 raise ValueError(value)
33
34 return super().__init__(value=value, bits=32)
35
36 def __repr__(self):
37 return f"{self.__class__.__name__}({self.value:08x})"
38
39 def disassemble(self):
40 if self.dbrecord is None:
41 yield f".long 0x{self.value:08x}"
42 else:
43 yield f".long 0x{self.value:08x} # {self.dbrecord.name}"
44
45 @property
46 def major(self):
47 return self[0:6]
48
49 @property
50 def dbrecord(self):
51 try:
52 return DATABASE[int(self)]
53 except KeyError:
54 return None
55
56
57 class PrefixedInstruction(_SelectableInt):
58 def __init__(self, prefix, suffix, byteorder=ByteOrder.LITTLE):
59 insn = _functools.partial(Instruction, byteorder=byteorder)
60 (prefix, suffix) = map(insn, (prefix, suffix))
61 value = ((prefix.value << 32) | suffix.value)
62 return super().__init__(value=value, bits=64)
63
64 def __repr__(self):
65 return f"{self.__class__.__name__}({self.value:016x})"
66
67 def disassemble(self):
68 if self.dbrecord is None:
69 yield f".llong 0x{self.value:08x}"
70 else:
71 yield f".llong 0x{self.value:08x} # {self.dbrecord.name}"
72
73 @property
74 def prefix(self):
75 return Instruction(self[0:32])
76
77 @property
78 def suffix(self):
79 return Instruction(self[32:64])
80
81 @property
82 def dbrecord(self):
83 return self.suffix.dbrecord
84
85
86 class SVP64Instruction(PrefixedInstruction):
87 class PrefixError(ValueError):
88 pass
89
90 class Prefix(_SVP64PrefixFields, Instruction):
91 class RM(_SVP64RMFields):
92 @property
93 def sv_mode(self):
94 return (self.mode & 0b11)
95
96 @property
97 def rm(self):
98 return self.__class__.RM(super().rm)
99
100 class Suffix(Instruction):
101 pass
102
103 def __init__(self, prefix, suffix, byteorder=ByteOrder.LITTLE):
104 if SVP64Instruction.Prefix(prefix).pid != 0b11:
105 raise SVP64Instruction.PrefixError(prefix)
106 return super().__init__(prefix, suffix, byteorder)
107
108 def disassemble(self):
109 if self.dbrecord is None:
110 yield f".llong 0x{self.value:08x}"
111 else:
112 yield f".llong 0x{self.value:08x} # sv.{self.dbrecord.name}"
113
114 @property
115 def prefix(self):
116 return self.__class__.Prefix(super().prefix)
117
118 @property
119 def suffix(self):
120 return self.__class__.Suffix(super().suffix)
121
122
123 def load(ifile, byteorder, **_):
124 def load(ifile):
125 prefix = ifile.read(4)
126 length = len(prefix)
127 if length == 0:
128 return None
129 elif length < 4:
130 raise IOError(prefix)
131 prefix = Instruction(prefix, byteorder)
132 if prefix.major != 0x1:
133 return Instruction(prefix, byteorder)
134
135 suffix = ifile.read(4)
136 length = len(suffix)
137 if length == 0:
138 return prefix
139 elif length < 4:
140 raise IOError(suffix)
141 try:
142 return SVP64Instruction(prefix, suffix, byteorder)
143 except SVP64Instruction.PrefixError:
144 return PrefixedInstruction(prefix, suffix, byteorder)
145
146 while True:
147 insn = load(ifile)
148 if insn is None:
149 break
150 yield insn
151
152
153 def dump(insns, ofile, **_):
154 for insn in insns:
155 yield from insn.disassemble()
156
157
158 def main():
159 parser = _argparse.ArgumentParser()
160 parser.add_argument("ifile", nargs="?",
161 type=_argparse.FileType("rb"), default=_sys.stdin.buffer)
162 parser.add_argument("ofile", nargs="?",
163 type=_argparse.FileType("w"), default=_sys.stdout)
164 parser.add_argument("-b", "--byteorder",
165 type=ByteOrder, default=ByteOrder.LITTLE)
166
167 args = dict(vars(parser.parse_args()))
168 ifile = args["ifile"]
169 ofile = args["ofile"]
170 byteorder = args["byteorder"]
171
172 insns = load(ifile, byteorder)
173 for line in dump(insns, byteorder):
174 print(line, file=ofile)
175
176
177 if __name__ == "__main__":
178 main()