1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
7 import pathlib
as _pathlib
11 from functools
import cached_property
13 from cached_property
import cached_property
15 from openpower
.decoder
.power_enums
import (
16 Function
as _Function
,
23 CROutSel
as _CROutSel
,
25 LDSTMode
as _LDSTMode
,
34 SVExtraRegType
as _SVExtraRegType
,
35 SVExtraReg
as _SVExtraReg
,
37 from openpower
.decoder
.selectable_int
import (
38 SelectableInt
as _SelectableInt
,
39 selectconcat
as _selectconcat
,
41 from openpower
.decoder
.power_fields
import (
45 DecodeFields
as _DecodeFields
,
47 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
50 def dataclass(cls
, record
, keymap
=None, typemap
=None):
54 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
56 def transform(key_value
):
57 (key
, value
) = key_value
58 key
= keymap
.get(key
, key
)
59 hook
= typemap
.get(key
, lambda value
: value
)
60 if hook
is bool and value
in ("", "0"):
66 record
= dict(map(transform
, record
.items()))
67 for key
in frozenset(record
.keys()):
74 @_functools.total_ordering
75 @_dataclasses.dataclass(eq
=True, frozen
=True)
79 if self
.bit_length() <= 32:
80 return f
"0x{self:08x}"
82 return f
"0x{self:016x}"
86 if self
.bit_length() <= 32:
87 return f
"0x{self:08x}"
89 return f
"0x{self:016x}"
94 def __lt__(self
, other
):
95 if not isinstance(other
, Opcode
):
97 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
99 def __post_init__(self
):
100 (value
, mask
) = (self
.value
, self
.mask
)
102 if isinstance(value
, Opcode
):
104 raise ValueError(mask
)
105 (value
, mask
) = (value
.value
, value
.mask
)
106 elif isinstance(value
, str):
108 raise ValueError(mask
)
109 value
= int(value
, 0)
111 if not isinstance(value
, int):
112 raise ValueError(value
)
115 if not isinstance(mask
, int):
116 raise ValueError(mask
)
118 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
119 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
122 class IntegerOpcode(Opcode
):
123 def __init__(self
, value
):
124 if isinstance(value
, str):
125 value
= int(value
, 0)
126 return super().__init
__(value
=value
, mask
=None)
129 class PatternOpcode(Opcode
):
130 def __init__(self
, value
):
131 (pattern
, value
, mask
) = (value
, 0, 0)
133 for symbol
in pattern
:
134 if symbol
not in {"0", "1", "-"}:
135 raise ValueError(pattern
)
136 value |
= (symbol
== "1")
137 mask |
= (symbol
!= "-")
143 return super().__init
__(value
=value
, mask
=mask
)
146 class FieldsOpcode(Opcode
):
147 def __init__(self
, fields
):
148 def field(opcode
, field
):
149 (value
, mask
) = opcode
150 (field
, bits
) = field
151 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
152 for (index
, shift
) in enumerate(shifts
):
153 bit
= ((field
& (1 << index
)) != 0)
154 value |
= (bit
<< shift
)
158 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
160 return super().__init
__(value
=value
, mask
=mask
)
163 @_dataclasses.dataclass(eq
=True, frozen
=True)
165 class FlagsMeta(type):
180 class Flags(frozenset, metaclass
=FlagsMeta
):
181 def __new__(cls
, flags
=frozenset()):
182 flags
= frozenset(flags
)
183 diff
= (flags
- frozenset(cls
))
185 raise ValueError(flags
)
186 return super().__new
__(cls
, flags
)
190 flags
: Flags
= Flags()
192 function
: _Function
= _Function
.NONE
193 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
194 in1
: _In1Sel
= _In1Sel
.RA
195 in2
: _In2Sel
= _In2Sel
.NONE
196 in3
: _In3Sel
= _In3Sel
.NONE
197 out
: _OutSel
= _OutSel
.NONE
198 cr_in
: _CRInSel
= _CRInSel
.NONE
199 cr_out
: _CROutSel
= _CROutSel
.NONE
200 cry_in
: _CryIn
= _CryIn
.ZERO
201 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
202 upd
: _LDSTMode
= _LDSTMode
.NONE
203 Rc
: _RCOE
= _RCOE
.NONE
204 form
: _Form
= _Form
.NONE
206 unofficial
: bool = False
210 "internal op": "intop",
214 "ldst len": "ldst_len",
216 "CONDITIONS": "conditions",
220 def CSV(cls
, record
, opcode_cls
=Opcode
):
221 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
222 typemap
["opcode"] = opcode_cls
225 for flag
in frozenset(PPCRecord
.Flags
):
226 if bool(record
.pop(flag
, "")):
228 record
["flags"] = PPCRecord
.Flags(flags
)
230 return dataclass(cls
, record
,
231 keymap
=PPCRecord
.__KEYMAP
,
236 return frozenset(self
.comment
.split("=")[-1].split("/"))
239 class PPCMultiRecord(frozenset):
245 lvalue
= lhs
.opcode
.value
246 rvalue
= rhs
.opcode
.value
247 lmask
= lhs
.opcode
.mask
248 rmask
= rhs
.opcode
.mask
249 bits
= max(lmask
.bit_length(), rmask
.bit_length())
250 for bit
in range(bits
):
251 lvstate
= ((lvalue
& (1 << bit
)) != 0)
252 rvstate
= ((rvalue
& (1 << bit
)) != 0)
253 lmstate
= ((lmask
& (1 << bit
)) != 0)
254 rmstate
= ((rmask
& (1 << bit
)) != 0)
257 if (not lmstate
or not rmstate
) or (lvstate
!= rvstate
):
260 value |
= (vstate
<< bit
)
261 mask |
= (mstate
<< bit
)
263 opcode
= opcode
=Opcode(value
=value
, mask
=mask
)
265 return _dataclasses
.replace(lhs
, opcode
=opcode
)
267 return _functools
.reduce(merge
, self
)
269 def __getattr__(self
, attr
):
270 return getattr(self
.unified
, attr
)
273 @_dataclasses.dataclass(eq
=True, frozen
=True)
275 class ExtraMap(tuple):
277 @_dataclasses.dataclass(eq
=True, frozen
=True)
279 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
280 reg
: _SVExtraReg
= _SVExtraReg
.NONE
283 return f
"{self.regtype.value}:{self.reg.name}"
285 def __new__(cls
, value
="0"):
286 if isinstance(value
, str):
287 def transform(value
):
288 (regtype
, reg
) = value
.split(":")
289 regtype
= _SVExtraRegType(regtype
)
290 reg
= _SVExtraReg(reg
)
291 return cls
.Entry(regtype
=regtype
, reg
=reg
)
296 value
= map(transform
, value
.split(";"))
298 return super().__new
__(cls
, value
)
301 return repr(list(self
))
303 def __new__(cls
, value
=tuple()):
307 return super().__new
__(cls
, map(cls
.Extra
, value
))
310 return repr({index
:self
[index
] for index
in range(0, 4)})
313 ptype
: _SVPtype
= _SVPtype
.NONE
314 etype
: _SVEtype
= _SVEtype
.NONE
315 in1
: _In1Sel
= _In1Sel
.NONE
316 in2
: _In2Sel
= _In2Sel
.NONE
317 in3
: _In3Sel
= _In3Sel
.NONE
318 out
: _OutSel
= _OutSel
.NONE
319 out2
: _OutSel
= _OutSel
.NONE
320 cr_in
: _CRInSel
= _CRInSel
.NONE
321 cr_out
: _CROutSel
= _CROutSel
.NONE
322 extra
: ExtraMap
= ExtraMap()
324 mode
: _SVMode
= _SVMode
.NORMAL
328 "CONDITIONS": "conditions",
336 def CSV(cls
, record
):
337 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
343 for idx
in range(0, 4):
344 extra
.append(record
.pop(f
"{idx}"))
346 record
["extra"] = cls
.ExtraMap(extra
)
348 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
352 def __init__(self
, value
=(0, 32)):
353 if isinstance(value
, str):
354 (start
, end
) = map(int, value
.split(":"))
357 if start
< 0 or end
< 0 or start
>= end
:
358 raise ValueError(value
)
363 return super().__init
__()
366 return f
"[{self.__start}:{self.__end}]"
369 yield from range(self
.start
, (self
.end
+ 1))
380 @_dataclasses.dataclass(eq
=True, frozen
=True)
382 class Mode(_enum
.Enum
):
383 INTEGER
= _enum
.auto()
384 PATTERN
= _enum
.auto()
387 def _missing_(cls
, value
):
388 if isinstance(value
, str):
389 return cls
[value
.upper()]
390 return super()._missing
_(value
)
393 def __new__(cls
, value
=None):
394 if isinstance(value
, str):
395 if value
.upper() == "NONE":
398 value
= int(value
, 0)
402 return super().__new
__(cls
, value
)
408 return (bin(self
) if self
else "None")
417 def CSV(cls
, record
):
418 return dataclass(cls
, record
)
422 def __init__(self
, items
):
423 if isinstance(items
, dict):
424 items
= items
.items()
427 (name
, bitrange
) = item
428 return (name
, list(bitrange
.values()))
430 self
.__mapping
= dict(map(transform
, items
))
432 return super().__init
__()
435 return repr(self
.__mapping
)
438 yield from self
.__mapping
.items()
440 def __contains__(self
, key
):
441 return self
.__mapping
.__contains
__(key
)
443 def __getitem__(self
, key
):
444 return self
.__mapping
.get(key
, None)
447 @_dataclasses.dataclass(eq
=True, frozen
=True)
451 def disassemble(self
, value
, record
, verbose
=False):
452 raise NotImplementedError
455 @_dataclasses.dataclass(eq
=True, frozen
=True)
456 class DynamicOperand(Operand
):
457 def disassemble(self
, value
, record
, verbose
=False):
458 span
= record
.fields
[self
.name
]
461 yield f
"{int(value):0{value.bits}b}"
464 yield str(int(value
))
467 @_dataclasses.dataclass(eq
=True, frozen
=True)
468 class ImmediateOperand(DynamicOperand
):
472 @_dataclasses.dataclass(eq
=True, frozen
=True)
473 class StaticOperand(Operand
):
476 def disassemble(self
, value
, record
, verbose
=False):
477 span
= record
.fields
[self
.name
]
480 yield f
"{int(value):0{value.bits}b}"
483 yield str(int(value
))
486 @_dataclasses.dataclass(eq
=True, frozen
=True)
487 class DynamicOperandTargetAddrLI(DynamicOperand
):
496 def disassemble(self
, value
, record
, verbose
=False):
497 span
= record
.fields
["LI"]
500 yield f
"{int(value):0{value.bits}b}"
502 yield "target_addr = EXTS(LI || 0b00))"
504 yield hex(int(_selectconcat(value
,
505 _SelectableInt(value
=0b00, bits
=2))))
508 class DynamicOperandTargetAddrBD(DynamicOperand
):
517 def disassemble(self
, value
, record
, verbose
=False):
518 span
= record
.fields
["BD"]
521 yield f
"{int(value):0{value.bits}b}"
523 yield "target_addr = EXTS(BD || 0b00))"
525 yield hex(int(_selectconcat(value
,
526 _SelectableInt(value
=0b00, bits
=2))))
529 @_dataclasses.dataclass(eq
=True, frozen
=True)
530 class DynamicOperandGPR(DynamicOperand
):
531 def disassemble(self
, value
, record
, verbose
=False):
532 span
= record
.fields
[self
.name
]
535 yield f
"{int(value):0{value.bits}b}"
538 yield f
"r{str(int(value))}"
541 @_dataclasses.dataclass(eq
=True, frozen
=True)
542 class DynamicOperandFPR(DynamicOperand
):
543 def disassemble(self
, value
, record
, verbose
=False):
544 span
= record
.fields
[self
.name
]
547 yield f
"{int(value):0{value.bits}b}"
550 yield f
"f{str(int(value))}"
553 class Operands(tuple):
554 def __new__(cls
, insn
, iterable
):
556 "b": {"target_addr": DynamicOperandTargetAddrLI
},
557 "ba": {"target_addr": DynamicOperandTargetAddrLI
},
558 "bl": {"target_addr": DynamicOperandTargetAddrLI
},
559 "bla": {"target_addr": DynamicOperandTargetAddrLI
},
560 "bc": {"target_addr": DynamicOperandTargetAddrBD
},
561 "bca": {"target_addr": DynamicOperandTargetAddrBD
},
562 "bcl": {"target_addr": DynamicOperandTargetAddrBD
},
563 "bcla": {"target_addr": DynamicOperandTargetAddrBD
},
567 for operand
in iterable
:
568 dynamic_cls
= DynamicOperand
569 static_cls
= StaticOperand
572 (name
, value
) = operand
.split("=")
573 operand
= static_cls(name
=name
, value
=int(value
))
574 operands
.append(operand
)
576 if operand
.endswith(")"):
577 operand
= operand
.replace("(", " ").replace(")", "")
578 (immediate
, _
, operand
) = operand
.partition(" ")
582 if immediate
is not None:
583 operands
.append(ImmediateOperand(name
=immediate
))
585 if insn
in branches
and operand
in branches
[insn
]:
586 dynamic_cls
= branches
[insn
][operand
]
588 if operand
in _RegType
.__members
__:
589 regtype
= _RegType
[operand
]
590 if regtype
is _RegType
.GPR
:
591 dynamic_cls
= DynamicOperandGPR
592 elif regtype
is _RegType
.FPR
:
593 dynamic_cls
= DynamicOperandFPR
595 operand
= dynamic_cls(name
=operand
)
596 operands
.append(operand
)
598 return super().__new
__(cls
, operands
)
600 def __contains__(self
, key
):
601 return self
.__getitem
__(key
) is not None
603 def __getitem__(self
, key
):
605 if operand
.name
== key
:
613 if isinstance(operand
, DynamicOperand
):
619 if isinstance(operand
, StaticOperand
):
623 @_functools.total_ordering
624 @_dataclasses.dataclass(eq
=True, frozen
=True)
631 svp64
: SVP64Record
= None
640 def __lt__(self
, other
):
641 if not isinstance(other
, Record
):
642 return NotImplemented
643 return (self
.opcode
< other
.opcode
)
648 if self
.section
.opcode
:
649 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
650 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
652 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
654 for operand
in self
.operands
.static
:
655 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
657 return FieldsOpcode(fields
)
661 return self
.ppc
.function
681 if self
.svp64
is None:
687 return self
.ppc
.cr_in
691 return self
.ppc
.cr_out
693 def sv_extra(self
, key
):
694 if key
not in frozenset({
695 "in1", "in2", "in3", "cr_in",
696 "out", "out2", "cr_out",
700 sel
= getattr(self
.svp64
, key
)
701 if sel
is _CRInSel
.BA_BB
:
702 return _SVExtra
.Idx_1_2
703 reg
= _SVExtraReg(sel
)
704 if reg
is _SVExtraReg
.NONE
:
708 _SVExtraRegType
.SRC
: {},
709 _SVExtraRegType
.DST
: {},
711 for index
in range(0, 4):
712 for entry
in self
.svp64
.extra
[index
]:
713 extra_map
[entry
.regtype
][entry
.reg
] = Record
.__EXTRA
[index
]
715 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
716 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
717 if extra
is not _SVExtra
.NONE
:
722 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
723 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
724 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
725 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
726 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
727 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
728 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
732 if self
.svp64
is None:
734 return self
.svp64
.ptype
738 if self
.svp64
is None:
740 return self
.svp64
.etype
743 class Instruction(_Mapping
):
745 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
746 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
747 raise ValueError(bits
)
749 if isinstance(value
, bytes
):
750 if ((len(value
) * 8) != bits
):
751 raise ValueError(f
"bit length mismatch")
752 value
= int.from_bytes(value
, byteorder
=byteorder
)
754 if isinstance(value
, int):
755 value
= _SelectableInt(value
=value
, bits
=bits
)
756 elif isinstance(value
, Instruction
):
757 value
= value
.storage
759 if not isinstance(value
, _SelectableInt
):
760 raise ValueError(value
)
763 if len(value
) != bits
:
764 raise ValueError(value
)
766 value
= _SelectableInt(value
=value
, bits
=bits
)
768 return cls(storage
=value
)
771 return hash(int(self
))
773 def record(self
, db
):
779 def disassemble(self
, db
, byteorder
="little", verbose
=False):
780 raise NotImplementedError
783 class WordInstruction(Instruction
):
784 _
: _Field
= range(0, 32)
785 po
: _Field
= range(0, 6)
788 def integer(cls
, value
, byteorder
="little"):
789 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
794 for idx
in range(32):
797 return "".join(map(str, bits
))
800 record
= self
.record(db
=db
)
803 dynamic_operands
= []
804 for operand
in record
.operands
.dynamic
:
807 name
= f
"{immediate}({name})"
809 if isinstance(operand
, ImmediateOperand
):
810 immediate
= operand
.name
812 dynamic_operands
.append(name
)
815 for operand
in record
.operands
.static
:
816 static_operands
.append(f
"{operand.name}={operand.value}")
820 operands
+= f
" {','.join(dynamic_operands)}"
822 operands
+= f
" ({' '.join(static_operands)})"
824 return f
"{record.name}{operands}"
826 def opcode(self
, db
):
827 record
= self
.record(db
=db
)
828 return f
"0x{record.opcode.value:08x}"
831 record
= self
.record(db
=db
)
832 return f
"0x{record.opcode.mask:08x}"
834 def disassemble(self
, db
, byteorder
="little", verbose
=False):
836 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
837 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
839 record
= self
.record(db
=db
)
841 yield f
"{blob} .long 0x{integer:08x}"
845 for operand
in record
.operands
.dynamic
:
846 operand
= " ".join(operand
.disassemble(value
=self
,
847 record
=record
, verbose
=False))
848 operands
.append(operand
)
850 operands
= ",".join(operands
)
851 operands
= f
" {operands}"
855 yield f
"{blob} {record.name}{operands}"
860 spec
= self
.spec(db
=db
)
861 opcode
= self
.opcode(db
=db
)
862 mask
= self
.mask(db
=db
)
863 yield f
"{indent}spec"
864 yield f
"{indent}{indent}{spec}"
865 yield f
"{indent}binary"
866 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
867 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
868 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
869 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
870 yield f
"{indent}opcode"
871 yield f
"{indent}{indent}{opcode}"
872 yield f
"{indent}mask"
873 yield f
"{indent}{indent}{mask}"
874 for operand
in record
.operands
:
876 yield f
"{indent}{name}"
877 parts
= operand
.disassemble(value
=self
,
878 record
=record
, verbose
=True)
880 yield f
"{indent}{indent}{part}"
884 class PrefixedInstruction(Instruction
):
885 class Prefix(WordInstruction
.remap(range(0, 32))):
888 class Suffix(WordInstruction
.remap(range(32, 64))):
891 _
: _Field
= range(64)
897 def integer(cls
, value
, byteorder
="little"):
898 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
901 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
902 def transform(value
):
903 return WordInstruction
.integer(value
=value
,
904 byteorder
=byteorder
)[0:32]
906 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
907 value
= _selectconcat(prefix
, suffix
)
909 return super().integer(value
=value
)
912 class Mode(_Mapping
):
913 _
: _Field
= range(0, 5)
914 sel
: _Field
= range(0, 2)
917 class NormalMode(Mode
):
924 """scalar reduce mode (mapreduce), SUBVL=1"""
928 """parallel reduce mode (mapreduce), SUBVL=1"""
932 """subvector reduce mode, SUBVL>1"""
936 """Pack/Unpack mode, SUBVL>1"""
940 """Rc=1: ffirst CR sel"""
945 """Rc=0: ffirst z/nonz"""
951 """sat mode: N=0/1 u/s, SUBVL=1"""
957 """sat mode: N=0/1 u/s, SUBVL>1"""
964 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
971 """Rc=1: pred-result CR sel"""
976 """Rc=0: pred-result z/nonz"""
997 class LDSTImmMode(Mode
):
1006 """Structured Pack/Unpack"""
1013 """Rc=1: ffirst CR sel"""
1018 """Rc=0: ffirst z/nonz"""
1024 """sat mode: N=0/1 u/s"""
1032 """Rc=1: pred-result CR sel"""
1037 """Rc=0: pred-result z/nonz"""
1051 class LDSTIdxMode(Mode
):
1059 """strided (scalar only source)"""
1065 """sat mode: N=0/1 u/s"""
1071 """Rc=1: pred-result CR sel"""
1076 """Rc=0: pred-result z/nonz"""
1093 ldst_imm
: LDSTImmMode
1094 ldst_idx
: LDSTIdxMode
1096 _
: _Field
= range(24)
1097 mmode
: _Field
= (0,)
1098 mask
: _Field
= range(1, 4)
1099 elwidth
: _Field
= range(4, 6)
1100 ewsrc
: _Field
= range(6, 8)
1101 subvl
: _Field
= range(8, 10)
1102 extra
: _Field
= range(10, 19)
1103 mode
: Mode
.remap(range(19, 24))
1104 extra2
: _Array
[4] = (
1110 smask
: _Field
= range(16, 19)
1111 extra3
: _Array
[3] = (
1118 class SVP64Instruction(PrefixedInstruction
):
1119 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1120 class Prefix(PrefixedInstruction
.Prefix
):
1122 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1129 for idx
in range(64):
1130 bit
= int(self
[idx
])
1132 return "".join(map(str, bits
))
1135 return f
"sv.{self.suffix.spec(db=db)}"
1137 def opcode(self
, db
):
1138 return self
.suffix
.opcode(db
=db
)
1141 return self
.suffix
.mask(db
=db
)
1144 record
= self
.record(db
=db
)
1147 if record
.operands
["Rc"] is not None:
1148 Rc
= bool(self
[record
.fields
["Rc"]])
1150 record
= self
.record(db
=db
)
1151 subvl
= self
.prefix
.rm
.subvl
1152 mode
= self
.prefix
.rm
.mode
1155 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1189 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1190 mode
= mode
.ldst_imm
1208 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1209 mode
= mode
.ldst_idx
1210 if mode
.sel
== 0b00:
1212 elif mode
.sel
== 0b01:
1214 elif mode
.sel
== 0b10:
1216 elif mode
.sel
== 0b11:
1223 NormalMode
.simple
: "normal: simple",
1224 NormalMode
.smr
: "normal: smr",
1225 NormalMode
.pmr
: "normal: pmr",
1226 NormalMode
.svmr
: "normal: svmr",
1227 NormalMode
.pu
: "normal: pu",
1228 NormalMode
.ffrc1
: "normal: ffrc1",
1229 NormalMode
.ffrc0
: "normal: ffrc0",
1230 NormalMode
.sat
: "normal: sat",
1231 NormalMode
.satx
: "normal: satx",
1232 NormalMode
.satpu
: "normal: satpu",
1233 NormalMode
.prrc1
: "normal: prrc1",
1234 NormalMode
.prrc0
: "normal: prrc0",
1235 LDSTImmMode
.simple
: "ld/st imm: simple",
1236 LDSTImmMode
.spu
: "ld/st imm: spu",
1237 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1238 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1239 LDSTImmMode
.sat
: "ld/st imm: sat",
1240 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1241 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1242 LDSTIdxMode
.simple
: "ld/st idx simple",
1243 LDSTIdxMode
.stride
: "ld/st idx stride",
1244 LDSTIdxMode
.sat
: "ld/st idx sat",
1245 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1246 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1248 for (cls
, desc
) in modes
.items():
1249 if isinstance(mode
, cls
):
1252 raise NotImplementedError
1254 def disassemble(self
, db
, byteorder
="little", verbose
=False):
1255 integer_prefix
= int(self
.prefix
)
1256 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
1257 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
1259 integer_suffix
= int(self
.suffix
)
1260 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
1261 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
1263 record
= self
.record(db
=db
)
1264 if record
is None or record
.svp64
is None:
1265 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
1266 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
1269 yield f
"{blob_prefix} sv.{record.name}"
1270 yield f
"{blob_suffix}"
1272 (mode
, mode_desc
) = self
.mode(db
=db
)
1276 binary
= self
.binary
1277 spec
= self
.spec(db
=db
)
1278 opcode
= self
.opcode(db
=db
)
1279 mask
= self
.mask(db
=db
)
1280 yield f
"{indent}spec"
1281 yield f
"{indent}{indent}{spec}"
1282 yield f
"{indent}binary"
1283 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1284 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1285 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1286 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1287 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1288 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1289 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1290 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1291 yield f
"{indent}opcode"
1292 yield f
"{indent}{indent}{opcode}"
1293 yield f
"{indent}mask"
1294 yield f
"{indent}{indent}{mask}"
1295 for operand
in record
.operands
:
1297 yield f
"{indent}{name}"
1298 parts
= operand
.disassemble(value
=self
,
1299 record
=record
, verbose
=True)
1301 yield f
"{indent}{indent}{part}"
1303 yield f
"{indent}mode"
1304 yield f
"{indent}{indent}{mode_desc}"
1308 def parse(stream
, factory
):
1310 return ("TODO" not in frozenset(entry
.values()))
1312 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1313 entries
= _csv
.DictReader(lines
)
1314 entries
= filter(match
, entries
)
1315 return tuple(map(factory
, entries
))
1318 class MarkdownDatabase
:
1321 for (name
, desc
) in _ISA():
1324 (dynamic
, *static
) = desc
.regs
1325 operands
.extend(dynamic
)
1326 operands
.extend(static
)
1327 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1329 return super().__init
__()
1332 yield from self
.__db
.items()
1334 def __getitem__(self
, key
):
1335 return self
.__db
.__getitem
__(key
)
1338 class FieldsDatabase
:
1341 df
= _DecodeFields()
1343 for (form
, fields
) in df
.instrs
.items():
1344 if form
in {"DQE", "TX"}:
1348 db
[_Form
[form
]] = Fields(fields
)
1352 return super().__init
__()
1354 def __getitem__(self
, key
):
1355 return self
.__db
.__getitem
__(key
)
1359 def __init__(self
, root
, mdwndb
):
1360 # The code below groups the instructions by section:identifier.
1361 # We use the comment as an identifier, there's nothing better.
1362 # The point is to capture different opcodes for the same instruction.
1363 dd
= _collections
.defaultdict
1364 records
= dd(lambda: dd(set))
1365 path
= (root
/ "insndb.csv")
1366 with
open(path
, "r", encoding
="UTF-8") as stream
:
1367 for section
in parse(stream
, Section
.CSV
):
1368 path
= (root
/ section
.path
)
1370 section
.Mode
.INTEGER
: IntegerOpcode
,
1371 section
.Mode
.PATTERN
: PatternOpcode
,
1373 factory
= _functools
.partial(
1374 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1375 with
open(path
, "r", encoding
="UTF-8") as stream
:
1376 for insn
in parse(stream
, factory
):
1377 records
[section
][insn
.comment
].add(insn
)
1380 for (section
, group
) in records
.items():
1381 for records
in group
.values():
1382 db
[section
].add(PPCMultiRecord(records
))
1385 self
.__mdwndb
= mdwndb
1387 return super().__init
__()
1389 def __getitem__(self
, key
):
1390 def exact_match(key
, record
):
1391 for name
in record
.names
:
1397 def Rc_match(key
, record
):
1398 if not key
.endswith("."):
1401 if not record
.Rc
is _RCOE
.RC
:
1404 return exact_match(key
[:-1], record
)
1406 def LK_match(key
, record
):
1407 if not key
.endswith("l"):
1410 if "lk" not in record
.flags
:
1413 return exact_match(key
[:-1], record
)
1415 def AA_match(key
, record
):
1416 if not key
.endswith("a"):
1419 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1422 if self
.__mdwndb
[key
]["AA"] is None:
1425 return (exact_match(key
[:-1], record
) or
1426 LK_match(key
[:-1], record
))
1428 for (section
, records
) in self
.__db
.items():
1429 for record
in records
:
1430 if exact_match(key
, record
):
1431 return (section
, record
)
1433 for record
in records
:
1434 if (Rc_match(key
, record
) or
1435 LK_match(key
, record
) or
1436 AA_match(key
, record
)):
1437 return (section
, record
)
1442 class SVP64Database
:
1443 def __init__(self
, root
, ppcdb
):
1445 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1446 for (prefix
, _
, names
) in _os
.walk(root
):
1447 prefix
= _pathlib
.Path(prefix
)
1448 for name
in filter(lambda name
: pattern
.match(name
), names
):
1449 path
= (prefix
/ _pathlib
.Path(name
))
1450 with
open(path
, "r", encoding
="UTF-8") as stream
:
1451 db
.update(parse(stream
, SVP64Record
.CSV
))
1453 self
.__db
= {record
.name
:record
for record
in db
}
1454 self
.__ppcdb
= ppcdb
1456 return super().__init
__()
1458 def __getitem__(self
, key
):
1459 (_
, record
) = self
.__ppcdb
[key
]
1463 for name
in record
.names
:
1464 record
= self
.__db
.get(name
, None)
1465 if record
is not None:
1472 def __init__(self
, root
):
1473 root
= _pathlib
.Path(root
)
1475 mdwndb
= MarkdownDatabase()
1476 fieldsdb
= FieldsDatabase()
1477 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1478 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1481 for (name
, operands
) in mdwndb
:
1482 (section
, ppc
) = ppcdb
[name
]
1485 svp64
= svp64db
[name
]
1486 fields
= fieldsdb
[ppc
.form
]
1487 record
= Record(name
=name
,
1488 section
=section
, ppc
=ppc
, svp64
=svp64
,
1489 operands
=operands
, fields
=fields
)
1492 self
.__db
= tuple(sorted(db
))
1494 return super().__init
__()
1497 return repr(self
.__db
)
1500 yield from self
.__db
1502 @_functools.lru_cache(maxsize
=None)
1503 def __contains__(self
, key
):
1504 return self
.__getitem
__(key
) is not None
1506 @_functools.lru_cache(maxsize
=None)
1507 def __getitem__(self
, key
):
1508 if isinstance(key
, (int, Instruction
)):
1511 opcode
= record
.opcode
1512 if ((opcode
.value
& opcode
.mask
) ==
1513 (key
& opcode
.mask
)):
1516 elif isinstance(key
, Opcode
):
1518 if record
.opcode
== key
:
1520 elif isinstance(key
, str):
1522 if record
.name
== key
: