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 CROutSel
as _CROutSel
,
27 LDSTMode
as _LDSTMode
,
36 SVExtraRegType
as _SVExtraRegType
,
37 SVExtraReg
as _SVExtraReg
,
39 from openpower
.decoder
.selectable_int
import (
40 SelectableInt
as _SelectableInt
,
41 selectconcat
as _selectconcat
,
43 from openpower
.decoder
.power_fields
import (
46 DecodeFields
as _DecodeFields
,
48 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
51 @_functools.total_ordering
52 class Verbosity(_enum
.Enum
):
55 VERBOSE
= _enum
.auto()
57 def __lt__(self
, other
):
58 if not isinstance(other
, self
.__class
__):
60 return (self
.value
< other
.value
)
63 def dataclass(cls
, record
, keymap
=None, typemap
=None):
67 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
69 def transform(key_value
):
70 (key
, value
) = key_value
71 key
= keymap
.get(key
, key
)
72 hook
= typemap
.get(key
, lambda value
: value
)
73 if hook
is bool and value
in ("", "0"):
79 record
= dict(map(transform
, record
.items()))
80 for key
in frozenset(record
.keys()):
87 @_functools.total_ordering
88 @_dataclasses.dataclass(eq
=True, frozen
=True)
91 def __new__(cls
, value
):
92 if isinstance(value
, str):
94 if not isinstance(value
, int):
95 raise ValueError(value
)
97 if value
.bit_length() > 64:
98 raise ValueError(value
)
100 return super().__new
__(cls
, value
)
103 return super().__repr
__()
106 return f
"{self:0{self.bit_length()}b}"
108 def bit_length(self
):
109 if super().bit_length() > 32:
113 class Value(Integer
):
122 def __lt__(self
, other
):
123 if not isinstance(other
, Opcode
):
124 return NotImplemented
125 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
127 def __post_init__(self
):
128 if self
.value
.bit_length() != self
.mask
.bit_length():
129 raise ValueError("bit length mismatch")
132 def pattern(value
, mask
, bit_length
):
133 for bit
in range(bit_length
):
134 if ((mask
& (1 << (bit_length
- bit
- 1))) == 0):
136 elif (value
& (1 << (bit_length
- bit
- 1))):
141 return "".join(pattern(self
.value
, self
.mask
, self
.value
.bit_length()))
144 class IntegerOpcode(Opcode
):
145 def __init__(self
, value
):
146 if value
.startswith("0b"):
147 mask
= int(("1" * len(value
[2:])), 2)
151 value
= Opcode
.Value(value
)
152 mask
= Opcode
.Mask(mask
)
154 return super().__init
__(value
=value
, mask
=mask
)
157 class PatternOpcode(Opcode
):
158 def __init__(self
, pattern
):
159 if not isinstance(pattern
, str):
160 raise ValueError(pattern
)
162 (value
, mask
) = (0, 0)
163 for symbol
in pattern
:
164 if symbol
not in {"0", "1", "-"}:
165 raise ValueError(pattern
)
166 value |
= (symbol
== "1")
167 mask |
= (symbol
!= "-")
173 value
= Opcode
.Value(value
)
174 mask
= Opcode
.Mask(mask
)
176 return super().__init
__(value
=value
, mask
=mask
)
179 @_dataclasses.dataclass(eq
=True, frozen
=True)
181 class FlagsMeta(type):
196 class Flags(frozenset, metaclass
=FlagsMeta
):
197 def __new__(cls
, flags
=frozenset()):
198 flags
= frozenset(flags
)
199 diff
= (flags
- frozenset(cls
))
201 raise ValueError(flags
)
202 return super().__new
__(cls
, flags
)
206 flags
: Flags
= Flags()
208 function
: _Function
= _Function
.NONE
209 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
210 in1
: _In1Sel
= _In1Sel
.RA
211 in2
: _In2Sel
= _In2Sel
.NONE
212 in3
: _In3Sel
= _In3Sel
.NONE
213 out
: _OutSel
= _OutSel
.NONE
214 cr_in
: _CRInSel
= _CRInSel
.NONE
215 cr_out
: _CROutSel
= _CROutSel
.NONE
216 cry_in
: _CryIn
= _CryIn
.ZERO
217 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
218 upd
: _LDSTMode
= _LDSTMode
.NONE
219 Rc
: _RCOE
= _RCOE
.NONE
220 form
: _Form
= _Form
.NONE
222 unofficial
: bool = False
226 "internal op": "intop",
230 "ldst len": "ldst_len",
232 "CONDITIONS": "conditions",
236 def CSV(cls
, record
, opcode_cls
):
237 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
238 typemap
["opcode"] = opcode_cls
241 for flag
in frozenset(PPCRecord
.Flags
):
242 if bool(record
.pop(flag
, "")):
244 record
["flags"] = PPCRecord
.Flags(flags
)
246 return dataclass(cls
, record
,
247 keymap
=PPCRecord
.__KEYMAP
,
252 return frozenset(self
.comment
.split("=")[-1].split("/"))
255 class PPCMultiRecord(tuple):
256 def __getattr__(self
, attr
):
258 raise AttributeError(attr
)
259 return getattr(self
[0], attr
)
262 @_dataclasses.dataclass(eq
=True, frozen
=True)
264 class ExtraMap(tuple):
266 @_dataclasses.dataclass(eq
=True, frozen
=True)
268 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
269 reg
: _SVExtraReg
= _SVExtraReg
.NONE
272 return f
"{self.regtype.value}:{self.reg.name}"
274 def __new__(cls
, value
="0"):
275 if isinstance(value
, str):
276 def transform(value
):
277 (regtype
, reg
) = value
.split(":")
278 regtype
= _SVExtraRegType(regtype
)
279 reg
= _SVExtraReg(reg
)
280 return cls
.Entry(regtype
=regtype
, reg
=reg
)
285 value
= map(transform
, value
.split(";"))
287 return super().__new
__(cls
, value
)
290 return repr(list(self
))
292 def __new__(cls
, value
=tuple()):
296 return super().__new
__(cls
, map(cls
.Extra
, value
))
299 return repr({index
:self
[index
] for index
in range(0, 4)})
302 ptype
: _SVPtype
= _SVPtype
.NONE
303 etype
: _SVEtype
= _SVEtype
.NONE
304 in1
: _In1Sel
= _In1Sel
.NONE
305 in2
: _In2Sel
= _In2Sel
.NONE
306 in3
: _In3Sel
= _In3Sel
.NONE
307 out
: _OutSel
= _OutSel
.NONE
308 out2
: _OutSel
= _OutSel
.NONE
309 cr_in
: _CRInSel
= _CRInSel
.NONE
310 cr_out
: _CROutSel
= _CROutSel
.NONE
311 extra
: ExtraMap
= ExtraMap()
313 mode
: _SVMode
= _SVMode
.NORMAL
317 "CONDITIONS": "conditions",
325 def CSV(cls
, record
):
326 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
332 for idx
in range(0, 4):
333 extra
.append(record
.pop(f
"{idx}"))
335 record
["extra"] = cls
.ExtraMap(extra
)
337 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
339 @_functools.lru_cache(maxsize
=None)
340 def extra_idx(self
, key
):
348 if key
not in frozenset({
349 "in1", "in2", "in3", "cr_in",
350 "out", "out2", "cr_out",
354 sel
= getattr(self
, key
)
355 if sel
is _CRInSel
.BA_BB
:
356 return _SVExtra
.Idx_1_2
357 reg
= _SVExtraReg(sel
)
358 if reg
is _SVExtraReg
.NONE
:
362 _SVExtraRegType
.SRC
: {},
363 _SVExtraRegType
.DST
: {},
365 for index
in range(0, 4):
366 for entry
in self
.extra
[index
]:
367 extra_map
[entry
.regtype
][entry
.reg
] = extra_idx
[index
]
369 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
370 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
371 if extra
is not _SVExtra
.NONE
:
376 extra_idx_in1
= property(_functools
.partial(extra_idx
, key
="in1"))
377 extra_idx_in2
= property(_functools
.partial(extra_idx
, key
="in2"))
378 extra_idx_in3
= property(_functools
.partial(extra_idx
, key
="in3"))
379 extra_idx_out
= property(_functools
.partial(extra_idx
, key
="out"))
380 extra_idx_out2
= property(_functools
.partial(extra_idx
, key
="out2"))
381 extra_idx_cr_in
= property(_functools
.partial(extra_idx
, key
="cr_in"))
382 extra_idx_cr_out
= property(_functools
.partial(extra_idx
, key
="cr_out"))
384 @_functools.lru_cache(maxsize
=None)
385 def extra_reg(self
, key
):
386 return _SVExtraReg(getattr(self
, key
))
388 extra_reg_in1
= property(_functools
.partial(extra_reg
, key
="in1"))
389 extra_reg_in2
= property(_functools
.partial(extra_reg
, key
="in2"))
390 extra_reg_in3
= property(_functools
.partial(extra_reg
, key
="in3"))
391 extra_reg_out
= property(_functools
.partial(extra_reg
, key
="out"))
392 extra_reg_out2
= property(_functools
.partial(extra_reg
, key
="out2"))
393 extra_reg_cr_in
= property(_functools
.partial(extra_reg
, key
="cr_in"))
394 extra_reg_cr_out
= property(_functools
.partial(extra_reg
, key
="cr_out"))
398 def __init__(self
, value
=(0, 32)):
399 if isinstance(value
, str):
400 (start
, end
) = map(int, value
.split(":"))
403 if start
< 0 or end
< 0 or start
>= end
:
404 raise ValueError(value
)
409 return super().__init
__()
412 return f
"[{self.__start}:{self.__end}]"
415 yield from range(self
.start
, (self
.end
+ 1))
417 def __reversed__(self
):
418 return tuple(reversed(tuple(self
)))
429 @_dataclasses.dataclass(eq
=True, frozen
=True)
431 class Mode(_enum
.Enum
):
432 INTEGER
= _enum
.auto()
433 PATTERN
= _enum
.auto()
436 def _missing_(cls
, value
):
437 if isinstance(value
, str):
438 return cls
[value
.upper()]
439 return super()._missing
_(value
)
442 def __new__(cls
, value
=None):
443 if isinstance(value
, str):
444 if value
.upper() == "NONE":
447 value
= int(value
, 0)
451 return super().__new
__(cls
, value
)
457 return (bin(self
) if self
else "None")
463 opcode
: IntegerOpcode
= None
466 def CSV(cls
, record
):
467 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
468 if record
["opcode"] == "NONE":
469 typemap
["opcode"] = lambda _
: None
471 return dataclass(cls
, record
, typemap
=typemap
)
475 def __init__(self
, items
):
476 if isinstance(items
, dict):
477 items
= items
.items()
480 (name
, bitrange
) = item
481 return (name
, tuple(bitrange
.values()))
483 self
.__mapping
= dict(map(transform
, items
))
485 return super().__init
__()
488 return repr(self
.__mapping
)
491 yield from self
.__mapping
.items()
493 def __contains__(self
, key
):
494 return self
.__mapping
.__contains
__(key
)
496 def __getitem__(self
, key
):
497 return self
.__mapping
.get(key
, None)
500 @_dataclasses.dataclass(eq
=True, frozen
=True)
504 def span(self
, record
):
505 return record
.fields
[self
.name
]
507 def disassemble(self
, insn
, record
,
508 verbosity
=Verbosity
.NORMAL
, indent
=""):
509 raise NotImplementedError
512 class DynamicOperand(Operand
):
513 def disassemble(self
, insn
, record
,
514 verbosity
=Verbosity
.NORMAL
, indent
=""):
515 span
= self
.span(record
=record
)
516 if isinstance(insn
, SVP64Instruction
):
517 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
520 if verbosity
>= Verbosity
.VERBOSE
:
521 span
= map(str, span
)
522 yield f
"{indent}{self.name}"
523 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
524 yield f
"{indent}{indent}{', '.join(span)}"
526 yield str(int(value
))
529 @_dataclasses.dataclass(eq
=True, frozen
=True)
530 class StaticOperand(Operand
):
533 def disassemble(self
, insn
, record
,
534 verbosity
=Verbosity
.NORMAL
, indent
=""):
535 span
= self
.span(record
=record
)
536 if isinstance(insn
, SVP64Instruction
):
537 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
540 if verbosity
>= Verbosity
.VERBOSE
:
541 span
= map(str, span
)
542 yield f
"{indent}{self.name}"
543 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
544 yield f
"{indent}{indent}{', '.join(span)}"
546 yield str(int(value
))
549 class ImmediateOperand(DynamicOperand
):
553 class NonZeroOperand(DynamicOperand
):
554 def disassemble(self
, insn
, record
,
555 verbosity
=Verbosity
.NORMAL
, indent
=""):
556 span
= self
.span(record
=record
)
557 if isinstance(insn
, SVP64Instruction
):
558 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
561 if verbosity
>= Verbosity
.VERBOSE
:
562 span
= map(str, span
)
563 yield f
"{indent}{self.name}"
564 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
565 yield f
"{indent}{indent}{', '.join(span)}"
567 yield str(int(value
) + 1)
570 class RegisterOperand(DynamicOperand
):
571 def spec(self
, insn
, record
, merge
):
573 span
= self
.span(record
=record
)
574 if isinstance(insn
, SVP64Instruction
):
575 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
577 span
= tuple(map(str, span
))
579 if isinstance(insn
, SVP64Instruction
):
580 extra_idx
= self
.extra_idx(record
=record
)
581 if extra_idx
is _SVExtra
.NONE
:
582 return (vector
, value
, span
)
584 if record
.etype
is _SVEtype
.EXTRA3
:
585 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
586 elif record
.etype
is _SVEtype
.EXTRA2
:
587 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
589 raise ValueError(record
.etype
)
592 vector
= bool(spec
[0])
593 spec_span
= spec
.__class
__
594 if record
.etype
is _SVEtype
.EXTRA3
:
595 spec_span
= tuple(map(str, spec_span
[1, 2]))
597 elif record
.etype
is _SVEtype
.EXTRA2
:
598 spec_span
= tuple(map(str, spec_span
[1,]))
599 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
602 spec_span
= (spec_span
+ ("{0}",))
604 spec_span
= (("{0}",) + spec_span
)
606 raise ValueError(record
.etype
)
608 (value
, span
) = merge(vector
, value
, span
, spec
, spec_span
)
610 return (vector
, value
, span
)
614 return _SVExtraReg(self
.name
)
616 def extra_idx(self
, record
):
617 for key
in frozenset({
618 "in1", "in2", "in3", "cr_in",
619 "out", "out2", "cr_out",
621 extra_reg
= record
.svp64
.extra_reg(key
=key
)
622 if extra_reg
is self
.extra_reg
:
623 return record
.extra_idx(key
=key
)
627 def disassemble(self
, insn
, record
,
628 verbosity
=Verbosity
.NORMAL
, prefix
="", indent
=""):
629 (vector
, value
, span
) = self
.spec(insn
=insn
, record
=record
)
631 if verbosity
>= Verbosity
.VERBOSE
:
632 mode
= "vector" if vector
else "scalar"
633 yield f
"{indent}{self.name} ({mode})"
634 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
635 yield f
"{indent}{indent}{', '.join(span)}"
636 if isinstance(insn
, SVP64Instruction
):
637 extra_idx
= self
.extra_idx(record
)
638 if record
.etype
is _SVEtype
.NONE
:
639 yield f
"{indent}{indent}extra[none]"
641 etype
= repr(record
.etype
).lower()
642 yield f
"{indent}{indent}{etype}{extra_idx!r}"
644 vector
= "*" if vector
else ""
645 yield f
"{vector}{prefix}{int(value)}"
648 class GPRFPROperand(RegisterOperand
):
649 def spec(self
, insn
, record
):
650 def merge(vector
, value
, span
, spec
, spec_span
):
651 bits
= (len(span
) + len(spec_span
))
652 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
653 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
654 # this is silly these should be in a general base class,
655 # settable by constructor
660 value
= ((value
<< vshift
) |
(spec
<<spshft
))
661 span
= (span
+ spec_span
)
663 value
= ((spec
<< sshift
) | value
)
664 span
= (spec_span
+ span
)
668 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
671 class GPROperand(GPRFPROperand
):
672 def disassemble(self
, insn
, record
,
673 verbosity
=Verbosity
.NORMAL
, indent
=""):
674 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "r"
675 yield from super().disassemble(prefix
=prefix
,
676 insn
=insn
, record
=record
,
677 verbosity
=verbosity
, indent
=indent
)
680 class FPROperand(GPRFPROperand
):
681 def disassemble(self
, insn
, record
,
682 verbosity
=Verbosity
.NORMAL
, indent
=""):
683 prefix
= "" if (verbosity
<= Verbosity
.SHORT
) else "f"
684 yield from super().disassemble(prefix
=prefix
,
685 insn
=insn
, record
=record
,
686 verbosity
=verbosity
, indent
=indent
)
689 class CR3Operand(RegisterOperand
):
690 def spec(self
, insn
, record
):
691 def merge(vector
, value
, span
, spec
, spec_span
):
692 bits
= (len(span
) + len(spec_span
))
693 #print ("value", bin(value.value), value.bits)
694 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
695 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
696 #print ("spec", bin(spec.value), spec.bits)
697 #print ("value", bin(value.value), value.bits)
698 #print ("lsbs", bin(lsbs.value), lsbs.bits)
699 # this is silly these should be in a general base class,
700 # settable by constructor
705 value
= ((value
<< vshift
) |
(spec
<<spshft
))
706 span
= (span
[0:3] + spec_span
+ ('{0}', '{0}') + span
[3:5])
708 value
= ((spec
<< sshift
) | value
)
709 span
= (('{0}', '{0}') + spec_span
+ span
)
711 # add the 2 LSBs back in
712 #print ("after", bin(value.value), value.bits)
715 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
718 # exactly the same as CR3Operand, should be exactly the same base class
719 # which should also be exactly the same base class as GPR and FPR operand
720 # which sohuld be taking a constructor with prefix "r" and "f" as options
721 # as well as vshift, sshift and spsft as parameters, and whether
722 # to skip 2 LSBs and put them back on afterwards.
723 # it's all the exact same scheme, so why on earth duplicate code?
724 class CR5Operand(RegisterOperand
):
725 def spec(self
, insn
, record
):
726 def merge(vector
, value
, span
, spec
, spec_span
):
727 # record the 2 lsbs first
728 lsbs
= _SelectableInt(value
=value
.value
&3, bits
=2)
729 bits
= (len(span
) + len(spec_span
))
730 #print ("value", bin(value.value), value.bits)
731 value
= _SelectableInt(value
=value
.value
>>2, bits
=bits
)
732 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
733 #print ("spec", bin(spec.value), spec.bits)
734 #print ("value", bin(value.value), value.bits)
735 #print ("lsbs", bin(lsbs.value), lsbs.bits)
736 # this is silly these should be in a general base class,
737 # settable by constructor
742 value
= ((value
<< vshift
) |
(spec
<<spshft
))
743 span
= (span
[0:3] + spec_span
+ ('{0}', '{0}') + span
[3:5])
745 value
= ((spec
<< sshift
) | value
)
746 span
= (('{0}', '{0}') + spec_span
+ span
)
748 # add the 2 LSBs back in
749 res
= _SelectableInt(value
=(value
.value
<<2)+lsbs
.value
, bits
=bits
+2)
750 #print ("after", bin(value.value), value.bits)
751 #print ("res", bin(res.value), res.bits)
754 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
757 # this is silly, all of these should be the same base class
758 class DynamicOperandCR(RegisterOperand
):
759 def spec(self
, insn
, record
):
760 def merge(vector
, value
, span
, spec
, spec_span
):
761 bits
= (len(span
) + len(spec_span
))
762 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
763 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
768 (value
, span
, (0, 1, 2)),
769 (spec
, spec_span
, (0, 1)),
770 (value
, span
, (3, 4)),
774 _SelectableInt(value
=0, bits
=1),
775 _SelectableInt(value
=0, bits
=1),
777 dst_span
= ["{0}", "{0}"]
779 (spec
, spec_span
, (0, 1)),
780 (value
, span
, (0, 1, 2, 3, 4)),
783 for (src_value
, src_span
, sel
) in table
:
785 dst_value
.append(src_value
[idx
])
786 dst_span
.append(src_span
[idx
])
788 value
= _selectconcat(dst_value
)
789 span
= tuple(dst_span
)
793 return super().spec(insn
=insn
, record
=record
, merge
=merge
)
795 def disassemble(self
, insn
, record
, verbose
=False, indent
=""):
796 yield from super().disassemble(prefix
="cr",
797 insn
=insn
, record
=record
, verbose
=verbose
, indent
=indent
)
800 class TargetAddrOperand(RegisterOperand
):
801 def disassemble(self
, insn
, record
, field
,
802 verbosity
=Verbosity
.NORMAL
, indent
=""):
803 span
= self
.span(record
=record
)
804 if isinstance(insn
, SVP64Instruction
):
805 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
808 if verbosity
>= Verbosity
.VERBOSE
:
809 span
= tuple(map(str, span
))
810 yield f
"{indent}{self.name} = EXTS({field} || 0b00))"
811 yield f
"{indent}{indent}{field}"
812 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
813 yield f
"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
815 yield hex(int(_selectconcat(value
,
816 _SelectableInt(value
=0b00, bits
=2))))
819 class TargetAddrOperandLI(TargetAddrOperand
):
820 def span(self
, record
):
821 return record
.fields
["LI"]
823 def disassemble(self
, insn
, record
,
824 verbosity
=Verbosity
.NORMAL
, indent
=""):
825 return super().disassemble(field
="LI",
826 insn
=insn
, record
=record
,
827 verbosity
=verbosity
, indent
=indent
)
830 class TargetAddrOperandBD(TargetAddrOperand
):
831 def span(self
, record
):
832 return record
.fields
["BD"]
834 def disassemble(self
, insn
, record
,
835 verbosity
=Verbosity
.NORMAL
, indent
=""):
836 return super().disassemble(field
="BD",
837 insn
=insn
, record
=record
,
838 verbosity
=verbosity
, indent
=indent
)
841 class DOperandDX(DynamicOperand
):
842 def span(self
, record
):
843 operands
= map(DynamicOperand
, ("d0", "d1", "d2"))
844 spans
= map(lambda operand
: operand
.span(record
=record
), operands
)
845 return sum(spans
, tuple())
847 def disassemble(self
, insn
, record
,
848 verbosity
=Verbosity
.NORMAL
, indent
=""):
849 span
= self
.span(record
=record
)
850 if isinstance(insn
, SVP64Instruction
):
851 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
854 if verbosity
>= Verbosity
.VERBOSE
:
861 for (subname
, subspan
) in mapping
.items():
862 operand
= DynamicOperand(name
=subname
)
863 span
= operand
.span(record
=record
)
864 if isinstance(insn
, SVP64Instruction
):
865 span
= tuple(map(lambda bit
: (bit
+ 32), span
))
867 span
= map(str, span
)
868 yield f
"{indent}{indent}{operand.name} = D{subspan}"
869 yield f
"{indent}{indent}{indent}{int(value):0{value.bits}b}"
870 yield f
"{indent}{indent}{indent}{', '.join(span)}"
872 yield str(int(value
))
875 class Operands(tuple):
876 def __new__(cls
, insn
, iterable
):
878 "b": {"target_addr": TargetAddrOperandLI
},
879 "ba": {"target_addr": TargetAddrOperandLI
},
880 "bl": {"target_addr": TargetAddrOperandLI
},
881 "bla": {"target_addr": TargetAddrOperandLI
},
882 "bc": {"target_addr": TargetAddrOperandBD
},
883 "bca": {"target_addr": TargetAddrOperandBD
},
884 "bcl": {"target_addr": TargetAddrOperandBD
},
885 "bcla": {"target_addr": TargetAddrOperandBD
},
886 "addpcis": {"D": DOperandDX
},
887 "fishmv": {"D": DOperandDX
},
888 "fmvis": {"D": DOperandDX
},
891 "SVi": NonZeroOperand
,
892 "SVd": NonZeroOperand
,
893 "SVxd": NonZeroOperand
,
894 "SVyd": NonZeroOperand
,
895 "SVzd": NonZeroOperand
,
899 for operand
in iterable
:
900 dynamic_cls
= DynamicOperand
901 static_cls
= StaticOperand
904 (name
, value
) = operand
.split("=")
905 operand
= static_cls(name
=name
, value
=int(value
))
906 operands
.append(operand
)
908 if operand
.endswith(")"):
909 operand
= operand
.replace("(", " ").replace(")", "")
910 (immediate
, _
, operand
) = operand
.partition(" ")
914 if immediate
is not None:
915 operands
.append(ImmediateOperand(name
=immediate
))
917 if insn
in custom_insns
and operand
in custom_insns
[insn
]:
918 dynamic_cls
= custom_insns
[insn
][operand
]
919 if operand
in custom_fields
:
920 dynamic_cls
= custom_fields
[operand
]
922 if operand
in _RegType
.__members
__:
923 regtype
= _RegType
[operand
]
924 if regtype
is _RegType
.GPR
:
925 dynamic_cls
= GPROperand
926 elif regtype
is _RegType
.FPR
:
927 dynamic_cls
= FPROperand
928 if regtype
is _RegType
.CR_BIT
: # 5-bit
929 dynamic_cls
= CR5Operand
930 if regtype
is _RegType
.CR_REG
: # actually CR Field, 3-bit
931 dynamic_cls
= CR3Operand
933 operand
= dynamic_cls(name
=operand
)
934 operands
.append(operand
)
936 return super().__new
__(cls
, operands
)
938 def __contains__(self
, key
):
939 return self
.__getitem
__(key
) is not None
941 def __getitem__(self
, key
):
943 if operand
.name
== key
:
951 if isinstance(operand
, DynamicOperand
):
957 if isinstance(operand
, StaticOperand
):
962 def __init__(self
, iterable
):
963 self
.__pcode
= tuple(iterable
)
964 return super().__init
__()
967 yield from self
.__pcode
970 return self
.__pcode
.__repr
__()
973 @_dataclasses.dataclass(eq
=True, frozen
=True)
974 class MarkdownRecord
:
979 @_functools.total_ordering
980 @_dataclasses.dataclass(eq
=True, frozen
=True)
987 svp64
: SVP64Record
= None
989 def __lt__(self
, other
):
990 if not isinstance(other
, Record
):
991 return NotImplemented
992 return (min(self
.opcodes
) < min(other
.opcodes
))
1000 PO
= self
.section
.opcode
1002 for (src
, dst
) in enumerate(reversed(BitSel((0, 5)))):
1003 value
[dst
] = int((PO
.value
& (1 << src
)) != 0)
1004 mask
[dst
] = int((PO
.mask
& (1 << src
)) != 0)
1007 for (src
, dst
) in enumerate(reversed(self
.section
.bitsel
)):
1008 value
[dst
] = int((XO
.value
& (1 << src
)) != 0)
1009 mask
[dst
] = int((XO
.mask
& (1 << src
)) != 0)
1011 for operand
in self
.mdwn
.operands
.static
:
1012 for (src
, dst
) in enumerate(reversed(operand
.span(record
=self
))):
1013 value
[dst
] = int((operand
.value
& (1 << src
)) != 0)
1016 value
= Opcode
.Value(int(("".join(map(str, value
))), 2))
1017 mask
= Opcode
.Mask(int(("".join(map(str, mask
))), 2))
1019 return Opcode(value
=value
, mask
=mask
)
1021 return tuple(sorted(map(opcode
, self
.ppc
)))
1023 def match(self
, key
):
1024 for opcode
in self
.opcodes
:
1025 if ((opcode
.value
& opcode
.mask
) ==
1026 (key
& opcode
.mask
)):
1032 return self
.ppc
.function
1052 if self
.svp64
is None:
1058 return self
.ppc
.cr_in
1062 return self
.ppc
.cr_out
1064 ptype
= property(lambda self
: self
.svp64
.ptype
)
1065 etype
= property(lambda self
: self
.svp64
.etype
)
1067 def extra_idx(self
, key
):
1068 return self
.svp64
.extra_idx(key
)
1070 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
1071 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
1072 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
1073 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
1074 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
1075 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
1076 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
1079 class Instruction(_Mapping
):
1081 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
1082 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
1083 raise ValueError(bits
)
1085 if isinstance(value
, bytes
):
1086 if ((len(value
) * 8) != bits
):
1087 raise ValueError(f
"bit length mismatch")
1088 value
= int.from_bytes(value
, byteorder
=byteorder
)
1090 if isinstance(value
, int):
1091 value
= _SelectableInt(value
=value
, bits
=bits
)
1092 elif isinstance(value
, Instruction
):
1093 value
= value
.storage
1095 if not isinstance(value
, _SelectableInt
):
1096 raise ValueError(value
)
1099 if len(value
) != bits
:
1100 raise ValueError(value
)
1102 value
= _SelectableInt(value
=value
, bits
=bits
)
1104 return cls(storage
=value
)
1107 return hash(int(self
))
1109 def record(self
, db
):
1112 raise KeyError(self
)
1115 def spec(self
, db
, prefix
):
1116 record
= self
.record(db
=db
)
1118 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1119 self
.dynamic_operands(db
=db
)))
1121 static_operands
= []
1122 for (name
, value
) in self
.static_operands(db
=db
):
1123 static_operands
.append(f
"{name}={value}")
1126 if dynamic_operands
:
1127 operands
+= f
" {','.join(dynamic_operands)}"
1129 operands
+= f
" ({' '.join(static_operands)})"
1131 return f
"{prefix}{record.name}{operands}"
1133 def dynamic_operands(self
, db
, verbosity
=Verbosity
.NORMAL
):
1134 record
= self
.record(db
=db
)
1139 for operand
in record
.mdwn
.operands
.dynamic
:
1141 dis
= operand
.disassemble(insn
=self
, record
=record
,
1142 verbosity
=min(verbosity
, Verbosity
.NORMAL
))
1143 value
= " ".join(dis
)
1145 name
= f
"{imm_name}({name})"
1146 value
= f
"{imm_value}({value})"
1148 if isinstance(operand
, ImmediateOperand
):
1155 def static_operands(self
, db
):
1156 record
= self
.record(db
=db
)
1157 for operand
in record
.mdwn
.operands
.static
:
1158 yield (operand
.name
, operand
.value
)
1160 def disassemble(self
, db
,
1162 verbosity
=Verbosity
.NORMAL
):
1163 raise NotImplementedError
1166 class WordInstruction(Instruction
):
1167 _
: _Field
= range(0, 32)
1168 po
: _Field
= range(0, 6)
1171 def integer(cls
, value
, byteorder
="little"):
1172 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1177 for idx
in range(32):
1178 bit
= int(self
[idx
])
1180 return "".join(map(str, bits
))
1182 def disassemble(self
, db
,
1184 verbosity
=Verbosity
.NORMAL
):
1186 if verbosity
<= Verbosity
.SHORT
:
1189 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1190 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1195 yield f
"{blob}.long 0x{integer:08x}"
1198 operands
= tuple(map(_operator
.itemgetter(1),
1199 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1201 yield f
"{blob}{record.name} {','.join(operands)}"
1203 yield f
"{blob}{record.name}"
1205 if verbosity
>= Verbosity
.VERBOSE
:
1207 binary
= self
.binary
1208 spec
= self
.spec(db
=db
, prefix
="")
1209 yield f
"{indent}spec"
1210 yield f
"{indent}{indent}{spec}"
1211 yield f
"{indent}pcode"
1212 for stmt
in record
.mdwn
.pcode
:
1213 yield f
"{indent}{indent}{stmt}"
1214 yield f
"{indent}binary"
1215 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1216 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1217 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1218 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1219 yield f
"{indent}opcodes"
1220 for opcode
in record
.opcodes
:
1221 yield f
"{indent}{indent}{opcode!r}"
1222 for operand
in record
.mdwn
.operands
:
1223 yield from operand
.disassemble(insn
=self
, record
=record
,
1224 verbosity
=verbosity
, indent
=indent
)
1228 class PrefixedInstruction(Instruction
):
1229 class Prefix(WordInstruction
.remap(range(0, 32))):
1232 class Suffix(WordInstruction
.remap(range(32, 64))):
1235 _
: _Field
= range(64)
1241 def integer(cls
, value
, byteorder
="little"):
1242 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
1245 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
1246 def transform(value
):
1247 return WordInstruction
.integer(value
=value
,
1248 byteorder
=byteorder
)[0:32]
1250 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
1251 value
= _selectconcat(prefix
, suffix
)
1253 return super().integer(value
=value
)
1256 class Mode(_Mapping
):
1257 _
: _Field
= range(0, 5)
1258 sel
: _Field
= range(0, 2)
1261 class NormalMode(Mode
):
1268 """scalar reduce mode (mapreduce), SUBVL=1"""
1272 """parallel reduce mode (mapreduce), SUBVL=1"""
1276 """subvector reduce mode, SUBVL>1"""
1280 """Pack/Unpack mode, SUBVL>1"""
1284 """Rc=1: ffirst CR sel"""
1289 """Rc=0: ffirst z/nonz"""
1295 """sat mode: N=0/1 u/s, SUBVL=1"""
1301 """sat mode: N=0/1 u/s, SUBVL>1"""
1308 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1315 """Rc=1: pred-result CR sel"""
1320 """Rc=0: pred-result z/nonz"""
1341 class LDSTImmMode(Mode
):
1350 """Structured Pack/Unpack"""
1357 """Rc=1: ffirst CR sel"""
1362 """Rc=0: ffirst z/nonz"""
1368 """sat mode: N=0/1 u/s"""
1376 """Rc=1: pred-result CR sel"""
1381 """Rc=0: pred-result z/nonz"""
1395 class LDSTIdxMode(Mode
):
1403 """strided (scalar only source)"""
1409 """sat mode: N=0/1 u/s"""
1415 """Rc=1: pred-result CR sel"""
1420 """Rc=0: pred-result z/nonz"""
1434 class Extra(_Mapping
):
1435 _
: _Field
= range(0, 9)
1438 class Extra2(Extra
):
1439 idx0
: _Field
= range(0, 2)
1440 idx1
: _Field
= range(2, 4)
1441 idx2
: _Field
= range(4, 6)
1442 idx3
: _Field
= range(6, 8)
1444 def __getitem__(self
, key
):
1450 _SVExtra
.Idx0
: self
.idx0
,
1451 _SVExtra
.Idx1
: self
.idx1
,
1452 _SVExtra
.Idx2
: self
.idx2
,
1453 _SVExtra
.Idx3
: self
.idx3
,
1456 def __setitem__(self
, key
, value
):
1457 self
[key
].assign(value
)
1460 class Extra3(Extra
):
1461 idx0
: _Field
= range(0, 3)
1462 idx1
: _Field
= range(3, 6)
1463 idx2
: _Field
= range(6, 9)
1465 def __getitem__(self
, key
):
1470 _SVExtra
.Idx0
: self
.idx0
,
1471 _SVExtra
.Idx1
: self
.idx1
,
1472 _SVExtra
.Idx2
: self
.idx2
,
1475 def __setitem__(self
, key
, value
):
1476 self
[key
].assign(value
)
1482 ldst_imm
: LDSTImmMode
1483 ldst_idx
: LDSTIdxMode
1485 _
: _Field
= range(24)
1486 mmode
: _Field
= (0,)
1487 mask
: _Field
= range(1, 4)
1488 elwidth
: _Field
= range(4, 6)
1489 ewsrc
: _Field
= range(6, 8)
1490 subvl
: _Field
= range(8, 10)
1491 mode
: Mode
.remap(range(19, 24))
1492 smask
: _Field
= range(16, 19)
1494 extra
: Extra
.remap(range(10, 19))
1495 extra2
: Extra2
.remap(range(10, 19))
1496 extra3
: Extra3
.remap(range(10, 19))
1499 class SVP64Instruction(PrefixedInstruction
):
1500 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1501 class Prefix(PrefixedInstruction
.Prefix
):
1503 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
1507 def record(self
, db
):
1508 record
= db
[self
.suffix
]
1510 raise KeyError(self
)
1516 for idx
in range(64):
1517 bit
= int(self
[idx
])
1519 return "".join(map(str, bits
))
1522 record
= self
.record(db
=db
)
1525 if record
.mdwn
.operands
["Rc"] is not None:
1526 Rc
= bool(self
[record
.fields
["Rc"]])
1528 record
= self
.record(db
=db
)
1529 subvl
= self
.prefix
.rm
.subvl
1530 mode
= self
.prefix
.rm
.mode
1533 if record
.svp64
.mode
is _SVMode
.NORMAL
:
1567 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1568 mode
= mode
.ldst_imm
1586 elif record
.svp64
.mode
is _SVMode
.LDST_IMM
:
1587 mode
= mode
.ldst_idx
1588 if mode
.sel
== 0b00:
1590 elif mode
.sel
== 0b01:
1592 elif mode
.sel
== 0b10:
1594 elif mode
.sel
== 0b11:
1601 NormalMode
.simple
: "normal: simple",
1602 NormalMode
.smr
: "normal: smr",
1603 NormalMode
.pmr
: "normal: pmr",
1604 NormalMode
.svmr
: "normal: svmr",
1605 NormalMode
.pu
: "normal: pu",
1606 NormalMode
.ffrc1
: "normal: ffrc1",
1607 NormalMode
.ffrc0
: "normal: ffrc0",
1608 NormalMode
.sat
: "normal: sat",
1609 NormalMode
.satx
: "normal: satx",
1610 NormalMode
.satpu
: "normal: satpu",
1611 NormalMode
.prrc1
: "normal: prrc1",
1612 NormalMode
.prrc0
: "normal: prrc0",
1613 LDSTImmMode
.simple
: "ld/st imm: simple",
1614 LDSTImmMode
.spu
: "ld/st imm: spu",
1615 LDSTImmMode
.ffrc1
: "ld/st imm: ffrc1",
1616 LDSTImmMode
.ffrc0
: "ld/st imm: ffrc0",
1617 LDSTImmMode
.sat
: "ld/st imm: sat",
1618 LDSTImmMode
.prrc1
: "ld/st imm: prrc1",
1619 LDSTImmMode
.prrc0
: "ld/st imm: prrc0",
1620 LDSTIdxMode
.simple
: "ld/st idx simple",
1621 LDSTIdxMode
.stride
: "ld/st idx stride",
1622 LDSTIdxMode
.sat
: "ld/st idx sat",
1623 LDSTIdxMode
.prrc1
: "ld/st idx prrc1",
1624 LDSTIdxMode
.prrc0
: "ld/st idx prrc0",
1626 for (cls
, desc
) in modes
.items():
1627 if isinstance(mode
, cls
):
1630 if record
.svp64
.mode
is _SVMode
.BRANCH
:
1631 return (self
.prefix
.rm
.mode
, "branch")
1633 raise ValueError(self
)
1635 def disassemble(self
, db
,
1637 verbosity
=Verbosity
.NORMAL
):
1639 if verbosity
<= Verbosity
.SHORT
:
1642 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
1643 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1646 blob_prefix
= blob(int(self
.prefix
))
1647 blob_suffix
= blob(int(self
.suffix
))
1649 if record
is None or record
.svp64
is None:
1650 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
1651 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
1654 operands
= tuple(map(_operator
.itemgetter(1),
1655 self
.dynamic_operands(db
=db
, verbosity
=verbosity
)))
1657 yield f
"{blob_prefix}sv.{record.name} {','.join(operands)}"
1659 yield f
"{blob_prefix}{record.name}"
1661 yield f
"{blob_suffix}"
1663 (mode
, mode_desc
) = self
.mode(db
=db
)
1665 if verbosity
>= Verbosity
.VERBOSE
:
1667 binary
= self
.binary
1668 spec
= self
.spec(db
=db
, prefix
="sv.")
1669 yield f
"{indent}spec"
1670 yield f
"{indent}{indent}{spec}"
1671 yield f
"{indent}pcode"
1672 for stmt
in record
.mdwn
.pcode
:
1673 yield f
"{indent}{indent}{stmt}"
1674 yield f
"{indent}binary"
1675 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1676 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1677 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1678 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1679 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
1680 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
1681 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
1682 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
1683 yield f
"{indent}opcodes"
1684 for opcode
in record
.opcodes
:
1685 yield f
"{indent}{indent}{opcode!r}"
1686 for operand
in record
.mdwn
.operands
:
1687 yield from operand
.disassemble(insn
=self
, record
=record
,
1688 verbosity
=verbosity
, indent
=indent
)
1690 yield f
"{indent}mode"
1691 yield f
"{indent}{indent}{mode_desc}"
1695 def parse(stream
, factory
):
1697 return ("TODO" not in frozenset(entry
.values()))
1699 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
1700 entries
= _csv
.DictReader(lines
)
1701 entries
= filter(match
, entries
)
1702 return tuple(map(factory
, entries
))
1705 class MarkdownDatabase
:
1708 for (name
, desc
) in _ISA():
1711 (dynamic
, *static
) = desc
.regs
1712 operands
.extend(dynamic
)
1713 operands
.extend(static
)
1714 pcode
= PCode(iterable
=desc
.pcode
)
1715 operands
= Operands(insn
=name
, iterable
=operands
)
1716 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
1720 return super().__init
__()
1723 yield from self
.__db
.items()
1725 def __getitem__(self
, key
):
1726 return self
.__db
.__getitem
__(key
)
1729 class FieldsDatabase
:
1732 df
= _DecodeFields()
1734 for (form
, fields
) in df
.instrs
.items():
1735 if form
in {"DQE", "TX"}:
1739 db
[_Form
[form
]] = Fields(fields
)
1743 return super().__init
__()
1745 def __getitem__(self
, key
):
1746 return self
.__db
.__getitem
__(key
)
1750 def __init__(self
, root
, mdwndb
):
1751 # The code below groups the instructions by section:identifier.
1752 # We use the comment as an identifier, there's nothing better.
1753 # The point is to capture different opcodes for the same instruction.
1754 dd
= _collections
.defaultdict
1755 records
= dd(lambda: dd(set))
1756 path
= (root
/ "insndb.csv")
1757 with
open(path
, "r", encoding
="UTF-8") as stream
:
1758 for section
in parse(stream
, Section
.CSV
):
1759 path
= (root
/ section
.path
)
1761 section
.Mode
.INTEGER
: IntegerOpcode
,
1762 section
.Mode
.PATTERN
: PatternOpcode
,
1764 factory
= _functools
.partial(
1765 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
1766 with
open(path
, "r", encoding
="UTF-8") as stream
:
1767 for insn
in parse(stream
, factory
):
1768 records
[section
][insn
.comment
].add(insn
)
1771 for (section
, group
) in records
.items():
1772 for records
in group
.values():
1773 db
[section
].add(PPCMultiRecord(records
))
1776 self
.__mdwndb
= mdwndb
1778 return super().__init
__()
1780 def __getitem__(self
, key
):
1781 def exact_match(key
, record
):
1782 for name
in record
.names
:
1788 def Rc_match(key
, record
):
1789 if not key
.endswith("."):
1792 if not record
.Rc
is _RCOE
.RC
:
1795 return exact_match(key
[:-1], record
)
1797 def LK_match(key
, record
):
1798 if not key
.endswith("l"):
1801 if "lk" not in record
.flags
:
1804 return exact_match(key
[:-1], record
)
1806 def AA_match(key
, record
):
1807 if not key
.endswith("a"):
1810 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
1813 if self
.__mdwndb
[key
].operands
["AA"] is None:
1816 return (exact_match(key
[:-1], record
) or
1817 LK_match(key
[:-1], record
))
1819 for (section
, records
) in self
.__db
.items():
1820 for record
in records
:
1821 if exact_match(key
, record
):
1822 return (section
, record
)
1824 for record
in records
:
1825 if (Rc_match(key
, record
) or
1826 LK_match(key
, record
) or
1827 AA_match(key
, record
)):
1828 return (section
, record
)
1833 class SVP64Database
:
1834 def __init__(self
, root
, ppcdb
):
1836 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1837 for (prefix
, _
, names
) in _os
.walk(root
):
1838 prefix
= _pathlib
.Path(prefix
)
1839 for name
in filter(lambda name
: pattern
.match(name
), names
):
1840 path
= (prefix
/ _pathlib
.Path(name
))
1841 with
open(path
, "r", encoding
="UTF-8") as stream
:
1842 db
.update(parse(stream
, SVP64Record
.CSV
))
1844 self
.__db
= {record
.name
:record
for record
in db
}
1845 self
.__ppcdb
= ppcdb
1847 return super().__init
__()
1849 def __getitem__(self
, key
):
1850 (_
, record
) = self
.__ppcdb
[key
]
1854 for name
in record
.names
:
1855 record
= self
.__db
.get(name
, None)
1856 if record
is not None:
1863 def __init__(self
, root
):
1864 root
= _pathlib
.Path(root
)
1866 mdwndb
= MarkdownDatabase()
1867 fieldsdb
= FieldsDatabase()
1868 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
1869 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
1872 for (name
, mdwn
) in mdwndb
:
1873 (section
, ppc
) = ppcdb
[name
]
1876 svp64
= svp64db
[name
]
1877 fields
= fieldsdb
[ppc
.form
]
1878 record
= Record(name
=name
,
1879 section
=section
, ppc
=ppc
, svp64
=svp64
,
1880 mdwn
=mdwn
, fields
=fields
)
1883 self
.__db
= tuple(sorted(db
))
1885 return super().__init
__()
1888 return repr(self
.__db
)
1891 yield from self
.__db
1893 @_functools.lru_cache(maxsize
=None)
1894 def __contains__(self
, key
):
1895 return self
.__getitem
__(key
) is not None
1897 @_functools.lru_cache(maxsize
=None)
1898 def __getitem__(self
, key
):
1899 if isinstance(key
, (int, Instruction
)):
1902 if record
.match(key
=key
):
1905 elif isinstance(key
, Opcode
):
1907 if record
.opcode
== key
:
1910 elif isinstance(key
, str):
1912 if record
.name
== key
: