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(tuple):
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 disassemble(self
, db
, byteorder
="little", verbose
=False):
774 raise NotImplementedError
777 class WordInstruction(Instruction
):
778 _
: _Field
= range(0, 32)
779 po
: _Field
= range(0, 6)
782 def integer(cls
, value
, byteorder
="little"):
783 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
788 for idx
in range(32):
791 return "".join(map(str, bits
))
793 def spec(self
, record
):
795 dynamic_operands
= []
796 for operand
in record
.operands
.dynamic
:
799 name
= f
"{immediate}({name})"
801 if isinstance(operand
, ImmediateOperand
):
802 immediate
= operand
.name
804 dynamic_operands
.append(name
)
807 for operand
in record
.operands
.static
:
808 static_operands
.append(f
"{operand.name}={operand.value}")
812 operands
+= f
" {','.join(dynamic_operands)}"
814 operands
+= f
" ({' '.join(static_operands)})"
816 return f
"{record.name}{operands}"
818 def opcode(self
, record
):
819 return f
"0x{record.opcode.value:08x}"
821 def mask(self
, record
):
822 return f
"0x{record.opcode.mask:08x}"
824 def disassemble(self
, db
, byteorder
="little", verbose
=False):
826 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
827 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
831 yield f
"{blob} .long 0x{integer:08x}"
835 for operand
in record
.operands
.dynamic
:
836 operand
= " ".join(operand
.disassemble(value
=self
,
837 record
=record
, verbose
=False))
838 operands
.append(operand
)
840 operands
= ",".join(operands
)
841 operands
= f
" {operands}"
845 yield f
"{blob} {record.name}{operands}"
850 spec
= self
.spec(record
=record
)
851 opcode
= self
.opcode(record
=record
)
852 mask
= self
.mask(record
=record
)
853 yield f
"{indent}spec"
854 yield f
"{indent}{indent}{spec}"
855 yield f
"{indent}binary"
856 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
857 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
858 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
859 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
860 yield f
"{indent}opcode"
861 yield f
"{indent}{indent}{opcode}"
862 yield f
"{indent}mask"
863 yield f
"{indent}{indent}{mask}"
864 for operand
in record
.operands
:
866 yield f
"{indent}{name}"
867 parts
= operand
.disassemble(value
=self
,
868 record
=record
, verbose
=True)
870 yield f
"{indent}{indent}{part}"
874 class PrefixedInstruction(Instruction
):
875 class Prefix(WordInstruction
.remap(range(0, 32))):
878 class Suffix(WordInstruction
.remap(range(32, 64))):
881 _
: _Field
= range(64)
887 def integer(cls
, value
, byteorder
="little"):
888 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
891 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
892 def transform(value
):
893 return WordInstruction
.integer(value
=value
,
894 byteorder
=byteorder
)[0:32]
896 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
897 value
= _selectconcat(prefix
, suffix
)
899 return super().integer(value
=value
)
902 class Mode(_Mapping
):
903 _
: _Field
= range(0, 5)
904 sel
: _Field
= range(0, 2)
907 class NormalMode(Mode
):
914 """scalar reduce mode (mapreduce), SUBVL=1"""
918 """parallel reduce mode (mapreduce), SUBVL=1"""
922 """subvector reduce mode, SUBVL>1"""
926 """Pack/Unpack mode, SUBVL>1"""
930 """Rc=1: ffirst CR sel"""
935 """Rc=0: ffirst z/nonz"""
941 """sat mode: N=0/1 u/s, SUBVL=1"""
947 """sat mode: N=0/1 u/s, SUBVL>1"""
954 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
961 """Rc=1: pred-result CR sel"""
966 """Rc=0: pred-result z/nonz"""
987 class LDSTImmMode(Mode
):
996 """Structured Pack/Unpack"""
1003 """Rc=1: ffirst CR sel"""
1008 """Rc=0: ffirst z/nonz"""
1014 """sat mode: N=0/1 u/s"""
1022 """Rc=1: pred-result CR sel"""
1027 """Rc=0: pred-result z/nonz"""
1041 class LDSTIdxMode(Mode
):
1049 """strided (scalar only source)"""
1055 """sat mode: N=0/1 u/s"""
1061 """Rc=1: pred-result CR sel"""
1066 """Rc=0: pred-result z/nonz"""
1083 ldst_imm
: LDSTImmMode
1084 ldst_idx
: LDSTIdxMode
1086 _
: _Field
= range(24)
1087 mmode
: _Field
= (0,)
1088 mask
: _Field
= range(1, 4)
1089 elwidth
: _Field
= range(4, 6)
1090 ewsrc
: _Field
= range(6, 8)
1091 subvl
: _Field
= range(8, 10)
1092 extra
: _Field
= range(10, 19)
1093 mode
: Mode
.remap(range(19, 24))
1094 extra2
: _Array
[4] = (
1100 smask
: _Field
= range(16, 19)
1101 extra3
: _Array
[3] = (
1108 class SVP64Instruction(PrefixedInstruction
):
1109 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1110 class Prefix(PrefixedInstruction
.Prefix
):
1112 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1119 for idx
in range(64):
1120 bit
= int(self
[idx
])
1122 return "".join(map(str, bits
))
1124 def spec(self
, record
):
1125 return f
"sv.{self.suffix.spec(record=record)}"
1127 def opcode(self
, record
):
1128 return self
.suffix
.opcode(record
=record
)
1130 def mask(self
, record
):
1131 return self
.suffix
.mask(record
=record
)
1133 def disassemble(self
, db
, byteorder
="little", verbose
=False):
1134 integer_prefix
= int(self
.prefix
)
1135 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
1136 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
1138 integer_suffix
= int(self
.suffix
)
1139 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
1140 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
1142 record
= db
[self
.suffix
]
1143 if record
is None or record
.svp64
is None:
1144 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
1145 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
1149 if record
.operands
["Rc"] is not None:
1150 Rc
= bool(self
[record
.fields
["Rc"]])
1152 subvl
= self
.prefix
.rm
.subvl
1153 mode
= self
.prefix
.rm
.mode
1156 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1190 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1191 mode
= mode
.ldst_imm
1209 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1210 mode
= mode
.ldst_idx
1211 if mode
.sel
== 0b00:
1213 elif mode
.sel
== 0b01:
1215 elif mode
.sel
== 0b10:
1217 elif mode
.sel
== 0b11:
1223 if type(mode
) is Mode
:
1224 raise NotImplementedError
1226 yield f
"{blob_prefix} sv.{record.name}"
1227 yield f
"{blob_suffix}"
1231 binary
= self
.binary
1232 spec
= self
.spec(record
=record
)
1233 opcode
= self
.opcode(record
=record
)
1234 mask
= self
.mask(record
=record
)
1235 yield f
"{indent}spec"
1236 yield f
"{indent}{indent}{spec}"
1237 yield f
"{indent}binary"
1238 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1239 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1240 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1241 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1242 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1243 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1244 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1245 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1246 yield f
"{indent}opcode"
1247 yield f
"{indent}{indent}{opcode}"
1248 yield f
"{indent}mask"
1249 yield f
"{indent}{indent}{mask}"
1250 for operand
in record
.operands
:
1252 yield f
"{indent}{name}"
1253 parts
= operand
.disassemble(value
=self
,
1254 record
=record
, verbose
=True)
1256 yield f
"{indent}{indent}{part}"
1260 def parse(stream
, factory
):
1262 return ("TODO" not in frozenset(entry
.values()))
1264 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1265 entries
= _csv
.DictReader(lines
)
1266 entries
= filter(match
, entries
)
1267 return tuple(map(factory
, entries
))
1270 class MarkdownDatabase
:
1273 for (name
, desc
) in _ISA():
1276 (dynamic
, *static
) = desc
.regs
1277 operands
.extend(dynamic
)
1278 operands
.extend(static
)
1279 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1281 return super().__init
__()
1284 yield from self
.__db
.items()
1286 def __getitem__(self
, key
):
1287 return self
.__db
.__getitem
__(key
)
1290 class FieldsDatabase
:
1293 df
= _DecodeFields()
1295 for (form
, fields
) in df
.instrs
.items():
1296 if form
in {"DQE", "TX"}:
1300 db
[_Form
[form
]] = Fields(fields
)
1304 return super().__init
__()
1306 def __getitem__(self
, key
):
1307 return self
.__db
.__getitem
__(key
)
1311 def __init__(self
, root
, mdwndb
, fieldsdb
):
1312 # The code below groups the instructions by section:identifier.
1313 # We use the comment as an identifier, there's nothing better.
1314 # The point is to capture different opcodes for the same instruction.
1315 dd
= _collections
.defaultdict
1316 records
= dd(lambda: dd(set))
1317 path
= (root
/ "insndb.csv")
1318 with
open(path
, "r", encoding
="UTF-8") as stream
:
1319 for section
in parse(stream
, Section
.CSV
):
1320 path
= (root
/ section
.path
)
1322 section
.Mode
.INTEGER
: IntegerOpcode
,
1323 section
.Mode
.PATTERN
: PatternOpcode
,
1325 factory
= _functools
.partial(
1326 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1327 with
open(path
, "r", encoding
="UTF-8") as stream
:
1328 for insn
in parse(stream
, factory
):
1329 records
[section
][insn
.comment
].add(insn
)
1332 for (section
, group
) in records
.items():
1333 for records
in group
.values():
1334 db
[section
].add(PPCMultiRecord(records
))
1337 self
.__mdwndb
= mdwndb
1338 self
.__fieldsdb
= fieldsdb
1340 return super().__init
__()
1342 def __getitem__(self
, key
):
1343 def exact_match(key
, record
):
1344 for name
in record
.names
:
1350 def Rc_match(key
, record
):
1351 if not key
.endswith("."):
1354 if not record
.Rc
is _RCOE
.RC
:
1357 return exact_match(key
[:-1], record
)
1359 def LK_match(key
, record
):
1360 if not key
.endswith("l"):
1363 if "lk" not in record
.flags
:
1366 return exact_match(key
[:-1], record
)
1368 def AA_match(key
, record
):
1369 if not key
.endswith("a"):
1372 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1375 if self
.__mdwndb
[key
]["AA"] is None:
1378 return (exact_match(key
[:-1], record
) or
1379 LK_match(key
[:-1], record
))
1381 for (section
, records
) in self
.__db
.items():
1382 for record
in records
:
1383 if (exact_match(key
, record
) or
1384 Rc_match(key
, record
) or
1385 LK_match(key
, record
) or
1386 AA_match(key
, record
)):
1387 return (section
, record
)
1392 class SVP64Database
:
1393 def __init__(self
, root
, ppcdb
):
1395 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1396 for (prefix
, _
, names
) in _os
.walk(root
):
1397 prefix
= _pathlib
.Path(prefix
)
1398 for name
in filter(lambda name
: pattern
.match(name
), names
):
1399 path
= (prefix
/ _pathlib
.Path(name
))
1400 with
open(path
, "r", encoding
="UTF-8") as stream
:
1401 db
.update(parse(stream
, SVP64Record
.CSV
))
1403 self
.__db
= {record
.name
:record
for record
in db
}
1404 self
.__ppcdb
= ppcdb
1406 return super().__init
__()
1408 def __getitem__(self
, key
):
1409 (_
, record
) = self
.__ppcdb
[key
]
1413 for name
in record
.names
:
1414 record
= self
.__db
.get(name
, None)
1415 if record
is not None:
1422 def __init__(self
, root
):
1423 root
= _pathlib
.Path(root
)
1425 mdwndb
= MarkdownDatabase()
1426 fieldsdb
= FieldsDatabase()
1427 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
, fieldsdb
=fieldsdb
)
1428 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1431 for (name
, operands
) in mdwndb
:
1432 (section
, ppc
) = ppcdb
[name
]
1435 svp64
= svp64db
[name
]
1436 fields
= fieldsdb
[ppc
.form
]
1437 record
= Record(name
=name
,
1438 section
=section
, ppc
=ppc
, svp64
=svp64
,
1439 operands
=operands
, fields
=fields
)
1442 self
.__db
= tuple(sorted(db
))
1444 return super().__init
__()
1447 return repr(self
.__db
)
1450 yield from self
.__db
1452 @_functools.lru_cache(maxsize
=None)
1453 def __contains__(self
, key
):
1454 return self
.__getitem
__(key
) is not None
1456 @_functools.lru_cache(maxsize
=None)
1457 def __getitem__(self
, key
):
1458 if isinstance(key
, (int, Instruction
)):
1461 opcode
= record
.opcode
1462 if ((opcode
.value
& opcode
.mask
) ==
1463 (key
& opcode
.mask
)):
1466 elif isinstance(key
, Opcode
):
1468 if record
.opcode
== key
:
1470 elif isinstance(key
, str):
1472 if record
.name
== key
: