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