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
,
37 SVExtraRegType
as _SVExtraRegType
,
38 SVExtraReg
as _SVExtraReg
,
40 from openpower
.decoder
.selectable_int
import (
41 SelectableInt
as _SelectableInt
,
42 selectconcat
as _selectconcat
,
44 from openpower
.decoder
.power_fields
import (
47 DecodeFields
as _DecodeFields
,
49 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
52 @_functools.total_ordering
53 class Verbosity(_enum
.Enum
):
56 VERBOSE
= _enum
.auto()
58 def __lt__(self
, other
):
59 if not isinstance(other
, self
.__class
__):
61 return (self
.value
< other
.value
)
64 def dataclass(cls
, record
, keymap
=None, typemap
=None):
68 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
70 def transform(key_value
):
71 (key
, value
) = key_value
72 key
= keymap
.get(key
, key
)
73 hook
= typemap
.get(key
, lambda value
: value
)
74 if hook
is bool and value
in ("", "0"):
80 record
= dict(map(transform
, record
.items()))
81 for key
in frozenset(record
.keys()):
88 @_functools.total_ordering
89 @_dataclasses.dataclass(eq
=True, frozen
=True)
92 def __new__(cls
, value
):
93 if isinstance(value
, str):
95 if not isinstance(value
, int):
96 raise ValueError(value
)
98 if value
.bit_length() > 64:
99 raise ValueError(value
)
101 return super().__new
__(cls
, value
)
104 return super().__repr
__()
107 return f
"{self:0{self.bit_length()}b}"
109 def bit_length(self
):
110 if super().bit_length() > 32:
114 class Value(Integer
):
123 def __lt__(self
, other
):
124 if not isinstance(other
, Opcode
):
125 return NotImplemented
126 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
128 def __post_init__(self
):
129 if self
.value
.bit_length() != self
.mask
.bit_length():
130 raise ValueError("bit length mismatch")
133 def pattern(value
, mask
, bit_length
):
134 for bit
in range(bit_length
):
135 if ((mask
& (1 << (bit_length
- bit
- 1))) == 0):
137 elif (value
& (1 << (bit_length
- bit
- 1))):
142 return "".join(pattern(self
.value
, self
.mask
, self
.value
.bit_length()))
145 class IntegerOpcode(Opcode
):
146 def __init__(self
, value
):
147 if value
.startswith("0b"):
148 mask
= int(("1" * len(value
[2:])), 2)
152 value
= Opcode
.Value(value
)
153 mask
= Opcode
.Mask(mask
)
155 return super().__init
__(value
=value
, mask
=mask
)
158 class PatternOpcode(Opcode
):
159 def __init__(self
, pattern
):
160 if not isinstance(pattern
, str):
161 raise ValueError(pattern
)
163 (value
, mask
) = (0, 0)
164 for symbol
in pattern
:
165 if symbol
not in {"0", "1", "-"}:
166 raise ValueError(pattern
)
167 value |
= (symbol
== "1")
168 mask |
= (symbol
!= "-")
174 value
= Opcode
.Value(value
)
175 mask
= Opcode
.Mask(mask
)
177 return super().__init
__(value
=value
, mask
=mask
)
180 @_dataclasses.dataclass(eq
=True, frozen
=True)
182 class FlagsMeta(type):
197 class Flags(frozenset, metaclass
=FlagsMeta
):
198 def __new__(cls
, flags
=frozenset()):
199 flags
= frozenset(flags
)
200 diff
= (flags
- frozenset(cls
))
202 raise ValueError(flags
)
203 return super().__new
__(cls
, flags
)
207 flags
: Flags
= Flags()
209 function
: _Function
= _Function
.NONE
210 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
211 in1
: _In1Sel
= _In1Sel
.RA
212 in2
: _In2Sel
= _In2Sel
.NONE
213 in3
: _In3Sel
= _In3Sel
.NONE
214 out
: _OutSel
= _OutSel
.NONE
215 cr_in
: _CRInSel
= _CRInSel
.NONE
216 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
217 cr_out
: _CROutSel
= _CROutSel
.NONE
218 cry_in
: _CryIn
= _CryIn
.ZERO
219 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
220 upd
: _LDSTMode
= _LDSTMode
.NONE
221 Rc
: _RCOE
= _RCOE
.NONE
222 form
: _Form
= _Form
.NONE
224 unofficial
: bool = False
228 "internal op": "intop",
232 "ldst len": "ldst_len",
234 "CONDITIONS": "conditions",
238 def CSV(cls
, record
, opcode_cls
):
239 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
240 typemap
["opcode"] = opcode_cls
242 if record
["CR in"] == "BA_BB":
243 record
["cr_in"] = "BA"
244 record
["cr_in2"] = "BB"
248 for flag
in frozenset(PPCRecord
.Flags
):
249 if bool(record
.pop(flag
, "")):
251 record
["flags"] = PPCRecord
.Flags(flags
)
253 return dataclass(cls
, record
,
254 keymap
=PPCRecord
.__KEYMAP
,
259 return frozenset(self
.comment
.split("=")[-1].split("/"))
262 class PPCMultiRecord(tuple):
263 def __getattr__(self
, attr
):
265 raise AttributeError(attr
)
266 return getattr(self
[0], attr
)
269 @_dataclasses.dataclass(eq
=True, frozen
=True)
271 class ExtraMap(tuple):
273 @_dataclasses.dataclass(eq
=True, frozen
=True)
275 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
276 reg
: _SVExtraReg
= _SVExtraReg
.NONE
279 return f
"{self.regtype.value}:{self.reg.name}"
281 def __new__(cls
, value
="0"):
282 if isinstance(value
, str):
283 def transform(value
):
284 (regtype
, reg
) = value
.split(":")
285 regtype
= _SVExtraRegType(regtype
)
286 reg
= _SVExtraReg(reg
)
287 return cls
.Entry(regtype
=regtype
, reg
=reg
)
292 value
= map(transform
, value
.split(";"))
294 return super().__new
__(cls
, value
)
297 return repr(list(self
))
299 def __new__(cls
, value
=tuple()):
303 return super().__new
__(cls
, map(cls
.Extra
, value
))
306 return repr({index
:self
[index
] for index
in range(0, 4)})
309 ptype
: _SVPtype
= _SVPtype
.NONE
310 etype
: _SVEtype
= _SVEtype
.NONE
311 in1
: _In1Sel
= _In1Sel
.NONE
312 in2
: _In2Sel
= _In2Sel
.NONE
313 in3
: _In3Sel
= _In3Sel
.NONE
314 out
: _OutSel
= _OutSel
.NONE
315 out2
: _OutSel
= _OutSel
.NONE
316 cr_in
: _CRInSel
= _CRInSel
.NONE
317 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
318 cr_out
: _CROutSel
= _CROutSel
.NONE
319 extra
: ExtraMap
= ExtraMap()
321 mode
: _SVMode
= _SVMode
.NORMAL
325 "CONDITIONS": "conditions",
333 def CSV(cls
, record
):
334 for key
in frozenset({
335 "in1", "in2", "in3", "CR in",
336 "out", "out2", "CR out",
342 if record
["CR in"] == "BA_BB":
343 record
["cr_in"] = "BA"
344 record
["cr_in2"] = "BB"
348 for idx
in range(0, 4):
349 extra
.append(record
.pop(f
"{idx}"))
351 record
["extra"] = cls
.ExtraMap(extra
)
353 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
355 @_functools.lru_cache(maxsize
=None)
356 def extra_idx(self
, key
):
364 if key
not in frozenset({
365 "in1", "in2", "in3", "cr_in", "cr_in2",
366 "out", "out2", "cr_out",
370 sel
= getattr(self
, key
)
371 if sel
is _CRInSel
.BA_BB
:
372 return _SVExtra
.Idx_1_2
373 reg
= _SVExtraReg(sel
)
374 if reg
is _SVExtraReg
.NONE
:
378 _SVExtraRegType
.SRC
: {},
379 _SVExtraRegType
.DST
: {},
381 for index
in range(0, 4):
382 for entry
in self
.extra
[index
]:
383 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
385 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
386 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
387 if extra
is not _SVExtra
.NONE
:
392 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
393 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
394 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
395 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
396 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
397 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
398 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
400 @_functools.lru_cache(maxsize
=None)
401 def extra_reg(self
, key
):
402 return _SVExtraReg(getattr(self
, key
))
404 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
405 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
406 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
407 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
408 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
409 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
410 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
414 def __init__(self
, value
=(0, 32)):
415 if isinstance(value
, str):
416 (start
, end
) = map(int, value
.split(":"))
419 if start
< 0 or end
< 0 or start
>= end
:
420 raise ValueError(value
)
425 return super().__init
__()
428 return f
"[{self.__start}:{self.__end}]"
431 yield from range(self
.start
, (self
.end
+ 1))
433 def __reversed__(self
):
434 return tuple(reversed(tuple(self
)))
445 @_dataclasses.dataclass(eq
=True, frozen
=True)
447 class Mode(_enum
.Enum
):
448 INTEGER
= _enum
.auto()
449 PATTERN
= _enum
.auto()
452 def _missing_(cls
, value
):
453 if isinstance(value
, str):
454 return cls
[value
.upper()]
455 return super()._missing
_(value
)
458 def __new__(cls
, value
=None):
459 if isinstance(value
, str):
460 if value
.upper() == "NONE":
463 value
= int(value
, 0)
467 return super().__new
__(cls
, value
)
473 return (bin(self
) if self
else "None")
479 opcode
: IntegerOpcode
= None
482 def CSV(cls
, record
):
483 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
484 if record
["opcode"] == "NONE":
485 typemap
["opcode"] = lambda _
: None
487 return dataclass(cls
, record
, typemap
=typemap
)
491 def __init__(self
, items
):
492 if isinstance(items
, dict):
493 items
= items
.items()
496 (name
, bitrange
) = item
497 return (name
, tuple(bitrange
.values()))
499 self
.__mapping
= dict(map(transform
, items
))
501 return super().__init
__()
504 return repr(self
.__mapping
)
507 yield from self
.__mapping
.items()
509 def __contains__(self
, key
):
510 return self
.__mapping
.__contains
__(key
)
512 def __getitem__(self
, key
):
513 return self
.__mapping
.get(key
, None)
516 @_dataclasses.dataclass(eq
=True, frozen
=True)
520 def span(self
, record
):
521 return record
.fields
[self
.name
]
523 def disassemble(self
, insn
, record
,
524 verbosity
=Verbosity
.NORMAL
, indent
=""):
525 raise NotImplementedError
528 class DynamicOperand(Operand
):
529 def disassemble(self
, insn
, record
,
530 verbosity
=Verbosity
.NORMAL
, indent
=""):
531 span
= self
.span(record
=record
)
532 if isinstance(insn
, SVP64Instruction
):
533 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
536 if verbosity
>= Verbosity
.VERBOSE
:
537 span
= map(str, span
)
538 yield f
"{indent}{self.name}"
539 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
540 yield f
"{indent}{indent}{', '.join(span)}"
542 yield str(int(value
))
545 class SignedOperand(DynamicOperand
):
546 def disassemble(self
, insn
, record
,
547 verbosity
=Verbosity
.NORMAL
, indent
=""):
548 span
= self
.span(record
=record
)
549 if isinstance(insn
, SVP64Instruction
):
550 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
553 if verbosity
>= Verbosity
.VERBOSE
:
554 span
= map(str, span
)
555 yield f
"{indent}{self.name}"
556 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
557 yield f
"{indent}{indent}{', '.join(span)}"
559 yield str(value
.to_signed_int())
562 @_dataclasses.dataclass(eq
=True, frozen
=True)
563 class StaticOperand(Operand
):
566 def disassemble(self
, insn
, record
,
567 verbosity
=Verbosity
.NORMAL
, indent
=""):
568 span
= self
.span(record
=record
)
569 if isinstance(insn
, SVP64Instruction
):
570 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
573 if verbosity
>= Verbosity
.VERBOSE
:
574 span
= map(str, span
)
575 yield f
"{indent}{self.name}"
576 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
577 yield f
"{indent}{indent}{', '.join(span)}"
579 yield str(int(value
))
582 class ImmediateOperand(DynamicOperand
):
586 class NonZeroOperand(DynamicOperand
):
587 def disassemble(self
, insn
, record
,
588 verbosity
=Verbosity
.NORMAL
, indent
=""):
589 span
= self
.span(record
=record
)
590 if isinstance(insn
, SVP64Instruction
):
591 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
594 if verbosity
>= Verbosity
.VERBOSE
:
595 span
= map(str, span
)
596 yield f
"{indent}{self.name}"
597 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
598 yield f
"{indent}{indent}{', '.join(span)}"
600 yield str(int(value
) + 1)
603 class RegisterOperand(DynamicOperand
):
604 def sv_spec_enter(self
, value
, span
):
607 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
610 def spec(self
, insn
, record
):
612 span
= self
.span(record
=record
)
613 if isinstance(insn
, SVP64Instruction
):
614 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
616 span
= tuple(map(str, span
))
618 if isinstance(insn
, SVP64Instruction
):
619 (origin_value
, origin_span
) = (value
, span
)
620 (value
, span
) = self
.sv_spec_enter(value
=value
, span
=span
)
622 extra_idx
= self
.extra_idx(record
=record
)
623 if extra_idx
is _SVExtra
.NONE
:
624 return (vector
, value
, span
)
626 if record
.etype
is _SVEtype
.EXTRA3
:
627 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
628 elif record
.etype
is _SVEtype
.EXTRA2
:
629 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
631 raise ValueError(record
.etype
)
634 vector
= bool(spec
[0])
635 spec_span
= spec
.__class
__
636 if record
.etype
is _SVEtype
.EXTRA3
:
637 spec_span
= tuple(map(str, spec_span
[1, 2]))
639 elif record
.etype
is _SVEtype
.EXTRA2
:
640 spec_span
= tuple(map(str, spec_span
[1,]))
641 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
644 spec_span
= (spec_span
+ ("{0}",))
646 spec_span
= (("{0}",) + spec_span
)
648 raise ValueError(record
.etype
)
650 vector_shift
= (2 + (5 - value
.bits
))
651 scalar_shift
= value
.bits
652 spec_shift
= (5 - value
.bits
)
654 bits
= (len(span
) + len(spec_span
))
655 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
656 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
658 value
= ((value
<< vector_shift
) |
(spec
<< spec_shift
))
659 span
= (span
+ spec_span
+ ((spec_shift
* ('{0}',))))
661 value
= ((spec
<< scalar_shift
) | value
)
662 span
= ((spec_shift
* ('{0}',)) + spec_span
+ span
)
664 (value
, span
) = self
.sv_spec_leave(value
=value
, span
=span
,
665 origin_value
=origin_value
, origin_span
=origin_span
)
667 return (vector
, value
, span
)
671 return _SVExtraReg(self
.name
)
673 def extra_idx(self
, record
):
674 for key
in frozenset({
675 "in1", "in2", "in3", "cr_in", "cr_in2",
676 "out", "out2", "cr_out",
678 extra_reg
= record
.svp64
.extra_reg(key
=key
)
679 if extra_reg
is self
.extra_reg
:
680 return record
.extra_idx(key
=key
)
684 def disassemble(self
, insn
, record
,
685 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
686 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
688 if verbosity
>= Verbosity
.VERBOSE
:
689 mode
= "vector" if vector
else "scalar"
690 yield f
"{indent}{self.name} ({mode})"
691 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
692 yield f
"{indent}{indent}{', '.join(span)}"
693 if isinstance(insn
, SVP64Instruction
):
694 extra_idx
= self
.extra_idx(record
)
695 if record
.etype
is _SVEtype
.NONE
:
696 yield f
"{indent}{indent}extra[none]"
698 etype
= repr(record
.etype
).lower()
699 yield f
"{indent}{indent}{etype}{extra_idx!r}"
701 vector
= "*" if vector
else ""
702 yield f
"{vector}{prefix}{int(value)}"
705 class GPROperand(RegisterOperand
):
706 def disassemble(self
, insn
, record
,
707 verbosity
=Verbosity
.NORMAL
, indent
=""):
708 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
709 yield from super().disassemble(prefix
=prefix
,
710 insn
=insn
, record
=record
,
711 verbosity
=verbosity
, indent
=indent
)
714 class FPROperand(RegisterOperand
):
715 def disassemble(self
, insn
, record
,
716 verbosity
=Verbosity
.NORMAL
, indent
=""):
717 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
718 yield from super().disassemble(prefix
=prefix
,
719 insn
=insn
, record
=record
,
720 verbosity
=verbosity
, indent
=indent
)
723 class CR3Operand(RegisterOperand
):
727 class CR5Operand(RegisterOperand
):
728 def sv_spec_enter(self
, value
, span
):
729 value
= _SelectableInt(value
=(value
.value
>> 2), bits
=3)
732 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
733 value
= _selectconcat(value
, origin_value
[3:5])
738 class TargetAddrOperand(RegisterOperand
):
739 def disassemble(self
, insn
, record
, field
,
740 verbosity
=Verbosity
.NORMAL
, indent
=""):
741 span
= self
.span(record
=record
)
742 if isinstance(insn
, SVP64Instruction
):
743 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
746 if verbosity
>= Verbosity
.VERBOSE
:
747 span
= tuple(map(str, span
))
748 yield f
"{indent}{self.name} = EXTS({field} || 0b00))"
749 yield f
"{indent}{indent}{field}"
750 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
751 yield f
"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
753 yield hex(_selectconcat(value
,
754 _SelectableInt(value
=0b00, bits
=2)).to_signed_int())
757 class TargetAddrOperandLI(TargetAddrOperand
):
758 def span(self
, record
):
759 return record
.fields
["LI"]
761 def disassemble(self
, insn
, record
,
762 verbosity
=Verbosity
.NORMAL
, indent
=""):
763 return super().disassemble(field
="LI",
764 insn
=insn
, record
=record
,
765 verbosity
=verbosity
, indent
=indent
)
768 class TargetAddrOperandBD(TargetAddrOperand
):
769 def span(self
, record
):
770 return record
.fields
["BD"]
772 def disassemble(self
, insn
, record
,
773 verbosity
=Verbosity
.NORMAL
, indent
=""):
774 return super().disassemble(field
="BD",
775 insn
=insn
, record
=record
,
776 verbosity
=verbosity
, indent
=indent
)
779 class DOperandDX(DynamicOperand
):
780 def span(self
, record
):
781 operands
= map(DynamicOperand
, ("d0", "d1", "d2"))
782 spans
= map(lambda operand
: operand
.span(record
=record
), operands
)
783 return sum(spans
, tuple())
785 def disassemble(self
, insn
, record
,
786 verbosity
=Verbosity
.NORMAL
, indent
=""):
787 span
= self
.span(record
=record
)
788 if isinstance(insn
, SVP64Instruction
):
789 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
792 if verbosity
>= Verbosity
.VERBOSE
:
799 for (subname
, subspan
) in mapping
.items():
800 operand
= DynamicOperand(name
=subname
)
801 span
= operand
.span(record
=record
)
802 if isinstance(insn
, SVP64Instruction
):
803 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
805 span
= map(str, span
)
806 yield f
"{indent}{indent}{operand.name} = D{subspan}"
807 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}"
808 yield f
"{indent}{indent}{indent}{', '.join(span)}"
810 yield str(value
.to_signed_int())
813 class Operands(tuple):
814 def __new__(cls
, insn
, iterable
):
816 "b": {"target_addr": TargetAddrOperandLI
},
817 "ba": {"target_addr": TargetAddrOperandLI
},
818 "bl": {"target_addr": TargetAddrOperandLI
},
819 "bla": {"target_addr": TargetAddrOperandLI
},
820 "bc": {"target_addr": TargetAddrOperandBD
},
821 "bca": {"target_addr": TargetAddrOperandBD
},
822 "bcl": {"target_addr": TargetAddrOperandBD
},
823 "bcla": {"target_addr": TargetAddrOperandBD
},
824 "addpcis": {"D": DOperandDX
},
825 "fishmv": {"D": DOperandDX
},
826 "fmvis": {"D": DOperandDX
},
829 "SVi": NonZeroOperand
,
830 "SVd": NonZeroOperand
,
831 "SVxd": NonZeroOperand
,
832 "SVyd": NonZeroOperand
,
833 "SVzd": NonZeroOperand
,
841 "SIM": SignedOperand
,
842 "SVD": SignedOperand
,
843 "SVDS": SignedOperand
,
847 for operand
in iterable
:
848 dynamic_cls
= DynamicOperand
849 static_cls
= StaticOperand
852 (name
, value
) = operand
.split("=")
853 operand
= static_cls(name
=name
, value
=int(value
))
854 operands
.append(operand
)
856 if operand
.endswith(")"):
857 operand
= operand
.replace("(", " ").replace(")", "")
858 (immediate
, _
, operand
) = operand
.partition(" ")
862 if immediate
is not None:
863 operands
.append(ImmediateOperand(name
=immediate
))
865 if insn
in custom_insns
and operand
in custom_insns
[insn
]:
866 dynamic_cls
= custom_insns
[insn
][operand
]
867 if operand
in custom_fields
:
868 dynamic_cls
= custom_fields
[operand
]
870 if operand
in _RegType
.__members
__:
871 regtype
= _RegType
[operand
]
872 if regtype
is _RegType
.GPR
:
873 dynamic_cls
= GPROperand
874 elif regtype
is _RegType
.FPR
:
875 dynamic_cls
= FPROperand
876 if regtype
is _RegType
.CR_BIT
: # 5-bit
877 dynamic_cls
= CR5Operand
878 if regtype
is _RegType
.CR_REG
: # actually CR Field, 3-bit
879 dynamic_cls
= CR3Operand
881 operand
= dynamic_cls(name
=operand
)
882 operands
.append(operand
)
884 return super().__new
__(cls
, operands
)
886 def __contains__(self
, key
):
887 return self
.__getitem
__(key
) is not None
889 def __getitem__(self
, key
):
891 if operand
.name
== key
:
899 if isinstance(operand
, DynamicOperand
):
905 if isinstance(operand
, StaticOperand
):
910 def __init__(self
, iterable
):
911 self
.__pcode
= tuple(iterable
)
912 return super().__init
__()
915 yield from self
.__pcode
918 return self
.__pcode
.__repr
__()
921 @_dataclasses.dataclass(eq
=True, frozen
=True)
922 class MarkdownRecord
:
927 @_functools.total_ordering
928 @_dataclasses.dataclass(eq
=True, frozen
=True)
935 svp64
: SVP64Record
= None
937 def __lt__(self
, other
):
938 if not isinstance(other
, Record
):
939 return NotImplemented
940 return (min(self
.opcodes
) < min(other
.opcodes
))
948 PO
= self
.section
.opcode
950 for (src
, dst
) in enumerate(reversed(BitSel((0, 5)))):
951 value
[dst
] = int((PO
.value
& (1 << src
)) != 0)
952 mask
[dst
] = int((PO
.mask
& (1 << src
)) != 0)
955 for (src
, dst
) in enumerate(reversed(self
.section
.bitsel
)):
956 value
[dst
] = int((XO
.value
& (1 << src
)) != 0)
957 mask
[dst
] = int((XO
.mask
& (1 << src
)) != 0)
959 for operand
in self
.mdwn
.operands
.static
:
960 for (src
, dst
) in enumerate(reversed(operand
.span(record
=self
))):
961 value
[dst
] = int((operand
.value
& (1 << src
)) != 0)
964 value
= Opcode
.Value(int(("".join(map(str, value
))), 2))
965 mask
= Opcode
.Mask(int(("".join(map(str, mask
))), 2))
967 return Opcode(value
=value
, mask
=mask
)
969 return tuple(sorted(map(opcode
, self
.ppc
)))
971 def match(self
, key
):
972 for opcode
in self
.opcodes
:
973 if ((opcode
.value
& opcode
.mask
) ==
974 (key
& opcode
.mask
)):
980 return self
.ppc
.function
1000 if self
.svp64
is None:
1006 return self
.ppc
.cr_in
1010 return self
.ppc
.cr_in2
1014 return self
.ppc
.cr_out
1016 ptype
= property(lambda self
: self
.svp64
.ptype
)
1017 etype
= property(lambda self
: self
.svp64
.etype
)
1019 def extra_idx(self
, key
):
1020 return self
.svp64
.extra_idx(key
)
1022 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
1023 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
1024 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
1025 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
1026 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
1027 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
1028 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
1031 class Instruction(_Mapping
):
1033 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
1034 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
1035 raise ValueError(bits
)
1037 if isinstance(value
, bytes
):
1038 if ((len(value
) * 8) != bits
):
1039 raise ValueError(f
"bit length mismatch")
1040 value
= int.from_bytes(value
, byteorder
=byteorder
)
1042 if isinstance(value
, int):
1043 value
= _SelectableInt(value
=value
, bits
=bits
)
1044 elif isinstance(value
, Instruction
):
1045 value
= value
.storage
1047 if not isinstance(value
, _SelectableInt
):
1048 raise ValueError(value
)
1051 if len(value
) != bits
:
1052 raise ValueError(value
)
1054 value
= _SelectableInt(value
=value
, bits
=bits
)
1056 return cls(storage
=value
)
1059 return hash(int(self
))
1061 def __getitem__(self
, key
):
1062 return self
.storage
.__getitem
__(key
)
1064 def __setitem__(self
, key
, value
):
1065 return self
.storage
.__setitem
__(key
, value
)
1067 def bytes(self
, byteorder
="little"):
1068 nr_bytes
= (self
.storage
.bits
// 8)
1069 return int(self
).to_bytes(nr_bytes
, byteorder
=byteorder
)
1071 def record(self
, db
):
1074 raise KeyError(self
)
1077 def spec(self
, db
, prefix
):
1078 record
= self
.record(db
=db
)
1080 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1081 self
.dynamic_operands(db
=db
)))
1083 static_operands
= []
1084 for (name
, value
) in self
.static_operands(db
=db
):
1085 static_operands
.append(f
"{name}={value}")
1088 if dynamic_operands
:
1089 operands
+= f
" {','.join(dynamic_operands)}"
1091 operands
+= f
" ({' '.join(static_operands)})"
1093 return f
"{prefix}{record.name}{operands}"
1095 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1096 record
= self
.record(db
=db
)
1101 for operand
in record
.mdwn
.operands
.dynamic
:
1103 dis
= operand
.disassemble(insn
=self
, record
=record
,
1104 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1105 value
= " ".join(dis
)
1107 name
= f
"{imm_name}({name})"
1108 value
= f
"{imm_value}({value})"
1110 if isinstance(operand
, ImmediateOperand
):
1117 def static_operands(self
, db
):
1118 record
= self
.record(db
=db
)
1119 for operand
in record
.mdwn
.operands
.static
:
1120 yield (operand
.name
, operand
.value
)
1122 def disassemble(self
, db
,
1124 verbosity
=Verbosity
.NORMAL
):
1125 raise NotImplementedError
1128 class WordInstruction(Instruction
):
1129 _
: _Field
= range(0, 32)
1130 po
: _Field
= range(0, 6)
1133 def integer(cls
, value
, byteorder
="little"):
1134 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1139 for idx
in range(32):
1140 bit
= int(self
[idx
])
1142 return "".join(map(str, bits
))
1144 def disassemble(self
, db
,
1146 verbosity
=Verbosity
.NORMAL
):
1148 if verbosity
<= Verbosity
.SHORT
:
1151 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1152 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1157 yield f
"{blob}.long 0x{integer:08x}"
1160 operands
= tuple(map(_operator
.itemgetter(1),
1161 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1163 yield f
"{blob}{record.name} {','.join(operands)}"
1165 yield f
"{blob}{record.name}"
1167 if verbosity
>= Verbosity
.VERBOSE
:
1169 binary
= self
.binary
1170 spec
= self
.spec(db
=db
, prefix
="")
1171 yield f
"{indent}spec"
1172 yield f
"{indent}{indent}{spec}"
1173 yield f
"{indent}pcode"
1174 for stmt
in record
.mdwn
.pcode
:
1175 yield f
"{indent}{indent}{stmt}"
1176 yield f
"{indent}binary"
1177 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1178 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1179 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1180 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1181 yield f
"{indent}opcodes"
1182 for opcode
in record
.opcodes
:
1183 yield f
"{indent}{indent}{opcode!r}"
1184 for operand
in record
.mdwn
.operands
:
1185 yield from operand
.disassemble(insn
=self
, record
=record
,
1186 verbosity
=verbosity
, indent
=indent
)
1190 class PrefixedInstruction(Instruction
):
1191 class Prefix(WordInstruction
.remap(range(0, 32))):
1194 class Suffix(WordInstruction
.remap(range(32, 64))):
1197 _
: _Field
= range(64)
1203 def integer(cls
, value
, byteorder
="little"):
1204 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1207 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1208 def transform(value
):
1209 return WordInstruction
.integer(value
=value
,
1210 byteorder
=byteorder
)[0:32]
1212 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1213 value
= _selectconcat(prefix
, suffix
)
1215 return super().integer(value
=value
)
1218 class Mode(_Mapping
):
1219 _
: _Field
= range(0, 5)
1222 class Extra(_Mapping
):
1223 _
: _Field
= range(0, 9)
1226 class Extra2(Extra
):
1227 idx0
: _Field
= range(0, 2)
1228 idx1
: _Field
= range(2, 4)
1229 idx2
: _Field
= range(4, 6)
1230 idx3
: _Field
= range(6, 8)
1232 def __getitem__(self
, key
):
1238 _SVExtra
.Idx0
: self
.idx0
,
1239 _SVExtra
.Idx1
: self
.idx1
,
1240 _SVExtra
.Idx2
: self
.idx2
,
1241 _SVExtra
.Idx3
: self
.idx3
,
1244 def __setitem__(self
, key
, value
):
1245 self
[key
].assign(value
)
1248 class Extra3(Extra
):
1249 idx0
: _Field
= range(0, 3)
1250 idx1
: _Field
= range(3, 6)
1251 idx2
: _Field
= range(6, 9)
1253 def __getitem__(self
, key
):
1258 _SVExtra
.Idx0
: self
.idx0
,
1259 _SVExtra
.Idx1
: self
.idx1
,
1260 _SVExtra
.Idx2
: self
.idx2
,
1263 def __setitem__(self
, key
, value
):
1264 self
[key
].assign(value
)
1267 class BaseRM(_Mapping
):
1268 _
: _Field
= range(24)
1269 mmode
: _Field
= (0,)
1270 mask
: _Field
= range(1, 4)
1271 elwidth
: _Field
= range(4, 6)
1272 ewsrc
: _Field
= range(6, 8)
1273 subvl
: _Field
= range(8, 10)
1274 mode
: Mode
.remap(range(19, 24))
1275 smask
: _Field
= range(16, 19)
1277 extra
: Extra
.remap(range(10, 19))
1278 extra2
: Extra2
.remap(range(10, 19))
1279 extra3
: Extra3
.remap(range(10, 19))
1282 class NormalRM(BaseRM
):
1283 class simple(BaseRM
):
1289 """scalar reduce mode (mapreduce), SUBVL=1"""
1293 """parallel reduce mode (mapreduce), SUBVL=1"""
1297 """subvector reduce mode, SUBVL>1"""
1301 """Pack/Unpack mode, SUBVL>1"""
1305 """Rc=1: ffirst CR sel"""
1307 CR
: BaseRM
.mode
[3, 4]
1310 """Rc=0: ffirst z/nonz"""
1316 """sat mode: N=0/1 u/s, SUBVL=1"""
1322 """sat mode: N=0/1 u/s, SUBVL>1"""
1329 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1336 """Rc=1: pred-result CR sel"""
1338 CR
: BaseRM
.mode
[3, 4]
1341 """Rc=0: pred-result z/nonz"""
1362 class LDSTImmRM(BaseRM
):
1371 """Structured Pack/Unpack"""
1378 """Rc=1: ffirst CR sel"""
1380 CR
: BaseRM
.mode
[3, 4]
1383 """Rc=0: ffirst z/nonz"""
1389 """sat mode: N=0/1 u/s"""
1397 """Rc=1: pred-result CR sel"""
1399 CR
: BaseRM
.mode
[3, 4]
1402 """Rc=0: pred-result z/nonz"""
1416 class LDSTIdxRM(BaseRM
):
1424 """strided (scalar only source)"""
1430 """sat mode: N=0/1 u/s"""
1436 """Rc=1: pred-result CR sel"""
1438 CR
: BaseRM
.mode
[3, 4]
1441 """Rc=0: pred-result z/nonz"""
1455 class CROpRM(BaseRM
):
1456 class simple(BaseRM
):
1464 """scalar reduce mode (mapreduce), SUBVL=1"""
1470 """subvector reduce mode, SUBVL>1"""
1478 class reserved(BaseRM
):
1487 """ffirst 3-bit mode"""
1497 """ffirst 5-bit mode"""
1514 class BranchBaseRM(BaseRM
):
1523 class BranchRM(BranchBaseRM
):
1524 class simple(BranchBaseRM
):
1528 class vls(BranchBaseRM
):
1533 class ctr(BranchBaseRM
):
1537 class ctrvls(vls
, ctr
):
1538 """CTR-test+VLSET mode"""
1549 class SVP64Instruction(PrefixedInstruction
):
1550 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1551 class Prefix(PrefixedInstruction
.Prefix
):
1553 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1557 def record(self
, db
):
1558 record
= db
[self
.suffix
]
1560 raise KeyError(self
)
1566 for idx
in range(64):
1567 bit
= int(self
[idx
])
1569 return "".join(map(str, bits
))
1572 record
= self
.record(db
=db
)
1575 if record
.mdwn
.operands
["Rc"] is not None:
1576 Rc
= bool(self
[record
.fields
["Rc"]])
1578 record
= self
.record(db
=db
)
1579 subvl
= self
.prefix
.rm
.subvl
1582 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1584 if rm
.mode
[0:2] == 0b00:
1585 if rm
.mode
[2] == 0b0:
1589 if rm
.mode
[3] == 0b0:
1594 if rm
.mode
[4] == 0b0:
1598 elif rm
.mode
[0:2] == 0b01:
1603 elif rm
.mode
[0:2] == 0b10:
1611 elif rm
.mode
[0:2] == 0b11:
1617 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1619 if rm
.mode
[0:2] == 0b00:
1620 if rm
.mode
[2] == 0b0:
1624 elif rm
.mode
[0:2] == 0b01:
1629 elif rm
.mode
[0:2] == 0b10:
1631 elif rm
.mode
[0:2] == 0b11:
1637 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1639 if rm
.mode
[0:2] == 0b00:
1641 elif rm
.mode
[0:2] == 0b01:
1643 elif rm
.mode
[0:2] == 0b10:
1645 elif rm
.mode
[0:2] == 0b11:
1651 elif record
.svp64
.mode
is _SVMode
.CROP
:
1666 for idx
in range(0, 4):
1667 for entry
in record
.svp64
.extra
[idx
]:
1668 if entry
.regtype
is _SVExtraRegType
.DST
:
1669 if regtype
is not None:
1670 raise ValueError(record
.svp64
)
1671 regtype
= _RegType(entry
.reg
)
1672 if regtype
is _RegType
.CR_REG
:
1674 elif regtype
is _RegType
.CR_BIT
:
1677 raise ValueError(record
.svp64
)
1679 elif record
.svp64
.mode
is _SVMode
.BRANCH
:
1692 raise ValueError(self
)
1695 NormalRM
.simple
: "normal: simple",
1696 NormalRM
.smr
: "normal: smr",
1697 NormalRM
.pmr
: "normal: pmr",
1698 NormalRM
.svmr
: "normal: svmr",
1699 NormalRM
.pu
: "normal: pu",
1700 NormalRM
.ffrc1
: "normal: ffrc1",
1701 NormalRM
.ffrc0
: "normal: ffrc0",
1702 NormalRM
.sat
: "normal: sat",
1703 NormalRM
.satx
: "normal: satx",
1704 NormalRM
.satpu
: "normal: satpu",
1705 NormalRM
.prrc1
: "normal: prrc1",
1706 NormalRM
.prrc0
: "normal: prrc0",
1707 LDSTImmRM
.simple
: "ld/st imm: simple",
1708 LDSTImmRM
.spu
: "ld/st imm: spu",
1709 LDSTImmRM
.ffrc1
: "ld/st imm: ffrc1",
1710 LDSTImmRM
.ffrc0
: "ld/st imm: ffrc0",
1711 LDSTImmRM
.sat
: "ld/st imm: sat",
1712 LDSTImmRM
.prrc1
: "ld/st imm: prrc1",
1713 LDSTImmRM
.prrc0
: "ld/st imm: prrc0",
1714 LDSTIdxRM
.simple
: "ld/st idx: simple",
1715 LDSTIdxRM
.stride
: "ld/st idx: stride",
1716 LDSTIdxRM
.sat
: "ld/st idx: sat",
1717 LDSTIdxRM
.prrc1
: "ld/st idx: prrc1",
1718 LDSTIdxRM
.prrc0
: "ld/st idx: prrc0",
1719 CROpRM
.simple
: "simple mode",
1720 CROpRM
.smr
: "scalar reduce mode (mapreduce), SUBVL=1",
1721 CROpRM
.svmr
: "subvector reduce mode, SUBVL>1",
1722 CROpRM
.reserved
: "reserved",
1723 CROpRM
.ff3
: "ffirst 3-bit mode",
1724 CROpRM
.ff5
: "ffirst 5-bit mode",
1725 BranchRM
.simple
: "simple mode",
1726 BranchRM
.vls
: "VLSET mode",
1727 BranchRM
.ctr
: "CTR-test mode",
1728 BranchRM
.ctrvls
: "CTR-test+VLSET mode",
1730 for (cls
, desc
) in table
.items():
1731 if isinstance(rm
, cls
):
1734 raise ValueError(self
)
1736 def disassemble(self
, db
,
1738 verbosity
=Verbosity
.NORMAL
):
1740 if verbosity
<= Verbosity
.SHORT
:
1743 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1744 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1747 blob_prefix
= blob(int(self
.prefix
))
1748 blob_suffix
= blob(int(self
.suffix
))
1750 if record
is None or record
.svp64
is None:
1751 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1752 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1755 operands
= tuple(map(_operator
.itemgetter(1),
1756 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1758 yield f
"{blob_prefix}sv.{record.name} {','.join(operands)}"
1760 yield f
"{blob_prefix}{record.name}"
1762 yield f
"{blob_suffix}"
1764 (rm
, rm_desc
) = self
.rm(db
=db
)
1766 if verbosity
>= Verbosity
.VERBOSE
:
1768 binary
= self
.binary
1769 spec
= self
.spec(db
=db
, prefix
="sv.")
1770 yield f
"{indent}spec"
1771 yield f
"{indent}{indent}{spec}"
1772 yield f
"{indent}pcode"
1773 for stmt
in record
.mdwn
.pcode
:
1774 yield f
"{indent}{indent}{stmt}"
1775 yield f
"{indent}binary"
1776 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1777 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1778 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1779 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1780 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1781 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1782 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1783 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1784 yield f
"{indent}opcodes"
1785 for opcode
in record
.opcodes
:
1786 yield f
"{indent}{indent}{opcode!r}"
1787 for operand
in record
.mdwn
.operands
:
1788 yield from operand
.disassemble(insn
=self
, record
=record
,
1789 verbosity
=verbosity
, indent
=indent
)
1792 yield f
"{indent}{indent}{rm_desc}"
1796 def parse(stream
, factory
):
1798 return ("TODO" not in frozenset(entry
.values()))
1800 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1801 entries
= _csv
.DictReader(lines
)
1802 entries
= filter(match
, entries
)
1803 return tuple(map(factory
, entries
))
1806 class MarkdownDatabase
:
1809 for (name
, desc
) in _ISA():
1812 (dynamic
, *static
) = desc
.regs
1813 operands
.extend(dynamic
)
1814 operands
.extend(static
)
1815 pcode
= PCode(iterable
=desc
.pcode
)
1816 operands
= Operands(insn
=name
, iterable
=operands
)
1817 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
1821 return super().__init
__()
1824 yield from self
.__db
.items()
1826 def __getitem__(self
, key
):
1827 return self
.__db
.__getitem
__(key
)
1830 class FieldsDatabase
:
1833 df
= _DecodeFields()
1835 for (form
, fields
) in df
.instrs
.items():
1836 if form
in {"DQE", "TX"}:
1840 db
[_Form
[form
]] = Fields(fields
)
1844 return super().__init
__()
1846 def __getitem__(self
, key
):
1847 return self
.__db
.__getitem
__(key
)
1851 def __init__(self
, root
, mdwndb
):
1852 # The code below groups the instructions by section:identifier.
1853 # We use the comment as an identifier, there's nothing better.
1854 # The point is to capture different opcodes for the same instruction.
1855 dd
= _collections
.defaultdict
1856 records
= dd(lambda: dd(set))
1857 path
= (root
/ "insndb.csv")
1858 with
open(path
, "r", encoding
="UTF-8") as stream
:
1859 for section
in parse(stream
, Section
.CSV
):
1860 path
= (root
/ section
.path
)
1862 section
.Mode
.INTEGER
: IntegerOpcode
,
1863 section
.Mode
.PATTERN
: PatternOpcode
,
1865 factory
= _functools
.partial(
1866 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1867 with
open(path
, "r", encoding
="UTF-8") as stream
:
1868 for insn
in parse(stream
, factory
):
1869 records
[section
][insn
.comment
].add(insn
)
1872 for (section
, group
) in records
.items():
1873 for records
in group
.values():
1874 db
[section
].add(PPCMultiRecord(records
))
1877 self
.__mdwndb
= mdwndb
1879 return super().__init
__()
1881 def __getitem__(self
, key
):
1882 def exact_match(key
, record
):
1883 return (key
in record
.names
)
1885 def Rc_match(key
, record
):
1886 if not key
.endswith("."):
1889 if record
.Rc
is _RCOE
.NONE
:
1892 return exact_match(key
[:-1], record
)
1894 def LK_match(key
, record
):
1895 if not key
.endswith("l"):
1898 if "lk" not in record
.flags
:
1901 return exact_match(key
[:-1], record
)
1903 def AA_match(key
, record
):
1904 if not key
.endswith("a"):
1907 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1910 if self
.__mdwndb
[key
].operands
["AA"] is None:
1913 return (exact_match(key
[:-1], record
) or
1914 LK_match(key
[:-1], record
))
1916 for (section
, records
) in self
.__db
.items():
1917 for record
in records
:
1918 if exact_match(key
, record
):
1919 return (section
, record
)
1921 for record
in records
:
1922 if (Rc_match(key
, record
) or
1923 LK_match(key
, record
) or
1924 AA_match(key
, record
)):
1925 return (section
, record
)
1930 class SVP64Database
:
1931 def __init__(self
, root
, ppcdb
):
1933 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1934 for (prefix
, _
, names
) in _os
.walk(root
):
1935 prefix
= _pathlib
.Path(prefix
)
1936 for name
in filter(lambda name
: pattern
.match(name
), names
):
1937 path
= (prefix
/ _pathlib
.Path(name
))
1938 with
open(path
, "r", encoding
="UTF-8") as stream
:
1939 db
.update(parse(stream
, SVP64Record
.CSV
))
1941 self
.__db
= {record
.name
:record
for record
in db
}
1942 self
.__ppcdb
= ppcdb
1944 return super().__init
__()
1946 def __getitem__(self
, key
):
1947 (_
, record
) = self
.__ppcdb
[key
]
1951 for name
in record
.names
:
1952 record
= self
.__db
.get(name
, None)
1953 if record
is not None:
1960 def __init__(self
, root
):
1961 root
= _pathlib
.Path(root
)
1962 mdwndb
= MarkdownDatabase()
1963 fieldsdb
= FieldsDatabase()
1964 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1965 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1969 opcodes
= _collections
.defaultdict(set)
1971 for (name
, mdwn
) in mdwndb
:
1972 (section
, ppc
) = ppcdb
[name
]
1975 svp64
= svp64db
[name
]
1976 fields
= fieldsdb
[ppc
.form
]
1977 record
= Record(name
=name
,
1978 section
=section
, ppc
=ppc
, svp64
=svp64
,
1979 mdwn
=mdwn
, fields
=fields
)
1981 names
[record
.name
] = record
1985 opcodes
[PO
.value
].add(record
)
1988 self
.__names
= names
1989 self
.__opcodes
= opcodes
1991 return super().__init
__()
1994 return repr(self
.__db
)
1997 yield from self
.__db
1999 @_functools.lru_cache(maxsize
=None)
2000 def __contains__(self
, key
):
2001 return self
.__getitem
__(key
) is not None
2003 @_functools.lru_cache(maxsize
=None)
2004 def __getitem__(self
, key
):
2005 if isinstance(key
, (int, Instruction
)):
2007 XO
= int(_SelectableInt(value
=int(key
), bits
=32)[0:6])
2008 for record
in self
.__opcodes
[XO
]:
2009 if record
.match(key
=key
):
2012 elif isinstance(key
, str):
2013 return self
.__names
[key
]