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
)
350 @_functools.lru_cache(maxsize
=None)
351 def extra_idx(self
, key
):
359 if key
not in frozenset({
360 "in1", "in2", "in3", "cr_in",
361 "out", "out2", "cr_out",
365 sel
= getattr(self
, key
)
366 if sel
is _CRInSel
.BA_BB
:
367 return _SVExtra
.Idx_1_2
368 reg
= _SVExtraReg(sel
)
369 if reg
is _SVExtraReg
.NONE
:
373 _SVExtraRegType
.SRC
: {},
374 _SVExtraRegType
.DST
: {},
376 for index
in range(0, 4):
377 for entry
in self
.extra
[index
]:
378 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
380 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
381 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
382 if extra
is not _SVExtra
.NONE
:
387 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
388 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
389 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
390 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
391 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
392 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
393 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
395 @_functools.lru_cache(maxsize
=None)
396 def extra_reg(self
, key
):
397 return _SVExtraReg(getattr(self
, key
))
399 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
400 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
401 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
402 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
403 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
404 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
405 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
409 def __init__(self
, value
=(0, 32)):
410 if isinstance(value
, str):
411 (start
, end
) = map(int, value
.split(":"))
414 if start
< 0 or end
< 0 or start
>= end
:
415 raise ValueError(value
)
420 return super().__init
__()
423 return f
"[{self.__start}:{self.__end}]"
426 yield from range(self
.start
, (self
.end
+ 1))
437 @_dataclasses.dataclass(eq
=True, frozen
=True)
439 class Mode(_enum
.Enum
):
440 INTEGER
= _enum
.auto()
441 PATTERN
= _enum
.auto()
444 def _missing_(cls
, value
):
445 if isinstance(value
, str):
446 return cls
[value
.upper()]
447 return super()._missing
_(value
)
450 def __new__(cls
, value
=None):
451 if isinstance(value
, str):
452 if value
.upper() == "NONE":
455 value
= int(value
, 0)
459 return super().__new
__(cls
, value
)
465 return (bin(self
) if self
else "None")
474 def CSV(cls
, record
):
475 return dataclass(cls
, record
)
479 def __init__(self
, items
):
480 if isinstance(items
, dict):
481 items
= items
.items()
484 (name
, bitrange
) = item
485 return (name
, list(bitrange
.values()))
487 self
.__mapping
= dict(map(transform
, items
))
489 return super().__init
__()
492 return repr(self
.__mapping
)
495 yield from self
.__mapping
.items()
497 def __contains__(self
, key
):
498 return self
.__mapping
.__contains
__(key
)
500 def __getitem__(self
, key
):
501 return self
.__mapping
.get(key
, None)
504 @_dataclasses.dataclass(eq
=True, frozen
=True)
508 def disassemble(self
, value
, record
, verbose
=False):
509 raise NotImplementedError
512 @_dataclasses.dataclass(eq
=True, frozen
=True)
513 class DynamicOperand(Operand
):
514 def disassemble(self
, value
, record
, verbose
=False):
515 span
= record
.fields
[self
.name
]
518 yield f
"{int(value):0{value.bits}b}"
521 yield str(int(value
))
524 @_dataclasses.dataclass(eq
=True, frozen
=True)
525 class DynamicOperandReg(DynamicOperand
):
528 return _SVExtraReg(self
.name
)
530 def extra_idx(self
, record
):
531 for key
in frozenset({
532 "in1", "in2", "in3", "cr_in",
533 "out", "out2", "cr_out",
535 if self
.extra_reg
== record
.svp64
.extra_reg(key
):
536 return record
.extra_idx(key
)
541 @_dataclasses.dataclass(eq
=True, frozen
=True)
542 class ImmediateOperand(DynamicOperand
):
546 @_dataclasses.dataclass(eq
=True, frozen
=True)
547 class StaticOperand(Operand
):
550 def disassemble(self
, value
, record
, verbose
=False):
551 span
= record
.fields
[self
.name
]
554 yield f
"{int(value):0{value.bits}b}"
557 yield str(int(value
))
560 @_dataclasses.dataclass(eq
=True, frozen
=True)
561 class DynamicOperandTargetAddrLI(DynamicOperandReg
):
570 def disassemble(self
, value
, record
, verbose
=False):
571 span
= record
.fields
["LI"]
574 yield f
"{int(value):0{value.bits}b}"
576 yield "target_addr = EXTS(LI || 0b00))"
578 yield hex(int(_selectconcat(value
,
579 _SelectableInt(value
=0b00, bits
=2))))
582 class DynamicOperandTargetAddrBD(DynamicOperand
):
591 def disassemble(self
, value
, record
, verbose
=False):
592 span
= record
.fields
["BD"]
595 yield f
"{int(value):0{value.bits}b}"
597 yield "target_addr = EXTS(BD || 0b00))"
599 yield hex(int(_selectconcat(value
,
600 _SelectableInt(value
=0b00, bits
=2))))
603 @_dataclasses.dataclass(eq
=True, frozen
=True)
604 class DynamicOperandGPR(DynamicOperandReg
):
605 def disassemble(self
, value
, record
, verbose
=False):
606 svp64
= isinstance(value
, SVP64Instruction
)
607 span
= record
.fields
[self
.name
]
610 yield f
"{int(value):0{value.bits}b}"
613 extra_idx
= self
.extra_idx(record
)
614 if record
.etype
is _SVEtype
.NONE
:
617 etype
= repr(record
.etype
).lower()
618 yield f
"{etype}{extra_idx!r}"
620 yield f
"r{str(int(value))}"
623 @_dataclasses.dataclass(eq
=True, frozen
=True)
624 class DynamicOperandFPR(DynamicOperandReg
):
625 def disassemble(self
, value
, record
, verbose
=False):
626 svp64
= isinstance(value
, SVP64Instruction
)
627 span
= record
.fields
[self
.name
]
630 yield f
"{int(value):0{value.bits}b}"
633 extra_idx
= self
.extra_idx(record
)
634 if record
.etype
is _SVEtype
.NONE
:
637 etype
= repr(record
.etype
).lower()
638 yield f
"{etype}{extra_idx!r}"
640 yield f
"f{str(int(value))}"
643 class Operands(tuple):
644 def __new__(cls
, insn
, iterable
):
646 "b": {"target_addr": DynamicOperandTargetAddrLI
},
647 "ba": {"target_addr": DynamicOperandTargetAddrLI
},
648 "bl": {"target_addr": DynamicOperandTargetAddrLI
},
649 "bla": {"target_addr": DynamicOperandTargetAddrLI
},
650 "bc": {"target_addr": DynamicOperandTargetAddrBD
},
651 "bca": {"target_addr": DynamicOperandTargetAddrBD
},
652 "bcl": {"target_addr": DynamicOperandTargetAddrBD
},
653 "bcla": {"target_addr": DynamicOperandTargetAddrBD
},
657 for operand
in iterable
:
658 dynamic_cls
= DynamicOperand
659 static_cls
= StaticOperand
662 (name
, value
) = operand
.split("=")
663 operand
= static_cls(name
=name
, value
=int(value
))
664 operands
.append(operand
)
666 if operand
.endswith(")"):
667 operand
= operand
.replace("(", " ").replace(")", "")
668 (immediate
, _
, operand
) = operand
.partition(" ")
672 if immediate
is not None:
673 operands
.append(ImmediateOperand(name
=immediate
))
675 if insn
in branches
and operand
in branches
[insn
]:
676 dynamic_cls
= branches
[insn
][operand
]
678 if operand
in _RegType
.__members
__:
679 regtype
= _RegType
[operand
]
680 if regtype
is _RegType
.GPR
:
681 dynamic_cls
= DynamicOperandGPR
682 elif regtype
is _RegType
.FPR
:
683 dynamic_cls
= DynamicOperandFPR
685 operand
= dynamic_cls(name
=operand
)
686 operands
.append(operand
)
688 return super().__new
__(cls
, operands
)
690 def __contains__(self
, key
):
691 return self
.__getitem
__(key
) is not None
693 def __getitem__(self
, key
):
695 if operand
.name
== key
:
703 if isinstance(operand
, DynamicOperand
):
709 if isinstance(operand
, StaticOperand
):
713 @_functools.total_ordering
714 @_dataclasses.dataclass(eq
=True, frozen
=True)
721 svp64
: SVP64Record
= None
723 def __lt__(self
, other
):
724 if not isinstance(other
, Record
):
725 return NotImplemented
726 return (self
.opcode
< other
.opcode
)
731 if self
.section
.opcode
:
732 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
733 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
735 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
737 for operand
in self
.operands
.static
:
738 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
740 return FieldsOpcode(fields
)
744 return self
.ppc
.function
764 if self
.svp64
is None:
770 return self
.ppc
.cr_in
774 return self
.ppc
.cr_out
776 def extra_idx(self
, key
):
777 return self
.svp64
.extra_idx(key
)
779 ptype
= property(lambda self
: self
.svp64
.ptype
)
780 etype
= property(lambda self
: self
.svp64
.etype
)
781 extra_in1
= property(lambda self
: self
.svp64
.extra_in1
)
782 extra_in2
= property(lambda self
: self
.svp64
.extra_in2
)
783 extra_in3
= property(lambda self
: self
.svp64
.extra_in3
)
784 extra_out
= property(lambda self
: self
.svp64
.extra_out
)
785 extra_out2
= property(lambda self
: self
.svp64
.extra_out2
)
786 extra_cr_in
= property(lambda self
: self
.svp64
.extra_cr_in
)
787 extra_cr_out
= property(lambda self
: self
.svp64
.extra_cr_out
)
790 class Instruction(_Mapping
):
792 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
793 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
794 raise ValueError(bits
)
796 if isinstance(value
, bytes
):
797 if ((len(value
) * 8) != bits
):
798 raise ValueError(f
"bit length mismatch")
799 value
= int.from_bytes(value
, byteorder
=byteorder
)
801 if isinstance(value
, int):
802 value
= _SelectableInt(value
=value
, bits
=bits
)
803 elif isinstance(value
, Instruction
):
804 value
= value
.storage
806 if not isinstance(value
, _SelectableInt
):
807 raise ValueError(value
)
810 if len(value
) != bits
:
811 raise ValueError(value
)
813 value
= _SelectableInt(value
=value
, bits
=bits
)
815 return cls(storage
=value
)
818 return hash(int(self
))
820 def record(self
, db
):
826 def disassemble(self
, db
, byteorder
="little", verbose
=False):
827 raise NotImplementedError
830 class WordInstruction(Instruction
):
831 _
: _Field
= range(0, 32)
832 po
: _Field
= range(0, 6)
835 def integer(cls
, value
, byteorder
="little"):
836 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
841 for idx
in range(32):
844 return "".join(map(str, bits
))
847 record
= self
.record(db
=db
)
850 dynamic_operands
= []
851 for operand
in record
.operands
.dynamic
:
854 name
= f
"{immediate}({name})"
856 if isinstance(operand
, ImmediateOperand
):
857 immediate
= operand
.name
859 dynamic_operands
.append(name
)
862 for operand
in record
.operands
.static
:
863 static_operands
.append(f
"{operand.name}={operand.value}")
867 operands
+= f
" {','.join(dynamic_operands)}"
869 operands
+= f
" ({' '.join(static_operands)})"
871 return f
"{record.name}{operands}"
873 def opcode(self
, db
):
874 record
= self
.record(db
=db
)
875 return f
"0x{record.opcode.value:08x}"
878 record
= self
.record(db
=db
)
879 return f
"0x{record.opcode.mask:08x}"
881 def disassemble(self
, db
, byteorder
="little", verbose
=False):
883 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
884 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
886 record
= self
.record(db
=db
)
888 yield f
"{blob} .long 0x{integer:08x}"
892 for operand
in record
.operands
.dynamic
:
893 operand
= " ".join(operand
.disassemble(value
=self
,
894 record
=record
, verbose
=False))
895 operands
.append(operand
)
897 operands
= ",".join(operands
)
898 operands
= f
" {operands}"
902 yield f
"{blob} {record.name}{operands}"
907 spec
= self
.spec(db
=db
)
908 opcode
= self
.opcode(db
=db
)
909 mask
= self
.mask(db
=db
)
910 yield f
"{indent}spec"
911 yield f
"{indent}{indent}{spec}"
912 yield f
"{indent}binary"
913 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
914 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
915 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
916 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
917 yield f
"{indent}opcode"
918 yield f
"{indent}{indent}{opcode}"
919 yield f
"{indent}mask"
920 yield f
"{indent}{indent}{mask}"
921 for operand
in record
.operands
:
923 yield f
"{indent}{name}"
924 parts
= operand
.disassemble(value
=self
,
925 record
=record
, verbose
=True)
927 yield f
"{indent}{indent}{part}"
931 class PrefixedInstruction(Instruction
):
932 class Prefix(WordInstruction
.remap(range(0, 32))):
935 class Suffix(WordInstruction
.remap(range(32, 64))):
938 _
: _Field
= range(64)
944 def integer(cls
, value
, byteorder
="little"):
945 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
948 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
949 def transform(value
):
950 return WordInstruction
.integer(value
=value
,
951 byteorder
=byteorder
)[0:32]
953 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
954 value
= _selectconcat(prefix
, suffix
)
956 return super().integer(value
=value
)
959 class Mode(_Mapping
):
960 _
: _Field
= range(0, 5)
961 sel
: _Field
= range(0, 2)
964 class NormalMode(Mode
):
971 """scalar reduce mode (mapreduce), SUBVL=1"""
975 """parallel reduce mode (mapreduce), SUBVL=1"""
979 """subvector reduce mode, SUBVL>1"""
983 """Pack/Unpack mode, SUBVL>1"""
987 """Rc=1: ffirst CR sel"""
992 """Rc=0: ffirst z/nonz"""
998 """sat mode: N=0/1 u/s, SUBVL=1"""
1004 """sat mode: N=0/1 u/s, SUBVL>1"""
1011 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1018 """Rc=1: pred-result CR sel"""
1023 """Rc=0: pred-result z/nonz"""
1044 class LDSTImmMode(Mode
):
1053 """Structured Pack/Unpack"""
1060 """Rc=1: ffirst CR sel"""
1065 """Rc=0: ffirst z/nonz"""
1071 """sat mode: N=0/1 u/s"""
1079 """Rc=1: pred-result CR sel"""
1084 """Rc=0: pred-result z/nonz"""
1098 class LDSTIdxMode(Mode
):
1106 """strided (scalar only source)"""
1112 """sat mode: N=0/1 u/s"""
1118 """Rc=1: pred-result CR sel"""
1123 """Rc=0: pred-result z/nonz"""
1140 ldst_imm
: LDSTImmMode
1141 ldst_idx
: LDSTIdxMode
1143 _
: _Field
= range(24)
1144 mmode
: _Field
= (0,)
1145 mask
: _Field
= range(1, 4)
1146 elwidth
: _Field
= range(4, 6)
1147 ewsrc
: _Field
= range(6, 8)
1148 subvl
: _Field
= range(8, 10)
1149 extra
: _Field
= range(10, 19)
1150 mode
: Mode
.remap(range(19, 24))
1151 extra2
: _Array
[4] = (
1157 smask
: _Field
= range(16, 19)
1158 extra3
: _Array
[3] = (
1165 class SVP64Instruction(PrefixedInstruction
):
1166 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1167 class Prefix(PrefixedInstruction
.Prefix
):
1169 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1176 for idx
in range(64):
1177 bit
= int(self
[idx
])
1179 return "".join(map(str, bits
))
1182 return f
"sv.{self.suffix.spec(db=db)}"
1184 def opcode(self
, db
):
1185 return self
.suffix
.opcode(db
=db
)
1188 return self
.suffix
.mask(db
=db
)
1191 record
= self
.record(db
=db
)
1194 if record
.operands
["Rc"] is not None:
1195 Rc
= bool(self
[record
.fields
["Rc"]])
1197 record
= self
.record(db
=db
)
1198 subvl
= self
.prefix
.rm
.subvl
1199 mode
= self
.prefix
.rm
.mode
1202 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1236 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1237 mode
= mode
.ldst_imm
1255 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1256 mode
= mode
.ldst_idx
1257 if mode
.sel
== 0b00:
1259 elif mode
.sel
== 0b01:
1261 elif mode
.sel
== 0b10:
1263 elif mode
.sel
== 0b11:
1270 NormalMode
.simple
: "normal: simple",
1271 NormalMode
.smr
: "normal: smr",
1272 NormalMode
.pmr
: "normal: pmr",
1273 NormalMode
.svmr
: "normal: svmr",
1274 NormalMode
.pu
: "normal: pu",
1275 NormalMode
.ffrc1
: "normal: ffrc1",
1276 NormalMode
.ffrc0
: "normal: ffrc0",
1277 NormalMode
.sat
: "normal: sat",
1278 NormalMode
.satx
: "normal: satx",
1279 NormalMode
.satpu
: "normal: satpu",
1280 NormalMode
.prrc1
: "normal: prrc1",
1281 NormalMode
.prrc0
: "normal: prrc0",
1282 LDSTImmMode
.simple
: "ld/st imm: simple",
1283 LDSTImmMode
.spu
: "ld/st imm: spu",
1284 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1285 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1286 LDSTImmMode
.sat
: "ld/st imm: sat",
1287 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1288 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1289 LDSTIdxMode
.simple
: "ld/st idx simple",
1290 LDSTIdxMode
.stride
: "ld/st idx stride",
1291 LDSTIdxMode
.sat
: "ld/st idx sat",
1292 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1293 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1295 for (cls
, desc
) in modes
.items():
1296 if isinstance(mode
, cls
):
1299 raise NotImplementedError
1301 def disassemble(self
, db
, byteorder
="little", verbose
=False):
1302 integer_prefix
= int(self
.prefix
)
1303 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
1304 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
1306 integer_suffix
= int(self
.suffix
)
1307 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
1308 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
1310 record
= self
.record(db
=db
)
1311 if record
is None or record
.svp64
is None:
1312 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
1313 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
1316 yield f
"{blob_prefix} sv.{record.name}"
1317 yield f
"{blob_suffix}"
1319 (mode
, mode_desc
) = self
.mode(db
=db
)
1323 binary
= self
.binary
1324 spec
= self
.spec(db
=db
)
1325 opcode
= self
.opcode(db
=db
)
1326 mask
= self
.mask(db
=db
)
1327 yield f
"{indent}spec"
1328 yield f
"{indent}{indent}{spec}"
1329 yield f
"{indent}binary"
1330 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1331 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1332 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1333 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1334 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1335 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1336 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1337 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1338 yield f
"{indent}opcode"
1339 yield f
"{indent}{indent}{opcode}"
1340 yield f
"{indent}mask"
1341 yield f
"{indent}{indent}{mask}"
1342 for operand
in record
.operands
:
1344 yield f
"{indent}{name}"
1345 parts
= operand
.disassemble(value
=self
,
1346 record
=record
, verbose
=True)
1348 yield f
"{indent}{indent}{part}"
1350 yield f
"{indent}mode"
1351 yield f
"{indent}{indent}{mode_desc}"
1355 def parse(stream
, factory
):
1357 return ("TODO" not in frozenset(entry
.values()))
1359 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1360 entries
= _csv
.DictReader(lines
)
1361 entries
= filter(match
, entries
)
1362 return tuple(map(factory
, entries
))
1365 class MarkdownDatabase
:
1368 for (name
, desc
) in _ISA():
1371 (dynamic
, *static
) = desc
.regs
1372 operands
.extend(dynamic
)
1373 operands
.extend(static
)
1374 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1376 return super().__init
__()
1379 yield from self
.__db
.items()
1381 def __getitem__(self
, key
):
1382 return self
.__db
.__getitem
__(key
)
1385 class FieldsDatabase
:
1388 df
= _DecodeFields()
1390 for (form
, fields
) in df
.instrs
.items():
1391 if form
in {"DQE", "TX"}:
1395 db
[_Form
[form
]] = Fields(fields
)
1399 return super().__init
__()
1401 def __getitem__(self
, key
):
1402 return self
.__db
.__getitem
__(key
)
1406 def __init__(self
, root
, mdwndb
):
1407 # The code below groups the instructions by section:identifier.
1408 # We use the comment as an identifier, there's nothing better.
1409 # The point is to capture different opcodes for the same instruction.
1410 dd
= _collections
.defaultdict
1411 records
= dd(lambda: dd(set))
1412 path
= (root
/ "insndb.csv")
1413 with
open(path
, "r", encoding
="UTF-8") as stream
:
1414 for section
in parse(stream
, Section
.CSV
):
1415 path
= (root
/ section
.path
)
1417 section
.Mode
.INTEGER
: IntegerOpcode
,
1418 section
.Mode
.PATTERN
: PatternOpcode
,
1420 factory
= _functools
.partial(
1421 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1422 with
open(path
, "r", encoding
="UTF-8") as stream
:
1423 for insn
in parse(stream
, factory
):
1424 records
[section
][insn
.comment
].add(insn
)
1427 for (section
, group
) in records
.items():
1428 for records
in group
.values():
1429 db
[section
].add(PPCMultiRecord(records
))
1432 self
.__mdwndb
= mdwndb
1434 return super().__init
__()
1436 def __getitem__(self
, key
):
1437 def exact_match(key
, record
):
1438 for name
in record
.names
:
1444 def Rc_match(key
, record
):
1445 if not key
.endswith("."):
1448 if not record
.Rc
is _RCOE
.RC
:
1451 return exact_match(key
[:-1], record
)
1453 def LK_match(key
, record
):
1454 if not key
.endswith("l"):
1457 if "lk" not in record
.flags
:
1460 return exact_match(key
[:-1], record
)
1462 def AA_match(key
, record
):
1463 if not key
.endswith("a"):
1466 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1469 if self
.__mdwndb
[key
]["AA"] is None:
1472 return (exact_match(key
[:-1], record
) or
1473 LK_match(key
[:-1], record
))
1475 for (section
, records
) in self
.__db
.items():
1476 for record
in records
:
1477 if exact_match(key
, record
):
1478 return (section
, record
)
1480 for record
in records
:
1481 if (Rc_match(key
, record
) or
1482 LK_match(key
, record
) or
1483 AA_match(key
, record
)):
1484 return (section
, record
)
1489 class SVP64Database
:
1490 def __init__(self
, root
, ppcdb
):
1492 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1493 for (prefix
, _
, names
) in _os
.walk(root
):
1494 prefix
= _pathlib
.Path(prefix
)
1495 for name
in filter(lambda name
: pattern
.match(name
), names
):
1496 path
= (prefix
/ _pathlib
.Path(name
))
1497 with
open(path
, "r", encoding
="UTF-8") as stream
:
1498 db
.update(parse(stream
, SVP64Record
.CSV
))
1500 self
.__db
= {record
.name
:record
for record
in db
}
1501 self
.__ppcdb
= ppcdb
1503 return super().__init
__()
1505 def __getitem__(self
, key
):
1506 (_
, record
) = self
.__ppcdb
[key
]
1510 for name
in record
.names
:
1511 record
= self
.__db
.get(name
, None)
1512 if record
is not None:
1519 def __init__(self
, root
):
1520 root
= _pathlib
.Path(root
)
1522 mdwndb
= MarkdownDatabase()
1523 fieldsdb
= FieldsDatabase()
1524 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1525 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1528 for (name
, operands
) in mdwndb
:
1529 (section
, ppc
) = ppcdb
[name
]
1532 svp64
= svp64db
[name
]
1533 fields
= fieldsdb
[ppc
.form
]
1534 record
= Record(name
=name
,
1535 section
=section
, ppc
=ppc
, svp64
=svp64
,
1536 operands
=operands
, fields
=fields
)
1539 self
.__db
= tuple(sorted(db
))
1541 return super().__init
__()
1544 return repr(self
.__db
)
1547 yield from self
.__db
1549 @_functools.lru_cache(maxsize
=None)
1550 def __contains__(self
, key
):
1551 return self
.__getitem
__(key
) is not None
1553 @_functools.lru_cache(maxsize
=None)
1554 def __getitem__(self
, key
):
1555 if isinstance(key
, (int, Instruction
)):
1558 opcode
= record
.opcode
1559 if ((opcode
.value
& opcode
.mask
) ==
1560 (key
& opcode
.mask
)):
1563 elif isinstance(key
, Opcode
):
1565 if record
.opcode
== key
:
1567 elif isinstance(key
, str):
1569 if record
.name
== key
: