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