power_insn: refactor opcode matching
[openpower-isa.git] / src / openpower / decoder / power_insn.py
1 import collections as _collections
2 import csv as _csv
3 import dataclasses as _dataclasses
4 import enum as _enum
5 import functools as _functools
6 import itertools as _itertools
7 import os as _os
8 import operator as _operator
9 import pathlib as _pathlib
10 import re as _re
11
12 try:
13 from functools import cached_property
14 except ImportError:
15 from cached_property import cached_property
16
17 from openpower.decoder.power_enums import (
18 Function as _Function,
19 MicrOp as _MicrOp,
20 In1Sel as _In1Sel,
21 In2Sel as _In2Sel,
22 In3Sel as _In3Sel,
23 OutSel as _OutSel,
24 CRInSel as _CRInSel,
25 CROutSel as _CROutSel,
26 LDSTLen as _LDSTLen,
27 LDSTMode as _LDSTMode,
28 RCOE as _RCOE,
29 CryIn as _CryIn,
30 Form as _Form,
31 SVEtype as _SVEtype,
32 SVMode as _SVMode,
33 SVPtype as _SVPtype,
34 SVExtra as _SVExtra,
35 RegType as _RegType,
36 SVExtraRegType as _SVExtraRegType,
37 SVExtraReg as _SVExtraReg,
38 )
39 from openpower.decoder.selectable_int import (
40 SelectableInt as _SelectableInt,
41 selectconcat as _selectconcat,
42 )
43 from openpower.decoder.power_fields import (
44 Field as _Field,
45 Mapping as _Mapping,
46 DecodeFields as _DecodeFields,
47 )
48 from openpower.decoder.pseudo.pagereader import ISA as _ISA
49
50
51 @_functools.total_ordering
52 class Verbosity(_enum.Enum):
53 SHORT = _enum.auto()
54 NORMAL = _enum.auto()
55 VERBOSE = _enum.auto()
56
57 def __lt__(self, other):
58 if not isinstance(other, self.__class__):
59 return NotImplemented
60 return (self.value < other.value)
61
62
63 def dataclass(cls, record, keymap=None, typemap=None):
64 if keymap is None:
65 keymap = {}
66 if typemap is None:
67 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
68
69 def transform(key_value):
70 (key, value) = key_value
71 key = keymap.get(key, key)
72 hook = typemap.get(key, lambda value: value)
73 if hook is bool and value in ("", "0"):
74 value = False
75 else:
76 value = hook(value)
77 return (key, value)
78
79 record = dict(map(transform, record.items()))
80 for key in frozenset(record.keys()):
81 if record[key] == "":
82 record.pop(key)
83
84 return cls(**record)
85
86
87 @_functools.total_ordering
88 @_dataclasses.dataclass(eq=True, frozen=True)
89 class Opcode:
90 class Value(int):
91 def __repr__(self):
92 if self.bit_length() <= 32:
93 return f"0x{self:08x}"
94 else:
95 return f"0x{self:016x}"
96
97 class Mask(int):
98 def __repr__(self):
99 if self.bit_length() <= 32:
100 return f"0x{self:08x}"
101 else:
102 return f"0x{self:016x}"
103
104 value: Value
105 mask: Mask = None
106
107 def __lt__(self, other):
108 if not isinstance(other, Opcode):
109 return NotImplemented
110 return ((self.value, self.mask) < (other.value, other.mask))
111
112 def __post_init__(self):
113 (value, mask) = (self.value, self.mask)
114
115 if isinstance(value, Opcode):
116 if mask is not None:
117 raise ValueError(mask)
118 (value, mask) = (value.value, value.mask)
119 elif isinstance(value, str):
120 if mask is not None:
121 raise ValueError(mask)
122 value = int(value, 0)
123
124 if not isinstance(value, int):
125 raise ValueError(value)
126 if mask is None:
127 mask = value
128 if not isinstance(mask, int):
129 raise ValueError(mask)
130
131 object.__setattr__(self, "value", self.__class__.Value(value))
132 object.__setattr__(self, "mask", self.__class__.Mask(mask))
133
134
135 class IntegerOpcode(Opcode):
136 def __init__(self, value):
137 if isinstance(value, str):
138 value = int(value, 0)
139 return super().__init__(value=value, mask=None)
140
141
142 class PatternOpcode(Opcode):
143 def __init__(self, value):
144 (pattern, value, mask) = (value, 0, 0)
145
146 for symbol in pattern:
147 if symbol not in {"0", "1", "-"}:
148 raise ValueError(pattern)
149 value |= (symbol == "1")
150 mask |= (symbol != "-")
151 value <<= 1
152 mask <<= 1
153 value >>= 1
154 mask >>= 1
155
156 return super().__init__(value=value, mask=mask)
157
158
159 @_dataclasses.dataclass(eq=True, frozen=True)
160 class PPCRecord:
161 class FlagsMeta(type):
162 def __iter__(cls):
163 yield from (
164 "inv A",
165 "inv out",
166 "cry out",
167 "BR",
168 "sgn ext",
169 "rsrv",
170 "32b",
171 "sgn",
172 "lk",
173 "sgl pipe",
174 )
175
176 class Flags(frozenset, metaclass=FlagsMeta):
177 def __new__(cls, flags=frozenset()):
178 flags = frozenset(flags)
179 diff = (flags - frozenset(cls))
180 if diff:
181 raise ValueError(flags)
182 return super().__new__(cls, flags)
183
184 opcode: Opcode
185 comment: str
186 flags: Flags = Flags()
187 comment2: str = ""
188 function: _Function = _Function.NONE
189 intop: _MicrOp = _MicrOp.OP_ILLEGAL
190 in1: _In1Sel = _In1Sel.RA
191 in2: _In2Sel = _In2Sel.NONE
192 in3: _In3Sel = _In3Sel.NONE
193 out: _OutSel = _OutSel.NONE
194 cr_in: _CRInSel = _CRInSel.NONE
195 cr_out: _CROutSel = _CROutSel.NONE
196 cry_in: _CryIn = _CryIn.ZERO
197 ldst_len: _LDSTLen = _LDSTLen.NONE
198 upd: _LDSTMode = _LDSTMode.NONE
199 Rc: _RCOE = _RCOE.NONE
200 form: _Form = _Form.NONE
201 conditions: str = ""
202 unofficial: bool = False
203
204 __KEYMAP = {
205 "unit": "function",
206 "internal op": "intop",
207 "CR in": "cr_in",
208 "CR out": "cr_out",
209 "cry in": "cry_in",
210 "ldst len": "ldst_len",
211 "rc": "Rc",
212 "CONDITIONS": "conditions",
213 }
214
215 @classmethod
216 def CSV(cls, record, opcode_cls=Opcode):
217 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
218 typemap["opcode"] = opcode_cls
219
220 flags = set()
221 for flag in frozenset(PPCRecord.Flags):
222 if bool(record.pop(flag, "")):
223 flags.add(flag)
224 record["flags"] = PPCRecord.Flags(flags)
225
226 return dataclass(cls, record,
227 keymap=PPCRecord.__KEYMAP,
228 typemap=typemap)
229
230 @cached_property
231 def names(self):
232 return frozenset(self.comment.split("=")[-1].split("/"))
233
234
235 class PPCMultiRecord(frozenset):
236 @cached_property
237 def unified(self):
238 def merge(lhs, rhs):
239 value = 0
240 mask = 0
241 lvalue = lhs.opcode.value
242 rvalue = rhs.opcode.value
243 lmask = lhs.opcode.mask
244 rmask = rhs.opcode.mask
245 bits = max(lmask.bit_length(), rmask.bit_length())
246 for bit in range(bits):
247 lvstate = ((lvalue & (1 << bit)) != 0)
248 rvstate = ((rvalue & (1 << bit)) != 0)
249 lmstate = ((lmask & (1 << bit)) != 0)
250 rmstate = ((rmask & (1 << bit)) != 0)
251 vstate = lvstate
252 mstate = True
253 if (not lmstate or not rmstate) or (lvstate != rvstate):
254 vstate = 0
255 mstate = 0
256 value |= (vstate << bit)
257 mask |= (mstate << bit)
258
259 opcode = opcode=Opcode(value=value, mask=mask)
260
261 return _dataclasses.replace(lhs, opcode=opcode)
262
263 return _functools.reduce(merge, self)
264
265 def __getattr__(self, attr):
266 return getattr(self.unified, attr)
267
268
269 @_dataclasses.dataclass(eq=True, frozen=True)
270 class SVP64Record:
271 class ExtraMap(tuple):
272 class Extra(tuple):
273 @_dataclasses.dataclass(eq=True, frozen=True)
274 class Entry:
275 regtype: _SVExtraRegType = _SVExtraRegType.NONE
276 reg: _SVExtraReg = _SVExtraReg.NONE
277
278 def __repr__(self):
279 return f"{self.regtype.value}:{self.reg.name}"
280
281 def __new__(cls, value="0"):
282 if isinstance(value, str):
283 def transform(value):
284 (regtype, reg) = value.split(":")
285 regtype = _SVExtraRegType(regtype)
286 reg = _SVExtraReg(reg)
287 return cls.Entry(regtype=regtype, reg=reg)
288
289 if value == "0":
290 value = tuple()
291 else:
292 value = map(transform, value.split(";"))
293
294 return super().__new__(cls, value)
295
296 def __repr__(self):
297 return repr(list(self))
298
299 def __new__(cls, value=tuple()):
300 value = tuple(value)
301 if len(value) == 0:
302 value = (("0",) * 4)
303 return super().__new__(cls, map(cls.Extra, value))
304
305 def __repr__(self):
306 return repr({index:self[index] for index in range(0, 4)})
307
308 name: str
309 ptype: _SVPtype = _SVPtype.NONE
310 etype: _SVEtype = _SVEtype.NONE
311 in1: _In1Sel = _In1Sel.NONE
312 in2: _In2Sel = _In2Sel.NONE
313 in3: _In3Sel = _In3Sel.NONE
314 out: _OutSel = _OutSel.NONE
315 out2: _OutSel = _OutSel.NONE
316 cr_in: _CRInSel = _CRInSel.NONE
317 cr_out: _CROutSel = _CROutSel.NONE
318 extra: ExtraMap = ExtraMap()
319 conditions: str = ""
320 mode: _SVMode = _SVMode.NORMAL
321
322 __KEYMAP = {
323 "insn": "name",
324 "CONDITIONS": "conditions",
325 "Ptype": "ptype",
326 "Etype": "etype",
327 "CR in": "cr_in",
328 "CR out": "cr_out",
329 }
330
331 @classmethod
332 def CSV(cls, record):
333 for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
334 value = record[key]
335 if value == "0":
336 record[key] = "NONE"
337
338 extra = []
339 for idx in range(0, 4):
340 extra.append(record.pop(f"{idx}"))
341
342 record["extra"] = cls.ExtraMap(extra)
343
344 return dataclass(cls, record, keymap=cls.__KEYMAP)
345
346 @_functools.lru_cache(maxsize=None)
347 def extra_idx(self, key):
348 extra_idx = (
349 _SVExtra.Idx0,
350 _SVExtra.Idx1,
351 _SVExtra.Idx2,
352 _SVExtra.Idx3,
353 )
354
355 if key not in frozenset({
356 "in1", "in2", "in3", "cr_in",
357 "out", "out2", "cr_out",
358 }):
359 raise KeyError(key)
360
361 sel = getattr(self, key)
362 if sel is _CRInSel.BA_BB:
363 return _SVExtra.Idx_1_2
364 reg = _SVExtraReg(sel)
365 if reg is _SVExtraReg.NONE:
366 return _SVExtra.NONE
367
368 extra_map = {
369 _SVExtraRegType.SRC: {},
370 _SVExtraRegType.DST: {},
371 }
372 for index in range(0, 4):
373 for entry in self.extra[index]:
374 extra_map[entry.regtype][entry.reg] = extra_idx[index]
375
376 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
377 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
378 if extra is not _SVExtra.NONE:
379 return extra
380
381 return _SVExtra.NONE
382
383 extra_idx_in1 = property(_functools.partial(extra_idx, key="in1"))
384 extra_idx_in2 = property(_functools.partial(extra_idx, key="in2"))
385 extra_idx_in3 = property(_functools.partial(extra_idx, key="in3"))
386 extra_idx_out = property(_functools.partial(extra_idx, key="out"))
387 extra_idx_out2 = property(_functools.partial(extra_idx, key="out2"))
388 extra_idx_cr_in = property(_functools.partial(extra_idx, key="cr_in"))
389 extra_idx_cr_out = property(_functools.partial(extra_idx, key="cr_out"))
390
391 @_functools.lru_cache(maxsize=None)
392 def extra_reg(self, key):
393 return _SVExtraReg(getattr(self, key))
394
395 extra_reg_in1 = property(_functools.partial(extra_reg, key="in1"))
396 extra_reg_in2 = property(_functools.partial(extra_reg, key="in2"))
397 extra_reg_in3 = property(_functools.partial(extra_reg, key="in3"))
398 extra_reg_out = property(_functools.partial(extra_reg, key="out"))
399 extra_reg_out2 = property(_functools.partial(extra_reg, key="out2"))
400 extra_reg_cr_in = property(_functools.partial(extra_reg, key="cr_in"))
401 extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
402
403
404 class BitSel:
405 def __init__(self, value=(0, 32)):
406 if isinstance(value, str):
407 (start, end) = map(int, value.split(":"))
408 else:
409 (start, end) = value
410 if start < 0 or end < 0 or start >= end:
411 raise ValueError(value)
412
413 self.__start = start
414 self.__end = end
415
416 return super().__init__()
417
418 def __repr__(self):
419 return f"[{self.__start}:{self.__end}]"
420
421 def __iter__(self):
422 yield from range(self.start, (self.end + 1))
423
424 def __reversed__(self):
425 return tuple(reversed(tuple(self)))
426
427 @property
428 def start(self):
429 return self.__start
430
431 @property
432 def end(self):
433 return self.__end
434
435
436 @_dataclasses.dataclass(eq=True, frozen=True)
437 class Section:
438 class Mode(_enum.Enum):
439 INTEGER = _enum.auto()
440 PATTERN = _enum.auto()
441
442 @classmethod
443 def _missing_(cls, value):
444 if isinstance(value, str):
445 return cls[value.upper()]
446 return super()._missing_(value)
447
448 class Suffix(int):
449 def __new__(cls, value=None):
450 if isinstance(value, str):
451 if value.upper() == "NONE":
452 value = None
453 else:
454 value = int(value, 0)
455 if value is None:
456 value = 0
457
458 return super().__new__(cls, value)
459
460 def __str__(self):
461 return repr(self)
462
463 def __repr__(self):
464 return (bin(self) if self else "None")
465
466 path: _pathlib.Path
467 opcode: Opcode
468 bitsel: BitSel
469 suffix: Suffix
470 mode: Mode
471
472 @classmethod
473 def CSV(cls, record):
474 return dataclass(cls, record)
475
476
477 class Fields:
478 def __init__(self, items):
479 if isinstance(items, dict):
480 items = items.items()
481
482 def transform(item):
483 (name, bitrange) = item
484 return (name, tuple(bitrange.values()))
485
486 self.__mapping = dict(map(transform, items))
487
488 return super().__init__()
489
490 def __repr__(self):
491 return repr(self.__mapping)
492
493 def __iter__(self):
494 yield from self.__mapping.items()
495
496 def __contains__(self, key):
497 return self.__mapping.__contains__(key)
498
499 def __getitem__(self, key):
500 return self.__mapping.get(key, None)
501
502
503 @_dataclasses.dataclass(eq=True, frozen=True)
504 class Operand:
505 name: str
506
507 def span(self, record):
508 return record.fields[self.name]
509
510 def disassemble(self, insn, record,
511 verbosity=Verbosity.NORMAL, indent=""):
512 raise NotImplementedError
513
514
515 @_dataclasses.dataclass(eq=True, frozen=True)
516 class DynamicOperand(Operand):
517 def disassemble(self, insn, record,
518 verbosity=Verbosity.NORMAL, indent=""):
519 span = self.span(record=record)
520 if isinstance(insn, SVP64Instruction):
521 span = tuple(map(lambda bit: (bit + 32), span))
522 value = insn[span]
523
524 if verbosity >= Verbosity.VERBOSE:
525 span = map(str, span)
526 yield f"{indent}{self.name}"
527 yield f"{indent}{indent}{int(value):0{value.bits}b}"
528 yield f"{indent}{indent}{', '.join(span)}"
529 else:
530 yield str(int(value))
531
532
533 @_dataclasses.dataclass(eq=True, frozen=True)
534 class ImmediateOperand(DynamicOperand):
535 pass
536
537
538 @_dataclasses.dataclass(eq=True, frozen=True)
539 class StaticOperand(Operand):
540 value: int
541
542 def disassemble(self, insn, record,
543 verbosity=Verbosity.NORMAL, indent=""):
544 span = self.span(record=record)
545 if isinstance(insn, SVP64Instruction):
546 span = tuple(map(lambda bit: (bit + 32), span))
547 value = insn[span]
548
549 if verbosity >= Verbosity.VERBOSE:
550 span = map(str, span)
551 yield f"{indent}{self.name}"
552 yield f"{indent}{indent}{int(value):0{value.bits}b}"
553 yield f"{indent}{indent}{', '.join(span)}"
554 else:
555 yield str(int(value))
556
557
558 @_dataclasses.dataclass(eq=True, frozen=True)
559 class DynamicOperandReg(DynamicOperand):
560 def spec(self, insn, record, merge):
561 vector = False
562 span = self.span(record=record)
563 if isinstance(insn, SVP64Instruction):
564 span = tuple(map(lambda bit: (bit + 32), span))
565 value = insn[span]
566 span = tuple(map(str, span))
567
568 if isinstance(insn, SVP64Instruction):
569 extra_idx = self.extra_idx(record=record)
570 if extra_idx is _SVExtra.NONE:
571 return (vector, value, span)
572
573 if record.etype is _SVEtype.EXTRA3:
574 spec = insn.prefix.rm.extra3[extra_idx]
575 elif record.etype is _SVEtype.EXTRA2:
576 spec = insn.prefix.rm.extra2[extra_idx]
577 else:
578 raise ValueError(record.etype)
579
580 if spec != 0:
581 vector = bool(spec[0])
582 spec_span = spec.__class__
583 if record.etype is _SVEtype.EXTRA3:
584 spec_span = tuple(map(str, spec_span[1, 2]))
585 spec = spec[1, 2]
586 elif record.etype is _SVEtype.EXTRA2:
587 spec_span = tuple(map(str, spec_span[1,]))
588 spec = _SelectableInt(value=spec[1].value, bits=2)
589 if vector:
590 spec <<= 1
591 spec_span = (spec_span + ("{0}",))
592 else:
593 spec_span = (("{0}",) + spec_span)
594 else:
595 raise ValueError(record.etype)
596
597 (value, span) = merge(vector, value, span, spec, spec_span)
598
599 return (vector, value, span)
600
601 @property
602 def extra_reg(self):
603 return _SVExtraReg(self.name)
604
605 def extra_idx(self, record):
606 for key in frozenset({
607 "in1", "in2", "in3", "cr_in",
608 "out", "out2", "cr_out",
609 }):
610 extra_reg = record.svp64.extra_reg(key=key)
611 if extra_reg is self.extra_reg:
612 return record.extra_idx(key=key)
613
614 return _SVExtra.NONE
615
616 def disassemble(self, insn, record,
617 verbosity=Verbosity.NORMAL, prefix="", indent=""):
618 (vector, value, span) = self.spec(insn=insn, record=record)
619
620 if verbosity >= Verbosity.VERBOSE:
621 yield f"{indent}{self.name}"
622 yield f"{indent}{indent}{int(value):0{value.bits}b}"
623 yield f"{indent}{indent}{', '.join(span)}"
624 if isinstance(insn, SVP64Instruction):
625 extra_idx = self.extra_idx(record)
626 if record.etype is _SVEtype.NONE:
627 yield f"{indent}{indent}extra[none]"
628 else:
629 etype = repr(record.etype).lower()
630 yield f"{indent}{indent}{etype}{extra_idx!r}"
631 yield f"{indent}type"
632 yield f"{indent}{indent}{'vector' if vector else 'scalar'}"
633 else:
634 vector = "*" if vector else ""
635 yield f"{vector}{prefix}{int(value)}"
636
637
638 class DynamicOperandGPRFPR(DynamicOperandReg):
639 def spec(self, insn, record):
640 def merge(vector, value, span, spec, spec_span):
641 bits = (len(span) + len(spec_span))
642 value = _SelectableInt(value=value.value, bits=bits)
643 spec = _SelectableInt(value=spec.value, bits=bits)
644 if vector:
645 value = ((value << 2) | spec)
646 span = (span + spec_span)
647 else:
648 value = ((spec << 5) | value)
649 span = (spec_span + span)
650
651 return (value, span)
652
653 return super().spec(insn=insn, record=record, merge=merge)
654
655
656 class DynamicOperandGPR(DynamicOperandGPRFPR):
657 def disassemble(self, insn, record,
658 verbosity=Verbosity.NORMAL, indent=""):
659 prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
660 yield from super().disassemble(prefix=prefix,
661 insn=insn, record=record,
662 verbosity=verbosity, indent=indent)
663
664
665 @_dataclasses.dataclass(eq=True, frozen=True)
666 class DynamicOperandFPR(DynamicOperandGPRFPR):
667 def disassemble(self, insn, record,
668 verbosity=Verbosity.NORMAL, indent=""):
669 prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
670 yield from super().disassemble(prefix=prefix,
671 insn=insn, record=record,
672 verbosity=verbosity, indent=indent)
673
674
675 @_dataclasses.dataclass(eq=True, frozen=True)
676 class DynamicOperandTargetAddr(DynamicOperandReg):
677 def disassemble(self, insn, record, field,
678 verbosity=Verbosity.NORMAL, indent=""):
679 span = self.span(record=record)
680 if isinstance(insn, SVP64Instruction):
681 span = tuple(map(lambda bit: (bit + 32), span))
682 value = insn[span]
683
684 if verbosity >= Verbosity.VERBOSE:
685 span = tuple(map(str, span))
686 yield f"{indent}{self.name}"
687 yield f"{indent}{indent}{int(value):0{value.bits}b}00"
688 yield f"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
689 yield f"{indent}{indent}target_addr = EXTS({field} || 0b00))"
690 else:
691 yield hex(int(_selectconcat(value,
692 _SelectableInt(value=0b00, bits=2))))
693
694
695 @_dataclasses.dataclass(eq=True, frozen=True)
696 class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr):
697 def span(self, record):
698 return record.fields["LI"]
699
700 def disassemble(self, insn, record,
701 verbosity=Verbosity.NORMAL, indent=""):
702 return super().disassemble(field="LI",
703 insn=insn, record=record,
704 verbosity=verbosity, indent=indent)
705
706
707 class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr):
708 def span(self, record):
709 return record.fields["BD"]
710
711 def disassemble(self, insn, record,
712 verbosity=Verbosity.NORMAL, indent=""):
713 return super().disassemble(field="BD",
714 insn=insn, record=record,
715 verbosity=verbosity, indent=indent)
716
717
718 class DynamicOperandDDX(DynamicOperand):
719 def span(self, record):
720 operands = map(DynamicOperand, ("d0", "d1", "d2"))
721 spans = map(lambda operand: operand.span(record=record), operands)
722 return sum(spans, tuple())
723
724 def disassemble(self, insn, record,
725 verbosity=Verbosity.NORMAL, indent=""):
726 span = self.span(record=record)
727 if isinstance(insn, SVP64Instruction):
728 span = tuple(map(lambda bit: (bit + 32), span))
729 value = insn[span]
730
731 if verbosity >= Verbosity.VERBOSE:
732 yield f"{indent}D"
733 mapping = {
734 "d0": "[0:9]",
735 "d1": "[10:15]",
736 "d2": "[16]",
737 }
738 for (subname, subspan) in mapping.items():
739 operand = DynamicOperand(name=subname)
740 span = operand.span(record=record)
741 if isinstance(insn, SVP64Instruction):
742 span = tuple(map(lambda bit: (bit + 32), span))
743 value = insn[span]
744 span = map(str, span)
745 yield f"{indent}{indent}{operand.name} = D{subspan}"
746 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
747 yield f"{indent}{indent}{indent}{', '.join(span)}"
748 else:
749 yield str(int(value))
750
751
752 class Operands(tuple):
753 def __new__(cls, insn, iterable):
754 custom = {
755 "b": {"target_addr": DynamicOperandTargetAddrLI},
756 "ba": {"target_addr": DynamicOperandTargetAddrLI},
757 "bl": {"target_addr": DynamicOperandTargetAddrLI},
758 "bla": {"target_addr": DynamicOperandTargetAddrLI},
759 "bc": {"target_addr": DynamicOperandTargetAddrBD},
760 "bca": {"target_addr": DynamicOperandTargetAddrBD},
761 "bcl": {"target_addr": DynamicOperandTargetAddrBD},
762 "bcla": {"target_addr": DynamicOperandTargetAddrBD},
763 "addpcis": {"D": DynamicOperandDDX},
764 "fishmv": {"D": DynamicOperandDDX},
765 "fmvis": {"D": DynamicOperandDDX},
766 }
767
768 operands = []
769 for operand in iterable:
770 dynamic_cls = DynamicOperand
771 static_cls = StaticOperand
772
773 if "=" in operand:
774 (name, value) = operand.split("=")
775 operand = static_cls(name=name, value=int(value))
776 operands.append(operand)
777 else:
778 if operand.endswith(")"):
779 operand = operand.replace("(", " ").replace(")", "")
780 (immediate, _, operand) = operand.partition(" ")
781 else:
782 immediate = None
783
784 if immediate is not None:
785 operands.append(ImmediateOperand(name=immediate))
786
787 if insn in custom and operand in custom[insn]:
788 dynamic_cls = custom[insn][operand]
789
790 if operand in _RegType.__members__:
791 regtype = _RegType[operand]
792 if regtype is _RegType.GPR:
793 dynamic_cls = DynamicOperandGPR
794 elif regtype is _RegType.FPR:
795 dynamic_cls = DynamicOperandFPR
796
797 operand = dynamic_cls(name=operand)
798 operands.append(operand)
799
800 return super().__new__(cls, operands)
801
802 def __contains__(self, key):
803 return self.__getitem__(key) is not None
804
805 def __getitem__(self, key):
806 for operand in self:
807 if operand.name == key:
808 return operand
809
810 return None
811
812 @property
813 def dynamic(self):
814 for operand in self:
815 if isinstance(operand, DynamicOperand):
816 yield operand
817
818 @property
819 def static(self):
820 for operand in self:
821 if isinstance(operand, StaticOperand):
822 yield operand
823
824
825 @_functools.total_ordering
826 @_dataclasses.dataclass(eq=True, frozen=True)
827 class Record:
828 name: str
829 section: Section
830 ppc: PPCRecord
831 fields: Fields
832 operands: Operands
833 svp64: SVP64Record = None
834
835 def __lt__(self, other):
836 if not isinstance(other, Record):
837 return NotImplemented
838 return (self.opcode < other.opcode)
839
840 @cached_property
841 def opcode(self):
842 value = ([0] * 32)
843 mask = ([0] * 32)
844
845 if self.section.opcode:
846 for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
847 value[dst] = ((self.section.opcode.value & (1 << src)) != 0)
848 mask[dst] = ((self.section.opcode.mask & (1 << src)) != 0)
849
850 for (src, dst) in enumerate(reversed(self.section.bitsel)):
851 value[dst] = ((self.ppc.opcode.value & (1 << src)) != 0)
852 mask[dst] = ((self.ppc.opcode.mask & (1 << src)) != 0)
853
854 for operand in self.operands.static:
855 for (src, dst) in enumerate(reversed(operand.span(record=self))):
856 value[dst] = ((operand.value & (1 << src)) != 0)
857 mask[dst] = True
858
859 for operand in self.operands.dynamic:
860 for dst in operand.span(record=self):
861 value[dst] = False
862 mask[dst] = False
863
864 def onebit(bit):
865 return _SelectableInt(value=int(bit), bits=1)
866
867 value = _selectconcat(*map(onebit, value))
868 mask = _selectconcat(*map(onebit, mask))
869
870 value = int(value)
871 mask = int(mask)
872
873 return Opcode(value=value, mask=mask)
874
875 @property
876 def function(self):
877 return self.ppc.function
878
879 @property
880 def in1(self):
881 return self.ppc.in1
882
883 @property
884 def in2(self):
885 return self.ppc.in2
886
887 @property
888 def in3(self):
889 return self.ppc.in3
890
891 @property
892 def out(self):
893 return self.ppc.out
894
895 @property
896 def out2(self):
897 if self.svp64 is None:
898 return _OutSel.NONE
899 return self.ppc.out
900
901 @property
902 def cr_in(self):
903 return self.ppc.cr_in
904
905 @property
906 def cr_out(self):
907 return self.ppc.cr_out
908
909 ptype = property(lambda self: self.svp64.ptype)
910 etype = property(lambda self: self.svp64.etype)
911
912 def extra_idx(self, key):
913 return self.svp64.extra_idx(key)
914
915 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
916 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
917 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
918 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
919 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
920 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
921 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
922
923
924 class Instruction(_Mapping):
925 @classmethod
926 def integer(cls, value=0, bits=None, byteorder="little"):
927 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
928 raise ValueError(bits)
929
930 if isinstance(value, bytes):
931 if ((len(value) * 8) != bits):
932 raise ValueError(f"bit length mismatch")
933 value = int.from_bytes(value, byteorder=byteorder)
934
935 if isinstance(value, int):
936 value = _SelectableInt(value=value, bits=bits)
937 elif isinstance(value, Instruction):
938 value = value.storage
939
940 if not isinstance(value, _SelectableInt):
941 raise ValueError(value)
942 if bits is None:
943 bits = len(cls)
944 if len(value) != bits:
945 raise ValueError(value)
946
947 value = _SelectableInt(value=value, bits=bits)
948
949 return cls(storage=value)
950
951 def __hash__(self):
952 return hash(int(self))
953
954 def record(self, db):
955 record = db[self]
956 if record is None:
957 raise KeyError(self)
958 return record
959
960 def spec(self, db, prefix):
961 record = self.record(db=db)
962
963 dynamic_operands = tuple(map(_operator.itemgetter(0),
964 self.dynamic_operands(db=db)))
965
966 static_operands = []
967 for (name, value) in self.static_operands(db=db):
968 static_operands.append(f"{name}={value}")
969
970 operands = ""
971 if dynamic_operands:
972 operands += f" {','.join(dynamic_operands)}"
973 if static_operands:
974 operands += f" ({' '.join(static_operands)})"
975
976 return f"{prefix}{record.name}{operands}"
977
978 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
979 record = self.record(db=db)
980
981 imm = False
982 imm_name = ""
983 imm_value = ""
984 for operand in record.operands.dynamic:
985 name = operand.name
986 dis = operand.disassemble(insn=self, record=record,
987 verbosity=min(verbosity, Verbosity.NORMAL))
988 value = " ".join(dis)
989 if imm:
990 name = f"{imm_name}({name})"
991 value = f"{imm_value}({value})"
992 imm = False
993 if isinstance(operand, ImmediateOperand):
994 imm_name = name
995 imm_value = value
996 imm = True
997 if not imm:
998 yield (name, value)
999
1000 def static_operands(self, db):
1001 record = self.record(db=db)
1002 for operand in record.operands.static:
1003 yield (operand.name, operand.value)
1004
1005 def disassemble(self, db,
1006 byteorder="little",
1007 verbosity=Verbosity.NORMAL):
1008 raise NotImplementedError
1009
1010
1011 class WordInstruction(Instruction):
1012 _: _Field = range(0, 32)
1013 po: _Field = range(0, 6)
1014
1015 @classmethod
1016 def integer(cls, value, byteorder="little"):
1017 return super().integer(bits=32, value=value, byteorder=byteorder)
1018
1019 @property
1020 def binary(self):
1021 bits = []
1022 for idx in range(32):
1023 bit = int(self[idx])
1024 bits.append(bit)
1025 return "".join(map(str, bits))
1026
1027 def opcode(self, db):
1028 record = self.record(db=db)
1029 return f"0x{record.opcode.value:08x}"
1030
1031 def mask(self, db):
1032 record = self.record(db=db)
1033 return f"0x{record.opcode.mask:08x}"
1034
1035 def disassemble(self, db,
1036 byteorder="little",
1037 verbosity=Verbosity.NORMAL):
1038 integer = int(self)
1039 if verbosity <= Verbosity.SHORT:
1040 blob = ""
1041 else:
1042 blob = integer.to_bytes(length=4, byteorder=byteorder)
1043 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1044 blob += " "
1045
1046 record = self.record(db=db)
1047 if record is None:
1048 yield f"{blob}.long 0x{integer:08x}"
1049 return
1050
1051 operands = tuple(map(_operator.itemgetter(1),
1052 self.dynamic_operands(db=db, verbosity=verbosity)))
1053 if operands:
1054 yield f"{blob}{record.name} {','.join(operands)}"
1055 else:
1056 yield f"{blob}{record.name}"
1057
1058 if verbosity >= Verbosity.VERBOSE:
1059 indent = (" " * 4)
1060 binary = self.binary
1061 spec = self.spec(db=db, prefix="")
1062 opcode = self.opcode(db=db)
1063 mask = self.mask(db=db)
1064 yield f"{indent}spec"
1065 yield f"{indent}{indent}{spec}"
1066 yield f"{indent}binary"
1067 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1068 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1069 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1070 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1071 yield f"{indent}opcode"
1072 yield f"{indent}{indent}{opcode}"
1073 yield f"{indent}mask"
1074 yield f"{indent}{indent}{mask}"
1075 for operand in record.operands:
1076 yield from operand.disassemble(insn=self, record=record,
1077 verbosity=verbosity, indent=indent)
1078 yield ""
1079
1080
1081 class PrefixedInstruction(Instruction):
1082 class Prefix(WordInstruction.remap(range(0, 32))):
1083 pass
1084
1085 class Suffix(WordInstruction.remap(range(32, 64))):
1086 pass
1087
1088 _: _Field = range(64)
1089 prefix: Prefix
1090 suffix: Suffix
1091 po: Suffix.po
1092
1093 @classmethod
1094 def integer(cls, value, byteorder="little"):
1095 return super().integer(bits=64, value=value, byteorder=byteorder)
1096
1097 @classmethod
1098 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1099 def transform(value):
1100 return WordInstruction.integer(value=value,
1101 byteorder=byteorder)[0:32]
1102
1103 (prefix, suffix) = map(transform, (prefix, suffix))
1104 value = _selectconcat(prefix, suffix)
1105
1106 return super().integer(value=value)
1107
1108
1109 class Mode(_Mapping):
1110 _: _Field = range(0, 5)
1111 sel: _Field = range(0, 2)
1112
1113
1114 class NormalMode(Mode):
1115 class simple(Mode):
1116 """simple mode"""
1117 dz: Mode[3]
1118 sz: Mode[4]
1119
1120 class smr(Mode):
1121 """scalar reduce mode (mapreduce), SUBVL=1"""
1122 RG: Mode[4]
1123
1124 class pmr(Mode):
1125 """parallel reduce mode (mapreduce), SUBVL=1"""
1126 pass
1127
1128 class svmr(Mode):
1129 """subvector reduce mode, SUBVL>1"""
1130 SVM: Mode[3]
1131
1132 class pu(Mode):
1133 """Pack/Unpack mode, SUBVL>1"""
1134 SVM: Mode[3]
1135
1136 class ffrc1(Mode):
1137 """Rc=1: ffirst CR sel"""
1138 inv: Mode[2]
1139 CRbit: Mode[3, 4]
1140
1141 class ffrc0(Mode):
1142 """Rc=0: ffirst z/nonz"""
1143 inv: Mode[2]
1144 VLi: Mode[3]
1145 RC1: Mode[4]
1146
1147 class sat(Mode):
1148 """sat mode: N=0/1 u/s, SUBVL=1"""
1149 N: Mode[2]
1150 dz: Mode[3]
1151 sz: Mode[4]
1152
1153 class satx(Mode):
1154 """sat mode: N=0/1 u/s, SUBVL>1"""
1155 N: Mode[2]
1156 zz: Mode[3]
1157 dz: Mode[3]
1158 sz: Mode[3]
1159
1160 class satpu(Mode):
1161 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1162 N: Mode[2]
1163 zz: Mode[3]
1164 dz: Mode[3]
1165 sz: Mode[3]
1166
1167 class prrc1(Mode):
1168 """Rc=1: pred-result CR sel"""
1169 inv: Mode[2]
1170 CRbit: Mode[3, 4]
1171
1172 class prrc0(Mode):
1173 """Rc=0: pred-result z/nonz"""
1174 inv: Mode[2]
1175 zz: Mode[3]
1176 RC1: Mode[4]
1177 dz: Mode[3]
1178 sz: Mode[3]
1179
1180 simple: simple
1181 smr: smr
1182 pmr: pmr
1183 svmr: svmr
1184 pu: pu
1185 ffrc1: ffrc1
1186 ffrc0: ffrc0
1187 sat: sat
1188 satx: satx
1189 satpu: satpu
1190 prrc1: prrc1
1191 prrc0: prrc0
1192
1193
1194 class LDSTImmMode(Mode):
1195 class simple(Mode):
1196 """simple mode"""
1197 zz: Mode[3]
1198 els: Mode[4]
1199 dz: Mode[3]
1200 sz: Mode[3]
1201
1202 class spu(Mode):
1203 """Structured Pack/Unpack"""
1204 zz: Mode[3]
1205 els: Mode[4]
1206 dz: Mode[3]
1207 sz: Mode[3]
1208
1209 class ffrc1(Mode):
1210 """Rc=1: ffirst CR sel"""
1211 inv: Mode[2]
1212 CRbit: Mode[3, 4]
1213
1214 class ffrc0(Mode):
1215 """Rc=0: ffirst z/nonz"""
1216 inv: Mode[2]
1217 els: Mode[3]
1218 RC1: Mode[4]
1219
1220 class sat(Mode):
1221 """sat mode: N=0/1 u/s"""
1222 N: Mode[2]
1223 zz: Mode[3]
1224 els: Mode[4]
1225 dz: Mode[3]
1226 sz: Mode[3]
1227
1228 class prrc1(Mode):
1229 """Rc=1: pred-result CR sel"""
1230 inv: Mode[2]
1231 CRbit: Mode[3, 4]
1232
1233 class prrc0(Mode):
1234 """Rc=0: pred-result z/nonz"""
1235 inv: Mode[2]
1236 els: Mode[3]
1237 RC1: Mode[4]
1238
1239 simple: simple
1240 spu: spu
1241 ffrc1: ffrc1
1242 ffrc0: ffrc0
1243 sat: sat
1244 prrc1: prrc1
1245 prrc0: prrc0
1246
1247
1248 class LDSTIdxMode(Mode):
1249 class simple(Mode):
1250 """simple mode"""
1251 SEA: Mode[2]
1252 sz: Mode[3]
1253 dz: Mode[3]
1254
1255 class stride(Mode):
1256 """strided (scalar only source)"""
1257 SEA: Mode[2]
1258 dz: Mode[3]
1259 sz: Mode[4]
1260
1261 class sat(Mode):
1262 """sat mode: N=0/1 u/s"""
1263 N: Mode[2]
1264 dz: Mode[3]
1265 sz: Mode[4]
1266
1267 class prrc1(Mode):
1268 """Rc=1: pred-result CR sel"""
1269 inv: Mode[2]
1270 CRbit: Mode[3, 4]
1271
1272 class prrc0(Mode):
1273 """Rc=0: pred-result z/nonz"""
1274 inv: Mode[2]
1275 zz: Mode[3]
1276 RC1: Mode[4]
1277 dz: Mode[3]
1278 sz: Mode[3]
1279
1280 simple: simple
1281 stride: stride
1282 sat: sat
1283 prrc1: prrc1
1284 prrc0: prrc0
1285
1286
1287 class Extra(_Mapping):
1288 _: _Field = range(0, 9)
1289
1290
1291 class Extra2(Extra):
1292 idx0: _Field = range(0, 2)
1293 idx1: _Field = range(2, 4)
1294 idx2: _Field = range(4, 6)
1295 idx3: _Field = range(6, 8)
1296
1297 def __getitem__(self, key):
1298 return {
1299 0: self.idx0,
1300 1: self.idx1,
1301 2: self.idx2,
1302 3: self.idx3,
1303 _SVExtra.Idx0: self.idx0,
1304 _SVExtra.Idx1: self.idx1,
1305 _SVExtra.Idx2: self.idx2,
1306 _SVExtra.Idx3: self.idx3,
1307 }[key]
1308
1309 def __setitem__(self, key, value):
1310 self[key].assign(value)
1311
1312
1313 class Extra3(Extra):
1314 idx0: _Field = range(0, 3)
1315 idx1: _Field = range(3, 6)
1316 idx2: _Field = range(6, 9)
1317
1318 def __getitem__(self, key):
1319 return {
1320 0: self.idx0,
1321 1: self.idx1,
1322 2: self.idx2,
1323 _SVExtra.Idx0: self.idx0,
1324 _SVExtra.Idx1: self.idx1,
1325 _SVExtra.Idx2: self.idx2,
1326 }[key]
1327
1328 def __setitem__(self, key, value):
1329 self[key].assign(value)
1330
1331
1332 class RM(_Mapping):
1333 class Mode(Mode):
1334 normal: NormalMode
1335 ldst_imm: LDSTImmMode
1336 ldst_idx: LDSTIdxMode
1337
1338 _: _Field = range(24)
1339 mmode: _Field = (0,)
1340 mask: _Field = range(1, 4)
1341 elwidth: _Field = range(4, 6)
1342 ewsrc: _Field = range(6, 8)
1343 subvl: _Field = range(8, 10)
1344 mode: Mode.remap(range(19, 24))
1345 smask: _Field = range(16, 19)
1346
1347 extra: Extra.remap(range(10, 19))
1348 extra2: Extra2.remap(range(10, 19))
1349 extra3: Extra3.remap(range(10, 19))
1350
1351
1352 class SVP64Instruction(PrefixedInstruction):
1353 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1354 class Prefix(PrefixedInstruction.Prefix):
1355 id: _Field = (7, 9)
1356 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1357
1358 prefix: Prefix
1359
1360 @property
1361 def binary(self):
1362 bits = []
1363 for idx in range(64):
1364 bit = int(self[idx])
1365 bits.append(bit)
1366 return "".join(map(str, bits))
1367
1368 def opcode(self, db):
1369 return self.suffix.opcode(db=db)
1370
1371 def mask(self, db):
1372 return self.suffix.mask(db=db)
1373
1374 def mode(self, db):
1375 record = self.record(db=db)
1376
1377 Rc = False
1378 if record.operands["Rc"] is not None:
1379 Rc = bool(self[record.fields["Rc"]])
1380
1381 record = self.record(db=db)
1382 subvl = self.prefix.rm.subvl
1383 mode = self.prefix.rm.mode
1384 sel = mode.sel
1385
1386 if record.svp64.mode is _SVMode.NORMAL:
1387 mode = mode.normal
1388 if sel == 0b00:
1389 if mode[2] == 0b0:
1390 mode = mode.simple
1391 else:
1392 if subvl == 0b00:
1393 if mode[3] == 0b0:
1394 mode = mode.smr
1395 else:
1396 mode = mode.pmr
1397 else:
1398 if mode[4] == 0b0:
1399 mode = mode.svmr
1400 else:
1401 mode = mode.pu
1402 elif sel == 0b01:
1403 if Rc:
1404 mode = mode.ffrc1
1405 else:
1406 mode = mode.ffrc0
1407 elif sel == 0b10:
1408 if subvl == 0b00:
1409 mode = mode.sat
1410 else:
1411 if mode[4]:
1412 mode = mode.satx
1413 else:
1414 mode = mode.satpu
1415 elif sel == 0b11:
1416 if Rc:
1417 mode = mode.prrc1
1418 else:
1419 mode = mode.prrc0
1420 elif record.svp64.mode is _SVMode.LDST_IMM:
1421 mode = mode.ldst_imm
1422 if sel == 0b00:
1423 if mode[2] == 0b0:
1424 mode = mode.simple
1425 else:
1426 mode = mode.spu
1427 elif sel == 0b01:
1428 if Rc:
1429 mode = mode.ffrc1
1430 else:
1431 mode = mode.ffrc0
1432 elif sel == 0b10:
1433 mode = mode.sat
1434 elif sel == 0b11:
1435 if Rc:
1436 mode = mode.prrc1
1437 else:
1438 mode = mode.prrc0
1439 elif record.svp64.mode is _SVMode.LDST_IMM:
1440 mode = mode.ldst_idx
1441 if mode.sel == 0b00:
1442 mode = mode.simple
1443 elif mode.sel == 0b01:
1444 mode = mode.stride
1445 elif mode.sel == 0b10:
1446 mode = mode.sat
1447 elif mode.sel == 0b11:
1448 if Rc:
1449 mode = mode.prrc1
1450 else:
1451 mode = mode.prrc0
1452
1453 modes = {
1454 NormalMode.simple: "normal: simple",
1455 NormalMode.smr: "normal: smr",
1456 NormalMode.pmr: "normal: pmr",
1457 NormalMode.svmr: "normal: svmr",
1458 NormalMode.pu: "normal: pu",
1459 NormalMode.ffrc1: "normal: ffrc1",
1460 NormalMode.ffrc0: "normal: ffrc0",
1461 NormalMode.sat: "normal: sat",
1462 NormalMode.satx: "normal: satx",
1463 NormalMode.satpu: "normal: satpu",
1464 NormalMode.prrc1: "normal: prrc1",
1465 NormalMode.prrc0: "normal: prrc0",
1466 LDSTImmMode.simple: "ld/st imm: simple",
1467 LDSTImmMode.spu: "ld/st imm: spu",
1468 LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
1469 LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
1470 LDSTImmMode.sat: "ld/st imm: sat",
1471 LDSTImmMode.prrc1: "ld/st imm: prrc1",
1472 LDSTImmMode.prrc0: "ld/st imm: prrc0",
1473 LDSTIdxMode.simple: "ld/st idx simple",
1474 LDSTIdxMode.stride: "ld/st idx stride",
1475 LDSTIdxMode.sat: "ld/st idx sat",
1476 LDSTIdxMode.prrc1: "ld/st idx prrc1",
1477 LDSTIdxMode.prrc0: "ld/st idx prrc0",
1478 }
1479 for (cls, desc) in modes.items():
1480 if isinstance(mode, cls):
1481 return (mode, desc)
1482
1483 if record.svp64.mode is _SVMode.BRANCH:
1484 return (self.prefix.rm.mode, "branch")
1485
1486 raise ValueError(self)
1487
1488 def disassemble(self, db,
1489 byteorder="little",
1490 verbosity=Verbosity.NORMAL):
1491 def blob(integer):
1492 if verbosity <= Verbosity.SHORT:
1493 return ""
1494 else:
1495 blob = integer.to_bytes(length=4, byteorder=byteorder)
1496 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1497 return f"{blob} "
1498
1499 blob_prefix = blob(int(self.prefix))
1500 blob_suffix = blob(int(self.suffix))
1501 record = self.record(db=db)
1502 if record is None or record.svp64 is None:
1503 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
1504 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
1505 return
1506
1507 operands = tuple(map(_operator.itemgetter(1),
1508 self.dynamic_operands(db=db, verbosity=verbosity)))
1509 if operands:
1510 yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
1511 else:
1512 yield f"{blob_prefix}{record.name}"
1513 yield f"{blob_suffix}"
1514
1515 (mode, mode_desc) = self.mode(db=db)
1516
1517 if verbosity >= Verbosity.VERBOSE:
1518 indent = (" " * 4)
1519 binary = self.binary
1520 spec = self.spec(db=db, prefix="sv.")
1521 opcode = self.opcode(db=db)
1522 mask = self.mask(db=db)
1523 yield f"{indent}spec"
1524 yield f"{indent}{indent}{spec}"
1525 yield f"{indent}binary"
1526 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1527 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1528 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1529 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1530 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1531 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1532 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1533 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1534 yield f"{indent}opcode"
1535 yield f"{indent}{indent}{opcode}"
1536 yield f"{indent}mask"
1537 yield f"{indent}{indent}{mask}"
1538 for operand in record.operands:
1539 yield from operand.disassemble(insn=self, record=record,
1540 verbosity=verbosity, indent=indent)
1541
1542 yield f"{indent}mode"
1543 yield f"{indent}{indent}{mode_desc}"
1544 yield ""
1545
1546
1547 def parse(stream, factory):
1548 def match(entry):
1549 return ("TODO" not in frozenset(entry.values()))
1550
1551 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1552 entries = _csv.DictReader(lines)
1553 entries = filter(match, entries)
1554 return tuple(map(factory, entries))
1555
1556
1557 class MarkdownDatabase:
1558 def __init__(self):
1559 db = {}
1560 for (name, desc) in _ISA():
1561 operands = []
1562 if desc.regs:
1563 (dynamic, *static) = desc.regs
1564 operands.extend(dynamic)
1565 operands.extend(static)
1566 db[name] = Operands(insn=name, iterable=operands)
1567 self.__db = db
1568 return super().__init__()
1569
1570 def __iter__(self):
1571 yield from self.__db.items()
1572
1573 def __getitem__(self, key):
1574 return self.__db.__getitem__(key)
1575
1576
1577 class FieldsDatabase:
1578 def __init__(self):
1579 db = {}
1580 df = _DecodeFields()
1581 df.create_specs()
1582 for (form, fields) in df.instrs.items():
1583 if form in {"DQE", "TX"}:
1584 continue
1585 if form == "all":
1586 form = "NONE"
1587 db[_Form[form]] = Fields(fields)
1588
1589 self.__db = db
1590
1591 return super().__init__()
1592
1593 def __getitem__(self, key):
1594 return self.__db.__getitem__(key)
1595
1596
1597 class PPCDatabase:
1598 def __init__(self, root, mdwndb):
1599 # The code below groups the instructions by section:identifier.
1600 # We use the comment as an identifier, there's nothing better.
1601 # The point is to capture different opcodes for the same instruction.
1602 dd = _collections.defaultdict
1603 records = dd(lambda: dd(set))
1604 path = (root / "insndb.csv")
1605 with open(path, "r", encoding="UTF-8") as stream:
1606 for section in parse(stream, Section.CSV):
1607 path = (root / section.path)
1608 opcode_cls = {
1609 section.Mode.INTEGER: IntegerOpcode,
1610 section.Mode.PATTERN: PatternOpcode,
1611 }[section.mode]
1612 factory = _functools.partial(
1613 PPCRecord.CSV, opcode_cls=opcode_cls)
1614 with open(path, "r", encoding="UTF-8") as stream:
1615 for insn in parse(stream, factory):
1616 records[section][insn.comment].add(insn)
1617
1618 db = dd(set)
1619 for (section, group) in records.items():
1620 for records in group.values():
1621 db[section].add(PPCMultiRecord(records))
1622
1623 self.__db = db
1624 self.__mdwndb = mdwndb
1625
1626 return super().__init__()
1627
1628 def __getitem__(self, key):
1629 def exact_match(key, record):
1630 for name in record.names:
1631 if name == key:
1632 return True
1633
1634 return False
1635
1636 def Rc_match(key, record):
1637 if not key.endswith("."):
1638 return False
1639
1640 if not record.Rc is _RCOE.RC:
1641 return False
1642
1643 return exact_match(key[:-1], record)
1644
1645 def LK_match(key, record):
1646 if not key.endswith("l"):
1647 return False
1648
1649 if "lk" not in record.flags:
1650 return False
1651
1652 return exact_match(key[:-1], record)
1653
1654 def AA_match(key, record):
1655 if not key.endswith("a"):
1656 return False
1657
1658 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1659 return False
1660
1661 if self.__mdwndb[key]["AA"] is None:
1662 return False
1663
1664 return (exact_match(key[:-1], record) or
1665 LK_match(key[:-1], record))
1666
1667 for (section, records) in self.__db.items():
1668 for record in records:
1669 if exact_match(key, record):
1670 return (section, record)
1671
1672 for record in records:
1673 if (Rc_match(key, record) or
1674 LK_match(key, record) or
1675 AA_match(key, record)):
1676 return (section, record)
1677
1678 return (None, None)
1679
1680
1681 class SVP64Database:
1682 def __init__(self, root, ppcdb):
1683 db = set()
1684 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1685 for (prefix, _, names) in _os.walk(root):
1686 prefix = _pathlib.Path(prefix)
1687 for name in filter(lambda name: pattern.match(name), names):
1688 path = (prefix / _pathlib.Path(name))
1689 with open(path, "r", encoding="UTF-8") as stream:
1690 db.update(parse(stream, SVP64Record.CSV))
1691
1692 self.__db = {record.name:record for record in db}
1693 self.__ppcdb = ppcdb
1694
1695 return super().__init__()
1696
1697 def __getitem__(self, key):
1698 (_, record) = self.__ppcdb[key]
1699 if record is None:
1700 return None
1701
1702 for name in record.names:
1703 record = self.__db.get(name, None)
1704 if record is not None:
1705 return record
1706
1707 return None
1708
1709
1710 class Database:
1711 def __init__(self, root):
1712 root = _pathlib.Path(root)
1713
1714 mdwndb = MarkdownDatabase()
1715 fieldsdb = FieldsDatabase()
1716 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
1717 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1718
1719 db = set()
1720 for (name, operands) in mdwndb:
1721 (section, ppc) = ppcdb[name]
1722 if ppc is None:
1723 continue
1724 svp64 = svp64db[name]
1725 fields = fieldsdb[ppc.form]
1726 record = Record(name=name,
1727 section=section, ppc=ppc, svp64=svp64,
1728 operands=operands, fields=fields)
1729 db.add(record)
1730
1731 self.__db = tuple(sorted(db))
1732
1733 return super().__init__()
1734
1735 def __repr__(self):
1736 return repr(self.__db)
1737
1738 def __iter__(self):
1739 yield from self.__db
1740
1741 @_functools.lru_cache(maxsize=None)
1742 def __contains__(self, key):
1743 return self.__getitem__(key) is not None
1744
1745 @_functools.lru_cache(maxsize=None)
1746 def __getitem__(self, key):
1747 if isinstance(key, (int, Instruction)):
1748 key = int(key)
1749 matches = []
1750 for record in self:
1751 opcode = record.opcode
1752 if ((opcode.value & opcode.mask) ==
1753 (key & opcode.mask)):
1754 matches.append(record)
1755 if matches:
1756 return matches[-1]
1757 return None
1758 elif isinstance(key, Opcode):
1759 for record in self:
1760 if record.opcode == key:
1761 return record
1762 elif isinstance(key, str):
1763 for record in self:
1764 if record.name == key:
1765 return record
1766 return None