insndb: decouple visitors and walking
[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 RecordNameVisitor(Visitor):
39 def __init__(self, name):
40 self.__name = name
41 self.__records = set()
42 return super().__init__()
43
44 @contextlib.contextmanager
45 def Record(self, node):
46 if node.name == self.__name:
47 self.__records.add(node)
48 yield node
49
50 def __iter__(self):
51 yield from self.__records
52
53
54 class ListVisitor(Visitor):
55 @contextlib.contextmanager
56 def Record(self, node):
57 print(node.name)
58 yield node
59
60
61 class OpcodesVisitor(Visitor):
62 @contextlib.contextmanager
63 def Record(self, node):
64 for opcode in node.opcodes:
65 print(opcode)
66 yield node
67
68
69 class OperandsVisitor(Visitor):
70 @contextlib.contextmanager
71 def Record(self, node):
72 for operand in node.dynamic_operands:
73 print(operand.name, ",".join(map(str, operand.span)))
74 for operand in node.static_operands:
75 if operand.name not in ("PO", "XO"):
76 desc = f"{operand.name}={operand.value}"
77 print(desc, ",".join(map(str, operand.span)))
78 yield node
79
80
81 class PCodeVisitor(Visitor):
82 @contextlib.contextmanager
83 def Record(self, node):
84 for line in node.pcode:
85 print(line)
86 yield node
87
88
89 class ExtrasVisitor(Visitor):
90 @contextlib.contextmanager
91 def Extra(self, node):
92 print(node.name)
93 print(" sel", node.sel)
94 print(" reg", node.reg)
95 print(" seltype", node.seltype)
96 print(" idx", node.idx)
97 yield node
98
99
100 def main():
101 commands = {
102 "list": (
103 ListVisitor,
104 "list available instructions",
105 ),
106 "opcodes": (
107 OpcodesVisitor,
108 "print instruction opcodes",
109 ),
110 "operands": (
111 OperandsVisitor,
112 "print instruction operands",
113 ),
114 "pcode": (
115 PCodeVisitor,
116 "print instruction pseudocode",
117 ),
118 "extras": (
119 ExtrasVisitor,
120 "print instruction extras (SVP64)",
121 ),
122 }
123
124 main_parser = argparse.ArgumentParser()
125 main_parser.add_argument("-l", "--log",
126 help="activate logging",
127 action="store_true",
128 default=False)
129 main_subparser = main_parser.add_subparsers(dest="command", required=True)
130
131 for (command, (visitor, helper)) in commands.items():
132 parser = main_subparser.add_parser(command, help=helper)
133 if command not in ("list",):
134 if command in ("extras",):
135 arg_cls = SVP64Instruction
136 else:
137 arg_cls = Instruction
138 parser.add_argument("insn", type=arg_cls,
139 metavar="INSN", help="instruction")
140
141 args = vars(main_parser.parse_args())
142 command = args.pop("command")
143 log = args.pop("log")
144 if not log:
145 os.environ["SILENCELOG"] = "true"
146 visitor = commands[command][0]()
147
148 db = Database(find_wiki_dir())
149 if command in ("list",):
150 nodes = (db,)
151 else:
152 match = RecordNameVisitor(name=args["insn"])
153 with match(node=db):
154 nodes = frozenset(match)
155
156 for node in nodes:
157 with visitor(node=node):
158 pass
159
160
161 if __name__ == "__main__":
162 main()