10 import mdis
.dispatcher
14 from openpower
.decoder
.power_enums
import (
18 import openpower
.insndb
.core
as insndb
21 def traverse(root
, visitor
, walker
, **kwargs
):
22 with
visitor(root
, **kwargs
):
23 for (node
, *_
, path
, pathcls
) in walker(root
):
24 traverse(node
, visitor
, walker
, path
=path
, pathcls
=pathcls
)
30 for (dst
, origin
) in enumerate(span
):
31 src
= (32 - (origin
+ 1))
32 dst
= (bits
- (dst
+ 1))
33 dst
= f
"UINT32_C({dst})"
34 src
= f
"UINT32_C({src})"
35 yield f
"/* {origin:<2} */ (((insn >> {src}) & {one}) << {dst}) |"
39 class Mode(enum
.Enum
):
40 PPC_DIS_GEN_C
= "opid-dis-gen.c"
41 PPC_OPC_GEN_C
= "opid-opc-gen.c"
43 def __call__(self
, db
, **arguments
):
44 def pairwise(iterable
):
45 (a
, b
) = itertools
.tee(iterable
)
51 Mode
.PPC_DIS_GEN_C
: DisGenSource
,
52 Mode
.PPC_OPC_GEN_C
: OpcGenSource
,
53 }[self
](cache
=cache
, **arguments
)
54 for (root
, visitor
) in pairwise((db
, cache
, codegen
),):
55 walker_cls
= getattr(visitor
, "Walker", Walker
)
56 traverse(root
=root
, visitor
=visitor
, walker
=walker_cls())
59 class StructMeta(type):
60 def __new__(metacls
, name
, bases
, ns
):
61 cls
= super().__new
__(metacls
, name
, bases
, ns
)
62 return dataclasses
.dataclass(cls
, eq
=True, frozen
=True)
65 class Struct(metaclass
=StructMeta
):
69 class DynamicOperandIds(tuple): pass
70 class StaticOperands(tuple): pass
71 class DynamicOperands(tuple): pass
72 class POTable(tuple): pass
73 class RecordTable(tuple): pass
76 class DynamicOperandId(Struct
):
81 class DynamicOperand(Struct
):
89 opcode
: insndb
.Record
.Opcode
90 dynamic_operand_ids
: DynamicOperandIds
91 static_operands
: StaticOperands
94 class Cache(mdis
.visitor
.ContextVisitor
):
96 self
.__PO
= ([0] * (1 << 6))
97 self
.__records
= collections
.defaultdict(list)
98 self
.__static
_operand
= collections
.defaultdict(list)
99 self
.__dynamic
_operand
= collections
.defaultdict(set)
100 self
.__dynamic
_operand
_id
= collections
.defaultdict(list)
102 return super().__init
__()
105 table
= tuple(self
.__dynamic
_operand
.keys())
106 nil
= DynamicOperandId()
108 def dynamic_operand_id(item
):
109 (name
, cls
, span
) = item
110 index
= (table
.index((cls
, span
),) + 1)
111 return DynamicOperandId(name
=name
, index
=index
)
113 def dynamic_operand(item
):
114 ((cls
, span
), names
) = item
115 return DynamicOperand(cls
=cls
, span
=span
, names
=tuple(sorted(names
)))
118 (opcode
, name
) = item
119 dynamic_operand_ids
= map(dynamic_operand_id
, self
.__dynamic
_operand
_id
[name
])
120 dynamic_operand_ids
= DynamicOperandIds(tuple(dynamic_operand_ids
) + (nil
,))
121 static_operands
= StaticOperands(self
.__static
_operand
[name
])
123 return Record(opcode
=opcode
, name
=name
,
124 dynamic_operand_ids
=dynamic_operand_ids
,
125 static_operands
=static_operands
)
127 yield DynamicOperands(map(dynamic_operand
, self
.__dynamic
_operand
.items()))
128 yield RecordTable(map(record
, sorted(self
.__records
.items())))
129 yield POTable(self
.__PO
)
131 @mdis.dispatcher
.Hook(insndb
.Record
)
132 @contextlib.contextmanager
133 def dispatch_record(self
, node
):
137 @mdis.dispatcher
.Hook(insndb
.Record
.Opcode
)
138 @contextlib.contextmanager
139 def dispatch_record_opcode(self
, node
):
140 self
.__records
[node
] = self
.__record
.name
141 self
.__PO
[self
.__record
.PO
] += 1
144 @mdis.dispatcher
.Hook(insndb
.StaticOperand
)
145 @contextlib.contextmanager
146 def dispatch_static_operand(self
, node
):
147 self
.__static
_operand
[self
.__record
.name
].append(node
)
150 @mdis.dispatcher
.Hook(insndb
.DynamicOperand
)
151 @contextlib.contextmanager
152 def dispatch_dynamic_operand(self
, node
):
153 (cls
, span
) = (node
.__class
__, node
.span
)
154 self
.__dynamic
_operand
[cls
, span
].add(node
.name
)
155 self
.__dynamic
_operand
_id
[self
.__record
.name
].append((node
.name
, cls
, span
),)
159 class Walker(insndb
.Walker
):
160 @mdis.dispatcher
.Hook(Cache
)
161 def dispatch_cache(self
, node
):
165 class Codegen(mdis
.visitor
.ContextVisitor
):
166 def __init__(self
, cache
, **arguments
):
169 return super().__init
__()
175 def __exit__(self
, exc_type
, exc_value
, exc_traceback
):
178 def emit(self
, message
=""):
179 indent
= ((" " * 4 * self
.__level
) if message
else "")
180 print(f
"{indent}{message}")
182 @mdis.dispatcher
.Hook(Cache
)
183 @contextlib.contextmanager
184 def dispatch_cache(self
, node
):
186 self
.emit(" * Autogenerated by libresoc codegen script")
187 self
.emit(" * DO NOT EDIT: all changes will be lost")
193 class Header(Codegen
):
197 class Source(Codegen
):
198 @mdis.dispatcher
.Hook(str)
199 @contextlib.contextmanager
200 def dispatch_str(self
, node
, *, path
, pathcls
):
201 self
.emit(f
"{pathcls(path)} = \"{node}\",")
202 with self
: yield node
204 @mdis.dispatcher
.Hook(object)
205 @contextlib.contextmanager
206 def dispatch_object(self
, node
, *, path
, pathcls
):
207 self
.emit(f
"{pathcls(path)} = {{")
208 with self
: yield node
211 @mdis.dispatcher
.Hook(Cache
)
212 @contextlib.contextmanager
213 def dispatch_cache(self
, node
):
215 self
.emit(" * Autogenerated by libresoc codegen script")
216 self
.emit(" * DO NOT EDIT: all changes will be lost")
219 self
.emit("#include <stddef.h>")
220 self
.emit("#include <stdint.h>")
222 self
.emit("#include \"opid.h\"")
227 class Record(Struct
):
228 static_operands
: StaticOperands
230 opcode
: insndb
.Record
.Opcode
231 dynamic_operand_ids
: DynamicOperandIds
234 class DisGenSource(Source
):
235 class Walker(Walker
):
236 @mdis.dispatcher
.Hook(DynamicOperand
, RecordTable
)
237 def dispatch_ignore(self
, node
):
240 @mdis.dispatcher
.Hook(Cache
)
241 def dispatch_cache(self
, node
):
242 (operands
, _
, _
) = node
243 yield from self([operands
])
245 @mdis.dispatcher
.Hook(DynamicOperands
)
246 @contextlib.contextmanager
247 def dispatch_operands(self
, node
):
248 self
.emit("static inline enum opid_state")
249 self
.emit("opid_disassemble_operand(uint32_t insn,")
252 self
.emit("size_t category,")
253 self
.emit("struct opid_operand *operand) {")
255 self
.emit(f
"switch (category) {{")
257 self
.emit("default:")
259 self
.emit("return OPID_ERROR_OPERAND_0;")
263 self
.emit("return OPID_SUCCESS;")
266 @mdis.dispatcher
.Hook(DynamicOperand
)
267 @contextlib.contextmanager
268 def dispatch_operand(self
, node
, *, path
, pathcls
):
269 def generic_handler(span
, flags
="UINT32_C(0)"):
270 yield f
"operand->value = ("
272 yield from fetch(span
)
274 yield f
"operand->flags = {flags};"
277 def nonzero_handler(span
):
278 yield f
"operand->value = (UINT32_C(1) + ("
280 yield from fetch(span
)
282 yield f
"operand->flags = OPID_OPERAND_NONZERO;"
285 def signed_handler(span
, flags
="OPID_OPERAND_SIGNED"):
286 mask
= f
"(UINT32_C(1) << (UINT32_C({len(span)}) - 1))"
287 yield "operand->value = ("
293 yield from fetch(span
)
301 yield f
"operand->flags = {flags};"
304 def address_handler(span
):
305 yield from signed_handler(span
, "(OPID_OPERAND_ADDRESS | OPID_OPERAND_SIGNED)")
307 def gpr_handler(span
, pair
=False):
309 yield from generic_handler(span
, "OPID_OPERAND_GPR")
311 yield from generic_handler(span
, "(OPID_OPERAND_GPR | OPID_OPERAND_PAIR)")
313 def fpr_handler(span
, pair
=False):
315 yield from generic_handler(span
, "OPID_OPERAND_FPR")
317 yield from generic_handler(span
, "(OPID_OPERAND_FPR | OPID_OPERAND_PAIR)")
319 def cr3_handler(span
):
320 yield from generic_handler(span
, "OPID_OPERAND_CR3")
322 def cr5_handler(span
):
323 yield from generic_handler(span
, "OPID_OPERAND_CR5")
326 insndb
.GPRPairOperand
: lambda span
: gpr_handler(span
, True),
327 insndb
.FPRPairOperand
: lambda span
: fpr_handler(span
, True),
328 insndb
.GPROperand
: gpr_handler
,
329 insndb
.FPROperand
: fpr_handler
,
330 insndb
.CR3Operand
: cr3_handler
,
331 insndb
.CR5Operand
: cr5_handler
,
332 insndb
.TargetAddrOperand
: address_handler
,
333 insndb
.SignedOperand
: signed_handler
,
334 insndb
.NonZeroOperand
: nonzero_handler
,
335 insndb
.DynamicOperand
: generic_handler
,
338 self
.emit(f
"case 0x{(path + 1):02x}: /* {', '.join(node.names)} */")
340 for (cls
, handler
) in handlers
.items():
341 if issubclass(node
.cls
, cls
):
344 raise ValueError("unknown handler")
345 for line
in handler(span
=node
.span
):
351 class OpcGenSource(Source
):
352 class Walker(Walker
):
353 @mdis.dispatcher
.Hook(DynamicOperandId
, DynamicOperands
, insndb
.StaticOperand
, POTable
)
354 def dispatch_ignore(self
, node
):
357 @mdis.dispatcher
.Hook(Record
)
358 def dispatch_record(self
, node
):
360 "dynamic_operand_ids": "operands",
363 for field
in dataclasses
.fields(node
):
365 value
= getattr(node
, key
)
366 key
= keys
.get(key
, key
)
367 yield (value
, node
, key
, mdis
.walker
.AttributePath
)
369 @mdis.dispatcher
.Hook(Cache
)
370 def dispatch_cache(self
, node
):
371 (_
, records
, potable
) = node
372 yield from self([records
, potable
])
374 @mdis.dispatcher
.Hook(DynamicOperandId
)
375 @contextlib.contextmanager
376 def dispatch_dynamic_operand_id(self
, node
, *, path
, pathcls
):
377 index
= f
"UINT8_C(0x{node.index:02x})"
378 self
.emit(f
"{pathcls(path)} = {index}, /* {node.name} */")
379 with self
: yield node
381 @mdis.dispatcher
.Hook(StaticOperands
)
382 @contextlib.contextmanager
383 def dispatch_static_operands(self
, node
):
391 @mdis.dispatcher
.Hook(insndb
.StaticOperand
)
392 @contextlib.contextmanager
393 def dispatch_static_operand(self
, node
):
394 self
.emit(f
" * {node.name}={node.value} [{', '.join(map(str, node.span))}]")
397 @mdis.dispatcher
.Hook(insndb
.Record
.Opcode
.Value
, insndb
.Record
.Opcode
.Mask
)
398 @contextlib.contextmanager
399 def dispatch_opcode_parts(self
, node
, *, path
, pathcls
):
400 self
.emit(f
"{pathcls(path)} = UINT32_C(0x{node:016x}),")
401 with self
: yield node
403 @mdis.dispatcher
.Hook(insndb
.Record
.Opcode
)
404 @contextlib.contextmanager
405 def dispatch_opcode(self
, node
):
406 self
.emit(".opcode = {")
407 with self
: yield node
410 @mdis.dispatcher
.Hook(POTable
)
411 @contextlib.contextmanager
412 def dispatch_potable(self
, node
):
413 heads
= ([0] * (1 << 6))
414 tails
= ([0] * (1 << 6))
415 for (index
, counter
) in enumerate(itertools
.accumulate(node
)):
416 heads
[index
] = (counter
- node
[index
])
417 tails
[index
] = counter
418 heads
= [(tail
- node
[index
]) for (index
, tail
) in enumerate(tails
)]
419 self
.emit("static uint16_t const opid_opcode_table[64][2] = {")
421 for index
in range(64):
424 self
.emit(f
"[0x{index:02x}] = {{{head}, {tail}}},")
428 @mdis.dispatcher
.Hook(RecordTable
)
429 @contextlib.contextmanager
430 def dispatch_records(self
, node
):
431 self
.emit("static struct opid_record const opid_record_table[] = {")
432 with self
: yield node
438 table
= {mode
:{} for mode
in Mode
}
439 main_parser
= argparse
.ArgumentParser("codegen",
440 description
="C code generator")
441 main_parser
.add_argument("-d", "--database",
443 default
=pathlib
.Path(find_wiki_dir()))
444 main_subprarsers
= main_parser
.add_subparsers(dest
="mode", required
=True)
445 for (mode
, _
) in table
.items():
446 parser
= main_subprarsers
.add_parser(mode
.value
)
448 arguments
= dict(vars(main_parser
.parse_args()))
449 mode
= Mode(arguments
.pop("mode"))
450 db
= insndb
.Database(root
=arguments
.pop("database"))
452 return mode(db
=db
, **arguments
)
455 if __name__
== "__main__":