--- /dev/null
+*-gen.*
+*.a
+*.so
--- /dev/null
+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 $@
--- /dev/null
+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.GPROperand: 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()
--- /dev/null
+#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);
+++ /dev/null
-svp64-*-gen.*
-*.a
-*.so
+++ /dev/null
-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 $@
+++ /dev/null
-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.GPROperand: 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()
+++ /dev/null
-#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);