1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
7 import operator
as _operator
8 import pathlib
as _pathlib
12 from functools
import cached_property
14 from cached_property
import cached_property
16 from openpower
.decoder
.power_enums
import (
17 Function
as _Function
,
24 CROutSel
as _CROutSel
,
26 LDSTMode
as _LDSTMode
,
35 SVExtraRegType
as _SVExtraRegType
,
36 SVExtraReg
as _SVExtraReg
,
38 from openpower
.decoder
.selectable_int
import (
39 SelectableInt
as _SelectableInt
,
40 selectconcat
as _selectconcat
,
42 from openpower
.decoder
.power_fields
import (
45 DecodeFields
as _DecodeFields
,
47 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
50 @_functools.total_ordering
51 class Verbosity(_enum
.Enum
):
54 VERBOSE
= _enum
.auto()
56 def __lt__(self
, other
):
57 if not isinstance(other
, self
.__class
__):
59 return (self
.value
< other
.value
)
62 def dataclass(cls
, record
, keymap
=None, typemap
=None):
66 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
68 def transform(key_value
):
69 (key
, value
) = key_value
70 key
= keymap
.get(key
, key
)
71 hook
= typemap
.get(key
, lambda value
: value
)
72 if hook
is bool and value
in ("", "0"):
78 record
= dict(map(transform
, record
.items()))
79 for key
in frozenset(record
.keys()):
86 @_functools.total_ordering
87 @_dataclasses.dataclass(eq
=True, frozen
=True)
91 if self
.bit_length() <= 32:
92 return f
"0x{self:08x}"
94 return f
"0x{self:016x}"
98 if self
.bit_length() <= 32:
99 return f
"0x{self:08x}"
101 return f
"0x{self:016x}"
106 def __lt__(self
, other
):
107 if not isinstance(other
, Opcode
):
108 return NotImplemented
109 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
111 def __post_init__(self
):
112 (value
, mask
) = (self
.value
, self
.mask
)
114 if isinstance(value
, Opcode
):
116 raise ValueError(mask
)
117 (value
, mask
) = (value
.value
, value
.mask
)
118 elif isinstance(value
, str):
120 raise ValueError(mask
)
121 value
= int(value
, 0)
123 if not isinstance(value
, int):
124 raise ValueError(value
)
127 if not isinstance(mask
, int):
128 raise ValueError(mask
)
130 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
131 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
134 class IntegerOpcode(Opcode
):
135 def __init__(self
, value
):
136 if isinstance(value
, str):
137 value
= int(value
, 0)
138 return super().__init
__(value
=value
, mask
=None)
141 class PatternOpcode(Opcode
):
142 def __init__(self
, value
):
143 (pattern
, value
, mask
) = (value
, 0, 0)
145 for symbol
in pattern
:
146 if symbol
not in {"0", "1", "-"}:
147 raise ValueError(pattern
)
148 value |
= (symbol
== "1")
149 mask |
= (symbol
!= "-")
155 return super().__init
__(value
=value
, mask
=mask
)
158 class FieldsOpcode(Opcode
):
159 def __init__(self
, fields
):
160 def field(opcode
, field
):
161 (value
, mask
) = opcode
162 (field
, bits
) = field
163 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
164 for (index
, shift
) in enumerate(shifts
):
165 bit
= ((field
& (1 << index
)) != 0)
166 value |
= (bit
<< shift
)
170 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
172 return super().__init
__(value
=value
, mask
=mask
)
175 @_dataclasses.dataclass(eq
=True, frozen
=True)
177 class FlagsMeta(type):
192 class Flags(frozenset, metaclass
=FlagsMeta
):
193 def __new__(cls
, flags
=frozenset()):
194 flags
= frozenset(flags
)
195 diff
= (flags
- frozenset(cls
))
197 raise ValueError(flags
)
198 return super().__new
__(cls
, flags
)
202 flags
: Flags
= Flags()
204 function
: _Function
= _Function
.NONE
205 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
206 in1
: _In1Sel
= _In1Sel
.RA
207 in2
: _In2Sel
= _In2Sel
.NONE
208 in3
: _In3Sel
= _In3Sel
.NONE
209 out
: _OutSel
= _OutSel
.NONE
210 cr_in
: _CRInSel
= _CRInSel
.NONE
211 cr_out
: _CROutSel
= _CROutSel
.NONE
212 cry_in
: _CryIn
= _CryIn
.ZERO
213 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
214 upd
: _LDSTMode
= _LDSTMode
.NONE
215 Rc
: _RCOE
= _RCOE
.NONE
216 form
: _Form
= _Form
.NONE
218 unofficial
: bool = False
222 "internal op": "intop",
226 "ldst len": "ldst_len",
228 "CONDITIONS": "conditions",
232 def CSV(cls
, record
, opcode_cls
=Opcode
):
233 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
234 typemap
["opcode"] = opcode_cls
237 for flag
in frozenset(PPCRecord
.Flags
):
238 if bool(record
.pop(flag
, "")):
240 record
["flags"] = PPCRecord
.Flags(flags
)
242 return dataclass(cls
, record
,
243 keymap
=PPCRecord
.__KEYMAP
,
248 return frozenset(self
.comment
.split("=")[-1].split("/"))
251 class PPCMultiRecord(frozenset):
257 lvalue
= lhs
.opcode
.value
258 rvalue
= rhs
.opcode
.value
259 lmask
= lhs
.opcode
.mask
260 rmask
= rhs
.opcode
.mask
261 bits
= max(lmask
.bit_length(), rmask
.bit_length())
262 for bit
in range(bits
):
263 lvstate
= ((lvalue
& (1 << bit
)) != 0)
264 rvstate
= ((rvalue
& (1 << bit
)) != 0)
265 lmstate
= ((lmask
& (1 << bit
)) != 0)
266 rmstate
= ((rmask
& (1 << bit
)) != 0)
269 if (not lmstate
or not rmstate
) or (lvstate
!= rvstate
):
272 value |
= (vstate
<< bit
)
273 mask |
= (mstate
<< bit
)
275 opcode
= opcode
=Opcode(value
=value
, mask
=mask
)
277 return _dataclasses
.replace(lhs
, opcode
=opcode
)
279 return _functools
.reduce(merge
, self
)
281 def __getattr__(self
, attr
):
282 return getattr(self
.unified
, attr
)
285 @_dataclasses.dataclass(eq
=True, frozen
=True)
287 class ExtraMap(tuple):
289 @_dataclasses.dataclass(eq
=True, frozen
=True)
291 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
292 reg
: _SVExtraReg
= _SVExtraReg
.NONE
295 return f
"{self.regtype.value}:{self.reg.name}"
297 def __new__(cls
, value
="0"):
298 if isinstance(value
, str):
299 def transform(value
):
300 (regtype
, reg
) = value
.split(":")
301 regtype
= _SVExtraRegType(regtype
)
302 reg
= _SVExtraReg(reg
)
303 return cls
.Entry(regtype
=regtype
, reg
=reg
)
308 value
= map(transform
, value
.split(";"))
310 return super().__new
__(cls
, value
)
313 return repr(list(self
))
315 def __new__(cls
, value
=tuple()):
319 return super().__new
__(cls
, map(cls
.Extra
, value
))
322 return repr({index
:self
[index
] for index
in range(0, 4)})
325 ptype
: _SVPtype
= _SVPtype
.NONE
326 etype
: _SVEtype
= _SVEtype
.NONE
327 in1
: _In1Sel
= _In1Sel
.NONE
328 in2
: _In2Sel
= _In2Sel
.NONE
329 in3
: _In3Sel
= _In3Sel
.NONE
330 out
: _OutSel
= _OutSel
.NONE
331 out2
: _OutSel
= _OutSel
.NONE
332 cr_in
: _CRInSel
= _CRInSel
.NONE
333 cr_out
: _CROutSel
= _CROutSel
.NONE
334 extra
: ExtraMap
= ExtraMap()
336 mode
: _SVMode
= _SVMode
.NORMAL
340 "CONDITIONS": "conditions",
348 def CSV(cls
, record
):
349 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
355 for idx
in range(0, 4):
356 extra
.append(record
.pop(f
"{idx}"))
358 record
["extra"] = cls
.ExtraMap(extra
)
360 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
362 @_functools.lru_cache(maxsize
=None)
363 def extra_idx(self
, key
):
371 if key
not in frozenset({
372 "in1", "in2", "in3", "cr_in",
373 "out", "out2", "cr_out",
377 sel
= getattr(self
, key
)
378 if sel
is _CRInSel
.BA_BB
:
379 return _SVExtra
.Idx_1_2
380 reg
= _SVExtraReg(sel
)
381 if reg
is _SVExtraReg
.NONE
:
385 _SVExtraRegType
.SRC
: {},
386 _SVExtraRegType
.DST
: {},
388 for index
in range(0, 4):
389 for entry
in self
.extra
[index
]:
390 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
392 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
393 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
394 if extra
is not _SVExtra
.NONE
:
399 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
400 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
401 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
402 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
403 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
404 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
405 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
407 @_functools.lru_cache(maxsize
=None)
408 def extra_reg(self
, key
):
409 return _SVExtraReg(getattr(self
, key
))
411 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
412 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
413 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
414 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
415 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
416 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
417 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
421 def __init__(self
, value
=(0, 32)):
422 if isinstance(value
, str):
423 (start
, end
) = map(int, value
.split(":"))
426 if start
< 0 or end
< 0 or start
>= end
:
427 raise ValueError(value
)
432 return super().__init
__()
435 return f
"[{self.__start}:{self.__end}]"
438 yield from range(self
.start
, (self
.end
+ 1))
449 @_dataclasses.dataclass(eq
=True, frozen
=True)
451 class Mode(_enum
.Enum
):
452 INTEGER
= _enum
.auto()
453 PATTERN
= _enum
.auto()
456 def _missing_(cls
, value
):
457 if isinstance(value
, str):
458 return cls
[value
.upper()]
459 return super()._missing
_(value
)
462 def __new__(cls
, value
=None):
463 if isinstance(value
, str):
464 if value
.upper() == "NONE":
467 value
= int(value
, 0)
471 return super().__new
__(cls
, value
)
477 return (bin(self
) if self
else "None")
486 def CSV(cls
, record
):
487 return dataclass(cls
, record
)
491 def __init__(self
, items
):
492 if isinstance(items
, dict):
493 items
= items
.items()
496 (name
, bitrange
) = item
497 return (name
, tuple(bitrange
.values()))
499 self
.__mapping
= dict(map(transform
, items
))
501 return super().__init
__()
504 return repr(self
.__mapping
)
507 yield from self
.__mapping
.items()
509 def __contains__(self
, key
):
510 return self
.__mapping
.__contains
__(key
)
512 def __getitem__(self
, key
):
513 return self
.__mapping
.get(key
, None)
516 @_dataclasses.dataclass(eq
=True, frozen
=True)
520 def disassemble(self
, insn
, record
,
521 verbosity
=Verbosity
.NORMAL
, indent
=""):
522 raise NotImplementedError
525 @_dataclasses.dataclass(eq
=True, frozen
=True)
526 class DynamicOperand(Operand
):
527 def disassemble(self
, insn
, record
,
528 verbosity
=Verbosity
.NORMAL
, indent
=""):
529 span
= record
.fields
[self
.name
]
530 if isinstance(insn
, SVP64Instruction
):
531 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
534 if verbosity
>= Verbosity
.VERBOSE
:
535 span
= map(str, span
)
536 yield f
"{indent}{self.name}"
537 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
538 yield f
"{indent}{indent}{', '.join(span)}"
540 yield str(int(value
))
543 @_dataclasses.dataclass(eq
=True, frozen
=True)
544 class ImmediateOperand(DynamicOperand
):
548 @_dataclasses.dataclass(eq
=True, frozen
=True)
549 class StaticOperand(Operand
):
552 def disassemble(self
, insn
, record
,
553 verbosity
=Verbosity
.NORMAL
, indent
=""):
554 span
= record
.fields
[self
.name
]
555 if isinstance(insn
, SVP64Instruction
):
556 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
559 if verbosity
>= Verbosity
.VERBOSE
:
560 span
= map(str, span
)
561 yield f
"{indent}{self.name}"
562 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
563 yield f
"{indent}{indent}{', '.join(span)}"
565 yield str(int(value
))
568 @_dataclasses.dataclass(eq
=True, frozen
=True)
569 class DynamicOperandReg(DynamicOperand
):
570 def spec(self
, insn
, record
, merge
):
572 span
= record
.fields
[self
.name
]
573 if isinstance(insn
, SVP64Instruction
):
574 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
577 if isinstance(insn
, SVP64Instruction
):
578 extra_idx
= self
.extra_idx(record
=record
)
580 if record
.etype
is _SVEtype
.EXTRA3
:
581 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
582 elif record
.etype
is _SVEtype
.EXTRA2
:
583 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
585 raise ValueError(record
.etype
)
588 vector
= bool(spec
[0])
589 span
= tuple(map(str, span
))
590 spec_span
= spec
.__class
__
591 if record
.etype
is _SVEtype
.EXTRA3
:
592 spec_span
= tuple(map(str, spec_span
[1, 2]))
594 elif record
.etype
is _SVEtype
.EXTRA2
:
595 spec_span
= tuple(map(str, spec_span
[1,]))
596 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
599 spec_span
= (spec_span
+ ("{0}",))
601 spec_span
= (("{0}",) + spec_span
)
603 raise ValueError(record
.etype
)
605 (value
, span
) = merge(vector
, value
, span
, spec
, spec_span
)
607 span
= tuple(map(str, span
))
609 return (vector
, value
, span
)
613 return _SVExtraReg(self
.name
)
615 def extra_idx(self
, record
):
616 for key
in frozenset({
617 "in1", "in2", "in3", "cr_in",
618 "out", "out2", "cr_out",
620 extra_reg
= record
.svp64
.extra_reg(key
=key
)
621 if extra_reg
is self
.extra_reg
:
622 return record
.extra_idx(key
=key
)
626 def disassemble(self
, insn
, record
,
627 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
628 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
630 if verbosity
>= Verbosity
.VERBOSE
:
631 yield f
"{indent}{self.name}"
632 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
633 yield f
"{indent}{indent}{', '.join(span)}"
634 if isinstance(insn
, SVP64Instruction
):
635 extra_idx
= self
.extra_idx(record
)
636 if record
.etype
is _SVEtype
.NONE
:
637 yield f
"{indent}{indent}extra[none]"
639 etype
= repr(record
.etype
).lower()
640 yield f
"{indent}{indent}{etype}{extra_idx!r}"
641 yield f
"{indent}type"
642 yield f
"{indent}{indent}{'vector' if vector else 'scalar'}"
644 vector
= "*" if vector
else ""
645 yield f
"{vector}{prefix}{int(value)}"
648 class DynamicOperandGPRFPR(DynamicOperandReg
):
649 def spec(self
, insn
, record
):
650 def merge(vector
, value
, span
, spec
, spec_span
):
651 bits
= (len(span
) + len(spec_span
))
652 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
653 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
655 value
= ((value
<< 2) | spec
)
656 span
= (span
+ spec_span
)
658 value
= ((spec
<< 5) | value
)
659 span
= (spec_span
+ span
)
661 value
= _SelectableInt(value
=value
, bits
=bits
)
665 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
668 class DynamicOperandGPR(DynamicOperandGPRFPR
):
669 def disassemble(self
, insn
, record
,
670 verbosity
=Verbosity
.NORMAL
, indent
=""):
671 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
672 yield from super().disassemble(prefix
=prefix
,
673 insn
=insn
, record
=record
,
674 verbosity
=verbosity
, indent
=indent
)
677 @_dataclasses.dataclass(eq
=True, frozen
=True)
678 class DynamicOperandFPR(DynamicOperandGPRFPR
):
679 def disassemble(self
, insn
, record
,
680 verbosity
=Verbosity
.NORMAL
, indent
=""):
681 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
682 yield from super().disassemble(prefix
=prefix
,
683 insn
=insn
, record
=record
,
684 verbosity
=verbosity
, indent
=indent
)
687 @_dataclasses.dataclass(eq
=True, frozen
=True)
688 class DynamicOperandTargetAddr(DynamicOperandReg
):
689 def disassemble(self
, insn
, record
, field
,
690 verbosity
=Verbosity
.NORMAL
, indent
=""):
691 span
= record
.fields
[field
]
692 if isinstance(insn
, SVP64Instruction
):
693 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
696 if verbosity
>= Verbosity
.VERBOSE
:
697 span
= tuple(map(str, span
))
698 yield f
"{indent}{self.name}"
699 yield f
"{indent}{indent}{int(value):0{value.bits}b}00"
700 yield f
"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
701 yield f
"{indent}{indent}target_addr = EXTS({field} || 0b00))"
703 yield hex(int(_selectconcat(value
,
704 _SelectableInt(value
=0b00, bits
=2))))
707 @_dataclasses.dataclass(eq
=True, frozen
=True)
708 class DynamicOperandTargetAddrLI(DynamicOperandTargetAddr
):
709 def disassemble(self
, insn
, record
,
710 verbosity
=Verbosity
.NORMAL
, indent
=""):
711 return super().disassemble(field
="LI",
712 insn
=insn
, record
=record
,
713 verbosity
=verbosity
, indent
=indent
)
716 class DynamicOperandTargetAddrBD(DynamicOperandTargetAddr
):
717 def disassemble(self
, insn
, record
,
718 verbosity
=Verbosity
.NORMAL
, indent
=""):
719 return super().disassemble(field
="BD",
720 insn
=insn
, record
=record
,
721 verbosity
=verbosity
, indent
=indent
)
724 class Operands(tuple):
725 def __new__(cls
, insn
, iterable
):
727 "b": {"target_addr": DynamicOperandTargetAddrLI
},
728 "ba": {"target_addr": DynamicOperandTargetAddrLI
},
729 "bl": {"target_addr": DynamicOperandTargetAddrLI
},
730 "bla": {"target_addr": DynamicOperandTargetAddrLI
},
731 "bc": {"target_addr": DynamicOperandTargetAddrBD
},
732 "bca": {"target_addr": DynamicOperandTargetAddrBD
},
733 "bcl": {"target_addr": DynamicOperandTargetAddrBD
},
734 "bcla": {"target_addr": DynamicOperandTargetAddrBD
},
738 for operand
in iterable
:
739 dynamic_cls
= DynamicOperand
740 static_cls
= StaticOperand
743 (name
, value
) = operand
.split("=")
744 operand
= static_cls(name
=name
, value
=int(value
))
745 operands
.append(operand
)
747 if operand
.endswith(")"):
748 operand
= operand
.replace("(", " ").replace(")", "")
749 (immediate
, _
, operand
) = operand
.partition(" ")
753 if immediate
is not None:
754 operands
.append(ImmediateOperand(name
=immediate
))
756 if insn
in branches
and operand
in branches
[insn
]:
757 dynamic_cls
= branches
[insn
][operand
]
759 if operand
in _RegType
.__members
__:
760 regtype
= _RegType
[operand
]
761 if regtype
is _RegType
.GPR
:
762 dynamic_cls
= DynamicOperandGPR
763 elif regtype
is _RegType
.FPR
:
764 dynamic_cls
= DynamicOperandFPR
766 operand
= dynamic_cls(name
=operand
)
767 operands
.append(operand
)
769 return super().__new
__(cls
, operands
)
771 def __contains__(self
, key
):
772 return self
.__getitem
__(key
) is not None
774 def __getitem__(self
, key
):
776 if operand
.name
== key
:
784 if isinstance(operand
, DynamicOperand
):
790 if isinstance(operand
, StaticOperand
):
794 @_functools.total_ordering
795 @_dataclasses.dataclass(eq
=True, frozen
=True)
802 svp64
: SVP64Record
= None
804 def __lt__(self
, other
):
805 if not isinstance(other
, Record
):
806 return NotImplemented
807 return (self
.opcode
< other
.opcode
)
812 if self
.section
.opcode
:
813 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
814 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
816 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
818 for operand
in self
.operands
.static
:
819 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
821 return FieldsOpcode(fields
)
825 return self
.ppc
.function
845 if self
.svp64
is None:
851 return self
.ppc
.cr_in
855 return self
.ppc
.cr_out
857 ptype
= property(lambda self
: self
.svp64
.ptype
)
858 etype
= property(lambda self
: self
.svp64
.etype
)
860 def extra_idx(self
, key
):
861 return self
.svp64
.extra_idx(key
)
863 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
864 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
865 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
866 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
867 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
868 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
869 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
872 class Instruction(_Mapping
):
874 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
875 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
876 raise ValueError(bits
)
878 if isinstance(value
, bytes
):
879 if ((len(value
) * 8) != bits
):
880 raise ValueError(f
"bit length mismatch")
881 value
= int.from_bytes(value
, byteorder
=byteorder
)
883 if isinstance(value
, int):
884 value
= _SelectableInt(value
=value
, bits
=bits
)
885 elif isinstance(value
, Instruction
):
886 value
= value
.storage
888 if not isinstance(value
, _SelectableInt
):
889 raise ValueError(value
)
892 if len(value
) != bits
:
893 raise ValueError(value
)
895 value
= _SelectableInt(value
=value
, bits
=bits
)
897 return cls(storage
=value
)
900 return hash(int(self
))
902 def record(self
, db
):
908 def spec(self
, db
, prefix
):
909 record
= self
.record(db
=db
)
911 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
912 self
.dynamic_operands(db
=db
)))
915 for (name
, value
) in self
.static_operands(db
=db
):
916 static_operands
.append(f
"{name}={value}")
920 operands
+= f
" {','.join(dynamic_operands)}"
922 operands
+= f
" ({' '.join(static_operands)})"
924 return f
"{prefix}{record.name}{operands}"
926 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
927 record
= self
.record(db
=db
)
932 for operand
in record
.operands
.dynamic
:
934 dis
= operand
.disassemble(insn
=self
, record
=record
,
935 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
936 value
= " ".join(dis
)
938 name
= f
"{imm_name}({name})"
939 value
= f
"{imm_value}({value})"
941 if isinstance(operand
, ImmediateOperand
):
948 def static_operands(self
, db
):
949 record
= self
.record(db
=db
)
950 for operand
in record
.operands
.static
:
951 yield (operand
.name
, operand
.value
)
953 def disassemble(self
, db
,
955 verbosity
=Verbosity
.NORMAL
):
956 raise NotImplementedError
959 class WordInstruction(Instruction
):
960 _
: _Field
= range(0, 32)
961 po
: _Field
= range(0, 6)
964 def integer(cls
, value
, byteorder
="little"):
965 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
970 for idx
in range(32):
973 return "".join(map(str, bits
))
975 def opcode(self
, db
):
976 record
= self
.record(db
=db
)
977 return f
"0x{record.opcode.value:08x}"
980 record
= self
.record(db
=db
)
981 return f
"0x{record.opcode.mask:08x}"
983 def disassemble(self
, db
,
985 verbosity
=Verbosity
.NORMAL
):
987 if verbosity
<= Verbosity
.SHORT
:
990 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
991 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
994 record
= self
.record(db
=db
)
996 yield f
"{blob}.long 0x{integer:08x}"
999 operands
= tuple(map(_operator
.itemgetter(1),
1000 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1002 yield f
"{blob}{record.name} {','.join(operands)}"
1004 yield f
"{blob}{record.name}"
1006 if verbosity
>= Verbosity
.VERBOSE
:
1008 binary
= self
.binary
1009 spec
= self
.spec(db
=db
, prefix
="")
1010 opcode
= self
.opcode(db
=db
)
1011 mask
= self
.mask(db
=db
)
1012 yield f
"{indent}spec"
1013 yield f
"{indent}{indent}{spec}"
1014 yield f
"{indent}binary"
1015 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1016 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1017 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1018 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1019 yield f
"{indent}opcode"
1020 yield f
"{indent}{indent}{opcode}"
1021 yield f
"{indent}mask"
1022 yield f
"{indent}{indent}{mask}"
1023 for operand
in record
.operands
:
1024 yield from operand
.disassemble(insn
=self
, record
=record
,
1025 verbosity
=verbosity
, indent
=indent
)
1029 class PrefixedInstruction(Instruction
):
1030 class Prefix(WordInstruction
.remap(range(0, 32))):
1033 class Suffix(WordInstruction
.remap(range(32, 64))):
1036 _
: _Field
= range(64)
1042 def integer(cls
, value
, byteorder
="little"):
1043 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1046 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1047 def transform(value
):
1048 return WordInstruction
.integer(value
=value
,
1049 byteorder
=byteorder
)[0:32]
1051 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1052 value
= _selectconcat(prefix
, suffix
)
1054 return super().integer(value
=value
)
1057 class Mode(_Mapping
):
1058 _
: _Field
= range(0, 5)
1059 sel
: _Field
= range(0, 2)
1062 class NormalMode(Mode
):
1069 """scalar reduce mode (mapreduce), SUBVL=1"""
1073 """parallel reduce mode (mapreduce), SUBVL=1"""
1077 """subvector reduce mode, SUBVL>1"""
1081 """Pack/Unpack mode, SUBVL>1"""
1085 """Rc=1: ffirst CR sel"""
1090 """Rc=0: ffirst z/nonz"""
1096 """sat mode: N=0/1 u/s, SUBVL=1"""
1102 """sat mode: N=0/1 u/s, SUBVL>1"""
1109 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1116 """Rc=1: pred-result CR sel"""
1121 """Rc=0: pred-result z/nonz"""
1142 class LDSTImmMode(Mode
):
1151 """Structured Pack/Unpack"""
1158 """Rc=1: ffirst CR sel"""
1163 """Rc=0: ffirst z/nonz"""
1169 """sat mode: N=0/1 u/s"""
1177 """Rc=1: pred-result CR sel"""
1182 """Rc=0: pred-result z/nonz"""
1196 class LDSTIdxMode(Mode
):
1204 """strided (scalar only source)"""
1210 """sat mode: N=0/1 u/s"""
1216 """Rc=1: pred-result CR sel"""
1221 """Rc=0: pred-result z/nonz"""
1235 class Extra(_Mapping
):
1236 _
: _Field
= range(0, 9)
1239 class Extra2(Extra
):
1240 idx0
: _Field
= range(0, 2)
1241 idx1
: _Field
= range(2, 4)
1242 idx2
: _Field
= range(4, 6)
1243 idx3
: _Field
= range(6, 8)
1245 def __getitem__(self
, key
):
1251 _SVExtra
.Idx0
: self
.idx0
,
1252 _SVExtra
.Idx1
: self
.idx1
,
1253 _SVExtra
.Idx2
: self
.idx2
,
1254 _SVExtra
.Idx3
: self
.idx3
,
1257 def __setitem__(self
, key
, value
):
1258 self
[key
].assign(value
)
1261 class Extra3(Extra
):
1262 idx0
: _Field
= range(0, 3)
1263 idx1
: _Field
= range(3, 6)
1264 idx2
: _Field
= range(6, 9)
1266 def __getitem__(self
, key
):
1271 _SVExtra
.Idx0
: self
.idx0
,
1272 _SVExtra
.Idx1
: self
.idx1
,
1273 _SVExtra
.Idx2
: self
.idx2
,
1276 def __setitem__(self
, key
, value
):
1277 self
[key
].assign(value
)
1283 ldst_imm
: LDSTImmMode
1284 ldst_idx
: LDSTIdxMode
1286 _
: _Field
= range(24)
1287 mmode
: _Field
= (0,)
1288 mask
: _Field
= range(1, 4)
1289 elwidth
: _Field
= range(4, 6)
1290 ewsrc
: _Field
= range(6, 8)
1291 subvl
: _Field
= range(8, 10)
1292 mode
: Mode
.remap(range(19, 24))
1293 smask
: _Field
= range(16, 19)
1295 extra
: Extra
.remap(range(10, 19))
1296 extra2
: Extra2
.remap(range(10, 19))
1297 extra3
: Extra3
.remap(range(10, 19))
1300 class SVP64Instruction(PrefixedInstruction
):
1301 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1302 class Prefix(PrefixedInstruction
.Prefix
):
1304 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1311 for idx
in range(64):
1312 bit
= int(self
[idx
])
1314 return "".join(map(str, bits
))
1316 def opcode(self
, db
):
1317 return self
.suffix
.opcode(db
=db
)
1320 return self
.suffix
.mask(db
=db
)
1323 record
= self
.record(db
=db
)
1326 if record
.operands
["Rc"] is not None:
1327 Rc
= bool(self
[record
.fields
["Rc"]])
1329 record
= self
.record(db
=db
)
1330 subvl
= self
.prefix
.rm
.subvl
1331 mode
= self
.prefix
.rm
.mode
1334 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1368 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1369 mode
= mode
.ldst_imm
1387 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1388 mode
= mode
.ldst_idx
1389 if mode
.sel
== 0b00:
1391 elif mode
.sel
== 0b01:
1393 elif mode
.sel
== 0b10:
1395 elif mode
.sel
== 0b11:
1402 NormalMode
.simple
: "normal: simple",
1403 NormalMode
.smr
: "normal: smr",
1404 NormalMode
.pmr
: "normal: pmr",
1405 NormalMode
.svmr
: "normal: svmr",
1406 NormalMode
.pu
: "normal: pu",
1407 NormalMode
.ffrc1
: "normal: ffrc1",
1408 NormalMode
.ffrc0
: "normal: ffrc0",
1409 NormalMode
.sat
: "normal: sat",
1410 NormalMode
.satx
: "normal: satx",
1411 NormalMode
.satpu
: "normal: satpu",
1412 NormalMode
.prrc1
: "normal: prrc1",
1413 NormalMode
.prrc0
: "normal: prrc0",
1414 LDSTImmMode
.simple
: "ld/st imm: simple",
1415 LDSTImmMode
.spu
: "ld/st imm: spu",
1416 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1417 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1418 LDSTImmMode
.sat
: "ld/st imm: sat",
1419 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1420 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1421 LDSTIdxMode
.simple
: "ld/st idx simple",
1422 LDSTIdxMode
.stride
: "ld/st idx stride",
1423 LDSTIdxMode
.sat
: "ld/st idx sat",
1424 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1425 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1427 for (cls
, desc
) in modes
.items():
1428 if isinstance(mode
, cls
):
1431 if record
.svp64
.mode
is _SVMode
.BRANCH
:
1432 return (self
.prefix
.rm
.mode
, "branch")
1434 raise ValueError(self
)
1436 def disassemble(self
, db
,
1438 verbosity
=Verbosity
.NORMAL
):
1440 if verbosity
<= Verbosity
.SHORT
:
1443 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1444 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1447 blob_prefix
= blob(int(self
.prefix
))
1448 blob_suffix
= blob(int(self
.suffix
))
1449 record
= self
.record(db
=db
)
1450 if record
is None or record
.svp64
is None:
1451 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1452 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1455 operands
= tuple(map(_operator
.itemgetter(1),
1456 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1458 yield f
"{blob_prefix}sv.{record.name} {','.join(operands)}"
1460 yield f
"{blob_prefix}{record.name}"
1461 yield f
"{blob_suffix}"
1463 (mode
, mode_desc
) = self
.mode(db
=db
)
1465 if verbosity
>= Verbosity
.VERBOSE
:
1467 binary
= self
.binary
1468 spec
= self
.spec(db
=db
, prefix
="sv.")
1469 opcode
= self
.opcode(db
=db
)
1470 mask
= self
.mask(db
=db
)
1471 yield f
"{indent}spec"
1472 yield f
"{indent}{indent}{spec}"
1473 yield f
"{indent}binary"
1474 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1475 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1476 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1477 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1478 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1479 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1480 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1481 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1482 yield f
"{indent}opcode"
1483 yield f
"{indent}{indent}{opcode}"
1484 yield f
"{indent}mask"
1485 yield f
"{indent}{indent}{mask}"
1486 for operand
in record
.operands
:
1487 yield from operand
.disassemble(insn
=self
, record
=record
,
1488 verbosity
=verbosity
, indent
=indent
)
1490 yield f
"{indent}mode"
1491 yield f
"{indent}{indent}{mode_desc}"
1495 def parse(stream
, factory
):
1497 return ("TODO" not in frozenset(entry
.values()))
1499 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1500 entries
= _csv
.DictReader(lines
)
1501 entries
= filter(match
, entries
)
1502 return tuple(map(factory
, entries
))
1505 class MarkdownDatabase
:
1508 for (name
, desc
) in _ISA():
1511 (dynamic
, *static
) = desc
.regs
1512 operands
.extend(dynamic
)
1513 operands
.extend(static
)
1514 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1516 return super().__init
__()
1519 yield from self
.__db
.items()
1521 def __getitem__(self
, key
):
1522 return self
.__db
.__getitem
__(key
)
1525 class FieldsDatabase
:
1528 df
= _DecodeFields()
1530 for (form
, fields
) in df
.instrs
.items():
1531 if form
in {"DQE", "TX"}:
1535 db
[_Form
[form
]] = Fields(fields
)
1539 return super().__init
__()
1541 def __getitem__(self
, key
):
1542 return self
.__db
.__getitem
__(key
)
1546 def __init__(self
, root
, mdwndb
):
1547 # The code below groups the instructions by section:identifier.
1548 # We use the comment as an identifier, there's nothing better.
1549 # The point is to capture different opcodes for the same instruction.
1550 dd
= _collections
.defaultdict
1551 records
= dd(lambda: dd(set))
1552 path
= (root
/ "insndb.csv")
1553 with
open(path
, "r", encoding
="UTF-8") as stream
:
1554 for section
in parse(stream
, Section
.CSV
):
1555 path
= (root
/ section
.path
)
1557 section
.Mode
.INTEGER
: IntegerOpcode
,
1558 section
.Mode
.PATTERN
: PatternOpcode
,
1560 factory
= _functools
.partial(
1561 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1562 with
open(path
, "r", encoding
="UTF-8") as stream
:
1563 for insn
in parse(stream
, factory
):
1564 records
[section
][insn
.comment
].add(insn
)
1567 for (section
, group
) in records
.items():
1568 for records
in group
.values():
1569 db
[section
].add(PPCMultiRecord(records
))
1572 self
.__mdwndb
= mdwndb
1574 return super().__init
__()
1576 def __getitem__(self
, key
):
1577 def exact_match(key
, record
):
1578 for name
in record
.names
:
1584 def Rc_match(key
, record
):
1585 if not key
.endswith("."):
1588 if not record
.Rc
is _RCOE
.RC
:
1591 return exact_match(key
[:-1], record
)
1593 def LK_match(key
, record
):
1594 if not key
.endswith("l"):
1597 if "lk" not in record
.flags
:
1600 return exact_match(key
[:-1], record
)
1602 def AA_match(key
, record
):
1603 if not key
.endswith("a"):
1606 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1609 if self
.__mdwndb
[key
]["AA"] is None:
1612 return (exact_match(key
[:-1], record
) or
1613 LK_match(key
[:-1], record
))
1615 for (section
, records
) in self
.__db
.items():
1616 for record
in records
:
1617 if exact_match(key
, record
):
1618 return (section
, record
)
1620 for record
in records
:
1621 if (Rc_match(key
, record
) or
1622 LK_match(key
, record
) or
1623 AA_match(key
, record
)):
1624 return (section
, record
)
1629 class SVP64Database
:
1630 def __init__(self
, root
, ppcdb
):
1632 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1633 for (prefix
, _
, names
) in _os
.walk(root
):
1634 prefix
= _pathlib
.Path(prefix
)
1635 for name
in filter(lambda name
: pattern
.match(name
), names
):
1636 path
= (prefix
/ _pathlib
.Path(name
))
1637 with
open(path
, "r", encoding
="UTF-8") as stream
:
1638 db
.update(parse(stream
, SVP64Record
.CSV
))
1640 self
.__db
= {record
.name
:record
for record
in db
}
1641 self
.__ppcdb
= ppcdb
1643 return super().__init
__()
1645 def __getitem__(self
, key
):
1646 (_
, record
) = self
.__ppcdb
[key
]
1650 for name
in record
.names
:
1651 record
= self
.__db
.get(name
, None)
1652 if record
is not None:
1659 def __init__(self
, root
):
1660 root
= _pathlib
.Path(root
)
1662 mdwndb
= MarkdownDatabase()
1663 fieldsdb
= FieldsDatabase()
1664 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1665 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1668 for (name
, operands
) in mdwndb
:
1669 (section
, ppc
) = ppcdb
[name
]
1672 svp64
= svp64db
[name
]
1673 fields
= fieldsdb
[ppc
.form
]
1674 record
= Record(name
=name
,
1675 section
=section
, ppc
=ppc
, svp64
=svp64
,
1676 operands
=operands
, fields
=fields
)
1679 self
.__db
= tuple(sorted(db
))
1681 return super().__init
__()
1684 return repr(self
.__db
)
1687 yield from self
.__db
1689 @_functools.lru_cache(maxsize
=None)
1690 def __contains__(self
, key
):
1691 return self
.__getitem
__(key
) is not None
1693 @_functools.lru_cache(maxsize
=None)
1694 def __getitem__(self
, key
):
1695 if isinstance(key
, (int, Instruction
)):
1698 opcode
= record
.opcode
1699 if ((opcode
.value
& opcode
.mask
) ==
1700 (key
& opcode
.mask
)):
1703 elif isinstance(key
, Opcode
):
1705 if record
.opcode
== key
:
1707 elif isinstance(key
, str):
1709 if record
.name
== key
: