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