insndb/db: switch to holy-cow visitors
[openpower-isa.git] / src / openpower / insndb / db.py
index 753ab626ab00e48ae5cd828f15bce7e1355d8d92..a5210f087c85f63ead87622ac161fec19554ffd2 100644 (file)
 import argparse
 import contextlib
-import sys
+import os
+import types
 
 from openpower.decoder.power_enums import (
     find_wiki_dir,
 )
-from openpower.insndb.types import (
+from openpower.insndb.core import (
     Database,
+    Extra,
+    Record,
+    Records,
     Visitor,
+    visit,
+    visitormethod,
 )
 
 
+class Instruction(str):
+    def __new__(cls, string):
+        svp64 = False
+        if string.startswith("sv."):
+            string = string[len("sv."):]
+            svp64 = True
+        self = super().__new__(cls, string)
+        self.__svp64 = svp64
+        return self
+
+    @property
+    def svp64(self):
+        return self.__svp64
+
+
+class SVP64Instruction(Instruction):
+    def __new__(cls, string):
+        self = super().__new__(cls, string)
+        if not self.svp64:
+            raise ValueError("illegal SVP64 instruction")
+        return self
+
+
+class ListVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, node):
+        print(node.name)
+        yield node
+
+
+class OpcodesVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, node):
+        for opcode in node.opcodes:
+            print(opcode)
+        yield node
+
+
+class OperandsVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, node):
+        if isinstance(node, Record):
+            for operand in node.dynamic_operands:
+                print(operand.name, ",".join(map(str, operand.span)))
+            for operand in node.static_operands:
+                if operand.name not in ("PO", "XO"):
+                    desc = f"{operand.name}={operand.value}"
+                    print(desc, ",".join(map(str, operand.span)))
+        yield node
+
+
+class PCodeVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, node):
+        if isinstance(node, Record):
+            for line in node.pcode:
+                print(line)
+        yield node
+
+
+class ExtrasVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, node):
+        for (name, extra) in node.extras.items():
+            print(name)
+            print("    sel", extra["sel"])
+            print("    reg", extra["reg"])
+            print("    seltype", extra["seltype"])
+            print("    idx", extra["idx"])
+        yield node
+
+
 def main():
-    class GenericVisitor(Visitor):
-        def __init__(self, **_):
-            pass
-
-    class ListVisitor(GenericVisitor):
-        @contextlib.contextmanager
-        def record(self, record):
-            print(record.name)
-            yield record
-
-    class OpcodesVisitor(GenericVisitor):
-        def __init__(self, insn, **_):
-            self.__insn = insn
-            return super().__init__()
-
-        @contextlib.contextmanager
-        def record(self, record):
-            if record.name == self.__insn:
-                for opcode in record.opcodes:
-                    print(opcode)
-            yield record
-
-    visitors = {
-        "list": ListVisitor,
-        "opcodes": OpcodesVisitor,
+    commands = {
+        "list": (
+            ListVisitor,
+            "list available instructions",
+        ),
+        "opcodes": (
+            OpcodesVisitor,
+            "print instruction opcodes",
+        ),
+        "operands": (
+            OperandsVisitor,
+            "print instruction operands",
+        ),
+        "pcode": (
+            PCodeVisitor,
+            "print instruction pseudocode",
+        ),
+        "extras": (
+            ExtrasVisitor,
+            "print instruction extras (SVP64)",
+        ),
     }
-    parser = argparse.ArgumentParser()
-    subparser = parser.add_subparsers(dest="command", required=True)
-    parser_list = subparser.add_parser("list",
-        help="list all instructions")
-    parser_opcodes = subparser.add_parser("opcodes",
-        help="print instruction opcodes")
-    parser_opcodes.add_argument("insn",
-        metavar="INSN",
-        help="instruction")
-
-    args = vars(parser.parse_args())
+
+    main_parser = argparse.ArgumentParser()
+    main_parser.add_argument("-l", "--log",
+        help="activate logging",
+        action="store_true",
+        default=False)
+    main_subparser = main_parser.add_subparsers(dest="command", required=True)
+
+    for (command, (visitor, helper)) in commands.items():
+        parser = main_subparser.add_parser(command, help=helper)
+        if command not in ("list",):
+            if command in ("extras",):
+                arg_cls = SVP64Instruction
+            else:
+                arg_cls = Instruction
+            parser.add_argument("insn", type=arg_cls,
+                metavar="INSN", help="instruction")
+
+    args = vars(main_parser.parse_args())
     command = args.pop("command")
-    visitor = visitors[command](**args)
+    log = args.pop("log")
+    if not log:
+        os.environ["SILENCELOG"] = "true"
+    visitor = commands[command][0]()
 
     db = Database(find_wiki_dir())
-    db.visit(visitor=visitor)
+    records = next(db.walk(match=lambda node: isinstance(node, Records)))
+    if command in ("list",):
+        match = None
+    else:
+        insn = args.pop("insn")
+        def match(record):
+            return (isinstance(record, Record) and (record.name == insn))
+
+    for node in records.walk(match=match):
+        visit(visitor=visitor, node=node)
+
+
+if __name__ == "__main__":
+    main()