1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
6 import itertools
as _itertools
8 import operator
as _operator
9 import pathlib
as _pathlib
13 from functools
import cached_property
15 from cached_property
import cached_property
17 from openpower
.decoder
.power_enums
import (
18 Function
as _Function
,
25 CROutSel
as _CROutSel
,
27 LDSTMode
as _LDSTMode
,
36 SVExtraRegType
as _SVExtraRegType
,
37 SVExtraReg
as _SVExtraReg
,
39 from openpower
.decoder
.selectable_int
import (
40 SelectableInt
as _SelectableInt
,
41 selectconcat
as _selectconcat
,
43 from openpower
.decoder
.power_fields
import (
46 DecodeFields
as _DecodeFields
,
48 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
51 @_functools.total_ordering
52 class Verbosity(_enum
.Enum
):
55 VERBOSE
= _enum
.auto()
57 def __lt__(self
, other
):
58 if not isinstance(other
, self
.__class
__):
60 return (self
.value
< other
.value
)
63 def dataclass(cls
, record
, keymap
=None, typemap
=None):
67 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
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"):
79 record
= dict(map(transform
, record
.items()))
80 for key
in frozenset(record
.keys()):
87 @_functools.total_ordering
88 @_dataclasses.dataclass(eq
=True, frozen
=True)
92 if self
.bit_length() <= 32:
93 return f
"0x{self:08x}"
95 return f
"0x{self:016x}"
99 if self
.bit_length() <= 32:
100 return f
"0x{self:08x}"
102 return f
"0x{self:016x}"
107 def __lt__(self
, other
):
108 if not isinstance(other
, Opcode
):
109 return NotImplemented
110 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
112 def __post_init__(self
):
113 (value
, mask
) = (self
.value
, self
.mask
)
115 if isinstance(value
, Opcode
):
117 raise ValueError(mask
)
118 (value
, mask
) = (value
.value
, value
.mask
)
119 elif isinstance(value
, str):
121 raise ValueError(mask
)
122 value
= int(value
, 0)
124 if not isinstance(value
, int):
125 raise ValueError(value
)
128 if not isinstance(mask
, int):
129 raise ValueError(mask
)
131 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
132 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
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)
142 class PatternOpcode(Opcode
):
143 def __init__(self
, value
):
144 (pattern
, value
, mask
) = (value
, 0, 0)
146 for symbol
in pattern
:
147 if symbol
not in {"0", "1", "-"}:
148 raise ValueError(pattern
)
149 value |
= (symbol
== "1")
150 mask |
= (symbol
!= "-")
156 return super().__init
__(value
=value
, mask
=mask
)
159 @_dataclasses.dataclass(eq
=True, frozen
=True)
161 class FlagsMeta(type):
176 class Flags(frozenset, metaclass
=FlagsMeta
):
177 def __new__(cls
, flags
=frozenset()):
178 flags
= frozenset(flags
)
179 diff
= (flags
- frozenset(cls
))
181 raise ValueError(flags
)
182 return super().__new
__(cls
, flags
)
186 flags
: Flags
= Flags()
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
202 unofficial
: bool = False
206 "internal op": "intop",
210 "ldst len": "ldst_len",
212 "CONDITIONS": "conditions",
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
221 for flag
in frozenset(PPCRecord
.Flags
):
222 if bool(record
.pop(flag
, "")):
224 record
["flags"] = PPCRecord
.Flags(flags
)
226 return dataclass(cls
, record
,
227 keymap
=PPCRecord
.__KEYMAP
,
232 return frozenset(self
.comment
.split("=")[-1].split("/"))
235 class PPCMultiRecord(frozenset):
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)
253 if (not lmstate
or not rmstate
) or (lvstate
!= rvstate
):
256 value |
= (vstate
<< bit
)
257 mask |
= (mstate
<< bit
)
259 opcode
= opcode
=Opcode(value
=value
, mask
=mask
)
261 return _dataclasses
.replace(lhs
, opcode
=opcode
)
263 return _functools
.reduce(merge
, self
)
265 def __getattr__(self
, attr
):
266 return getattr(self
.unified
, attr
)
269 @_dataclasses.dataclass(eq
=True, frozen
=True)
271 class ExtraMap(tuple):
273 @_dataclasses.dataclass(eq
=True, frozen
=True)
275 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
276 reg
: _SVExtraReg
= _SVExtraReg
.NONE
279 return f
"{self.regtype.value}:{self.reg.name}"
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
)
292 value
= map(transform
, value
.split(";"))
294 return super().__new
__(cls
, value
)
297 return repr(list(self
))
299 def __new__(cls
, value
=tuple()):
303 return super().__new
__(cls
, map(cls
.Extra
, value
))
306 return repr({index
:self
[index
] for index
in range(0, 4)})
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()
320 mode
: _SVMode
= _SVMode
.NORMAL
324 "CONDITIONS": "conditions",
332 def CSV(cls
, record
):
333 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
339 for idx
in range(0, 4):
340 extra
.append(record
.pop(f
"{idx}"))
342 record
["extra"] = cls
.ExtraMap(extra
)
344 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
346 @_functools.lru_cache(maxsize
=None)
347 def extra_idx(self
, key
):
355 if key
not in frozenset({
356 "in1", "in2", "in3", "cr_in",
357 "out", "out2", "cr_out",
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
:
369 _SVExtraRegType
.SRC
: {},
370 _SVExtraRegType
.DST
: {},
372 for index
in range(0, 4):
373 for entry
in self
.extra
[index
]:
374 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
376 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
377 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
378 if extra
is not _SVExtra
.NONE
:
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"))
391 @_functools.lru_cache(maxsize
=None)
392 def extra_reg(self
, key
):
393 return _SVExtraReg(getattr(self
, key
))
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"))
405 def __init__(self
, value
=(0, 32)):
406 if isinstance(value
, str):
407 (start
, end
) = map(int, value
.split(":"))
410 if start
< 0 or end
< 0 or start
>= end
:
411 raise ValueError(value
)
416 return super().__init
__()
419 return f
"[{self.__start}:{self.__end}]"
422 yield from range(self
.start
, (self
.end
+ 1))
424 def __reversed__(self
):
425 return tuple(reversed(tuple(self
)))
436 @_dataclasses.dataclass(eq
=True, frozen
=True)
438 class Mode(_enum
.Enum
):
439 INTEGER
= _enum
.auto()
440 PATTERN
= _enum
.auto()
443 def _missing_(cls
, value
):
444 if isinstance(value
, str):
445 return cls
[value
.upper()]
446 return super()._missing
_(value
)
449 def __new__(cls
, value
=None):
450 if isinstance(value
, str):
451 if value
.upper() == "NONE":
454 value
= int(value
, 0)
458 return super().__new
__(cls
, value
)
464 return (bin(self
) if self
else "None")
473 def CSV(cls
, record
):
474 return dataclass(cls
, record
)
478 def __init__(self
, items
):
479 if isinstance(items
, dict):
480 items
= items
.items()
483 (name
, bitrange
) = item
484 return (name
, tuple(bitrange
.values()))
486 self
.__mapping
= dict(map(transform
, items
))
488 return super().__init
__()
491 return repr(self
.__mapping
)
494 yield from self
.__mapping
.items()
496 def __contains__(self
, key
):
497 return self
.__mapping
.__contains
__(key
)
499 def __getitem__(self
, key
):
500 return self
.__mapping
.get(key
, None)
503 @_dataclasses.dataclass(eq
=True, frozen
=True)
507 def span(self
, record
):
508 return record
.fields
[self
.name
]
510 def disassemble(self
, insn
, record
,
511 verbosity
=Verbosity
.NORMAL
, indent
=""):
512 raise NotImplementedError
515 class DynamicOperand(Operand
):
516 def disassemble(self
, insn
, record
,
517 verbosity
=Verbosity
.NORMAL
, indent
=""):
518 span
= self
.span(record
=record
)
519 if isinstance(insn
, SVP64Instruction
):
520 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
523 if verbosity
>= Verbosity
.VERBOSE
:
524 span
= map(str, span
)
525 yield f
"{indent}{self.name}"
526 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
527 yield f
"{indent}{indent}{', '.join(span)}"
529 yield str(int(value
))
532 @_dataclasses.dataclass(eq
=True, frozen
=True)
533 class StaticOperand(Operand
):
536 def disassemble(self
, insn
, record
,
537 verbosity
=Verbosity
.NORMAL
, indent
=""):
538 span
= self
.span(record
=record
)
539 if isinstance(insn
, SVP64Instruction
):
540 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
543 if verbosity
>= Verbosity
.VERBOSE
:
544 span
= map(str, span
)
545 yield f
"{indent}{self.name}"
546 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
547 yield f
"{indent}{indent}{', '.join(span)}"
549 yield str(int(value
))
552 class ImmediateOperand(DynamicOperand
):
556 class NonZeroOperand(DynamicOperand
):
557 def disassemble(self
, insn
, record
,
558 verbosity
=Verbosity
.NORMAL
, indent
=""):
559 span
= self
.span(record
=record
)
560 if isinstance(insn
, SVP64Instruction
):
561 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
564 if verbosity
>= Verbosity
.VERBOSE
:
565 span
= map(str, span
)
566 yield f
"{indent}{self.name}"
567 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
568 yield f
"{indent}{indent}{', '.join(span)}"
570 yield str(int(value
) + 1)
573 class RegisterOperand(DynamicOperand
):
574 def spec(self
, insn
, record
, merge
):
576 span
= self
.span(record
=record
)
577 if isinstance(insn
, SVP64Instruction
):
578 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
580 span
= tuple(map(str, span
))
582 if isinstance(insn
, SVP64Instruction
):
583 extra_idx
= self
.extra_idx(record
=record
)
584 if extra_idx
is _SVExtra
.NONE
:
585 return (vector
, value
, span
)
587 if record
.etype
is _SVEtype
.EXTRA3
:
588 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
589 elif record
.etype
is _SVEtype
.EXTRA2
:
590 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
592 raise ValueError(record
.etype
)
595 vector
= bool(spec
[0])
596 spec_span
= spec
.__class
__
597 if record
.etype
is _SVEtype
.EXTRA3
:
598 spec_span
= tuple(map(str, spec_span
[1, 2]))
600 elif record
.etype
is _SVEtype
.EXTRA2
:
601 spec_span
= tuple(map(str, spec_span
[1,]))
602 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
605 spec_span
= (spec_span
+ ("{0}",))
607 spec_span
= (("{0}",) + spec_span
)
609 raise ValueError(record
.etype
)
611 (value
, span
) = merge(vector
, value
, span
, spec
, spec_span
)
613 return (vector
, value
, span
)
617 return _SVExtraReg(self
.name
)
619 def extra_idx(self
, record
):
620 for key
in frozenset({
621 "in1", "in2", "in3", "cr_in",
622 "out", "out2", "cr_out",
624 extra_reg
= record
.svp64
.extra_reg(key
=key
)
625 if extra_reg
is self
.extra_reg
:
626 return record
.extra_idx(key
=key
)
630 def disassemble(self
, insn
, record
,
631 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
632 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
634 if verbosity
>= Verbosity
.VERBOSE
:
635 yield f
"{indent}{self.name}"
636 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
637 yield f
"{indent}{indent}{', '.join(span)}"
638 if isinstance(insn
, SVP64Instruction
):
639 extra_idx
= self
.extra_idx(record
)
640 if record
.etype
is _SVEtype
.NONE
:
641 yield f
"{indent}{indent}extra[none]"
643 etype
= repr(record
.etype
).lower()
644 yield f
"{indent}{indent}{etype}{extra_idx!r}"
645 yield f
"{indent}type"
646 yield f
"{indent}{indent}{'vector' if vector else 'scalar'}"
648 vector
= "*" if vector
else ""
649 yield f
"{vector}{prefix}{int(value)}"
652 class GPRFPROperand(RegisterOperand
):
653 def spec(self
, insn
, record
):
654 def merge(vector
, value
, span
, spec
, spec_span
):
655 bits
= (len(span
) + len(spec_span
))
656 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
657 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
659 value
= ((value
<< 2) | spec
)
660 span
= (span
+ spec_span
)
662 value
= ((spec
<< 5) | value
)
663 span
= (spec_span
+ span
)
667 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
670 class GPROperand(GPRFPROperand
):
671 def disassemble(self
, insn
, record
,
672 verbosity
=Verbosity
.NORMAL
, indent
=""):
673 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
674 yield from super().disassemble(prefix
=prefix
,
675 insn
=insn
, record
=record
,
676 verbosity
=verbosity
, indent
=indent
)
679 class FPROperand(GPRFPROperand
):
680 def disassemble(self
, insn
, record
,
681 verbosity
=Verbosity
.NORMAL
, indent
=""):
682 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
683 yield from super().disassemble(prefix
=prefix
,
684 insn
=insn
, record
=record
,
685 verbosity
=verbosity
, indent
=indent
)
688 class DynamicOperandCR(RegisterOperand
):
689 def spec(self
, insn
, record
):
690 def merge(vector
, value
, span
, spec
, spec_span
):
691 bits
= (len(span
) + len(spec_span
))
692 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
693 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
698 (value
, span
, (0, 1, 2)),
699 (spec
, spec_span
, (0, 1)),
700 (value
, span
, (3, 4)),
704 _SelectableInt(value
=0, bits
=1),
705 _SelectableInt(value
=0, bits
=1),
707 dst_span
= ["{0}", "{0}"]
709 (spec
, spec_span
, (0, 1)),
710 (value
, span
, (0, 1, 2, 3, 4)),
713 for (src_value
, src_span
, sel
) in table
:
715 dst_value
.append(src_value
[idx
])
716 dst_span
.append(src_span
[idx
])
718 value
= _selectconcat(dst_value
)
719 span
= tuple(dst_span
)
723 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
725 def disassemble(self
, insn
, record
, verbose
=False, indent
=""):
726 yield from super().disassemble(prefix
="cr",
727 insn
=insn
, record
=record
, verbose
=verbose
, indent
=indent
)
730 class TargetAddrOperand(RegisterOperand
):
731 def disassemble(self
, insn
, record
, field
,
732 verbosity
=Verbosity
.NORMAL
, indent
=""):
733 span
= self
.span(record
=record
)
734 if isinstance(insn
, SVP64Instruction
):
735 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
738 if verbosity
>= Verbosity
.VERBOSE
:
739 span
= tuple(map(str, span
))
740 yield f
"{indent}{self.name}"
741 yield f
"{indent}{indent}{int(value):0{value.bits}b}00"
742 yield f
"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
743 yield f
"{indent}{indent}target_addr = EXTS({field} || 0b00))"
745 yield hex(int(_selectconcat(value
,
746 _SelectableInt(value
=0b00, bits
=2))))
749 class TargetAddrOperandLI(TargetAddrOperand
):
750 def span(self
, record
):
751 return record
.fields
["LI"]
753 def disassemble(self
, insn
, record
,
754 verbosity
=Verbosity
.NORMAL
, indent
=""):
755 return super().disassemble(field
="LI",
756 insn
=insn
, record
=record
,
757 verbosity
=verbosity
, indent
=indent
)
760 class TargetAddrOperandBD(TargetAddrOperand
):
761 def span(self
, record
):
762 return record
.fields
["BD"]
764 def disassemble(self
, insn
, record
,
765 verbosity
=Verbosity
.NORMAL
, indent
=""):
766 return super().disassemble(field
="BD",
767 insn
=insn
, record
=record
,
768 verbosity
=verbosity
, indent
=indent
)
771 class DOperandDX(DynamicOperand
):
772 def span(self
, record
):
773 operands
= map(DynamicOperand
, ("d0", "d1", "d2"))
774 spans
= map(lambda operand
: operand
.span(record
=record
), operands
)
775 return sum(spans
, tuple())
777 def disassemble(self
, insn
, record
,
778 verbosity
=Verbosity
.NORMAL
, indent
=""):
779 span
= self
.span(record
=record
)
780 if isinstance(insn
, SVP64Instruction
):
781 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
784 if verbosity
>= Verbosity
.VERBOSE
:
791 for (subname
, subspan
) in mapping
.items():
792 operand
= DynamicOperand(name
=subname
)
793 span
= operand
.span(record
=record
)
794 if isinstance(insn
, SVP64Instruction
):
795 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
797 span
= map(str, span
)
798 yield f
"{indent}{indent}{operand.name} = D{subspan}"
799 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}"
800 yield f
"{indent}{indent}{indent}{', '.join(span)}"
802 yield str(int(value
))
805 class Operands(tuple):
806 def __new__(cls
, insn
, iterable
):
808 "b": {"target_addr": TargetAddrOperandLI
},
809 "ba": {"target_addr": TargetAddrOperandLI
},
810 "bl": {"target_addr": TargetAddrOperandLI
},
811 "bla": {"target_addr": TargetAddrOperandLI
},
812 "bc": {"target_addr": TargetAddrOperandBD
},
813 "bca": {"target_addr": TargetAddrOperandBD
},
814 "bcl": {"target_addr": TargetAddrOperandBD
},
815 "bcla": {"target_addr": TargetAddrOperandBD
},
816 "addpcis": {"D": DOperandDX
},
817 "fishmv": {"D": DOperandDX
},
818 "fmvis": {"D": DOperandDX
},
821 "SVi": NonZeroOperand
,
822 "SVd": NonZeroOperand
,
823 "SVxd": NonZeroOperand
,
824 "SVyd": NonZeroOperand
,
825 "SVzd": NonZeroOperand
,
829 for operand
in iterable
:
830 dynamic_cls
= DynamicOperand
831 static_cls
= StaticOperand
834 (name
, value
) = operand
.split("=")
835 operand
= static_cls(name
=name
, value
=int(value
))
836 operands
.append(operand
)
838 if operand
.endswith(")"):
839 operand
= operand
.replace("(", " ").replace(")", "")
840 (immediate
, _
, operand
) = operand
.partition(" ")
844 if immediate
is not None:
845 operands
.append(ImmediateOperand(name
=immediate
))
847 if insn
in custom_insns
and operand
in custom_insns
[insn
]:
848 dynamic_cls
= custom_insns
[insn
][operand
]
849 if operand
in custom_fields
:
850 dynamic_cls
= custom_fields
[operand
]
852 if operand
in _RegType
.__members
__:
853 regtype
= _RegType
[operand
]
854 if regtype
is _RegType
.GPR
:
855 dynamic_cls
= GPROperand
856 elif regtype
is _RegType
.FPR
:
857 dynamic_cls
= FPROperand
859 operand
= dynamic_cls(name
=operand
)
860 operands
.append(operand
)
862 return super().__new
__(cls
, operands
)
864 def __contains__(self
, key
):
865 return self
.__getitem
__(key
) is not None
867 def __getitem__(self
, key
):
869 if operand
.name
== key
:
877 if isinstance(operand
, DynamicOperand
):
883 if isinstance(operand
, StaticOperand
):
887 @_functools.total_ordering
888 @_dataclasses.dataclass(eq
=True, frozen
=True)
895 svp64
: SVP64Record
= None
897 def __lt__(self
, other
):
898 if not isinstance(other
, Record
):
899 return NotImplemented
900 return (self
.opcode
< other
.opcode
)
907 if self
.section
.opcode
:
908 for (src
, dst
) in enumerate(reversed(BitSel((0, 5)))):
909 value
[dst
] = ((self
.section
.opcode
.value
& (1 << src
)) != 0)
910 mask
[dst
] = ((self
.section
.opcode
.mask
& (1 << src
)) != 0)
912 for (src
, dst
) in enumerate(reversed(self
.section
.bitsel
)):
913 value
[dst
] = ((self
.ppc
.opcode
.value
& (1 << src
)) != 0)
914 mask
[dst
] = ((self
.ppc
.opcode
.mask
& (1 << src
)) != 0)
916 for operand
in self
.operands
.static
:
917 for (src
, dst
) in enumerate(reversed(operand
.span(record
=self
))):
918 value
[dst
] = ((operand
.value
& (1 << src
)) != 0)
921 for operand
in self
.operands
.dynamic
:
922 for dst
in operand
.span(record
=self
):
927 return _SelectableInt(value
=int(bit
), bits
=1)
929 value
= _selectconcat(*map(onebit
, value
))
930 mask
= _selectconcat(*map(onebit
, mask
))
935 return Opcode(value
=value
, mask
=mask
)
939 return self
.ppc
.function
959 if self
.svp64
is None:
965 return self
.ppc
.cr_in
969 return self
.ppc
.cr_out
971 ptype
= property(lambda self
: self
.svp64
.ptype
)
972 etype
= property(lambda self
: self
.svp64
.etype
)
974 def extra_idx(self
, key
):
975 return self
.svp64
.extra_idx(key
)
977 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
978 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
979 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
980 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
981 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
982 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
983 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
986 class Instruction(_Mapping
):
988 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
989 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
990 raise ValueError(bits
)
992 if isinstance(value
, bytes
):
993 if ((len(value
) * 8) != bits
):
994 raise ValueError(f
"bit length mismatch")
995 value
= int.from_bytes(value
, byteorder
=byteorder
)
997 if isinstance(value
, int):
998 value
= _SelectableInt(value
=value
, bits
=bits
)
999 elif isinstance(value
, Instruction
):
1000 value
= value
.storage
1002 if not isinstance(value
, _SelectableInt
):
1003 raise ValueError(value
)
1006 if len(value
) != bits
:
1007 raise ValueError(value
)
1009 value
= _SelectableInt(value
=value
, bits
=bits
)
1011 return cls(storage
=value
)
1014 return hash(int(self
))
1016 def record(self
, db
):
1019 raise KeyError(self
)
1022 def spec(self
, db
, prefix
):
1023 record
= self
.record(db
=db
)
1025 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1026 self
.dynamic_operands(db
=db
)))
1028 static_operands
= []
1029 for (name
, value
) in self
.static_operands(db
=db
):
1030 static_operands
.append(f
"{name}={value}")
1033 if dynamic_operands
:
1034 operands
+= f
" {','.join(dynamic_operands)}"
1036 operands
+= f
" ({' '.join(static_operands)})"
1038 return f
"{prefix}{record.name}{operands}"
1040 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1041 record
= self
.record(db
=db
)
1046 for operand
in record
.operands
.dynamic
:
1048 dis
= operand
.disassemble(insn
=self
, record
=record
,
1049 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1050 value
= " ".join(dis
)
1052 name
= f
"{imm_name}({name})"
1053 value
= f
"{imm_value}({value})"
1055 if isinstance(operand
, ImmediateOperand
):
1062 def static_operands(self
, db
):
1063 record
= self
.record(db
=db
)
1064 for operand
in record
.operands
.static
:
1065 yield (operand
.name
, operand
.value
)
1067 def disassemble(self
, db
,
1069 verbosity
=Verbosity
.NORMAL
):
1070 raise NotImplementedError
1073 class WordInstruction(Instruction
):
1074 _
: _Field
= range(0, 32)
1075 po
: _Field
= range(0, 6)
1078 def integer(cls
, value
, byteorder
="little"):
1079 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1084 for idx
in range(32):
1085 bit
= int(self
[idx
])
1087 return "".join(map(str, bits
))
1089 def opcode(self
, db
):
1090 record
= self
.record(db
=db
)
1091 return f
"0x{record.opcode.value:08x}"
1094 record
= self
.record(db
=db
)
1095 return f
"0x{record.opcode.mask:08x}"
1097 def disassemble(self
, db
,
1099 verbosity
=Verbosity
.NORMAL
):
1101 if verbosity
<= Verbosity
.SHORT
:
1104 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1105 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1110 yield f
"{blob}.long 0x{integer:08x}"
1113 operands
= tuple(map(_operator
.itemgetter(1),
1114 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1116 yield f
"{blob}{record.name} {','.join(operands)}"
1118 yield f
"{blob}{record.name}"
1120 if verbosity
>= Verbosity
.VERBOSE
:
1122 binary
= self
.binary
1123 spec
= self
.spec(db
=db
, prefix
="")
1124 opcode
= self
.opcode(db
=db
)
1125 mask
= self
.mask(db
=db
)
1126 yield f
"{indent}spec"
1127 yield f
"{indent}{indent}{spec}"
1128 yield f
"{indent}binary"
1129 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1130 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1131 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1132 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1133 yield f
"{indent}opcode"
1134 yield f
"{indent}{indent}{opcode}"
1135 yield f
"{indent}mask"
1136 yield f
"{indent}{indent}{mask}"
1137 for operand
in record
.operands
:
1138 yield from operand
.disassemble(insn
=self
, record
=record
,
1139 verbosity
=verbosity
, indent
=indent
)
1143 class PrefixedInstruction(Instruction
):
1144 class Prefix(WordInstruction
.remap(range(0, 32))):
1147 class Suffix(WordInstruction
.remap(range(32, 64))):
1150 _
: _Field
= range(64)
1156 def integer(cls
, value
, byteorder
="little"):
1157 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1160 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1161 def transform(value
):
1162 return WordInstruction
.integer(value
=value
,
1163 byteorder
=byteorder
)[0:32]
1165 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1166 value
= _selectconcat(prefix
, suffix
)
1168 return super().integer(value
=value
)
1171 class Mode(_Mapping
):
1172 _
: _Field
= range(0, 5)
1173 sel
: _Field
= range(0, 2)
1176 class NormalMode(Mode
):
1183 """scalar reduce mode (mapreduce), SUBVL=1"""
1187 """parallel reduce mode (mapreduce), SUBVL=1"""
1191 """subvector reduce mode, SUBVL>1"""
1195 """Pack/Unpack mode, SUBVL>1"""
1199 """Rc=1: ffirst CR sel"""
1204 """Rc=0: ffirst z/nonz"""
1210 """sat mode: N=0/1 u/s, SUBVL=1"""
1216 """sat mode: N=0/1 u/s, SUBVL>1"""
1223 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1230 """Rc=1: pred-result CR sel"""
1235 """Rc=0: pred-result z/nonz"""
1256 class LDSTImmMode(Mode
):
1265 """Structured Pack/Unpack"""
1272 """Rc=1: ffirst CR sel"""
1277 """Rc=0: ffirst z/nonz"""
1283 """sat mode: N=0/1 u/s"""
1291 """Rc=1: pred-result CR sel"""
1296 """Rc=0: pred-result z/nonz"""
1310 class LDSTIdxMode(Mode
):
1318 """strided (scalar only source)"""
1324 """sat mode: N=0/1 u/s"""
1330 """Rc=1: pred-result CR sel"""
1335 """Rc=0: pred-result z/nonz"""
1349 class Extra(_Mapping
):
1350 _
: _Field
= range(0, 9)
1353 class Extra2(Extra
):
1354 idx0
: _Field
= range(0, 2)
1355 idx1
: _Field
= range(2, 4)
1356 idx2
: _Field
= range(4, 6)
1357 idx3
: _Field
= range(6, 8)
1359 def __getitem__(self
, key
):
1365 _SVExtra
.Idx0
: self
.idx0
,
1366 _SVExtra
.Idx1
: self
.idx1
,
1367 _SVExtra
.Idx2
: self
.idx2
,
1368 _SVExtra
.Idx3
: self
.idx3
,
1371 def __setitem__(self
, key
, value
):
1372 self
[key
].assign(value
)
1375 class Extra3(Extra
):
1376 idx0
: _Field
= range(0, 3)
1377 idx1
: _Field
= range(3, 6)
1378 idx2
: _Field
= range(6, 9)
1380 def __getitem__(self
, key
):
1385 _SVExtra
.Idx0
: self
.idx0
,
1386 _SVExtra
.Idx1
: self
.idx1
,
1387 _SVExtra
.Idx2
: self
.idx2
,
1390 def __setitem__(self
, key
, value
):
1391 self
[key
].assign(value
)
1397 ldst_imm
: LDSTImmMode
1398 ldst_idx
: LDSTIdxMode
1400 _
: _Field
= range(24)
1401 mmode
: _Field
= (0,)
1402 mask
: _Field
= range(1, 4)
1403 elwidth
: _Field
= range(4, 6)
1404 ewsrc
: _Field
= range(6, 8)
1405 subvl
: _Field
= range(8, 10)
1406 mode
: Mode
.remap(range(19, 24))
1407 smask
: _Field
= range(16, 19)
1409 extra
: Extra
.remap(range(10, 19))
1410 extra2
: Extra2
.remap(range(10, 19))
1411 extra3
: Extra3
.remap(range(10, 19))
1414 class SVP64Instruction(PrefixedInstruction
):
1415 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1416 class Prefix(PrefixedInstruction
.Prefix
):
1418 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1425 for idx
in range(64):
1426 bit
= int(self
[idx
])
1428 return "".join(map(str, bits
))
1430 def opcode(self
, db
):
1431 return self
.suffix
.opcode(db
=db
)
1434 return self
.suffix
.mask(db
=db
)
1437 record
= self
.record(db
=db
)
1440 if record
.operands
["Rc"] is not None:
1441 Rc
= bool(self
[record
.fields
["Rc"]])
1443 record
= self
.record(db
=db
)
1444 subvl
= self
.prefix
.rm
.subvl
1445 mode
= self
.prefix
.rm
.mode
1448 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1482 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1483 mode
= mode
.ldst_imm
1501 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1502 mode
= mode
.ldst_idx
1503 if mode
.sel
== 0b00:
1505 elif mode
.sel
== 0b01:
1507 elif mode
.sel
== 0b10:
1509 elif mode
.sel
== 0b11:
1516 NormalMode
.simple
: "normal: simple",
1517 NormalMode
.smr
: "normal: smr",
1518 NormalMode
.pmr
: "normal: pmr",
1519 NormalMode
.svmr
: "normal: svmr",
1520 NormalMode
.pu
: "normal: pu",
1521 NormalMode
.ffrc1
: "normal: ffrc1",
1522 NormalMode
.ffrc0
: "normal: ffrc0",
1523 NormalMode
.sat
: "normal: sat",
1524 NormalMode
.satx
: "normal: satx",
1525 NormalMode
.satpu
: "normal: satpu",
1526 NormalMode
.prrc1
: "normal: prrc1",
1527 NormalMode
.prrc0
: "normal: prrc0",
1528 LDSTImmMode
.simple
: "ld/st imm: simple",
1529 LDSTImmMode
.spu
: "ld/st imm: spu",
1530 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1531 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1532 LDSTImmMode
.sat
: "ld/st imm: sat",
1533 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1534 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1535 LDSTIdxMode
.simple
: "ld/st idx simple",
1536 LDSTIdxMode
.stride
: "ld/st idx stride",
1537 LDSTIdxMode
.sat
: "ld/st idx sat",
1538 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1539 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1541 for (cls
, desc
) in modes
.items():
1542 if isinstance(mode
, cls
):
1545 if record
.svp64
.mode
is _SVMode
.BRANCH
:
1546 return (self
.prefix
.rm
.mode
, "branch")
1548 raise ValueError(self
)
1550 def disassemble(self
, db
,
1552 verbosity
=Verbosity
.NORMAL
):
1554 if verbosity
<= Verbosity
.SHORT
:
1557 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1558 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1561 blob_prefix
= blob(int(self
.prefix
))
1562 blob_suffix
= blob(int(self
.suffix
))
1564 if record
is None or record
.svp64
is None:
1565 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1566 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1569 operands
= tuple(map(_operator
.itemgetter(1),
1570 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1572 yield f
"{blob_prefix}sv.{record.name} {','.join(operands)}"
1574 yield f
"{blob_prefix}{record.name}"
1576 yield f
"{blob_suffix}"
1578 (mode
, mode_desc
) = self
.mode(db
=db
)
1580 if verbosity
>= Verbosity
.VERBOSE
:
1582 binary
= self
.binary
1583 spec
= self
.spec(db
=db
, prefix
="sv.")
1584 opcode
= self
.opcode(db
=db
)
1585 mask
= self
.mask(db
=db
)
1586 yield f
"{indent}spec"
1587 yield f
"{indent}{indent}{spec}"
1588 yield f
"{indent}binary"
1589 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1590 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1591 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1592 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1593 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1594 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1595 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1596 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1597 yield f
"{indent}opcode"
1598 yield f
"{indent}{indent}{opcode}"
1599 yield f
"{indent}mask"
1600 yield f
"{indent}{indent}{mask}"
1601 for operand
in record
.operands
:
1602 yield from operand
.disassemble(insn
=self
, record
=record
,
1603 verbosity
=verbosity
, indent
=indent
)
1605 yield f
"{indent}mode"
1606 yield f
"{indent}{indent}{mode_desc}"
1610 def parse(stream
, factory
):
1612 return ("TODO" not in frozenset(entry
.values()))
1614 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1615 entries
= _csv
.DictReader(lines
)
1616 entries
= filter(match
, entries
)
1617 return tuple(map(factory
, entries
))
1620 class MarkdownDatabase
:
1623 for (name
, desc
) in _ISA():
1626 (dynamic
, *static
) = desc
.regs
1627 operands
.extend(dynamic
)
1628 operands
.extend(static
)
1629 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1631 return super().__init
__()
1634 yield from self
.__db
.items()
1636 def __getitem__(self
, key
):
1637 return self
.__db
.__getitem
__(key
)
1640 class FieldsDatabase
:
1643 df
= _DecodeFields()
1645 for (form
, fields
) in df
.instrs
.items():
1646 if form
in {"DQE", "TX"}:
1650 db
[_Form
[form
]] = Fields(fields
)
1654 return super().__init
__()
1656 def __getitem__(self
, key
):
1657 return self
.__db
.__getitem
__(key
)
1661 def __init__(self
, root
, mdwndb
):
1662 # The code below groups the instructions by section:identifier.
1663 # We use the comment as an identifier, there's nothing better.
1664 # The point is to capture different opcodes for the same instruction.
1665 dd
= _collections
.defaultdict
1666 records
= dd(lambda: dd(set))
1667 path
= (root
/ "insndb.csv")
1668 with
open(path
, "r", encoding
="UTF-8") as stream
:
1669 for section
in parse(stream
, Section
.CSV
):
1670 path
= (root
/ section
.path
)
1672 section
.Mode
.INTEGER
: IntegerOpcode
,
1673 section
.Mode
.PATTERN
: PatternOpcode
,
1675 factory
= _functools
.partial(
1676 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1677 with
open(path
, "r", encoding
="UTF-8") as stream
:
1678 for insn
in parse(stream
, factory
):
1679 records
[section
][insn
.comment
].add(insn
)
1682 for (section
, group
) in records
.items():
1683 for records
in group
.values():
1684 db
[section
].add(PPCMultiRecord(records
))
1687 self
.__mdwndb
= mdwndb
1689 return super().__init
__()
1691 def __getitem__(self
, key
):
1692 def exact_match(key
, record
):
1693 for name
in record
.names
:
1699 def Rc_match(key
, record
):
1700 if not key
.endswith("."):
1703 if not record
.Rc
is _RCOE
.RC
:
1706 return exact_match(key
[:-1], record
)
1708 def LK_match(key
, record
):
1709 if not key
.endswith("l"):
1712 if "lk" not in record
.flags
:
1715 return exact_match(key
[:-1], record
)
1717 def AA_match(key
, record
):
1718 if not key
.endswith("a"):
1721 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1724 if self
.__mdwndb
[key
]["AA"] is None:
1727 return (exact_match(key
[:-1], record
) or
1728 LK_match(key
[:-1], record
))
1730 for (section
, records
) in self
.__db
.items():
1731 for record
in records
:
1732 if exact_match(key
, record
):
1733 return (section
, record
)
1735 for record
in records
:
1736 if (Rc_match(key
, record
) or
1737 LK_match(key
, record
) or
1738 AA_match(key
, record
)):
1739 return (section
, record
)
1744 class SVP64Database
:
1745 def __init__(self
, root
, ppcdb
):
1747 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1748 for (prefix
, _
, names
) in _os
.walk(root
):
1749 prefix
= _pathlib
.Path(prefix
)
1750 for name
in filter(lambda name
: pattern
.match(name
), names
):
1751 path
= (prefix
/ _pathlib
.Path(name
))
1752 with
open(path
, "r", encoding
="UTF-8") as stream
:
1753 db
.update(parse(stream
, SVP64Record
.CSV
))
1755 self
.__db
= {record
.name
:record
for record
in db
}
1756 self
.__ppcdb
= ppcdb
1758 return super().__init
__()
1760 def __getitem__(self
, key
):
1761 (_
, record
) = self
.__ppcdb
[key
]
1765 for name
in record
.names
:
1766 record
= self
.__db
.get(name
, None)
1767 if record
is not None:
1774 def __init__(self
, root
):
1775 root
= _pathlib
.Path(root
)
1777 mdwndb
= MarkdownDatabase()
1778 fieldsdb
= FieldsDatabase()
1779 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1780 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1783 for (name
, operands
) in mdwndb
:
1784 (section
, ppc
) = ppcdb
[name
]
1787 svp64
= svp64db
[name
]
1788 fields
= fieldsdb
[ppc
.form
]
1789 record
= Record(name
=name
,
1790 section
=section
, ppc
=ppc
, svp64
=svp64
,
1791 operands
=operands
, fields
=fields
)
1794 self
.__db
= tuple(sorted(db
))
1796 return super().__init
__()
1799 return repr(self
.__db
)
1802 yield from self
.__db
1804 @_functools.lru_cache(maxsize
=None)
1805 def __contains__(self
, key
):
1806 return self
.__getitem
__(key
) is not None
1808 @_functools.lru_cache(maxsize
=None)
1809 def __getitem__(self
, key
):
1810 if isinstance(key
, (int, Instruction
)):
1814 opcode
= record
.opcode
1815 if ((opcode
.value
& opcode
.mask
) ==
1816 (key
& opcode
.mask
)):
1817 matches
.append(record
)
1821 elif isinstance(key
, Opcode
):
1823 if record
.opcode
== key
:
1825 elif isinstance(key
, str):
1827 if record
.name
== key
: