1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
6 import itertools
as _itertools
8 import operator
as _operator
9 import pathlib
as _pathlib
13 from functools
import cached_property
15 from cached_property
import cached_property
17 from openpower
.decoder
.power_enums
import (
18 Function
as _Function
,
25 CRIn2Sel
as _CRIn2Sel
,
26 CROutSel
as _CROutSel
,
28 LDSTMode
as _LDSTMode
,
33 SVmask_src
as _SVmask_src
,
38 SVExtraRegType
as _SVExtraRegType
,
39 SVExtraReg
as _SVExtraReg
,
41 from openpower
.decoder
.selectable_int
import (
42 SelectableInt
as _SelectableInt
,
43 selectconcat
as _selectconcat
,
45 from openpower
.decoder
.power_fields
import (
48 DecodeFields
as _DecodeFields
,
50 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
53 @_functools.total_ordering
54 class Verbosity(_enum
.Enum
):
57 VERBOSE
= _enum
.auto()
59 def __lt__(self
, other
):
60 if not isinstance(other
, self
.__class
__):
62 return (self
.value
< other
.value
)
65 def dataclass(cls
, record
, keymap
=None, typemap
=None):
69 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
71 def transform(key_value
):
72 (key
, value
) = key_value
73 key
= keymap
.get(key
, key
)
74 hook
= typemap
.get(key
, lambda value
: value
)
75 if hook
is bool and value
in ("", "0"):
81 record
= dict(map(transform
, record
.items()))
82 for key
in frozenset(record
.keys()):
89 @_functools.total_ordering
90 @_dataclasses.dataclass(eq
=True, frozen
=True)
93 def __new__(cls
, value
):
94 if isinstance(value
, str):
96 if not isinstance(value
, int):
97 raise ValueError(value
)
99 if value
.bit_length() > 64:
100 raise ValueError(value
)
102 return super().__new
__(cls
, value
)
105 return super().__repr
__()
108 return f
"{self:0{self.bit_length()}b}"
110 def bit_length(self
):
111 if super().bit_length() > 32:
115 class Value(Integer
):
124 def __lt__(self
, other
):
125 if not isinstance(other
, Opcode
):
126 return NotImplemented
127 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
129 def __post_init__(self
):
130 if self
.value
.bit_length() != self
.mask
.bit_length():
131 raise ValueError("bit length mismatch")
134 def pattern(value
, mask
, bit_length
):
135 for bit
in range(bit_length
):
136 if ((mask
& (1 << (bit_length
- bit
- 1))) == 0):
138 elif (value
& (1 << (bit_length
- bit
- 1))):
143 return "".join(pattern(self
.value
, self
.mask
, self
.value
.bit_length()))
146 class IntegerOpcode(Opcode
):
147 def __init__(self
, value
):
148 if value
.startswith("0b"):
149 mask
= int(("1" * len(value
[2:])), 2)
153 value
= Opcode
.Value(value
)
154 mask
= Opcode
.Mask(mask
)
156 return super().__init
__(value
=value
, mask
=mask
)
159 class PatternOpcode(Opcode
):
160 def __init__(self
, pattern
):
161 if not isinstance(pattern
, str):
162 raise ValueError(pattern
)
164 (value
, mask
) = (0, 0)
165 for symbol
in pattern
:
166 if symbol
not in {"0", "1", "-"}:
167 raise ValueError(pattern
)
168 value |
= (symbol
== "1")
169 mask |
= (symbol
!= "-")
175 value
= Opcode
.Value(value
)
176 mask
= Opcode
.Mask(mask
)
178 return super().__init
__(value
=value
, mask
=mask
)
181 @_dataclasses.dataclass(eq
=True, frozen
=True)
183 class FlagsMeta(type):
198 class Flags(frozenset, metaclass
=FlagsMeta
):
199 def __new__(cls
, flags
=frozenset()):
200 flags
= frozenset(flags
)
201 diff
= (flags
- frozenset(cls
))
203 raise ValueError(flags
)
204 return super().__new
__(cls
, flags
)
208 flags
: Flags
= Flags()
210 function
: _Function
= _Function
.NONE
211 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
212 in1
: _In1Sel
= _In1Sel
.RA
213 in2
: _In2Sel
= _In2Sel
.NONE
214 in3
: _In3Sel
= _In3Sel
.NONE
215 out
: _OutSel
= _OutSel
.NONE
216 cr_in
: _CRInSel
= _CRInSel
.NONE
217 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
218 cr_out
: _CROutSel
= _CROutSel
.NONE
219 cry_in
: _CryIn
= _CryIn
.ZERO
220 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
221 upd
: _LDSTMode
= _LDSTMode
.NONE
222 Rc
: _RCOE
= _RCOE
.NONE
223 form
: _Form
= _Form
.NONE
225 unofficial
: bool = False
229 "internal op": "intop",
233 "ldst len": "ldst_len",
235 "CONDITIONS": "conditions",
238 def __lt__(self
, other
):
239 if not isinstance(other
, self
.__class
__):
240 return NotImplemented
241 lhs
= (self
.opcode
, self
.comment
)
242 rhs
= (other
.opcode
, other
.comment
)
246 def CSV(cls
, record
, opcode_cls
):
247 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
248 typemap
["opcode"] = opcode_cls
250 if record
["CR in"] == "BA_BB":
251 record
["cr_in"] = "BA"
252 record
["cr_in2"] = "BB"
256 for flag
in frozenset(PPCRecord
.Flags
):
257 if bool(record
.pop(flag
, "")):
259 record
["flags"] = PPCRecord
.Flags(flags
)
261 return dataclass(cls
, record
,
262 keymap
=PPCRecord
.__KEYMAP
,
267 return frozenset(self
.comment
.split("=")[-1].split("/"))
270 class PPCMultiRecord(tuple):
271 def __getattr__(self
, attr
):
273 raise AttributeError(attr
)
274 return getattr(self
[0], attr
)
277 @_dataclasses.dataclass(eq
=True, frozen
=True)
279 class ExtraMap(tuple):
281 @_dataclasses.dataclass(eq
=True, frozen
=True)
283 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
284 reg
: _SVExtraReg
= _SVExtraReg
.NONE
287 return f
"{self.regtype.value}:{self.reg.name}"
289 def __new__(cls
, value
="0"):
290 if isinstance(value
, str):
291 def transform(value
):
292 (regtype
, reg
) = value
.split(":")
293 regtype
= _SVExtraRegType(regtype
)
294 reg
= _SVExtraReg(reg
)
295 return cls
.Entry(regtype
=regtype
, reg
=reg
)
300 value
= map(transform
, value
.split(";"))
302 return super().__new
__(cls
, value
)
305 return repr(list(self
))
307 def __new__(cls
, value
=tuple()):
311 return super().__new
__(cls
, map(cls
.Extra
, value
))
314 return repr({index
:self
[index
] for index
in range(0, 4)})
317 ptype
: _SVPtype
= _SVPtype
.NONE
318 etype
: _SVEtype
= _SVEtype
.NONE
319 msrc
: _SVmask_src
= _SVmask_src
.NO
# MASK_SRC is active
320 in1
: _In1Sel
= _In1Sel
.NONE
321 in2
: _In2Sel
= _In2Sel
.NONE
322 in3
: _In3Sel
= _In3Sel
.NONE
323 out
: _OutSel
= _OutSel
.NONE
324 out2
: _OutSel
= _OutSel
.NONE
325 cr_in
: _CRInSel
= _CRInSel
.NONE
326 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
327 cr_out
: _CROutSel
= _CROutSel
.NONE
328 extra
: ExtraMap
= ExtraMap()
330 mode
: _SVMode
= _SVMode
.NORMAL
334 "CONDITIONS": "conditions",
343 def CSV(cls
, record
):
344 for key
in frozenset({
345 "in1", "in2", "in3", "CR in",
346 "out", "out2", "CR out",
352 if record
["CR in"] == "BA_BB":
353 record
["cr_in"] = "BA"
354 record
["cr_in2"] = "BB"
358 for idx
in range(0, 4):
359 extra
.append(record
.pop(f
"{idx}"))
361 record
["extra"] = cls
.ExtraMap(extra
)
363 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
365 @_functools.lru_cache(maxsize
=None)
366 def extra_idx(self
, key
):
374 if key
not in frozenset({
375 "in1", "in2", "in3", "cr_in", "cr_in2",
376 "out", "out2", "cr_out",
380 sel
= getattr(self
, key
)
381 if sel
is _CRInSel
.BA_BB
:
382 return _SVExtra
.Idx_1_2
383 reg
= _SVExtraReg(sel
)
384 if reg
is _SVExtraReg
.NONE
:
388 _SVExtraRegType
.SRC
: {},
389 _SVExtraRegType
.DST
: {},
391 for index
in range(0, 4):
392 for entry
in self
.extra
[index
]:
393 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
395 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
396 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
397 if extra
is not _SVExtra
.NONE
:
402 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
403 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
404 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
405 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
406 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
407 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
408 extra_idx_cr_in2
= property(_functools
.partial(extra_idx
, key
="cr_in2"))
409 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
411 @_functools.lru_cache(maxsize
=None)
412 def extra_reg(self
, key
):
413 return _SVExtraReg(getattr(self
, key
))
415 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
416 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
417 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
418 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
419 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
420 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
421 extra_reg_cr_in2
= property(_functools
.partial(extra_reg
, key
="cr_in2"))
422 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
426 def __init__(self
, value
=(0, 32)):
427 if isinstance(value
, str):
428 (start
, end
) = map(int, value
.split(":"))
431 if start
< 0 or end
< 0 or start
>= end
:
432 raise ValueError(value
)
437 return super().__init
__()
440 return f
"[{self.__start}:{self.__end}]"
443 yield from range(self
.start
, (self
.end
+ 1))
445 def __reversed__(self
):
446 return tuple(reversed(tuple(self
)))
457 @_dataclasses.dataclass(eq
=True, frozen
=True)
459 class Mode(_enum
.Enum
):
460 INTEGER
= _enum
.auto()
461 PATTERN
= _enum
.auto()
464 def _missing_(cls
, value
):
465 if isinstance(value
, str):
466 return cls
[value
.upper()]
467 return super()._missing
_(value
)
470 def __new__(cls
, value
=None):
471 if isinstance(value
, str):
472 if value
.upper() == "NONE":
475 value
= int(value
, 0)
479 return super().__new
__(cls
, value
)
485 return (bin(self
) if self
else "None")
491 opcode
: IntegerOpcode
= None
494 def CSV(cls
, record
):
495 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
496 if record
["opcode"] == "NONE":
497 typemap
["opcode"] = lambda _
: None
499 return dataclass(cls
, record
, typemap
=typemap
)
503 def __init__(self
, items
):
504 if isinstance(items
, dict):
505 items
= items
.items()
508 (name
, bitrange
) = item
509 return (name
, tuple(bitrange
.values()))
511 self
.__mapping
= dict(map(transform
, items
))
513 return super().__init
__()
516 return repr(self
.__mapping
)
519 yield from self
.__mapping
.items()
521 def __contains__(self
, key
):
522 return self
.__mapping
.__contains
__(key
)
524 def __getitem__(self
, key
):
525 return self
.__mapping
.get(key
, None)
528 @_dataclasses.dataclass(eq
=True, frozen
=True)
532 def span(self
, record
):
533 return record
.fields
[self
.name
]
535 def disassemble(self
, insn
, record
,
536 verbosity
=Verbosity
.NORMAL
, indent
=""):
537 raise NotImplementedError
540 class DynamicOperand(Operand
):
541 def disassemble(self
, insn
, record
,
542 verbosity
=Verbosity
.NORMAL
, indent
=""):
543 span
= self
.span(record
=record
)
544 if isinstance(insn
, SVP64Instruction
):
545 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
548 if verbosity
>= Verbosity
.VERBOSE
:
549 span
= map(str, span
)
550 yield f
"{indent}{self.name}"
551 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
552 yield f
"{indent}{indent}{', '.join(span)}"
554 yield str(int(value
))
557 class SignedOperand(DynamicOperand
):
558 def disassemble(self
, insn
, record
,
559 verbosity
=Verbosity
.NORMAL
, indent
=""):
560 span
= self
.span(record
=record
)
561 if isinstance(insn
, SVP64Instruction
):
562 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
565 if verbosity
>= Verbosity
.VERBOSE
:
566 span
= map(str, span
)
567 yield f
"{indent}{self.name}"
568 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
569 yield f
"{indent}{indent}{', '.join(span)}"
571 yield str(value
.to_signed_int())
574 @_dataclasses.dataclass(eq
=True, frozen
=True)
575 class StaticOperand(Operand
):
578 def disassemble(self
, insn
, record
,
579 verbosity
=Verbosity
.NORMAL
, indent
=""):
580 span
= self
.span(record
=record
)
581 if isinstance(insn
, SVP64Instruction
):
582 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
585 if verbosity
>= Verbosity
.VERBOSE
:
586 span
= map(str, span
)
587 yield f
"{indent}{self.name}"
588 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
589 yield f
"{indent}{indent}{', '.join(span)}"
591 yield str(int(value
))
594 class ImmediateOperand(DynamicOperand
):
598 class NonZeroOperand(DynamicOperand
):
599 def disassemble(self
, insn
, record
,
600 verbosity
=Verbosity
.NORMAL
, indent
=""):
601 span
= self
.span(record
=record
)
602 if isinstance(insn
, SVP64Instruction
):
603 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
606 if verbosity
>= Verbosity
.VERBOSE
:
607 span
= map(str, span
)
608 yield f
"{indent}{self.name}"
609 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
610 yield f
"{indent}{indent}{', '.join(span)}"
612 yield str(int(value
) + 1)
615 class RegisterOperand(DynamicOperand
):
616 def sv_spec_enter(self
, value
, span
):
619 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
622 def spec(self
, insn
, record
):
624 span
= self
.span(record
=record
)
625 if isinstance(insn
, SVP64Instruction
):
626 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
628 span
= tuple(map(str, span
))
630 if isinstance(insn
, SVP64Instruction
):
631 (origin_value
, origin_span
) = (value
, span
)
632 (value
, span
) = self
.sv_spec_enter(value
=value
, span
=span
)
634 extra_idx
= self
.extra_idx(record
=record
)
635 if extra_idx
is _SVExtra
.NONE
:
636 return (vector
, value
, span
)
638 if record
.etype
is _SVEtype
.EXTRA3
:
639 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
640 elif record
.etype
is _SVEtype
.EXTRA2
:
641 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
643 raise ValueError(record
.etype
)
646 vector
= bool(spec
[0])
647 spec_span
= spec
.__class
__
648 if record
.etype
is _SVEtype
.EXTRA3
:
649 spec_span
= tuple(map(str, spec_span
[1, 2]))
651 elif record
.etype
is _SVEtype
.EXTRA2
:
652 spec_span
= tuple(map(str, spec_span
[1,]))
653 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
656 spec_span
= (spec_span
+ ("{0}",))
658 spec_span
= (("{0}",) + spec_span
)
660 raise ValueError(record
.etype
)
662 vector_shift
= (2 + (5 - value
.bits
))
663 scalar_shift
= value
.bits
664 spec_shift
= (5 - value
.bits
)
666 bits
= (len(span
) + len(spec_span
))
667 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
668 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
670 value
= ((value
<< vector_shift
) |
(spec
<< spec_shift
))
671 span
= (span
+ spec_span
+ ((spec_shift
* ("{0}",))))
673 value
= ((spec
<< scalar_shift
) | value
)
674 span
= ((spec_shift
* ("{0}",)) + spec_span
+ span
)
676 (value
, span
) = self
.sv_spec_leave(value
=value
, span
=span
,
677 origin_value
=origin_value
, origin_span
=origin_span
)
679 return (vector
, value
, span
)
683 return _SVExtraReg(self
.name
)
685 def extra_idx(self
, record
):
686 for key
in frozenset({
687 "in1", "in2", "in3", "cr_in", "cr_in2",
688 "out", "out2", "cr_out",
690 extra_reg
= record
.svp64
.extra_reg(key
=key
)
691 if extra_reg
is self
.extra_reg
:
692 return record
.extra_idx(key
=key
)
696 def disassemble(self
, insn
, record
,
697 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
698 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
700 if verbosity
>= Verbosity
.VERBOSE
:
701 mode
= "vector" if vector
else "scalar"
702 yield f
"{indent}{self.name} ({mode})"
703 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
704 yield f
"{indent}{indent}{', '.join(span)}"
705 if isinstance(insn
, SVP64Instruction
):
706 extra_idx
= self
.extra_idx(record
)
707 if record
.etype
is _SVEtype
.NONE
:
708 yield f
"{indent}{indent}extra[none]"
710 etype
= repr(record
.etype
).lower()
711 yield f
"{indent}{indent}{etype}{extra_idx!r}"
713 vector
= "*" if vector
else ""
714 yield f
"{vector}{prefix}{int(value)}"
717 class GPROperand(RegisterOperand
):
718 def disassemble(self
, insn
, record
,
719 verbosity
=Verbosity
.NORMAL
, indent
=""):
720 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
721 yield from super().disassemble(prefix
=prefix
,
722 insn
=insn
, record
=record
,
723 verbosity
=verbosity
, indent
=indent
)
726 class FPROperand(RegisterOperand
):
727 def disassemble(self
, insn
, record
,
728 verbosity
=Verbosity
.NORMAL
, indent
=""):
729 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
730 yield from super().disassemble(prefix
=prefix
,
731 insn
=insn
, record
=record
,
732 verbosity
=verbosity
, indent
=indent
)
735 class CR3Operand(RegisterOperand
):
739 class CR5Operand(RegisterOperand
):
740 def sv_spec_enter(self
, value
, span
):
741 value
= _SelectableInt(value
=(value
.value
>> 2), bits
=3)
744 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
745 value
= _selectconcat(value
, origin_value
[3:5])
750 class EXTSOperand(RegisterOperand
):
751 n_zeros
: int # number of zeros - set through constructor override
752 d_field
: str # field name to report - ditto
753 hex_out
: bool # set to indicate whether format is 0xNNN or decimal NNN
755 def span(self
, record
):
756 return record
.fields
[self
.d_field
]
758 def disassemble(self
, insn
, record
, verbosity
=Verbosity
.NORMAL
, indent
=""):
759 span
= self
.span(record
=record
)
760 if isinstance(insn
, SVP64Instruction
):
761 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
764 if verbosity
>= Verbosity
.VERBOSE
:
765 span
= (tuple(map(str, span
)) + ("{0}",)*self
.n_zeros
)
766 z
= "0" * self
.n_zeros
767 yield indent
+ "%s = EXTS(%s || 0b%s)" % (self
.name
, self
.d_field
, z
)
768 yield indent
* 2 + self
.d_field
769 yield indent
* 3 + f
"{int(value):0{value.bits}b}" + z
770 yield indent
* 3 + ', '.join(span
)
772 value
= _selectconcat(value
,
773 _SelectableInt(value
=0, bits
=self
.n_zeros
)).to_signed_int()
780 class TargetAddrOperand(EXTSOperand
):
781 """set up TargetAddrOperand as an EXTSOperand with 2 leading zeros
783 def __init__(self
, *args
, **kwargs
): # no idea what the args are
786 super().__init
__(*args
, **kwargs
)
789 class TargetAddrOperandLI(TargetAddrOperand
):
790 def __init__(self
, *args
, **kwargs
): # no idea what the args are
792 super().__init
__(*args
, **kwargs
)
795 class TargetAddrOperandBD(TargetAddrOperand
):
796 def __init__(self
, *args
, **kwargs
): # no idea what the args are
798 super().__init
__(*args
, **kwargs
)
801 # inherit from ImmediateOperand as well in order to pass "isinstance" test
802 class EXTSOperandDS(EXTSOperand
, ImmediateOperand
):
803 def __init__(self
, *args
, **kwargs
): # no idea what the args are
807 super().__init
__(*args
, **kwargs
)
810 # inherit from ImmediateOperand as well in order to pass "isinstance" test
811 class EXTSOperandDQ(EXTSOperand
, ImmediateOperand
):
812 def __init__(self
, *args
, **kwargs
): # no idea what the args are
816 super().__init
__(*args
, **kwargs
)
819 class DOperandDX(SignedOperand
):
820 def span(self
, record
):
821 operands
= map(DynamicOperand
, ("d0", "d1", "d2"))
822 spans
= map(lambda operand
: operand
.span(record
=record
), operands
)
823 return sum(spans
, tuple())
825 def disassemble(self
, insn
, record
,
826 verbosity
=Verbosity
.NORMAL
, indent
=""):
827 span
= self
.span(record
=record
)
828 if isinstance(insn
, SVP64Instruction
):
829 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
832 if verbosity
>= Verbosity
.VERBOSE
:
839 for (subname
, subspan
) in mapping
.items():
840 operand
= DynamicOperand(name
=subname
)
841 span
= operand
.span(record
=record
)
842 if isinstance(insn
, SVP64Instruction
):
843 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
845 span
= map(str, span
)
846 yield f
"{indent}{indent}{operand.name} = D{subspan}"
847 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}"
848 yield f
"{indent}{indent}{indent}{', '.join(span)}"
850 yield str(value
.to_signed_int())
853 class Operands(tuple):
854 def __new__(cls
, insn
, iterable
):
856 "b": {"target_addr": TargetAddrOperandLI
},
857 "ba": {"target_addr": TargetAddrOperandLI
},
858 "bl": {"target_addr": TargetAddrOperandLI
},
859 "bla": {"target_addr": TargetAddrOperandLI
},
860 "bc": {"target_addr": TargetAddrOperandBD
},
861 "bca": {"target_addr": TargetAddrOperandBD
},
862 "bcl": {"target_addr": TargetAddrOperandBD
},
863 "bcla": {"target_addr": TargetAddrOperandBD
},
864 "addpcis": {"D": DOperandDX
},
865 "fishmv": {"D": DOperandDX
},
866 "fmvis": {"D": DOperandDX
},
869 "SVi": NonZeroOperand
,
870 "SVd": NonZeroOperand
,
871 "SVxd": NonZeroOperand
,
872 "SVyd": NonZeroOperand
,
873 "SVzd": NonZeroOperand
,
875 "D": SignedOperand
, # TODO, make a SignedImmediate class?
879 "SIM": SignedOperand
,
880 "SVD": SignedOperand
,
881 "SVDS": SignedOperand
,
883 custom_immediates
= {
889 for operand
in iterable
:
890 dynamic_cls
= DynamicOperand
891 static_cls
= StaticOperand
894 (name
, value
) = operand
.split("=")
895 operand
= static_cls(name
=name
, value
=int(value
))
896 operands
.append(operand
)
898 if operand
.endswith(")"):
899 operand
= operand
.replace("(", " ").replace(")", "")
900 (immediate
, _
, operand
) = operand
.partition(" ")
904 if immediate
is not None:
905 if immediate
in custom_immediates
:
906 dynamic_cls
= custom_immediates
[immediate
]
907 operands
.append(dynamic_cls(name
=immediate
))
909 operands
.append(ImmediateOperand(name
=immediate
))
911 if operand
in custom_fields
:
912 dynamic_cls
= custom_fields
[operand
]
913 if insn
in custom_insns
and operand
in custom_insns
[insn
]:
914 dynamic_cls
= custom_insns
[insn
][operand
]
916 if operand
in _RegType
.__members
__:
917 regtype
= _RegType
[operand
]
918 if regtype
is _RegType
.GPR
:
919 dynamic_cls
= GPROperand
920 elif regtype
is _RegType
.FPR
:
921 dynamic_cls
= FPROperand
922 if regtype
is _RegType
.CR_BIT
: # 5-bit
923 dynamic_cls
= CR5Operand
924 if regtype
is _RegType
.CR_REG
: # actually CR Field, 3-bit
925 dynamic_cls
= CR3Operand
927 operand
= dynamic_cls(name
=operand
)
928 operands
.append(operand
)
930 return super().__new
__(cls
, operands
)
932 def __contains__(self
, key
):
933 return self
.__getitem
__(key
) is not None
935 def __getitem__(self
, key
):
937 if operand
.name
== key
:
945 if isinstance(operand
, DynamicOperand
):
951 if isinstance(operand
, StaticOperand
):
956 def __init__(self
, iterable
):
957 self
.__pcode
= tuple(iterable
)
958 return super().__init
__()
961 yield from self
.__pcode
964 return self
.__pcode
.__repr
__()
967 @_dataclasses.dataclass(eq
=True, frozen
=True)
968 class MarkdownRecord
:
973 @_functools.total_ordering
974 @_dataclasses.dataclass(eq
=True, frozen
=True)
981 svp64
: SVP64Record
= None
983 def __lt__(self
, other
):
984 if not isinstance(other
, Record
):
985 return NotImplemented
986 lhs
= (min(self
.opcodes
), self
.name
)
987 rhs
= (min(other
.opcodes
), other
.name
)
996 PO
= self
.section
.opcode
998 for (src
, dst
) in enumerate(reversed(BitSel((0, 5)))):
999 value
[dst
] = int((PO
.value
& (1 << src
)) != 0)
1000 mask
[dst
] = int((PO
.mask
& (1 << src
)) != 0)
1003 for (src
, dst
) in enumerate(reversed(self
.section
.bitsel
)):
1004 value
[dst
] = int((XO
.value
& (1 << src
)) != 0)
1005 mask
[dst
] = int((XO
.mask
& (1 << src
)) != 0)
1007 for operand
in self
.mdwn
.operands
.static
:
1008 for (src
, dst
) in enumerate(reversed(operand
.span(record
=self
))):
1009 value
[dst
] = int((operand
.value
& (1 << src
)) != 0)
1012 value
= Opcode
.Value(int(("".join(map(str, value
))), 2))
1013 mask
= Opcode
.Mask(int(("".join(map(str, mask
))), 2))
1015 return Opcode(value
=value
, mask
=mask
)
1017 return tuple(sorted(map(opcode
, self
.ppc
)))
1019 def match(self
, key
):
1020 for opcode
in self
.opcodes
:
1021 if ((opcode
.value
& opcode
.mask
) ==
1022 (key
& opcode
.mask
)):
1028 return self
.svp64
.mode
1048 if self
.svp64
is None:
1054 return self
.ppc
.cr_in
1058 return self
.ppc
.cr_in2
1062 return self
.ppc
.cr_out
1064 ptype
= property(lambda self
: self
.svp64
.ptype
)
1065 etype
= property(lambda self
: self
.svp64
.etype
)
1067 def extra_idx(self
, key
):
1068 return self
.svp64
.extra_idx(key
)
1070 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
1071 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
1072 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
1073 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
1074 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
1075 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
1076 extra_idx_cr_in2
= property(lambda self
: self
.svp64
.extra_idx_cr_in2
)
1077 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
1081 Rc
= self
.mdwn
.operands
["Rc"]
1084 return bool(Rc
.value
)
1086 class Instruction(_Mapping
):
1088 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
1089 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
1090 raise ValueError(bits
)
1092 if isinstance(value
, bytes
):
1093 if ((len(value
) * 8) != bits
):
1094 raise ValueError(f
"bit length mismatch")
1095 value
= int.from_bytes(value
, byteorder
=byteorder
)
1097 if isinstance(value
, int):
1098 value
= _SelectableInt(value
=value
, bits
=bits
)
1099 elif isinstance(value
, Instruction
):
1100 value
= value
.storage
1102 if not isinstance(value
, _SelectableInt
):
1103 raise ValueError(value
)
1106 if len(value
) != bits
:
1107 raise ValueError(value
)
1109 value
= _SelectableInt(value
=value
, bits
=bits
)
1111 return cls(storage
=value
)
1114 return hash(int(self
))
1116 def __getitem__(self
, key
):
1117 return self
.storage
.__getitem
__(key
)
1119 def __setitem__(self
, key
, value
):
1120 return self
.storage
.__setitem
__(key
, value
)
1122 def bytes(self
, byteorder
="little"):
1123 nr_bytes
= (self
.storage
.bits
// 8)
1124 return int(self
).to_bytes(nr_bytes
, byteorder
=byteorder
)
1126 def record(self
, db
):
1129 raise KeyError(self
)
1132 def spec(self
, db
, prefix
):
1133 record
= self
.record(db
=db
)
1135 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1136 self
.dynamic_operands(db
=db
)))
1138 static_operands
= []
1139 for (name
, value
) in self
.static_operands(db
=db
):
1140 static_operands
.append(f
"{name}={value}")
1143 if dynamic_operands
:
1145 operands
+= ",".join(dynamic_operands
)
1148 operands
+= " ".join(static_operands
)
1150 return f
"{prefix}{record.name}{operands}"
1152 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1153 record
= self
.record(db
=db
)
1158 for operand
in record
.mdwn
.operands
.dynamic
:
1160 dis
= operand
.disassemble(insn
=self
, record
=record
,
1161 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1162 value
= " ".join(dis
)
1164 name
= f
"{imm_name}({name})"
1165 value
= f
"{imm_value}({value})"
1167 if isinstance(operand
, ImmediateOperand
):
1174 def static_operands(self
, db
):
1175 record
= self
.record(db
=db
)
1176 for operand
in record
.mdwn
.operands
.static
:
1177 yield (operand
.name
, operand
.value
)
1179 def disassemble(self
, db
,
1181 verbosity
=Verbosity
.NORMAL
):
1182 raise NotImplementedError
1185 class WordInstruction(Instruction
):
1186 _
: _Field
= range(0, 32)
1187 po
: _Field
= range(0, 6)
1190 def integer(cls
, value
, byteorder
="little"):
1191 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1196 for idx
in range(32):
1197 bit
= int(self
[idx
])
1199 return "".join(map(str, bits
))
1201 def disassemble(self
, db
,
1203 verbosity
=Verbosity
.NORMAL
):
1205 if verbosity
<= Verbosity
.SHORT
:
1208 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1209 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1214 yield f
"{blob}.long 0x{integer:08x}"
1217 operands
= tuple(map(_operator
.itemgetter(1),
1218 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1220 operands
= ",".join(operands
)
1221 yield f
"{blob}{record.name} {operands}"
1223 yield f
"{blob}{record.name}"
1225 if verbosity
>= Verbosity
.VERBOSE
:
1227 binary
= self
.binary
1228 spec
= self
.spec(db
=db
, prefix
="")
1229 yield f
"{indent}spec"
1230 yield f
"{indent}{indent}{spec}"
1231 yield f
"{indent}pcode"
1232 for stmt
in record
.mdwn
.pcode
:
1233 yield f
"{indent}{indent}{stmt}"
1234 yield f
"{indent}binary"
1235 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1236 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1237 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1238 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1239 yield f
"{indent}opcodes"
1240 for opcode
in record
.opcodes
:
1241 yield f
"{indent}{indent}{opcode!r}"
1242 for operand
in record
.mdwn
.operands
:
1243 yield from operand
.disassemble(insn
=self
, record
=record
,
1244 verbosity
=verbosity
, indent
=indent
)
1248 class PrefixedInstruction(Instruction
):
1249 class Prefix(WordInstruction
.remap(range(0, 32))):
1252 class Suffix(WordInstruction
.remap(range(32, 64))):
1255 _
: _Field
= range(64)
1261 def integer(cls
, value
, byteorder
="little"):
1262 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1265 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1266 def transform(value
):
1267 return WordInstruction
.integer(value
=value
,
1268 byteorder
=byteorder
)[0:32]
1270 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1271 value
= _selectconcat(prefix
, suffix
)
1273 return super().integer(bits
=64, value
=value
)
1276 class Mode(_Mapping
):
1277 _
: _Field
= range(0, 5)
1280 class Extra(_Mapping
):
1281 _
: _Field
= range(0, 9)
1284 class Extra2(Extra
):
1285 idx0
: _Field
= range(0, 2)
1286 idx1
: _Field
= range(2, 4)
1287 idx2
: _Field
= range(4, 6)
1288 idx3
: _Field
= range(6, 8)
1290 def __getitem__(self
, key
):
1296 _SVExtra
.Idx0
: self
.idx0
,
1297 _SVExtra
.Idx1
: self
.idx1
,
1298 _SVExtra
.Idx2
: self
.idx2
,
1299 _SVExtra
.Idx3
: self
.idx3
,
1302 def __setitem__(self
, key
, value
):
1303 self
[key
].assign(value
)
1306 class Extra3(Extra
):
1307 idx0
: _Field
= range(0, 3)
1308 idx1
: _Field
= range(3, 6)
1309 idx2
: _Field
= range(6, 9)
1311 def __getitem__(self
, key
):
1316 _SVExtra
.Idx0
: self
.idx0
,
1317 _SVExtra
.Idx1
: self
.idx1
,
1318 _SVExtra
.Idx2
: self
.idx2
,
1321 def __setitem__(self
, key
, value
):
1322 self
[key
].assign(value
)
1325 class BaseRM(_Mapping
):
1326 _
: _Field
= range(24)
1327 mmode
: _Field
= (0,)
1328 mask
: _Field
= range(1, 4)
1329 elwidth
: _Field
= range(4, 6)
1330 ewsrc
: _Field
= range(6, 8)
1331 subvl
: _Field
= range(8, 10)
1332 mode
: Mode
.remap(range(19, 24))
1333 smask
: _Field
= range(16, 19)
1334 extra
: Extra
.remap(range(10, 19))
1335 extra2
: Extra2
.remap(range(10, 19))
1336 extra3
: Extra3
.remap(range(10, 19))
1338 def specifiers(self
, record
):
1339 subvl
= int(self
.subvl
)
1347 def disassemble(self
, verbosity
=Verbosity
.NORMAL
):
1348 if verbosity
>= Verbosity
.VERBOSE
:
1350 for (name
, span
) in self
.traverse(path
="RM"):
1351 value
= self
.storage
[span
]
1353 yield f
"{indent}{int(value):0{value.bits}b}"
1354 yield f
"{indent}{', '.join(map(str, span))}"
1357 class FFPRRc1BaseRM(BaseRM
):
1358 def specifiers(self
, record
, mode
):
1359 inv
= _SelectableInt(value
=int(self
.inv
), bits
=1)
1360 CR
= _SelectableInt(value
=int(self
.CR
), bits
=2)
1361 mask
= int(_selectconcat(CR
, inv
))
1362 predicate
= PredicateBaseRM
.predicate(True, mask
)
1363 yield f
"{mode}={predicate}"
1365 yield from super().specifiers(record
=record
)
1368 class FFPRRc0BaseRM(BaseRM
):
1369 def specifiers(self
, record
, mode
):
1371 inv
= "~" if self
.inv
else ""
1372 yield f
"{mode}={inv}RC1"
1374 yield from super().specifiers(record
=record
)
1377 class SatBaseRM(BaseRM
):
1378 def specifiers(self
, record
):
1384 yield from super().specifiers(record
=record
)
1387 class ZZBaseRM(BaseRM
):
1388 def specifiers(self
, record
):
1392 yield from super().specifiers(record
=record
)
1395 class DZBaseRM(BaseRM
):
1396 def specifiers(self
, record
):
1400 yield from super().specifiers(record
=record
)
1403 class SZBaseRM(BaseRM
):
1404 def specifiers(self
, record
):
1408 yield from super().specifiers(record
=record
)
1411 class MRBaseRM(BaseRM
):
1412 def specifiers(self
, record
):
1418 yield from super().specifiers(record
=record
)
1421 class ElsBaseRM(BaseRM
):
1422 def specifiers(self
, record
):
1426 yield from super().specifiers(record
=record
)
1429 class WidthBaseRM(BaseRM
):
1431 def width(FP
, width
):
1440 width
= ("fp" + width
)
1443 def specifiers(self
, record
):
1444 # elwidths: use "w=" if same otherwise dw/sw
1445 # FIXME this should consider FP instructions
1447 dw
= WidthBaseRM
.width(FP
, int(self
.elwidth
))
1448 sw
= WidthBaseRM
.width(FP
, int(self
.ewsrc
))
1457 yield from super().specifiers(record
=record
)
1460 class PredicateBaseRM(BaseRM
):
1462 def predicate(CR
, mask
):
1465 (False, 0b001): "1<<r3",
1466 (False, 0b010): "r3",
1467 (False, 0b011): "~r3",
1468 (False, 0b100): "r10",
1469 (False, 0b101): "~r10",
1470 (False, 0b110): "r30",
1471 (False, 0b111): "~r30",
1473 (True, 0b000): "lt",
1474 (True, 0b001): "ge",
1475 (True, 0b010): "gt",
1476 (True, 0b011): "le",
1477 (True, 0b100): "eq",
1478 (True, 0b101): "ne",
1479 (True, 0b110): "so",
1480 (True, 0b111): "ns",
1483 def specifiers(self
, record
):
1484 # predication - single and twin
1485 # use "m=" if same otherwise sm/dm
1486 CR
= (int(self
.mmode
) == 1)
1487 mask
= int(self
.mask
)
1488 sm
= dm
= PredicateBaseRM
.predicate(CR
, mask
)
1489 if record
.svp64
.ptype
is _SVPtype
.P2
:
1490 smask
= int(self
.smask
)
1491 sm
= PredicateBaseRM
.predicate(CR
, smask
)
1500 yield from super().specifiers(record
=record
)
1503 class PredicateWidthBaseRM(WidthBaseRM
, PredicateBaseRM
):
1507 class SEABaseRM(BaseRM
):
1508 def specifiers(self
, record
):
1512 yield from super().specifiers(record
=record
)
1515 class VLiBaseRM(BaseRM
):
1516 def specifiers(self
, record
):
1520 yield from super().specifiers(record
=record
)
1523 class NormalBaseRM(PredicateWidthBaseRM
):
1526 https://libre-soc.org/openpower/sv/normal/
1531 class NormalSimpleRM(DZBaseRM
, SZBaseRM
, NormalBaseRM
):
1532 """normal: simple mode"""
1536 def specifiers(self
, record
):
1537 yield from super().specifiers(record
=record
)
1540 class NormalMRRM(MRBaseRM
, NormalBaseRM
):
1541 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
1545 class NormalFFRc1RM(FFPRRc1BaseRM
, NormalBaseRM
):
1546 """normal: Rc=1: ffirst CR sel"""
1548 CR
: BaseRM
.mode
[3, 4]
1550 def specifiers(self
, record
):
1551 yield from super().specifiers(record
=record
, mode
="ff")
1554 class NormalFFRc0RM(FFPRRc0BaseRM
, VLiBaseRM
, NormalBaseRM
):
1555 """normal: Rc=0: ffirst z/nonz"""
1560 def specifiers(self
, record
):
1561 yield from super().specifiers(record
=record
, mode
="ff")
1564 class NormalSatRM(SatBaseRM
, DZBaseRM
, SZBaseRM
, NormalBaseRM
):
1565 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
1571 class NormalPRRc1RM(FFPRRc1BaseRM
, NormalBaseRM
):
1572 """normal: Rc=1: pred-result CR sel"""
1574 CR
: BaseRM
.mode
[3, 4]
1576 def specifiers(self
, record
):
1577 yield from super().specifiers(record
=record
, mode
="pr")
1580 class NormalPRRc0RM(FFPRRc0BaseRM
, ZZBaseRM
, NormalBaseRM
):
1581 """normal: Rc=0: pred-result z/nonz"""
1588 def specifiers(self
, record
):
1589 yield from super().specifiers(record
=record
, mode
="pr")
1592 class NormalRM(NormalBaseRM
):
1593 simple
: NormalSimpleRM
1595 ffrc1
: NormalFFRc1RM
1596 ffrc0
: NormalFFRc0RM
1598 prrc1
: NormalPRRc1RM
1599 prrc0
: NormalPRRc0RM
1602 class LDSTImmBaseRM(PredicateWidthBaseRM
):
1604 LD/ST Immediate mode
1605 https://libre-soc.org/openpower/sv/ldst/
1610 class LDSTImmSimpleRM(ElsBaseRM
, ZZBaseRM
, LDSTImmBaseRM
):
1611 """ld/st immediate: simple mode"""
1618 class LDSTImmPostRM(LDSTImmBaseRM
):
1619 """ld/st immediate: postinc mode (and load-fault)"""
1620 pi
: BaseRM
.mode
[3] # Post-Increment Mode
1621 lf
: BaseRM
.mode
[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
1623 def specifiers(self
, record
):
1630 class LDSTImmFFRc1RM(FFPRRc1BaseRM
, LDSTImmBaseRM
):
1631 """ld/st immediate: Rc=1: ffirst CR sel"""
1633 CR
: BaseRM
.mode
[3, 4]
1635 def specifiers(self
, record
):
1636 yield from super().specifiers(record
=record
, mode
="ff")
1639 class LDSTImmFFRc0RM(FFPRRc0BaseRM
, ElsBaseRM
, LDSTImmBaseRM
):
1640 """ld/st immediate: Rc=0: ffirst z/nonz"""
1645 def specifiers(self
, record
):
1646 yield from super().specifiers(record
=record
, mode
="ff")
1649 class LDSTImmSatRM(ElsBaseRM
, SatBaseRM
, ZZBaseRM
, LDSTImmBaseRM
):
1650 """ld/st immediate: sat mode: N=0/1 u/s"""
1658 class LDSTImmPRRc1RM(FFPRRc1BaseRM
, LDSTImmBaseRM
):
1659 """ld/st immediate: Rc=1: pred-result CR sel"""
1661 CR
: BaseRM
.mode
[3, 4]
1663 def specifiers(self
, record
):
1664 yield from super().specifiers(record
=record
, mode
="pr")
1667 class LDSTImmPRRc0RM(FFPRRc0BaseRM
, ElsBaseRM
, LDSTImmBaseRM
):
1668 """ld/st immediate: Rc=0: pred-result z/nonz"""
1673 def specifiers(self
, record
):
1674 yield from super().specifiers(record
=record
, mode
="pr")
1677 class LDSTImmRM(LDSTImmBaseRM
):
1678 simple
: LDSTImmSimpleRM
1680 ffrc1
: LDSTImmFFRc1RM
1681 ffrc0
: LDSTImmFFRc0RM
1683 prrc1
: LDSTImmPRRc1RM
1684 prrc0
: LDSTImmPRRc0RM
1687 class LDSTIdxBaseRM(PredicateWidthBaseRM
):
1690 https://libre-soc.org/openpower/sv/ldst/
1695 class LDSTIdxSimpleRM(SEABaseRM
, DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1696 """ld/st index: simple mode"""
1702 class LDSTIdxStrideRM(SEABaseRM
, DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1703 """ld/st index: strided (scalar only source)"""
1708 def specifiers(self
, record
):
1711 yield from super().specifiers(record
=record
)
1714 class LDSTIdxSatRM(SatBaseRM
, DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1715 """ld/st index: sat mode: N=0/1 u/s"""
1721 class LDSTIdxPRRc1RM(LDSTIdxBaseRM
):
1722 """ld/st index: Rc=1: pred-result CR sel"""
1724 CR
: BaseRM
.mode
[3, 4]
1726 def specifiers(self
, record
):
1727 yield from super().specifiers(record
=record
, mode
="pr")
1730 class LDSTIdxPRRc0RM(FFPRRc0BaseRM
, ZZBaseRM
, LDSTIdxBaseRM
):
1731 """ld/st index: Rc=0: pred-result z/nonz"""
1738 def specifiers(self
, record
):
1739 yield from super().specifiers(record
=record
, mode
="pr")
1742 class LDSTIdxRM(LDSTIdxBaseRM
):
1743 simple
: LDSTIdxSimpleRM
1744 stride
: LDSTIdxStrideRM
1746 prrc1
: LDSTIdxPRRc1RM
1747 prrc0
: LDSTIdxPRRc0RM
1751 class CROpBaseRM(BaseRM
):
1754 https://libre-soc.org/openpower/sv/cr_ops/
1759 class CROpSimpleRM(PredicateBaseRM
, DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1760 """cr_op: simple mode"""
1765 def specifiers(self
, record
):
1767 yield "rg" # simple CR Mode reports /rg
1769 yield from super().specifiers(record
=record
)
1771 class CROpMRRM(MRBaseRM
, DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1772 """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
1778 class CROpFF3RM(FFPRRc1BaseRM
, VLiBaseRM
, ZZBaseRM
, PredicateBaseRM
, CROpBaseRM
):
1779 """cr_op: ffirst 3-bit mode"""
1787 def specifiers(self
, record
):
1788 yield from super().specifiers(record
=record
, mode
="ff")
1791 class CROpFF5RM(FFPRRc0BaseRM
, PredicateBaseRM
,
1792 VLiBaseRM
, DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1793 """cr_op: ffirst 5-bit mode"""
1796 RC1
: BaseRM
[19] # cheat: set RC=1 based on ffirst mode being set
1800 def specifiers(self
, record
):
1801 yield from super().specifiers(record
=record
, mode
="ff")
1804 class CROpRM(CROpBaseRM
):
1805 simple
: CROpSimpleRM
1811 # ********************
1813 # https://libre-soc.org/openpower/sv/branches/
1814 class BranchBaseRM(BaseRM
):
1824 def specifiers(self
, record
):
1836 raise ValueError(self
.sz
)
1848 # Branch modes lack source mask.
1849 # Therefore a custom code is needed.
1850 CR
= (int(self
.mmode
) == 1)
1851 mask
= int(self
.mask
)
1852 m
= PredicateBaseRM
.predicate(CR
, mask
)
1856 yield from super().specifiers(record
=record
)
1859 class BranchSimpleRM(BranchBaseRM
):
1860 """branch: simple mode"""
1864 class BranchVLSRM(BranchBaseRM
):
1865 """branch: VLSET mode"""
1869 def specifiers(self
, record
):
1875 }[int(self
.VSb
), int(self
.VLi
)]
1877 yield from super().specifiers(record
=record
)
1880 class BranchCTRRM(BranchBaseRM
):
1881 """branch: CTR-test mode"""
1884 def specifiers(self
, record
):
1890 yield from super().specifiers(record
=record
)
1893 class BranchCTRVLSRM(BranchVLSRM
, BranchCTRRM
):
1894 """branch: CTR-test+VLSET mode"""
1898 class BranchRM(BranchBaseRM
):
1899 simple
: BranchSimpleRM
1902 ctrvls
: BranchCTRVLSRM
1912 def select(self
, record
):
1916 # the idea behind these tables is that they are now literally
1917 # in identical format to insndb.csv and minor_xx.csv and can
1918 # be done precisely as that. the only thing to watch out for
1919 # is the insertion of Rc=1 as a "mask/value" bit and likewise
1920 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
1923 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1924 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1925 # mode Rc mask Rc member
1927 (0b000000, 0b111000, "simple"), # simple (no Rc)
1928 (0b001000, 0b111000, "mr"), # mapreduce (no Rc)
1929 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1930 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1931 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1932 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1933 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1936 search
= ((int(rm
.mode
) << 1) | Rc
)
1938 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1939 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1940 # mode Rc mask Rc member
1941 # ironically/coincidentally this table is identical to NORMAL
1942 # mode except reserved in place of mr
1944 (0b000000, 0b111000, "simple"), # simple (no Rc)
1945 (0b001000, 0b111000, "post"), # post (no Rc)
1946 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1947 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1948 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1949 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1950 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1953 search
= ((int(rm
.mode
) << 1) | Rc
)
1955 elif record
.svp64
.mode
is _SVMode
.LDST_IDX
:
1956 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1957 # mode Rc mask Rc member
1959 (0b000000, 0b110000, "simple"), # simple (no Rc)
1960 (0b010000, 0b110000, "stride"), # strided, (no Rc)
1961 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1962 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1963 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1966 search
= ((int(rm
.mode
) << 1) | Rc
)
1968 elif record
.svp64
.mode
is _SVMode
.CROP
:
1969 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
1970 # mode 3b mask 3b member
1972 (0b000000, 0b111000, "simple"), # simple
1973 (0b001000, 0b111000, "mr"), # mapreduce
1974 (0b100001, 0b100001, "ff3"), # failfirst, 3-bit CR
1975 (0b100000, 0b100000, "ff5"), # failfirst, 5-bit CR
1977 # determine CR type, 5-bit (BA/BB/BT) or 3-bit Field (BF/BFA)
1979 for idx
in range(0, 4):
1980 for entry
in record
.svp64
.extra
[idx
]:
1981 if entry
.regtype
is _SVExtraRegType
.DST
:
1982 if regtype
is not None:
1983 raise ValueError(record
.svp64
)
1984 regtype
= _RegType(entry
.reg
)
1985 if regtype
is _RegType
.CR_REG
:
1987 elif regtype
is _RegType
.CR_BIT
:
1990 raise ValueError(record
.svp64
)
1991 # finally provide info for search
1993 search
= ((int(rm
.mode
) << 1) |
(regtype
or 0))
1995 elif record
.svp64
.mode
is _SVMode
.BRANCH
:
1999 (0b00, 0b11, "simple"), # simple
2000 (0b01, 0b11, "vls"), # VLset
2001 (0b10, 0b11, "ctr"), # CTR mode
2002 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
2004 # slightly weird: doesn't have a 5-bit "mode" field like others
2006 search
= int(rm
.mode
[0, 1])
2009 if table
is not None:
2010 for (value
, mask
, member
) in table
:
2011 if ((value
& mask
) == (search
& mask
)):
2012 rm
= getattr(rm
, member
)
2015 if rm
.__class
__ is self
.__class
__:
2016 raise ValueError(self
)
2021 class SVP64Instruction(PrefixedInstruction
):
2022 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
2023 class Prefix(PrefixedInstruction
.Prefix
):
2025 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
2029 def record(self
, db
):
2030 record
= db
[self
.suffix
]
2032 raise KeyError(self
)
2038 for idx
in range(64):
2039 bit
= int(self
[idx
])
2041 return "".join(map(str, bits
))
2043 def disassemble(self
, db
,
2045 verbosity
=Verbosity
.NORMAL
):
2047 if verbosity
<= Verbosity
.SHORT
:
2050 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
2051 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
2054 record
= self
.record(db
=db
)
2055 blob_prefix
= blob(int(self
.prefix
))
2056 blob_suffix
= blob(int(self
.suffix
))
2057 if record
is None or record
.svp64
is None:
2058 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
2059 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
2062 name
= f
"sv.{record.name}"
2064 rm
= self
.prefix
.rm
.select(record
=record
)
2066 # convert specifiers to /x/y/z (sorted lexicographically)
2067 specifiers
= sorted(rm
.specifiers(record
=record
))
2068 if specifiers
: # if any add one extra to get the extra "/"
2069 specifiers
= ([""] + specifiers
)
2070 specifiers
= "/".join(specifiers
)
2072 # convert operands to " ,x,y,z"
2073 operands
= tuple(map(_operator
.itemgetter(1),
2074 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
2075 operands
= ",".join(operands
)
2076 if len(operands
) > 0: # if any separate with a space
2077 operands
= (" " + operands
)
2079 yield f
"{blob_prefix}{name}{specifiers}{operands}"
2081 yield f
"{blob_suffix}"
2083 if verbosity
>= Verbosity
.VERBOSE
:
2085 binary
= self
.binary
2086 spec
= self
.spec(db
=db
, prefix
="sv.")
2088 yield f
"{indent}spec"
2089 yield f
"{indent}{indent}{spec}"
2090 yield f
"{indent}pcode"
2091 for stmt
in record
.mdwn
.pcode
:
2092 yield f
"{indent}{indent}{stmt}"
2093 yield f
"{indent}binary"
2094 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
2095 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
2096 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
2097 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
2098 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
2099 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
2100 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
2101 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
2102 yield f
"{indent}opcodes"
2103 for opcode
in record
.opcodes
:
2104 yield f
"{indent}{indent}{opcode!r}"
2105 for operand
in record
.mdwn
.operands
:
2106 yield from operand
.disassemble(insn
=self
, record
=record
,
2107 verbosity
=verbosity
, indent
=indent
)
2109 yield f
"{indent}{indent}{rm.__doc__}"
2110 for line
in rm
.disassemble(verbosity
=verbosity
):
2111 yield f
"{indent}{indent}{line}"
2115 def parse(stream
, factory
):
2117 return ("TODO" not in frozenset(entry
.values()))
2119 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
2120 entries
= _csv
.DictReader(lines
)
2121 entries
= filter(match
, entries
)
2122 return tuple(map(factory
, entries
))
2125 class MarkdownDatabase
:
2128 for (name
, desc
) in _ISA():
2131 (dynamic
, *static
) = desc
.regs
2132 operands
.extend(dynamic
)
2133 operands
.extend(static
)
2134 pcode
= PCode(iterable
=desc
.pcode
)
2135 operands
= Operands(insn
=name
, iterable
=operands
)
2136 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
2138 self
.__db
= dict(sorted(db
.items()))
2140 return super().__init
__()
2143 yield from self
.__db
.items()
2145 def __contains__(self
, key
):
2146 return self
.__db
.__contains
__(key
)
2148 def __getitem__(self
, key
):
2149 return self
.__db
.__getitem
__(key
)
2152 class FieldsDatabase
:
2155 df
= _DecodeFields()
2157 for (form
, fields
) in df
.instrs
.items():
2158 if form
in {"DQE", "TX"}:
2162 db
[_Form
[form
]] = Fields(fields
)
2166 return super().__init
__()
2168 def __getitem__(self
, key
):
2169 return self
.__db
.__getitem
__(key
)
2173 def __init__(self
, root
, mdwndb
):
2174 # The code below groups the instructions by name:section.
2175 # There can be multiple names for the same instruction.
2176 # The point is to capture different opcodes for the same instruction.
2177 dd
= _collections
.defaultdict
2179 records
= _collections
.defaultdict(set)
2180 path
= (root
/ "insndb.csv")
2181 with
open(path
, "r", encoding
="UTF-8") as stream
:
2182 for section
in parse(stream
, Section
.CSV
):
2183 path
= (root
/ section
.path
)
2185 section
.Mode
.INTEGER
: IntegerOpcode
,
2186 section
.Mode
.PATTERN
: PatternOpcode
,
2188 factory
= _functools
.partial(
2189 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
2190 with
open(path
, "r", encoding
="UTF-8") as stream
:
2191 for insn
in parse(stream
, factory
):
2192 for name
in insn
.names
:
2193 records
[name
].add(insn
)
2194 sections
[name
] = section
2196 for (name
, multirecord
) in sorted(records
.items()):
2197 multirecord
= PPCMultiRecord(sorted(multirecord
))
2198 records
[name
] = multirecord
2200 def exact_match(name
):
2201 record
= records
.get(name
)
2207 if not name
.endswith("l"):
2209 alias
= exact_match(name
[:-1])
2212 record
= records
[alias
]
2213 if "lk" not in record
.flags
:
2214 raise ValueError(record
)
2218 if not name
.endswith("a"):
2220 alias
= LK_match(name
[:-1])
2223 record
= records
[alias
]
2224 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
2225 raise ValueError(record
)
2226 operands
= mdwndb
[name
].operands
["AA"]
2227 if operands
is None:
2228 raise ValueError(record
)
2232 if not name
.endswith("."):
2234 alias
= exact_match(name
[:-1])
2237 record
= records
[alias
]
2238 if record
.Rc
is _RCOE
.NONE
:
2239 raise ValueError(record
)
2243 matches
= (exact_match
, LK_match
, AA_match
, Rc_match
)
2244 for (name
, _
) in mdwndb
:
2246 for match
in matches
:
2248 if alias
is not None:
2252 section
= sections
[alias
]
2253 record
= records
[alias
]
2254 db
[name
] = (section
, record
)
2256 self
.__db
= dict(sorted(db
.items()))
2258 return super().__init
__()
2260 @_functools.lru_cache(maxsize
=512, typed
=False)
2261 def __getitem__(self
, key
):
2262 return self
.__db
.get(key
, (None, None))
2265 class SVP64Database
:
2266 def __init__(self
, root
, ppcdb
):
2268 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
2269 for (prefix
, _
, names
) in _os
.walk(root
):
2270 prefix
= _pathlib
.Path(prefix
)
2271 for name
in filter(lambda name
: pattern
.match(name
), names
):
2272 path
= (prefix
/ _pathlib
.Path(name
))
2273 with
open(path
, "r", encoding
="UTF-8") as stream
:
2274 db
.update(parse(stream
, SVP64Record
.CSV
))
2275 db
= {record
.name
:record
for record
in db
}
2277 self
.__db
= dict(sorted(db
.items()))
2278 self
.__ppcdb
= ppcdb
2280 return super().__init
__()
2282 def __getitem__(self
, key
):
2283 (_
, record
) = self
.__ppcdb
[key
]
2287 for name
in record
.names
:
2288 record
= self
.__db
.get(name
, None)
2289 if record
is not None:
2296 def __init__(self
, root
):
2297 root
= _pathlib
.Path(root
)
2298 mdwndb
= MarkdownDatabase()
2299 fieldsdb
= FieldsDatabase()
2300 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
2301 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
2305 opcodes
= _collections
.defaultdict(set)
2307 for (name
, mdwn
) in mdwndb
:
2308 (section
, ppc
) = ppcdb
[name
]
2311 svp64
= svp64db
[name
]
2312 fields
= fieldsdb
[ppc
.form
]
2313 record
= Record(name
=name
,
2314 section
=section
, ppc
=ppc
, svp64
=svp64
,
2315 mdwn
=mdwn
, fields
=fields
)
2317 names
[record
.name
] = record
2321 opcodes
[PO
.value
].add(record
)
2323 self
.__db
= sorted(db
)
2324 self
.__names
= dict(sorted(names
.items()))
2325 self
.__opcodes
= dict(sorted(opcodes
.items()))
2327 return super().__init
__()
2330 return repr(self
.__db
)
2333 yield from self
.__db
2335 @_functools.lru_cache(maxsize
=None)
2336 def __contains__(self
, key
):
2337 return self
.__getitem
__(key
) is not None
2339 @_functools.lru_cache(maxsize
=None)
2340 def __getitem__(self
, key
):
2341 # specific hunt for all "extra.csv" matches. TODO: separate db of extras
2342 if isinstance(key
, Instruction
):
2344 for k
, records
in self
.__opcodes
.items():
2345 for record
in records
:
2346 if str(record
.section
.path
).endswith("extra.csv"):
2347 if record
.match(key
=ki
):
2349 # now look by XO-match, first, which is much better sorted.
2350 # not in major.csv (e.g. 17 which is in extra.csv) already done above
2351 if isinstance(key
, (int, Instruction
)):
2353 XO
= int(_SelectableInt(value
=int(key
), bits
=32)[0:6])
2354 assert XO
in self
.__opcodes
# should have been caught by extra.csv
2355 for record
in self
.__opcodes
[XO
]:
2356 if record
.match(key
=key
):
2358 # hunt by string instead
2359 elif isinstance(key
, str):
2360 return self
.__names
[key
]