1 import collections
as _collections
2 import contextlib
as _contextlib
4 import dataclasses
as _dataclasses
6 import functools
as _functools
7 import inspect
as _inspect
9 import operator
as _operator
10 import pathlib
as _pathlib
12 import types
as _types
13 import typing
as _typing
16 from functools
import cached_property
18 from cached_property
import cached_property
20 from openpower
.decoder
.power_enums
import (
21 Function
as _Function
,
28 CRIn2Sel
as _CRIn2Sel
,
29 CROutSel
as _CROutSel
,
31 LDSTMode
as _LDSTMode
,
36 SVMaskSrc
as _SVMaskSrc
,
43 SVP64SubVL
as _SVP64SubVL
,
44 SVP64Pred
as _SVP64Pred
,
45 SVP64PredMode
as _SVP64PredMode
,
46 SVP64Width
as _SVP64Width
,
48 from openpower
.decoder
.selectable_int
import (
49 SelectableInt
as _SelectableInt
,
50 selectconcat
as _selectconcat
,
52 from openpower
.decoder
.power_fields
import (
55 DecodeFields
as _DecodeFields
,
57 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
61 def __init__(self
, walk
):
63 return super().__init
__()
65 def __get__(self
, instance
, owner
):
69 return _functools
.partial(self
.__walk
, entity
)
74 def walk(clsself
, match
=lambda _
: True):
78 class DataclassMeta(type):
79 def __new__(metacls
, name
, bases
, ns
):
80 cls
= super().__new
__(metacls
, name
, bases
, ns
)
81 return _dataclasses
.dataclass(cls
, eq
=True, frozen
=True)
84 class Dataclass(Node
, metaclass
=DataclassMeta
):
86 def walk(clsself
, match
=lambda _
: True):
87 def field_type(field
):
90 def field_value(field
):
91 return getattr(clsself
, field
.name
)
93 field_node
= (field_type
if isinstance(clsself
, type) else field_value
)
95 for field
in _dataclasses
.fields(clsself
):
97 node
= field_node(field
)
101 class Tuple(Node
, tuple):
102 def __init_subclass__(cls
, datatype
):
103 cls
.__datatype
= datatype
104 return super().__init
_subclass
__()
107 def walk(clsself
, match
=lambda _
: True):
108 if isinstance(clsself
, type):
109 yield ("[]", clsself
.__datatype
)
111 for (index
, item
) in enumerate(filter(match
, clsself
)):
112 yield (str(index
), item
)
115 class Dict(Node
, dict):
116 def __init_subclass__(cls
, datatype
):
117 cls
.__datatype
= datatype
118 return super().__init
_subclass
__()
121 return hash(tuple(sorted(self
.items())))
124 raise NotImplementedError()
126 def __delitem__(self
, key
):
127 raise NotImplementedError()
129 def __setitem__(self
, key
, value
):
130 raise NotImplementedError()
132 def popitem(self
) -> tuple:
133 raise NotImplementedError()
135 def pop(self
, key
, default
=None):
136 raise NotImplementedError()
138 def update(self
, entry
, **kwargs
):
139 raise NotImplementedError()
142 def walk(clsself
, match
=lambda _
: True):
143 if isinstance(clsself
, type):
144 yield ("{}", clsself
.__datatype
)
146 yield from filter(lambda kv
: match(kv
[0]), clsself
.items())
150 def __init__(self
, nodecls
, method
):
151 self
.__nodecls
= nodecls
152 self
.__method
= method
153 return super().__init
__()
157 return self
.__nodecls
159 @_contextlib.contextmanager
160 def __call__(self
, path
, node
):
161 return self
.__method
(self
=self
, path
=path
, node
=node
)
164 class VisitorMeta(type):
165 def __init__(cls
, name
, bases
, ns
):
167 for (key
, value
) in ns
.items():
168 if isinstance(value
, VisitorMethod
):
169 if value
.type in cls
.__registry
:
170 raise AttributeError(f
"overriding visitor method: {key!r}")
171 cls
.__registry
[value
.type] = value
172 return super().__init
__(name
, bases
, ns
)
174 def __contains__(self
, nodecls
):
175 return self
.__registry
.__contains
__(nodecls
)
177 def __getitem__(self
, nodecls
):
178 return self
.__registry
.__getitem
__(nodecls
)
180 def __setitem__(self
, nodecls
, call
):
181 return self
.__registry
.__setitem
__(nodecls
, call
)
184 yield from self
.__registry
.items()
187 class Visitor(metaclass
=VisitorMeta
):
188 @_contextlib.contextmanager
189 def __call__(self
, path
, node
):
190 (visitorcls
, nodecls
) = map(type, (self
, node
))
191 if nodecls
in visitorcls
:
192 handler
= visitorcls
[nodecls
]
193 with
handler(path
=path
, node
=node
) as ctx
:
200 def __init__(self
, nodecls
):
201 if not isinstance(nodecls
, type):
202 raise ValueError(nodecls
)
203 self
.__nodecls
= nodecls
204 return super().__init
__()
206 def __call__(self
, method
):
207 if not callable(method
):
208 raise ValueError(method
)
209 return VisitorMethod(nodecls
=self
.__nodecls
, method
=method
)
212 def walk(root
, match
=lambda _
: True):
213 pairs
= _collections
.deque([root
])
215 (path
, node
) = pairs
.popleft()
216 pairs
.extend(node
.walk(match
=match
))
220 def visit(visitor
, node
, path
="/", match
=lambda _
: True):
221 with
visitor(path
=path
, node
=node
):
222 if isinstance(node
, Node
):
223 for (subpath
, subnode
) in node
.walk(match
=match
):
224 visit(visitor
=visitor
, path
=subpath
, node
=subnode
)
227 @_functools.total_ordering
228 class Style(_enum
.Enum
):
229 LEGACY
= _enum
.auto()
231 NORMAL
= _enum
.auto()
232 VERBOSE
= _enum
.auto()
234 def __lt__(self
, other
):
235 if not isinstance(other
, self
.__class
__):
236 return NotImplemented
237 return (self
.value
< other
.value
)
240 @_functools.total_ordering
241 class Priority(_enum
.Enum
):
247 def _missing_(cls
, value
):
248 if isinstance(value
, str):
249 value
= value
.upper()
253 return super()._missing
_(value
)
255 def __lt__(self
, other
):
256 if not isinstance(other
, self
.__class
__):
257 return NotImplemented
259 # NOTE: the order is inversed, LOW < NORMAL < HIGH
260 return (self
.value
> other
.value
)
263 def dataclass(cls
, record
, keymap
=None, typemap
=None):
267 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
269 def transform(key_value
):
270 (key
, value
) = key_value
271 key
= keymap
.get(key
, key
)
272 hook
= typemap
.get(key
, lambda value
: value
)
273 if hook
is bool and value
in ("", "0"):
279 record
= dict(map(transform
, record
.items()))
280 for key
in frozenset(record
.keys()):
281 if record
[key
] == "":
287 @_functools.total_ordering
288 class Opcode(Dataclass
):
290 def __new__(cls
, value
):
291 if isinstance(value
, str):
292 value
= int(value
, 0)
293 if not isinstance(value
, int):
294 raise ValueError(value
)
296 if value
.bit_length() > 64:
297 raise ValueError(value
)
299 return super().__new
__(cls
, value
)
302 return self
.__repr
__()
305 return f
"{self:0{self.bit_length()}b}"
307 def bit_length(self
):
308 if super().bit_length() > 32:
312 class Value(Integer
):
321 def __lt__(self
, other
):
322 if not isinstance(other
, Opcode
):
323 return NotImplemented
324 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
327 return (self
.value
& self
.mask
)
330 return int(self
).__index
__()
333 def pattern(value
, mask
, bit_length
):
334 for bit
in range(bit_length
):
335 if ((mask
& (1 << (bit_length
- bit
- 1))) == 0):
337 elif (value
& (1 << (bit_length
- bit
- 1))):
342 return "".join(pattern(self
.value
, self
.mask
, self
.value
.bit_length()))
344 def match(self
, key
):
345 return ((self
.value
& self
.mask
) == (key
& self
.mask
))
348 @_functools.total_ordering
349 class IntegerOpcode(Opcode
):
350 def __init__(self
, value
):
351 if value
.startswith("0b"):
352 mask
= int(("1" * len(value
[2:])), 2)
356 value
= Opcode
.Value(value
)
357 mask
= Opcode
.Mask(mask
)
359 return super().__init
__(value
=value
, mask
=mask
)
362 @_functools.total_ordering
363 class PatternOpcode(Opcode
):
364 def __init__(self
, pattern
):
365 if not isinstance(pattern
, str):
366 raise ValueError(pattern
)
368 (value
, mask
) = (0, 0)
369 for symbol
in pattern
:
370 if symbol
not in {"0", "1", "-"}:
371 raise ValueError(pattern
)
372 value |
= (symbol
== "1")
373 mask |
= (symbol
!= "-")
379 value
= Opcode
.Value(value
)
380 mask
= Opcode
.Mask(mask
)
382 return super().__init
__(value
=value
, mask
=mask
)
385 class PPCRecord(Dataclass
):
386 class FlagsMeta(type):
401 class Flags(Tuple
, datatype
=str, metaclass
=FlagsMeta
):
402 def __new__(cls
, flags
=frozenset()):
403 flags
= frozenset(flags
)
404 diff
= (flags
- frozenset(cls
))
406 raise ValueError(flags
)
407 return super().__new
__(cls
, sorted(flags
))
411 flags
: Flags
= Flags()
413 function
: _Function
= _Function
.NONE
414 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
415 in1
: _In1Sel
= _In1Sel
.NONE
416 in2
: _In2Sel
= _In2Sel
.NONE
417 in3
: _In3Sel
= _In3Sel
.NONE
418 out
: _OutSel
= _OutSel
.NONE
419 cr_in
: _CRInSel
= _CRInSel
.NONE
420 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
421 cr_out
: _CROutSel
= _CROutSel
.NONE
422 cry_in
: _CryIn
= _CryIn
.ZERO
423 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
424 upd
: _LDSTMode
= _LDSTMode
.NONE
425 Rc
: _RCOE
= _RCOE
.NONE
426 form
: _Form
= _Form
.NONE
428 unofficial
: bool = False
432 "internal op": "intop",
436 "ldst len": "ldst_len",
438 "CONDITIONS": "conditions",
441 def __lt__(self
, other
):
442 if not isinstance(other
, self
.__class
__):
443 return NotImplemented
444 lhs
= (self
.opcode
, self
.comment
)
445 rhs
= (other
.opcode
, other
.comment
)
449 def CSV(cls
, record
, opcode_cls
):
450 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
451 typemap
["opcode"] = opcode_cls
453 if record
["CR in"] == "BA_BB":
454 record
["cr_in"] = "BA"
455 record
["cr_in2"] = "BB"
459 for flag
in frozenset(PPCRecord
.Flags
):
460 if bool(record
.pop(flag
, "")):
462 record
["flags"] = PPCRecord
.Flags(flags
)
464 return dataclass(cls
, record
,
465 keymap
=PPCRecord
.__KEYMAP
,
470 return frozenset(self
.comment
.split("=")[-1].split("/"))
473 class PPCMultiRecord(Tuple
, datatype
=PPCRecord
):
474 def __getattr__(self
, attr
):
477 raise AttributeError(attr
)
478 return getattr(self
[0], attr
)
481 class SVP64Record(Dataclass
):
482 class ExtraMap(tuple):
484 @_dataclasses.dataclass(eq
=True, frozen
=True)
486 seltype
: _SelType
= _SelType
.NONE
487 reg
: _Reg
= _Reg
.NONE
490 return f
"{self.seltype.value}:{self.reg.name}"
492 def __new__(cls
, value
="0"):
493 if isinstance(value
, str):
494 def transform(value
):
495 (seltype
, reg
) = value
.split(":")
496 seltype
= _SelType(seltype
)
498 return cls
.Entry(seltype
=seltype
, reg
=reg
)
503 value
= map(transform
, value
.split(";"))
505 return super().__new
__(cls
, value
)
508 return repr(list(self
))
510 def __new__(cls
, value
=tuple()):
514 return super().__new
__(cls
, map(cls
.Extra
, value
))
517 return repr({index
:self
[index
] for index
in range(0, 4)})
520 ptype
: _SVPType
= _SVPType
.NONE
521 etype
: _SVEType
= _SVEType
.NONE
522 msrc
: _SVMaskSrc
= _SVMaskSrc
.NO
# MASK_SRC is active
523 in1
: _In1Sel
= _In1Sel
.NONE
524 in2
: _In2Sel
= _In2Sel
.NONE
525 in3
: _In3Sel
= _In3Sel
.NONE
526 out
: _OutSel
= _OutSel
.NONE
527 out2
: _OutSel
= _OutSel
.NONE
528 cr_in
: _CRInSel
= _CRInSel
.NONE
529 cr_in2
: _CRIn2Sel
= _CRIn2Sel
.NONE
530 cr_out
: _CROutSel
= _CROutSel
.NONE
531 extra
: ExtraMap
= ExtraMap()
533 mode
: _SVMode
= _SVMode
.NORMAL
537 "CONDITIONS": "conditions",
546 def CSV(cls
, record
):
547 record
["insn"] = record
["insn"].split("=")[-1]
549 for key
in frozenset({
550 "in1", "in2", "in3", "CR in",
551 "out", "out2", "CR out",
557 if record
["CR in"] == "BA_BB":
558 record
["cr_in"] = "BA"
559 record
["cr_in2"] = "BB"
563 for idx
in range(0, 4):
564 extra
.append(record
.pop(f
"{idx}"))
566 record
["extra"] = cls
.ExtraMap(extra
)
568 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
573 "in1", "in2", "in3", "cr_in", "cr_in2",
574 "out", "out2", "cr_out",
589 for index
in range(0, 4):
590 for entry
in self
.extra
[index
]:
591 extras
[entry
.seltype
][entry
.reg
] = idxmap
[index
]
593 for (seltype
, regs
) in extras
.items():
594 idx
= regs
.get(reg
, _SVExtra
.NONE
)
595 if idx
is not _SVExtra
.NONE
:
596 yield (reg
, seltype
, idx
)
603 # has the word "in", it is a SelType.SRC "out" -> DST
604 # in1/2/3 and CR in are SRC, and must match only against "s:NN"
605 # out/out1 and CR out are DST, and must match only against "d:NN"
606 keytype
= _SelType
.SRC
if ("in" in key
) else _SelType
.DST
607 sel
= sels
[key
] = getattr(self
, key
)
608 reg
= regs
[key
] = _Reg(sel
)
609 seltypes
[key
] = _SelType
.NONE
610 idxs
[key
] = _SVExtra
.NONE
611 for (reg
, seltype
, idx
) in extra(reg
.alias
):
612 if keytype
!= seltype
: # only check SRC-to-SRC and DST-to-DST
614 if idx
!= idxs
[key
] and idxs
[key
] is not _SVExtra
.NONE
:
615 raise ValueError(idx
)
618 seltypes
[key
] = seltype
620 if sels
["cr_in"] is _CRInSel
.BA_BB
:
621 sels
["cr_in"] = _CRIn2Sel
.BA
622 sels
["cr_in2"] = _CRIn2Sel
.BB
623 idxs
["cr_in2"] = idxs
["cr_in"]
624 for key
in ("cr_in", "cr_in2"):
625 regs
[key
] = _Reg(sels
[key
])
626 seltype
[key
] = _SelType
.SRC
633 "seltype": seltypes
[key
],
637 return _types
.MappingProxyType(records
)
639 extra_idx_in1
= property(lambda self
: self
.extras
["in1"]["idx"])
640 extra_idx_in2
= property(lambda self
: self
.extras
["in2"]["idx"])
641 extra_idx_in3
= property(lambda self
: self
.extras
["in3"]["idx"])
642 extra_idx_out
= property(lambda self
: self
.extras
["out"]["idx"])
643 extra_idx_out2
= property(lambda self
: self
.extras
["out2"]["idx"])
644 extra_idx_cr_in
= property(lambda self
: self
.extras
["cr_in"]["idx"])
645 extra_idx_cr_in2
= property(lambda self
: self
.extras
["cr_in2"]["idx"])
646 extra_idx_cr_out
= property(lambda self
: self
.extras
["cr_out"]["idx"])
651 for idx
in range(0, 4):
652 for entry
in self
.extra
[idx
]:
653 if entry
.seltype
is _SelType
.DST
:
654 if extra
is not None:
655 raise ValueError(self
.svp64
)
659 if _RegType(extra
.reg
) not in (_RegType
.CR_3BIT
, _RegType
.CR_5BIT
):
660 raise ValueError(self
.svp64
)
665 def extra_CR_3bit(self
):
666 return (_RegType(self
.extra_CR
.reg
) is _RegType
.CR_3BIT
)
670 def __init__(self
, value
=(0, 32)):
671 if isinstance(value
, str):
672 (start
, end
) = map(int, value
.split(":"))
675 if start
< 0 or end
< 0 or start
>= end
:
676 raise ValueError(value
)
681 return super().__init
__()
684 return (self
.__end
- self
.__start
+ 1)
687 return f
"[{self.__start}:{self.__end}]"
690 yield from range(self
.start
, (self
.end
+ 1))
692 def __reversed__(self
):
693 return tuple(reversed(tuple(self
)))
704 class Section(Dataclass
):
705 class Mode(_enum
.Enum
):
706 INTEGER
= _enum
.auto()
707 PATTERN
= _enum
.auto()
710 def _missing_(cls
, value
):
711 if isinstance(value
, str):
712 return cls
[value
.upper()]
713 return super()._missing
_(value
)
716 def __new__(cls
, value
=None):
717 if isinstance(value
, str):
718 if value
.upper() == "NONE":
721 value
= int(value
, 0)
725 return super().__new
__(cls
, value
)
731 return (bin(self
) if self
else "None")
737 opcode
: IntegerOpcode
= None
738 priority
: Priority
= Priority
.NORMAL
740 def __lt__(self
, other
):
741 if not isinstance(other
, self
.__class
__):
742 return NotImplemented
743 return (self
.priority
< other
.priority
)
746 def CSV(cls
, record
):
747 keymap
= {"path": "csv"}
748 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
749 if record
["opcode"] == "NONE":
750 typemap
["opcode"] = lambda _
: None
752 return dataclass(cls
, record
, typemap
=typemap
, keymap
=keymap
)
755 class Fields(Dict
, datatype
=type("Bits", (Tuple
,), {}, datatype
=int)):
756 def __init__(self
, items
):
757 if isinstance(items
, dict):
758 items
= items
.items()
761 (name
, bitrange
) = item
762 return (name
, tuple(bitrange
.values()))
764 mapping
= dict(map(transform
, items
))
766 return super().__init
__(mapping
)
769 yield from self
.__mapping
.items()
784 def __init__(self
, insn
, operands
):
786 "b": {"target_addr": TargetAddrOperandLI
},
787 "ba": {"target_addr": TargetAddrOperandLI
},
788 "bl": {"target_addr": TargetAddrOperandLI
},
789 "bla": {"target_addr": TargetAddrOperandLI
},
790 "bc": {"target_addr": TargetAddrOperandBD
},
791 "bca": {"target_addr": TargetAddrOperandBD
},
792 "bcl": {"target_addr": TargetAddrOperandBD
},
793 "bcla": {"target_addr": TargetAddrOperandBD
},
794 "addpcis": {"D": DOperandDX
},
795 "fishmv": {"D": DOperandDX
},
796 "fmvis": {"D": DOperandDX
},
799 "SVi": NonZeroOperand
,
800 "SVd": NonZeroOperand
,
801 "SVxd": NonZeroOperand
,
802 "SVyd": NonZeroOperand
,
803 "SVzd": NonZeroOperand
,
805 "D": SignedImmediateOperand
,
809 "SIM": SignedOperand
,
810 "SVD": SignedOperand
,
811 "SVDS": SignedOperand
,
812 "RSp": GPRPairOperand
,
813 "RTp": GPRPairOperand
,
814 "FRAp": FPRPairOperand
,
815 "FRBp": FPRPairOperand
,
816 "FRSp": FPRPairOperand
,
817 "FRTp": FPRPairOperand
,
819 custom_immediates
= {
825 for operand
in operands
:
829 (name
, value
) = operand
.split("=")
830 mapping
[name
] = (StaticOperand
, {
836 if name
.endswith(")"):
837 name
= name
.replace("(", " ").replace(")", "")
838 (imm_name
, _
, name
) = name
.partition(" ")
842 if imm_name
is not None:
843 imm_cls
= custom_immediates
.get(imm_name
, ImmediateOperand
)
845 if insn
in custom_insns
and name
in custom_insns
[insn
]:
846 cls
= custom_insns
[insn
][name
]
847 elif name
in custom_fields
:
848 cls
= custom_fields
[name
]
849 elif name
in _Reg
.__members
__:
851 if reg
in self
.__class
__.__GPR
_PAIRS
:
853 elif reg
in self
.__class
__.__FPR
_PAIRS
:
856 regtype
= _RegType
[name
]
857 if regtype
is _RegType
.GPR
:
859 elif regtype
is _RegType
.FPR
:
861 elif regtype
is _RegType
.CR_3BIT
:
863 elif regtype
is _RegType
.CR_5BIT
:
866 if imm_name
is not None:
867 mapping
[imm_name
] = (imm_cls
, {"name": imm_name
})
868 mapping
[name
] = (cls
, {"name": name
})
872 for (name
, (cls
, kwargs
)) in mapping
.items():
873 kwargs
= dict(kwargs
)
874 kwargs
["name"] = name
875 if issubclass(cls
, StaticOperand
):
876 static
.append((cls
, kwargs
))
877 elif issubclass(cls
, DynamicOperand
):
878 dynamic
.append((cls
, kwargs
))
880 raise ValueError(name
)
882 self
.__mapping
= mapping
883 self
.__static
= tuple(static
)
884 self
.__dynamic
= tuple(dynamic
)
886 return super().__init
__()
889 for (_
, items
) in self
.__mapping
.items():
890 (cls
, kwargs
) = items
894 return self
.__mapping
.__repr
__()
896 def __contains__(self
, key
):
897 return self
.__mapping
.__contains
__(key
)
899 def __getitem__(self
, key
):
900 return self
.__mapping
.__getitem
__(key
)
908 return self
.__dynamic
911 class Arguments(tuple):
912 def __new__(cls
, record
, arguments
, operands
):
913 operands
= iter(tuple(operands
))
914 arguments
= iter(tuple(arguments
))
919 operand
= next(operands
)
920 except StopIteration:
924 argument
= next(arguments
)
925 except StopIteration:
926 raise ValueError("operands count mismatch")
928 if isinstance(operand
, ImmediateOperand
):
929 argument
= argument
.replace("(", " ").replace(")", "")
930 (imm_argument
, _
, argument
) = argument
.partition(" ")
932 (imm_operand
, operand
) = (operand
, next(operands
))
933 except StopIteration:
934 raise ValueError("operands count mismatch")
935 items
.append((imm_argument
, imm_operand
))
936 items
.append((argument
, operand
))
940 except StopIteration:
943 raise ValueError("operands count mismatch")
945 return super().__new
__(cls
, items
)
948 class PCode(Tuple
, datatype
=str):
952 class MarkdownRecord(Dataclass
):
957 @_functools.total_ordering
958 class Record(Dataclass
):
964 svp64
: SVP64Record
= None
968 if self
.svp64
is not None:
969 return self
.svp64
.extras
971 return _types
.MappingProxyType({})
975 return self
.mdwn
.pcode
977 def __lt__(self
, other
):
978 if not isinstance(other
, Record
):
979 return NotImplemented
980 lhs
= (min(self
.opcodes
), self
.name
)
981 rhs
= (min(other
.opcodes
), other
.name
)
986 return (self
.static_operands
+ self
.dynamic_operands
)
989 def static_operands(self
):
991 operands
.append(POStaticOperand(record
=self
, value
=self
.PO
))
993 operands
.append(XOStaticOperand(
995 value
=ppc
.opcode
.value
,
996 span
=self
.section
.bitsel
,
998 for (cls
, kwargs
) in self
.mdwn
.operands
.static
:
999 operands
.append(cls(record
=self
, **kwargs
))
1000 return tuple(operands
)
1003 def dynamic_operands(self
):
1005 for (cls
, kwargs
) in self
.mdwn
.operands
.dynamic
:
1006 operands
.append(cls(record
=self
, **kwargs
))
1007 return tuple(operands
)
1011 def binary(mapping
):
1012 return int("".join(str(int(mapping
[bit
])) \
1013 for bit
in sorted(mapping
)), 2)
1015 def PO_XO(value
, mask
, opcode
, bits
):
1018 for (src
, dst
) in enumerate(reversed(bits
)):
1019 value
[dst
] = ((opcode
.value
& (1 << src
)) != 0)
1020 mask
[dst
] = ((opcode
.mask
& (1 << src
)) != 0)
1021 return (value
, mask
)
1023 def PO(value
, mask
, opcode
, bits
):
1024 return PO_XO(value
=value
, mask
=mask
, opcode
=opcode
, bits
=bits
)
1026 def XO(value
, mask
, opcode
, bits
):
1027 (value
, mask
) = PO_XO(value
=value
, mask
=mask
,
1028 opcode
=opcode
, bits
=bits
)
1029 for (op_cls
, op_kwargs
) in self
.mdwn
.operands
.static
:
1030 operand
= op_cls(record
=self
, **op_kwargs
)
1031 for (src
, dst
) in enumerate(reversed(operand
.span
)):
1032 value
[dst
] = ((operand
.value
& (1 << src
)) != 0)
1034 return (value
, mask
)
1037 value
= {bit
:False for bit
in range(32)}
1038 mask
= {bit
:False for bit
in range(32)}
1039 if self
.section
.opcode
is not None:
1040 (value
, mask
) = PO(value
=value
, mask
=mask
,
1041 opcode
=self
.section
.opcode
, bits
=range(0, 6))
1042 for ppc
in self
.ppc
:
1043 pairs
.append(XO(value
=value
, mask
=mask
,
1044 opcode
=ppc
.opcode
, bits
=self
.section
.bitsel
))
1047 for (value
, mask
) in pairs
:
1048 value
= Opcode
.Value(binary(value
))
1049 mask
= Opcode
.Mask(binary(mask
))
1050 result
.append(Opcode(value
=value
, mask
=mask
))
1052 return tuple(result
)
1056 opcode
= self
.section
.opcode
1058 opcode
= self
.ppc
[0].opcode
1059 if isinstance(opcode
, PatternOpcode
):
1060 value
= int(opcode
.value
)
1061 bits
= opcode
.value
.bit_length()
1062 return int(_SelectableInt(value
=value
, bits
=bits
)[0:6])
1064 return int(opcode
.value
)
1068 return tuple(ppc
.opcode
for ppc
in self
.ppc
)
1070 def match(self
, key
):
1071 for opcode
in self
.opcodes
:
1072 if opcode
.match(key
):
1079 return self
.svp64
.mode
1099 if self
.svp64
is None:
1105 return self
.ppc
.cr_in
1109 return self
.ppc
.cr_in2
1113 return self
.ppc
.cr_out
1115 ptype
= property(lambda self
: self
.svp64
.ptype
)
1116 etype
= property(lambda self
: self
.svp64
.etype
)
1118 extra_idx_in1
= property(lambda self
: self
.svp64
.extra_idx_in1
)
1119 extra_idx_in2
= property(lambda self
: self
.svp64
.extra_idx_in2
)
1120 extra_idx_in3
= property(lambda self
: self
.svp64
.extra_idx_in3
)
1121 extra_idx_out
= property(lambda self
: self
.svp64
.extra_idx_out
)
1122 extra_idx_out2
= property(lambda self
: self
.svp64
.extra_idx_out2
)
1123 extra_idx_cr_in
= property(lambda self
: self
.svp64
.extra_idx_cr_in
)
1124 extra_idx_cr_in2
= property(lambda self
: self
.svp64
.extra_idx_cr_in2
)
1125 extra_idx_cr_out
= property(lambda self
: self
.svp64
.extra_idx_cr_out
)
1127 def __contains__(self
, key
):
1128 return self
.mdwn
.operands
.__contains
__(key
)
1130 def __getitem__(self
, key
):
1131 (cls
, kwargs
) = self
.mdwn
.operands
.__getitem
__(key
)
1132 return cls(record
=self
, **kwargs
)
1136 if "Rc" not in self
:
1138 return self
["Rc"].value
1142 def __init__(self
, record
, name
):
1143 self
.__record
= record
1147 yield ("record", self
.record
)
1148 yield ("name", self
.__name
)
1151 return f
"{self.__class__.__name__}({self.name})"
1159 return self
.__record
1163 return self
.record
.fields
[self
.name
]
1165 def assemble(self
, insn
):
1166 raise NotImplementedError()
1168 def disassemble(self
, insn
,
1169 style
=Style
.NORMAL
, indent
=""):
1170 raise NotImplementedError()
1173 class DynamicOperand(Operand
):
1174 def assemble(self
, insn
, value
):
1176 if isinstance(value
, str):
1177 value
= int(value
, 0)
1179 raise ValueError("signed operands not allowed")
1182 def disassemble(self
, insn
,
1183 style
=Style
.NORMAL
, indent
=""):
1187 if style
>= Style
.VERBOSE
:
1188 span
= map(str, span
)
1189 yield f
"{indent}{self.name}"
1190 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
1191 yield f
"{indent}{indent}{', '.join(span)}"
1193 yield str(int(value
))
1196 class SignedOperand(DynamicOperand
):
1197 def assemble(self
, insn
, value
):
1198 if isinstance(value
, str):
1199 value
= int(value
, 0)
1200 return super().assemble(value
=value
, insn
=insn
)
1202 def assemble(self
, insn
, value
):
1204 if isinstance(value
, str):
1205 value
= int(value
, 0)
1208 def disassemble(self
, insn
,
1209 style
=Style
.NORMAL
, indent
=""):
1211 value
= insn
[span
].to_signed_int()
1212 sign
= "-" if (value
< 0) else ""
1215 if style
>= Style
.VERBOSE
:
1216 span
= map(str, span
)
1217 yield f
"{indent}{self.name}"
1218 yield f
"{indent}{indent}{sign}{value}"
1219 yield f
"{indent}{indent}{', '.join(span)}"
1221 yield f
"{sign}{value}"
1224 class StaticOperand(Operand
):
1225 def __init__(self
, record
, name
, value
):
1226 self
.__value
= value
1227 return super().__init
__(record
=record
, name
=name
)
1230 yield ("value", self
.__value
)
1231 yield from super().__iter
__()
1234 return f
"{self.__class__.__name__}({self.name}, value={self.value})"
1240 def assemble(self
, insn
):
1241 insn
[self
.span
] = self
.value
1243 def disassemble(self
, insn
,
1244 style
=Style
.NORMAL
, indent
=""):
1248 if style
>= Style
.VERBOSE
:
1249 span
= map(str, span
)
1250 yield f
"{indent}{self.name}"
1251 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
1252 yield f
"{indent}{indent}{', '.join(span)}"
1254 yield str(int(value
))
1257 class SpanStaticOperand(StaticOperand
):
1258 def __init__(self
, record
, name
, value
, span
):
1259 self
.__span
= tuple(span
)
1260 return super().__init
__(record
=record
, name
=name
, value
=value
)
1263 yield ("span", self
.__span
)
1264 yield from super().__iter
__()
1271 class POStaticOperand(SpanStaticOperand
):
1272 def __init__(self
, record
, value
):
1273 return super().__init
__(record
=record
, name
="PO",
1274 value
=value
, span
=range(0, 6))
1277 for (key
, value
) in super().__iter
__():
1278 if key
not in {"name", "span"}:
1282 class XOStaticOperand(SpanStaticOperand
):
1283 def __init__(self
, record
, value
, span
):
1284 bits
= record
.section
.bitsel
1285 value
= _SelectableInt(value
=value
, bits
=len(bits
))
1286 span
= dict(zip(bits
, range(len(bits
))))
1287 span_rev
= {value
:key
for (key
, value
) in span
.items()}
1289 # This part is tricky: we cannot use record.operands,
1290 # as this code is called by record.static_operands method.
1291 for (cls
, kwargs
) in record
.mdwn
.operands
:
1292 operand
= cls(record
=record
, **kwargs
)
1293 for idx
in operand
.span
:
1294 rev
= span
.pop(idx
, None)
1296 span_rev
.pop(rev
, None)
1298 value
= int(_selectconcat(*(value
[bit
] for bit
in span
.values())))
1299 span
= tuple(span
.keys())
1301 return super().__init
__(record
=record
, name
="XO",
1302 value
=value
, span
=span
)
1305 for (key
, value
) in super().__iter
__():
1306 if key
not in {"name"}:
1310 class ImmediateOperand(DynamicOperand
):
1314 class SignedImmediateOperand(SignedOperand
, ImmediateOperand
):
1318 class NonZeroOperand(DynamicOperand
):
1319 def assemble(self
, insn
, value
):
1320 if isinstance(value
, str):
1321 value
= int(value
, 0)
1322 if not isinstance(value
, int):
1323 raise ValueError("non-integer operand")
1325 raise ValueError("non-zero operand")
1327 return super().assemble(value
=value
, insn
=insn
)
1329 def disassemble(self
, insn
,
1330 style
=Style
.NORMAL
, indent
=""):
1334 if style
>= Style
.VERBOSE
:
1335 span
= map(str, span
)
1336 yield f
"{indent}{self.name}"
1337 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
1338 yield f
"{indent}{indent}{', '.join(span)}"
1340 yield str(int(value
) + 1)
1343 class ExtendableOperand(DynamicOperand
):
1344 def sv_spec_enter(self
, value
, span
):
1345 return (value
, span
)
1347 def sv_spec(self
, insn
):
1351 span
= tuple(map(str, span
))
1353 if isinstance(insn
, SVP64Instruction
):
1354 (origin_value
, origin_span
) = (value
, span
)
1355 (value
, span
) = self
.sv_spec_enter(value
=value
, span
=span
)
1357 for extra_idx
in self
.extra_idx
:
1358 if self
.record
.etype
is _SVEType
.EXTRA3
:
1359 spec
= insn
.prefix
.rm
.extra3
[extra_idx
]
1360 elif self
.record
.etype
is _SVEType
.EXTRA2
:
1361 spec
= insn
.prefix
.rm
.extra2
[extra_idx
]
1363 raise ValueError(self
.record
.etype
)
1366 vector
= bool(spec
[0])
1367 spec_span
= spec
.__class
__
1368 if self
.record
.etype
is _SVEType
.EXTRA3
:
1369 spec_span
= tuple(map(str, spec_span
[1, 2]))
1371 elif self
.record
.etype
is _SVEType
.EXTRA2
:
1372 spec_span
= tuple(map(str, spec_span
[1,]))
1373 spec
= _SelectableInt(value
=spec
[1].value
, bits
=2)
1376 spec_span
= (spec_span
+ ("{0}",))
1378 spec_span
= (("{0}",) + spec_span
)
1380 raise ValueError(self
.record
.etype
)
1382 vector_shift
= (2 + (5 - value
.bits
))
1383 scalar_shift
= value
.bits
1384 spec_shift
= (5 - value
.bits
)
1386 bits
= (len(span
) + len(spec_span
))
1387 value
= _SelectableInt(value
=value
.value
, bits
=bits
)
1388 spec
= _SelectableInt(value
=spec
.value
, bits
=bits
)
1390 value
= ((value
<< vector_shift
) |
(spec
<< spec_shift
))
1391 span
= (span
+ spec_span
+ ((spec_shift
* ("{0}",))))
1393 value
= ((spec
<< scalar_shift
) | value
)
1394 span
= ((spec_shift
* ("{0}",)) + spec_span
+ span
)
1396 (value
, span
) = self
.sv_spec_leave(value
=value
, span
=span
,
1397 origin_value
=origin_value
, origin_span
=origin_span
)
1399 return (vector
, value
, span
)
1401 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
1402 return (value
, span
)
1405 def extra_idx(self
):
1406 for (key
, record
) in self
.record
.svp64
.extras
.items():
1407 if record
["reg"].alias
is self
.extra_reg
.alias
:
1411 def extra_reg(self
):
1412 return _Reg(self
.name
)
1414 def remap(self
, value
, vector
):
1415 raise NotImplementedError()
1417 def assemble(self
, value
, insn
, prefix
):
1420 if isinstance(value
, str):
1421 value
= value
.lower()
1422 if value
.startswith("%"):
1424 if value
.startswith("*"):
1425 if not isinstance(insn
, SVP64Instruction
):
1426 raise ValueError(value
)
1429 if value
.startswith(prefix
):
1430 if (self
.extra_reg
.or_zero
and (value
== f
"{prefix}0")):
1431 raise ValueError(value
)
1432 value
= value
[len(prefix
):]
1433 value
= int(value
, 0)
1435 if isinstance(insn
, SVP64Instruction
):
1436 (value
, extra
) = self
.remap(value
=value
, vector
=vector
)
1438 for extra_idx
in self
.extra_idx
:
1439 if self
.record
.etype
is _SVEType
.EXTRA3
:
1440 insn
.prefix
.rm
.extra3
[extra_idx
] = extra
1441 elif self
.record
.etype
is _SVEType
.EXTRA2
:
1442 insn
.prefix
.rm
.extra2
[extra_idx
] = extra
1444 raise ValueError(self
.record
.etype
)
1446 return super().assemble(value
=value
, insn
=insn
)
1448 def disassemble(self
, insn
,
1449 style
=Style
.NORMAL
, prefix
="", indent
=""):
1450 (vector
, value
, span
) = self
.sv_spec(insn
=insn
)
1452 if (self
.extra_reg
.or_zero
and (value
== 0)):
1455 if style
>= Style
.VERBOSE
:
1456 mode
= "vector" if vector
else "scalar"
1457 yield f
"{indent}{self.name} ({mode})"
1458 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
1459 yield f
"{indent}{indent}{', '.join(span)}"
1460 if isinstance(insn
, SVP64Instruction
):
1461 for extra_idx
in frozenset(self
.extra_idx
):
1462 if self
.record
.etype
is _SVEType
.NONE
:
1463 yield f
"{indent}{indent}extra[none]"
1465 etype
= repr(self
.record
.etype
).lower()
1466 yield f
"{indent}{indent}{etype}{extra_idx!r}"
1468 vector
= "*" if vector
else ""
1469 yield f
"{vector}{prefix}{int(value)}"
1472 class SimpleRegisterOperand(ExtendableOperand
):
1473 def remap(self
, value
, vector
):
1475 extra
= (value
& 0b11)
1476 value
= (value
>> 2)
1478 extra
= (value
>> 5)
1479 value
= (value
& 0b11111)
1481 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1482 # (and shrink to a single bit if ok)
1483 if self
.record
.etype
is _SVEType
.EXTRA2
:
1485 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1486 assert (extra
& 0b01) == 0, \
1487 ("vector field %s cannot fit into EXTRA2" % value
)
1488 extra
= (0b10 |
(extra
>> 1))
1490 # range is r0-r63 in increments of 1
1491 assert (extra
>> 1) == 0, \
1492 ("scalar GPR %d cannot fit into EXTRA2" % value
)
1494 elif self
.record
.etype
is _SVEType
.EXTRA3
:
1496 # EXTRA3 vector bit needs marking
1499 raise ValueError(self
.record
.etype
)
1501 return (value
, extra
)
1504 class GPROperand(SimpleRegisterOperand
):
1505 def assemble(self
, insn
, value
):
1506 return super().assemble(value
=value
, insn
=insn
, prefix
="r")
1508 def disassemble(self
, insn
,
1509 style
=Style
.NORMAL
, indent
=""):
1510 prefix
= "" if (style
<= Style
.SHORT
) else "r"
1511 yield from super().disassemble(prefix
=prefix
, insn
=insn
,
1512 style
=style
, indent
=indent
)
1515 class GPRPairOperand(GPROperand
):
1519 class FPROperand(SimpleRegisterOperand
):
1520 def assemble(self
, insn
, value
):
1521 return super().assemble(value
=value
, insn
=insn
, prefix
="f")
1523 def disassemble(self
, insn
,
1524 style
=Style
.NORMAL
, indent
=""):
1525 prefix
= "" if (style
<= Style
.SHORT
) else "f"
1526 yield from super().disassemble(prefix
=prefix
, insn
=insn
,
1527 style
=style
, indent
=indent
)
1530 class FPRPairOperand(FPROperand
):
1534 class ConditionRegisterFieldOperand(ExtendableOperand
):
1535 def pattern(name_pattern
):
1536 (name
, pattern
) = name_pattern
1537 return (name
, _re
.compile(f
"^{pattern}$", _re
.S
))
1546 CR
= r
"(?:CR|cr)([0-9]+)"
1548 BIT
= rf
"({'|'.join(CONDS.keys())})"
1549 LBIT
= fr
"{BIT}\s*\+\s*" # BIT+
1550 RBIT
= fr
"\s*\+\s*{BIT}" # +BIT
1551 CRN
= fr
"{CR}\s*\*\s*{N}" # CR*N
1552 NCR
= fr
"{N}\s*\*\s*{CR}" # N*CR
1553 XCR
= fr
"{CR}\.{BIT}"
1554 PATTERNS
= tuple(map(pattern
, (
1559 ("BIT+CR", (LBIT
+ CR
)),
1560 ("CR+BIT", (CR
+ RBIT
)),
1561 ("BIT+CR*N", (LBIT
+ CRN
)),
1562 ("CR*N+BIT", (CRN
+ RBIT
)),
1563 ("BIT+N*CR", (LBIT
+ NCR
)),
1564 ("N*CR+BIT", (NCR
+ RBIT
)),
1567 def remap(self
, value
, vector
, regtype
):
1568 if regtype
is _RegType
.CR_5BIT
:
1569 subvalue
= (value
& 0b11)
1573 extra
= (value
& 0b1111)
1576 extra
= (value
>> 3)
1579 if self
.record
.etype
is _SVEType
.EXTRA2
:
1581 assert (extra
& 0b111) == 0, \
1582 "vector CR cannot fit into EXTRA2"
1583 extra
= (0b10 |
(extra
>> 3))
1585 assert (extra
>> 1) == 0, \
1586 "scalar CR cannot fit into EXTRA2"
1588 elif self
.record
.etype
is _SVEType
.EXTRA3
:
1590 assert (extra
& 0b11) == 0, \
1591 "vector CR cannot fit into EXTRA3"
1592 extra
= (0b100 |
(extra
>> 2))
1594 assert (extra
>> 2) == 0, \
1595 "scalar CR cannot fit into EXTRA3"
1598 if regtype
is _RegType
.CR_5BIT
:
1599 value
= ((value
<< 2) | subvalue
)
1601 return (value
, extra
)
1603 def assemble(self
, insn
, value
):
1604 if isinstance(value
, str):
1607 if value
.startswith("*"):
1608 if not isinstance(insn
, SVP64Instruction
):
1609 raise ValueError(value
)
1613 for (name
, pattern
) in reversed(self
.__class
__.PATTERNS
):
1614 match
= pattern
.match(value
)
1615 if match
is not None:
1616 keys
= name
.replace("+", "_").replace("*", "_").split("_")
1617 values
= match
.groups()
1618 match
= dict(zip(keys
, values
))
1619 CR
= int(match
["CR"])
1623 N
= int(match
.get("N", "1"))
1624 BIT
= self
.__class
__.CONDS
[match
.get("BIT", "lt")]
1625 value
= ((CR
* N
) + BIT
)
1632 return super().assemble(value
=value
, insn
=insn
, prefix
="cr")
1634 def disassemble(self
, insn
,
1635 style
=Style
.NORMAL
, prefix
="", indent
=""):
1636 (vector
, value
, span
) = self
.sv_spec(insn
=insn
)
1638 if style
>= Style
.VERBOSE
:
1639 mode
= "vector" if vector
else "scalar"
1640 yield f
"{indent}{self.name} ({mode})"
1641 yield f
"{indent}{indent}{int(value):0{value.bits}b}"
1642 yield f
"{indent}{indent}{', '.join(span)}"
1643 if isinstance(insn
, SVP64Instruction
):
1644 for extra_idx
in frozenset(self
.extra_idx
):
1645 if self
.record
.etype
is _SVEType
.NONE
:
1646 yield f
"{indent}{indent}extra[none]"
1648 etype
= repr(self
.record
.etype
).lower()
1649 yield f
"{indent}{indent}{etype}{extra_idx!r}"
1651 vector
= "*" if vector
else ""
1652 CR
= int(value
>> 2)
1654 cond
= ("lt", "gt", "eq", "so")[CC
]
1655 if style
>= Style
.NORMAL
:
1657 if isinstance(insn
, SVP64Instruction
):
1658 yield f
"{vector}cr{CR}.{cond}"
1660 yield f
"4*cr{CR}+{cond}"
1664 yield f
"{vector}{prefix}{int(value)}"
1667 class CR3Operand(ConditionRegisterFieldOperand
):
1668 def remap(self
, value
, vector
):
1669 return super().remap(value
=value
, vector
=vector
,
1670 regtype
=_RegType
.CR_3BIT
)
1673 class CR5Operand(ConditionRegisterFieldOperand
):
1674 def remap(self
, value
, vector
):
1675 return super().remap(value
=value
, vector
=vector
,
1676 regtype
=_RegType
.CR_5BIT
)
1678 def sv_spec_enter(self
, value
, span
):
1679 value
= _SelectableInt(value
=(value
.value
>> 2), bits
=3)
1680 return (value
, span
)
1682 def sv_spec_leave(self
, value
, span
, origin_value
, origin_span
):
1683 value
= _selectconcat(value
, origin_value
[3:5])
1685 return (value
, span
)
1688 class EXTSOperand(SignedOperand
):
1689 field
: str # real name to report
1690 nz
: int = 0 # number of zeros
1691 fmt
: str = "d" # integer formatter
1693 def __init__(self
, record
, name
, field
, nz
=0, fmt
="d"):
1694 self
.__field
= field
1697 return super().__init
__(record
=record
, name
=name
)
1713 return self
.record
.fields
[self
.field
]
1715 def assemble(self
, insn
, value
):
1717 if isinstance(value
, str):
1718 value
= int(value
, 0)
1719 insn
[span
] = (value
>> self
.nz
)
1721 def disassemble(self
, insn
,
1722 style
=Style
.NORMAL
, indent
=""):
1724 value
= insn
[span
].to_signed_int()
1725 sign
= "-" if (value
< 0) else ""
1726 value
= (abs(value
) << self
.nz
)
1728 if style
>= Style
.VERBOSE
:
1729 span
= (tuple(map(str, span
)) + (("{0}",) * self
.nz
))
1730 zeros
= ("0" * self
.nz
)
1731 hint
= f
"{self.name} = EXTS({self.field} || {zeros})"
1732 yield f
"{indent * 1}{hint}"
1733 yield f
"{indent * 2}{self.field}"
1734 yield f
"{indent * 3}{sign}{value:{self.fmt}}"
1735 yield f
"{indent * 3}{', '.join(span)}"
1737 yield f
"{sign}{value:{self.fmt}}"
1740 class TargetAddrOperand(EXTSOperand
):
1741 def __init__(self
, record
, name
, field
):
1742 return super().__init
__(record
=record
, name
=name
, field
=field
,
1746 class TargetAddrOperandLI(TargetAddrOperand
):
1747 def __init__(self
, record
, name
):
1748 return super().__init
__(record
=record
, name
=name
, field
="LI")
1751 class TargetAddrOperandBD(TargetAddrOperand
):
1752 def __init__(self
, record
, name
):
1753 return super().__init
__(record
=record
, name
=name
, field
="BD")
1756 class EXTSOperandDS(EXTSOperand
, ImmediateOperand
):
1757 def __init__(self
, record
, name
):
1758 return super().__init
__(record
=record
, name
=name
, field
="DS", nz
=2)
1761 class EXTSOperandDQ(EXTSOperand
, ImmediateOperand
):
1762 def __init__(self
, record
, name
):
1763 return super().__init
__(record
=record
, name
=name
, field
="DQ", nz
=4)
1766 class DOperandDX(SignedOperand
):
1769 cls
= lambda name
: DynamicOperand(record
=self
.record
, name
=name
)
1770 operands
= map(cls
, ("d0", "d1", "d2"))
1771 spans
= map(lambda operand
: operand
.span
, operands
)
1772 return sum(spans
, tuple())
1774 def disassemble(self
, insn
,
1775 style
=Style
.NORMAL
, indent
=""):
1777 value
= insn
[span
].to_signed_int()
1778 sign
= "-" if (value
< 0) else ""
1781 if style
>= Style
.VERBOSE
:
1788 for (subname
, subspan
) in mapping
.items():
1789 operand
= DynamicOperand(name
=subname
)
1791 span
= map(str, span
)
1792 yield f
"{indent}{indent}{operand.name} = D{subspan}"
1793 yield f
"{indent}{indent}{indent}{sign}{value}"
1794 yield f
"{indent}{indent}{indent}{', '.join(span)}"
1796 yield f
"{sign}{value}"
1799 class Instruction(_Mapping
):
1801 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
1802 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
1803 raise ValueError(bits
)
1805 if isinstance(value
, bytes
):
1806 if ((len(value
) * 8) != bits
):
1807 raise ValueError(f
"bit length mismatch")
1808 value
= int.from_bytes(value
, byteorder
=byteorder
)
1810 if isinstance(value
, int):
1811 value
= _SelectableInt(value
=value
, bits
=bits
)
1812 elif isinstance(value
, Instruction
):
1813 value
= value
.storage
1815 if not isinstance(value
, _SelectableInt
):
1816 raise ValueError(value
)
1819 if len(value
) != bits
:
1820 raise ValueError(value
)
1822 value
= _SelectableInt(value
=value
, bits
=bits
)
1824 return cls(storage
=value
)
1827 return hash(int(self
))
1829 def __getitem__(self
, key
):
1830 return self
.storage
.__getitem
__(key
)
1832 def __setitem__(self
, key
, value
):
1833 return self
.storage
.__setitem
__(key
, value
)
1835 def bytes(self
, byteorder
="little"):
1836 nr_bytes
= (len(self
.__class
__) // 8)
1837 return int(self
).to_bytes(nr_bytes
, byteorder
=byteorder
)
1840 def record(cls
, db
, entry
):
1843 raise KeyError(entry
)
1847 def operands(cls
, record
):
1848 yield from record
.operands
1851 def static_operands(cls
, record
):
1852 return filter(lambda operand
: isinstance(operand
, StaticOperand
),
1853 cls
.operands(record
=record
))
1856 def dynamic_operands(cls
, record
):
1857 return filter(lambda operand
: isinstance(operand
, DynamicOperand
),
1858 cls
.operands(record
=record
))
1860 def spec(self
, record
, prefix
):
1861 dynamic_operands
= tuple(map(_operator
.itemgetter(0),
1862 self
.spec_dynamic_operands(record
=record
)))
1864 static_operands
= []
1865 for (name
, value
) in self
.spec_static_operands(record
=record
):
1866 static_operands
.append(f
"{name}={value}")
1869 if dynamic_operands
:
1871 operands
+= ",".join(dynamic_operands
)
1874 operands
+= " ".join(static_operands
)
1876 return f
"{prefix}{record.name}{operands}"
1878 def spec_static_operands(self
, record
):
1879 for operand
in self
.static_operands(record
=record
):
1880 if not isinstance(operand
, (POStaticOperand
, XOStaticOperand
)):
1881 yield (operand
.name
, operand
.value
)
1883 def spec_dynamic_operands(self
, record
, style
=Style
.NORMAL
):
1887 for operand
in self
.dynamic_operands(record
=record
):
1889 value
= " ".join(operand
.disassemble(insn
=self
,
1890 style
=min(style
, Style
.NORMAL
)))
1892 name
= f
"{imm_name}({name})"
1893 value
= f
"{imm_value}({value})"
1895 if isinstance(operand
, ImmediateOperand
):
1903 def assemble(cls
, record
, arguments
=None):
1904 if arguments
is None:
1907 insn
= cls
.integer(value
=0)
1909 for operand
in cls
.static_operands(record
=record
):
1910 operand
.assemble(insn
=insn
)
1912 arguments
= Arguments(record
=record
,
1913 arguments
=arguments
, operands
=cls
.dynamic_operands(record
=record
))
1914 for (value
, operand
) in arguments
:
1915 operand
.assemble(insn
=insn
, value
=value
)
1919 def disassemble(self
, record
,
1921 style
=Style
.NORMAL
):
1922 raise NotImplementedError()
1925 class WordInstruction(Instruction
):
1926 _
: _Field
= range(0, 32)
1927 PO
: _Field
= range(0, 6)
1930 def integer(cls
, value
, byteorder
="little"):
1931 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
1936 for idx
in range(32):
1937 bit
= int(self
[idx
])
1939 return "".join(map(str, bits
))
1941 def disassemble(self
, record
,
1943 style
=Style
.NORMAL
):
1944 if style
<= Style
.SHORT
:
1947 blob
= self
.bytes(byteorder
=byteorder
)
1948 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
1952 yield f
"{blob}.long 0x{int(self):08x}"
1955 # awful temporary hack: workaround for ld-update
1956 # https://bugs.libre-soc.org/show_bug.cgi?id=1056#c2
1957 # XXX TODO must check that *EXTENDED* RA != extended-RT
1958 if (record
.svp64
is not None and
1959 record
.mode
== _SVMode
.LDST_IMM
and
1960 'u' in record
.name
):
1961 yield f
"{blob}.long 0x{int(self):08x}"
1965 if style
is Style
.LEGACY
:
1967 for operand
in self
.dynamic_operands(record
=record
):
1968 if isinstance(operand
, (GPRPairOperand
, FPRPairOperand
)):
1971 if style
is Style
.LEGACY
and (paired
or record
.ppc
.unofficial
):
1972 yield f
"{blob}.long 0x{int(self):08x}"
1974 operands
= tuple(map(_operator
.itemgetter(1),
1975 self
.spec_dynamic_operands(record
=record
, style
=style
)))
1977 operands
= ",".join(operands
)
1978 yield f
"{blob}{record.name} {operands}"
1980 yield f
"{blob}{record.name}"
1982 if style
>= Style
.VERBOSE
:
1984 binary
= self
.binary
1985 spec
= self
.spec(record
=record
, prefix
="")
1986 yield f
"{indent}spec"
1987 yield f
"{indent}{indent}{spec}"
1988 yield f
"{indent}pcode"
1989 for stmt
in record
.mdwn
.pcode
:
1990 yield f
"{indent}{indent}{stmt}"
1991 yield f
"{indent}binary"
1992 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
1993 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
1994 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
1995 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
1996 yield f
"{indent}opcodes"
1997 for opcode
in record
.opcodes
:
1998 yield f
"{indent}{indent}{opcode!r}"
1999 for operand
in self
.operands(record
=record
):
2000 yield from operand
.disassemble(insn
=self
,
2001 style
=style
, indent
=indent
)
2005 class PrefixedInstruction(Instruction
):
2006 class Prefix(WordInstruction
.remap(range(0, 32))):
2009 class Suffix(WordInstruction
.remap(range(32, 64))):
2012 _
: _Field
= range(64)
2018 def integer(cls
, value
, byteorder
="little"):
2019 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
2022 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
2023 def transform(value
):
2024 return WordInstruction
.integer(value
=value
,
2025 byteorder
=byteorder
)[0:32]
2027 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
2028 value
= _selectconcat(prefix
, suffix
)
2030 return super().integer(bits
=64, value
=value
)
2033 class Mode(_Mapping
):
2034 _
: _Field
= range(0, 5)
2035 sel
: _Field
= (0, 1)
2038 class ExtraRM(_Mapping
):
2039 _
: _Field
= range(0, 9)
2042 class Extra2RM(ExtraRM
):
2043 idx0
: _Field
= range(0, 2)
2044 idx1
: _Field
= range(2, 4)
2045 idx2
: _Field
= range(4, 6)
2046 idx3
: _Field
= range(6, 8)
2048 def __getitem__(self
, key
):
2054 _SVExtra
.Idx0
: self
.idx0
,
2055 _SVExtra
.Idx1
: self
.idx1
,
2056 _SVExtra
.Idx2
: self
.idx2
,
2057 _SVExtra
.Idx3
: self
.idx3
,
2060 def __setitem__(self
, key
, value
):
2061 self
[key
].assign(value
)
2064 class Extra3RM(ExtraRM
):
2065 idx0
: _Field
= range(0, 3)
2066 idx1
: _Field
= range(3, 6)
2067 idx2
: _Field
= range(6, 9)
2069 def __getitem__(self
, key
):
2074 _SVExtra
.Idx0
: self
.idx0
,
2075 _SVExtra
.Idx1
: self
.idx1
,
2076 _SVExtra
.Idx2
: self
.idx2
,
2079 def __setitem__(self
, key
, value
):
2080 self
[key
].assign(value
)
2083 class BaseRM(_Mapping
):
2084 _
: _Field
= range(24)
2085 mmode
: _Field
= (0,)
2086 mask
: _Field
= range(1, 4)
2087 elwidth
: _Field
= range(4, 6)
2088 ewsrc
: _Field
= range(6, 8)
2089 subvl
: _Field
= range(8, 10)
2090 mode
: Mode
.remap(range(19, 24))
2091 smask_extra322
: _Field
= (6,7,18,) # LDST_IDX is EXTRA332
2092 smask
: _Field
= range(16, 19) # everything else use this
2093 extra
: ExtraRM
.remap(range(10, 19))
2094 extra2
: Extra2RM
.remap(range(10, 19))
2095 extra3
: Extra3RM
.remap(range(10, 19))
2096 # XXX extra332 = (extra3[0], extra3[1], extra2[3])
2098 def specifiers(self
, record
):
2099 subvl
= int(self
.subvl
)
2107 def disassemble(self
, style
=Style
.NORMAL
):
2108 if style
>= Style
.VERBOSE
:
2110 for (name
, span
) in self
.traverse(path
="RM"):
2111 value
= self
.storage
[span
]
2113 yield f
"{indent}{int(value):0{value.bits}b}"
2114 yield f
"{indent}{', '.join(map(str, span))}"
2117 class FFRc1BaseRM(BaseRM
):
2118 def specifiers(self
, record
, mode
):
2119 inv
= _SelectableInt(value
=int(self
.inv
), bits
=1)
2120 CR
= _SelectableInt(value
=int(self
.CR
), bits
=2)
2121 mask
= int(_selectconcat(CR
, inv
))
2122 predicate
= PredicateBaseRM
.predicate(True, mask
)
2123 yield f
"{mode}={predicate}"
2125 yield from super().specifiers(record
=record
)
2128 class FFRc0BaseRM(BaseRM
):
2129 def specifiers(self
, record
, mode
):
2131 inv
= "~" if self
.inv
else ""
2132 yield f
"{mode}={inv}RC1"
2134 yield from super().specifiers(record
=record
)
2137 class SatBaseRM(BaseRM
):
2138 def specifiers(self
, record
):
2144 yield from super().specifiers(record
=record
)
2147 class ZZBaseRM(BaseRM
):
2148 def specifiers(self
, record
):
2152 yield from super().specifiers(record
=record
)
2155 class ZZCombinedBaseRM(BaseRM
):
2156 def specifiers(self
, record
):
2157 if self
.sz
and self
.dz
:
2164 yield from super().specifiers(record
=record
)
2167 class DZBaseRM(BaseRM
):
2168 def specifiers(self
, record
):
2172 yield from super().specifiers(record
=record
)
2175 class SZBaseRM(BaseRM
):
2176 def specifiers(self
, record
):
2180 yield from super().specifiers(record
=record
)
2183 class MRBaseRM(BaseRM
):
2184 def specifiers(self
, record
):
2190 yield from super().specifiers(record
=record
)
2193 class ElsBaseRM(BaseRM
):
2194 def specifiers(self
, record
):
2198 yield from super().specifiers(record
=record
)
2201 class WidthBaseRM(BaseRM
):
2203 def width(FP
, width
):
2212 width
= ("fp" + width
)
2215 def specifiers(self
, record
):
2216 # elwidths: use "w=" if same otherwise dw/sw
2217 # FIXME this should consider FP instructions
2219 dw
= WidthBaseRM
.width(FP
, int(self
.elwidth
))
2220 sw
= WidthBaseRM
.width(FP
, int(self
.ewsrc
))
2221 if record
.svp64
.mode
is _SVMode
.CROP
:
2225 sw
= WidthBaseRM
.width(FP
, int(self
.ewsrc
))
2234 yield from super().specifiers(record
=record
)
2237 class PredicateBaseRM(BaseRM
):
2239 def predicate(CR
, mask
):
2242 (False, 0b001): "1<<r3",
2243 (False, 0b010): "r3",
2244 (False, 0b011): "~r3",
2245 (False, 0b100): "r10",
2246 (False, 0b101): "~r10",
2247 (False, 0b110): "r30",
2248 (False, 0b111): "~r30",
2250 (True, 0b000): "lt",
2251 (True, 0b001): "ge",
2252 (True, 0b010): "gt",
2253 (True, 0b011): "le",
2254 (True, 0b100): "eq",
2255 (True, 0b101): "ne",
2256 (True, 0b110): "so",
2257 (True, 0b111): "ns",
2260 def specifiers(self
, record
):
2261 # predication - single and twin
2262 # use "m=" if same otherwise sm/dm
2263 CR
= (int(self
.mmode
) == 1)
2264 mask
= int(self
.mask
)
2265 sm
= dm
= PredicateBaseRM
.predicate(CR
, mask
)
2266 if record
.svp64
.ptype
is _SVPType
.P2
:
2267 # LDST_IDX smask moving to extra322 but not straight away (False)
2268 if False and record
.svp64
.mode
is _SVMode
.LDST_IDX
:
2269 smask
= int(self
.smask_extra332
)
2271 smask
= int(self
.smask
)
2272 sm
= PredicateBaseRM
.predicate(CR
, smask
)
2281 yield from super().specifiers(record
=record
)
2284 class PredicateWidthBaseRM(WidthBaseRM
, PredicateBaseRM
):
2288 class SEABaseRM(BaseRM
):
2289 def specifiers(self
, record
):
2293 yield from super().specifiers(record
=record
)
2296 class VLiBaseRM(BaseRM
):
2297 def specifiers(self
, record
):
2301 yield from super().specifiers(record
=record
)
2304 class NormalBaseRM(PredicateWidthBaseRM
):
2307 https://libre-soc.org/openpower/sv/normal/
2312 class NormalSimpleRM(ZZCombinedBaseRM
, NormalBaseRM
):
2313 """normal: simple mode"""
2317 def specifiers(self
, record
):
2318 yield from super().specifiers(record
=record
)
2321 class NormalMRRM(MRBaseRM
, NormalBaseRM
):
2322 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2326 class NormalFFRc1RM(FFRc1BaseRM
, VLiBaseRM
, NormalBaseRM
):
2327 """normal: Rc=1: ffirst CR sel"""
2330 CR
: BaseRM
.mode
[3, 4]
2332 def specifiers(self
, record
):
2333 yield from super().specifiers(record
=record
, mode
="ff")
2336 class NormalFFRc0RM(FFRc0BaseRM
, VLiBaseRM
, NormalBaseRM
):
2337 """normal: Rc=0: ffirst z/nonz"""
2342 def specifiers(self
, record
):
2343 yield from super().specifiers(record
=record
, mode
="ff")
2346 class NormalSatRM(SatBaseRM
, ZZCombinedBaseRM
, NormalBaseRM
):
2347 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2353 class NormalRM(NormalBaseRM
):
2354 simple
: NormalSimpleRM
2356 ffrc1
: NormalFFRc1RM
2357 ffrc0
: NormalFFRc0RM
2361 class LDSTImmBaseRM(PredicateWidthBaseRM
):
2363 LD/ST Immediate mode
2364 https://libre-soc.org/openpower/sv/ldst/
2369 class LDSTImmSimpleRM(ElsBaseRM
, ZZBaseRM
, LDSTImmBaseRM
):
2370 """ld/st immediate: simple mode"""
2371 pi
: BaseRM
.mode
[2] # Post-Increment Mode
2372 lf
: BaseRM
.mode
[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2378 def specifiers(self
, record
):
2384 yield from super().specifiers(record
=record
)
2387 class LDSTFFRc1RM(FFRc1BaseRM
, VLiBaseRM
, LDSTImmBaseRM
):
2388 """ld/st immediate&indexed: Rc=1: ffirst CR sel"""
2391 CR
: BaseRM
.mode
[3, 4]
2393 def specifiers(self
, record
):
2394 yield from super().specifiers(record
=record
, mode
="ff")
2397 class LDSTFFRc0RM(FFRc0BaseRM
, VLiBaseRM
, LDSTImmBaseRM
):
2398 """ld/st immediate&indexed: Rc=0: ffirst z/nonz"""
2403 def specifiers(self
, record
):
2404 yield from super().specifiers(record
=record
, mode
="ff")
2407 class LDSTImmRM(LDSTImmBaseRM
):
2408 simple
: LDSTImmSimpleRM
2413 class LDSTIdxBaseRM(PredicateWidthBaseRM
):
2416 https://libre-soc.org/openpower/sv/ldst/
2421 class LDSTIdxSimpleRM(SEABaseRM
, ZZBaseRM
, LDSTIdxBaseRM
):
2422 """ld/st index: simple mode (includes element-strided and Signed-EA)"""
2423 pi
: BaseRM
.mode
[2] # Post-Increment Mode
2430 def specifiers(self
, record
):
2436 yield from super().specifiers(record
=record
)
2439 class LDSTIdxRM(LDSTIdxBaseRM
):
2440 simple
: LDSTIdxSimpleRM
2446 class CROpBaseRM(BaseRM
):
2449 https://libre-soc.org/openpower/sv/cr_ops/
2454 class CROpSimpleRM(PredicateBaseRM
, ZZCombinedBaseRM
, CROpBaseRM
):
2455 """crop: simple mode"""
2460 def specifiers(self
, record
):
2462 yield "rg" # simple CR Mode reports /rg
2464 yield from super().specifiers(record
=record
)
2467 class CROpMRRM(MRBaseRM
, ZZCombinedBaseRM
, CROpBaseRM
):
2468 """crop: scalar reduce mode (mapreduce)"""
2474 class CROpFF5RM(FFRc0BaseRM
, PredicateBaseRM
, VLiBaseRM
, DZBaseRM
,
2475 SZBaseRM
, CROpBaseRM
):
2476 """crop: ffirst 5-bit mode"""
2483 def specifiers(self
, record
):
2484 yield from super().specifiers(record
=record
, mode
="ff")
2487 # FIXME: almost everything in this class contradicts the specs (it doesn't)
2488 # The modes however are swapped: 5-bit is 3-bit, 3-bit is 5-bit
2489 class CROpFF3RM(FFRc1BaseRM
, PredicateBaseRM
, VLiBaseRM
, ZZBaseRM
, CROpBaseRM
):
2490 """cr_op: ffirst 3-bit mode"""
2496 def specifiers(self
, record
):
2497 yield from super().specifiers(record
=record
, mode
="ff")
2500 class CROpRM(CROpBaseRM
):
2501 simple
: CROpSimpleRM
2507 # ********************
2509 # https://libre-soc.org/openpower/sv/branches/
2510 class BranchBaseRM(BaseRM
):
2520 def specifiers(self
, record
):
2532 raise ValueError(self
.sz
)
2544 # Branch modes lack source mask.
2545 # Therefore a custom code is needed.
2546 CR
= (int(self
.mmode
) == 1)
2547 mask
= int(self
.mask
)
2548 m
= PredicateBaseRM
.predicate(CR
, mask
)
2552 yield from super().specifiers(record
=record
)
2555 class BranchSimpleRM(BranchBaseRM
):
2556 """branch: simple mode"""
2560 class BranchVLSRM(BranchBaseRM
):
2561 """branch: VLSET mode"""
2565 def specifiers(self
, record
):
2571 }[int(self
.VSb
), int(self
.VLi
)]
2573 yield from super().specifiers(record
=record
)
2576 class BranchCTRRM(BranchBaseRM
):
2577 """branch: CTR-test mode"""
2580 def specifiers(self
, record
):
2586 yield from super().specifiers(record
=record
)
2589 class BranchCTRVLSRM(BranchVLSRM
, BranchCTRRM
):
2590 """branch: CTR-test+VLSET mode"""
2594 class BranchRM(BranchBaseRM
):
2595 simple
: BranchSimpleRM
2598 ctrvls
: BranchCTRVLSRM
2609 @_dataclasses.dataclass(eq
=True, frozen
=True)
2614 def match(cls
, desc
, record
):
2615 raise NotImplementedError()
2617 def validate(self
, others
):
2620 def assemble(self
, insn
):
2621 raise NotImplementedError()
2624 @_dataclasses.dataclass(eq
=True, frozen
=True)
2625 class SpecifierWidth(Specifier
):
2629 def match(cls
, desc
, record
, etalon
):
2630 (mode
, _
, value
) = desc
.partition("=")
2632 value
= value
.strip()
2635 width
= _SVP64Width(value
)
2637 return cls(record
=record
, width
=width
)
2640 @_dataclasses.dataclass(eq
=True, frozen
=True)
2641 class SpecifierW(SpecifierWidth
):
2643 def match(cls
, desc
, record
):
2644 return super().match(desc
=desc
, record
=record
, etalon
="w")
2646 def assemble(self
, insn
):
2647 selector
= insn
.select(record
=self
.record
)
2648 if self
.record
.svp64
.mode
is not _SVMode
.CROP
:
2649 selector
.ewsrc
= self
.width
.value
2650 selector
.elwidth
= self
.width
.value
2653 @_dataclasses.dataclass(eq
=True, frozen
=True)
2654 class SpecifierSW(SpecifierWidth
):
2656 def match(cls
, desc
, record
):
2657 if record
.svp64
.mode
is _SVMode
.CROP
:
2659 return super().match(desc
=desc
, record
=record
, etalon
="sw")
2661 def assemble(self
, insn
):
2662 selector
= insn
.select(record
=self
.record
)
2663 selector
.ewsrc
= self
.width
.value
2666 @_dataclasses.dataclass(eq
=True, frozen
=True)
2667 class SpecifierDW(SpecifierWidth
):
2669 def match(cls
, desc
, record
):
2670 return super().match(desc
=desc
, record
=record
, etalon
="dw")
2672 def assemble(self
, insn
):
2673 selector
= insn
.select(record
=self
.record
)
2674 selector
.elwidth
= self
.width
.value
2677 @_dataclasses.dataclass(eq
=True, frozen
=True)
2678 class SpecifierSubVL(Specifier
):
2682 def match(cls
, desc
, record
):
2684 value
= _SVP64SubVL(desc
)
2688 return cls(record
=record
, value
=value
)
2690 def assemble(self
, insn
):
2691 selector
= insn
.select(record
=self
.record
)
2692 selector
.subvl
= int(self
.value
.value
)
2695 @_dataclasses.dataclass(eq
=True, frozen
=True)
2696 class SpecifierPredicate(Specifier
):
2701 def match(cls
, desc
, record
, mode_match
, pred_match
):
2702 (mode
, _
, pred
) = desc
.partition("=")
2705 if not mode_match(mode
):
2708 pred
= _SVP64Pred(pred
.strip())
2709 if not pred_match(pred
):
2710 raise ValueError(pred
)
2712 return cls(record
=record
, mode
=mode
, pred
=pred
)
2715 @_dataclasses.dataclass(eq
=True, frozen
=True)
2716 class SpecifierFF(SpecifierPredicate
):
2718 def match(cls
, desc
, record
):
2719 return super().match(desc
=desc
, record
=record
,
2720 mode_match
=lambda mode_arg
: mode_arg
== "ff",
2721 pred_match
=lambda pred_arg
: pred_arg
.mode
in (
2726 def assemble(self
, insn
):
2727 selector
= insn
.select(record
=self
.record
)
2728 if selector
.mode
.sel
!= 0:
2729 raise ValueError("cannot override mode")
2730 if self
.record
.svp64
.mode
is _SVMode
.CROP
:
2731 selector
.mode
.sel
= 0b01
2732 # HACK: please finally provide correct logic for CRs.
2733 if self
.pred
in (_SVP64Pred
.RC1
, _SVP64Pred
.RC1_N
):
2734 selector
.mode
[2] = (self
.pred
is _SVP64Pred
.RC1_N
)
2736 selector
.mode
[2] = self
.pred
.inv
2737 selector
.mode
[3, 4] = self
.pred
.state
2739 selector
.mode
.sel
= 0b01 if self
.mode
== "ff" else 0b11
2740 selector
.inv
= self
.pred
.inv
2742 selector
.CR
= self
.pred
.state
2744 selector
.RC1
= self
.pred
.state
2747 @_dataclasses.dataclass(eq
=True, frozen
=True)
2748 class SpecifierMask(SpecifierPredicate
):
2750 def match(cls
, desc
, record
, mode
):
2751 return super().match(desc
=desc
, record
=record
,
2752 mode_match
=lambda mode_arg
: mode_arg
== mode
,
2753 pred_match
=lambda pred_arg
: pred_arg
.mode
in (
2758 def assemble(self
, insn
):
2759 raise NotImplementedError()
2762 @_dataclasses.dataclass(eq
=True, frozen
=True)
2763 class SpecifierM(SpecifierMask
):
2765 def match(cls
, desc
, record
):
2766 return super().match(desc
=desc
, record
=record
, mode
="m")
2768 def validate(self
, others
):
2770 if isinstance(spec
, SpecifierSM
):
2771 raise ValueError("source-mask and predicate mask conflict")
2772 elif isinstance(spec
, SpecifierDM
):
2773 raise ValueError("dest-mask and predicate mask conflict")
2775 def assemble(self
, insn
):
2776 selector
= insn
.select(record
=self
.record
)
2777 selector
.mask
= int(self
.pred
)
2778 if ((self
.record
.ptype
is _SVPType
.P2
) and
2779 (self
.record
.svp64
.mode
is not _SVMode
.BRANCH
)):
2780 selector
.smask
= int(self
.pred
)
2781 # LDST_IDX smask moving to extra322 but not straight away (False)
2782 if False and self
.record
.svp64
.mode
is _SVMode
.LDST_IDX
:
2783 selector
.smask_extra332
= int(self
.pred
)
2785 selector
.smask
= int(self
.pred
)
2787 selector
.mmode
= (self
.pred
.mode
is _SVP64PredMode
.CR
)
2790 @_dataclasses.dataclass(eq
=True, frozen
=True)
2791 class SpecifierSM(SpecifierMask
):
2793 def match(cls
, desc
, record
):
2794 return super().match(desc
=desc
, record
=record
, mode
="sm")
2796 def validate(self
, others
):
2797 if self
.record
.svp64
.ptype
is _SVPType
.P1
:
2798 raise ValueError("source-mask on non-twin predicate")
2800 if self
.pred
.mode
is _SVP64PredMode
.CR
:
2803 if isinstance(spec
, SpecifierDM
):
2807 raise ValueError("missing dest-mask in CR twin predication")
2808 if self
.pred
.mode
!= twin
.pred
.mode
:
2809 raise ValueError(f
"predicate masks mismatch: "
2810 f
"{self.pred!r} vs {twin.pred!r}")
2812 def assemble(self
, insn
):
2813 selector
= insn
.select(record
=self
.record
)
2814 # LDST_IDX smask moving to extra322 but not straight away (False)
2815 if False and self
.record
.svp64
.mode
is _SVMode
.LDST_IDX
:
2816 selector
.smask_extra332
= int(self
.pred
)
2818 selector
.smask
= int(self
.pred
)
2819 selector
.mmode
= (self
.pred
.mode
is _SVP64PredMode
.CR
)
2822 @_dataclasses.dataclass(eq
=True, frozen
=True)
2823 class SpecifierDM(SpecifierMask
):
2825 def match(cls
, desc
, record
):
2826 return super().match(desc
=desc
, record
=record
, mode
="dm")
2828 def validate(self
, others
):
2829 if self
.record
.svp64
.ptype
is _SVPType
.P1
:
2830 raise ValueError("dest-mask on non-twin predicate")
2832 if self
.pred
.mode
is _SVP64PredMode
.CR
:
2835 if isinstance(spec
, SpecifierSM
):
2839 raise ValueError("missing source-mask in CR twin predication")
2840 if self
.pred
.mode
!= twin
.pred
.mode
:
2841 raise ValueError(f
"predicate masks mismatch: "
2842 f
"{self.pred!r} vs {twin.pred!r}")
2844 def assemble(self
, insn
):
2845 selector
= insn
.select(record
=self
.record
)
2846 selector
.mask
= int(self
.pred
)
2847 selector
.mmode
= (self
.pred
.mode
is _SVP64PredMode
.CR
)
2850 @_dataclasses.dataclass(eq
=True, frozen
=True)
2851 class SpecifierZZ(Specifier
):
2853 def match(cls
, desc
, record
):
2857 return cls(record
=record
)
2859 def validate(self
, others
):
2861 # Since zz takes precedence (overrides) sz and dz,
2862 # treat them as mutually exclusive.
2863 if isinstance(spec
, (SpecifierSZ
, SpecifierDZ
)):
2864 raise ValueError("mutually exclusive predicate masks")
2866 def assemble(self
, insn
):
2867 selector
= insn
.select(record
=self
.record
)
2868 if hasattr(selector
, "zz"): # this should be done in a different way
2875 @_dataclasses.dataclass(eq
=True, frozen
=True)
2876 class SpecifierXZ(Specifier
):
2878 hint
: str = _dataclasses
.field(repr=False)
2881 def match(cls
, desc
, record
, etalon
, hint
):
2885 return cls(desc
=desc
, record
=record
, hint
=hint
)
2887 def validate(self
, others
):
2888 if self
.record
.svp64
.ptype
is _SVPType
.P1
:
2889 raise ValueError(f
"{self.hint} on non-twin predicate")
2891 if self
.pred
.mode
is _SVP64PredMode
.CR
:
2894 if isinstance(spec
, SpecifierXZ
):
2898 raise ValueError(f
"missing {self.hint} in CR twin predication")
2899 if self
.pred
!= twin
.pred
:
2900 raise ValueError(f
"predicate masks mismatch: "
2901 f
"{self.pred!r} vs {twin.pred!r}")
2903 def assemble(self
, insn
):
2904 selector
= insn
.select(record
=self
.record
)
2905 setattr(selector
, self
.desc
, 1)
2908 @_dataclasses.dataclass(eq
=True, frozen
=True)
2909 class SpecifierSZ(SpecifierXZ
):
2911 def match(cls
, desc
, record
):
2912 return super().match(desc
=desc
, record
=record
,
2913 etalon
="sz", hint
="source-mask")
2915 def validate(self
, others
):
2917 if self
.record
.svp64
.mode
is not _SVMode
.CROP
:
2918 if isinstance(spec
, SpecifierFF
):
2919 raise ValueError("source-zero not allowed in ff mode")
2922 @_dataclasses.dataclass(eq
=True, frozen
=True)
2923 class SpecifierDZ(SpecifierXZ
):
2925 def match(cls
, desc
, record
):
2926 return super().match(desc
=desc
, record
=record
,
2927 etalon
="dz", hint
="dest-mask")
2929 def validate(self
, others
):
2931 if ((self
.record
.svp64
.mode
is not _SVMode
.CROP
) and
2932 isinstance(spec
, SpecifierFF
) and
2933 (spec
.pred
.mode
is _SVP64PredMode
.RC1
)):
2934 raise ValueError(f
"dest-zero not allowed in ff mode BO")
2937 @_dataclasses.dataclass(eq
=True, frozen
=True)
2938 class SpecifierEls(Specifier
):
2940 def match(cls
, desc
, record
):
2944 if record
.svp64
.mode
not in (_SVMode
.LDST_IMM
, _SVMode
.LDST_IDX
):
2945 raise ValueError("els is only valid in ld/st modes, not "
2946 "%s" % str(self
.record
.svp64
.mode
))
2948 return cls(record
=record
)
2950 def assemble(self
, insn
):
2951 if self
.record
.svp64
.mode
is _SVMode
.LDST_IDX
: # stride mode
2952 insn
.prefix
.rm
.mode
[1] = 0
2954 selector
= insn
.select(record
=self
.record
)
2959 @_dataclasses.dataclass(eq
=True, frozen
=True)
2960 class SpecifierSEA(Specifier
):
2962 def match(cls
, desc
, record
):
2966 return cls(record
=record
)
2968 def validate(self
, others
):
2969 if self
.record
.svp64
.mode
is not _SVMode
.LDST_IDX
:
2970 raise ValueError("sea is only valid in ld/st modes, not "
2971 "%s" % str(self
.record
.svp64
.mode
))
2974 if isinstance(spec
, SpecifierFF
):
2975 raise ValueError(f
"sea cannot be used in ff mode")
2977 def assemble(self
, insn
):
2978 selector
= insn
.select(record
=self
.record
)
2979 if selector
.mode
.sel
not in (0b10, 0b00):
2980 raise ValueError("sea is only valid for normal and els modes, "
2981 "not %d" % int(selector
.mode
.sel
))
2985 @_dataclasses.dataclass(eq
=True, frozen
=True)
2986 class SpecifierSat(Specifier
):
2991 def match(cls
, desc
, record
, etalon
, sign
):
2995 if record
.svp64
.mode
not in (_SVMode
.NORMAL
, _SVMode
.LDST_IMM
,
2997 raise ValueError("only normal, ld/st imm and "
2998 "ld/st idx modes supported")
3000 return cls(record
=record
, desc
=desc
, sign
=sign
)
3002 def assemble(self
, insn
):
3003 selector
= insn
.select(record
=self
.record
)
3004 selector
.mode
[0] = 0b1
3005 selector
.mode
[1] = 0b0
3006 selector
.N
= int(self
.sign
)
3009 @_dataclasses.dataclass(eq
=True, frozen
=True)
3010 class SpecifierSatS(SpecifierSat
):
3012 def match(cls
, desc
, record
):
3013 return super().match(desc
=desc
, record
=record
,
3014 etalon
="sats", sign
=True)
3017 @_dataclasses.dataclass(eq
=True, frozen
=True)
3018 class SpecifierSatU(SpecifierSat
):
3020 def match(cls
, desc
, record
):
3021 return super().match(desc
=desc
, record
=record
,
3022 etalon
="satu", sign
=False)
3025 @_dataclasses.dataclass(eq
=True, frozen
=True)
3026 class SpecifierMapReduce(Specifier
):
3030 def match(cls
, record
, RG
):
3031 if record
.svp64
.mode
not in (_SVMode
.NORMAL
, _SVMode
.CROP
):
3032 raise ValueError("only normal and crop modes supported")
3034 return cls(record
=record
, RG
=RG
)
3036 def assemble(self
, insn
):
3037 selector
= insn
.select(record
=self
.record
)
3038 if self
.record
.svp64
.mode
not in (_SVMode
.NORMAL
, _SVMode
.CROP
):
3039 raise ValueError("only normal and crop modes supported")
3040 selector
.mode
[0] = 0
3041 selector
.mode
[1] = 0
3042 selector
.mode
[2] = 1
3043 selector
.RG
= self
.RG
3046 @_dataclasses.dataclass(eq
=True, frozen
=True)
3047 class SpecifierMR(SpecifierMapReduce
):
3049 def match(cls
, desc
, record
):
3053 return super().match(record
=record
, RG
=False)
3056 @_dataclasses.dataclass(eq
=True, frozen
=True)
3057 class SpecifierMRR(SpecifierMapReduce
):
3059 def match(cls
, desc
, record
):
3063 return super().match(record
=record
, RG
=True)
3066 @_dataclasses.dataclass(eq
=True, frozen
=True)
3067 class SpecifierBranch(Specifier
):
3069 def match(cls
, desc
, record
, etalon
):
3073 if record
.svp64
.mode
is not _SVMode
.BRANCH
:
3074 raise ValueError("only branch modes supported")
3076 return cls(record
=record
)
3079 @_dataclasses.dataclass(eq
=True, frozen
=True)
3080 class SpecifierAll(SpecifierBranch
):
3082 def match(cls
, desc
, record
):
3083 return super().match(desc
=desc
, record
=record
, etalon
="all")
3085 def assemble(self
, insn
):
3086 selector
= insn
.select(record
=self
.record
)
3090 @_dataclasses.dataclass(eq
=True, frozen
=True)
3091 class SpecifierSNZ(Specifier
):
3093 def match(cls
, desc
, record
):
3097 if record
.svp64
.mode
not in (_SVMode
.BRANCH
, _SVMode
.CROP
):
3098 raise ValueError("only branch and crop modes supported")
3100 return cls(record
=record
)
3102 def assemble(self
, insn
):
3103 selector
= insn
.select(record
=self
.record
)
3104 if self
.record
.svp64
.mode
in (_SVMode
.CROP
, _SVMode
.BRANCH
):
3106 if self
.record
.svp64
.mode
is _SVMode
.BRANCH
:
3109 raise ValueError("only branch and crop modes supported")
3112 @_dataclasses.dataclass(eq
=True, frozen
=True)
3113 class SpecifierSL(SpecifierBranch
):
3115 def match(cls
, desc
, record
):
3116 return super().match(desc
=desc
, record
=record
, etalon
="sl")
3118 def assemble(self
, insn
):
3119 selector
= insn
.select(record
=self
.record
)
3123 @_dataclasses.dataclass(eq
=True, frozen
=True)
3124 class SpecifierSLu(SpecifierBranch
):
3126 def match(cls
, desc
, record
):
3127 return super().match(desc
=desc
, record
=record
, etalon
="slu")
3129 def assemble(self
, insn
):
3130 selector
= insn
.select(record
=self
.record
)
3134 @_dataclasses.dataclass(eq
=True, frozen
=True)
3135 class SpecifierLRu(SpecifierBranch
):
3137 def match(cls
, desc
, record
):
3138 return super().match(desc
=desc
, record
=record
, etalon
="lru")
3140 def assemble(self
, insn
):
3141 selector
= insn
.select(record
=self
.record
)
3145 @_dataclasses.dataclass(eq
=True, frozen
=True)
3146 class SpecifierVSXX(SpecifierBranch
):
3151 def match(cls
, desc
, record
, etalon
, VSb
, VLi
):
3155 if record
.svp64
.mode
is not _SVMode
.BRANCH
:
3156 raise ValueError("only branch modes supported")
3158 return cls(record
=record
, VSb
=VSb
, VLi
=VLi
)
3160 def assemble(self
, insn
):
3161 selector
= insn
.select(record
=self
.record
)
3163 selector
.VSb
= int(self
.VSb
)
3164 selector
.VLi
= int(self
.VLi
)
3167 @_dataclasses.dataclass(eq
=True, frozen
=True)
3168 class SpecifierVS(SpecifierVSXX
):
3170 def match(cls
, desc
, record
):
3171 return super().match(desc
=desc
, record
=record
,
3172 etalon
="vs", VSb
=False, VLi
=False)
3175 @_dataclasses.dataclass(eq
=True, frozen
=True)
3176 class SpecifierVSi(SpecifierVSXX
):
3178 def match(cls
, desc
, record
):
3179 return super().match(desc
=desc
, record
=record
,
3180 etalon
="vsi", VSb
=False, VLi
=True)
3183 @_dataclasses.dataclass(eq
=True, frozen
=True)
3184 class SpecifierVSb(SpecifierVSXX
):
3186 def match(cls
, desc
, record
):
3187 return super().match(desc
=desc
, record
=record
,
3188 etalon
="vsb", VSb
=True, VLi
=False)
3191 @_dataclasses.dataclass(eq
=True, frozen
=True)
3192 class SpecifierVSbi(SpecifierVSXX
):
3194 def match(cls
, desc
, record
):
3195 return super().match(desc
=desc
, record
=record
,
3196 etalon
="vsbi", VSb
=True, VLi
=True)
3199 @_dataclasses.dataclass(eq
=True, frozen
=True)
3200 class SpecifierCTX(Specifier
):
3204 def match(cls
, desc
, record
, etalon
, CTi
):
3208 if record
.svp64
.mode
is not _SVMode
.BRANCH
:
3209 raise ValueError("only branch modes supported")
3211 return cls(record
=record
, CTi
=CTi
)
3213 def assemble(self
, insn
):
3214 selector
= insn
.select(record
=self
.record
)
3216 selector
.CTi
= int(self
.CTi
)
3219 @_dataclasses.dataclass(eq
=True, frozen
=True)
3220 class SpecifierCTR(SpecifierCTX
):
3222 def match(cls
, desc
, record
):
3223 return super().match(desc
=desc
, record
=record
,
3224 etalon
="ctr", CTi
=False)
3227 @_dataclasses.dataclass(eq
=True, frozen
=True)
3228 class SpecifierCTi(SpecifierCTX
):
3230 def match(cls
, desc
, record
):
3231 return super().match(desc
=desc
, record
=record
,
3232 etalon
="cti", CTi
=True)
3235 @_dataclasses.dataclass(eq
=True, frozen
=True)
3236 class SpecifierPI(Specifier
):
3238 def match(cls
, desc
, record
):
3242 if record
.svp64
.mode
not in [_SVMode
.LDST_IMM
, _SVMode
.LDST_IDX
]:
3243 raise ValueError("only ld/st imm/idx mode supported")
3245 return cls(record
=record
)
3247 def assemble(self
, insn
):
3248 selector
= insn
.select(record
=self
.record
)
3249 selector
.mode
[2] = 0b1
3253 @_dataclasses.dataclass(eq
=True, frozen
=True)
3254 class SpecifierLF(Specifier
):
3256 def match(cls
, desc
, record
):
3260 if record
.svp64
.mode
is not _SVMode
.LDST_IMM
:
3261 raise ValueError("only ld/st imm mode supported")
3263 return cls(record
=record
)
3265 def assemble(self
, insn
):
3266 selector
= insn
.select(record
=self
.record
)
3267 selector
.mode
[1] = 0
3271 @_dataclasses.dataclass(eq
=True, frozen
=True)
3272 class SpecifierVLi(Specifier
):
3274 def match(cls
, desc
, record
):
3278 return cls(record
=record
)
3280 def validate(self
, others
):
3282 if isinstance(spec
, SpecifierFF
):
3285 raise ValueError("VLi only allowed in failfirst")
3287 def assemble(self
, insn
):
3288 selector
= insn
.select(record
=self
.record
)
3289 selector
.mode
[1] = 1
3293 class Specifiers(tuple):
3328 def __new__(cls
, items
, record
):
3329 def transform(item
):
3330 for spec_cls
in cls
.SPECS
:
3331 spec
= spec_cls
.match(item
, record
=record
)
3332 if spec
is not None:
3334 raise ValueError(item
)
3336 # TODO: remove this hack
3337 items
= dict.fromkeys(items
)
3341 items
= tuple(items
)
3343 specs
= tuple(map(transform
, items
))
3344 for (index
, spec
) in enumerate(specs
):
3345 head
= specs
[:index
]
3346 tail
= specs
[index
+ 1:]
3347 spec
.validate(others
=(head
+ tail
))
3349 return super().__new
__(cls
, specs
)
3352 class SVP64OperandMeta(type):
3353 class SVP64NonZeroOperand(NonZeroOperand
):
3354 def assemble(self
, insn
, value
):
3355 if isinstance(value
, str):
3356 value
= int(value
, 0)
3357 if not isinstance(value
, int):
3358 raise ValueError("non-integer operand")
3360 # FIXME: this is really weird
3361 if self
.record
.name
in ("svstep", "svstep."):
3362 value
+= 1 # compensation
3364 return super().assemble(value
=value
, insn
=insn
)
3366 class SVP64XOStaticOperand(SpanStaticOperand
):
3367 def __init__(self
, record
, value
, span
):
3368 return super().__init
__(record
=record
, name
="XO",
3369 value
=value
, span
=span
)
3372 NonZeroOperand
: SVP64NonZeroOperand
,
3373 XOStaticOperand
: SVP64XOStaticOperand
,
3376 def __new__(metacls
, name
, bases
, ns
):
3378 for (index
, base_cls
) in enumerate(bases
):
3379 bases
[index
] = metacls
.__TRANSFORM
.get(base_cls
, base_cls
)
3381 bases
= tuple(bases
)
3383 return super().__new
__(metacls
, name
, bases
, ns
)
3386 class SVP64Operand(Operand
, metaclass
=SVP64OperandMeta
):
3389 return tuple(map(lambda bit
: (bit
+ 32), super().span
))
3393 def __init__(self
, insn
, record
):
3395 self
.__record
= record
3396 return super().__init
__()
3399 return self
.rm
.__doc
__
3402 return repr(self
.rm
)
3410 return self
.__record
3414 rm
= getattr(self
.insn
.prefix
.rm
, self
.record
.svp64
.mode
.name
.lower())
3416 # The idea behind these tables is that they are now literally
3417 # in identical format to insndb.csv and minor_xx.csv and can
3418 # be done precisely as that. The only thing to watch out for
3419 # is the insertion of Rc=1 as a "mask/value" bit and likewise
3420 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
3423 if self
.record
.svp64
.mode
is _SVMode
.NORMAL
:
3424 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3425 # mode Rc mask Rc member
3427 (0b000000, 0b111000, "simple"), # simple (no Rc)
3428 (0b001000, 0b111100, "mr"), # mapreduce (no Rc)
3429 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3430 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3431 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3432 (0b001100, 0b111100, "rsvd"), # reserved
3434 mode
= int(self
.insn
.prefix
.rm
.normal
.mode
)
3435 search
= ((mode
<< 1) | self
.record
.Rc
)
3437 elif self
.record
.svp64
.mode
is _SVMode
.LDST_IMM
:
3438 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3439 # mode Rc mask Rc member
3440 # ironically/coincidentally this table is identical to NORMAL
3441 # mode except reserved in place of mr
3443 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3444 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3445 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3447 search
= ((int(self
.insn
.prefix
.rm
.ldst_imm
.mode
) << 1) |
3450 elif self
.record
.svp64
.mode
is _SVMode
.LDST_IDX
:
3451 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3452 # mode Rc mask Rc member
3454 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3455 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3456 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3458 search
= ((int(self
.insn
.prefix
.rm
.ldst_idx
.mode
) << 1) |
3461 elif self
.record
.svp64
.mode
is _SVMode
.CROP
:
3462 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
3463 # mode 3b mask 3b member
3465 (0b000000, 0b111000, "simple"), # simple
3466 (0b001000, 0b111000, "mr"), # mapreduce
3467 (0b010001, 0b010001, "ff3"), # ffirst, 3-bit CR
3468 (0b010000, 0b010000, "ff5"), # ffirst, 5-bit CR
3470 search
= ((int(self
.insn
.prefix
.rm
.crop
.mode
) << 1) |
3471 int(self
.record
.svp64
.extra_CR_3bit
))
3473 elif self
.record
.svp64
.mode
is _SVMode
.BRANCH
:
3477 (0b00, 0b11, "simple"), # simple
3478 (0b01, 0b11, "vls"), # VLset
3479 (0b10, 0b11, "ctr"), # CTR mode
3480 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
3482 # slightly weird: doesn't have a 5-bit "mode" field like others
3483 search
= int(self
.insn
.prefix
.rm
.branch
.mode
.sel
)
3486 if table
is not None:
3487 for (value
, mask
, field
) in table
:
3488 if field
.startswith("rsvd"):
3490 if ((value
& mask
) == (search
& mask
)):
3491 return getattr(rm
, field
)
3495 def __getattr__(self
, key
):
3496 if key
.startswith(f
"_{self.__class__.__name__}__"):
3497 return super().__getattribute
__(key
)
3499 return getattr(self
.rm
, key
)
3501 def __setattr__(self
, key
, value
):
3502 if key
.startswith(f
"_{self.__class__.__name__}__"):
3503 return super().__setattr
__(key
, value
)
3506 if not hasattr(rm
, key
):
3507 raise AttributeError(key
)
3509 return setattr(rm
, key
, value
)
3512 class SVP64Instruction(PrefixedInstruction
):
3513 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3514 class Prefix(PrefixedInstruction
.Prefix
):
3516 rm
: RM
.remap((6, 8) + tuple(range(10, 32)))
3520 def select(self
, record
):
3521 return RMSelector(insn
=self
, record
=record
)
3526 for idx
in range(64):
3527 bit
= int(self
[idx
])
3529 return "".join(map(str, bits
))
3532 def assemble(cls
, record
, arguments
=None, specifiers
=None):
3533 insn
= super().assemble(record
=record
, arguments
=arguments
)
3535 specifiers
= Specifiers(items
=specifiers
, record
=record
)
3536 for specifier
in specifiers
:
3537 specifier
.assemble(insn
=insn
)
3539 insn
.prefix
.PO
= 0x1
3540 insn
.prefix
.id = 0x3
3544 def disassemble(self
, record
,
3546 style
=Style
.NORMAL
):
3548 if style
<= Style
.SHORT
:
3551 blob
= insn
.bytes(byteorder
=byteorder
)
3552 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
3555 blob_prefix
= blob(self
.prefix
)
3556 blob_suffix
= blob(self
.suffix
)
3558 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
3559 yield f
"{blob_suffix}.long 0x{int(self.suffix):08x}"
3562 assert record
.svp64
is not None
3564 name
= f
"sv.{record.name}"
3566 rm
= self
.select(record
=record
)
3568 # convert specifiers to /x/y/z (sorted lexicographically)
3569 specifiers
= sorted(rm
.specifiers(record
=record
))
3570 if specifiers
: # if any add one extra to get the extra "/"
3571 specifiers
= ([""] + specifiers
)
3572 specifiers
= "/".join(specifiers
)
3574 # convert operands to " ,x,y,z"
3575 operands
= tuple(map(_operator
.itemgetter(1),
3576 self
.spec_dynamic_operands(record
=record
, style
=style
)))
3577 operands
= ",".join(operands
)
3578 if len(operands
) > 0: # if any separate with a space
3579 operands
= (" " + operands
)
3581 if style
<= Style
.LEGACY
:
3582 yield f
"{blob_prefix}.long 0x{int(self.prefix):08x}"
3583 suffix
= WordInstruction
.integer(value
=int(self
.suffix
))
3584 yield from suffix
.disassemble(record
=record
,
3585 byteorder
=byteorder
, style
=style
)
3587 yield f
"{blob_prefix}{name}{specifiers}{operands}"
3589 yield f
"{blob_suffix}"
3591 if style
>= Style
.VERBOSE
:
3593 binary
= self
.binary
3594 spec
= self
.spec(record
=record
, prefix
="sv.")
3596 yield f
"{indent}spec"
3597 yield f
"{indent}{indent}{spec}"
3598 yield f
"{indent}pcode"
3599 for stmt
in record
.mdwn
.pcode
:
3600 yield f
"{indent}{indent}{stmt}"
3601 yield f
"{indent}binary"
3602 yield f
"{indent}{indent}[0:8] {binary[0:8]}"
3603 yield f
"{indent}{indent}[8:16] {binary[8:16]}"
3604 yield f
"{indent}{indent}[16:24] {binary[16:24]}"
3605 yield f
"{indent}{indent}[24:32] {binary[24:32]}"
3606 yield f
"{indent}{indent}[32:40] {binary[32:40]}"
3607 yield f
"{indent}{indent}[40:48] {binary[40:48]}"
3608 yield f
"{indent}{indent}[48:56] {binary[48:56]}"
3609 yield f
"{indent}{indent}[56:64] {binary[56:64]}"
3610 yield f
"{indent}opcodes"
3611 for opcode
in record
.opcodes
:
3612 yield f
"{indent}{indent}{opcode!r}"
3613 for operand
in self
.operands(record
=record
):
3614 yield from operand
.disassemble(insn
=self
,
3615 style
=style
, indent
=indent
)
3617 yield f
"{indent}{indent}{str(rm)}"
3618 for line
in rm
.disassemble(style
=style
):
3619 yield f
"{indent}{indent}{line}"
3623 def operands(cls
, record
):
3624 for operand
in super().operands(record
=record
):
3625 parent
= operand
.__class
__
3626 name
= f
"SVP64{parent.__name__}"
3627 bases
= (SVP64Operand
, parent
)
3628 child
= type(name
, bases
, {})
3629 yield child(**dict(operand
))
3632 def parse(stream
, factory
):
3634 return ("TODO" not in frozenset(entry
.values()))
3636 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
3637 entries
= _csv
.DictReader(lines
)
3638 entries
= filter(match
, entries
)
3639 return tuple(map(factory
, entries
))
3642 class MarkdownDatabase
:
3645 for (name
, desc
) in _ISA():
3648 (dynamic
, *static
) = desc
.regs
3649 operands
.extend(dynamic
)
3650 operands
.extend(static
)
3651 pcode
= PCode(iterable
=filter(str.strip
, desc
.pcode
))
3652 operands
= Operands(insn
=name
, operands
=operands
)
3653 db
[name
] = MarkdownRecord(pcode
=pcode
, operands
=operands
)
3655 self
.__db
= dict(sorted(db
.items()))
3657 return super().__init
__()
3660 yield from self
.__db
.items()
3662 def __contains__(self
, key
):
3663 return self
.__db
.__contains
__(key
)
3665 def __getitem__(self
, key
):
3666 return self
.__db
.__getitem
__(key
)
3669 class FieldsDatabase
:
3672 df
= _DecodeFields()
3674 for (form
, fields
) in df
.instrs
.items():
3675 if form
in {"DQE", "TX"}:
3679 db
[_Form
[form
]] = Fields(fields
)
3683 return super().__init
__()
3685 def __getitem__(self
, key
):
3686 return self
.__db
.__getitem
__(key
)
3690 def __init__(self
, root
, mdwndb
):
3691 # The code below groups the instructions by name:section.
3692 # There can be multiple names for the same instruction.
3693 # The point is to capture different opcodes for the same instruction.
3695 records
= _collections
.defaultdict(set)
3696 path
= (root
/ "insndb.csv")
3697 with
open(path
, "r", encoding
="UTF-8") as stream
:
3698 for section
in sorted(parse(stream
, Section
.CSV
)):
3699 path
= (root
/ section
.csv
)
3701 section
.Mode
.INTEGER
: IntegerOpcode
,
3702 section
.Mode
.PATTERN
: PatternOpcode
,
3704 factory
= _functools
.partial(
3705 PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
3706 with
open(path
, "r", encoding
="UTF-8") as stream
:
3707 for insn
in parse(stream
, factory
):
3708 for name
in insn
.names
:
3709 records
[name
].add(insn
)
3710 sections
[name
] = section
3712 items
= sorted(records
.items())
3714 for (name
, multirecord
) in items
:
3715 records
[name
] = PPCMultiRecord(sorted(multirecord
))
3717 def exact_match(name
):
3718 record
= records
.get(name
)
3724 if not name
.endswith("l"):
3726 alias
= exact_match(name
[:-1])
3729 record
= records
[alias
]
3730 if "lk" not in record
.flags
:
3731 raise ValueError(record
)
3735 if not name
.endswith("a"):
3737 alias
= LK_match(name
[:-1])
3740 record
= records
[alias
]
3741 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
3742 raise ValueError(record
)
3743 if "AA" not in mdwndb
[name
].operands
:
3744 raise ValueError(record
)
3748 if not name
.endswith("."):
3750 alias
= exact_match(name
[:-1])
3753 record
= records
[alias
]
3754 if record
.Rc
is _RCOE
.NONE
:
3755 raise ValueError(record
)
3759 matches
= (exact_match
, LK_match
, AA_match
, Rc_match
)
3760 for (name
, _
) in mdwndb
:
3761 if name
.startswith("sv."):
3764 for match
in matches
:
3766 if alias
is not None:
3770 section
= sections
[alias
]
3771 record
= records
[alias
]
3772 db
[name
] = (section
, record
)
3774 self
.__db
= dict(sorted(db
.items()))
3776 return super().__init
__()
3778 @_functools.lru_cache(maxsize
=512, typed
=False)
3779 def __getitem__(self
, key
):
3780 return self
.__db
.get(key
, (None, None))
3783 class SVP64Database
:
3784 def __init__(self
, root
, ppcdb
):
3786 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3787 for (prefix
, _
, names
) in _os
.walk(root
):
3788 prefix
= _pathlib
.Path(prefix
)
3789 for name
in filter(lambda name
: pattern
.match(name
), names
):
3790 path
= (prefix
/ _pathlib
.Path(name
))
3791 with
open(path
, "r", encoding
="UTF-8") as stream
:
3792 db
.update(parse(stream
, SVP64Record
.CSV
))
3793 db
= {record
.name
:record
for record
in db
}
3795 self
.__db
= dict(sorted(db
.items()))
3796 self
.__ppcdb
= ppcdb
3798 return super().__init
__()
3800 def __getitem__(self
, key
):
3801 (_
, record
) = self
.__ppcdb
[key
]
3805 for name
in record
.names
:
3806 record
= self
.__db
.get(name
, None)
3807 if record
is not None:
3813 class Records(Tuple
, datatype
=Record
):
3814 def __new__(cls
, records
):
3815 return super().__new
__(cls
, sorted(records
))
3818 class Database(Node
):
3819 def __init__(self
, root
):
3820 root
= _pathlib
.Path(root
)
3821 mdwndb
= MarkdownDatabase()
3822 fieldsdb
= FieldsDatabase()
3823 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
)
3824 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
3828 opcodes
= _collections
.defaultdict(
3829 lambda: _collections
.defaultdict(set))
3831 for (name
, mdwn
) in mdwndb
:
3832 if name
.startswith("sv."):
3834 (section
, ppc
) = ppcdb
[name
]
3837 svp64
= svp64db
[name
]
3838 fields
= fieldsdb
[ppc
.form
]
3839 record
= Record(name
=name
,
3840 section
=section
, ppc
=ppc
, svp64
=svp64
,
3841 mdwn
=mdwn
, fields
=fields
)
3843 names
[record
.name
] = record
3844 opcodes
[section
][record
.PO
].add(record
)
3846 self
.__db
= Records(db
)
3847 self
.__names
= dict(sorted(names
.items()))
3848 self
.__opcodes
= dict(sorted(opcodes
.items()))
3850 return super().__init
__()
3853 def walk(clsself
, match
=lambda _
: True):
3854 if isinstance(clsself
, type):
3855 yield ("records", Records
)
3857 if match(clsself
.__db
):
3858 yield ("records", clsself
.__db
)
3861 return repr(self
.__db
)
3864 yield from self
.__db
3866 @_functools.lru_cache(maxsize
=None)
3867 def __contains__(self
, key
):
3868 return self
.__getitem
__(key
) is not None
3870 @_functools.lru_cache(maxsize
=None)
3871 def __getitem__(self
, key
):
3872 if isinstance(key
, SVP64Instruction
):
3875 if isinstance(key
, Instruction
):
3878 sections
= sorted(self
.__opcodes
)
3879 for section
in sections
:
3880 group
= self
.__opcodes
[section
]
3881 for record
in group
[PO
]:
3882 if record
.match(key
=key
):
3887 elif isinstance(key
, str):
3888 return self
.__names
.get(key
)
3890 raise ValueError("instruction or name expected")