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 record(self
, db
):
1070 raise KeyError(self
)
1073 def spec(self
, db
, prefix
):
1074 record
= self
.record(db
=db
)
1076 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1077 self
.dynamic_operands(db
=db
)))
1079 static_operands
= []
1080 for (name
, value
) in self
.static_operands(db
=db
):
1081 static_operands
.append(f
"{name}={value}")
1084 if dynamic_operands
:
1085 operands
+= f
" {','.join(dynamic_operands)}"
1087 operands
+= f
" ({' '.join(static_operands)})"
1089 return f
"{prefix}{record.name}{operands}"
1091 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1092 record
= self
.record(db
=db
)
1097 for operand
in record
.mdwn
.operands
.dynamic
:
1099 dis
= operand
.disassemble(insn
=self
, record
=record
,
1100 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1101 value
= " ".join(dis
)
1103 name
= f
"{imm_name}({name})"
1104 value
= f
"{imm_value}({value})"
1106 if isinstance(operand
, ImmediateOperand
):
1113 def static_operands(self
, db
):
1114 record
= self
.record(db
=db
)
1115 for operand
in record
.mdwn
.operands
.static
:
1116 yield (operand
.name
, operand
.value
)
1118 def disassemble(self
, db
,
1120 verbosity
=Verbosity
.NORMAL
):
1121 raise NotImplementedError
1124 class WordInstruction(Instruction
):
1125 _
: _Field
= range(0, 32)
1126 po
: _Field
= range(0, 6)
1129 def integer(cls
, value
, byteorder
="little"):
1130 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1135 for idx
in range(32):
1136 bit
= int(self
[idx
])
1138 return "".join(map(str, bits
))
1140 def disassemble(self
, db
,
1142 verbosity
=Verbosity
.NORMAL
):
1144 if verbosity
<= Verbosity
.SHORT
:
1147 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1148 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1153 yield f
"{blob}.long 0x{integer:08x}"
1156 operands
= tuple(map(_operator
.itemgetter(1),
1157 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1159 yield f
"{blob}{record.name} {','.join(operands)}"
1161 yield f
"{blob}{record.name}"
1163 if verbosity
>= Verbosity
.VERBOSE
:
1165 binary
= self
.binary
1166 spec
= self
.spec(db
=db
, prefix
="")
1167 yield f
"{indent}spec"
1168 yield f
"{indent}{indent}{spec}"
1169 yield f
"{indent}pcode"
1170 for stmt
in record
.mdwn
.pcode
:
1171 yield f
"{indent}{indent}{stmt}"
1172 yield f
"{indent}binary"
1173 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1174 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1175 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1176 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1177 yield f
"{indent}opcodes"
1178 for opcode
in record
.opcodes
:
1179 yield f
"{indent}{indent}{opcode!r}"
1180 for operand
in record
.mdwn
.operands
:
1181 yield from operand
.disassemble(insn
=self
, record
=record
,
1182 verbosity
=verbosity
, indent
=indent
)
1186 class PrefixedInstruction(Instruction
):
1187 class Prefix(WordInstruction
.remap(range(0, 32))):
1190 class Suffix(WordInstruction
.remap(range(32, 64))):
1193 _
: _Field
= range(64)
1199 def integer(cls
, value
, byteorder
="little"):
1200 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1203 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1204 def transform(value
):
1205 return WordInstruction
.integer(value
=value
,
1206 byteorder
=byteorder
)[0:32]
1208 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1209 value
= _selectconcat(prefix
, suffix
)
1211 return super().integer(value
=value
)
1214 class Mode(_Mapping
):
1215 _
: _Field
= range(0, 5)
1218 class Extra(_Mapping
):
1219 _
: _Field
= range(0, 9)
1222 class Extra2(Extra
):
1223 idx0
: _Field
= range(0, 2)
1224 idx1
: _Field
= range(2, 4)
1225 idx2
: _Field
= range(4, 6)
1226 idx3
: _Field
= range(6, 8)
1228 def __getitem__(self
, key
):
1234 _SVExtra
.Idx0
: self
.idx0
,
1235 _SVExtra
.Idx1
: self
.idx1
,
1236 _SVExtra
.Idx2
: self
.idx2
,
1237 _SVExtra
.Idx3
: self
.idx3
,
1240 def __setitem__(self
, key
, value
):
1241 self
[key
].assign(value
)
1244 class Extra3(Extra
):
1245 idx0
: _Field
= range(0, 3)
1246 idx1
: _Field
= range(3, 6)
1247 idx2
: _Field
= range(6, 9)
1249 def __getitem__(self
, key
):
1254 _SVExtra
.Idx0
: self
.idx0
,
1255 _SVExtra
.Idx1
: self
.idx1
,
1256 _SVExtra
.Idx2
: self
.idx2
,
1259 def __setitem__(self
, key
, value
):
1260 self
[key
].assign(value
)
1263 class BaseRM(_Mapping
):
1264 _
: _Field
= range(24)
1265 mmode
: _Field
= (0,)
1266 mask
: _Field
= range(1, 4)
1267 elwidth
: _Field
= range(4, 6)
1268 ewsrc
: _Field
= range(6, 8)
1269 subvl
: _Field
= range(8, 10)
1270 mode
: Mode
.remap(range(19, 24))
1271 smask
: _Field
= range(16, 19)
1273 extra
: Extra
.remap(range(10, 19))
1274 extra2
: Extra2
.remap(range(10, 19))
1275 extra3
: Extra3
.remap(range(10, 19))
1278 class NormalRM(BaseRM
):
1279 class simple(BaseRM
):
1285 """scalar reduce mode (mapreduce), SUBVL=1"""
1289 """parallel reduce mode (mapreduce), SUBVL=1"""
1293 """subvector reduce mode, SUBVL>1"""
1297 """Pack/Unpack mode, SUBVL>1"""
1301 """Rc=1: ffirst CR sel"""
1303 CR
: BaseRM
.mode
[3, 4]
1306 """Rc=0: ffirst z/nonz"""
1312 """sat mode: N=0/1 u/s, SUBVL=1"""
1318 """sat mode: N=0/1 u/s, SUBVL>1"""
1325 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1332 """Rc=1: pred-result CR sel"""
1334 CR
: BaseRM
.mode
[3, 4]
1337 """Rc=0: pred-result z/nonz"""
1358 class LDSTImmRM(BaseRM
):
1367 """Structured Pack/Unpack"""
1374 """Rc=1: ffirst CR sel"""
1376 CR
: BaseRM
.mode
[3, 4]
1379 """Rc=0: ffirst z/nonz"""
1385 """sat mode: N=0/1 u/s"""
1393 """Rc=1: pred-result CR sel"""
1395 CR
: BaseRM
.mode
[3, 4]
1398 """Rc=0: pred-result z/nonz"""
1412 class LDSTIdxRM(BaseRM
):
1420 """strided (scalar only source)"""
1426 """sat mode: N=0/1 u/s"""
1432 """Rc=1: pred-result CR sel"""
1434 CR
: BaseRM
.mode
[3, 4]
1437 """Rc=0: pred-result z/nonz"""
1451 class CROpRM(BaseRM
):
1452 class simple(BaseRM
):
1460 """scalar reduce mode (mapreduce), SUBVL=1"""
1466 """subvector reduce mode, SUBVL>1"""
1474 class reserved(BaseRM
):
1483 """ffirst 3-bit mode"""
1493 """ffirst 5-bit mode"""
1510 class BranchBaseRM(BaseRM
):
1519 class BranchRM(BranchBaseRM
):
1520 class simple(BranchBaseRM
):
1524 class vls(BranchBaseRM
):
1529 class ctr(BranchBaseRM
):
1533 class ctrvls(vls
, ctr
):
1534 """CTR-test+VLSET mode"""
1545 class SVP64Instruction(PrefixedInstruction
):
1546 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1547 class Prefix(PrefixedInstruction
.Prefix
):
1549 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1553 def record(self
, db
):
1554 record
= db
[self
.suffix
]
1556 raise KeyError(self
)
1562 for idx
in range(64):
1563 bit
= int(self
[idx
])
1565 return "".join(map(str, bits
))
1568 record
= self
.record(db
=db
)
1571 if record
.mdwn
.operands
["Rc"] is not None:
1572 Rc
= bool(self
[record
.fields
["Rc"]])
1574 record
= self
.record(db
=db
)
1575 subvl
= self
.prefix
.rm
.subvl
1578 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1580 if rm
.mode
[0:2] == 0b00:
1581 if rm
.mode
[2] == 0b0:
1585 if rm
.mode
[3] == 0b0:
1590 if rm
.mode
[4] == 0b0:
1594 elif rm
.mode
[0:2] == 0b01:
1599 elif rm
.mode
[0:2] == 0b10:
1607 elif rm
.mode
[0:2] == 0b11:
1613 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1615 if rm
.mode
[0:2] == 0b00:
1616 if rm
.mode
[2] == 0b0:
1620 elif rm
.mode
[0:2] == 0b01:
1625 elif rm
.mode
[0:2] == 0b10:
1627 elif rm
.mode
[0:2] == 0b11:
1633 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1635 if rm
.mode
[0:2] == 0b00:
1637 elif rm
.mode
[0:2] == 0b01:
1639 elif rm
.mode
[0:2] == 0b10:
1641 elif rm
.mode
[0:2] == 0b11:
1647 elif record
.svp64
.mode
is _SVMode
.CROP
:
1662 for idx
in range(0, 4):
1663 for entry
in record
.svp64
.extra
[idx
]:
1664 if entry
.regtype
is _SVExtraRegType
.DST
:
1665 if regtype
is not None:
1666 raise ValueError(record
.svp64
)
1667 regtype
= _RegType(entry
.reg
)
1668 if regtype
is _RegType
.CR_REG
:
1670 elif regtype
is _RegType
.CR_BIT
:
1673 raise ValueError(record
.svp64
)
1675 elif record
.svp64
.mode
is _SVMode
.BRANCH
:
1688 raise ValueError(self
)
1691 NormalRM
.simple
: "normal: simple",
1692 NormalRM
.smr
: "normal: smr",
1693 NormalRM
.pmr
: "normal: pmr",
1694 NormalRM
.svmr
: "normal: svmr",
1695 NormalRM
.pu
: "normal: pu",
1696 NormalRM
.ffrc1
: "normal: ffrc1",
1697 NormalRM
.ffrc0
: "normal: ffrc0",
1698 NormalRM
.sat
: "normal: sat",
1699 NormalRM
.satx
: "normal: satx",
1700 NormalRM
.satpu
: "normal: satpu",
1701 NormalRM
.prrc1
: "normal: prrc1",
1702 NormalRM
.prrc0
: "normal: prrc0",
1703 LDSTImmRM
.simple
: "ld/st imm: simple",
1704 LDSTImmRM
.spu
: "ld/st imm: spu",
1705 LDSTImmRM
.ffrc1
: "ld/st imm: ffrc1",
1706 LDSTImmRM
.ffrc0
: "ld/st imm: ffrc0",
1707 LDSTImmRM
.sat
: "ld/st imm: sat",
1708 LDSTImmRM
.prrc1
: "ld/st imm: prrc1",
1709 LDSTImmRM
.prrc0
: "ld/st imm: prrc0",
1710 LDSTIdxRM
.simple
: "ld/st idx: simple",
1711 LDSTIdxRM
.stride
: "ld/st idx: stride",
1712 LDSTIdxRM
.sat
: "ld/st idx: sat",
1713 LDSTIdxRM
.prrc1
: "ld/st idx: prrc1",
1714 LDSTIdxRM
.prrc0
: "ld/st idx: prrc0",
1715 CROpRM
.simple
: "simple mode",
1716 CROpRM
.smr
: "scalar reduce mode (mapreduce), SUBVL=1",
1717 CROpRM
.svmr
: "subvector reduce mode, SUBVL>1",
1718 CROpRM
.reserved
: "reserved",
1719 CROpRM
.ff3
: "ffirst 3-bit mode",
1720 CROpRM
.ff5
: "ffirst 5-bit mode",
1721 BranchRM
.simple
: "simple mode",
1722 BranchRM
.vls
: "VLSET mode",
1723 BranchRM
.ctr
: "CTR-test mode",
1724 BranchRM
.ctrvls
: "CTR-test+VLSET mode",
1726 for (cls
, desc
) in table
.items():
1727 if isinstance(rm
, cls
):
1730 raise ValueError(self
)
1732 def disassemble(self
, db
,
1734 verbosity
=Verbosity
.NORMAL
):
1736 if verbosity
<= Verbosity
.SHORT
:
1739 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1740 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1743 blob_prefix
= blob(int(self
.prefix
))
1744 blob_suffix
= blob(int(self
.suffix
))
1746 if record
is None or record
.svp64
is None:
1747 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1748 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1751 operands
= tuple(map(_operator
.itemgetter(1),
1752 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1754 yield f
"{blob_prefix}sv.{record.name} {','.join(operands)}"
1756 yield f
"{blob_prefix}{record.name}"
1758 yield f
"{blob_suffix}"
1760 (rm
, rm_desc
) = self
.rm(db
=db
)
1762 if verbosity
>= Verbosity
.VERBOSE
:
1764 binary
= self
.binary
1765 spec
= self
.spec(db
=db
, prefix
="sv.")
1766 yield f
"{indent}spec"
1767 yield f
"{indent}{indent}{spec}"
1768 yield f
"{indent}pcode"
1769 for stmt
in record
.mdwn
.pcode
:
1770 yield f
"{indent}{indent}{stmt}"
1771 yield f
"{indent}binary"
1772 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1773 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1774 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1775 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1776 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1777 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1778 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1779 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1780 yield f
"{indent}opcodes"
1781 for opcode
in record
.opcodes
:
1782 yield f
"{indent}{indent}{opcode!r}"
1783 for operand
in record
.mdwn
.operands
:
1784 yield from operand
.disassemble(insn
=self
, record
=record
,
1785 verbosity
=verbosity
, indent
=indent
)
1788 yield f
"{indent}{indent}{rm_desc}"
1792 def parse(stream
, factory
):
1794 return ("TODO" not in frozenset(entry
.values()))
1796 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1797 entries
= _csv
.DictReader(lines
)
1798 entries
= filter(match
, entries
)
1799 return tuple(map(factory
, entries
))
1802 class MarkdownDatabase
:
1805 for (name
, desc
) in _ISA():
1808 (dynamic
, *static
) = desc
.regs
1809 operands
.extend(dynamic
)
1810 operands
.extend(static
)
1811 pcode
= PCode(iterable
=desc
.pcode
)
1812 operands
= Operands(insn
=name
, iterable
=operands
)
1813 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
1817 return super().__init
__()
1820 yield from self
.__db
.items()
1822 def __getitem__(self
, key
):
1823 return self
.__db
.__getitem
__(key
)
1826 class FieldsDatabase
:
1829 df
= _DecodeFields()
1831 for (form
, fields
) in df
.instrs
.items():
1832 if form
in {"DQE", "TX"}:
1836 db
[_Form
[form
]] = Fields(fields
)
1840 return super().__init
__()
1842 def __getitem__(self
, key
):
1843 return self
.__db
.__getitem
__(key
)
1847 def __init__(self
, root
, mdwndb
):
1848 # The code below groups the instructions by section:identifier.
1849 # We use the comment as an identifier, there's nothing better.
1850 # The point is to capture different opcodes for the same instruction.
1851 dd
= _collections
.defaultdict
1852 records
= dd(lambda: dd(set))
1853 path
= (root
/ "insndb.csv")
1854 with
open(path
, "r", encoding
="UTF-8") as stream
:
1855 for section
in parse(stream
, Section
.CSV
):
1856 path
= (root
/ section
.path
)
1858 section
.Mode
.INTEGER
: IntegerOpcode
,
1859 section
.Mode
.PATTERN
: PatternOpcode
,
1861 factory
= _functools
.partial(
1862 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1863 with
open(path
, "r", encoding
="UTF-8") as stream
:
1864 for insn
in parse(stream
, factory
):
1865 records
[section
][insn
.comment
].add(insn
)
1868 for (section
, group
) in records
.items():
1869 for records
in group
.values():
1870 db
[section
].add(PPCMultiRecord(records
))
1873 self
.__mdwndb
= mdwndb
1875 return super().__init
__()
1877 def __getitem__(self
, key
):
1878 def exact_match(key
, record
):
1879 return (key
in record
.names
)
1881 def Rc_match(key
, record
):
1882 if not key
.endswith("."):
1885 if record
.Rc
is _RCOE
.NONE
:
1888 return exact_match(key
[:-1], record
)
1890 def LK_match(key
, record
):
1891 if not key
.endswith("l"):
1894 if "lk" not in record
.flags
:
1897 return exact_match(key
[:-1], record
)
1899 def AA_match(key
, record
):
1900 if not key
.endswith("a"):
1903 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1906 if self
.__mdwndb
[key
].operands
["AA"] is None:
1909 return (exact_match(key
[:-1], record
) or
1910 LK_match(key
[:-1], record
))
1912 for (section
, records
) in self
.__db
.items():
1913 for record
in records
:
1914 if exact_match(key
, record
):
1915 return (section
, record
)
1917 for record
in records
:
1918 if (Rc_match(key
, record
) or
1919 LK_match(key
, record
) or
1920 AA_match(key
, record
)):
1921 return (section
, record
)
1926 class SVP64Database
:
1927 def __init__(self
, root
, ppcdb
):
1929 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1930 for (prefix
, _
, names
) in _os
.walk(root
):
1931 prefix
= _pathlib
.Path(prefix
)
1932 for name
in filter(lambda name
: pattern
.match(name
), names
):
1933 path
= (prefix
/ _pathlib
.Path(name
))
1934 with
open(path
, "r", encoding
="UTF-8") as stream
:
1935 db
.update(parse(stream
, SVP64Record
.CSV
))
1937 self
.__db
= {record
.name
:record
for record
in db
}
1938 self
.__ppcdb
= ppcdb
1940 return super().__init
__()
1942 def __getitem__(self
, key
):
1943 (_
, record
) = self
.__ppcdb
[key
]
1947 for name
in record
.names
:
1948 record
= self
.__db
.get(name
, None)
1949 if record
is not None:
1956 def __init__(self
, root
):
1957 root
= _pathlib
.Path(root
)
1958 mdwndb
= MarkdownDatabase()
1959 fieldsdb
= FieldsDatabase()
1960 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1961 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1965 opcodes
= _collections
.defaultdict(set)
1967 for (name
, mdwn
) in mdwndb
:
1968 (section
, ppc
) = ppcdb
[name
]
1971 svp64
= svp64db
[name
]
1972 fields
= fieldsdb
[ppc
.form
]
1973 record
= Record(name
=name
,
1974 section
=section
, ppc
=ppc
, svp64
=svp64
,
1975 mdwn
=mdwn
, fields
=fields
)
1977 names
[record
.name
] = record
1981 opcodes
[PO
.value
].add(record
)
1984 self
.__names
= names
1985 self
.__opcodes
= opcodes
1987 return super().__init
__()
1990 return repr(self
.__db
)
1993 yield from self
.__db
1995 @_functools.lru_cache(maxsize
=None)
1996 def __contains__(self
, key
):
1997 return self
.__getitem
__(key
) is not None
1999 @_functools.lru_cache(maxsize
=None)
2000 def __getitem__(self
, key
):
2001 if isinstance(key
, (int, Instruction
)):
2003 XO
= int(_SelectableInt(value
=int(key
), bits
=32)[0:6])
2004 for record
in self
.__opcodes
[XO
]:
2005 if record
.match(key
=key
):
2008 elif isinstance(key
, str):
2009 return self
.__names
[key
]