insndb/db: refactor visitors
[openpower-isa.git] / src / openpower / insndb / db.py
1 import argparse
2 import contextlib
3 import os
4 import types
5
6 from openpower.decoder.power_enums import (
7 find_wiki_dir,
8 )
9 from openpower.insndb.core import (
10 Database,
11 Visitor,
12 )
13
14
15 class Instruction(str):
16 def __new__(cls, string):
17 svp64 = False
18 if string.startswith("sv."):
19 string = string[len("sv."):]
20 svp64 = True
21 self = super().__new__(cls, string)
22 self.__svp64 = svp64
23 return self
24
25 @property
26 def svp64(self):
27 return self.__svp64
28
29
30 class SVP64Instruction(Instruction):
31 def __new__(cls, string):
32 self = super().__new__(cls, string)
33 if not self.svp64:
34 raise ValueError("illegal SVP64 instruction")
35 return self
36
37
38 class BaseVisitor(Visitor):
39 def __init__(self, **arguments):
40 self.__arguments = types.MappingProxyType(arguments)
41 self.__current_db = None
42 self.__current_record = None
43 self.__current_extra = None
44 return super().__init__()
45
46 @property
47 def arguments(self):
48 return self.__arguments
49
50 @property
51 def current_db(self):
52 return self.__current_db
53
54 @property
55 def current_record(self):
56 return self.__current_record
57
58 @property
59 def current_extra(self):
60 return self.__current_extra
61
62 @contextlib.contextmanager
63 def db(self, db):
64 self.__current_db = db
65 yield db
66 self.__current_db = None
67
68 @contextlib.contextmanager
69 def record(self, record):
70 self.__current_record = record
71 yield record
72 self.__current_record = None
73
74 @contextlib.contextmanager
75 def extra(self, extra):
76 self.__current_extra = extra
77 yield extra
78 self.__current_extra = None
79
80
81 class ListVisitor(BaseVisitor):
82 @contextlib.contextmanager
83 def record(self, record):
84 print(record.name)
85 yield record
86
87
88 class InstructionVisitor(BaseVisitor):
89 pass
90
91
92 class SVP64InstructionVisitor(InstructionVisitor):
93 pass
94
95
96 class OpcodesVisitor(InstructionVisitor):
97 @contextlib.contextmanager
98 def record(self, record):
99 for opcode in record.opcodes:
100 print(opcode)
101
102
103 class OperandsVisitor(InstructionVisitor):
104 @contextlib.contextmanager
105 def record(self, record):
106 with super().record(record=record):
107 if self.current_record.name == self.arguments["insn"]:
108 for operand in record.dynamic_operands:
109 print(operand.name, ",".join(map(str, operand.span)))
110 for operand in record.static_operands:
111 if operand.name not in ("PO", "XO"):
112 desc = f"{operand.name}={operand.value}"
113 print(desc, ",".join(map(str, operand.span)))
114
115 yield record
116
117
118 class PCodeVisitor(InstructionVisitor):
119 @contextlib.contextmanager
120 def record(self, record):
121 with super().record(record=record):
122 if self.current_record.name == self.arguments["insn"]:
123 for line in record.pcode:
124 print(line)
125
126
127 class ExtrasVisitor(SVP64InstructionVisitor):
128 @contextlib.contextmanager
129 def extra(self, extra):
130 with super().extra(extra=extra) as extra:
131 if self.current_record.name == self.arguments["insn"]:
132 print(extra.name)
133 print(" sel", extra.sel)
134 print(" reg", extra.reg)
135 print(" seltype", extra.seltype)
136 print(" idx", extra.idx)
137 pass
138
139 yield extra
140
141
142 def main():
143 commands = {
144 "list": (
145 ListVisitor,
146 "list available instructions",
147 ),
148 "opcodes": (
149 OpcodesVisitor,
150 "print instruction opcodes",
151 ),
152 "operands": (
153 OperandsVisitor,
154 "print instruction operands",
155 ),
156 "pcode": (
157 PCodeVisitor,
158 "print instruction pseudocode",
159 ),
160 "extras": (
161 ExtrasVisitor,
162 "print instruction extras (SVP64)",
163 ),
164 }
165
166 main_parser = argparse.ArgumentParser()
167 main_parser.add_argument("-l", "--log",
168 help="activate logging",
169 action="store_true",
170 default=False)
171 main_subparser = main_parser.add_subparsers(dest="command", required=True)
172
173 for (command, (visitor, help)) in commands.items():
174 parser = main_subparser.add_parser(command, help=help)
175 if issubclass(visitor, InstructionVisitor):
176 if issubclass(visitor, SVP64InstructionVisitor):
177 arg_cls = SVP64Instruction
178 else:
179 arg_cls = Instruction
180 parser.add_argument("insn", type=arg_cls,
181 metavar="INSN", help="instruction")
182
183 args = vars(main_parser.parse_args())
184 command = args.pop("command")
185 log = args.pop("log")
186 if not log:
187 os.environ["SILENCELOG"] = "true"
188 visitor = commands[command][0](**args)
189
190 db = Database(find_wiki_dir())
191 db.visit(visitor=visitor)
192
193
194 if __name__ == "__main__":
195 main()