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