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",
239 def CSV(cls
, record
, opcode_cls
):
240 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
241 typemap
["opcode"] = opcode_cls
243 if record
["CR in"] == "BA_BB":
244 record
["cr_in"] = "BA"
245 record
["cr_in2"] = "BB"
249 for flag
in frozenset(PPCRecord
.Flags
):
250 if bool(record
.pop(flag
, "")):
252 record
["flags"] = PPCRecord
.Flags(flags
)
254 return dataclass(cls
, record
,
255 keymap
=PPCRecord
.__KEYMAP
,
260 return frozenset(self
.comment
.split("=")[-1].split("/"))
263 class PPCMultiRecord(tuple):
264 def __getattr__(self
, attr
):
266 raise AttributeError(attr
)
267 return getattr(self
[0], attr
)
270 @_dataclasses.dataclass(eq
=True, frozen
=True)
272 class ExtraMap(tuple):
274 @_dataclasses.dataclass(eq
=True, frozen
=True)
276 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
277 reg
: _SVExtraReg
= _SVExtraReg
.NONE
280 return f
"{self.regtype.value}:{self.reg.name}"
282 def __new__(cls
, value
="0"):
283 if isinstance(value
, str):
284 def transform(value
):
285 (regtype
, reg
) = value
.split(":")
286 regtype
= _SVExtraRegType(regtype
)
287 reg
= _SVExtraReg(reg
)
288 return cls
.Entry(regtype
=regtype
, reg
=reg
)
293 value
= map(transform
, value
.split(";"))
295 return super().__new
__(cls
, value
)
298 return repr(list(self
))
300 def __new__(cls
, value
=tuple()):
304 return super().__new
__(cls
, map(cls
.Extra
, value
))
307 return repr({index
:self
[index
] for index
in range(0, 4)})
310 ptype
: _SVPtype
= _SVPtype
.NONE
311 etype
: _SVEtype
= _SVEtype
.NONE
312 msrc
: _SVmask_src
= _SVmask_src
.NO
# MASK_SRC is active
313 in1
: _In1Sel
= _In1Sel
.NONE
314 in2
: _In2Sel
= _In2Sel
.NONE
315 in3
: _In3Sel
= _In3Sel
.NONE
316 out
: _OutSel
= _OutSel
.NONE
317 out2
: _OutSel
= _OutSel
.NONE
318 cr_in
: _CRInSel
= _CRInSel
.NONE
319 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
320 cr_out
: _CROutSel
= _CROutSel
.NONE
321 extra
: ExtraMap
= ExtraMap()
323 mode
: _SVMode
= _SVMode
.NORMAL
327 "CONDITIONS": "conditions",
336 def CSV(cls
, record
):
337 for key
in frozenset({
338 "in1", "in2", "in3", "CR in",
339 "out", "out2", "CR out",
345 if record
["CR in"] == "BA_BB":
346 record
["cr_in"] = "BA"
347 record
["cr_in2"] = "BB"
351 for idx
in range(0, 4):
352 extra
.append(record
.pop(f
"{idx}"))
354 record
["extra"] = cls
.ExtraMap(extra
)
356 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
358 @_functools.lru_cache(maxsize
=None)
359 def extra_idx(self
, key
):
367 if key
not in frozenset({
368 "in1", "in2", "in3", "cr_in", "cr_in2",
369 "out", "out2", "cr_out",
373 sel
= getattr(self
, key
)
374 if sel
is _CRInSel
.BA_BB
:
375 return _SVExtra
.Idx_1_2
376 reg
= _SVExtraReg(sel
)
377 if reg
is _SVExtraReg
.NONE
:
381 _SVExtraRegType
.SRC
: {},
382 _SVExtraRegType
.DST
: {},
384 for index
in range(0, 4):
385 for entry
in self
.extra
[index
]:
386 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
388 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
389 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
390 if extra
is not _SVExtra
.NONE
:
395 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
396 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
397 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
398 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
399 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
400 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
401 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
403 @_functools.lru_cache(maxsize
=None)
404 def extra_reg(self
, key
):
405 return _SVExtraReg(getattr(self
, key
))
407 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
408 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
409 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
410 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
411 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
412 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
413 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
417 def __init__(self
, value
=(0, 32)):
418 if isinstance(value
, str):
419 (start
, end
) = map(int, value
.split(":"))
422 if start
< 0 or end
< 0 or start
>= end
:
423 raise ValueError(value
)
428 return super().__init
__()
431 return f
"[{self.__start}:{self.__end}]"
434 yield from range(self
.start
, (self
.end
+ 1))
436 def __reversed__(self
):
437 return tuple(reversed(tuple(self
)))
448 @_dataclasses.dataclass(eq
=True, frozen
=True)
450 class Mode(_enum
.Enum
):
451 INTEGER
= _enum
.auto()
452 PATTERN
= _enum
.auto()
455 def _missing_(cls
, value
):
456 if isinstance(value
, str):
457 return cls
[value
.upper()]
458 return super()._missing
_(value
)
461 def __new__(cls
, value
=None):
462 if isinstance(value
, str):
463 if value
.upper() == "NONE":
466 value
= int(value
, 0)
470 return super().__new
__(cls
, value
)
476 return (bin(self
) if self
else "None")
482 opcode
: IntegerOpcode
= None
485 def CSV(cls
, record
):
486 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
487 if record
["opcode"] == "NONE":
488 typemap
["opcode"] = lambda _
: None
490 return dataclass(cls
, record
, typemap
=typemap
)
494 def __init__(self
, items
):
495 if isinstance(items
, dict):
496 items
= items
.items()
499 (name
, bitrange
) = item
500 return (name
, tuple(bitrange
.values()))
502 self
.__mapping
= dict(map(transform
, items
))
504 return super().__init
__()
507 return repr(self
.__mapping
)
510 yield from self
.__mapping
.items()
512 def __contains__(self
, key
):
513 return self
.__mapping
.__contains
__(key
)
515 def __getitem__(self
, key
):
516 return self
.__mapping
.get(key
, None)
519 @_dataclasses.dataclass(eq
=True, frozen
=True)
523 def span(self
, record
):
524 return record
.fields
[self
.name
]
526 def disassemble(self
, insn
, record
,
527 verbosity
=Verbosity
.NORMAL
, indent
=""):
528 raise NotImplementedError
531 class DynamicOperand(Operand
):
532 def disassemble(self
, insn
, record
,
533 verbosity
=Verbosity
.NORMAL
, indent
=""):
534 span
= self
.span(record
=record
)
535 if isinstance(insn
, SVP64Instruction
):
536 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
539 if verbosity
>= Verbosity
.VERBOSE
:
540 span
= map(str, span
)
541 yield f
"{indent}{self.name}"
542 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
543 yield f
"{indent}{indent}{', '.join(span)}"
545 yield str(int(value
))
548 class SignedOperand(DynamicOperand
):
549 def disassemble(self
, insn
, record
,
550 verbosity
=Verbosity
.NORMAL
, indent
=""):
551 span
= self
.span(record
=record
)
552 if isinstance(insn
, SVP64Instruction
):
553 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
556 if verbosity
>= Verbosity
.VERBOSE
:
557 span
= map(str, span
)
558 yield f
"{indent}{self.name}"
559 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
560 yield f
"{indent}{indent}{', '.join(span)}"
562 yield str(value
.to_signed_int())
565 @_dataclasses.dataclass(eq
=True, frozen
=True)
566 class StaticOperand(Operand
):
569 def disassemble(self
, insn
, record
,
570 verbosity
=Verbosity
.NORMAL
, indent
=""):
571 span
= self
.span(record
=record
)
572 if isinstance(insn
, SVP64Instruction
):
573 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
576 if verbosity
>= Verbosity
.VERBOSE
:
577 span
= map(str, span
)
578 yield f
"{indent}{self.name}"
579 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
580 yield f
"{indent}{indent}{', '.join(span)}"
582 yield str(int(value
))
585 class ImmediateOperand(DynamicOperand
):
589 class NonZeroOperand(DynamicOperand
):
590 def disassemble(self
, insn
, record
,
591 verbosity
=Verbosity
.NORMAL
, indent
=""):
592 span
= self
.span(record
=record
)
593 if isinstance(insn
, SVP64Instruction
):
594 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
597 if verbosity
>= Verbosity
.VERBOSE
:
598 span
= map(str, span
)
599 yield f
"{indent}{self.name}"
600 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
601 yield f
"{indent}{indent}{', '.join(span)}"
603 yield str(int(value
) + 1)
606 class RegisterOperand(DynamicOperand
):
607 def sv_spec_enter(self
, value
, span
):
610 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
613 def spec(self
, insn
, record
):
615 span
= self
.span(record
=record
)
616 if isinstance(insn
, SVP64Instruction
):
617 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
619 span
= tuple(map(str, span
))
621 if isinstance(insn
, SVP64Instruction
):
622 (origin_value
, origin_span
) = (value
, span
)
623 (value
, span
) = self
.sv_spec_enter(value
=value
, span
=span
)
625 extra_idx
= self
.extra_idx(record
=record
)
626 if extra_idx
is _SVExtra
.NONE
:
627 return (vector
, value
, span
)
629 if record
.etype
is _SVEtype
.EXTRA3
:
630 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
631 elif record
.etype
is _SVEtype
.EXTRA2
:
632 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
634 raise ValueError(record
.etype
)
637 vector
= bool(spec
[0])
638 spec_span
= spec
.__class
__
639 if record
.etype
is _SVEtype
.EXTRA3
:
640 spec_span
= tuple(map(str, spec_span
[1, 2]))
642 elif record
.etype
is _SVEtype
.EXTRA2
:
643 spec_span
= tuple(map(str, spec_span
[1,]))
644 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
647 spec_span
= (spec_span
+ ("{0}",))
649 spec_span
= (("{0}",) + spec_span
)
651 raise ValueError(record
.etype
)
653 vector_shift
= (2 + (5 - value
.bits
))
654 scalar_shift
= value
.bits
655 spec_shift
= (5 - value
.bits
)
657 bits
= (len(span
) + len(spec_span
))
658 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
659 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
661 value
= ((value
<< vector_shift
) |
(spec
<< spec_shift
))
662 span
= (span
+ spec_span
+ ((spec_shift
* ('{0}',))))
664 value
= ((spec
<< scalar_shift
) | value
)
665 span
= ((spec_shift
* ('{0}',)) + spec_span
+ span
)
667 (value
, span
) = self
.sv_spec_leave(value
=value
, span
=span
,
668 origin_value
=origin_value
, origin_span
=origin_span
)
670 return (vector
, value
, span
)
674 return _SVExtraReg(self
.name
)
676 def extra_idx(self
, record
):
677 for key
in frozenset({
678 "in1", "in2", "in3", "cr_in", "cr_in2",
679 "out", "out2", "cr_out",
681 extra_reg
= record
.svp64
.extra_reg(key
=key
)
682 if extra_reg
is self
.extra_reg
:
683 return record
.extra_idx(key
=key
)
687 def disassemble(self
, insn
, record
,
688 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
689 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
691 if verbosity
>= Verbosity
.VERBOSE
:
692 mode
= "vector" if vector
else "scalar"
693 yield f
"{indent}{self.name} ({mode})"
694 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
695 yield f
"{indent}{indent}{', '.join(span)}"
696 if isinstance(insn
, SVP64Instruction
):
697 extra_idx
= self
.extra_idx(record
)
698 if record
.etype
is _SVEtype
.NONE
:
699 yield f
"{indent}{indent}extra[none]"
701 etype
= repr(record
.etype
).lower()
702 yield f
"{indent}{indent}{etype}{extra_idx!r}"
704 vector
= "*" if vector
else ""
705 yield f
"{vector}{prefix}{int(value)}"
708 class GPROperand(RegisterOperand
):
709 def disassemble(self
, insn
, record
,
710 verbosity
=Verbosity
.NORMAL
, indent
=""):
711 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
712 yield from super().disassemble(prefix
=prefix
,
713 insn
=insn
, record
=record
,
714 verbosity
=verbosity
, indent
=indent
)
717 class FPROperand(RegisterOperand
):
718 def disassemble(self
, insn
, record
,
719 verbosity
=Verbosity
.NORMAL
, indent
=""):
720 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
721 yield from super().disassemble(prefix
=prefix
,
722 insn
=insn
, record
=record
,
723 verbosity
=verbosity
, indent
=indent
)
726 class CR3Operand(RegisterOperand
):
730 class CR5Operand(RegisterOperand
):
731 def sv_spec_enter(self
, value
, span
):
732 value
= _SelectableInt(value
=(value
.value
>> 2), bits
=3)
735 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
736 value
= _selectconcat(value
, origin_value
[3:5])
741 class TargetAddrOperand(RegisterOperand
):
742 def disassemble(self
, insn
, record
, field
,
743 verbosity
=Verbosity
.NORMAL
, indent
=""):
744 span
= self
.span(record
=record
)
745 if isinstance(insn
, SVP64Instruction
):
746 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
749 if verbosity
>= Verbosity
.VERBOSE
:
750 span
= tuple(map(str, span
))
751 yield f
"{indent}{self.name} = EXTS({field} || 0b00))"
752 yield f
"{indent}{indent}{field}"
753 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
754 yield f
"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
756 yield hex(_selectconcat(value
,
757 _SelectableInt(value
=0b00, bits
=2)).to_signed_int())
760 class TargetAddrOperandLI(TargetAddrOperand
):
761 def span(self
, record
):
762 return record
.fields
["LI"]
764 def disassemble(self
, insn
, record
,
765 verbosity
=Verbosity
.NORMAL
, indent
=""):
766 return super().disassemble(field
="LI",
767 insn
=insn
, record
=record
,
768 verbosity
=verbosity
, indent
=indent
)
771 class TargetAddrOperandBD(TargetAddrOperand
):
772 def span(self
, record
):
773 return record
.fields
["BD"]
775 def disassemble(self
, insn
, record
,
776 verbosity
=Verbosity
.NORMAL
, indent
=""):
777 return super().disassemble(field
="BD",
778 insn
=insn
, record
=record
,
779 verbosity
=verbosity
, indent
=indent
)
782 class DOperandDX(SignedOperand
):
783 def span(self
, record
):
784 operands
= map(DynamicOperand
, ("d0", "d1", "d2"))
785 spans
= map(lambda operand
: operand
.span(record
=record
), operands
)
786 return sum(spans
, tuple())
788 def disassemble(self
, insn
, record
,
789 verbosity
=Verbosity
.NORMAL
, indent
=""):
790 span
= self
.span(record
=record
)
791 if isinstance(insn
, SVP64Instruction
):
792 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
795 if verbosity
>= Verbosity
.VERBOSE
:
802 for (subname
, subspan
) in mapping
.items():
803 operand
= DynamicOperand(name
=subname
)
804 span
= operand
.span(record
=record
)
805 if isinstance(insn
, SVP64Instruction
):
806 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
808 span
= map(str, span
)
809 yield f
"{indent}{indent}{operand.name} = D{subspan}"
810 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}"
811 yield f
"{indent}{indent}{indent}{', '.join(span)}"
813 yield str(value
.to_signed_int())
816 class Operands(tuple):
817 def __new__(cls
, insn
, iterable
):
819 "b": {"target_addr": TargetAddrOperandLI
},
820 "ba": {"target_addr": TargetAddrOperandLI
},
821 "bl": {"target_addr": TargetAddrOperandLI
},
822 "bla": {"target_addr": TargetAddrOperandLI
},
823 "bc": {"target_addr": TargetAddrOperandBD
},
824 "bca": {"target_addr": TargetAddrOperandBD
},
825 "bcl": {"target_addr": TargetAddrOperandBD
},
826 "bcla": {"target_addr": TargetAddrOperandBD
},
827 "addpcis": {"D": DOperandDX
},
828 "fishmv": {"D": DOperandDX
},
829 "fmvis": {"D": DOperandDX
},
832 "SVi": NonZeroOperand
,
833 "SVd": NonZeroOperand
,
834 "SVxd": NonZeroOperand
,
835 "SVyd": NonZeroOperand
,
836 "SVzd": NonZeroOperand
,
844 "SIM": SignedOperand
,
845 "SVD": SignedOperand
,
846 "SVDS": SignedOperand
,
850 for operand
in iterable
:
851 dynamic_cls
= DynamicOperand
852 static_cls
= StaticOperand
855 (name
, value
) = operand
.split("=")
856 operand
= static_cls(name
=name
, value
=int(value
))
857 operands
.append(operand
)
859 if operand
.endswith(")"):
860 operand
= operand
.replace("(", " ").replace(")", "")
861 (immediate
, _
, operand
) = operand
.partition(" ")
865 if immediate
is not None:
866 operands
.append(ImmediateOperand(name
=immediate
))
868 if operand
in custom_fields
:
869 dynamic_cls
= custom_fields
[operand
]
870 if insn
in custom_insns
and operand
in custom_insns
[insn
]:
871 dynamic_cls
= custom_insns
[insn
][operand
]
873 if operand
in _RegType
.__members
__:
874 regtype
= _RegType
[operand
]
875 if regtype
is _RegType
.GPR
:
876 dynamic_cls
= GPROperand
877 elif regtype
is _RegType
.FPR
:
878 dynamic_cls
= FPROperand
879 if regtype
is _RegType
.CR_BIT
: # 5-bit
880 dynamic_cls
= CR5Operand
881 if regtype
is _RegType
.CR_REG
: # actually CR Field, 3-bit
882 dynamic_cls
= CR3Operand
884 operand
= dynamic_cls(name
=operand
)
885 operands
.append(operand
)
887 return super().__new
__(cls
, operands
)
889 def __contains__(self
, key
):
890 return self
.__getitem
__(key
) is not None
892 def __getitem__(self
, key
):
894 if operand
.name
== key
:
902 if isinstance(operand
, DynamicOperand
):
908 if isinstance(operand
, StaticOperand
):
913 def __init__(self
, iterable
):
914 self
.__pcode
= tuple(iterable
)
915 return super().__init
__()
918 yield from self
.__pcode
921 return self
.__pcode
.__repr
__()
924 @_dataclasses.dataclass(eq
=True, frozen
=True)
925 class MarkdownRecord
:
930 @_functools.total_ordering
931 @_dataclasses.dataclass(eq
=True, frozen
=True)
938 svp64
: SVP64Record
= None
940 def __lt__(self
, other
):
941 if not isinstance(other
, Record
):
942 return NotImplemented
943 return (min(self
.opcodes
) < min(other
.opcodes
))
951 PO
= self
.section
.opcode
953 for (src
, dst
) in enumerate(reversed(BitSel((0, 5)))):
954 value
[dst
] = int((PO
.value
& (1 << src
)) != 0)
955 mask
[dst
] = int((PO
.mask
& (1 << src
)) != 0)
958 for (src
, dst
) in enumerate(reversed(self
.section
.bitsel
)):
959 value
[dst
] = int((XO
.value
& (1 << src
)) != 0)
960 mask
[dst
] = int((XO
.mask
& (1 << src
)) != 0)
962 for operand
in self
.mdwn
.operands
.static
:
963 for (src
, dst
) in enumerate(reversed(operand
.span(record
=self
))):
964 value
[dst
] = int((operand
.value
& (1 << src
)) != 0)
967 value
= Opcode
.Value(int(("".join(map(str, value
))), 2))
968 mask
= Opcode
.Mask(int(("".join(map(str, mask
))), 2))
970 return Opcode(value
=value
, mask
=mask
)
972 return tuple(sorted(map(opcode
, self
.ppc
)))
974 def match(self
, key
):
975 for opcode
in self
.opcodes
:
976 if ((opcode
.value
& opcode
.mask
) ==
977 (key
& opcode
.mask
)):
983 return self
.ppc
.function
1003 if self
.svp64
is None:
1009 return self
.ppc
.cr_in
1013 return self
.ppc
.cr_in2
1017 return self
.ppc
.cr_out
1019 ptype
= property(lambda self
: self
.svp64
.ptype
)
1020 etype
= property(lambda self
: self
.svp64
.etype
)
1022 def extra_idx(self
, key
):
1023 return self
.svp64
.extra_idx(key
)
1025 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
1026 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
1027 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
1028 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
1029 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
1030 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
1031 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
1034 class Instruction(_Mapping
):
1036 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
1037 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
1038 raise ValueError(bits
)
1040 if isinstance(value
, bytes
):
1041 if ((len(value
) * 8) != bits
):
1042 raise ValueError(f
"bit length mismatch")
1043 value
= int.from_bytes(value
, byteorder
=byteorder
)
1045 if isinstance(value
, int):
1046 value
= _SelectableInt(value
=value
, bits
=bits
)
1047 elif isinstance(value
, Instruction
):
1048 value
= value
.storage
1050 if not isinstance(value
, _SelectableInt
):
1051 raise ValueError(value
)
1054 if len(value
) != bits
:
1055 raise ValueError(value
)
1057 value
= _SelectableInt(value
=value
, bits
=bits
)
1059 return cls(storage
=value
)
1062 return hash(int(self
))
1064 def __getitem__(self
, key
):
1065 return self
.storage
.__getitem
__(key
)
1067 def __setitem__(self
, key
, value
):
1068 return self
.storage
.__setitem
__(key
, value
)
1070 def bytes(self
, byteorder
="little"):
1071 nr_bytes
= (self
.storage
.bits
// 8)
1072 return int(self
).to_bytes(nr_bytes
, byteorder
=byteorder
)
1074 def record(self
, db
):
1077 raise KeyError(self
)
1080 def spec(self
, db
, prefix
):
1081 record
= self
.record(db
=db
)
1083 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1084 self
.dynamic_operands(db
=db
)))
1086 static_operands
= []
1087 for (name
, value
) in self
.static_operands(db
=db
):
1088 static_operands
.append(f
"{name}={value}")
1091 if dynamic_operands
:
1092 operands
+= f
" {','.join(dynamic_operands)}"
1094 operands
+= f
" ({' '.join(static_operands)})"
1096 return f
"{prefix}{record.name}{operands}"
1098 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1099 record
= self
.record(db
=db
)
1104 for operand
in record
.mdwn
.operands
.dynamic
:
1106 dis
= operand
.disassemble(insn
=self
, record
=record
,
1107 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1108 value
= " ".join(dis
)
1110 name
= f
"{imm_name}({name})"
1111 value
= f
"{imm_value}({value})"
1113 if isinstance(operand
, ImmediateOperand
):
1120 def static_operands(self
, db
):
1121 record
= self
.record(db
=db
)
1122 for operand
in record
.mdwn
.operands
.static
:
1123 yield (operand
.name
, operand
.value
)
1125 def disassemble(self
, db
,
1127 verbosity
=Verbosity
.NORMAL
):
1128 raise NotImplementedError
1131 class WordInstruction(Instruction
):
1132 _
: _Field
= range(0, 32)
1133 po
: _Field
= range(0, 6)
1136 def integer(cls
, value
, byteorder
="little"):
1137 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1142 for idx
in range(32):
1143 bit
= int(self
[idx
])
1145 return "".join(map(str, bits
))
1147 def disassemble(self
, db
,
1149 verbosity
=Verbosity
.NORMAL
):
1151 if verbosity
<= Verbosity
.SHORT
:
1154 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1155 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1160 yield f
"{blob}.long 0x{integer:08x}"
1163 operands
= tuple(map(_operator
.itemgetter(1),
1164 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1166 yield f
"{blob}{record.name} {','.join(operands)}"
1168 yield f
"{blob}{record.name}"
1170 if verbosity
>= Verbosity
.VERBOSE
:
1172 binary
= self
.binary
1173 spec
= self
.spec(db
=db
, prefix
="")
1174 yield f
"{indent}spec"
1175 yield f
"{indent}{indent}{spec}"
1176 yield f
"{indent}pcode"
1177 for stmt
in record
.mdwn
.pcode
:
1178 yield f
"{indent}{indent}{stmt}"
1179 yield f
"{indent}binary"
1180 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1181 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1182 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1183 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1184 yield f
"{indent}opcodes"
1185 for opcode
in record
.opcodes
:
1186 yield f
"{indent}{indent}{opcode!r}"
1187 for operand
in record
.mdwn
.operands
:
1188 yield from operand
.disassemble(insn
=self
, record
=record
,
1189 verbosity
=verbosity
, indent
=indent
)
1193 class PrefixedInstruction(Instruction
):
1194 class Prefix(WordInstruction
.remap(range(0, 32))):
1197 class Suffix(WordInstruction
.remap(range(32, 64))):
1200 _
: _Field
= range(64)
1206 def integer(cls
, value
, byteorder
="little"):
1207 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1210 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1211 def transform(value
):
1212 return WordInstruction
.integer(value
=value
,
1213 byteorder
=byteorder
)[0:32]
1215 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1216 value
= _selectconcat(prefix
, suffix
)
1218 return super().integer(bits
=64, value
=value
)
1221 class Mode(_Mapping
):
1222 _
: _Field
= range(0, 5)
1225 class Extra(_Mapping
):
1226 _
: _Field
= range(0, 9)
1229 class Extra2(Extra
):
1230 idx0
: _Field
= range(0, 2)
1231 idx1
: _Field
= range(2, 4)
1232 idx2
: _Field
= range(4, 6)
1233 idx3
: _Field
= range(6, 8)
1235 def __getitem__(self
, key
):
1241 _SVExtra
.Idx0
: self
.idx0
,
1242 _SVExtra
.Idx1
: self
.idx1
,
1243 _SVExtra
.Idx2
: self
.idx2
,
1244 _SVExtra
.Idx3
: self
.idx3
,
1247 def __setitem__(self
, key
, value
):
1248 self
[key
].assign(value
)
1251 class Extra3(Extra
):
1252 idx0
: _Field
= range(0, 3)
1253 idx1
: _Field
= range(3, 6)
1254 idx2
: _Field
= range(6, 9)
1256 def __getitem__(self
, key
):
1261 _SVExtra
.Idx0
: self
.idx0
,
1262 _SVExtra
.Idx1
: self
.idx1
,
1263 _SVExtra
.Idx2
: self
.idx2
,
1266 def __setitem__(self
, key
, value
):
1267 self
[key
].assign(value
)
1270 class BaseRM(_Mapping
):
1271 _
: _Field
= range(24)
1272 mmode
: _Field
= (0,)
1273 mask
: _Field
= range(1, 4)
1274 elwidth
: _Field
= range(4, 6)
1275 ewsrc
: _Field
= range(6, 8)
1276 subvl
: _Field
= range(8, 10)
1277 mode
: Mode
.remap(range(19, 24))
1278 smask
: _Field
= range(16, 19)
1279 extra
: Extra
.remap(range(10, 19))
1280 extra2
: Extra2
.remap(range(10, 19))
1281 extra3
: Extra3
.remap(range(10, 19))
1283 def specifiers(self
, record
):
1284 subvl
= int(self
.subvl
)
1292 def disassemble(self
, verbosity
=Verbosity
.NORMAL
):
1293 if verbosity
>= Verbosity
.VERBOSE
:
1295 for (name
, value
, members
) in self
.traverse(path
="RM"):
1297 yield f
"{indent}{int(value):0{value.bits}b}"
1298 yield f
"{indent}{', '.join(map(str, members))}"
1301 class FFPRRc1BaseRM(BaseRM
):
1302 def specifiers(self
, record
, mode
):
1303 inv
= _SelectableInt(value
=int(self
.inv
), bits
=1)
1304 CR
= _SelectableInt(value
=int(self
.CR
), bits
=2)
1305 mask
= int(_selectconcat(inv
, CR
))
1316 yield f
"{mode}={predicate}"
1318 yield from super().specifiers(record
=record
)
1321 class FFPRRc0BaseRM(BaseRM
):
1322 def specifiers(self
, record
, mode
):
1324 inv
= "~" if self
.inv
else ""
1325 yield f
"{mode}={inv}RC1"
1327 yield from super().specifiers(record
=record
)
1330 class SatBaseRM(BaseRM
):
1331 def specifiers(self
, record
):
1337 yield from super().specifiers(record
=record
)
1340 class ZZBaseRM(BaseRM
):
1341 def specifiers(self
, record
):
1345 yield from super().specifiers(record
=record
)
1348 class DZBaseRM(BaseRM
):
1349 def specifiers(self
, record
):
1353 yield from super().specifiers(record
=record
)
1356 class SZBaseRM(BaseRM
):
1357 def specifiers(self
, record
):
1361 yield from super().specifiers(record
=record
)
1364 class MRBaseRM(BaseRM
):
1365 def specifiers(self
, record
):
1367 # reverse-gear but this is a mix-in class, different reports needed
1368 if isinstance(self
, CROpSimpleRM
):
1369 yield "rg" # simple CR Mode reports /rg
1371 yield "mrr" # all others assume "mapreduce+reverse"
1373 # in CR-Simple just don't report anything
1374 if not isinstance(self
, CROpSimpleRM
):
1375 yield "mr" # all but CR-Simple report "mapreduce"
1377 yield from super().specifiers(record
=record
)
1380 class NormalLDSTBaseRM(BaseRM
):
1381 def specifiers(self
, record
):
1389 (0, 0b001): "1<<r3",
1407 mmode
= int(self
.mmode
)
1408 mask
= int(self
.mask
)
1409 if record
.svp64
.ptype
is _SVPtype
.P2
:
1410 (smask
, dmask
) = (int(self
.smask
), mask
)
1412 (smask
, dmask
) = (mask
, mask
)
1413 if all((smask
, dmask
)) and (smask
== dmask
):
1414 yield f
"m={predicates[(mmode, smask)]}"
1416 sw
= predicates
.get((mmode
, smask
))
1417 dw
= predicates
.get((mmode
, dmask
))
1423 dw
= int(self
.elwidth
)
1424 sw
= int(self
.ewsrc
)
1425 if all((dw
, sw
)) and (dw
== sw
):
1426 yield f
"w={widths[dw]}"
1429 yield f
"dw={widths[dw]}"
1431 yield f
"sw={widths[sw]}"
1433 yield from super().specifiers(record
=record
)
1436 # ********************
1438 # https://libre-soc.org/openpower/sv/normal/
1439 class NormalBaseRM(NormalLDSTBaseRM
):
1443 class NormalSimpleRM(DZBaseRM
, SZBaseRM
, NormalBaseRM
):
1444 """normal: simple mode"""
1448 def specifiers(self
, record
):
1449 yield from super().specifiers(record
=record
)
1452 class NormalSMRRM(MRBaseRM
, NormalBaseRM
):
1453 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
1457 class NormalReservedRM(NormalBaseRM
):
1458 """normal: reserved"""
1462 class NormalFFRc1RM(FFPRRc1BaseRM
, NormalBaseRM
):
1463 """normal: Rc=1: ffirst CR sel"""
1465 CR
: BaseRM
.mode
[3, 4]
1467 def specifiers(self
, record
):
1468 yield from super().specifiers(record
=record
, mode
="ff")
1471 class NormalFFRc0RM(FFPRRc0BaseRM
, NormalBaseRM
):
1472 """normal: Rc=0: ffirst z/nonz"""
1477 def specifiers(self
, record
):
1478 yield from super().specifiers(record
=record
, mode
="ff")
1481 class NormalSatRM(SatBaseRM
, DZBaseRM
, SZBaseRM
, NormalBaseRM
):
1482 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
1488 class NormalPRRc1RM(FFPRRc1BaseRM
, NormalBaseRM
):
1489 """normal: Rc=1: pred-result CR sel"""
1491 CR
: BaseRM
.mode
[3, 4]
1493 def specifiers(self
, record
):
1494 yield from super().specifiers(record
=record
, mode
="pr")
1497 class NormalPRRc0RM(FFPRRc0BaseRM
, ZZBaseRM
, NormalBaseRM
):
1498 """normal: Rc=0: pred-result z/nonz"""
1505 def specifiers(self
, record
):
1506 yield from super().specifiers(record
=record
, mode
="pr")
1509 class NormalRM(NormalBaseRM
):
1510 simple
: NormalSimpleRM
1512 reserved
: NormalReservedRM
1513 ffrc1
: NormalFFRc1RM
1514 ffrc0
: NormalFFRc0RM
1516 prrc1
: NormalPRRc1RM
1517 prrc0
: NormalPRRc0RM
1520 # ********************
1521 # LD/ST Immediate mode
1522 # https://libre-soc.org/openpower/sv/ldst/
1524 class LDSTImmBaseRM(NormalLDSTBaseRM
):
1528 class LDSTImmSimpleRM(ZZBaseRM
, LDSTImmBaseRM
):
1529 """ld/st immediate: simple mode"""
1536 class LDSTImmReservedRM(LDSTImmBaseRM
):
1537 """ld/st immediate: reserved"""
1541 class LDSTImmFFRc1RM(FFPRRc1BaseRM
, LDSTImmBaseRM
):
1542 """ld/st immediate: Rc=1: ffirst CR sel"""
1544 CR
: BaseRM
.mode
[3, 4]
1546 def specifiers(self
, record
):
1547 yield from super().specifiers(record
=record
, mode
="ff")
1550 class LDSTImmFFRc0RM(FFPRRc0BaseRM
, LDSTImmBaseRM
):
1551 """ld/st immediate: Rc=0: ffirst z/nonz"""
1556 def specifiers(self
, record
):
1557 yield from super().specifiers(record
=record
, mode
="ff")
1560 class LDSTImmSatRM(SatBaseRM
, ZZBaseRM
, LDSTImmBaseRM
):
1561 """ld/st immediate: sat mode: N=0/1 u/s"""
1569 class LDSTImmPRRc1RM(FFPRRc1BaseRM
, LDSTImmBaseRM
):
1570 """ld/st immediate: Rc=1: pred-result CR sel"""
1572 CR
: BaseRM
.mode
[3, 4]
1574 def specifiers(self
, record
):
1575 yield from super().specifiers(record
=record
, mode
="pr")
1578 class LDSTImmPRRc0RM(FFPRRc0BaseRM
, LDSTImmBaseRM
):
1579 """ld/st immediate: Rc=0: pred-result z/nonz"""
1584 def specifiers(self
, record
):
1585 yield from super().specifiers(record
=record
, mode
="pr")
1588 class LDSTImmRM(LDSTImmBaseRM
):
1589 simple
: LDSTImmSimpleRM
1590 reserved
: LDSTImmReservedRM
1591 ffrc1
: LDSTImmFFRc1RM
1592 ffrc0
: LDSTImmFFRc0RM
1594 prrc1
: LDSTImmPRRc1RM
1595 prrc0
: LDSTImmPRRc0RM
1598 # ********************
1599 # LD/ST Indexed mode
1600 # https://libre-soc.org/openpower/sv/ldst/
1602 class LDSTIdxBaseRM(NormalLDSTBaseRM
):
1606 class LDSTIdxSimpleRM(DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1607 """ld/st index: simple mode"""
1613 class LDSTIdxStrideRM(DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1614 """ld/st index: strided (scalar only source)"""
1620 class LDSTIdxSatRM(SatBaseRM
, DZBaseRM
, SZBaseRM
, LDSTIdxBaseRM
):
1621 """ld/st index: sat mode: N=0/1 u/s"""
1627 class LDSTIdxPRRc1RM(LDSTIdxBaseRM
):
1628 """ld/st index: Rc=1: pred-result CR sel"""
1630 CR
: BaseRM
.mode
[3, 4]
1632 def specifiers(self
, record
):
1633 yield from super().specifiers(record
=record
, mode
="pr")
1636 class LDSTIdxPRRc0RM(FFPRRc0BaseRM
, ZZBaseRM
, LDSTIdxBaseRM
):
1637 """ld/st index: Rc=0: pred-result z/nonz"""
1644 def specifiers(self
, record
):
1645 yield from super().specifiers(record
=record
, mode
="pr")
1648 class LDSTIdxRM(LDSTIdxBaseRM
):
1649 simple
: LDSTIdxSimpleRM
1650 stride
: LDSTIdxStrideRM
1652 prrc1
: LDSTIdxPRRc1RM
1653 prrc0
: LDSTIdxPRRc0RM
1657 # ********************
1659 # https://libre-soc.org/openpower/sv/cr_ops/
1660 class CROpBaseRM(BaseRM
):
1664 class CROpSimpleRM(MRBaseRM
, DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1665 """cr_op: simple mode"""
1671 class CROpSMRRM(MRBaseRM
, DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1672 """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
1678 class CROpFF3RM(ZZBaseRM
, CROpBaseRM
):
1679 """cr_op: ffirst 3-bit mode"""
1687 def specifiers(self
, record
):
1688 yield from super().specifiers(record
=record
, mode
="ff")
1691 class CROpFF5RM(DZBaseRM
, SZBaseRM
, CROpBaseRM
):
1692 """cr_op: ffirst 5-bit mode"""
1698 def specifiers(self
, record
):
1699 yield from super().specifiers(record
=record
)
1702 class CROpRM(CROpBaseRM
):
1703 simple
: CROpSimpleRM
1709 # ********************
1711 # https://libre-soc.org/openpower/sv/branches/
1712 class BranchBaseRM(BaseRM
):
1721 class BranchSimpleRM(BranchBaseRM
):
1722 """branch: simple mode"""
1726 class BranchVLSRM(BranchBaseRM
):
1727 """branch: VLSET mode"""
1732 class BranchCTRRM(BranchBaseRM
):
1733 """branch: CTR-test mode"""
1737 class BranchCTRVLSRM(BranchVLSRM
, BranchCTRRM
):
1738 """branch: CTR-test+VLSET mode"""
1742 class BranchRM(BranchBaseRM
):
1743 simple
: BranchSimpleRM
1746 ctrvls
: BranchCTRVLSRM
1755 def select(self
, record
, Rc
):
1758 # the idea behind these tables is that they are now literally
1759 # in identical format to insndb.csv and minor_xx.csv and can
1760 # be done precisely as that. the only thing to watch out for
1761 # is the insertion of Rc=1 as a "mask/value" bit and likewise
1762 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
1765 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1766 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1767 # mode Rc mask Rc member
1769 (0b000000, 0b111000, "simple"), # simple (no Rc)
1770 (0b001000, 0b111000, "smr"), # mapreduce (no Rc)
1771 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1772 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1773 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1774 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1775 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1778 search
= ((int(rm
.mode
) << 1) | Rc
)
1780 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1781 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1782 # mode Rc mask Rc member
1783 # ironically/coincidentally this table is identical to NORMAL
1784 # mode except reserved in place of smr
1786 (0b000000, 0b111000, "simple"), # simple (no Rc)
1787 (0b001000, 0b111000, "reserved"), # rsvd (no Rc)
1788 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1789 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1790 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1791 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1792 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1795 search
= ((int(rm
.mode
) << 1) | Rc
)
1797 elif record
.svp64
.mode
is _SVMode
.LDST_IDX
:
1798 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1799 # mode Rc mask Rc member
1801 (0b000000, 0b111000, "simple"), # simple (no Rc)
1802 (0b010000, 0b110000, "stride"), # strided, (no Rc)
1803 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1804 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1805 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1808 search
= ((int(rm
.mode
) << 1) | Rc
)
1810 elif record
.svp64
.mode
is _SVMode
.CROP
:
1811 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
1812 # mode 3b mask 3b member
1814 (0b000000, 0b111000, "simple"), # simple
1815 (0b001000, 0b111000, "smr"), # mapreduce
1816 (0b100000, 0b100000, "ff5"), # failfirst, 5-bit CR
1817 (0b100001, 0b100001, "ff3"), # failfirst, 3-bit CR
1819 # determine CR type, 5-bit (BA/BB/BT) or 3-bit Field (BF/BFA)
1821 for idx
in range(0, 4):
1822 for entry
in record
.svp64
.extra
[idx
]:
1823 if entry
.regtype
is _SVExtraRegType
.DST
:
1824 if regtype
is not None:
1825 raise ValueError(record
.svp64
)
1826 regtype
= _RegType(entry
.reg
)
1827 if regtype
is _RegType
.CR_REG
:
1829 elif regtype
is _RegType
.CR_BIT
:
1832 raise ValueError(record
.svp64
)
1833 # finally provide info for search
1835 search
= ((int(rm
.mode
) << 1) |
(regtype
or 0))
1837 elif record
.svp64
.mode
is _SVMode
.BRANCH
:
1838 # just mode 5-bit. could be reduced down to 2, oh well.
1841 (0b00000, 0b11000, "simple"), # simple
1842 (0b01000, 0b11000, "vls"), # VLset
1843 (0b10000, 0b11000, "ctr"), # CTR mode
1844 (0b11000, 0b11000, "ctrvls"), # CTR+VLset mode
1846 # slightly weird: doesn't have a 5-bit "mode" field like others
1847 search
= int(rm
[19:23])
1850 if table
is not None:
1851 for (value
, mask
, member
) in table
:
1852 if ((value
& search
) == (mask
& search
)):
1853 rm
= getattr(rm
, member
)
1856 if rm
.__class
__ is self
.__class
__:
1857 raise ValueError(self
)
1862 class SVP64Instruction(PrefixedInstruction
):
1863 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1864 class Prefix(PrefixedInstruction
.Prefix
):
1866 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1870 def record(self
, db
):
1871 record
= db
[self
.suffix
]
1873 raise KeyError(self
)
1879 for idx
in range(64):
1880 bit
= int(self
[idx
])
1882 return "".join(map(str, bits
))
1884 def disassemble(self
, db
,
1886 verbosity
=Verbosity
.NORMAL
):
1888 if verbosity
<= Verbosity
.SHORT
:
1891 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1892 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1895 record
= self
.record(db
=db
)
1896 blob_prefix
= blob(int(self
.prefix
))
1897 blob_suffix
= blob(int(self
.suffix
))
1898 if record
is None or record
.svp64
is None:
1899 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1900 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1903 name
= f
"sv.{record.name}"
1906 if record
.mdwn
.operands
["Rc"] is not None:
1907 Rc
= bool(record
.mdwn
.operands
["Rc"].value
)
1908 rm
= self
.prefix
.rm
.select(record
=record
, Rc
=Rc
)
1910 # convert specifiers to /x/y/z
1911 specifiers
= list(rm
.specifiers(record
=record
))
1912 if specifiers
: # if any add one extra to get the extra "/"
1913 specifiers
= ['']+specifiers
1914 specifiers
= "/".join(specifiers
)
1916 # convert operands to " ,x,y,z"
1917 operands
= tuple(map(_operator
.itemgetter(1),
1918 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1919 operands
= ','.join(operands
)
1920 if len(operands
) > 0: # if any separate with a space
1921 operands
= " " + operands
1923 yield f
"{blob_prefix}{name}{specifiers}{operands}"
1925 yield f
"{blob_suffix}"
1927 if verbosity
>= Verbosity
.VERBOSE
:
1929 binary
= self
.binary
1930 spec
= self
.spec(db
=db
, prefix
="sv.")
1932 yield f
"{indent}spec"
1933 yield f
"{indent}{indent}{spec}"
1934 yield f
"{indent}pcode"
1935 for stmt
in record
.mdwn
.pcode
:
1936 yield f
"{indent}{indent}{stmt}"
1937 yield f
"{indent}binary"
1938 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1939 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1940 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1941 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1942 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1943 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1944 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1945 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1946 yield f
"{indent}opcodes"
1947 for opcode
in record
.opcodes
:
1948 yield f
"{indent}{indent}{opcode!r}"
1949 for operand
in record
.mdwn
.operands
:
1950 yield from operand
.disassemble(insn
=self
, record
=record
,
1951 verbosity
=verbosity
, indent
=indent
)
1953 yield f
"{indent}{indent}{rm.__doc__}"
1954 for line
in rm
.disassemble(verbosity
=verbosity
):
1955 yield f
"{indent}{indent}{line}"
1959 def parse(stream
, factory
):
1961 return ("TODO" not in frozenset(entry
.values()))
1963 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1964 entries
= _csv
.DictReader(lines
)
1965 entries
= filter(match
, entries
)
1966 return tuple(map(factory
, entries
))
1969 class MarkdownDatabase
:
1972 for (name
, desc
) in _ISA():
1975 (dynamic
, *static
) = desc
.regs
1976 operands
.extend(dynamic
)
1977 operands
.extend(static
)
1978 pcode
= PCode(iterable
=desc
.pcode
)
1979 operands
= Operands(insn
=name
, iterable
=operands
)
1980 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
1984 return super().__init
__()
1987 yield from self
.__db
.items()
1989 def __contains__(self
, key
):
1990 return self
.__db
.__contains
__(key
)
1992 def __getitem__(self
, key
):
1993 return self
.__db
.__getitem
__(key
)
1996 class FieldsDatabase
:
1999 df
= _DecodeFields()
2001 for (form
, fields
) in df
.instrs
.items():
2002 if form
in {"DQE", "TX"}:
2006 db
[_Form
[form
]] = Fields(fields
)
2010 return super().__init
__()
2012 def __getitem__(self
, key
):
2013 return self
.__db
.__getitem
__(key
)
2017 def __init__(self
, root
, mdwndb
):
2018 # The code below groups the instructions by section:identifier.
2019 # We use the comment as an identifier, there's nothing better.
2020 # The point is to capture different opcodes for the same instruction.
2021 dd
= _collections
.defaultdict
2022 records
= dd(lambda: dd(set))
2023 path
= (root
/ "insndb.csv")
2024 with
open(path
, "r", encoding
="UTF-8") as stream
:
2025 for section
in parse(stream
, Section
.CSV
):
2026 path
= (root
/ section
.path
)
2028 section
.Mode
.INTEGER
: IntegerOpcode
,
2029 section
.Mode
.PATTERN
: PatternOpcode
,
2031 factory
= _functools
.partial(
2032 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
2033 with
open(path
, "r", encoding
="UTF-8") as stream
:
2034 for insn
in parse(stream
, factory
):
2035 records
[section
][insn
.comment
].add(insn
)
2038 for (section
, group
) in records
.items():
2039 for records
in group
.values():
2040 sections
[section
].add(PPCMultiRecord(records
))
2043 for (section
, records
) in sections
.items():
2044 for record
in records
:
2045 def exact_match(names
):
2050 def Rc_match(names
):
2052 if f
"{name}." in mdwndb
:
2056 def LK_match(names
):
2057 if "lk" not in record
.flags
:
2062 if f
"{name}l" in mdwndb
:
2066 def AA_match(names
):
2067 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
2072 operands
= mdwndb
[name
].operands
["AA"]
2073 if ((operands
is not None) and
2074 (f
"{name}a" in mdwndb
)):
2078 def reductor(names
, match
):
2081 matches
= (exact_match
, Rc_match
, LK_match
, AA_match
)
2083 names
= _functools
.reduce(reductor
, matches
, record
.names
)
2085 db
[name
] = (section
, record
)
2088 self
.__mdwndb
= mdwndb
2090 return super().__init
__()
2092 @_functools.lru_cache(maxsize
=512, typed
=False)
2093 def __getitem__(self
, key
):
2094 return self
.__db
.get(key
, (None, None))
2097 class SVP64Database
:
2098 def __init__(self
, root
, ppcdb
):
2100 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
2101 for (prefix
, _
, names
) in _os
.walk(root
):
2102 prefix
= _pathlib
.Path(prefix
)
2103 for name
in filter(lambda name
: pattern
.match(name
), names
):
2104 path
= (prefix
/ _pathlib
.Path(name
))
2105 with
open(path
, "r", encoding
="UTF-8") as stream
:
2106 db
.update(parse(stream
, SVP64Record
.CSV
))
2108 self
.__db
= {record
.name
:record
for record
in db
}
2109 self
.__ppcdb
= ppcdb
2111 return super().__init
__()
2113 def __getitem__(self
, key
):
2114 (_
, record
) = self
.__ppcdb
[key
]
2118 for name
in record
.names
:
2119 record
= self
.__db
.get(name
, None)
2120 if record
is not None:
2127 def __init__(self
, root
):
2128 root
= _pathlib
.Path(root
)
2129 mdwndb
= MarkdownDatabase()
2130 fieldsdb
= FieldsDatabase()
2131 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
2132 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
2136 opcodes
= _collections
.defaultdict(set)
2138 for (name
, mdwn
) in mdwndb
:
2139 (section
, ppc
) = ppcdb
[name
]
2142 svp64
= svp64db
[name
]
2143 fields
= fieldsdb
[ppc
.form
]
2144 record
= Record(name
=name
,
2145 section
=section
, ppc
=ppc
, svp64
=svp64
,
2146 mdwn
=mdwn
, fields
=fields
)
2148 names
[record
.name
] = record
2152 opcodes
[PO
.value
].add(record
)
2155 self
.__names
= names
2156 self
.__opcodes
= opcodes
2158 return super().__init
__()
2161 return repr(self
.__db
)
2164 yield from self
.__db
2166 @_functools.lru_cache(maxsize
=None)
2167 def __contains__(self
, key
):
2168 return self
.__getitem
__(key
) is not None
2170 @_functools.lru_cache(maxsize
=None)
2171 def __getitem__(self
, key
):
2172 if isinstance(key
, (int, Instruction
)):
2174 XO
= int(_SelectableInt(value
=int(key
), bits
=32)[0:6])
2175 for record
in self
.__opcodes
[XO
]:
2176 if record
.match(key
=key
):
2179 elif isinstance(key
, str):
2180 return self
.__names
[key
]