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 (
44 DecodeFields
as _DecodeFields
,
46 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
49 def dataclass(cls
, record
, keymap
=None, typemap
=None):
53 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
55 def transform(key_value
):
56 (key
, value
) = key_value
57 key
= keymap
.get(key
, key
)
58 hook
= typemap
.get(key
, lambda value
: value
)
59 if hook
is bool and value
in ("", "0"):
65 record
= dict(map(transform
, record
.items()))
66 for key
in frozenset(record
.keys()):
73 @_functools.total_ordering
74 @_dataclasses.dataclass(eq
=True, frozen
=True)
78 if self
.bit_length() <= 32:
79 return f
"0x{self:08x}"
81 return f
"0x{self:016x}"
85 if self
.bit_length() <= 32:
86 return f
"0x{self:08x}"
88 return f
"0x{self:016x}"
93 def __lt__(self
, other
):
94 if not isinstance(other
, Opcode
):
96 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
98 def __post_init__(self
):
99 (value
, mask
) = (self
.value
, self
.mask
)
101 if isinstance(value
, Opcode
):
103 raise ValueError(mask
)
104 (value
, mask
) = (value
.value
, value
.mask
)
105 elif isinstance(value
, str):
107 raise ValueError(mask
)
108 value
= int(value
, 0)
110 if not isinstance(value
, int):
111 raise ValueError(value
)
114 if not isinstance(mask
, int):
115 raise ValueError(mask
)
117 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
118 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
121 class IntegerOpcode(Opcode
):
122 def __init__(self
, value
):
123 if isinstance(value
, str):
124 value
= int(value
, 0)
125 return super().__init
__(value
=value
, mask
=None)
128 class PatternOpcode(Opcode
):
129 def __init__(self
, value
):
130 (pattern
, value
, mask
) = (value
, 0, 0)
132 for symbol
in pattern
:
133 if symbol
not in {"0", "1", "-"}:
134 raise ValueError(pattern
)
135 value |
= (symbol
== "1")
136 mask |
= (symbol
!= "-")
142 return super().__init
__(value
=value
, mask
=mask
)
145 class FieldsOpcode(Opcode
):
146 def __init__(self
, fields
):
147 def field(opcode
, field
):
148 (value
, mask
) = opcode
149 (field
, bits
) = field
150 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
151 for (index
, shift
) in enumerate(shifts
):
152 bit
= ((field
& (1 << index
)) != 0)
153 value |
= (bit
<< shift
)
157 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
159 return super().__init
__(value
=value
, mask
=mask
)
162 @_dataclasses.dataclass(eq
=True, frozen
=True)
164 class FlagsMeta(type):
179 class Flags(frozenset, metaclass
=FlagsMeta
):
180 def __new__(cls
, flags
=frozenset()):
181 flags
= frozenset(flags
)
182 diff
= (flags
- frozenset(cls
))
184 raise ValueError(flags
)
185 return super().__new
__(cls
, flags
)
189 flags
: Flags
= Flags()
191 function
: _Function
= _Function
.NONE
192 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
193 in1
: _In1Sel
= _In1Sel
.RA
194 in2
: _In2Sel
= _In2Sel
.NONE
195 in3
: _In3Sel
= _In3Sel
.NONE
196 out
: _OutSel
= _OutSel
.NONE
197 cr_in
: _CRInSel
= _CRInSel
.NONE
198 cr_out
: _CROutSel
= _CROutSel
.NONE
199 cry_in
: _CryIn
= _CryIn
.ZERO
200 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
201 upd
: _LDSTMode
= _LDSTMode
.NONE
202 Rc
: _RCOE
= _RCOE
.NONE
203 form
: _Form
= _Form
.NONE
205 unofficial
: bool = False
209 "internal op": "intop",
213 "ldst len": "ldst_len",
215 "CONDITIONS": "conditions",
219 def CSV(cls
, record
, opcode_cls
=Opcode
):
220 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
221 typemap
["opcode"] = opcode_cls
224 for flag
in frozenset(PPCRecord
.Flags
):
225 if bool(record
.pop(flag
, "")):
227 record
["flags"] = PPCRecord
.Flags(flags
)
229 return dataclass(cls
, record
,
230 keymap
=PPCRecord
.__KEYMAP
,
235 return frozenset(self
.comment
.split("=")[-1].split("/"))
238 class PPCMultiRecord(frozenset):
244 lvalue
= lhs
.opcode
.value
245 rvalue
= rhs
.opcode
.value
246 lmask
= lhs
.opcode
.mask
247 rmask
= rhs
.opcode
.mask
248 bits
= max(lmask
.bit_length(), rmask
.bit_length())
249 for bit
in range(bits
):
250 lvstate
= ((lvalue
& (1 << bit
)) != 0)
251 rvstate
= ((rvalue
& (1 << bit
)) != 0)
252 lmstate
= ((lmask
& (1 << bit
)) != 0)
253 rmstate
= ((rmask
& (1 << bit
)) != 0)
256 if (not lmstate
or not rmstate
) or (lvstate
!= rvstate
):
259 value |
= (vstate
<< bit
)
260 mask |
= (mstate
<< bit
)
262 opcode
= opcode
=Opcode(value
=value
, mask
=mask
)
264 return _dataclasses
.replace(lhs
, opcode
=opcode
)
266 return _functools
.reduce(merge
, self
)
268 def __getattr__(self
, attr
):
269 return getattr(self
.unified
, attr
)
272 @_dataclasses.dataclass(eq
=True, frozen
=True)
274 class ExtraMap(tuple):
276 @_dataclasses.dataclass(eq
=True, frozen
=True)
278 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
279 reg
: _SVExtraReg
= _SVExtraReg
.NONE
282 return f
"{self.regtype.value}:{self.reg.name}"
284 def __new__(cls
, value
="0"):
285 if isinstance(value
, str):
286 def transform(value
):
287 (regtype
, reg
) = value
.split(":")
288 regtype
= _SVExtraRegType(regtype
)
289 reg
= _SVExtraReg(reg
)
290 return cls
.Entry(regtype
=regtype
, reg
=reg
)
295 value
= map(transform
, value
.split(";"))
297 return super().__new
__(cls
, value
)
300 return repr(list(self
))
302 def __new__(cls
, value
=tuple()):
306 return super().__new
__(cls
, map(cls
.Extra
, value
))
309 return repr({index
:self
[index
] for index
in range(0, 4)})
312 ptype
: _SVPtype
= _SVPtype
.NONE
313 etype
: _SVEtype
= _SVEtype
.NONE
314 in1
: _In1Sel
= _In1Sel
.NONE
315 in2
: _In2Sel
= _In2Sel
.NONE
316 in3
: _In3Sel
= _In3Sel
.NONE
317 out
: _OutSel
= _OutSel
.NONE
318 out2
: _OutSel
= _OutSel
.NONE
319 cr_in
: _CRInSel
= _CRInSel
.NONE
320 cr_out
: _CROutSel
= _CROutSel
.NONE
321 extra
: ExtraMap
= ExtraMap()
323 mode
: _SVMode
= _SVMode
.NORMAL
327 "CONDITIONS": "conditions",
335 def CSV(cls
, record
):
336 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
342 for idx
in range(0, 4):
343 extra
.append(record
.pop(f
"{idx}"))
345 record
["extra"] = cls
.ExtraMap(extra
)
347 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
349 @_functools.lru_cache(maxsize
=None)
350 def extra_idx(self
, key
):
358 if key
not in frozenset({
359 "in1", "in2", "in3", "cr_in",
360 "out", "out2", "cr_out",
364 sel
= getattr(self
, key
)
365 if sel
is _CRInSel
.BA_BB
:
366 return _SVExtra
.Idx_1_2
367 reg
= _SVExtraReg(sel
)
368 if reg
is _SVExtraReg
.NONE
:
372 _SVExtraRegType
.SRC
: {},
373 _SVExtraRegType
.DST
: {},
375 for index
in range(0, 4):
376 for entry
in self
.extra
[index
]:
377 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
379 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
380 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
381 if extra
is not _SVExtra
.NONE
:
386 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
387 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
388 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
389 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
390 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
391 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
392 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
394 @_functools.lru_cache(maxsize
=None)
395 def extra_reg(self
, key
):
396 return _SVExtraReg(getattr(self
, key
))
398 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
399 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
400 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
401 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
402 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
403 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
404 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
408 def __init__(self
, value
=(0, 32)):
409 if isinstance(value
, str):
410 (start
, end
) = map(int, value
.split(":"))
413 if start
< 0 or end
< 0 or start
>= end
:
414 raise ValueError(value
)
419 return super().__init
__()
422 return f
"[{self.__start}:{self.__end}]"
425 yield from range(self
.start
, (self
.end
+ 1))
436 @_dataclasses.dataclass(eq
=True, frozen
=True)
438 class Mode(_enum
.Enum
):
439 INTEGER
= _enum
.auto()
440 PATTERN
= _enum
.auto()
443 def _missing_(cls
, value
):
444 if isinstance(value
, str):
445 return cls
[value
.upper()]
446 return super()._missing
_(value
)
449 def __new__(cls
, value
=None):
450 if isinstance(value
, str):
451 if value
.upper() == "NONE":
454 value
= int(value
, 0)
458 return super().__new
__(cls
, value
)
464 return (bin(self
) if self
else "None")
473 def CSV(cls
, record
):
474 return dataclass(cls
, record
)
478 def __init__(self
, items
):
479 if isinstance(items
, dict):
480 items
= items
.items()
483 (name
, bitrange
) = item
484 return (name
, tuple(bitrange
.values()))
486 self
.__mapping
= dict(map(transform
, items
))
488 return super().__init
__()
491 return repr(self
.__mapping
)
494 yield from self
.__mapping
.items()
496 def __contains__(self
, key
):
497 return self
.__mapping
.__contains
__(key
)
499 def __getitem__(self
, key
):
500 return self
.__mapping
.get(key
, None)
503 @_dataclasses.dataclass(eq
=True, frozen
=True)
507 def disassemble(self
, insn
, record
, verbose
=False):
508 raise NotImplementedError
511 @_dataclasses.dataclass(eq
=True, frozen
=True)
512 class DynamicOperand(Operand
):
513 def disassemble(self
, insn
, record
, verbose
=False):
514 span
= record
.fields
[self
.name
]
515 if isinstance(insn
, SVP64Instruction
):
516 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
520 yield f
"{int(value):0{value.bits}b}"
523 yield str(int(value
))
526 @_dataclasses.dataclass(eq
=True, frozen
=True)
527 class DynamicOperandReg(DynamicOperand
):
528 def spec(self
, insn
, record
):
530 span
= record
.fields
[self
.name
]
531 if isinstance(insn
, SVP64Instruction
):
532 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
535 if isinstance(insn
, SVP64Instruction
):
536 extra_idx
= self
.extra_idx(record
=record
)
538 if record
.etype
is _SVEtype
.EXTRA3
:
539 extra
= insn
.prefix
.rm
.extra3
[extra_idx
]
540 elif record
.etype
is _SVEtype
.EXTRA2
:
541 extra
= insn
.prefix
.rm
.extra2
[extra_idx
]
543 raise ValueError(record
.etype
)
546 vector
= bool(extra
[0])
547 span
= (span
+ tuple(extra
.__class
__))
548 if record
.etype
is _SVEtype
.EXTRA3
:
549 extra
= int(extra
[1, 2])
550 elif record
.etype
is _SVEtype
.EXTRA2
:
551 extra
= (int(extra
[1]) << 1)
553 raise ValueError(record
.etype
)
557 value
= ((base
<< 2) | extra
)
559 value
= ((extra
<< 5) | base
)
560 value
= _SelectableInt(value
=value
, bits
=len(span
))
565 return (vector
, value
, span
)
569 return _SVExtraReg(self
.name
)
571 def extra_idx(self
, record
):
572 for key
in frozenset({
573 "in1", "in2", "in3", "cr_in",
574 "out", "out2", "cr_out",
576 extra_reg
= record
.svp64
.extra_reg(key
=key
)
577 if extra_reg
is self
.extra_reg
:
578 return record
.extra_idx(key
=key
)
582 def disassemble(self
, insn
, record
, verbose
=False, prefix
=""):
583 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
585 yield f
"{int(value):0{value.bits}b}"
587 if isinstance(insn
, SVP64Instruction
):
588 extra_idx
= self
.extra_idx(record
)
589 if record
.etype
is _SVEtype
.NONE
:
592 etype
= repr(record
.etype
).lower()
593 yield f
"{etype}{extra_idx!r}"
595 vector
= "*" if vector
else ""
596 yield f
"{vector}{prefix}{int(value)}"
599 @_dataclasses.dataclass(eq
=True, frozen
=True)
600 class ImmediateOperand(DynamicOperand
):
604 @_dataclasses.dataclass(eq
=True, frozen
=True)
605 class StaticOperand(Operand
):
608 def disassemble(self
, insn
, record
, verbose
=False):
609 span
= record
.fields
[self
.name
]
610 if isinstance(insn
, SVP64Instruction
):
611 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
615 yield f
"{int(value):0{value.bits}b}"
618 yield str(int(value
))
621 @_dataclasses.dataclass(eq
=True, frozen
=True)
622 class DynamicOperandTargetAddrLI(DynamicOperandReg
):
631 def disassemble(self
, insn
, record
, verbose
=False):
632 span
= record
.fields
["LI"]
633 if isinstance(insn
, SVP64Instruction
):
634 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
638 yield f
"{int(value):0{value.bits}b}"
640 yield "target_addr = EXTS(LI || 0b00))"
642 yield hex(int(_selectconcat(value
,
643 _SelectableInt(value
=0b00, bits
=2))))
646 class DynamicOperandTargetAddrBD(DynamicOperand
):
655 def disassemble(self
, insn
, record
, verbose
=False):
656 span
= record
.fields
["BD"]
657 if isinstance(insn
, SVP64Instruction
):
658 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
662 yield f
"{int(value):0{value.bits}b}"
664 yield "target_addr = EXTS(BD || 0b00))"
666 yield hex(int(_selectconcat(value
,
667 _SelectableInt(value
=0b00, bits
=2))))
670 @_dataclasses.dataclass(eq
=True, frozen
=True)
671 class DynamicOperandGPR(DynamicOperandReg
):
672 def disassemble(self
, insn
, record
, verbose
=False):
673 yield from super().disassemble(prefix
="r",
674 insn
=insn
, record
=record
, verbose
=verbose
)
677 @_dataclasses.dataclass(eq
=True, frozen
=True)
678 class DynamicOperandFPR(DynamicOperandReg
):
679 def disassemble(self
, insn
, record
, verbose
=False):
680 yield from super().disassemble(prefix
="f",
681 insn
=insn
, record
=record
, verbose
=verbose
)
684 class Operands(tuple):
685 def __new__(cls
, insn
, iterable
):
687 "b": {"target_addr": DynamicOperandTargetAddrLI
},
688 "ba": {"target_addr": DynamicOperandTargetAddrLI
},
689 "bl": {"target_addr": DynamicOperandTargetAddrLI
},
690 "bla": {"target_addr": DynamicOperandTargetAddrLI
},
691 "bc": {"target_addr": DynamicOperandTargetAddrBD
},
692 "bca": {"target_addr": DynamicOperandTargetAddrBD
},
693 "bcl": {"target_addr": DynamicOperandTargetAddrBD
},
694 "bcla": {"target_addr": DynamicOperandTargetAddrBD
},
698 for operand
in iterable
:
699 dynamic_cls
= DynamicOperand
700 static_cls
= StaticOperand
703 (name
, value
) = operand
.split("=")
704 operand
= static_cls(name
=name
, value
=int(value
))
705 operands
.append(operand
)
707 if operand
.endswith(")"):
708 operand
= operand
.replace("(", " ").replace(")", "")
709 (immediate
, _
, operand
) = operand
.partition(" ")
713 if immediate
is not None:
714 operands
.append(ImmediateOperand(name
=immediate
))
716 if insn
in branches
and operand
in branches
[insn
]:
717 dynamic_cls
= branches
[insn
][operand
]
719 if operand
in _RegType
.__members
__:
720 regtype
= _RegType
[operand
]
721 if regtype
is _RegType
.GPR
:
722 dynamic_cls
= DynamicOperandGPR
723 elif regtype
is _RegType
.FPR
:
724 dynamic_cls
= DynamicOperandFPR
726 operand
= dynamic_cls(name
=operand
)
727 operands
.append(operand
)
729 return super().__new
__(cls
, operands
)
731 def __contains__(self
, key
):
732 return self
.__getitem
__(key
) is not None
734 def __getitem__(self
, key
):
736 if operand
.name
== key
:
744 if isinstance(operand
, DynamicOperand
):
750 if isinstance(operand
, StaticOperand
):
754 @_functools.total_ordering
755 @_dataclasses.dataclass(eq
=True, frozen
=True)
762 svp64
: SVP64Record
= None
764 def __lt__(self
, other
):
765 if not isinstance(other
, Record
):
766 return NotImplemented
767 return (self
.opcode
< other
.opcode
)
772 if self
.section
.opcode
:
773 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
774 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
776 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
778 for operand
in self
.operands
.static
:
779 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
781 return FieldsOpcode(fields
)
785 return self
.ppc
.function
805 if self
.svp64
is None:
811 return self
.ppc
.cr_in
815 return self
.ppc
.cr_out
817 ptype
= property(lambda self
: self
.svp64
.ptype
)
818 etype
= property(lambda self
: self
.svp64
.etype
)
820 def extra_idx(self
, key
):
821 return self
.svp64
.extra_idx(key
)
823 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
824 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
825 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
826 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
827 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
828 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
829 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
832 class Instruction(_Mapping
):
834 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
835 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
836 raise ValueError(bits
)
838 if isinstance(value
, bytes
):
839 if ((len(value
) * 8) != bits
):
840 raise ValueError(f
"bit length mismatch")
841 value
= int.from_bytes(value
, byteorder
=byteorder
)
843 if isinstance(value
, int):
844 value
= _SelectableInt(value
=value
, bits
=bits
)
845 elif isinstance(value
, Instruction
):
846 value
= value
.storage
848 if not isinstance(value
, _SelectableInt
):
849 raise ValueError(value
)
852 if len(value
) != bits
:
853 raise ValueError(value
)
855 value
= _SelectableInt(value
=value
, bits
=bits
)
857 return cls(storage
=value
)
860 return hash(int(self
))
862 def record(self
, db
):
868 def disassemble(self
, db
, byteorder
="little", verbose
=False):
869 raise NotImplementedError
872 class WordInstruction(Instruction
):
873 _
: _Field
= range(0, 32)
874 po
: _Field
= range(0, 6)
877 def integer(cls
, value
, byteorder
="little"):
878 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
883 for idx
in range(32):
886 return "".join(map(str, bits
))
889 record
= self
.record(db
=db
)
892 dynamic_operands
= []
893 for operand
in record
.operands
.dynamic
:
896 name
= f
"{immediate}({name})"
898 if isinstance(operand
, ImmediateOperand
):
899 immediate
= operand
.name
901 dynamic_operands
.append(name
)
904 for operand
in record
.operands
.static
:
905 static_operands
.append(f
"{operand.name}={operand.value}")
909 operands
+= f
" {','.join(dynamic_operands)}"
911 operands
+= f
" ({' '.join(static_operands)})"
913 return f
"{record.name}{operands}"
915 def opcode(self
, db
):
916 record
= self
.record(db
=db
)
917 return f
"0x{record.opcode.value:08x}"
920 record
= self
.record(db
=db
)
921 return f
"0x{record.opcode.mask:08x}"
923 def disassemble(self
, db
, byteorder
="little", verbose
=False):
925 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
926 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
928 record
= self
.record(db
=db
)
930 yield f
"{blob} .long 0x{integer:08x}"
934 for operand
in record
.operands
.dynamic
:
935 operand
= " ".join(operand
.disassemble(insn
=self
,
936 record
=record
, verbose
=False))
937 operands
.append(operand
)
939 operands
= ",".join(operands
)
940 operands
= f
" {operands}"
944 yield f
"{blob} {record.name}{operands}"
949 spec
= self
.spec(db
=db
)
950 opcode
= self
.opcode(db
=db
)
951 mask
= self
.mask(db
=db
)
952 yield f
"{indent}spec"
953 yield f
"{indent}{indent}{spec}"
954 yield f
"{indent}binary"
955 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
956 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
957 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
958 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
959 yield f
"{indent}opcode"
960 yield f
"{indent}{indent}{opcode}"
961 yield f
"{indent}mask"
962 yield f
"{indent}{indent}{mask}"
963 for operand
in record
.operands
:
965 yield f
"{indent}{name}"
966 parts
= operand
.disassemble(insn
=self
,
967 record
=record
, verbose
=True)
969 yield f
"{indent}{indent}{part}"
973 class PrefixedInstruction(Instruction
):
974 class Prefix(WordInstruction
.remap(range(0, 32))):
977 class Suffix(WordInstruction
.remap(range(32, 64))):
980 _
: _Field
= range(64)
986 def integer(cls
, value
, byteorder
="little"):
987 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
990 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
991 def transform(value
):
992 return WordInstruction
.integer(value
=value
,
993 byteorder
=byteorder
)[0:32]
995 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
996 value
= _selectconcat(prefix
, suffix
)
998 return super().integer(value
=value
)
1001 class Mode(_Mapping
):
1002 _
: _Field
= range(0, 5)
1003 sel
: _Field
= range(0, 2)
1006 class NormalMode(Mode
):
1013 """scalar reduce mode (mapreduce), SUBVL=1"""
1017 """parallel reduce mode (mapreduce), SUBVL=1"""
1021 """subvector reduce mode, SUBVL>1"""
1025 """Pack/Unpack mode, SUBVL>1"""
1029 """Rc=1: ffirst CR sel"""
1034 """Rc=0: ffirst z/nonz"""
1040 """sat mode: N=0/1 u/s, SUBVL=1"""
1046 """sat mode: N=0/1 u/s, SUBVL>1"""
1053 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1060 """Rc=1: pred-result CR sel"""
1065 """Rc=0: pred-result z/nonz"""
1086 class LDSTImmMode(Mode
):
1095 """Structured Pack/Unpack"""
1102 """Rc=1: ffirst CR sel"""
1107 """Rc=0: ffirst z/nonz"""
1113 """sat mode: N=0/1 u/s"""
1121 """Rc=1: pred-result CR sel"""
1126 """Rc=0: pred-result z/nonz"""
1140 class LDSTIdxMode(Mode
):
1148 """strided (scalar only source)"""
1154 """sat mode: N=0/1 u/s"""
1160 """Rc=1: pred-result CR sel"""
1165 """Rc=0: pred-result z/nonz"""
1179 class ExtraSpec(_Mapping
):
1180 _
: _Field
= range(0, 9)
1183 class Extra2Spec(ExtraSpec
):
1184 idx0
: _Field
= range(0, 2)
1185 idx1
: _Field
= range(2, 4)
1186 idx2
: _Field
= range(4, 6)
1187 idx3
: _Field
= range(6, 8)
1189 def __getitem__(self
, key
):
1195 _SVExtra
.Idx0
: self
.idx0
,
1196 _SVExtra
.Idx1
: self
.idx1
,
1197 _SVExtra
.Idx2
: self
.idx2
,
1198 _SVExtra
.Idx3
: self
.idx3
,
1201 def __setitem__(self
, key
, value
):
1202 self
[key
].assign(value
)
1205 class Extra3Spec(ExtraSpec
):
1206 idx0
: _Field
= range(0, 3)
1207 idx1
: _Field
= range(3, 6)
1208 idx2
: _Field
= range(6, 9)
1210 def __getitem__(self
, key
):
1215 _SVExtra
.Idx0
: self
.idx0
,
1216 _SVExtra
.Idx1
: self
.idx1
,
1217 _SVExtra
.Idx2
: self
.idx2
,
1220 def __setitem__(self
, key
, value
):
1221 self
[key
].assign(value
)
1227 ldst_imm
: LDSTImmMode
1228 ldst_idx
: LDSTIdxMode
1230 _
: _Field
= range(24)
1231 mmode
: _Field
= (0,)
1232 mask
: _Field
= range(1, 4)
1233 elwidth
: _Field
= range(4, 6)
1234 ewsrc
: _Field
= range(6, 8)
1235 subvl
: _Field
= range(8, 10)
1236 mode
: Mode
.remap(range(19, 24))
1237 smask
: _Field
= range(16, 19)
1239 extra
: ExtraSpec
.remap(range(10, 19))
1240 extra2
: Extra2Spec
.remap(range(10, 19))
1241 extra3
: Extra3Spec
.remap(range(10, 19))
1244 class SVP64Instruction(PrefixedInstruction
):
1245 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1246 class Prefix(PrefixedInstruction
.Prefix
):
1248 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1255 for idx
in range(64):
1256 bit
= int(self
[idx
])
1258 return "".join(map(str, bits
))
1261 return f
"sv.{self.suffix.spec(db=db)}"
1263 def opcode(self
, db
):
1264 return self
.suffix
.opcode(db
=db
)
1267 return self
.suffix
.mask(db
=db
)
1270 record
= self
.record(db
=db
)
1273 if record
.operands
["Rc"] is not None:
1274 Rc
= bool(self
[record
.fields
["Rc"]])
1276 record
= self
.record(db
=db
)
1277 subvl
= self
.prefix
.rm
.subvl
1278 mode
= self
.prefix
.rm
.mode
1281 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1315 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1316 mode
= mode
.ldst_imm
1334 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1335 mode
= mode
.ldst_idx
1336 if mode
.sel
== 0b00:
1338 elif mode
.sel
== 0b01:
1340 elif mode
.sel
== 0b10:
1342 elif mode
.sel
== 0b11:
1349 NormalMode
.simple
: "normal: simple",
1350 NormalMode
.smr
: "normal: smr",
1351 NormalMode
.pmr
: "normal: pmr",
1352 NormalMode
.svmr
: "normal: svmr",
1353 NormalMode
.pu
: "normal: pu",
1354 NormalMode
.ffrc1
: "normal: ffrc1",
1355 NormalMode
.ffrc0
: "normal: ffrc0",
1356 NormalMode
.sat
: "normal: sat",
1357 NormalMode
.satx
: "normal: satx",
1358 NormalMode
.satpu
: "normal: satpu",
1359 NormalMode
.prrc1
: "normal: prrc1",
1360 NormalMode
.prrc0
: "normal: prrc0",
1361 LDSTImmMode
.simple
: "ld/st imm: simple",
1362 LDSTImmMode
.spu
: "ld/st imm: spu",
1363 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1364 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1365 LDSTImmMode
.sat
: "ld/st imm: sat",
1366 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1367 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1368 LDSTIdxMode
.simple
: "ld/st idx simple",
1369 LDSTIdxMode
.stride
: "ld/st idx stride",
1370 LDSTIdxMode
.sat
: "ld/st idx sat",
1371 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1372 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1374 for (cls
, desc
) in modes
.items():
1375 if isinstance(mode
, cls
):
1378 if record
.svp64
.mode
is _SVMode
.BRANCH
:
1379 return (self
.prefix
.rm
.mode
, "branch")
1381 raise ValueError(self
)
1383 def disassemble(self
, db
, byteorder
="little", verbose
=False):
1384 integer_prefix
= int(self
.prefix
)
1385 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
1386 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
1388 integer_suffix
= int(self
.suffix
)
1389 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
1390 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
1392 record
= self
.record(db
=db
)
1393 if record
is None or record
.svp64
is None:
1394 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
1395 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
1399 for operand
in record
.operands
.dynamic
:
1400 operand
= " ".join(operand
.disassemble(insn
=self
,
1401 record
=record
, verbose
=False))
1402 operands
.append(operand
)
1404 operands
= ",".join(operands
)
1405 operands
= f
" {operands}"
1409 yield f
"{blob_prefix} sv.{record.name}{operands}"
1410 yield f
"{blob_suffix}"
1412 (mode
, mode_desc
) = self
.mode(db
=db
)
1416 binary
= self
.binary
1417 spec
= self
.spec(db
=db
)
1418 opcode
= self
.opcode(db
=db
)
1419 mask
= self
.mask(db
=db
)
1420 yield f
"{indent}spec"
1421 yield f
"{indent}{indent}{spec}"
1422 yield f
"{indent}binary"
1423 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1424 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1425 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1426 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1427 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1428 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1429 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1430 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1431 yield f
"{indent}opcode"
1432 yield f
"{indent}{indent}{opcode}"
1433 yield f
"{indent}mask"
1434 yield f
"{indent}{indent}{mask}"
1435 for operand
in record
.operands
:
1437 yield f
"{indent}{name}"
1438 parts
= operand
.disassemble(insn
=self
,
1439 record
=record
, verbose
=True)
1441 yield f
"{indent}{indent}{part}"
1443 yield f
"{indent}mode"
1444 yield f
"{indent}{indent}{mode_desc}"
1448 def parse(stream
, factory
):
1450 return ("TODO" not in frozenset(entry
.values()))
1452 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1453 entries
= _csv
.DictReader(lines
)
1454 entries
= filter(match
, entries
)
1455 return tuple(map(factory
, entries
))
1458 class MarkdownDatabase
:
1461 for (name
, desc
) in _ISA():
1464 (dynamic
, *static
) = desc
.regs
1465 operands
.extend(dynamic
)
1466 operands
.extend(static
)
1467 db
[name
] = Operands(insn
=name
, iterable
=operands
)
1469 return super().__init
__()
1472 yield from self
.__db
.items()
1474 def __getitem__(self
, key
):
1475 return self
.__db
.__getitem
__(key
)
1478 class FieldsDatabase
:
1481 df
= _DecodeFields()
1483 for (form
, fields
) in df
.instrs
.items():
1484 if form
in {"DQE", "TX"}:
1488 db
[_Form
[form
]] = Fields(fields
)
1492 return super().__init
__()
1494 def __getitem__(self
, key
):
1495 return self
.__db
.__getitem
__(key
)
1499 def __init__(self
, root
, mdwndb
):
1500 # The code below groups the instructions by section:identifier.
1501 # We use the comment as an identifier, there's nothing better.
1502 # The point is to capture different opcodes for the same instruction.
1503 dd
= _collections
.defaultdict
1504 records
= dd(lambda: dd(set))
1505 path
= (root
/ "insndb.csv")
1506 with
open(path
, "r", encoding
="UTF-8") as stream
:
1507 for section
in parse(stream
, Section
.CSV
):
1508 path
= (root
/ section
.path
)
1510 section
.Mode
.INTEGER
: IntegerOpcode
,
1511 section
.Mode
.PATTERN
: PatternOpcode
,
1513 factory
= _functools
.partial(
1514 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1515 with
open(path
, "r", encoding
="UTF-8") as stream
:
1516 for insn
in parse(stream
, factory
):
1517 records
[section
][insn
.comment
].add(insn
)
1520 for (section
, group
) in records
.items():
1521 for records
in group
.values():
1522 db
[section
].add(PPCMultiRecord(records
))
1525 self
.__mdwndb
= mdwndb
1527 return super().__init
__()
1529 def __getitem__(self
, key
):
1530 def exact_match(key
, record
):
1531 for name
in record
.names
:
1537 def Rc_match(key
, record
):
1538 if not key
.endswith("."):
1541 if not record
.Rc
is _RCOE
.RC
:
1544 return exact_match(key
[:-1], record
)
1546 def LK_match(key
, record
):
1547 if not key
.endswith("l"):
1550 if "lk" not in record
.flags
:
1553 return exact_match(key
[:-1], record
)
1555 def AA_match(key
, record
):
1556 if not key
.endswith("a"):
1559 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1562 if self
.__mdwndb
[key
]["AA"] is None:
1565 return (exact_match(key
[:-1], record
) or
1566 LK_match(key
[:-1], record
))
1568 for (section
, records
) in self
.__db
.items():
1569 for record
in records
:
1570 if exact_match(key
, record
):
1571 return (section
, record
)
1573 for record
in records
:
1574 if (Rc_match(key
, record
) or
1575 LK_match(key
, record
) or
1576 AA_match(key
, record
)):
1577 return (section
, record
)
1582 class SVP64Database
:
1583 def __init__(self
, root
, ppcdb
):
1585 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1586 for (prefix
, _
, names
) in _os
.walk(root
):
1587 prefix
= _pathlib
.Path(prefix
)
1588 for name
in filter(lambda name
: pattern
.match(name
), names
):
1589 path
= (prefix
/ _pathlib
.Path(name
))
1590 with
open(path
, "r", encoding
="UTF-8") as stream
:
1591 db
.update(parse(stream
, SVP64Record
.CSV
))
1593 self
.__db
= {record
.name
:record
for record
in db
}
1594 self
.__ppcdb
= ppcdb
1596 return super().__init
__()
1598 def __getitem__(self
, key
):
1599 (_
, record
) = self
.__ppcdb
[key
]
1603 for name
in record
.names
:
1604 record
= self
.__db
.get(name
, None)
1605 if record
is not None:
1612 def __init__(self
, root
):
1613 root
= _pathlib
.Path(root
)
1615 mdwndb
= MarkdownDatabase()
1616 fieldsdb
= FieldsDatabase()
1617 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1618 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1621 for (name
, operands
) in mdwndb
:
1622 (section
, ppc
) = ppcdb
[name
]
1625 svp64
= svp64db
[name
]
1626 fields
= fieldsdb
[ppc
.form
]
1627 record
= Record(name
=name
,
1628 section
=section
, ppc
=ppc
, svp64
=svp64
,
1629 operands
=operands
, fields
=fields
)
1632 self
.__db
= tuple(sorted(db
))
1634 return super().__init
__()
1637 return repr(self
.__db
)
1640 yield from self
.__db
1642 @_functools.lru_cache(maxsize
=None)
1643 def __contains__(self
, key
):
1644 return self
.__getitem
__(key
) is not None
1646 @_functools.lru_cache(maxsize
=None)
1647 def __getitem__(self
, key
):
1648 if isinstance(key
, (int, Instruction
)):
1651 opcode
= record
.opcode
1652 if ((opcode
.value
& opcode
.mask
) ==
1653 (key
& opcode
.mask
)):
1656 elif isinstance(key
, Opcode
):
1658 if record
.opcode
== key
:
1660 elif isinstance(key
, str):
1662 if record
.name
== key
: