libsvp64: rename into libopid
authorDmitry Selyutin <ghostmansd@gmail.com>
Fri, 8 Sep 2023 06:47:31 +0000 (09:47 +0300)
committerDmitry Selyutin <ghostmansd@gmail.com>
Sun, 10 Sep 2023 20:29:53 +0000 (23:29 +0300)
src/libopid/.gitignore [new file with mode: 0644]
src/libopid/Makefile [new file with mode: 0644]
src/libopid/codegen.py [new file with mode: 0644]
src/libopid/opid.h [new file with mode: 0644]
src/libsvp64/.gitignore [deleted file]
src/libsvp64/Makefile [deleted file]
src/libsvp64/codegen.py [deleted file]
src/libsvp64/svp64.h [deleted file]

diff --git a/src/libopid/.gitignore b/src/libopid/.gitignore
new file mode 100644 (file)
index 0000000..d72be3e
--- /dev/null
@@ -0,0 +1,3 @@
+*-gen.*
+*.a
+*.so
diff --git a/src/libopid/Makefile b/src/libopid/Makefile
new file mode 100644 (file)
index 0000000..46bfbf1
--- /dev/null
@@ -0,0 +1,50 @@
+CC?=gcc
+AR?=ar
+CFLAGS?=-O3 -Werror -Wall -Wextra
+PYTHON?=python3
+
+
+GENS:=\
+       opid-dis-gen.c \
+       opid-opc-gen.c \
+
+SRCS:=$(GENS)
+
+OBJS:=\
+       opid-dis-gen.o \
+       opid-opc-gen.o \
+
+
+.SUFFIX: .so .a .o .c
+
+
+.PHONY: all
+all: build
+
+
+.PHONY: build
+build: libopid.so
+
+
+.PHONY: clean
+clean:
+       rm -f $(GENS)
+       rm -f $(OBJS)
+       rm -f libopid.so
+       rm -f libopid.a
+
+
+libopid.so: libopid.a
+       $(CC) -fPIC -shared -o $@ -L. -Wl,--whole-archive libopid.a -Wl,--no-whole-archive
+
+
+libopid.a: $(OBJS)
+       $(AR) rcs $@ $^
+
+
+ $(GENS): codegen.py
+       SILENCELOG=true $(PYTHON) codegen.py $@ > $@
+
+
+.c.o:
+       $(CC) $(CFLAGS) -fPIC -c $< -o $@
diff --git a/src/libopid/codegen.py b/src/libopid/codegen.py
new file mode 100644 (file)
index 0000000..1d0f11d
--- /dev/null
@@ -0,0 +1,520 @@
+import argparse
+import collections
+import contextlib
+import dataclasses
+import enum
+import itertools
+import pathlib
+import sys
+
+import mdis.dispatcher
+import mdis.visitor
+import mdis.walker
+
+from openpower.decoder.power_enums import (
+    find_wiki_dir,
+)
+
+import openpower.insndb.core as insndb
+
+
+def traverse(root, visitor, walker, **kwargs):
+    with visitor(root, **kwargs):
+        for (node, *_, path, pathcls) in walker(root):
+            traverse(node, visitor, walker, path=path, pathcls=pathcls)
+
+
+def fetch(span):
+    bits = len(span)
+    one = "UINT32_C(1)"
+    for (dst, origin) in enumerate(span):
+        src = (32 - (origin + 1))
+        dst = (bits - (dst + 1))
+        dst = f"UINT32_C({dst})"
+        src = f"UINT32_C({src})"
+        yield f"/* {origin:<2} */ (((insn >> {src}) & {one}) << {dst}) |"
+    yield f"UINT32_C(0)"
+
+
+class Mode(enum.Enum):
+    PPC_DIS_GEN_C = "opid-dis-gen.c"
+    PPC_OPC_GEN_C = "opid-opc-gen.c"
+
+    def __call__(self, db, **arguments):
+        def pairwise(iterable):
+            (a, b) = itertools.tee(iterable)
+            next(b, None)
+            return zip(a, b)
+
+        cache = Cache()
+        codegen = {
+            Mode.PPC_DIS_GEN_C: DisGenSource,
+            Mode.PPC_OPC_GEN_C: OpcGenSource,
+        }[self](cache=cache, **arguments)
+        for (root, visitor) in pairwise((db, cache, codegen),):
+            walker_cls = getattr(visitor, "Walker", Walker)
+            traverse(root=root, visitor=visitor, walker=walker_cls())
+
+
+class StructMeta(type):
+    def __new__(metacls, name, bases, ns):
+        cls = super().__new__(metacls, name, bases, ns)
+        return dataclasses.dataclass(cls, eq=True, frozen=True)
+
+
+class Struct(metaclass=StructMeta):
+    pass
+
+
+class DynamicOperandIds(tuple): pass
+class StaticOperands(tuple): pass
+class DynamicOperands(tuple): pass
+class POTable(tuple): pass
+class Records(tuple): pass
+
+
+class DynamicOperandId(Struct):
+    name: str = "NIL"
+    index: int = 0
+
+
+class DynamicOperand(Struct):
+    cls: type
+    span: tuple
+    names: tuple
+
+
+class Record(Struct):
+    name: str
+    opcode: insndb.Record.Opcode
+    dynamic_operand_ids: DynamicOperandIds
+    static_operands: StaticOperands
+
+
+class Cache(mdis.visitor.ContextVisitor):
+    def __init__(self):
+        self.__PO = ([0] * (1 << 6))
+        self.__records = collections.defaultdict(list)
+        self.__static_operand = collections.defaultdict(list)
+        self.__dynamic_operand = collections.defaultdict(set)
+        self.__dynamic_operand_id = collections.defaultdict(list)
+
+        return super().__init__()
+
+    def __iter__(self):
+        table = tuple(self.__dynamic_operand.keys())
+        nil = DynamicOperandId()
+
+        def dynamic_operand_id(item):
+            (name, cls, span) = item
+            index = (table.index((cls, span),) + 1)
+            return DynamicOperandId(name=name, index=index)
+
+        def dynamic_operand(item):
+            ((cls, span), names) = item
+            return DynamicOperand(cls=cls, span=span, names=tuple(sorted(names)))
+
+        def record(item):
+            (opcode, name) = item
+            dynamic_operand_ids = map(dynamic_operand_id, self.__dynamic_operand_id[name])
+            dynamic_operand_ids = DynamicOperandIds(tuple(dynamic_operand_ids) + (nil,))
+            static_operands = StaticOperands(self.__static_operand[name])
+
+            return Record(opcode=opcode, name=name,
+                dynamic_operand_ids=dynamic_operand_ids,
+                static_operands=static_operands)
+
+        yield DynamicOperands(map(dynamic_operand, self.__dynamic_operand.items()))
+        yield Records(map(record, sorted(self.__records.items())))
+        yield POTable(self.__PO)
+
+    @mdis.dispatcher.Hook(insndb.Record)
+    @contextlib.contextmanager
+    def dispatch_record(self, node):
+        self.__record = node
+        yield node
+
+    @mdis.dispatcher.Hook(insndb.Record.Opcode)
+    @contextlib.contextmanager
+    def dispatch_record_opcode(self, node):
+        self.__records[node] = self.__record.name
+        self.__PO[self.__record.PO] += 1
+        yield node
+
+    @mdis.dispatcher.Hook(insndb.StaticOperand)
+    @contextlib.contextmanager
+    def dispatch_static_operand(self, node):
+        self.__static_operand[self.__record.name].append(node)
+        yield node
+
+    @mdis.dispatcher.Hook(insndb.DynamicOperand)
+    @contextlib.contextmanager
+    def dispatch_dynamic_operand(self, node):
+        (cls, span) = (node.__class__, node.span)
+        self.__dynamic_operand[cls, span].add(node.name)
+        self.__dynamic_operand_id[self.__record.name].append((node.name, cls, span),)
+        yield node
+
+
+class Walker(insndb.Walker):
+    @mdis.dispatcher.Hook(Cache)
+    def dispatch_cache(self, node):
+        yield from ()
+
+
+class Codegen(mdis.visitor.ContextVisitor):
+    def __init__(self, cache, **arguments):
+        self.__level = 0
+
+        return super().__init__()
+
+    def __enter__(self):
+        self.__level += 1
+        return self
+
+    def __exit__(self, exc_type, exc_value, exc_traceback):
+        self.__level -= 1
+
+    def emit(self, message=""):
+        indent = ((" " * 4 * self.__level) if message else "")
+        print(f"{indent}{message}")
+
+    @mdis.dispatcher.Hook(Cache)
+    @contextlib.contextmanager
+    def dispatch_cache(self, node):
+        self.emit("/*")
+        self.emit(" * Autogenerated by libresoc codegen script")
+        self.emit(" * DO NOT EDIT: all changes will be lost")
+        self.emit(" */")
+        self.emit("")
+        yield node
+
+
+class Header(Codegen):
+    pass
+
+
+class Source(Codegen):
+    @mdis.dispatcher.Hook(str)
+    @contextlib.contextmanager
+    def dispatch_str(self, node, *, path, pathcls):
+        self.emit(f"{pathcls(path)} = \"{node}\",")
+        with self: yield node
+
+    @mdis.dispatcher.Hook(object)
+    @contextlib.contextmanager
+    def dispatch_object(self, node, *, path, pathcls):
+        self.emit(f"{pathcls(path)} = {{")
+        with self: yield node
+        self.emit("},")
+
+
+class Record(Struct):
+    static_operands: StaticOperands
+    name: str
+    opcode: insndb.Record.Opcode
+    dynamic_operand_ids: DynamicOperandIds
+
+
+class DisGenSource(Source):
+    class Walker(Walker):
+        @mdis.dispatcher.Hook(DynamicOperand, Records)
+        def dispatch_ignore(self, node):
+            yield from ()
+
+        @mdis.dispatcher.Hook(Cache)
+        def dispatch_cache(self, node):
+            (operands, _, _) = node
+            yield from self([operands])
+
+    @mdis.dispatcher.Hook(DynamicOperands)
+    @contextlib.contextmanager
+    def dispatch_operands(self, node):
+        self.emit("static inline enum opid_state")
+        self.emit("opid_disassemble_operand(struct opid_ctx *ctx, uint32_t insn, size_t id) {")
+        with self:
+            self.emit("uint32_t value;")
+            self.emit("uint32_t flags;")
+            self.emit("")
+            self.emit(f"switch (ctx->record->operands[id]) {{")
+            yield node
+            self.emit("default:")
+            with self:
+                self.emit("return (enum opid_state)((size_t)OPID_ERROR_OPERAND_0 + id);")
+            self.emit("}")
+        self.emit("")
+        with self:
+            self.emit("ctx->operands[id].value = value;")
+            self.emit("ctx->operands[id].flags = flags;")
+            self.emit("")
+            self.emit("return OPID_SUCCESS;")
+        self.emit("}")
+        self.emit("")
+
+        self.emit("static inline enum opid_state")
+        self.emit("opid_disassemble_operands(struct opid_ctx *ctx, uint32_t insn) {")
+        with self:
+            self.emit(f"for (size_t id = 0; ((id != OPID_OPERANDS) && ctx->record->operands[id]); ++id) {{")
+            with self:
+                self.emit("enum opid_state state;")
+                self.emit("")
+                self.emit("state = opid_disassemble_operand(ctx, insn, id);")
+                self.emit("if (state != OPID_SUCCESS)")
+                with self:
+                    self.emit("return state;")
+            self.emit("}")
+            self.emit("")
+            self.emit("return OPID_SUCCESS;")
+        self.emit("}")
+
+    @mdis.dispatcher.Hook(DynamicOperand)
+    @contextlib.contextmanager
+    def dispatch_operand(self, node, *, path, pathcls):
+        def generic_handler(span, flags="UINT32_C(0)"):
+            yield f"value = ("
+            with self:
+                yield from fetch(span)
+            yield f");"
+            yield f"flags = {flags};"
+            self.emit("break;")
+
+        def nonzero_handler(span):
+            yield from generic_handler(span, "OPID_OPERAND_NONZERO")
+
+        def signed_handler(span, flags="OPID_OPERAND_SIGNED"):
+            mask = f"(UINT32_C(1) << (UINT32_C({len(span)}) - 1))"
+            yield "value = ("
+            with self:
+                yield "("
+                with self:
+                    yield "("
+                    with self:
+                        yield from fetch(span)
+                    yield ")"
+                    yield "^"
+                    yield f"{mask}"
+                yield ")"
+                yield "-"
+                yield f"{mask}"
+            yield ");"
+            yield f"flags = {flags};"
+            self.emit("break;")
+
+        def address_handler(span):
+            yield from signed_handler(span, "(OPID_OPERAND_ADDRESS | OPID_OPERAND_SIGNED)")
+
+        def gpr_handler(span, pair=False):
+            if not pair:
+                yield from generic_handler(span, "OPID_OPERAND_GPR")
+            else:
+                yield from generic_handler(span, "(OPID_OPERAND_GPR | OPID_OPERAND_PAIR)")
+
+        def fpr_handler(span, pair=False):
+            if not pair:
+                yield from generic_handler(span, "OPID_OPERAND_FPR")
+            else:
+                yield from generic_handler(span, "(OPID_OPERAND_FPR | OPID_OPERAND_PAIR)")
+
+        def cr3_handler(span):
+            yield from generic_handler(span, "OPID_OPERAND_CR3")
+
+        def cr5_handler(span):
+            yield from generic_handler(span, "OPID_OPERAND_CR5")
+
+        handlers = {
+            insndb.GPRPairOperand: lambda span: gpr_handler(span, True),
+            insndb.FPRPairOperand: lambda span: fpr_handler(span, True),
+            insndb.GPROperand: gpr_handler,
+            insndb.FPROperand: fpr_handler,
+            insndb.CR3Operand: cr3_handler,
+            insndb.CR5Operand: cr5_handler,
+            insndb.TargetAddrOperand: address_handler,
+            insndb.SignedOperand: signed_handler,
+            insndb.NonZeroOperand: nonzero_handler,
+            insndb.DynamicOperand: generic_handler,
+            object: None,
+        }
+        self.emit(f"case 0x{(path + 1):02x}: /* {', '.join(node.names)} */")
+        with self:
+            for (cls, handler) in handlers.items():
+                if issubclass(node.cls, cls):
+                    break
+            if handler is None:
+                raise ValueError("unknown handler")
+            for line in handler(span=node.span):
+                self.emit(line)
+            self.emit("")
+            yield node
+
+    @mdis.dispatcher.Hook(Cache)
+    @contextlib.contextmanager
+    def dispatch_cache(self, node):
+        self.emit("/*")
+        self.emit(" * Autogenerated by libresoc codegen script")
+        self.emit(" * DO NOT EDIT: all changes will be lost")
+        self.emit(" */")
+        self.emit("")
+        self.emit("#include <stdbool.h>")
+        self.emit("#include <stddef.h>")
+        self.emit("#include <stdint.h>")
+        self.emit("")
+        self.emit("#include \"opid.h\"")
+        self.emit("")
+        yield node
+        self.emit("enum opid_state")
+        self.emit("opid_disassemble(struct opid_ctx *ctx, uint32_t insn) {")
+        with self:
+            self.emit("ctx->record = opid_lookup_insn(insn);")
+            self.emit("")
+            self.emit("if (ctx->record == NULL)")
+            with self:
+                self.emit("return OPID_ERROR_LOOKUP;")
+            self.emit("")
+            self.emit("return opid_disassemble_operands(ctx, insn);")
+        self.emit("}")
+
+
+class OpcGenSource(Source):
+    class Walker(Walker):
+        @mdis.dispatcher.Hook(DynamicOperandId, DynamicOperands, insndb.StaticOperand, POTable)
+        def dispatch_ignore(self, node):
+            yield from ()
+
+        @mdis.dispatcher.Hook(Record)
+        def dispatch_record(self, node):
+            keys = {
+                "dynamic_operand_ids": "operands",
+            }
+
+            for field in dataclasses.fields(node):
+                key = field.name
+                value = getattr(node, key)
+                key = keys.get(key, key)
+                yield (value, node, key, mdis.walker.AttributePath)
+
+        @mdis.dispatcher.Hook(Cache)
+        def dispatch_cache(self, node):
+            (_, records, potable) = node
+            yield from self([records, potable])
+
+    @mdis.dispatcher.Hook(DynamicOperandId)
+    @contextlib.contextmanager
+    def dispatch_dynamic_operand_id(self, node, *, path, pathcls):
+        index = f"UINT8_C(0x{node.index:02x})"
+        self.emit(f"{pathcls(path)} = {index}, /* {node.name} */")
+        with self: yield node
+
+    @mdis.dispatcher.Hook(StaticOperands)
+    @contextlib.contextmanager
+    def dispatch_static_operands(self, node):
+        if node:
+            self.emit("/*")
+            yield node
+            self.emit(" */")
+        else:
+            yield node
+
+    @mdis.dispatcher.Hook(insndb.StaticOperand)
+    @contextlib.contextmanager
+    def dispatch_static_operand(self, node):
+        self.emit(f" * {node.name}={node.value} [{', '.join(map(str, node.span))}]")
+        yield node
+
+    @mdis.dispatcher.Hook(insndb.Record.Opcode.Value, insndb.Record.Opcode.Mask)
+    @contextlib.contextmanager
+    def dispatch_opcode_parts(self, node, *, path, pathcls):
+        self.emit(f"{pathcls(path)} = UINT32_C(0x{node:016x}),")
+        with self: yield node
+
+    @mdis.dispatcher.Hook(insndb.Record.Opcode)
+    @contextlib.contextmanager
+    def dispatch_opcode(self, node):
+        self.emit(".opcode = {")
+        with self: yield node
+        self.emit("},")
+
+    @mdis.dispatcher.Hook(POTable)
+    @contextlib.contextmanager
+    def dispatch_potable(self, node):
+        heads = ([0] * (1 << 6))
+        tails = ([0] * (1 << 6))
+        for (index, counter) in enumerate(itertools.accumulate(node)):
+            heads[index] = (counter - node[index])
+            tails[index] = counter
+        heads = [(tail - node[index]) for (index, tail) in enumerate(tails)]
+        self.emit("static uint16_t const opid_opcode_hash[64][2] = {")
+        with self:
+            for index in range(64):
+                head = heads[index]
+                tail = tails[index]
+                self.emit(f"[0x{index:02x}] = {{{head}, {tail}}},")
+        self.emit("};")
+        self.emit("")
+        yield node
+
+    @mdis.dispatcher.Hook(Records)
+    @contextlib.contextmanager
+    def dispatch_records(self, node):
+        self.emit("static struct opid_record const opid_records[] = {")
+        with self: yield node
+        self.emit("};")
+        self.emit("")
+
+    @mdis.dispatcher.Hook(Cache)
+    @contextlib.contextmanager
+    def dispatch_cache(self, node):
+        self.emit("/*")
+        self.emit(" * Autogenerated by libresoc codegen script")
+        self.emit(" * DO NOT EDIT: all changes will be lost")
+        self.emit(" */")
+        self.emit("")
+        self.emit("#include <stddef.h>")
+        self.emit("#include <stdint.h>")
+        self.emit("")
+        self.emit("#include \"opid.h\"")
+        self.emit("")
+        yield node
+        self.emit("struct opid_record const *")
+        self.emit("opid_lookup_insn(uint32_t insn) {")
+        with self:
+            self.emit("uint32_t PO = (")
+            with self:
+                for line in fetch(range(6)):
+                    self.emit(line)
+            self.emit(");")
+            self.emit("struct opid_record const *iter = &opid_records[opid_opcode_hash[PO][0]];")
+            self.emit("struct opid_record const *tail = &opid_records[opid_opcode_hash[PO][1]];")
+            self.emit("")
+            self.emit("for (; iter != tail; ++iter) {")
+            with self:
+                self.emit("struct opid_opcode const *opcode = &iter->opcode;")
+                self.emit("")
+                self.emit("if ((opcode->value & opcode->mask) == (insn & opcode->mask))")
+                with self:
+                    self.emit("return iter;")
+            self.emit("}")
+            self.emit("")
+            self.emit("return NULL;")
+        self.emit("}")
+
+
+def main():
+    table = {mode:{} for mode in Mode}
+    main_parser = argparse.ArgumentParser("codegen",
+        description="C code generator")
+    main_parser.add_argument("-d", "--database",
+        type=pathlib.Path,
+        default=pathlib.Path(find_wiki_dir()))
+    main_subprarsers = main_parser.add_subparsers(dest="mode", required=True)
+    for (mode, _) in table.items():
+        parser = main_subprarsers.add_parser(mode.value)
+
+    arguments = dict(vars(main_parser.parse_args()))
+    mode = Mode(arguments.pop("mode"))
+    db = insndb.Database(root=arguments.pop("database"))
+
+    return mode(db=db, **arguments)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/src/libopid/opid.h b/src/libopid/opid.h
new file mode 100644 (file)
index 0000000..f0d01f8
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+enum opid_state {
+    OPID_SUCCESS,
+    OPID_ERROR_LOOKUP,
+    OPID_ERROR_OPERAND_0,
+    OPID_ERROR_OPERAND_1,
+    OPID_ERROR_OPERAND_2,
+    OPID_ERROR_OPERAND_3,
+    OPID_ERROR_OPERAND_4,
+    OPID_ERROR_OPERAND_5,
+    OPID_ERROR_OPERAND_6,
+    OPID_ERROR_OPERAND_7,
+};
+
+#define OPID_OPERANDS 8
+
+struct opid_opcode {
+    uint32_t value;
+    uint32_t mask;
+};
+
+struct opid_record {
+    struct opid_opcode opcode;
+    uint8_t operands[OPID_OPERANDS];
+    char name[16];
+};
+
+struct opid_operand {
+    uint32_t value;
+    uint32_t flags;
+};
+
+#define OPID_OPERAND_SIGNED    (UINT32_C(1) << UINT32_C(0))
+#define OPID_OPERAND_GPR       (UINT32_C(1) << UINT32_C(1))
+#define OPID_OPERAND_FPR       (UINT32_C(1) << UINT32_C(2))
+#define OPID_OPERAND_PAIR      (UINT32_C(1) << UINT32_C(3))
+#define OPID_OPERAND_CR3       (UINT32_C(1) << UINT32_C(4))
+#define OPID_OPERAND_CR5       (UINT32_C(1) << UINT32_C(5))
+#define OPID_OPERAND_NONZERO   (UINT32_C(1) << UINT32_C(6))
+#define OPID_OPERAND_ADDRESS   (UINT32_C(1) << UINT32_C(7))
+
+struct opid_ctx {
+    struct opid_record const *record;
+    struct opid_operand operands[OPID_OPERANDS];
+};
+
+#define opid_foreach_operand(ctx, operand) \
+    for (size_t id = 0; \
+        (((operand = &(ctx)->operands[id]), 1) && \
+            ((id != OPID_OPERANDS) && (ctx)->record->operands[id])); \
+        operand = &(ctx)->operands[++id])
+
+enum opid_state
+opid_disassemble(struct opid_ctx *ctx, uint32_t insn);
+
+struct opid_record const *
+opid_lookup_insn(uint32_t insn);
diff --git a/src/libsvp64/.gitignore b/src/libsvp64/.gitignore
deleted file mode 100644 (file)
index 4237630..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-svp64-*-gen.*
-*.a
-*.so
diff --git a/src/libsvp64/Makefile b/src/libsvp64/Makefile
deleted file mode 100644 (file)
index 8121b9f..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-CC?=gcc
-AR?=ar
-CFLAGS?=-O3 -Werror -Wall -Wextra
-PYTHON?=python3
-
-
-GENS:=\
-       svp64-dis-gen.c \
-       svp64-opc-gen.c \
-
-SRCS:=$(GENS)
-
-OBJS:=\
-       svp64-dis-gen.o \
-       svp64-opc-gen.o \
-
-
-.SUFFIX: .so .a .o .c
-
-
-.PHONY: all
-all: build
-
-
-.PHONY: build
-build: libsvp64.so
-
-
-.PHONY: clean
-clean:
-       rm -f $(GENS)
-       rm -f $(OBJS)
-       rm -f libsvp64.so
-       rm -f libsvp64.a
-
-
-libsvp64.so: libsvp64.a
-       $(CC) -fPIC -shared -o $@ -L. -Wl,--whole-archive libsvp64.a -Wl,--no-whole-archive
-
-
-libsvp64.a: $(OBJS)
-       $(AR) rcs $@ $^
-
-
- $(GENS): codegen.py
-       SILENCELOG=true $(PYTHON) codegen.py $@ > $@
-
-
-.c.o:
-       $(CC) $(CFLAGS) -fPIC -c $< -o $@
diff --git a/src/libsvp64/codegen.py b/src/libsvp64/codegen.py
deleted file mode 100644 (file)
index 7577d50..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-import argparse
-import collections
-import contextlib
-import dataclasses
-import enum
-import itertools
-import pathlib
-import sys
-
-import mdis.dispatcher
-import mdis.visitor
-import mdis.walker
-
-from openpower.decoder.power_enums import (
-    find_wiki_dir,
-)
-
-import openpower.insndb.core as insndb
-
-
-def traverse(root, visitor, walker, **kwargs):
-    with visitor(root, **kwargs):
-        for (node, *_, path, pathcls) in walker(root):
-            traverse(node, visitor, walker, path=path, pathcls=pathcls)
-
-
-def fetch(span):
-    bits = len(span)
-    one = "UINT32_C(1)"
-    for (dst, origin) in enumerate(span):
-        src = (32 - (origin + 1))
-        dst = (bits - (dst + 1))
-        dst = f"UINT32_C({dst})"
-        src = f"UINT32_C({src})"
-        yield f"/* {origin:<2} */ (((insn >> {src}) & {one}) << {dst}) |"
-    yield f"UINT32_C(0)"
-
-
-class Mode(enum.Enum):
-    PPC_DIS_GEN_C = "svp64-dis-gen.c"
-    PPC_OPC_GEN_C = "svp64-opc-gen.c"
-
-    def __call__(self, db, **arguments):
-        def pairwise(iterable):
-            (a, b) = itertools.tee(iterable)
-            next(b, None)
-            return zip(a, b)
-
-        cache = Cache()
-        codegen = {
-            Mode.PPC_DIS_GEN_C: DisGenSource,
-            Mode.PPC_OPC_GEN_C: OpcGenSource,
-        }[self](cache=cache, **arguments)
-        for (root, visitor) in pairwise((db, cache, codegen),):
-            walker_cls = getattr(visitor, "Walker", Walker)
-            traverse(root=root, visitor=visitor, walker=walker_cls())
-
-
-class StructMeta(type):
-    def __new__(metacls, name, bases, ns):
-        cls = super().__new__(metacls, name, bases, ns)
-        return dataclasses.dataclass(cls, eq=True, frozen=True)
-
-
-class Struct(metaclass=StructMeta):
-    pass
-
-
-class DynamicOperandIds(tuple): pass
-class StaticOperands(tuple): pass
-class DynamicOperands(tuple): pass
-class POTable(tuple): pass
-class Records(tuple): pass
-
-
-class DynamicOperandId(Struct):
-    name: str = "NIL"
-    index: int = 0
-
-
-class DynamicOperand(Struct):
-    cls: type
-    span: tuple
-    names: tuple
-
-
-class Record(Struct):
-    name: str
-    opcode: insndb.Record.Opcode
-    dynamic_operand_ids: DynamicOperandIds
-    static_operands: StaticOperands
-
-
-class Cache(mdis.visitor.ContextVisitor):
-    def __init__(self):
-        self.__PO = ([0] * (1 << 6))
-        self.__records = collections.defaultdict(list)
-        self.__static_operand = collections.defaultdict(list)
-        self.__dynamic_operand = collections.defaultdict(set)
-        self.__dynamic_operand_id = collections.defaultdict(list)
-
-        return super().__init__()
-
-    def __iter__(self):
-        table = tuple(self.__dynamic_operand.keys())
-        nil = DynamicOperandId()
-
-        def dynamic_operand_id(item):
-            (name, cls, span) = item
-            index = (table.index((cls, span),) + 1)
-            return DynamicOperandId(name=name, index=index)
-
-        def dynamic_operand(item):
-            ((cls, span), names) = item
-            return DynamicOperand(cls=cls, span=span, names=tuple(sorted(names)))
-
-        def record(item):
-            (opcode, name) = item
-            dynamic_operand_ids = map(dynamic_operand_id, self.__dynamic_operand_id[name])
-            dynamic_operand_ids = DynamicOperandIds(tuple(dynamic_operand_ids) + (nil,))
-            static_operands = StaticOperands(self.__static_operand[name])
-
-            return Record(opcode=opcode, name=name,
-                dynamic_operand_ids=dynamic_operand_ids,
-                static_operands=static_operands)
-
-        yield DynamicOperands(map(dynamic_operand, self.__dynamic_operand.items()))
-        yield Records(map(record, sorted(self.__records.items())))
-        yield POTable(self.__PO)
-
-    @mdis.dispatcher.Hook(insndb.Record)
-    @contextlib.contextmanager
-    def dispatch_record(self, node):
-        self.__record = node
-        yield node
-
-    @mdis.dispatcher.Hook(insndb.Record.Opcode)
-    @contextlib.contextmanager
-    def dispatch_record_opcode(self, node):
-        self.__records[node] = self.__record.name
-        self.__PO[self.__record.PO] += 1
-        yield node
-
-    @mdis.dispatcher.Hook(insndb.StaticOperand)
-    @contextlib.contextmanager
-    def dispatch_static_operand(self, node):
-        self.__static_operand[self.__record.name].append(node)
-        yield node
-
-    @mdis.dispatcher.Hook(insndb.DynamicOperand)
-    @contextlib.contextmanager
-    def dispatch_dynamic_operand(self, node):
-        (cls, span) = (node.__class__, node.span)
-        self.__dynamic_operand[cls, span].add(node.name)
-        self.__dynamic_operand_id[self.__record.name].append((node.name, cls, span),)
-        yield node
-
-
-class Walker(insndb.Walker):
-    @mdis.dispatcher.Hook(Cache)
-    def dispatch_cache(self, node):
-        yield from ()
-
-
-class Codegen(mdis.visitor.ContextVisitor):
-    def __init__(self, cache, **arguments):
-        self.__level = 0
-
-        return super().__init__()
-
-    def __enter__(self):
-        self.__level += 1
-        return self
-
-    def __exit__(self, exc_type, exc_value, exc_traceback):
-        self.__level -= 1
-
-    def emit(self, message=""):
-        indent = ((" " * 4 * self.__level) if message else "")
-        print(f"{indent}{message}")
-
-    @mdis.dispatcher.Hook(Cache)
-    @contextlib.contextmanager
-    def dispatch_cache(self, node):
-        self.emit("/*")
-        self.emit(" * Autogenerated by libresoc codegen script")
-        self.emit(" * DO NOT EDIT: all changes will be lost")
-        self.emit(" */")
-        self.emit("")
-        yield node
-
-
-class Header(Codegen):
-    pass
-
-
-class Source(Codegen):
-    @mdis.dispatcher.Hook(str)
-    @contextlib.contextmanager
-    def dispatch_str(self, node, *, path, pathcls):
-        self.emit(f"{pathcls(path)} = \"{node}\",")
-        with self: yield node
-
-    @mdis.dispatcher.Hook(object)
-    @contextlib.contextmanager
-    def dispatch_object(self, node, *, path, pathcls):
-        self.emit(f"{pathcls(path)} = {{")
-        with self: yield node
-        self.emit("},")
-
-
-class Record(Struct):
-    static_operands: StaticOperands
-    name: str
-    opcode: insndb.Record.Opcode
-    dynamic_operand_ids: DynamicOperandIds
-
-
-class DisGenSource(Source):
-    class Walker(Walker):
-        @mdis.dispatcher.Hook(DynamicOperand, Records)
-        def dispatch_ignore(self, node):
-            yield from ()
-
-        @mdis.dispatcher.Hook(Cache)
-        def dispatch_cache(self, node):
-            (operands, _, _) = node
-            yield from self([operands])
-
-    @mdis.dispatcher.Hook(DynamicOperands)
-    @contextlib.contextmanager
-    def dispatch_operands(self, node):
-        self.emit("static inline enum svp64_state")
-        self.emit("svp64_disassemble_operand(struct svp64_ctx *ctx, uint32_t insn, size_t id) {")
-        with self:
-            self.emit("uint32_t value;")
-            self.emit("uint32_t flags;")
-            self.emit("")
-            self.emit(f"switch (ctx->record->operands[id]) {{")
-            yield node
-            self.emit("default:")
-            with self:
-                self.emit("return (enum svp64_state)((size_t)SVP64_ERROR_OPERAND_0 + id);")
-            self.emit("}")
-        self.emit("")
-        with self:
-            self.emit("ctx->operands[id].value = value;")
-            self.emit("ctx->operands[id].flags = flags;")
-            self.emit("")
-            self.emit("return SVP64_SUCCESS;")
-        self.emit("}")
-        self.emit("")
-
-        self.emit("static inline enum svp64_state")
-        self.emit("svp64_disassemble_operands(struct svp64_ctx *ctx, uint32_t insn) {")
-        with self:
-            self.emit(f"for (size_t id = 0; ((id != SVP64_OPERANDS) && ctx->record->operands[id]); ++id) {{")
-            with self:
-                self.emit("enum svp64_state state;")
-                self.emit("")
-                self.emit("state = svp64_disassemble_operand(ctx, insn, id);")
-                self.emit("if (state != SVP64_SUCCESS)")
-                with self:
-                    self.emit("return state;")
-            self.emit("}")
-            self.emit("")
-            self.emit("return SVP64_SUCCESS;")
-        self.emit("}")
-
-    @mdis.dispatcher.Hook(DynamicOperand)
-    @contextlib.contextmanager
-    def dispatch_operand(self, node, *, path, pathcls):
-        def generic_handler(span, flags="UINT32_C(0)"):
-            yield f"value = ("
-            with self:
-                yield from fetch(span)
-            yield f");"
-            yield f"flags = {flags};"
-            self.emit("break;")
-
-        def nonzero_handler(span):
-            yield from generic_handler(span, "SVP64_OPERAND_NONZERO")
-
-        def signed_handler(span, flags="SVP64_OPERAND_SIGNED"):
-            mask = f"(UINT32_C(1) << (UINT32_C({len(span)}) - 1))"
-            yield "value = ("
-            with self:
-                yield "("
-                with self:
-                    yield "("
-                    with self:
-                        yield from fetch(span)
-                    yield ")"
-                    yield "^"
-                    yield f"{mask}"
-                yield ")"
-                yield "-"
-                yield f"{mask}"
-            yield ");"
-            yield f"flags = {flags};"
-            self.emit("break;")
-
-        def address_handler(span):
-            yield from signed_handler(span, "(SVP64_OPERAND_ADDRESS | SVP64_OPERAND_SIGNED)")
-
-        def gpr_handler(span, pair=False):
-            if not pair:
-                yield from generic_handler(span, "SVP64_OPERAND_GPR")
-            else:
-                yield from generic_handler(span, "(SVP64_OPERAND_GPR | SVP64_OPERAND_PAIR)")
-
-        def fpr_handler(span, pair=False):
-            if not pair:
-                yield from generic_handler(span, "SVP64_OPERAND_FPR")
-            else:
-                yield from generic_handler(span, "(SVP64_OPERAND_FPR | SVP64_OPERAND_PAIR)")
-
-        def cr3_handler(span):
-            yield from generic_handler(span, "SVP64_OPERAND_CR3")
-
-        def cr5_handler(span):
-            yield from generic_handler(span, "SVP64_OPERAND_CR5")
-
-        handlers = {
-            insndb.GPRPairOperand: lambda span: gpr_handler(span, True),
-            insndb.FPRPairOperand: lambda span: fpr_handler(span, True),
-            insndb.GPROperand: gpr_handler,
-            insndb.FPROperand: fpr_handler,
-            insndb.CR3Operand: cr3_handler,
-            insndb.CR5Operand: cr5_handler,
-            insndb.TargetAddrOperand: address_handler,
-            insndb.SignedOperand: signed_handler,
-            insndb.NonZeroOperand: nonzero_handler,
-            insndb.DynamicOperand: generic_handler,
-            object: None,
-        }
-        self.emit(f"case 0x{(path + 1):02x}: /* {', '.join(node.names)} */")
-        with self:
-            for (cls, handler) in handlers.items():
-                if issubclass(node.cls, cls):
-                    break
-            if handler is None:
-                raise ValueError("unknown handler")
-            for line in handler(span=node.span):
-                self.emit(line)
-            self.emit("")
-            yield node
-
-    @mdis.dispatcher.Hook(Cache)
-    @contextlib.contextmanager
-    def dispatch_cache(self, node):
-        self.emit("/*")
-        self.emit(" * Autogenerated by libresoc codegen script")
-        self.emit(" * DO NOT EDIT: all changes will be lost")
-        self.emit(" */")
-        self.emit("")
-        self.emit("#include <stdbool.h>")
-        self.emit("#include <stddef.h>")
-        self.emit("#include <stdint.h>")
-        self.emit("")
-        self.emit("#include \"svp64.h\"")
-        self.emit("")
-        yield node
-        self.emit("enum svp64_state")
-        self.emit("svp64_disassemble(struct svp64_ctx *ctx, uint32_t insn) {")
-        with self:
-            self.emit("ctx->record = svp64_lookup_insn(insn);")
-            self.emit("")
-            self.emit("if (ctx->record == NULL)")
-            with self:
-                self.emit("return SVP64_ERROR_LOOKUP;")
-            self.emit("")
-            self.emit("return svp64_disassemble_operands(ctx, insn);")
-        self.emit("}")
-
-
-class OpcGenSource(Source):
-    class Walker(Walker):
-        @mdis.dispatcher.Hook(DynamicOperandId, DynamicOperands, insndb.StaticOperand, POTable)
-        def dispatch_ignore(self, node):
-            yield from ()
-
-        @mdis.dispatcher.Hook(Record)
-        def dispatch_record(self, node):
-            keys = {
-                "dynamic_operand_ids": "operands",
-            }
-
-            for field in dataclasses.fields(node):
-                key = field.name
-                value = getattr(node, key)
-                key = keys.get(key, key)
-                yield (value, node, key, mdis.walker.AttributePath)
-
-        @mdis.dispatcher.Hook(Cache)
-        def dispatch_cache(self, node):
-            (_, records, potable) = node
-            yield from self([records, potable])
-
-    @mdis.dispatcher.Hook(DynamicOperandId)
-    @contextlib.contextmanager
-    def dispatch_dynamic_operand_id(self, node, *, path, pathcls):
-        index = f"UINT8_C(0x{node.index:02x})"
-        self.emit(f"{pathcls(path)} = {index}, /* {node.name} */")
-        with self: yield node
-
-    @mdis.dispatcher.Hook(StaticOperands)
-    @contextlib.contextmanager
-    def dispatch_static_operands(self, node):
-        if node:
-            self.emit("/*")
-            yield node
-            self.emit(" */")
-        else:
-            yield node
-
-    @mdis.dispatcher.Hook(insndb.StaticOperand)
-    @contextlib.contextmanager
-    def dispatch_static_operand(self, node):
-        self.emit(f" * {node.name}={node.value} [{', '.join(map(str, node.span))}]")
-        yield node
-
-    @mdis.dispatcher.Hook(insndb.Record.Opcode.Value, insndb.Record.Opcode.Mask)
-    @contextlib.contextmanager
-    def dispatch_opcode_parts(self, node, *, path, pathcls):
-        self.emit(f"{pathcls(path)} = UINT32_C(0x{node:016x}),")
-        with self: yield node
-
-    @mdis.dispatcher.Hook(insndb.Record.Opcode)
-    @contextlib.contextmanager
-    def dispatch_opcode(self, node):
-        self.emit(".opcode = {")
-        with self: yield node
-        self.emit("},")
-
-    @mdis.dispatcher.Hook(POTable)
-    @contextlib.contextmanager
-    def dispatch_potable(self, node):
-        heads = ([0] * (1 << 6))
-        tails = ([0] * (1 << 6))
-        for (index, counter) in enumerate(itertools.accumulate(node)):
-            heads[index] = (counter - node[index])
-            tails[index] = counter
-        heads = [(tail - node[index]) for (index, tail) in enumerate(tails)]
-        self.emit("static uint16_t const svp64_opcode_hash[64][2] = {")
-        with self:
-            for index in range(64):
-                head = heads[index]
-                tail = tails[index]
-                self.emit(f"[0x{index:02x}] = {{{head}, {tail}}},")
-        self.emit("};")
-        self.emit("")
-        yield node
-
-    @mdis.dispatcher.Hook(Records)
-    @contextlib.contextmanager
-    def dispatch_records(self, node):
-        self.emit("static struct svp64_record const svp64_records[] = {")
-        with self: yield node
-        self.emit("};")
-        self.emit("")
-
-    @mdis.dispatcher.Hook(Cache)
-    @contextlib.contextmanager
-    def dispatch_cache(self, node):
-        self.emit("/*")
-        self.emit(" * Autogenerated by libresoc codegen script")
-        self.emit(" * DO NOT EDIT: all changes will be lost")
-        self.emit(" */")
-        self.emit("")
-        self.emit("#include <stddef.h>")
-        self.emit("#include <stdint.h>")
-        self.emit("")
-        self.emit("#include \"svp64.h\"")
-        self.emit("")
-        yield node
-        self.emit("struct svp64_record const *")
-        self.emit("svp64_lookup_insn(uint32_t insn) {")
-        with self:
-            self.emit("uint32_t PO = (")
-            with self:
-                for line in fetch(range(6)):
-                    self.emit(line)
-            self.emit(");")
-            self.emit("struct svp64_record const *iter = &svp64_records[svp64_opcode_hash[PO][0]];")
-            self.emit("struct svp64_record const *tail = &svp64_records[svp64_opcode_hash[PO][1]];")
-            self.emit("")
-            self.emit("for (; iter != tail; ++iter) {")
-            with self:
-                self.emit("struct svp64_opcode const *opcode = &iter->opcode;")
-                self.emit("")
-                self.emit("if ((opcode->value & opcode->mask) == (insn & opcode->mask))")
-                with self:
-                    self.emit("return iter;")
-            self.emit("}")
-            self.emit("")
-            self.emit("return NULL;")
-        self.emit("}")
-
-
-def main():
-    table = {mode:{} for mode in Mode}
-    main_parser = argparse.ArgumentParser("codegen",
-        description="C code generator")
-    main_parser.add_argument("-d", "--database",
-        type=pathlib.Path,
-        default=pathlib.Path(find_wiki_dir()))
-    main_subprarsers = main_parser.add_subparsers(dest="mode", required=True)
-    for (mode, _) in table.items():
-        parser = main_subprarsers.add_parser(mode.value)
-
-    arguments = dict(vars(main_parser.parse_args()))
-    mode = Mode(arguments.pop("mode"))
-    db = insndb.Database(root=arguments.pop("database"))
-
-    return mode(db=db, **arguments)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/libsvp64/svp64.h b/src/libsvp64/svp64.h
deleted file mode 100644 (file)
index 43e9717..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-#include <stddef.h>
-#include <stdint.h>
-
-enum svp64_state {
-    SVP64_SUCCESS,
-    SVP64_ERROR_LOOKUP,
-    SVP64_ERROR_OPERAND_0,
-    SVP64_ERROR_OPERAND_1,
-    SVP64_ERROR_OPERAND_2,
-    SVP64_ERROR_OPERAND_3,
-    SVP64_ERROR_OPERAND_4,
-    SVP64_ERROR_OPERAND_5,
-    SVP64_ERROR_OPERAND_6,
-    SVP64_ERROR_OPERAND_7,
-};
-
-#define SVP64_OPERANDS 8
-
-struct svp64_opcode {
-    uint32_t value;
-    uint32_t mask;
-};
-
-struct svp64_record {
-    struct svp64_opcode opcode;
-    uint8_t operands[SVP64_OPERANDS];
-    char name[16];
-};
-
-struct svp64_operand {
-    uint32_t value;
-    uint32_t flags;
-};
-
-#define SVP64_OPERAND_SIGNED    (UINT32_C(1) << UINT32_C(0))
-#define SVP64_OPERAND_GPR       (UINT32_C(1) << UINT32_C(1))
-#define SVP64_OPERAND_FPR       (UINT32_C(1) << UINT32_C(2))
-#define SVP64_OPERAND_PAIR      (UINT32_C(1) << UINT32_C(3))
-#define SVP64_OPERAND_CR3       (UINT32_C(1) << UINT32_C(4))
-#define SVP64_OPERAND_CR5       (UINT32_C(1) << UINT32_C(5))
-#define SVP64_OPERAND_NONZERO   (UINT32_C(1) << UINT32_C(6))
-#define SVP64_OPERAND_ADDRESS   (UINT32_C(1) << UINT32_C(7))
-
-struct svp64_ctx {
-    struct svp64_record const *record;
-    struct svp64_operand operands[SVP64_OPERANDS];
-};
-
-#define svp64_foreach_operand(ctx, operand) \
-    for (size_t id = 0; \
-        (((operand = &(ctx)->operands[id]), 1) && \
-            ((id != SVP64_OPERANDS) && (ctx)->record->operands[id])); \
-        operand = &(ctx)->operands[++id])
-
-enum svp64_state
-svp64_disassemble(struct svp64_ctx *ctx, uint32_t insn);
-
-struct svp64_record const *
-svp64_lookup_insn(uint32_t insn);