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 Extra,
12 Record,
13 Visitor,
14 visit,
15 )
16
17
18 class Instruction(str):
19 def __new__(cls, string):
20 svp64 = False
21 if string.startswith("sv."):
22 string = string[len("sv."):]
23 svp64 = True
24 self = super().__new__(cls, string)
25 self.__svp64 = svp64
26 return self
27
28 @property
29 def svp64(self):
30 return self.__svp64
31
32
33 class SVP64Instruction(Instruction):
34 def __new__(cls, string):
35 self = super().__new__(cls, string)
36 if not self.svp64:
37 raise ValueError("illegal SVP64 instruction")
38 return self
39
40
41 class ListVisitor(Visitor):
42 @contextlib.contextmanager
43 def __call__(self, node):
44 if isinstance(node, Record):
45 print(node.name)
46 yield node
47
48
49 class OpcodesVisitor(Visitor):
50 @contextlib.contextmanager
51 def __call__(self, node):
52 if isinstance(node, Record):
53 for opcode in node.opcodes:
54 print(opcode)
55 yield node
56
57
58 class OperandsVisitor(Visitor):
59 @contextlib.contextmanager
60 def __call__(self, node):
61 if isinstance(node, Record):
62 for operand in node.dynamic_operands:
63 print(operand.name, ",".join(map(str, operand.span)))
64 for operand in node.static_operands:
65 if operand.name not in ("PO", "XO"):
66 desc = f"{operand.name}={operand.value}"
67 print(desc, ",".join(map(str, operand.span)))
68 yield node
69
70
71 class PCodeVisitor(Visitor):
72 @contextlib.contextmanager
73 def __call__(self, node):
74 if isinstance(node, Record):
75 for line in node.pcode:
76 print(line)
77 yield node
78
79
80 class ExtrasVisitor(Visitor):
81 @contextlib.contextmanager
82 def __call__(self, node):
83 if isinstance(node, Extra):
84 print(node.name)
85 print(" sel", node.sel)
86 print(" reg", node.reg)
87 print(" seltype", node.seltype)
88 print(" idx", node.idx)
89 yield node
90
91
92 def main():
93 commands = {
94 "list": (
95 ListVisitor,
96 "list available instructions",
97 ),
98 "opcodes": (
99 OpcodesVisitor,
100 "print instruction opcodes",
101 ),
102 "operands": (
103 OperandsVisitor,
104 "print instruction operands",
105 ),
106 "pcode": (
107 PCodeVisitor,
108 "print instruction pseudocode",
109 ),
110 "extras": (
111 ExtrasVisitor,
112 "print instruction extras (SVP64)",
113 ),
114 }
115
116 main_parser = argparse.ArgumentParser()
117 main_parser.add_argument("-l", "--log",
118 help="activate logging",
119 action="store_true",
120 default=False)
121 main_subparser = main_parser.add_subparsers(dest="command", required=True)
122
123 for (command, (visitor, helper)) in commands.items():
124 parser = main_subparser.add_parser(command, help=helper)
125 if command not in ("list",):
126 if command in ("extras",):
127 arg_cls = SVP64Instruction
128 else:
129 arg_cls = Instruction
130 parser.add_argument("insn", type=arg_cls,
131 metavar="INSN", help="instruction")
132
133 args = vars(main_parser.parse_args())
134 command = args.pop("command")
135 log = args.pop("log")
136 if not log:
137 os.environ["SILENCELOG"] = "true"
138 visitor = commands[command][0]()
139
140 db = Database(find_wiki_dir())
141 if command in ("list",):
142 match = None
143 else:
144 insn = args.pop("insn")
145 def match(record):
146 return (isinstance(record, Record) and (record.name == insn))
147
148 for node in db.subnodes(match=match):
149 visit(visitor=visitor, node=node)
150
151
152 if __name__ == "__main__":
153 main()