temporary hack-revert, the original is now in branch "paths"
[openpower-isa.git] / src / openpower / insndb / db.py
index 1ddb578e7ccb28a63c7e5ad0e83054e5f04330ce..fa5eb267ea7ae14f442183b260c2580b16d56a80 100644 (file)
 import argparse
 import contextlib
-import sys
+import os
+import types
 
 from openpower.decoder.power_enums import (
     find_wiki_dir,
 )
 from openpower.insndb.core import (
     Database,
+    Dataclass,
+    Dict,
+    Record,
+    Records,
+    Tuple,
     Visitor,
+    visit,
+    visitormethod,
 )
 
 
-class BaseVisitor(Visitor):
-    def __init__(self, **_):
-        pass
+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 ListVisitor(BaseVisitor):
-    @contextlib.contextmanager
-    def record(self, record):
-        print(record.name)
-        yield record
 
+class SVP64Instruction(Instruction):
+    def __new__(cls, string):
+        self = super().__new__(cls, string)
+        if not self.svp64:
+            raise ValueError("illegal SVP64 instruction")
+        return self
 
-class ConcreteInstructionVisitor(BaseVisitor):
-    def __init__(self, insn, **_):
-        self.__insn = insn
-        return super().__init__()
 
-    def handler(self, record):
-        raise NotImplementedError
+class TreeVisitor(Visitor):
+    def __init__(self):
+        self.__depth = 0
+        self.__path = [""]
+        return super().__init__()
 
     @contextlib.contextmanager
-    def record(self, record):
-        if record.name == self.__insn:
-            self.handler(record=record)
-        yield record
+    def __call__(self, path, node):
+        with super().__call__(path=path, node=node):
+            self.__path.append(path)
+            print("/".join(self.__path))
+            if not isinstance(node, (Dataclass, Tuple, Dict)):
+                print("    ", repr(node), sep="")
+            self.__depth += 1
+            yield node
+            self.__path.pop(-1)
+            self.__depth -= 1
 
 
-class OpcodesVisitor(ConcreteInstructionVisitor):
-    def handler(self, record):
-        for opcode in record.opcodes:
-            print(opcode)
+class ListVisitor(Visitor):
+    @visitormethod(Record)
+    def Record(self, path, node):
+        print(node.name)
+        yield node
+
+
+# No use other than checking issubclass and adding an argument.
+class InstructionVisitor(Visitor):
+    pass
 
+class SVP64InstructionVisitor(InstructionVisitor):
+    pass
 
-class OperandsVisitor(ConcreteInstructionVisitor):
-    def handler(self, record):
-        for operand in record.dynamic_operands:
-            print(operand.name)
-        for operand in record.static_operands:
-            if operand.name not in ("PO", "XO"):
-                print(operand.name, operand.value, sep="=")
+
+class OpcodesVisitor(InstructionVisitor):
+    @visitormethod(Record)
+    def Record(self, path, node):
+        for opcode in node.opcodes:
+            print(opcode)
+        yield node
+
+
+class OperandsVisitor(InstructionVisitor):
+    @visitormethod(Record)
+    def Record(self, path, 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(InstructionVisitor):
+    @visitormethod(Record)
+    def Record(self, path, node):
+        if isinstance(node, Record):
+            for line in node.pcode:
+                print(line)
+        yield node
+
+
+class ExtrasVisitor(SVP64InstructionVisitor):
+    @visitormethod(Record)
+    def Record(self, path, 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():
-    visitors = {
-        "list": ListVisitor,
-        "opcodes": OpcodesVisitor,
-        "operands": OperandsVisitor,
+    commands = {
+        "tree": (
+            TreeVisitor,
+            "list all records",
+        ),
+        "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)",
+        ),
     }
+
     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)
-    main_subparser.add_parser("list",
-        help="list all instructions")
 
-    for (command, help) in {
-                "opcodes": "print instruction opcodes",
-                "operands": "print instruction operands",
-            }.items():
-        parser = main_subparser.add_parser(command, help=help)
-        parser.add_argument("insn", metavar="INSN", help="instruction")
+    for (command, (visitor, helper)) in commands.items():
+        parser = main_subparser.add_parser(command, help=helper)
+        if issubclass(visitor, InstructionVisitor):
+            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)
+    (path, records) = next(db.walk(match=lambda pair: isinstance(pair, Records)))
+    if not isinstance(visitor, InstructionVisitor):
+        match = lambda _: True
+    else:
+        insn = args.pop("insn")
+        def match(record):
+            return (isinstance(record, Record) and (record.name == insn))
+
+    for (subpath, node) in records.walk(match=match):
+        visit(visitor=visitor, node=node, path=subpath)
+
+
+if __name__ == "__main__":
+    main()