pysvp64dis: consult the instruction database
[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 try:
13 from functools import cached_property
14 except ImportError:
15 from cached_property import cached_property
16
17
18 class ByteOrder(_enum.Enum):
19 LITTLE = "little"
20 BIG = "big"
21
22 def __str__(self):
23 return self.name.lower()
24
25
26 DATABASE = _Database(_find_wiki_dir())
27
28
29 class Instruction(_SelectableInt):
30 def __init__(self, value, byteorder=ByteOrder.LITTLE):
31 if isinstance(value, _SelectableInt):
32 value = value.value
33 elif isinstance(value, bytes):
34 value = int.from_bytes(value, byteorder=str(byteorder))
35
36 if not isinstance(value, int) or (value < 0) or (value > ((1 << 32) - 1)):
37 raise ValueError(value)
38
39 return super().__init__(value=value, bits=32)
40
41 def __repr__(self):
42 return f"{self.__class__.__name__}({self.value:08x})"
43
44 def __str__(self):
45 return f".long 0x{self.value:08x}"
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(_SelectableInt):
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 __str__(self):
70 return f".llong 0x{self.value:016x}"
71
72 @cached_property
73 def prefix(self):
74 return Instruction(self[0:32])
75
76 @cached_property
77 def suffix(self):
78 return Instruction(self[32:64])
79
80 @cached_property
81 def dbrecord(self):
82 return self.suffix.dbrecord
83
84
85 class SVP64Instruction(PrefixedInstruction):
86 class PrefixError(ValueError):
87 pass
88
89 class Prefix(_SVP64PrefixFields, Instruction):
90 class RM(_SVP64RMFields):
91 @cached_property
92 def sv_mode(self):
93 return (self.mode & 0b11)
94
95 @cached_property
96 def rm(self):
97 return self.__class__.RM(super().rm)
98
99 class Suffix(Instruction):
100 pass
101
102 def __init__(self, prefix, suffix, byteorder=ByteOrder.LITTLE):
103 if SVP64Instruction.Prefix(prefix).pid != 0b11:
104 raise SVP64Instruction.PrefixError(prefix)
105 return super().__init__(prefix, suffix, byteorder)
106
107 def __str__(self):
108 return (super().__str__() + " # sv")
109
110 @cached_property
111 def prefix(self):
112 return self.__class__.Prefix(super().prefix)
113
114 @cached_property
115 def suffix(self):
116 return self.__class__.Suffix(super().suffix)
117
118
119 def load(ifile, byteorder, **_):
120 def load(ifile):
121 prefix = ifile.read(4)
122 length = len(prefix)
123 if length == 0:
124 return None
125 elif length < 4:
126 raise IOError(prefix)
127 prefix = Instruction(prefix, byteorder)
128 if prefix.major != 0x1:
129 return Instruction(prefix, byteorder)
130
131 suffix = ifile.read(4)
132 length = len(suffix)
133 if length == 0:
134 return prefix
135 elif length < 4:
136 raise IOError(suffix)
137 try:
138 return SVP64Instruction(prefix, suffix, byteorder)
139 except SVP64Instruction.PrefixError:
140 return PrefixedInstruction(prefix, suffix, byteorder)
141
142 while True:
143 insn = load(ifile)
144 if insn is None:
145 break
146 yield insn
147
148
149 def dump(insns, ofile, **_):
150 for insn in insns:
151 yield str(insn)
152
153
154 def main():
155 parser = _argparse.ArgumentParser()
156 parser.add_argument("ifile", nargs="?",
157 type=_argparse.FileType("rb"), default=_sys.stdin.buffer)
158 parser.add_argument("ofile", nargs="?",
159 type=_argparse.FileType("w"), default=_sys.stdout)
160 parser.add_argument("-b", "--byteorder",
161 type=ByteOrder, default=ByteOrder.LITTLE)
162
163 args = dict(vars(parser.parse_args()))
164 ifile = args["ifile"]
165 ofile = args["ofile"]
166 byteorder = args["byteorder"]
167
168 insns = load(ifile, byteorder)
169 for line in dump(insns, byteorder):
170 print(line, file=ofile)
171
172
173 if __name__ == "__main__":
174 main()