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
, keymap
=PPCRecord
.__KEYMAP
, typemap
=typemap
)
234 return frozenset(self
.comment
.split("=")[-1].split("/"))
237 class PPCMultiRecord(tuple):
243 lvalue
= lhs
.opcode
.value
244 rvalue
= rhs
.opcode
.value
245 lmask
= lhs
.opcode
.mask
246 rmask
= rhs
.opcode
.mask
247 bits
= max(lmask
.bit_length(), rmask
.bit_length())
248 for bit
in range(bits
):
249 lvstate
= ((lvalue
& (1 << bit
)) != 0)
250 rvstate
= ((rvalue
& (1 << bit
)) != 0)
251 lmstate
= ((lmask
& (1 << bit
)) != 0)
252 rmstate
= ((rmask
& (1 << bit
)) != 0)
255 if (not lmstate
or not rmstate
) or (lvstate
!= rvstate
):
258 value |
= (vstate
<< bit
)
259 mask |
= (mstate
<< bit
)
261 return _dataclasses
.replace(lhs
, opcode
=Opcode(value
=value
, mask
=mask
))
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"):
338 record
["extra"] = cls
.ExtraMap(record
.pop(f
"{index}") for index
in range(0, 4))
340 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
344 def __init__(self
, value
=(0, 32)):
345 if isinstance(value
, str):
346 (start
, end
) = map(int, value
.split(":"))
349 if start
< 0 or end
< 0 or start
>= end
:
350 raise ValueError(value
)
355 return super().__init
__()
358 return f
"[{self.__start}:{self.__end}]"
361 yield from range(self
.start
, (self
.end
+ 1))
372 @_dataclasses.dataclass(eq
=True, frozen
=True)
374 class Mode(_enum
.Enum
):
375 INTEGER
= _enum
.auto()
376 PATTERN
= _enum
.auto()
379 def _missing_(cls
, value
):
380 if isinstance(value
, str):
381 return cls
[value
.upper()]
382 return super()._missing
_(value
)
385 def __new__(cls
, value
=None):
386 if isinstance(value
, str):
387 if value
.upper() == "NONE":
390 value
= int(value
, 0)
394 return super().__new
__(cls
, value
)
400 return (bin(self
) if self
else "None")
409 def CSV(cls
, record
):
410 return dataclass(cls
, record
)
414 def __init__(self
, items
):
415 if isinstance(items
, dict):
416 items
= items
.items()
419 (name
, bitrange
) = item
420 return (name
, list(bitrange
.values()))
422 self
.__mapping
= dict(map(transform
, items
))
424 return super().__init
__()
427 return repr(self
.__mapping
)
430 yield from self
.__mapping
.items()
432 def __contains__(self
, key
):
433 return self
.__mapping
.__contains
__(key
)
435 def __getitem__(self
, key
):
436 return self
.__mapping
.get(key
, None)
439 @_dataclasses.dataclass(eq
=True, frozen
=True)
443 def disassemble(self
, value
, record
, verbose
=False):
444 raise NotImplementedError
447 @_dataclasses.dataclass(eq
=True, frozen
=True)
448 class DynamicOperand(Operand
):
449 def disassemble(self
, value
, record
, verbose
=False):
450 span
= record
.fields
[self
.name
]
453 yield f
"{int(value):0{value.bits}b}"
456 yield str(int(value
))
459 @_dataclasses.dataclass(eq
=True, frozen
=True)
460 class StaticOperand(Operand
):
463 def disassemble(self
, value
, record
, verbose
=False):
464 span
= record
.fields
[self
.name
]
467 yield f
"{int(value):0{value.bits}b}"
470 yield str(int(value
))
473 @_dataclasses.dataclass(eq
=True, frozen
=True)
474 class DynamicOperandTargetAddrLI(DynamicOperand
):
483 def disassemble(self
, value
, record
, verbose
=False):
484 span
= record
.fields
["LI"]
487 yield f
"{int(value):0{value.bits}b}"
489 yield "target_addr = EXTS(LI || 0b00))"
491 yield hex(int(_selectconcat(value
,
492 _SelectableInt(value
=0b00, bits
=2))))
495 class DynamicOperandTargetAddrBD(DynamicOperand
):
504 def disassemble(self
, value
, record
, verbose
=False):
505 span
= record
.fields
["BD"]
508 yield f
"{int(value):0{value.bits}b}"
510 yield "target_addr = EXTS(BD || 0b00))"
512 yield hex(int(_selectconcat(value
,
513 _SelectableInt(value
=0b00, bits
=2))))
516 @_dataclasses.dataclass(eq
=True, frozen
=True)
517 class DynamicOperandGPR(DynamicOperand
):
518 def disassemble(self
, value
, record
, verbose
=False):
519 span
= record
.fields
[self
.name
]
522 yield f
"{int(value):0{value.bits}b}"
525 yield f
"r{str(int(value))}"
528 @_dataclasses.dataclass(eq
=True, frozen
=True)
529 class DynamicOperandFPR(DynamicOperand
):
530 def disassemble(self
, value
, record
, verbose
=False):
531 span
= record
.fields
[self
.name
]
534 yield f
"{int(value):0{value.bits}b}"
537 yield f
"f{str(int(value))}"
540 class Operands(tuple):
541 def __new__(cls
, insn
, iterable
):
543 "b": {"target_addr": DynamicOperandTargetAddrLI
},
544 "ba": {"target_addr": DynamicOperandTargetAddrLI
},
545 "bl": {"target_addr": DynamicOperandTargetAddrLI
},
546 "bla": {"target_addr": DynamicOperandTargetAddrLI
},
547 "bc": {"target_addr": DynamicOperandTargetAddrBD
},
548 "bca": {"target_addr": DynamicOperandTargetAddrBD
},
549 "bcl": {"target_addr": DynamicOperandTargetAddrBD
},
550 "bcla": {"target_addr": DynamicOperandTargetAddrBD
},
554 for operand
in iterable
:
555 dynamic_cls
= DynamicOperand
556 static_cls
= StaticOperand
559 (name
, value
) = operand
.split("=")
560 operand
= static_cls(name
=name
, value
=int(value
))
561 operands
.append(operand
)
563 if operand
.endswith(")"):
564 operand
= operand
.replace("(", " ").replace(")", "")
565 all_operands
= operand
.split(" ")
567 all_operands
= [operand
]
569 for operand
in all_operands
:
570 if insn
in branches
and operand
in branches
[insn
]:
571 dynamic_cls
= branches
[insn
][operand
]
573 if operand
in _RegType
.__members
__:
574 regtype
= _RegType
[operand
]
575 if regtype
is _RegType
.GPR
:
576 dynamic_cls
= DynamicOperandGPR
577 elif regtype
is _RegType
.FPR
:
578 dynamic_cls
= DynamicOperandFPR
580 operand
= dynamic_cls(name
=operand
)
581 operands
.append(operand
)
583 return super().__new
__(cls
, operands
)
585 def __contains__(self
, key
):
586 return self
.__getitem
__(key
) is not None
588 def __getitem__(self
, key
):
590 if operand
.name
== key
:
598 if isinstance(operand
, DynamicOperand
):
604 if isinstance(operand
, StaticOperand
):
608 @_functools.total_ordering
609 @_dataclasses.dataclass(eq
=True, frozen
=True)
616 svp64
: SVP64Record
= None
625 def __lt__(self
, other
):
626 if not isinstance(other
, Record
):
627 return NotImplemented
628 return (self
.opcode
< other
.opcode
)
633 if self
.section
.opcode
:
634 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
635 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
637 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
639 for operand
in self
.operands
.static
:
640 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
642 return FieldsOpcode(fields
)
646 return self
.ppc
.function
666 if self
.svp64
is None:
672 return self
.ppc
.cr_in
676 return self
.ppc
.cr_out
678 def sv_extra(self
, key
):
679 if key
not in frozenset({
680 "in1", "in2", "in3", "cr_in",
681 "out", "out2", "cr_out",
685 sel
= getattr(self
.svp64
, key
)
686 if sel
is _CRInSel
.BA_BB
:
687 return _SVExtra
.Idx_1_2
688 reg
= _SVExtraReg(sel
)
689 if reg
is _SVExtraReg
.NONE
:
693 _SVExtraRegType
.SRC
: {},
694 _SVExtraRegType
.DST
: {},
696 for index
in range(0, 4):
697 for entry
in self
.svp64
.extra
[index
]:
698 extra_map
[entry
.regtype
][entry
.reg
] = Record
.__EXTRA
[index
]
700 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
701 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
702 if extra
is not _SVExtra
.NONE
:
707 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
708 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
709 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
710 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
711 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
712 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
713 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
717 if self
.svp64
is None:
719 return self
.svp64
.ptype
723 if self
.svp64
is None:
725 return self
.svp64
.etype
728 class Instruction(_Mapping
):
730 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
731 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
732 raise ValueError(bits
)
734 if isinstance(value
, bytes
):
735 if ((len(value
) * 8) != bits
):
736 raise ValueError(f
"bit length mismatch")
737 value
= int.from_bytes(value
, byteorder
=byteorder
)
739 if isinstance(value
, int):
740 value
= _SelectableInt(value
=value
, bits
=bits
)
741 elif isinstance(value
, Instruction
):
742 value
= value
.storage
744 if not isinstance(value
, _SelectableInt
):
745 raise ValueError(value
)
748 if len(value
) != bits
:
749 raise ValueError(value
)
751 value
= _SelectableInt(value
=value
, bits
=bits
)
753 return cls(storage
=value
)
756 return hash(int(self
))
758 def disassemble(self
, db
, byteorder
="little", verbose
=False):
759 raise NotImplementedError
762 class WordInstruction(Instruction
):
763 _
: _Field
= range(0, 32)
764 po
: _Field
= range(0, 6)
767 def integer(cls
, value
, byteorder
="little"):
768 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
773 for idx
in range(32):
776 return "".join(map(str, bits
))
778 def spec(self
, record
):
779 dynamic_operands
= []
780 for operand
in record
.operands
.dynamic
:
781 dynamic_operands
.append(operand
.name
)
783 for operand
in record
.operands
.static
:
784 static_operands
.append(f
"{operand.name}={operand.value}")
787 operands
+= f
" {','.join(dynamic_operands)}"
789 operands
+= f
" ({' '.join(static_operands)})"
790 return f
"{record.name}{operands}"
792 def opcode(self
, record
):
793 return f
"0x{record.opcode.value:08x}"
795 def mask(self
, record
):
796 return f
"0x{record.opcode.mask:08x}"
798 def disassemble(self
, db
, byteorder
="little", verbose
=False):
800 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
801 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
805 yield f
"{blob} .long 0x{integer:08x}"
809 for operand
in record
.operands
.dynamic
:
810 operand
= " ".join(operand
.disassemble(value
=self
,
811 record
=record
, verbose
=False))
812 operands
.append(operand
)
814 operands
= ",".join(operands
)
815 operands
= f
" {operands}"
819 yield f
"{blob} {record.name}{operands}"
824 spec
= self
.spec(record
=record
)
825 opcode
= self
.opcode(record
=record
)
826 mask
= self
.mask(record
=record
)
827 yield f
"{indent}spec"
828 yield f
"{indent}{indent}{spec}"
829 yield f
"{indent}binary"
830 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
831 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
832 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
833 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
834 yield f
"{indent}opcode"
835 yield f
"{indent}{indent}{opcode}"
836 yield f
"{indent}mask"
837 yield f
"{indent}{indent}{mask}"
838 for operand
in record
.operands
:
840 yield f
"{indent}{name}"
841 parts
= operand
.disassemble(value
=self
,
842 record
=record
, verbose
=True)
844 yield f
"{indent}{indent}{part}"
848 class PrefixedInstruction(Instruction
):
849 class Prefix(WordInstruction
.remap(range(0, 32))):
852 class Suffix(WordInstruction
.remap(range(32, 64))):
855 _
: _Field
= range(64)
861 def integer(cls
, value
, byteorder
="little"):
862 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
865 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
866 def transform(value
):
867 return WordInstruction
.integer(value
=value
,
868 byteorder
=byteorder
)[0:32]
870 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
871 value
= _selectconcat(prefix
, suffix
)
873 return super().integer(value
=value
)
876 class Mode(_Mapping
):
877 _
: _Field
= range(0, 5)
878 sel
: _Field
= range(0, 2)
881 class NormalMode(Mode
):
888 """scalar reduce mode (mapreduce), SUBVL=1"""
892 """parallel reduce mode (mapreduce), SUBVL=1"""
896 """subvector reduce mode, SUBVL>1"""
900 """Pack/Unpack mode, SUBVL>1"""
904 """Rc=1: ffirst CR sel"""
909 """Rc=0: ffirst z/nonz"""
915 """sat mode: N=0/1 u/s, SUBVL=1"""
921 """sat mode: N=0/1 u/s, SUBVL>1"""
928 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
935 """Rc=1: pred-result CR sel"""
940 """Rc=0: pred-result z/nonz"""
961 class LDSTImmMode(Mode
):
970 """Structured Pack/Unpack"""
977 """Rc=1: ffirst CR sel"""
982 """Rc=0: ffirst z/nonz"""
988 """sat mode: N=0/1 u/s"""
996 """Rc=1: pred-result CR sel"""
1001 """Rc=0: pred-result z/nonz"""
1015 class LDSTIdxMode(Mode
):
1023 """strided (scalar only source)"""
1029 """sat mode: N=0/1 u/s"""
1035 """Rc=1: pred-result CR sel"""
1040 """Rc=0: pred-result z/nonz"""
1057 ldst_imm
: LDSTImmMode
1058 ldst_idx
: LDSTIdxMode
1060 _
: _Field
= range(24)
1061 mmode
: _Field
= (0,)
1062 mask
: _Field
= range(1, 4)
1063 elwidth
: _Field
= range(4, 6)
1064 ewsrc
: _Field
= range(6, 8)
1065 subvl
: _Field
= range(8, 10)
1066 extra
: _Field
= range(10, 19)
1067 mode
: Mode
.remap(range(19, 24))
1068 extra2
: _Array
[4] = (
1074 smask
: _Field
= range(16, 19)
1075 extra3
: _Array
[3] = (
1082 class SVP64Instruction(PrefixedInstruction
):
1083 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1084 class Prefix(PrefixedInstruction
.Prefix
):
1086 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1093 for idx
in range(64):
1094 bit
= int(self
[idx
])
1096 return "".join(map(str, bits
))
1098 def spec(self
, record
):
1099 return f
"sv.{self.suffix.spec(record=record)}"
1101 def opcode(self
, record
):
1102 return self
.suffix
.opcode(record
=record
)
1104 def mask(self
, record
):
1105 return self
.suffix
.mask(record
=record
)
1107 def disassemble(self
, db
, byteorder
="little", verbose
=False):
1108 integer_prefix
= int(self
.prefix
)
1109 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
1110 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
1112 integer_suffix
= int(self
.suffix
)
1113 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
1114 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
1116 record
= db
[self
.suffix
]
1117 if record
is None or record
.svp64
is None:
1118 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
1119 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
1123 if record
.operands
["Rc"] is not None:
1124 Rc
= bool(self
[record
.fields
["Rc"]])
1126 subvl
= self
.prefix
.rm
.subvl
1127 mode
= self
.prefix
.rm
.mode
1130 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1164 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1165 mode
= mode
.ldst_imm
1183 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1184 mode
= mode
.ldst_idx
1185 if mode
.sel
== 0b00:
1187 elif mode
.sel
== 0b01:
1189 elif mode
.sel
== 0b10:
1191 elif mode
.sel
== 0b11:
1197 if type(mode
) is Mode
:
1198 raise NotImplementedError
1200 yield f
"{blob_prefix} sv.{record.name}"
1201 yield f
"{blob_suffix}"
1205 binary
= self
.binary
1206 spec
= self
.spec(record
=record
)
1207 opcode
= self
.opcode(record
=record
)
1208 mask
= self
.mask(record
=record
)
1209 yield f
"{indent}spec"
1210 yield f
"{indent}{indent}{spec}"
1211 yield f
"{indent}binary"
1212 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1213 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1214 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1215 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1216 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1217 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1218 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1219 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1220 yield f
"{indent}opcode"
1221 yield f
"{indent}{indent}{opcode}"
1222 yield f
"{indent}mask"
1223 yield f
"{indent}{indent}{mask}"
1224 for operand
in record
.operands
:
1226 yield f
"{indent}{name}"
1227 parts
= operand
.disassemble(value
=self
,
1228 record
=record
, verbose
=True)
1230 yield f
"{indent}{indent}{part}"
1234 def parse(stream
, factory
):
1235 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1236 entries
= _csv
.DictReader(lines
)
1237 entries
= filter(lambda entry
: "TODO" not in frozenset(entry
.values()), entries
)
1238 return tuple(map(factory
, entries
))
1241 class MarkdownDatabase
:
1244 for (name
, desc
) in _ISA():
1247 (dynamic
, *static
) = desc
.regs
1248 operands
.extend(dynamic
)
1249 operands
.extend(static
)
1250 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1252 return super().__init
__()
1255 yield from self
.__db
.items()
1257 def __getitem__(self
, key
):
1258 return self
.__db
.__getitem
__(key
)
1261 class FieldsDatabase
:
1264 df
= _DecodeFields()
1266 for (form
, fields
) in df
.instrs
.items():
1267 if form
in {"DQE", "TX"}:
1271 db
[_Form
[form
]] = Fields(fields
)
1275 return super().__init
__()
1277 def __getitem__(self
, key
):
1278 return self
.__db
.__getitem
__(key
)
1282 def __init__(self
, root
, mdwndb
, fieldsdb
):
1283 # The code below groups the instructions by section:identifier.
1284 # We use the comment as an identifier, there's nothing better.
1285 # The point is to capture different opcodes for the same instruction.
1286 dd
= _collections
.defaultdict
1287 records
= dd(lambda: dd(set))
1288 path
= (root
/ "insndb.csv")
1289 with
open(path
, "r", encoding
="UTF-8") as stream
:
1290 for section
in parse(stream
, Section
.CSV
):
1291 path
= (root
/ section
.path
)
1293 section
.Mode
.INTEGER
: IntegerOpcode
,
1294 section
.Mode
.PATTERN
: PatternOpcode
,
1296 factory
= _functools
.partial(PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1297 with
open(path
, "r", encoding
="UTF-8") as stream
:
1298 for insn
in parse(stream
, factory
):
1299 records
[section
][insn
.comment
].add(insn
)
1302 for (section
, group
) in records
.items():
1303 for records
in group
.values():
1304 db
[section
].add(PPCMultiRecord(records
))
1307 self
.__mdwndb
= mdwndb
1308 self
.__fieldsdb
= fieldsdb
1310 return super().__init
__()
1312 def __getitem__(self
, key
):
1313 def exact_match(key
, record
):
1314 for name
in record
.names
:
1320 def Rc_match(key
, record
):
1321 if not key
.endswith("."):
1324 if not record
.Rc
is _RCOE
.RC
:
1327 return exact_match(key
[:-1], record
)
1329 def LK_match(key
, record
):
1330 if not key
.endswith("l"):
1333 if "lk" not in record
.flags
:
1336 return exact_match(key
[:-1], record
)
1338 def AA_match(key
, record
):
1339 if not key
.endswith("a"):
1342 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1345 if self
.__mdwndb
[key
]["AA"] is None:
1348 return (exact_match(key
[:-1], record
) or
1349 LK_match(key
[:-1], record
))
1351 for (section
, records
) in self
.__db
.items():
1352 for record
in records
:
1353 if (exact_match(key
, record
) or
1354 Rc_match(key
, record
) or
1355 LK_match(key
, record
) or
1356 AA_match(key
, record
)):
1357 return (section
, record
)
1362 class SVP64Database
:
1363 def __init__(self
, root
, ppcdb
):
1365 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1366 for (prefix
, _
, names
) in _os
.walk(root
):
1367 prefix
= _pathlib
.Path(prefix
)
1368 for name
in filter(lambda name
: pattern
.match(name
), names
):
1369 path
= (prefix
/ _pathlib
.Path(name
))
1370 with
open(path
, "r", encoding
="UTF-8") as stream
:
1371 db
.update(parse(stream
, SVP64Record
.CSV
))
1373 self
.__db
= {record
.name
:record
for record
in db
}
1374 self
.__ppcdb
= ppcdb
1376 return super().__init
__()
1378 def __getitem__(self
, key
):
1379 (_
, record
) = self
.__ppcdb
[key
]
1383 for name
in record
.names
:
1384 record
= self
.__db
.get(name
, None)
1385 if record
is not None:
1392 def __init__(self
, root
):
1393 root
= _pathlib
.Path(root
)
1395 mdwndb
= MarkdownDatabase()
1396 fieldsdb
= FieldsDatabase()
1397 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
, fieldsdb
=fieldsdb
)
1398 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1401 for (name
, operands
) in mdwndb
:
1402 (section
, ppc
) = ppcdb
[name
]
1405 svp64
= svp64db
[name
]
1406 fields
= fieldsdb
[ppc
.form
]
1407 record
= Record(name
=name
,
1408 section
=section
, ppc
=ppc
, svp64
=svp64
,
1409 operands
=operands
, fields
=fields
)
1412 self
.__db
= tuple(sorted(db
))
1414 return super().__init
__()
1417 return repr(self
.__db
)
1420 yield from self
.__db
1422 @_functools.lru_cache(maxsize
=None)
1423 def __contains__(self
, key
):
1424 return self
.__getitem
__(key
) is not None
1426 @_functools.lru_cache(maxsize
=None)
1427 def __getitem__(self
, key
):
1428 if isinstance(key
, (int, Instruction
)):
1431 opcode
= record
.opcode
1432 if ((opcode
.value
& opcode
.mask
) ==
1433 (key
& opcode
.mask
)):
1436 elif isinstance(key
, Opcode
):
1438 if record
.opcode
== key
:
1440 elif isinstance(key
, str):
1442 if record
.name
== key
: