insndb/db: switch to holy-cow 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 Extra,
12 Record,
13 Records,
14 Visitor,
15 visit,
16 visitormethod,
17 )
18
19
20 class Instruction(str):
21 def __new__(cls, string):
22 svp64 = False
23 if string.startswith("sv."):
24 string = string[len("sv."):]
25 svp64 = True
26 self = super().__new__(cls, string)
27 self.__svp64 = svp64
28 return self
29
30 @property
31 def svp64(self):
32 return self.__svp64
33
34
35 class SVP64Instruction(Instruction):
36 def __new__(cls, string):
37 self = super().__new__(cls, string)
38 if not self.svp64:
39 raise ValueError("illegal SVP64 instruction")
40 return self
41
42
43 class ListVisitor(Visitor):
44 @visitormethod(Record)
45 def Record(self, node):
46 print(node.name)
47 yield node
48
49
50 class OpcodesVisitor(Visitor):
51 @visitormethod(Record)
52 def Record(self, node):
53 for opcode in node.opcodes:
54 print(opcode)
55 yield node
56
57
58 class OperandsVisitor(Visitor):
59 @visitormethod(Record)
60 def Record(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 @visitormethod(Record)
73 def Record(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 @visitormethod(Record)
82 def Record(self, node):
83 for (name, extra) in node.extras.items():
84 print(name)
85 print(" sel", extra["sel"])
86 print(" reg", extra["reg"])
87 print(" seltype", extra["seltype"])
88 print(" idx", extra["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 records = next(db.walk(match=lambda node: isinstance(node, Records)))
142 if command in ("list",):
143 match = None
144 else:
145 insn = args.pop("insn")
146 def match(record):
147 return (isinstance(record, Record) and (record.name == insn))
148
149 for node in records.walk(match=match):
150 visit(visitor=visitor, node=node)
151
152
153 if __name__ == "__main__":
154 main()