make truediv available to pseudocode
[openpower-isa.git] / src / openpower / decoder / power_insn.py
1 import collections as _collections
2 import csv as _csv
3 import dataclasses as _dataclasses
4 import enum as _enum
5 import functools as _functools
6 import os as _os
7 import operator as _operator
8 import pathlib as _pathlib
9 import re as _re
10 import sys as _sys
11
12 try:
13 from functools import cached_property
14 except ImportError:
15 from cached_property import cached_property
16
17 from openpower.decoder.power_enums import (
18 Function as _Function,
19 MicrOp as _MicrOp,
20 In1Sel as _In1Sel,
21 In2Sel as _In2Sel,
22 In3Sel as _In3Sel,
23 OutSel as _OutSel,
24 CRInSel as _CRInSel,
25 CRIn2Sel as _CRIn2Sel,
26 CROutSel as _CROutSel,
27 LDSTLen as _LDSTLen,
28 LDSTMode as _LDSTMode,
29 RCOE as _RCOE,
30 CryIn as _CryIn,
31 Form as _Form,
32 SVEType as _SVEType,
33 SVMaskSrc as _SVMaskSrc,
34 SVMode as _SVMode,
35 SVPType as _SVPType,
36 SVExtra as _SVExtra,
37 RegType as _RegType,
38 SVP64RMMode as _SVP64RMMode,
39 SVExtraRegType as _SVExtraRegType,
40 SVExtraReg as _SVExtraReg,
41 SVP64SubVL as _SVP64SubVL,
42 SVP64Pred as _SVP64Pred,
43 SVP64PredMode as _SVP64PredMode,
44 SVP64Width as _SVP64Width,
45 )
46 from openpower.decoder.selectable_int import (
47 SelectableInt as _SelectableInt,
48 selectconcat as _selectconcat,
49 )
50 from openpower.decoder.power_fields import (
51 Field as _Field,
52 Mapping as _Mapping,
53 DecodeFields as _DecodeFields,
54 )
55 from openpower.decoder.pseudo.pagereader import ISA as _ISA
56
57
58 @_functools.total_ordering
59 class Style(_enum.Enum):
60 LEGACY = _enum.auto()
61 SHORT = _enum.auto()
62 NORMAL = _enum.auto()
63 VERBOSE = _enum.auto()
64
65 def __lt__(self, other):
66 if not isinstance(other, self.__class__):
67 return NotImplemented
68 return (self.value < other.value)
69
70
71 @_functools.total_ordering
72 class Priority(_enum.Enum):
73 LOW = -1
74 NORMAL = 0
75 HIGH = +1
76
77 @classmethod
78 def _missing_(cls, value):
79 if isinstance(value, str):
80 value = value.upper()
81 try:
82 return cls[value]
83 except ValueError:
84 return super()._missing_(value)
85
86 def __lt__(self, other):
87 if not isinstance(other, self.__class__):
88 return NotImplemented
89
90 # NOTE: the order is inversed, LOW < NORMAL < HIGH
91 return (self.value > other.value)
92
93
94 def dataclass(cls, record, keymap=None, typemap=None):
95 if keymap is None:
96 keymap = {}
97 if typemap is None:
98 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
99
100 def transform(key_value):
101 (key, value) = key_value
102 key = keymap.get(key, key)
103 hook = typemap.get(key, lambda value: value)
104 if hook is bool and value in ("", "0"):
105 value = False
106 else:
107 value = hook(value)
108 return (key, value)
109
110 record = dict(map(transform, record.items()))
111 for key in frozenset(record.keys()):
112 if record[key] == "":
113 record.pop(key)
114
115 return cls(**record)
116
117
118 @_functools.total_ordering
119 @_dataclasses.dataclass(eq=True, frozen=True)
120 class Opcode:
121 class Integer(int):
122 def __new__(cls, value):
123 if isinstance(value, str):
124 value = int(value, 0)
125 if not isinstance(value, int):
126 raise ValueError(value)
127
128 if value.bit_length() > 64:
129 raise ValueError(value)
130
131 return super().__new__(cls, value)
132
133 def __str__(self):
134 return self.__repr__()
135
136 def __repr__(self):
137 return f"{self:0{self.bit_length()}b}"
138
139 def bit_length(self):
140 if super().bit_length() > 32:
141 return 64
142 return 32
143
144 class Value(Integer):
145 pass
146
147 class Mask(Integer):
148 pass
149
150 value: Value
151 mask: Mask
152
153 def __lt__(self, other):
154 if not isinstance(other, Opcode):
155 return NotImplemented
156 return ((self.value, self.mask) < (other.value, other.mask))
157
158 def __int__(self):
159 return (self.value & self.mask)
160
161 def __index__(self):
162 return int(self).__index__()
163
164 def __repr__(self):
165 def pattern(value, mask, bit_length):
166 for bit in range(bit_length):
167 if ((mask & (1 << (bit_length - bit - 1))) == 0):
168 yield "-"
169 elif (value & (1 << (bit_length - bit - 1))):
170 yield "1"
171 else:
172 yield "0"
173
174 return "".join(pattern(self.value, self.mask, self.value.bit_length()))
175
176 def match(self, key):
177 return ((self.value & self.mask) == (key & self.mask))
178
179
180 @_functools.total_ordering
181 @_dataclasses.dataclass(eq=True, frozen=True)
182 class IntegerOpcode(Opcode):
183 def __init__(self, value):
184 if value.startswith("0b"):
185 mask = int(("1" * len(value[2:])), 2)
186 else:
187 mask = 0b111111
188
189 value = Opcode.Value(value)
190 mask = Opcode.Mask(mask)
191
192 return super().__init__(value=value, mask=mask)
193
194
195 @_functools.total_ordering
196 @_dataclasses.dataclass(eq=True, frozen=True)
197 class PatternOpcode(Opcode):
198 def __init__(self, pattern):
199 if not isinstance(pattern, str):
200 raise ValueError(pattern)
201
202 (value, mask) = (0, 0)
203 for symbol in pattern:
204 if symbol not in {"0", "1", "-"}:
205 raise ValueError(pattern)
206 value |= (symbol == "1")
207 mask |= (symbol != "-")
208 value <<= 1
209 mask <<= 1
210 value >>= 1
211 mask >>= 1
212
213 value = Opcode.Value(value)
214 mask = Opcode.Mask(mask)
215
216 return super().__init__(value=value, mask=mask)
217
218
219 @_dataclasses.dataclass(eq=True, frozen=True)
220 class PPCRecord:
221 class FlagsMeta(type):
222 def __iter__(cls):
223 yield from (
224 "inv A",
225 "inv out",
226 "cry out",
227 "BR",
228 "sgn ext",
229 "rsrv",
230 "32b",
231 "sgn",
232 "lk",
233 "sgl pipe",
234 )
235
236 class Flags(tuple, metaclass=FlagsMeta):
237 def __new__(cls, flags=frozenset()):
238 flags = frozenset(flags)
239 diff = (flags - frozenset(cls))
240 if diff:
241 raise ValueError(flags)
242 return super().__new__(cls, sorted(flags))
243
244 opcode: Opcode
245 comment: str
246 flags: Flags = Flags()
247 comment2: str = ""
248 function: _Function = _Function.NONE
249 intop: _MicrOp = _MicrOp.OP_ILLEGAL
250 in1: _In1Sel = _In1Sel.NONE
251 in2: _In2Sel = _In2Sel.NONE
252 in3: _In3Sel = _In3Sel.NONE
253 out: _OutSel = _OutSel.NONE
254 cr_in: _CRInSel = _CRInSel.NONE
255 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
256 cr_out: _CROutSel = _CROutSel.NONE
257 cry_in: _CryIn = _CryIn.ZERO
258 ldst_len: _LDSTLen = _LDSTLen.NONE
259 upd: _LDSTMode = _LDSTMode.NONE
260 Rc: _RCOE = _RCOE.NONE
261 form: _Form = _Form.NONE
262 conditions: str = ""
263 unofficial: bool = False
264
265 __KEYMAP = {
266 "unit": "function",
267 "internal op": "intop",
268 "CR in": "cr_in",
269 "CR out": "cr_out",
270 "cry in": "cry_in",
271 "ldst len": "ldst_len",
272 "rc": "Rc",
273 "CONDITIONS": "conditions",
274 }
275
276 def __lt__(self, other):
277 if not isinstance(other, self.__class__):
278 return NotImplemented
279 lhs = (self.opcode, self.comment)
280 rhs = (other.opcode, other.comment)
281 return (lhs < rhs)
282
283 @classmethod
284 def CSV(cls, record, opcode_cls):
285 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
286 typemap["opcode"] = opcode_cls
287
288 if record["CR in"] == "BA_BB":
289 record["cr_in"] = "BA"
290 record["cr_in2"] = "BB"
291 del record["CR in"]
292
293 flags = set()
294 for flag in frozenset(PPCRecord.Flags):
295 if bool(record.pop(flag, "")):
296 flags.add(flag)
297 record["flags"] = PPCRecord.Flags(flags)
298
299 return dataclass(cls, record,
300 keymap=PPCRecord.__KEYMAP,
301 typemap=typemap)
302
303 @cached_property
304 def names(self):
305 return frozenset(self.comment.split("=")[-1].split("/"))
306
307
308 class PPCMultiRecord(tuple):
309 def __getattr__(self, attr):
310 if attr == "opcode":
311 if len(self) != 1:
312 raise AttributeError(attr)
313 return getattr(self[0], attr)
314
315
316 @_dataclasses.dataclass(eq=True, frozen=True)
317 class SVP64Record:
318 class ExtraMap(tuple):
319 class Extra(tuple):
320 @_dataclasses.dataclass(eq=True, frozen=True)
321 class Entry:
322 regtype: _SVExtraRegType = _SVExtraRegType.NONE
323 reg: _SVExtraReg = _SVExtraReg.NONE
324
325 def __repr__(self):
326 return f"{self.regtype.value}:{self.reg.name}"
327
328 def __new__(cls, value="0"):
329 if isinstance(value, str):
330 def transform(value):
331 (regtype, reg) = value.split(":")
332 regtype = _SVExtraRegType(regtype)
333 reg = _SVExtraReg(reg)
334 return cls.Entry(regtype=regtype, reg=reg)
335
336 if value == "0":
337 value = tuple()
338 else:
339 value = map(transform, value.split(";"))
340
341 return super().__new__(cls, value)
342
343 def __repr__(self):
344 return repr(list(self))
345
346 def __new__(cls, value=tuple()):
347 value = tuple(value)
348 if len(value) == 0:
349 value = (("0",) * 4)
350 return super().__new__(cls, map(cls.Extra, value))
351
352 def __repr__(self):
353 return repr({index:self[index] for index in range(0, 4)})
354
355 name: str
356 ptype: _SVPType = _SVPType.NONE
357 etype: _SVEType = _SVEType.NONE
358 msrc: _SVMaskSrc = _SVMaskSrc.NO # MASK_SRC is active
359 in1: _In1Sel = _In1Sel.NONE
360 in2: _In2Sel = _In2Sel.NONE
361 in3: _In3Sel = _In3Sel.NONE
362 out: _OutSel = _OutSel.NONE
363 out2: _OutSel = _OutSel.NONE
364 cr_in: _CRInSel = _CRInSel.NONE
365 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
366 cr_out: _CROutSel = _CROutSel.NONE
367 extra: ExtraMap = ExtraMap()
368 conditions: str = ""
369 mode: _SVMode = _SVMode.NORMAL
370
371 __KEYMAP = {
372 "insn": "name",
373 "CONDITIONS": "conditions",
374 "Ptype": "ptype",
375 "Etype": "etype",
376 "SM": "msrc",
377 "CR in": "cr_in",
378 "CR out": "cr_out",
379 }
380
381 @classmethod
382 def CSV(cls, record):
383 record["insn"] = record["insn"].split("=")[-1]
384
385 for key in frozenset({
386 "in1", "in2", "in3", "CR in",
387 "out", "out2", "CR out",
388 }):
389 value = record[key]
390 if value == "0":
391 record[key] = "NONE"
392
393 if record["CR in"] == "BA_BB":
394 record["cr_in"] = "BA"
395 record["cr_in2"] = "BB"
396 del record["CR in"]
397
398 extra = []
399 for idx in range(0, 4):
400 extra.append(record.pop(f"{idx}"))
401
402 record["extra"] = cls.ExtraMap(extra)
403
404 return dataclass(cls, record, keymap=cls.__KEYMAP)
405
406 def extra_idx(self, key):
407 extra_idx = (
408 _SVExtra.Idx0,
409 _SVExtra.Idx1,
410 _SVExtra.Idx2,
411 _SVExtra.Idx3,
412 )
413
414 if key not in frozenset({
415 "in1", "in2", "in3", "cr_in", "cr_in2",
416 "out", "out2", "cr_out",
417 }):
418 raise KeyError(key)
419
420 sel = getattr(self, key)
421 if sel is _CRInSel.BA_BB:
422 yield _SVExtra.Idx_1_2
423 return
424
425 reg = _SVExtraReg(sel)
426 if reg is _SVExtraReg.NONE:
427 return
428
429 extra_map = {
430 _SVExtraRegType.DST: {},
431 _SVExtraRegType.SRC: {},
432 }
433 for index in range(0, 4):
434 for entry in self.extra[index]:
435 extra_map[entry.regtype][entry.reg] = extra_idx[index]
436
437 for regs in extra_map.values():
438 extra = regs.get(reg, _SVExtra.NONE)
439 if extra is not _SVExtra.NONE:
440 yield extra
441
442 extra_idx_in1 = property(_functools.partial(extra_idx, key="in1"))
443 extra_idx_in2 = property(_functools.partial(extra_idx, key="in2"))
444 extra_idx_in3 = property(_functools.partial(extra_idx, key="in3"))
445 extra_idx_out = property(_functools.partial(extra_idx, key="out"))
446 extra_idx_out2 = property(_functools.partial(extra_idx, key="out2"))
447 extra_idx_cr_in = property(_functools.partial(extra_idx, key="cr_in"))
448 extra_idx_cr_in2 = property(_functools.partial(extra_idx, key="cr_in2"))
449 extra_idx_cr_out = property(_functools.partial(extra_idx, key="cr_out"))
450
451 @_functools.lru_cache(maxsize=None)
452 def extra_reg(self, key):
453 return _SVExtraReg(getattr(self, key))
454
455 extra_reg_in1 = property(_functools.partial(extra_reg, key="in1"))
456 extra_reg_in2 = property(_functools.partial(extra_reg, key="in2"))
457 extra_reg_in3 = property(_functools.partial(extra_reg, key="in3"))
458 extra_reg_out = property(_functools.partial(extra_reg, key="out"))
459 extra_reg_out2 = property(_functools.partial(extra_reg, key="out2"))
460 extra_reg_cr_in = property(_functools.partial(extra_reg, key="cr_in"))
461 extra_reg_cr_in2 = property(_functools.partial(extra_reg, key="cr_in2"))
462 extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
463
464 @cached_property
465 def extra_CR(self):
466 extra = None
467 for idx in range(0, 4):
468 for entry in self.extra[idx]:
469 if entry.regtype is _SVExtraRegType.DST:
470 if extra is not None:
471 raise ValueError(self.svp64)
472 extra = entry
473 break
474
475 if _RegType(extra.reg) not in (_RegType.CR_3BIT, _RegType.CR_5BIT):
476 raise ValueError(self.svp64)
477
478 return extra
479
480 @cached_property
481 def extra_CR_3bit(self):
482 return (_RegType(self.extra_CR.reg) is _RegType.CR_3BIT)
483
484
485 class BitSel:
486 def __init__(self, value=(0, 32)):
487 if isinstance(value, str):
488 (start, end) = map(int, value.split(":"))
489 else:
490 (start, end) = value
491 if start < 0 or end < 0 or start >= end:
492 raise ValueError(value)
493
494 self.__start = start
495 self.__end = end
496
497 return super().__init__()
498
499 def __len__(self):
500 return (self.__end - self.__start + 1)
501
502 def __repr__(self):
503 return f"[{self.__start}:{self.__end}]"
504
505 def __iter__(self):
506 yield from range(self.start, (self.end + 1))
507
508 def __reversed__(self):
509 return tuple(reversed(tuple(self)))
510
511 @property
512 def start(self):
513 return self.__start
514
515 @property
516 def end(self):
517 return self.__end
518
519
520 @_dataclasses.dataclass(eq=True, frozen=True)
521 class Section:
522 class Mode(_enum.Enum):
523 INTEGER = _enum.auto()
524 PATTERN = _enum.auto()
525
526 @classmethod
527 def _missing_(cls, value):
528 if isinstance(value, str):
529 return cls[value.upper()]
530 return super()._missing_(value)
531
532 class Suffix(int):
533 def __new__(cls, value=None):
534 if isinstance(value, str):
535 if value.upper() == "NONE":
536 value = None
537 else:
538 value = int(value, 0)
539 if value is None:
540 value = 0
541
542 return super().__new__(cls, value)
543
544 def __str__(self):
545 return repr(self)
546
547 def __repr__(self):
548 return (bin(self) if self else "None")
549
550 path: _pathlib.Path
551 bitsel: BitSel
552 suffix: Suffix
553 mode: Mode
554 opcode: IntegerOpcode = None
555 priority: Priority = Priority.NORMAL
556
557 def __lt__(self, other):
558 if not isinstance(other, self.__class__):
559 return NotImplemented
560 return (self.priority < other.priority)
561
562 @classmethod
563 def CSV(cls, record):
564 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
565 if record["opcode"] == "NONE":
566 typemap["opcode"] = lambda _: None
567
568 return dataclass(cls, record, typemap=typemap)
569
570
571 class Fields:
572 def __init__(self, items):
573 if isinstance(items, dict):
574 items = items.items()
575
576 def transform(item):
577 (name, bitrange) = item
578 return (name, tuple(bitrange.values()))
579
580 self.__mapping = dict(map(transform, items))
581
582 return super().__init__()
583
584 def __repr__(self):
585 return repr(self.__mapping)
586
587 def __iter__(self):
588 yield from self.__mapping.items()
589
590 def __contains__(self, key):
591 return self.__mapping.__contains__(key)
592
593 def __getitem__(self, key):
594 return self.__mapping.get(key, None)
595
596
597 class Operands:
598 __GPR_PAIRS = (
599 _SVExtraReg.RTp,
600 _SVExtraReg.RSp,
601 )
602 __FPR_PAIRS = (
603 _SVExtraReg.FRAp,
604 _SVExtraReg.FRBp,
605 _SVExtraReg.FRSp,
606 _SVExtraReg.FRTp,
607 )
608
609 def __init__(self, insn, operands):
610 custom_insns = {
611 "b": {"target_addr": TargetAddrOperandLI},
612 "ba": {"target_addr": TargetAddrOperandLI},
613 "bl": {"target_addr": TargetAddrOperandLI},
614 "bla": {"target_addr": TargetAddrOperandLI},
615 "bc": {"target_addr": TargetAddrOperandBD},
616 "bca": {"target_addr": TargetAddrOperandBD},
617 "bcl": {"target_addr": TargetAddrOperandBD},
618 "bcla": {"target_addr": TargetAddrOperandBD},
619 "addpcis": {"D": DOperandDX},
620 "fishmv": {"D": DOperandDX},
621 "fmvis": {"D": DOperandDX},
622 }
623 custom_fields = {
624 "SVi": NonZeroOperand,
625 "SVd": NonZeroOperand,
626 "SVxd": NonZeroOperand,
627 "SVyd": NonZeroOperand,
628 "SVzd": NonZeroOperand,
629 "BD": SignedOperand,
630 "D": SignedImmediateOperand,
631 "SI": SignedOperand,
632 "IB": SignedOperand,
633 "LI": SignedOperand,
634 "SIM": SignedOperand,
635 "SVD": SignedOperand,
636 "SVDS": SignedOperand,
637 "RSp": GPRPairOperand,
638 "RTp": GPRPairOperand,
639 "FRAp": FPRPairOperand,
640 "FRBp": FPRPairOperand,
641 "FRSp": FPRPairOperand,
642 "FRTp": FPRPairOperand,
643 }
644 custom_immediates = {
645 "DQ": EXTSOperandDQ,
646 "DS": EXTSOperandDS,
647 }
648
649 mapping = {}
650 for operand in operands:
651 cls = DynamicOperand
652
653 if "=" in operand:
654 (name, value) = operand.split("=")
655 mapping[name] = (StaticOperand, {
656 "name": name,
657 "value": int(value),
658 })
659 else:
660 name = operand
661 if name.endswith(")"):
662 name = name.replace("(", " ").replace(")", "")
663 (imm_name, _, name) = name.partition(" ")
664 else:
665 imm_name = None
666
667 if imm_name is not None:
668 imm_cls = custom_immediates.get(imm_name, ImmediateOperand)
669
670 if insn in custom_insns and name in custom_insns[insn]:
671 cls = custom_insns[insn][name]
672 elif name in custom_fields:
673 cls = custom_fields[name]
674 elif name in _SVExtraReg.__members__:
675 reg = _SVExtraReg[name]
676 if reg in self.__class__.__GPR_PAIRS:
677 cls = GPRPairOperand
678 elif reg in self.__class__.__FPR_PAIRS:
679 cls = FPRPairOperand
680 else:
681 regtype = _RegType[name]
682 if regtype is _RegType.GPR:
683 cls = GPROperand
684 elif regtype is _RegType.FPR:
685 cls = FPROperand
686 elif regtype is _RegType.CR_3BIT:
687 cls = CR3Operand
688 elif regtype is _RegType.CR_5BIT:
689 cls = CR5Operand
690
691 if imm_name is not None:
692 mapping[imm_name] = (imm_cls, {"name": imm_name})
693 mapping[name] = (cls, {"name": name})
694
695 static = []
696 dynamic = []
697 for (name, (cls, kwargs)) in mapping.items():
698 kwargs = dict(kwargs)
699 kwargs["name"] = name
700 if issubclass(cls, StaticOperand):
701 static.append((cls, kwargs))
702 elif issubclass(cls, DynamicOperand):
703 dynamic.append((cls, kwargs))
704 else:
705 raise ValueError(name)
706
707 self.__mapping = mapping
708 self.__static = tuple(static)
709 self.__dynamic = tuple(dynamic)
710
711 return super().__init__()
712
713 def __iter__(self):
714 for (_, items) in self.__mapping.items():
715 (cls, kwargs) = items
716 yield (cls, kwargs)
717
718 def __repr__(self):
719 return self.__mapping.__repr__()
720
721 def __contains__(self, key):
722 return self.__mapping.__contains__(key)
723
724 def __getitem__(self, key):
725 return self.__mapping.__getitem__(key)
726
727 @property
728 def static(self):
729 return self.__static
730
731 @property
732 def dynamic(self):
733 return self.__dynamic
734
735
736 class Arguments(tuple):
737 def __new__(cls, record, arguments, operands):
738 operands = iter(tuple(operands))
739 arguments = iter(tuple(arguments))
740
741 items = []
742 while True:
743 try:
744 operand = next(operands)
745 except StopIteration:
746 break
747
748 try:
749 argument = next(arguments)
750 except StopIteration:
751 raise ValueError("operands count mismatch")
752
753 if isinstance(operand, ImmediateOperand):
754 argument = argument.replace("(", " ").replace(")", "")
755 (imm_argument, _, argument) = argument.partition(" ")
756 try:
757 (imm_operand, operand) = (operand, next(operands))
758 except StopIteration:
759 raise ValueError("operands count mismatch")
760 items.append((imm_argument, imm_operand))
761 items.append((argument, operand))
762
763 try:
764 next(arguments)
765 except StopIteration:
766 pass
767 else:
768 raise ValueError("operands count mismatch")
769
770 return super().__new__(cls, items)
771
772
773 class PCode:
774 def __init__(self, iterable):
775 self.__pcode = tuple(iterable)
776 return super().__init__()
777
778 def __iter__(self):
779 yield from self.__pcode
780
781 def __repr__(self):
782 return self.__pcode.__repr__()
783
784
785 @_dataclasses.dataclass(eq=True, frozen=True)
786 class MarkdownRecord:
787 pcode: PCode
788 operands: Operands
789
790
791 @_functools.total_ordering
792 @_dataclasses.dataclass(eq=True, frozen=True)
793 class Record:
794 name: str
795 section: Section
796 ppc: PPCRecord
797 fields: Fields
798 mdwn: MarkdownRecord
799 svp64: SVP64Record = None
800
801 def __lt__(self, other):
802 if not isinstance(other, Record):
803 return NotImplemented
804 lhs = (min(self.opcodes), self.name)
805 rhs = (min(other.opcodes), other.name)
806 return (lhs < rhs)
807
808 @cached_property
809 def operands(self):
810 return (self.static_operands + self.dynamic_operands)
811
812 @cached_property
813 def static_operands(self):
814 operands = []
815 operands.append(POStaticOperand(record=self, value=self.PO))
816 for ppc in self.ppc:
817 operands.append(XOStaticOperand(
818 record=self,
819 value=ppc.opcode.value,
820 span=self.section.bitsel,
821 ))
822 for (cls, kwargs) in self.mdwn.operands.static:
823 operands.append(cls(record=self, **kwargs))
824 return tuple(operands)
825
826 @cached_property
827 def dynamic_operands(self):
828 operands = []
829 for (cls, kwargs) in self.mdwn.operands.dynamic:
830 operands.append(cls(record=self, **kwargs))
831 return tuple(operands)
832
833 @cached_property
834 def opcodes(self):
835 def binary(mapping):
836 return int("".join(str(int(mapping[bit])) \
837 for bit in sorted(mapping)), 2)
838
839 def PO_XO(value, mask, opcode, bits):
840 value = dict(value)
841 mask = dict(mask)
842 for (src, dst) in enumerate(reversed(bits)):
843 value[dst] = ((opcode.value & (1 << src)) != 0)
844 mask[dst] = ((opcode.mask & (1 << src)) != 0)
845 return (value, mask)
846
847 def PO(value, mask, opcode, bits):
848 return PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
849
850 def XO(value, mask, opcode, bits):
851 (value, mask) = PO_XO(value=value, mask=mask,
852 opcode=opcode, bits=bits)
853 for (op_cls, op_kwargs) in self.mdwn.operands.static:
854 operand = op_cls(record=self, **op_kwargs)
855 for (src, dst) in enumerate(reversed(operand.span)):
856 value[dst] = ((operand.value & (1 << src)) != 0)
857 mask[dst] = True
858 return (value, mask)
859
860 pairs = []
861 value = {bit:False for bit in range(32)}
862 mask = {bit:False for bit in range(32)}
863 if self.section.opcode is not None:
864 (value, mask) = PO(value=value, mask=mask,
865 opcode=self.section.opcode, bits=range(0, 6))
866 for ppc in self.ppc:
867 pairs.append(XO(value=value, mask=mask,
868 opcode=ppc.opcode, bits=self.section.bitsel))
869
870 result = []
871 for (value, mask) in pairs:
872 value = Opcode.Value(binary(value))
873 mask = Opcode.Mask(binary(mask))
874 result.append(Opcode(value=value, mask=mask))
875
876 return tuple(result)
877
878 @cached_property
879 def PO(self):
880 opcode = self.section.opcode
881 if opcode is None:
882 opcode = self.ppc[0].opcode
883 if isinstance(opcode, PatternOpcode):
884 value = int(opcode.value)
885 bits = opcode.value.bit_length()
886 return int(_SelectableInt(value=value, bits=bits)[0:6])
887
888 return int(opcode.value)
889
890 @cached_property
891 def XO(self):
892 return tuple(ppc.opcode for ppc in self.ppc)
893
894 def match(self, key):
895 for opcode in self.opcodes:
896 if opcode.match(key):
897 return True
898
899 return False
900
901 @property
902 def mode(self):
903 return self.svp64.mode
904
905 @property
906 def in1(self):
907 return self.ppc.in1
908
909 @property
910 def in2(self):
911 return self.ppc.in2
912
913 @property
914 def in3(self):
915 return self.ppc.in3
916
917 @property
918 def out(self):
919 return self.ppc.out
920
921 @property
922 def out2(self):
923 if self.svp64 is None:
924 return _OutSel.NONE
925 return self.ppc.out
926
927 @property
928 def cr_in(self):
929 return self.ppc.cr_in
930
931 @property
932 def cr_in2(self):
933 return self.ppc.cr_in2
934
935 @property
936 def cr_out(self):
937 return self.ppc.cr_out
938
939 ptype = property(lambda self: self.svp64.ptype)
940 etype = property(lambda self: self.svp64.etype)
941
942 def extra_idx(self, key):
943 return self.svp64.extra_idx(key)
944
945 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
946 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
947 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
948 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
949 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
950 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
951 extra_idx_cr_in2 = property(lambda self: self.svp64.extra_idx_cr_in2)
952 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
953
954 def __contains__(self, key):
955 return self.mdwn.operands.__contains__(key)
956
957 def __getitem__(self, key):
958 (cls, kwargs) = self.mdwn.operands.__getitem__(key)
959 return cls(record=self, **kwargs)
960
961 @cached_property
962 def Rc(self):
963 if "Rc" not in self:
964 return False
965 return self["Rc"].value
966
967
968 class Operand:
969 def __init__(self, record, name):
970 self.__record = record
971 self.__name = name
972
973 def __iter__(self):
974 yield ("record", self.record)
975 yield ("name", self.__name)
976
977 def __repr__(self):
978 return f"{self.__class__.__name__}({self.name})"
979
980 @property
981 def name(self):
982 return self.__name
983
984 @property
985 def record(self):
986 return self.__record
987
988 @cached_property
989 def span(self):
990 return self.record.fields[self.name]
991
992 def assemble(self, insn):
993 raise NotImplementedError()
994
995 def disassemble(self, insn,
996 style=Style.NORMAL, indent=""):
997 raise NotImplementedError()
998
999
1000 class DynamicOperand(Operand):
1001 def assemble(self, insn, value):
1002 span = self.span
1003 if isinstance(value, str):
1004 value = int(value, 0)
1005 if value < 0:
1006 raise ValueError("signed operands not allowed")
1007 insn[span] = value
1008
1009 def disassemble(self, insn,
1010 style=Style.NORMAL, indent=""):
1011 span = self.span
1012 value = insn[span]
1013
1014 if style >= Style.VERBOSE:
1015 span = map(str, span)
1016 yield f"{indent}{self.name}"
1017 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1018 yield f"{indent}{indent}{', '.join(span)}"
1019 else:
1020 yield str(int(value))
1021
1022
1023 class SignedOperand(DynamicOperand):
1024 def assemble(self, insn, value):
1025 if isinstance(value, str):
1026 value = int(value, 0)
1027 return super().assemble(value=value, insn=insn)
1028
1029 def assemble(self, insn, value):
1030 span = self.span
1031 if isinstance(value, str):
1032 value = int(value, 0)
1033 insn[span] = value
1034
1035 def disassemble(self, insn,
1036 style=Style.NORMAL, indent=""):
1037 span = self.span
1038 value = insn[span].to_signed_int()
1039 sign = "-" if (value < 0) else ""
1040 value = abs(value)
1041
1042 if style >= Style.VERBOSE:
1043 span = map(str, span)
1044 yield f"{indent}{self.name}"
1045 yield f"{indent}{indent}{sign}{value}"
1046 yield f"{indent}{indent}{', '.join(span)}"
1047 else:
1048 yield f"{sign}{value}"
1049
1050
1051 class StaticOperand(Operand):
1052 def __init__(self, record, name, value):
1053 self.__value = value
1054 return super().__init__(record=record, name=name)
1055
1056 def __iter__(self):
1057 yield ("value", self.__value)
1058 yield from super().__iter__()
1059
1060 def __repr__(self):
1061 return f"{self.__class__.__name__}({self.name}, value={self.value})"
1062
1063 @property
1064 def value(self):
1065 return self.__value
1066
1067 def assemble(self, insn):
1068 insn[self.span] = self.value
1069
1070 def disassemble(self, insn,
1071 style=Style.NORMAL, indent=""):
1072 span = self.span
1073 value = insn[span]
1074
1075 if style >= Style.VERBOSE:
1076 span = map(str, span)
1077 yield f"{indent}{self.name}"
1078 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1079 yield f"{indent}{indent}{', '.join(span)}"
1080 else:
1081 yield str(int(value))
1082
1083
1084 class SpanStaticOperand(StaticOperand):
1085 def __init__(self, record, name, value, span):
1086 self.__span = tuple(span)
1087 return super().__init__(record=record, name=name, value=value)
1088
1089 def __iter__(self):
1090 yield ("span", self.__span)
1091 yield from super().__iter__()
1092
1093 @property
1094 def span(self):
1095 return self.__span
1096
1097
1098 class POStaticOperand(SpanStaticOperand):
1099 def __init__(self, record, value):
1100 return super().__init__(record=record, name="PO",
1101 value=value, span=range(0, 6))
1102
1103 def __iter__(self):
1104 for (key, value) in super().__iter__():
1105 if key not in {"name", "span"}:
1106 yield (key, value)
1107
1108
1109 class XOStaticOperand(SpanStaticOperand):
1110 def __init__(self, record, value, span):
1111 bits = record.section.bitsel
1112 value = _SelectableInt(value=value, bits=len(bits))
1113 span = dict(zip(bits, range(len(bits))))
1114 span_rev = {value:key for (key, value) in span.items()}
1115
1116 # This part is tricky: we cannot use record.operands,
1117 # as this code is called by record.static_operands method.
1118 for (cls, kwargs) in record.mdwn.operands:
1119 operand = cls(record=record, **kwargs)
1120 for idx in operand.span:
1121 rev = span.pop(idx, None)
1122 if rev is not None:
1123 span_rev.pop(rev, None)
1124
1125 value = int(_selectconcat(*(value[bit] for bit in span.values())))
1126 span = tuple(span.keys())
1127
1128 return super().__init__(record=record, name="XO",
1129 value=value, span=span)
1130
1131 def __iter__(self):
1132 for (key, value) in super().__iter__():
1133 if key not in {"name"}:
1134 yield (key, value)
1135
1136
1137 class ImmediateOperand(DynamicOperand):
1138 pass
1139
1140
1141 class SignedImmediateOperand(SignedOperand, ImmediateOperand):
1142 pass
1143
1144
1145 class NonZeroOperand(DynamicOperand):
1146 def assemble(self, insn, value):
1147 if isinstance(value, str):
1148 value = int(value, 0)
1149 if not isinstance(value, int):
1150 raise ValueError("non-integer operand")
1151 if value == 0:
1152 raise ValueError("non-zero operand")
1153 value -= 1
1154 return super().assemble(value=value, insn=insn)
1155
1156 def disassemble(self, insn,
1157 style=Style.NORMAL, indent=""):
1158 span = self.span
1159 value = insn[span]
1160
1161 if style >= Style.VERBOSE:
1162 span = map(str, span)
1163 yield f"{indent}{self.name}"
1164 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1165 yield f"{indent}{indent}{', '.join(span)}"
1166 else:
1167 yield str(int(value) + 1)
1168
1169
1170 class ExtendableOperand(DynamicOperand):
1171 def sv_spec_enter(self, value, span):
1172 return (value, span)
1173
1174 def sv_spec(self, insn):
1175 vector = False
1176 span = self.span
1177 value = insn[span]
1178 span = tuple(map(str, span))
1179
1180 if isinstance(insn, SVP64Instruction):
1181 (origin_value, origin_span) = (value, span)
1182 (value, span) = self.sv_spec_enter(value=value, span=span)
1183
1184 for extra_idx in self.extra_idx:
1185 if self.record.etype is _SVEType.EXTRA3:
1186 spec = insn.prefix.rm.extra3[extra_idx]
1187 elif self.record.etype is _SVEType.EXTRA2:
1188 spec = insn.prefix.rm.extra2[extra_idx]
1189 else:
1190 raise ValueError(self.record.etype)
1191
1192 if spec != 0:
1193 vector = bool(spec[0])
1194 spec_span = spec.__class__
1195 if self.record.etype is _SVEType.EXTRA3:
1196 spec_span = tuple(map(str, spec_span[1, 2]))
1197 spec = spec[1, 2]
1198 elif self.record.etype is _SVEType.EXTRA2:
1199 spec_span = tuple(map(str, spec_span[1,]))
1200 spec = _SelectableInt(value=spec[1].value, bits=2)
1201 if vector:
1202 spec <<= 1
1203 spec_span = (spec_span + ("{0}",))
1204 else:
1205 spec_span = (("{0}",) + spec_span)
1206 else:
1207 raise ValueError(self.record.etype)
1208
1209 vector_shift = (2 + (5 - value.bits))
1210 scalar_shift = value.bits
1211 spec_shift = (5 - value.bits)
1212
1213 bits = (len(span) + len(spec_span))
1214 value = _SelectableInt(value=value.value, bits=bits)
1215 spec = _SelectableInt(value=spec.value, bits=bits)
1216 if vector:
1217 value = ((value << vector_shift) | (spec << spec_shift))
1218 span = (span + spec_span + ((spec_shift * ("{0}",))))
1219 else:
1220 value = ((spec << scalar_shift) | value)
1221 span = ((spec_shift * ("{0}",)) + spec_span + span)
1222
1223 (value, span) = self.sv_spec_leave(value=value, span=span,
1224 origin_value=origin_value, origin_span=origin_span)
1225
1226 return (vector, value, span)
1227
1228 def sv_spec_leave(self, value, span, origin_value, origin_span):
1229 return (value, span)
1230
1231 @property
1232 def extra_reg(self):
1233 return _SVExtraReg(self.name)
1234
1235 @property
1236 def extra_idx(self):
1237 pairs = {
1238 _SVExtraReg.RSp: _SVExtraReg.RS,
1239 _SVExtraReg.RTp: _SVExtraReg.RT,
1240 _SVExtraReg.FRAp: _SVExtraReg.FRA,
1241 _SVExtraReg.FRBp: _SVExtraReg.FRB,
1242 _SVExtraReg.FRSp: _SVExtraReg.FRS,
1243 _SVExtraReg.FRTp: _SVExtraReg.FRT,
1244 }
1245
1246 for key in frozenset({
1247 "in1", "in2", "in3", "cr_in", "cr_in2",
1248 "out", "out2", "cr_out",
1249 }):
1250 extra_reg = self.record.svp64.extra_reg(key=key)
1251 this_extra_reg = pairs.get(self.extra_reg, self.extra_reg)
1252 that_extra_reg = pairs.get(extra_reg, extra_reg)
1253 if this_extra_reg is that_extra_reg:
1254 yield from tuple(self.record.extra_idx(key=key))
1255
1256 def remap(self, value, vector):
1257 raise NotImplementedError()
1258
1259 def assemble(self, value, insn, prefix):
1260 vector = False
1261
1262 if isinstance(value, str):
1263 value = value.lower()
1264 if value.startswith("%"):
1265 value = value[1:]
1266 if value.startswith("*"):
1267 if not isinstance(insn, SVP64Instruction):
1268 raise ValueError(value)
1269 value = value[1:]
1270 vector = True
1271 if value.startswith(prefix):
1272 value = value[len(prefix):]
1273 value = int(value, 0)
1274
1275 if isinstance(insn, SVP64Instruction):
1276 (value, extra) = self.remap(value=value, vector=vector)
1277
1278 for extra_idx in self.extra_idx:
1279 if self.record.etype is _SVEType.EXTRA3:
1280 insn.prefix.rm.extra3[extra_idx] = extra
1281 elif self.record.etype is _SVEType.EXTRA2:
1282 insn.prefix.rm.extra2[extra_idx] = extra
1283 else:
1284 raise ValueError(self.record.etype)
1285
1286 return super().assemble(value=value, insn=insn)
1287
1288 def disassemble(self, insn,
1289 style=Style.NORMAL, prefix="", indent=""):
1290 (vector, value, span) = self.sv_spec(insn=insn)
1291
1292 if style >= Style.VERBOSE:
1293 mode = "vector" if vector else "scalar"
1294 yield f"{indent}{self.name} ({mode})"
1295 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1296 yield f"{indent}{indent}{', '.join(span)}"
1297 if isinstance(insn, SVP64Instruction):
1298 extra_idx = self.extra_idx
1299 if self.record.etype is _SVEType.NONE:
1300 yield f"{indent}{indent}extra[none]"
1301 else:
1302 etype = repr(self.record.etype).lower()
1303 yield f"{indent}{indent}{etype}{extra_idx!r}"
1304 else:
1305 vector = "*" if vector else ""
1306 yield f"{vector}{prefix}{int(value)}"
1307
1308
1309 class SimpleRegisterOperand(ExtendableOperand):
1310 def remap(self, value, vector):
1311 if vector:
1312 extra = (value & 0b11)
1313 value = (value >> 2)
1314 else:
1315 extra = (value >> 5)
1316 value = (value & 0b11111)
1317
1318 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1319 # (and shrink to a single bit if ok)
1320 if self.record.etype is _SVEType.EXTRA2:
1321 if vector:
1322 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1323 assert (extra & 0b01) == 0, \
1324 ("vector field %s cannot fit into EXTRA2" % value)
1325 extra = (0b10 | (extra >> 1))
1326 else:
1327 # range is r0-r63 in increments of 1
1328 assert (extra >> 1) == 0, \
1329 ("scalar GPR %d cannot fit into EXTRA2" % value)
1330 extra &= 0b01
1331 elif self.record.etype is _SVEType.EXTRA3:
1332 if vector:
1333 # EXTRA3 vector bit needs marking
1334 extra |= 0b100
1335 else:
1336 raise ValueError(self.record.etype)
1337
1338 return (value, extra)
1339
1340
1341 class GPROperand(SimpleRegisterOperand):
1342 def assemble(self, insn, value):
1343 return super().assemble(value=value, insn=insn, prefix="r")
1344
1345 def disassemble(self, insn,
1346 style=Style.NORMAL, indent=""):
1347 prefix = "" if (style <= Style.SHORT) else "r"
1348 yield from super().disassemble(prefix=prefix, insn=insn,
1349 style=style, indent=indent)
1350
1351
1352 class GPRPairOperand(GPROperand):
1353 pass
1354
1355
1356 class FPROperand(SimpleRegisterOperand):
1357 def assemble(self, insn, value):
1358 return super().assemble(value=value, insn=insn, prefix="f")
1359
1360 def disassemble(self, insn,
1361 style=Style.NORMAL, indent=""):
1362 prefix = "" if (style <= Style.SHORT) else "f"
1363 yield from super().disassemble(prefix=prefix, insn=insn,
1364 style=style, indent=indent)
1365
1366
1367 class FPRPairOperand(FPROperand):
1368 pass
1369
1370
1371 class ConditionRegisterFieldOperand(ExtendableOperand):
1372 def pattern(name_pattern):
1373 (name, pattern) = name_pattern
1374 return (name, _re.compile(f"^{pattern}$", _re.S))
1375
1376 CONDS = {
1377 "lt": 0,
1378 "gt": 1,
1379 "eq": 2,
1380 "so": 3,
1381 "un": 3,
1382 }
1383 CR = r"(?:CR|cr)([0-9]+)"
1384 N = r"([0-9]+)"
1385 BIT = rf"({'|'.join(CONDS.keys())})"
1386 LBIT = fr"{BIT}\s*\+\s*" # BIT+
1387 RBIT = fr"\s*\+\s*{BIT}" # +BIT
1388 CRN = fr"{CR}\s*\*\s*{N}" # CR*N
1389 NCR = fr"{N}\s*\*\s*{CR}" # N*CR
1390 XCR = fr"{CR}\.{BIT}"
1391 PATTERNS = tuple(map(pattern, (
1392 ("CR", CR),
1393 ("XCR", XCR),
1394 ("CR*N", CRN),
1395 ("N*CR", NCR),
1396 ("BIT+CR", (LBIT + CR)),
1397 ("CR+BIT", (CR + RBIT)),
1398 ("BIT+CR*N", (LBIT + CRN)),
1399 ("CR*N+BIT", (CRN + RBIT)),
1400 ("BIT+N*CR", (LBIT + NCR)),
1401 ("N*CR+BIT", (NCR + RBIT)),
1402 )))
1403
1404 def remap(self, value, vector, regtype):
1405 if regtype is _RegType.CR_5BIT:
1406 subvalue = (value & 0b11)
1407 value >>= 2
1408
1409 if vector:
1410 extra = (value & 0b1111)
1411 value >>= 4
1412 else:
1413 extra = (value >> 3)
1414 value &= 0b111
1415
1416 if self.record.etype is _SVEType.EXTRA2:
1417 if vector:
1418 assert (extra & 0b111) == 0, \
1419 "vector CR cannot fit into EXTRA2"
1420 extra = (0b10 | (extra >> 3))
1421 else:
1422 assert (extra >> 1) == 0, \
1423 "scalar CR cannot fit into EXTRA2"
1424 extra &= 0b01
1425 elif self.record.etype is _SVEType.EXTRA3:
1426 if vector:
1427 assert (extra & 0b11) == 0, \
1428 "vector CR cannot fit into EXTRA3"
1429 extra = (0b100 | (extra >> 2))
1430 else:
1431 assert (extra >> 2) == 0, \
1432 "scalar CR cannot fit into EXTRA3"
1433 extra &= 0b11
1434
1435 if regtype is _RegType.CR_5BIT:
1436 value = ((value << 2) | subvalue)
1437
1438 return (value, extra)
1439
1440 def assemble(self, insn, value):
1441 if isinstance(value, str):
1442 vector = False
1443
1444 if value.startswith("*"):
1445 if not isinstance(insn, SVP64Instruction):
1446 raise ValueError(value)
1447 value = value[1:]
1448 vector = True
1449
1450 for (name, pattern) in reversed(self.__class__.PATTERNS):
1451 match = pattern.match(value)
1452 if match is not None:
1453 keys = name.replace("+", "_").replace("*", "_").split("_")
1454 values = match.groups()
1455 match = dict(zip(keys, values))
1456 CR = int(match["CR"])
1457 if name == "XCR":
1458 N = 4
1459 else:
1460 N = int(match.get("N", "1"))
1461 BIT = self.__class__.CONDS[match.get("BIT", "lt")]
1462 value = ((CR * N) + BIT)
1463 break
1464
1465 value = str(value)
1466 if vector:
1467 value = f"*{value}"
1468
1469 return super().assemble(value=value, insn=insn, prefix="cr")
1470
1471 def disassemble(self, insn,
1472 style=Style.NORMAL, prefix="", indent=""):
1473 (vector, value, span) = self.sv_spec(insn=insn)
1474
1475 if style >= Style.VERBOSE:
1476 mode = "vector" if vector else "scalar"
1477 yield f"{indent}{self.name} ({mode})"
1478 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1479 yield f"{indent}{indent}{', '.join(span)}"
1480 if isinstance(insn, SVP64Instruction):
1481 extra_idx = self.extra_idx
1482 if self.record.etype is _SVEType.NONE:
1483 yield f"{indent}{indent}extra[none]"
1484 else:
1485 etype = repr(self.record.etype).lower()
1486 yield f"{indent}{indent}{etype}{extra_idx!r}"
1487 else:
1488 vector = "*" if vector else ""
1489 CR = int(value >> 2)
1490 CC = int(value & 3)
1491 cond = ("lt", "gt", "eq", "so")[CC]
1492 if style >= Style.NORMAL:
1493 if CR != 0:
1494 if isinstance(insn, SVP64Instruction):
1495 yield f"{vector}cr{CR}.{cond}"
1496 else:
1497 yield f"4*cr{CR}+{cond}"
1498 else:
1499 yield cond
1500 else:
1501 yield f"{vector}{prefix}{int(value)}"
1502
1503
1504 class CR3Operand(ConditionRegisterFieldOperand):
1505 def remap(self, value, vector):
1506 return super().remap(value=value, vector=vector,
1507 regtype=_RegType.CR_3BIT)
1508
1509
1510 class CR5Operand(ConditionRegisterFieldOperand):
1511 def remap(self, value, vector):
1512 return super().remap(value=value, vector=vector,
1513 regtype=_RegType.CR_5BIT)
1514
1515 def sv_spec_enter(self, value, span):
1516 value = _SelectableInt(value=(value.value >> 2), bits=3)
1517 return (value, span)
1518
1519 def sv_spec_leave(self, value, span, origin_value, origin_span):
1520 value = _selectconcat(value, origin_value[3:5])
1521 span += origin_span
1522 return (value, span)
1523
1524
1525 class EXTSOperand(SignedOperand):
1526 field: str # real name to report
1527 nz: int = 0 # number of zeros
1528 fmt: str = "d" # integer formatter
1529
1530 def __init__(self, record, name, field, nz=0, fmt="d"):
1531 self.__field = field
1532 self.__nz = nz
1533 self.__fmt = fmt
1534 return super().__init__(record=record, name=name)
1535
1536 @property
1537 def field(self):
1538 return self.__field
1539
1540 @property
1541 def nz(self):
1542 return self.__nz
1543
1544 @property
1545 def fmt(self):
1546 return self.__fmt
1547
1548 @cached_property
1549 def span(self):
1550 return self.record.fields[self.field]
1551
1552 def assemble(self, insn, value):
1553 span = self.span
1554 if isinstance(value, str):
1555 value = int(value, 0)
1556 insn[span] = (value >> self.nz)
1557
1558 def disassemble(self, insn,
1559 style=Style.NORMAL, indent=""):
1560 span = self.span
1561 value = insn[span].to_signed_int()
1562 sign = "-" if (value < 0) else ""
1563 value = (abs(value) << self.nz)
1564
1565 if style >= Style.VERBOSE:
1566 span = (tuple(map(str, span)) + (("{0}",) * self.nz))
1567 zeros = ("0" * self.nz)
1568 hint = f"{self.name} = EXTS({self.field} || {zeros})"
1569 yield f"{indent * 1}{hint}"
1570 yield f"{indent * 2}{self.field}"
1571 yield f"{indent * 3}{sign}{value:{self.fmt}}"
1572 yield f"{indent * 3}{', '.join(span)}"
1573 else:
1574 yield f"{sign}{value:{self.fmt}}"
1575
1576
1577 class TargetAddrOperand(EXTSOperand):
1578 def __init__(self, record, name, field):
1579 return super().__init__(record=record, name=name, field=field,
1580 nz=2, fmt="#x")
1581
1582
1583 class TargetAddrOperandLI(TargetAddrOperand):
1584 def __init__(self, record, name):
1585 return super().__init__(record=record, name=name, field="LI")
1586
1587
1588 class TargetAddrOperandBD(TargetAddrOperand):
1589 def __init__(self, record, name):
1590 return super().__init__(record=record, name=name, field="BD")
1591
1592
1593 class EXTSOperandDS(EXTSOperand, ImmediateOperand):
1594 def __init__(self, record, name):
1595 return super().__init__(record=record, name=name, field="DS", nz=2)
1596
1597
1598 class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
1599 def __init__(self, record, name):
1600 return super().__init__(record=record, name=name, field="DQ", nz=4)
1601
1602
1603 class DOperandDX(SignedOperand):
1604 @cached_property
1605 def span(self):
1606 cls = lambda name: DynamicOperand(record=self.record, name=name)
1607 operands = map(cls, ("d0", "d1", "d2"))
1608 spans = map(lambda operand: operand.span, operands)
1609 return sum(spans, tuple())
1610
1611 def disassemble(self, insn,
1612 style=Style.NORMAL, indent=""):
1613 span = self.span
1614 value = insn[span].to_signed_int()
1615 sign = "-" if (value < 0) else ""
1616 value = abs(value)
1617
1618 if style >= Style.VERBOSE:
1619 yield f"{indent}D"
1620 mapping = {
1621 "d0": "[0:9]",
1622 "d1": "[10:15]",
1623 "d2": "[16]",
1624 }
1625 for (subname, subspan) in mapping.items():
1626 operand = DynamicOperand(name=subname)
1627 span = operand.span
1628 span = map(str, span)
1629 yield f"{indent}{indent}{operand.name} = D{subspan}"
1630 yield f"{indent}{indent}{indent}{sign}{value}"
1631 yield f"{indent}{indent}{indent}{', '.join(span)}"
1632 else:
1633 yield f"{sign}{value}"
1634
1635
1636 class Instruction(_Mapping):
1637 @classmethod
1638 def integer(cls, value=0, bits=None, byteorder="little"):
1639 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1640 raise ValueError(bits)
1641
1642 if isinstance(value, bytes):
1643 if ((len(value) * 8) != bits):
1644 raise ValueError(f"bit length mismatch")
1645 value = int.from_bytes(value, byteorder=byteorder)
1646
1647 if isinstance(value, int):
1648 value = _SelectableInt(value=value, bits=bits)
1649 elif isinstance(value, Instruction):
1650 value = value.storage
1651
1652 if not isinstance(value, _SelectableInt):
1653 raise ValueError(value)
1654 if bits is None:
1655 bits = len(cls)
1656 if len(value) != bits:
1657 raise ValueError(value)
1658
1659 value = _SelectableInt(value=value, bits=bits)
1660
1661 return cls(storage=value)
1662
1663 def __hash__(self):
1664 return hash(int(self))
1665
1666 def __getitem__(self, key):
1667 return self.storage.__getitem__(key)
1668
1669 def __setitem__(self, key, value):
1670 return self.storage.__setitem__(key, value)
1671
1672 def bytes(self, byteorder="little"):
1673 nr_bytes = (len(self.__class__) // 8)
1674 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1675
1676 @classmethod
1677 def record(cls, db, entry):
1678 record = db[entry]
1679 if record is None:
1680 raise KeyError(entry)
1681 return record
1682
1683 @classmethod
1684 def operands(cls, record):
1685 yield from record.operands
1686
1687 @classmethod
1688 def static_operands(cls, record):
1689 return filter(lambda operand: isinstance(operand, StaticOperand),
1690 cls.operands(record=record))
1691
1692 @classmethod
1693 def dynamic_operands(cls, record):
1694 return filter(lambda operand: isinstance(operand, DynamicOperand),
1695 cls.operands(record=record))
1696
1697 def spec(self, record, prefix):
1698 dynamic_operands = tuple(map(_operator.itemgetter(0),
1699 self.spec_dynamic_operands(record=record)))
1700
1701 static_operands = []
1702 for (name, value) in self.spec_static_operands(record=record):
1703 static_operands.append(f"{name}={value}")
1704
1705 operands = ""
1706 if dynamic_operands:
1707 operands += " "
1708 operands += ",".join(dynamic_operands)
1709 if static_operands:
1710 operands += " "
1711 operands += " ".join(static_operands)
1712
1713 return f"{prefix}{record.name}{operands}"
1714
1715 def spec_static_operands(self, record):
1716 for operand in self.static_operands(record=record):
1717 if not isinstance(operand, (POStaticOperand, XOStaticOperand)):
1718 yield (operand.name, operand.value)
1719
1720 def spec_dynamic_operands(self, record, style=Style.NORMAL):
1721 imm = False
1722 imm_name = ""
1723 imm_value = ""
1724 for operand in self.dynamic_operands(record=record):
1725 name = operand.name
1726 value = " ".join(operand.disassemble(insn=self,
1727 style=min(style, Style.NORMAL)))
1728 if imm:
1729 name = f"{imm_name}({name})"
1730 value = f"{imm_value}({value})"
1731 imm = False
1732 if isinstance(operand, ImmediateOperand):
1733 imm_name = name
1734 imm_value = value
1735 imm = True
1736 if not imm:
1737 yield (name, value)
1738
1739 @classmethod
1740 def assemble(cls, record, arguments=None):
1741 if arguments is None:
1742 arguments = ()
1743
1744 insn = cls.integer(value=0)
1745
1746 for operand in cls.static_operands(record=record):
1747 operand.assemble(insn=insn)
1748
1749 arguments = Arguments(record=record,
1750 arguments=arguments, operands=cls.dynamic_operands(record=record))
1751 for (value, operand) in arguments:
1752 operand.assemble(insn=insn, value=value)
1753
1754 return insn
1755
1756 def disassemble(self, record,
1757 byteorder="little",
1758 style=Style.NORMAL):
1759 raise NotImplementedError()
1760
1761
1762 class WordInstruction(Instruction):
1763 _: _Field = range(0, 32)
1764 PO: _Field = range(0, 6)
1765
1766 @classmethod
1767 def integer(cls, value, byteorder="little"):
1768 return super().integer(bits=32, value=value, byteorder=byteorder)
1769
1770 @property
1771 def binary(self):
1772 bits = []
1773 for idx in range(32):
1774 bit = int(self[idx])
1775 bits.append(bit)
1776 return "".join(map(str, bits))
1777
1778 def disassemble(self, record,
1779 byteorder="little",
1780 style=Style.NORMAL):
1781 if style <= Style.SHORT:
1782 blob = ""
1783 else:
1784 blob = self.bytes(byteorder=byteorder)
1785 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1786 blob += " "
1787
1788 if record is None:
1789 yield f"{blob}.long 0x{int(self):08x}"
1790 return
1791
1792 paired = False
1793 if style is Style.LEGACY:
1794 paired = False
1795 for operand in self.dynamic_operands(record=record):
1796 if isinstance(operand, (GPRPairOperand, FPRPairOperand)):
1797 paired = True
1798
1799 if style is Style.LEGACY and (paired or record.ppc.unofficial):
1800 yield f"{blob}.long 0x{int(self):08x}"
1801 else:
1802 operands = tuple(map(_operator.itemgetter(1),
1803 self.spec_dynamic_operands(record=record, style=style)))
1804 if operands:
1805 operands = ",".join(operands)
1806 yield f"{blob}{record.name} {operands}"
1807 else:
1808 yield f"{blob}{record.name}"
1809
1810 if style >= Style.VERBOSE:
1811 indent = (" " * 4)
1812 binary = self.binary
1813 spec = self.spec(record=record, prefix="")
1814 yield f"{indent}spec"
1815 yield f"{indent}{indent}{spec}"
1816 yield f"{indent}pcode"
1817 for stmt in record.mdwn.pcode:
1818 yield f"{indent}{indent}{stmt}"
1819 yield f"{indent}binary"
1820 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1821 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1822 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1823 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1824 yield f"{indent}opcodes"
1825 for opcode in record.opcodes:
1826 yield f"{indent}{indent}{opcode!r}"
1827 for operand in self.operands(record=record):
1828 yield from operand.disassemble(insn=self,
1829 style=style, indent=indent)
1830 yield ""
1831
1832
1833 class PrefixedInstruction(Instruction):
1834 class Prefix(WordInstruction.remap(range(0, 32))):
1835 pass
1836
1837 class Suffix(WordInstruction.remap(range(32, 64))):
1838 pass
1839
1840 _: _Field = range(64)
1841 prefix: Prefix
1842 suffix: Suffix
1843 PO: Suffix.PO
1844
1845 @classmethod
1846 def integer(cls, value, byteorder="little"):
1847 return super().integer(bits=64, value=value, byteorder=byteorder)
1848
1849 @classmethod
1850 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1851 def transform(value):
1852 return WordInstruction.integer(value=value,
1853 byteorder=byteorder)[0:32]
1854
1855 (prefix, suffix) = map(transform, (prefix, suffix))
1856 value = _selectconcat(prefix, suffix)
1857
1858 return super().integer(bits=64, value=value)
1859
1860
1861 class Mode(_Mapping):
1862 _: _Field = range(0, 5)
1863 sel: _Field = (0, 1)
1864
1865
1866 class Extra(_Mapping):
1867 _: _Field = range(0, 9)
1868
1869
1870 class Extra2(Extra):
1871 idx0: _Field = range(0, 2)
1872 idx1: _Field = range(2, 4)
1873 idx2: _Field = range(4, 6)
1874 idx3: _Field = range(6, 8)
1875
1876 def __getitem__(self, key):
1877 return {
1878 0: self.idx0,
1879 1: self.idx1,
1880 2: self.idx2,
1881 3: self.idx3,
1882 _SVExtra.Idx0: self.idx0,
1883 _SVExtra.Idx1: self.idx1,
1884 _SVExtra.Idx2: self.idx2,
1885 _SVExtra.Idx3: self.idx3,
1886 }[key]
1887
1888 def __setitem__(self, key, value):
1889 self[key].assign(value)
1890
1891
1892 class Extra3(Extra):
1893 idx0: _Field = range(0, 3)
1894 idx1: _Field = range(3, 6)
1895 idx2: _Field = range(6, 9)
1896
1897 def __getitem__(self, key):
1898 return {
1899 0: self.idx0,
1900 1: self.idx1,
1901 2: self.idx2,
1902 _SVExtra.Idx0: self.idx0,
1903 _SVExtra.Idx1: self.idx1,
1904 _SVExtra.Idx2: self.idx2,
1905 }[key]
1906
1907 def __setitem__(self, key, value):
1908 self[key].assign(value)
1909
1910
1911 class BaseRM(_Mapping):
1912 _: _Field = range(24)
1913 mmode: _Field = (0,)
1914 mask: _Field = range(1, 4)
1915 elwidth: _Field = range(4, 6)
1916 ewsrc: _Field = range(6, 8)
1917 subvl: _Field = range(8, 10)
1918 mode: Mode.remap(range(19, 24))
1919 smask: _Field = range(16, 19)
1920 extra: Extra.remap(range(10, 19))
1921 extra2: Extra2.remap(range(10, 19))
1922 extra3: Extra3.remap(range(10, 19))
1923
1924 def specifiers(self, record):
1925 subvl = int(self.subvl)
1926 if subvl > 0:
1927 yield {
1928 1: "vec2",
1929 2: "vec3",
1930 3: "vec4",
1931 }[subvl]
1932
1933 def disassemble(self, style=Style.NORMAL):
1934 if style >= Style.VERBOSE:
1935 indent = (" " * 4)
1936 for (name, span) in self.traverse(path="RM"):
1937 value = self.storage[span]
1938 yield f"{name}"
1939 yield f"{indent}{int(value):0{value.bits}b}"
1940 yield f"{indent}{', '.join(map(str, span))}"
1941
1942
1943 class FFRc1BaseRM(BaseRM):
1944 def specifiers(self, record, mode):
1945 inv = _SelectableInt(value=int(self.inv), bits=1)
1946 CR = _SelectableInt(value=int(self.CR), bits=2)
1947 mask = int(_selectconcat(CR, inv))
1948 predicate = PredicateBaseRM.predicate(True, mask)
1949 yield f"{mode}={predicate}"
1950
1951 yield from super().specifiers(record=record)
1952
1953
1954 class FFRc0BaseRM(BaseRM):
1955 def specifiers(self, record, mode):
1956 if self.RC1:
1957 inv = "~" if self.inv else ""
1958 yield f"{mode}={inv}RC1"
1959
1960 yield from super().specifiers(record=record)
1961
1962
1963 class SatBaseRM(BaseRM):
1964 def specifiers(self, record):
1965 if self.N:
1966 yield "sats"
1967 else:
1968 yield "satu"
1969
1970 yield from super().specifiers(record=record)
1971
1972
1973 class ZZBaseRM(BaseRM):
1974 def specifiers(self, record):
1975 if self.zz:
1976 yield "zz"
1977
1978 yield from super().specifiers(record=record)
1979
1980
1981 class ZZCombinedBaseRM(BaseRM):
1982 def specifiers(self, record):
1983 if self.sz and self.dz:
1984 yield "zz"
1985 elif self.sz:
1986 yield "sz"
1987 elif self.dz:
1988 yield "dz"
1989
1990 yield from super().specifiers(record=record)
1991
1992
1993 class DZBaseRM(BaseRM):
1994 def specifiers(self, record):
1995 if self.dz:
1996 yield "dz"
1997
1998 yield from super().specifiers(record=record)
1999
2000
2001 class SZBaseRM(BaseRM):
2002 def specifiers(self, record):
2003 if self.sz:
2004 yield "sz"
2005
2006 yield from super().specifiers(record=record)
2007
2008
2009 class MRBaseRM(BaseRM):
2010 def specifiers(self, record):
2011 if self.RG:
2012 yield "mrr"
2013 else:
2014 yield "mr"
2015
2016 yield from super().specifiers(record=record)
2017
2018
2019 class ElsBaseRM(BaseRM):
2020 def specifiers(self, record):
2021 if self.els:
2022 yield "els"
2023
2024 yield from super().specifiers(record=record)
2025
2026
2027 class WidthBaseRM(BaseRM):
2028 @staticmethod
2029 def width(FP, width):
2030 width = {
2031 0b11: "8",
2032 0b10: "16",
2033 0b01: "32",
2034 }.get(width)
2035 if width is None:
2036 return None
2037 if FP:
2038 width = ("fp" + width)
2039 return width
2040
2041 def specifiers(self, record):
2042 # elwidths: use "w=" if same otherwise dw/sw
2043 # FIXME this should consider FP instructions
2044 FP = False
2045 dw = WidthBaseRM.width(FP, int(self.elwidth))
2046 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2047 if dw == sw and dw:
2048 yield ("w=" + dw)
2049 else:
2050 if dw:
2051 yield ("dw=" + dw)
2052 if sw:
2053 yield ("sw=" + sw)
2054
2055 yield from super().specifiers(record=record)
2056
2057
2058 class PredicateBaseRM(BaseRM):
2059 @staticmethod
2060 def predicate(CR, mask):
2061 return {
2062 # integer
2063 (False, 0b001): "1<<r3",
2064 (False, 0b010): "r3",
2065 (False, 0b011): "~r3",
2066 (False, 0b100): "r10",
2067 (False, 0b101): "~r10",
2068 (False, 0b110): "r30",
2069 (False, 0b111): "~r30",
2070 # CRs
2071 (True, 0b000): "lt",
2072 (True, 0b001): "ge",
2073 (True, 0b010): "gt",
2074 (True, 0b011): "le",
2075 (True, 0b100): "eq",
2076 (True, 0b101): "ne",
2077 (True, 0b110): "so",
2078 (True, 0b111): "ns",
2079 }.get((CR, mask))
2080
2081 def specifiers(self, record):
2082 # predication - single and twin
2083 # use "m=" if same otherwise sm/dm
2084 CR = (int(self.mmode) == 1)
2085 mask = int(self.mask)
2086 sm = dm = PredicateBaseRM.predicate(CR, mask)
2087 if record.svp64.ptype is _SVPType.P2:
2088 smask = int(self.smask)
2089 sm = PredicateBaseRM.predicate(CR, smask)
2090 if sm == dm and dm:
2091 yield ("m=" + dm)
2092 else:
2093 if sm:
2094 yield ("sm=" + sm)
2095 if dm:
2096 yield ("dm=" + dm)
2097
2098 yield from super().specifiers(record=record)
2099
2100
2101 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
2102 pass
2103
2104
2105 class SEABaseRM(BaseRM):
2106 def specifiers(self, record):
2107 if self.SEA:
2108 yield "sea"
2109
2110 yield from super().specifiers(record=record)
2111
2112
2113 class VLiBaseRM(BaseRM):
2114 def specifiers(self, record):
2115 if self.VLi:
2116 yield "vli"
2117
2118 yield from super().specifiers(record=record)
2119
2120
2121 class NormalBaseRM(PredicateWidthBaseRM):
2122 """
2123 Normal mode
2124 https://libre-soc.org/openpower/sv/normal/
2125 """
2126 pass
2127
2128
2129 class NormalSimpleRM(ZZCombinedBaseRM, NormalBaseRM):
2130 """normal: simple mode"""
2131 dz: BaseRM.mode[3]
2132 sz: BaseRM.mode[4]
2133
2134 def specifiers(self, record):
2135 yield from super().specifiers(record=record)
2136
2137
2138 class NormalMRRM(MRBaseRM, NormalBaseRM):
2139 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2140 RG: BaseRM.mode[4]
2141
2142
2143 class NormalFFRc1RM(FFRc1BaseRM, NormalBaseRM):
2144 """normal: Rc=1: ffirst CR sel"""
2145 inv: BaseRM.mode[2]
2146 CR: BaseRM.mode[3, 4]
2147
2148 def specifiers(self, record):
2149 yield from super().specifiers(record=record, mode="ff")
2150
2151
2152 class NormalFFRc0RM(FFRc0BaseRM, VLiBaseRM, NormalBaseRM):
2153 """normal: Rc=0: ffirst z/nonz"""
2154 inv: BaseRM.mode[2]
2155 VLi: BaseRM.mode[3]
2156 RC1: BaseRM.mode[4]
2157
2158 def specifiers(self, record):
2159 yield from super().specifiers(record=record, mode="ff")
2160
2161
2162 class NormalSatRM(SatBaseRM, ZZCombinedBaseRM, NormalBaseRM):
2163 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2164 N: BaseRM.mode[2]
2165 dz: BaseRM.mode[3]
2166 sz: BaseRM.mode[4]
2167
2168
2169 class NormalRM(NormalBaseRM):
2170 simple: NormalSimpleRM
2171 mr: NormalMRRM
2172 ffrc1: NormalFFRc1RM
2173 ffrc0: NormalFFRc0RM
2174 sat: NormalSatRM
2175
2176
2177 class LDSTImmBaseRM(PredicateWidthBaseRM):
2178 """
2179 LD/ST Immediate mode
2180 https://libre-soc.org/openpower/sv/ldst/
2181 """
2182 pass
2183
2184
2185 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
2186 """ld/st immediate: simple mode"""
2187 zz: BaseRM.mode[3]
2188 els: BaseRM.mode[4]
2189 dz: BaseRM.mode[3]
2190 sz: BaseRM.mode[3]
2191
2192
2193 class LDSTImmPostRM(LDSTImmBaseRM):
2194 """ld/st immediate: postinc mode (and load-fault)"""
2195 pi: BaseRM.mode[3] # Post-Increment Mode
2196 lf: BaseRM.mode[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2197
2198 def specifiers(self, record):
2199 if self.pi:
2200 yield "pi"
2201 if self.lf:
2202 yield "lf"
2203
2204
2205 class LDSTFFRc1RM(FFRc1BaseRM, LDSTImmBaseRM):
2206 """ld/st immediate&indexed: Rc=1: ffirst CR sel"""
2207 VLi: BaseRM.mode[0]
2208 inv: BaseRM.mode[2]
2209 CR: BaseRM.mode[3, 4]
2210
2211 def specifiers(self, record):
2212 yield from super().specifiers(record=record, mode="ff")
2213
2214
2215 class LDSTFFRc0RM(FFRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
2216 """ld/st immediate&indexed: Rc=0: ffirst z/nonz"""
2217 VLi: BaseRM.mode[0]
2218 inv: BaseRM.mode[2]
2219 els: BaseRM.mode[3]
2220 RC1: BaseRM.mode[4]
2221
2222 def specifiers(self, record):
2223 yield from super().specifiers(record=record, mode="ff")
2224
2225
2226 class LDSTImmSatRM(ElsBaseRM, SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
2227 """ld/st immediate: sat mode: N=0/1 u/s"""
2228 N: BaseRM.mode[2]
2229 zz: BaseRM.mode[3]
2230 els: BaseRM.mode[4]
2231 dz: BaseRM.mode[3]
2232 sz: BaseRM.mode[3]
2233
2234
2235 class LDSTImmRM(LDSTImmBaseRM):
2236 simple: LDSTImmSimpleRM
2237 post: LDSTImmPostRM
2238 ffrc1: LDSTFFRc1RM
2239 ffrc0: LDSTFFRc0RM
2240 sat: LDSTImmSatRM
2241
2242
2243 class LDSTIdxBaseRM(PredicateWidthBaseRM):
2244 """
2245 LD/ST Indexed mode
2246 https://libre-soc.org/openpower/sv/ldst/
2247 """
2248 pass
2249
2250
2251 class LDSTIdxSimpleRM(SEABaseRM, ZZCombinedBaseRM, LDSTIdxBaseRM):
2252 """ld/st index: simple mode (includes element-strided and Signed-EA)"""
2253 els: BaseRM.mode[0]
2254 SEA: BaseRM.mode[2]
2255 dz: BaseRM.mode[3]
2256 sz: BaseRM.mode[4]
2257
2258 def specifiers(self, record):
2259 if self.els:
2260 yield "els"
2261
2262 yield from super().specifiers(record=record)
2263
2264
2265 class LDSTIdxSatRM(SatBaseRM, ZZCombinedBaseRM, LDSTIdxBaseRM):
2266 """ld/st index: sat mode: N=0/1 u/s"""
2267 N: BaseRM.mode[2]
2268 dz: BaseRM.mode[3]
2269 sz: BaseRM.mode[4]
2270
2271
2272 class LDSTIdxRM(LDSTIdxBaseRM):
2273 simple: LDSTIdxSimpleRM
2274 sat: LDSTIdxSatRM
2275 ffrc1: LDSTFFRc1RM
2276 ffrc0: LDSTFFRc0RM
2277
2278
2279
2280 class CROpBaseRM(BaseRM):
2281 """
2282 CR ops mode
2283 https://libre-soc.org/openpower/sv/cr_ops/
2284 """
2285 SNZ: BaseRM[7]
2286
2287
2288 class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2289 """crop: simple mode"""
2290 RG: BaseRM[20]
2291 dz: BaseRM[22]
2292 sz: BaseRM[23]
2293
2294 def specifiers(self, record):
2295 if self.RG:
2296 yield "rg" # simple CR Mode reports /rg
2297
2298 yield from super().specifiers(record=record)
2299
2300
2301 class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2302 """crop: scalar reduce mode (mapreduce), SUBVL=1"""
2303 RG: BaseRM[20]
2304 dz: BaseRM[22]
2305 sz: BaseRM[23]
2306
2307
2308 class CROpFF3RM(FFRc0BaseRM, PredicateBaseRM, VLiBaseRM, DZBaseRM, SZBaseRM, CROpBaseRM):
2309 """crop: ffirst 3-bit mode"""
2310 RC1: BaseRM[19]
2311 VLi: BaseRM[20]
2312 inv: BaseRM[21]
2313 dz: BaseRM[22]
2314 sz: BaseRM[23]
2315
2316 def specifiers(self, record):
2317 yield from super().specifiers(record=record, mode="ff")
2318
2319
2320 # FIXME: almost everything in this class contradicts the specs.
2321 # However, this is the direct translation of the pysvp64asm code.
2322 # Please revisit this code; there is an inactive sketch below.
2323 class CROpFF5RM(FFRc1BaseRM, PredicateBaseRM, VLiBaseRM, CROpBaseRM):
2324 """cr_op: ffirst 5-bit mode"""
2325 VLi: BaseRM[20]
2326 inv: BaseRM[21]
2327 CR: BaseRM[22, 23]
2328 dz: BaseRM[22]
2329 sz: BaseRM[23]
2330
2331 def specifiers(self, record):
2332 yield from super().specifiers(record=record, mode="ff")
2333
2334
2335 class CROpRM(CROpBaseRM):
2336 simple: CROpSimpleRM
2337 mr: CROpMRRM
2338 ff3: CROpFF3RM
2339 ff5: CROpFF5RM
2340
2341
2342 # ********************
2343 # Branches mode
2344 # https://libre-soc.org/openpower/sv/branches/
2345 class BranchBaseRM(BaseRM):
2346 ALL: BaseRM[4]
2347 SNZ: BaseRM[5]
2348 SL: BaseRM[17]
2349 SLu: BaseRM[18]
2350 LRu: BaseRM[22]
2351 sz: BaseRM[23]
2352 CTR: BaseRM[19]
2353 VLS: BaseRM[20]
2354
2355 def specifiers(self, record):
2356 if self.ALL:
2357 yield "all"
2358
2359 # /sz
2360 # branch.sz=1
2361 # branch.snz=0
2362 # /snz
2363 # branch.sz=1
2364 # branch.snz=1
2365 if self.SNZ:
2366 if not self.sz:
2367 raise ValueError(self.sz)
2368 yield "snz"
2369 elif self.sz:
2370 yield "sz"
2371
2372 if self.SL:
2373 yield "sl"
2374 if self.SLu:
2375 yield "slu"
2376 if self.LRu:
2377 yield "lru"
2378
2379 # Branch modes lack source mask.
2380 # Therefore a custom code is needed.
2381 CR = (int(self.mmode) == 1)
2382 mask = int(self.mask)
2383 m = PredicateBaseRM.predicate(CR, mask)
2384 if m is not None:
2385 yield ("m=" + m)
2386
2387 yield from super().specifiers(record=record)
2388
2389
2390 class BranchSimpleRM(BranchBaseRM):
2391 """branch: simple mode"""
2392 pass
2393
2394
2395 class BranchVLSRM(BranchBaseRM):
2396 """branch: VLSET mode"""
2397 VSb: BaseRM[7]
2398 VLi: BaseRM[21]
2399
2400 def specifiers(self, record):
2401 yield {
2402 (0b0, 0b0): "vs",
2403 (0b0, 0b1): "vsi",
2404 (0b1, 0b0): "vsb",
2405 (0b1, 0b1): "vsbi",
2406 }[int(self.VSb), int(self.VLi)]
2407
2408 yield from super().specifiers(record=record)
2409
2410
2411 class BranchCTRRM(BranchBaseRM):
2412 """branch: CTR-test mode"""
2413 CTi: BaseRM[6]
2414
2415 def specifiers(self, record):
2416 if self.CTi:
2417 yield "cti"
2418 else:
2419 yield "ctr"
2420
2421 yield from super().specifiers(record=record)
2422
2423
2424 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
2425 """branch: CTR-test+VLSET mode"""
2426 pass
2427
2428
2429 class BranchRM(BranchBaseRM):
2430 simple: BranchSimpleRM
2431 vls: BranchVLSRM
2432 ctr: BranchCTRRM
2433 ctrvls: BranchCTRVLSRM
2434
2435
2436 class RM(BaseRM):
2437 normal: NormalRM
2438 ldst_imm: LDSTImmRM
2439 ldst_idx: LDSTIdxRM
2440 crop: CROpRM
2441 branch: BranchRM
2442
2443
2444 @_dataclasses.dataclass(eq=True, frozen=True)
2445 class Specifier:
2446 record: Record
2447
2448 @classmethod
2449 def match(cls, desc, record):
2450 raise NotImplementedError()
2451
2452 def validate(self, others):
2453 pass
2454
2455 def assemble(self, insn):
2456 raise NotImplementedError()
2457
2458
2459 @_dataclasses.dataclass(eq=True, frozen=True)
2460 class SpecifierWidth(Specifier):
2461 width: _SVP64Width
2462
2463 @classmethod
2464 def match(cls, desc, record, etalon):
2465 (mode, _, value) = desc.partition("=")
2466 mode = mode.strip()
2467 value = value.strip()
2468 if mode != etalon:
2469 return None
2470 width = _SVP64Width(value)
2471
2472 return cls(record=record, width=width)
2473
2474
2475 @_dataclasses.dataclass(eq=True, frozen=True)
2476 class SpecifierW(SpecifierWidth):
2477 @classmethod
2478 def match(cls, desc, record):
2479 return super().match(desc=desc, record=record, etalon="w")
2480
2481 def assemble(self, insn):
2482 selector = insn.select(record=self.record)
2483 selector.ewsrc = self.width.value
2484 selector.elwidth = self.width.value
2485
2486
2487 @_dataclasses.dataclass(eq=True, frozen=True)
2488 class SpecifierSW(SpecifierWidth):
2489 @classmethod
2490 def match(cls, desc, record):
2491 return super().match(desc=desc, record=record, etalon="sw")
2492
2493 def assemble(self, insn):
2494 selector = insn.select(record=self.record)
2495 selector.ewsrc = self.width.value
2496
2497
2498 @_dataclasses.dataclass(eq=True, frozen=True)
2499 class SpecifierDW(SpecifierWidth):
2500 @classmethod
2501 def match(cls, desc, record):
2502 return super().match(desc=desc, record=record, etalon="dw")
2503
2504 def assemble(self, insn):
2505 selector = insn.select(record=self.record)
2506 selector.elwidth = self.width.value
2507
2508
2509 @_dataclasses.dataclass(eq=True, frozen=True)
2510 class SpecifierSubVL(Specifier):
2511 value: _SVP64SubVL
2512
2513 @classmethod
2514 def match(cls, desc, record):
2515 try:
2516 value = _SVP64SubVL(desc)
2517 except ValueError:
2518 return None
2519
2520 return cls(record=record, value=value)
2521
2522 def assemble(self, insn):
2523 selector = insn.select(record=self.record)
2524 selector.subvl = int(self.value.value)
2525
2526
2527 @_dataclasses.dataclass(eq=True, frozen=True)
2528 class SpecifierPredicate(Specifier):
2529 mode: str
2530 pred: _SVP64Pred
2531
2532 @classmethod
2533 def match(cls, desc, record, mode_match, pred_match):
2534 (mode, _, pred) = desc.partition("=")
2535
2536 mode = mode.strip()
2537 if not mode_match(mode):
2538 return None
2539
2540 pred = _SVP64Pred(pred.strip())
2541 if not pred_match(pred):
2542 raise ValueError(pred)
2543
2544 return cls(record=record, mode=mode, pred=pred)
2545
2546
2547 @_dataclasses.dataclass(eq=True, frozen=True)
2548 class SpecifierFF(SpecifierPredicate):
2549 @classmethod
2550 def match(cls, desc, record):
2551 return super().match(desc=desc, record=record,
2552 mode_match=lambda mode_arg: mode_arg == "ff",
2553 pred_match=lambda pred_arg: pred_arg.mode in (
2554 _SVP64PredMode.CR,
2555 _SVP64PredMode.RC1,
2556 ))
2557
2558 def assemble(self, insn):
2559 selector = insn.select(record=self.record)
2560 if selector.mode.sel != 0:
2561 raise ValueError("cannot override mode")
2562 if self.record.svp64.mode is _SVMode.CROP:
2563 selector.mode.sel = 0b10
2564 # HACK: please finally provide correct logic for CRs.
2565 if self.pred in (_SVP64Pred.RC1, _SVP64Pred.RC1_N):
2566 selector.mode[2] = (self.pred is _SVP64Pred.RC1_N)
2567 else:
2568 selector.mode[2] = self.pred.inv
2569 selector.mode[3, 4] = self.pred.state
2570 else:
2571 selector.mode.sel = 0b01 if self.mode == "ff" else 0b11
2572 selector.inv = self.pred.inv
2573 if self.record.Rc:
2574 selector.CR = self.pred.state
2575 else:
2576 selector.RC1 = self.pred.state
2577
2578
2579 @_dataclasses.dataclass(eq=True, frozen=True)
2580 class SpecifierMask(SpecifierPredicate):
2581 @classmethod
2582 def match(cls, desc, record, mode):
2583 return super().match(desc=desc, record=record,
2584 mode_match=lambda mode_arg: mode_arg == mode,
2585 pred_match=lambda pred_arg: pred_arg.mode in (
2586 _SVP64PredMode.INT,
2587 _SVP64PredMode.CR,
2588 ))
2589
2590 def assemble(self, insn):
2591 raise NotImplementedError()
2592
2593
2594 @_dataclasses.dataclass(eq=True, frozen=True)
2595 class SpecifierM(SpecifierMask):
2596 @classmethod
2597 def match(cls, desc, record):
2598 return super().match(desc=desc, record=record, mode="m")
2599
2600 def validate(self, others):
2601 for spec in others:
2602 if isinstance(spec, SpecifierSM):
2603 raise ValueError("source-mask and predicate mask conflict")
2604 elif isinstance(spec, SpecifierDM):
2605 raise ValueError("dest-mask and predicate mask conflict")
2606
2607 def assemble(self, insn):
2608 selector = insn.select(record=self.record)
2609 selector.mask = int(self.pred)
2610 if ((self.record.ptype is _SVPType.P2) and
2611 (self.record.svp64.mode is not _SVMode.BRANCH)):
2612 selector.smask = int(self.pred)
2613 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2614
2615
2616 @_dataclasses.dataclass(eq=True, frozen=True)
2617 class SpecifierSM(SpecifierMask):
2618 @classmethod
2619 def match(cls, desc, record):
2620 return super().match(desc=desc, record=record, mode="sm")
2621
2622 def validate(self, others):
2623 if self.record.svp64.ptype is _SVPType.P1:
2624 raise ValueError("source-mask on non-twin predicate")
2625
2626 if self.pred.mode is _SVP64PredMode.CR:
2627 twin = None
2628 for spec in others:
2629 if isinstance(spec, SpecifierDM):
2630 twin = spec
2631
2632 if twin is None:
2633 raise ValueError("missing dest-mask in CR twin predication")
2634 if self.pred.mode != twin.pred.mode:
2635 raise ValueError(f"predicate masks mismatch: "
2636 f"{self.pred!r} vs {twin.pred!r}")
2637
2638 def assemble(self, insn):
2639 selector = insn.select(record=self.record)
2640 selector.smask = int(self.pred)
2641 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2642
2643
2644 @_dataclasses.dataclass(eq=True, frozen=True)
2645 class SpecifierDM(SpecifierMask):
2646 @classmethod
2647 def match(cls, desc, record):
2648 return super().match(desc=desc, record=record, mode="dm")
2649
2650 def validate(self, others):
2651 if self.record.svp64.ptype is _SVPType.P1:
2652 raise ValueError("dest-mask on non-twin predicate")
2653
2654 if self.pred.mode is _SVP64PredMode.CR:
2655 twin = None
2656 for spec in others:
2657 if isinstance(spec, SpecifierSM):
2658 twin = spec
2659
2660 if twin is None:
2661 raise ValueError("missing source-mask in CR twin predication")
2662 if self.pred.mode != twin.pred.mode:
2663 raise ValueError(f"predicate masks mismatch: "
2664 f"{self.pred!r} vs {twin.pred!r}")
2665
2666 def assemble(self, insn):
2667 selector = insn.select(record=self.record)
2668 selector.mask = int(self.pred)
2669 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2670
2671
2672 @_dataclasses.dataclass(eq=True, frozen=True)
2673 class SpecifierZZ(Specifier):
2674 @classmethod
2675 def match(cls, desc, record):
2676 if desc != "zz":
2677 return None
2678
2679 return cls(record=record)
2680
2681 def validate(self, others):
2682 for spec in others:
2683 # Since zz takes precedence (overrides) sz and dz,
2684 # treat them as mutually exclusive.
2685 if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
2686 raise ValueError("mutually exclusive predicate masks")
2687
2688 def assemble(self, insn):
2689 selector = insn.select(record=self.record)
2690 if hasattr(selector, "zz"): # this should be done in a different way
2691 selector.zz = 1
2692 else:
2693 selector.sz = 1
2694 selector.dz = 1
2695
2696
2697 @_dataclasses.dataclass(eq=True, frozen=True)
2698 class SpecifierXZ(Specifier):
2699 desc: str
2700 hint: str = _dataclasses.field(repr=False)
2701
2702 @classmethod
2703 def match(cls, desc, record, etalon, hint):
2704 if desc != etalon:
2705 return None
2706
2707 return cls(desc=desc, record=record, hint=hint)
2708
2709 def validate(self, others):
2710 if self.record.svp64.ptype is _SVPType.P1:
2711 raise ValueError(f"{self.hint} on non-twin predicate")
2712
2713 if self.pred.mode is _SVP64PredMode.CR:
2714 twin = None
2715 for spec in others:
2716 if isinstance(spec, SpecifierXZ):
2717 twin = spec
2718
2719 if twin is None:
2720 raise ValueError(f"missing {self.hint} in CR twin predication")
2721 if self.pred != twin.pred:
2722 raise ValueError(f"predicate masks mismatch: "
2723 f"{self.pred!r} vs {twin.pred!r}")
2724
2725 def assemble(self, insn):
2726 selector = insn.select(record=self.record)
2727 setattr(selector, self.desc, 1)
2728
2729
2730 @_dataclasses.dataclass(eq=True, frozen=True)
2731 class SpecifierSZ(SpecifierXZ):
2732 @classmethod
2733 def match(cls, desc, record):
2734 return super().match(desc=desc, record=record,
2735 etalon="sz", hint="source-mask")
2736
2737 def validate(self, others):
2738 for spec in others:
2739 if self.record.svp64.mode is not _SVMode.CROP:
2740 if isinstance(spec, SpecifierFF):
2741 raise ValueError("source-zero not allowed in ff mode")
2742
2743
2744 @_dataclasses.dataclass(eq=True, frozen=True)
2745 class SpecifierDZ(SpecifierXZ):
2746 @classmethod
2747 def match(cls, desc, record):
2748 return super().match(desc=desc, record=record,
2749 etalon="dz", hint="dest-mask")
2750
2751 def validate(self, others):
2752 for spec in others:
2753 if ((self.record.svp64.mode is not _SVMode.CROP) and
2754 isinstance(spec, SpecifierFF) and
2755 (spec.pred.mode is _SVP64PredMode.RC1)):
2756 raise ValueError(f"dest-zero not allowed in ff mode BO")
2757
2758
2759 @_dataclasses.dataclass(eq=True, frozen=True)
2760 class SpecifierEls(Specifier):
2761 @classmethod
2762 def match(cls, desc, record):
2763 if desc != "els":
2764 return None
2765
2766 if record.svp64.mode not in (_SVMode.LDST_IMM, _SVMode.LDST_IDX):
2767 raise ValueError("els is only valid in ld/st modes, not "
2768 "%s" % str(self.record.svp64.mode))
2769
2770 return cls(record=record)
2771
2772 def assemble(self, insn):
2773 if self.record.svp64.mode is _SVMode.LDST_IDX: # stride mode
2774 insn.prefix.rm.mode[1] = 0
2775
2776 selector = insn.select(record=self.record)
2777 selector.els = 1
2778
2779
2780
2781 @_dataclasses.dataclass(eq=True, frozen=True)
2782 class SpecifierSEA(Specifier):
2783 @classmethod
2784 def match(cls, desc, record):
2785 if desc != "sea":
2786 return None
2787
2788 return cls(record=record)
2789
2790 def validate(self, others):
2791 if self.record.svp64.mode is not _SVMode.LDST_IDX:
2792 raise ValueError("sea is only valid in ld/st modes, not "
2793 "%s" % str(self.record.svp64.mode))
2794
2795 for spec in others:
2796 if isinstance(spec, SpecifierFF):
2797 raise ValueError(f"sea cannot be used in ff mode")
2798
2799 def assemble(self, insn):
2800 selector = insn.select(record=self.record)
2801 if selector.mode.sel not in (0b10, 0b00):
2802 raise ValueError("sea is only valid for normal and els modes, "
2803 "not %d" % int(selector.mode.sel))
2804 selector.SEA = 1
2805
2806
2807 @_dataclasses.dataclass(eq=True, frozen=True)
2808 class SpecifierSat(Specifier):
2809 desc: str
2810 sign: bool
2811
2812 @classmethod
2813 def match(cls, desc, record, etalon, sign):
2814 if desc != etalon:
2815 return None
2816
2817 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.LDST_IMM,
2818 _SVMode.LDST_IDX):
2819 raise ValueError("only normal, ld/st imm and "
2820 "ld/st idx modes supported")
2821
2822 return cls(record=record, desc=desc, sign=sign)
2823
2824 def assemble(self, insn):
2825 selector = insn.select(record=self.record)
2826 selector.mode[0] = 0b1
2827 selector.mode[1] = 0b0
2828 selector.N = int(self.sign)
2829
2830
2831 @_dataclasses.dataclass(eq=True, frozen=True)
2832 class SpecifierSatS(SpecifierSat):
2833 @classmethod
2834 def match(cls, desc, record):
2835 return super().match(desc=desc, record=record,
2836 etalon="sats", sign=True)
2837
2838
2839 @_dataclasses.dataclass(eq=True, frozen=True)
2840 class SpecifierSatU(SpecifierSat):
2841 @classmethod
2842 def match(cls, desc, record):
2843 return super().match(desc=desc, record=record,
2844 etalon="satu", sign=False)
2845
2846
2847 @_dataclasses.dataclass(eq=True, frozen=True)
2848 class SpecifierMapReduce(Specifier):
2849 RG: bool
2850
2851 @classmethod
2852 def match(cls, record, RG):
2853 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2854 raise ValueError("only normal and crop modes supported")
2855
2856 return cls(record=record, RG=RG)
2857
2858 def assemble(self, insn):
2859 selector = insn.select(record=self.record)
2860 if self.record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2861 raise ValueError("only normal and crop modes supported")
2862 selector.mode[0] = 0
2863 selector.mode[1] = 0
2864 selector.mode[2] = 1
2865 selector.RG = self.RG
2866
2867
2868 @_dataclasses.dataclass(eq=True, frozen=True)
2869 class SpecifierMR(SpecifierMapReduce):
2870 @classmethod
2871 def match(cls, desc, record):
2872 if desc != "mr":
2873 return None
2874
2875 return super().match(record=record, RG=False)
2876
2877
2878 @_dataclasses.dataclass(eq=True, frozen=True)
2879 class SpecifierMRR(SpecifierMapReduce):
2880 @classmethod
2881 def match(cls, desc, record):
2882 if desc != "mrr":
2883 return None
2884
2885 return super().match(record=record, RG=True)
2886
2887
2888 @_dataclasses.dataclass(eq=True, frozen=True)
2889 class SpecifierBranch(Specifier):
2890 @classmethod
2891 def match(cls, desc, record, etalon):
2892 if desc != etalon:
2893 return None
2894
2895 if record.svp64.mode is not _SVMode.BRANCH:
2896 raise ValueError("only branch modes supported")
2897
2898 return cls(record=record)
2899
2900
2901 @_dataclasses.dataclass(eq=True, frozen=True)
2902 class SpecifierAll(SpecifierBranch):
2903 @classmethod
2904 def match(cls, desc, record):
2905 return super().match(desc=desc, record=record, etalon="all")
2906
2907 def assemble(self, insn):
2908 selector = insn.select(record=self.record)
2909 selector.ALL = 1
2910
2911
2912 @_dataclasses.dataclass(eq=True, frozen=True)
2913 class SpecifierSNZ(Specifier):
2914 @classmethod
2915 def match(cls, desc, record):
2916 if desc != "snz":
2917 return None
2918
2919 if record.svp64.mode not in (_SVMode.BRANCH, _SVMode.CROP):
2920 raise ValueError("only branch and crop modes supported")
2921
2922 return cls(record=record)
2923
2924 def assemble(self, insn):
2925 selector = insn.select(record=self.record)
2926 if self.record.svp64.mode in (_SVMode.CROP, _SVMode.BRANCH):
2927 selector.SNZ = 1
2928 if self.record.svp64.mode is _SVMode.BRANCH:
2929 selector.sz = 1
2930 else:
2931 raise ValueError("only branch and crop modes supported")
2932
2933
2934 @_dataclasses.dataclass(eq=True, frozen=True)
2935 class SpecifierSL(SpecifierBranch):
2936 @classmethod
2937 def match(cls, desc, record):
2938 return super().match(desc=desc, record=record, etalon="sl")
2939
2940 def assemble(self, insn):
2941 selector = insn.select(record=self.record)
2942 selector.SL = 1
2943
2944
2945 @_dataclasses.dataclass(eq=True, frozen=True)
2946 class SpecifierSLu(SpecifierBranch):
2947 @classmethod
2948 def match(cls, desc, record):
2949 return super().match(desc=desc, record=record, etalon="slu")
2950
2951 def assemble(self, insn):
2952 selector = insn.select(record=self.record)
2953 selector.SLu = 1
2954
2955
2956 @_dataclasses.dataclass(eq=True, frozen=True)
2957 class SpecifierLRu(SpecifierBranch):
2958 @classmethod
2959 def match(cls, desc, record):
2960 return super().match(desc=desc, record=record, etalon="lru")
2961
2962 def assemble(self, insn):
2963 selector = insn.select(record=self.record)
2964 selector.LRu = 1
2965
2966
2967 @_dataclasses.dataclass(eq=True, frozen=True)
2968 class SpecifierVSXX(SpecifierBranch):
2969 VSb: bool
2970 VLi: bool
2971
2972 @classmethod
2973 def match(cls, desc, record, etalon, VSb, VLi):
2974 if desc != etalon:
2975 return None
2976
2977 if record.svp64.mode is not _SVMode.BRANCH:
2978 raise ValueError("only branch modes supported")
2979
2980 return cls(record=record, VSb=VSb, VLi=VLi)
2981
2982 def assemble(self, insn):
2983 selector = insn.select(record=self.record)
2984 selector.VLS = 1
2985 selector.VSb = int(self.VSb)
2986 selector.VLi = int(self.VLi)
2987
2988
2989 @_dataclasses.dataclass(eq=True, frozen=True)
2990 class SpecifierVS(SpecifierVSXX):
2991 @classmethod
2992 def match(cls, desc, record):
2993 return super().match(desc=desc, record=record,
2994 etalon="vs", VSb=False, VLi=False)
2995
2996
2997 @_dataclasses.dataclass(eq=True, frozen=True)
2998 class SpecifierVSi(SpecifierVSXX):
2999 @classmethod
3000 def match(cls, desc, record):
3001 return super().match(desc=desc, record=record,
3002 etalon="vsi", VSb=False, VLi=True)
3003
3004
3005 @_dataclasses.dataclass(eq=True, frozen=True)
3006 class SpecifierVSb(SpecifierVSXX):
3007 @classmethod
3008 def match(cls, desc, record):
3009 return super().match(desc=desc, record=record,
3010 etalon="vsb", VSb=True, VLi=False)
3011
3012
3013 @_dataclasses.dataclass(eq=True, frozen=True)
3014 class SpecifierVSbi(SpecifierVSXX):
3015 @classmethod
3016 def match(cls, desc, record):
3017 return super().match(desc=desc, record=record,
3018 etalon="vsbi", VSb=True, VLi=True)
3019
3020
3021 @_dataclasses.dataclass(eq=True, frozen=True)
3022 class SpecifierCTX(Specifier):
3023 CTi: bool
3024
3025 @classmethod
3026 def match(cls, desc, record, etalon, CTi):
3027 if desc != etalon:
3028 return None
3029
3030 if record.svp64.mode is not _SVMode.BRANCH:
3031 raise ValueError("only branch modes supported")
3032
3033 return cls(record=record, CTi=CTi)
3034
3035 def assemble(self, insn):
3036 selector = insn.select(record=self.record)
3037 selector.CTR = 1
3038 selector.CTi = int(self.CTi)
3039
3040
3041 @_dataclasses.dataclass(eq=True, frozen=True)
3042 class SpecifierCTR(SpecifierCTX):
3043 @classmethod
3044 def match(cls, desc, record):
3045 return super().match(desc=desc, record=record,
3046 etalon="ctr", CTi=False)
3047
3048
3049 @_dataclasses.dataclass(eq=True, frozen=True)
3050 class SpecifierCTi(SpecifierCTX):
3051 @classmethod
3052 def match(cls, desc, record):
3053 return super().match(desc=desc, record=record,
3054 etalon="cti", CTi=True)
3055
3056
3057 @_dataclasses.dataclass(eq=True, frozen=True)
3058 class SpecifierPI(Specifier):
3059 @classmethod
3060 def match(cls, desc, record):
3061 if desc != "pi":
3062 return None
3063
3064 if record.svp64.mode is not _SVMode.LDST_IMM:
3065 raise ValueError("only ld/st imm mode supported")
3066
3067 return cls(record=record)
3068
3069 def assemble(self, insn):
3070 selector = insn.select(record=self.record)
3071 selector.mode[0] = 0b0
3072 selector.mode[1] = 0b0
3073 selector.mode[2] = 0b1
3074 selector.pi = 0b1
3075
3076
3077 @_dataclasses.dataclass(eq=True, frozen=True)
3078 class SpecifierLF(Specifier):
3079 @classmethod
3080 def match(cls, desc, record):
3081 if desc != "lf":
3082 return None
3083
3084 if record.svp64.mode is not _SVMode.LDST_IMM:
3085 raise ValueError("only ld/st imm mode supported")
3086
3087 return cls(record=record)
3088
3089 def assemble(self, insn):
3090 selector = insn.select(record=self.record)
3091 selector.mode[2] = 1
3092 selector.lf = 0b1
3093
3094
3095 @_dataclasses.dataclass(eq=True, frozen=True)
3096 class SpecifierVLi(Specifier):
3097 @classmethod
3098 def match(cls, desc, record):
3099 if desc != "vli":
3100 return None
3101
3102 return cls(record=record)
3103
3104 def validate(self, others):
3105 for spec in others:
3106 if isinstance(spec, SpecifierFF):
3107 return
3108
3109 raise ValueError("VLi only allowed in failfirst")
3110
3111 def assemble(self, insn):
3112 selector = insn.select(record=self.record)
3113 selector.VLi = 1
3114
3115
3116 class Specifiers(tuple):
3117 SPECS = (
3118 SpecifierW,
3119 SpecifierSW,
3120 SpecifierDW,
3121 SpecifierSubVL,
3122 SpecifierFF,
3123 SpecifierM,
3124 SpecifierSM,
3125 SpecifierDM,
3126 SpecifierZZ,
3127 SpecifierSZ,
3128 SpecifierDZ,
3129 SpecifierEls,
3130 SpecifierSEA,
3131 SpecifierSatS,
3132 SpecifierSatU,
3133 SpecifierMR,
3134 SpecifierMRR,
3135 SpecifierAll,
3136 SpecifierSNZ,
3137 SpecifierSL,
3138 SpecifierSLu,
3139 SpecifierLRu,
3140 SpecifierVS,
3141 SpecifierVSi,
3142 SpecifierVSb,
3143 SpecifierVSbi,
3144 SpecifierVLi,
3145 SpecifierCTR,
3146 SpecifierCTi,
3147 SpecifierPI,
3148 SpecifierLF,
3149 )
3150
3151 def __new__(cls, items, record):
3152 def transform(item):
3153 for spec_cls in cls.SPECS:
3154 spec = spec_cls.match(item, record=record)
3155 if spec is not None:
3156 return spec
3157 raise ValueError(item)
3158
3159 # TODO: remove this hack
3160 items = dict.fromkeys(items)
3161 if "vli" in items:
3162 del items["vli"]
3163 items["vli"] = None
3164 items = tuple(items)
3165
3166 specs = tuple(map(transform, items))
3167 for (index, spec) in enumerate(specs):
3168 head = specs[:index]
3169 tail = specs[index + 1:]
3170 spec.validate(others=(head + tail))
3171
3172 return super().__new__(cls, specs)
3173
3174
3175 class SVP64OperandMeta(type):
3176 class SVP64NonZeroOperand(NonZeroOperand):
3177 def assemble(self, insn, value):
3178 if isinstance(value, str):
3179 value = int(value, 0)
3180 if not isinstance(value, int):
3181 raise ValueError("non-integer operand")
3182
3183 # FIXME: this is really weird
3184 if self.record.name in ("svstep", "svstep."):
3185 value += 1 # compensation
3186
3187 return super().assemble(value=value, insn=insn)
3188
3189 class SVP64XOStaticOperand(SpanStaticOperand):
3190 def __init__(self, record, value, span):
3191 return super().__init__(record=record, name="XO", value=value, span=span)
3192
3193 __TRANSFORM = {
3194 NonZeroOperand: SVP64NonZeroOperand,
3195 XOStaticOperand: SVP64XOStaticOperand,
3196 }
3197
3198 def __new__(metacls, name, bases, ns):
3199 bases = list(bases)
3200 for (index, base_cls) in enumerate(bases):
3201 bases[index] = metacls.__TRANSFORM.get(base_cls, base_cls)
3202
3203 bases = tuple(bases)
3204
3205 return super().__new__(metacls, name, bases, ns)
3206
3207
3208 class SVP64Operand(Operand, metaclass=SVP64OperandMeta):
3209 @property
3210 def span(self):
3211 return tuple(map(lambda bit: (bit + 32), super().span))
3212
3213
3214 class RMSelector:
3215 def __init__(self, insn, record):
3216 self.__insn = insn
3217 self.__record = record
3218 return super().__init__()
3219
3220 def __str__(self):
3221 return self.rm.__doc__
3222
3223 def __repr__(self):
3224 return repr(self.rm)
3225
3226 @property
3227 def insn(self):
3228 return self.__insn
3229
3230 @property
3231 def record(self):
3232 return self.__record
3233
3234 @property
3235 def rm(self):
3236 rm = getattr(self.insn.prefix.rm, self.record.svp64.mode.name.lower())
3237
3238 # The idea behind these tables is that they are now literally
3239 # in identical format to insndb.csv and minor_xx.csv and can
3240 # be done precisely as that. The only thing to watch out for
3241 # is the insertion of Rc=1 as a "mask/value" bit and likewise
3242 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
3243 # as the LSB.
3244 table = None
3245 if self.record.svp64.mode is _SVMode.NORMAL:
3246 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3247 # mode Rc mask Rc member
3248 table = (
3249 (0b000000, 0b111000, "simple"), # simple (no Rc)
3250 (0b001000, 0b111100, "mr"), # mapreduce (no Rc)
3251 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
3252 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
3253 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3254 (0b001100, 0b111100, "rsvd"), # reserved
3255 (0b110000, 0b110000, "rsvd"), # reserved
3256 )
3257 mode = int(self.insn.prefix.rm.normal.mode)
3258 search = ((mode << 1) | self.record.Rc)
3259
3260 elif self.record.svp64.mode is _SVMode.LDST_IMM:
3261 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3262 # mode Rc mask Rc member
3263 # ironically/coincidentally this table is identical to NORMAL
3264 # mode except reserved in place of mr
3265 table = (
3266 (0b000000, 0b111000, "simple"), # simple (no Rc involved)
3267 (0b001000, 0b111000, "post"), # post (no Rc involved)
3268 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3269 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3270 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3271 )
3272 search = ((int(self.insn.prefix.rm.ldst_imm.mode) << 1) |
3273 self.record.Rc)
3274
3275 elif self.record.svp64.mode is _SVMode.LDST_IDX:
3276 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3277 # mode Rc mask Rc member
3278 table = (
3279 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3280 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3281 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3282 )
3283 search = ((int(self.insn.prefix.rm.ldst_idx.mode) << 1) |
3284 self.record.Rc)
3285
3286 elif self.record.svp64.mode is _SVMode.CROP:
3287 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
3288 # mode 3b mask 3b member
3289 table = (
3290 (0b000000, 0b111000, "simple"), # simple
3291 (0b001000, 0b111000, "mr"), # mapreduce
3292 (0b100001, 0b100001, "ff3"), # ffirst, 3-bit CR
3293 (0b100000, 0b100000, "ff5"), # ffirst, 5-bit CR
3294 )
3295 search = ((int(self.insn.prefix.rm.crop.mode) << 1) |
3296 int(self.record.svp64.extra_CR_3bit))
3297
3298 elif self.record.svp64.mode is _SVMode.BRANCH:
3299 # just mode 2-bit
3300 # mode mask member
3301 table = (
3302 (0b00, 0b11, "simple"), # simple
3303 (0b01, 0b11, "vls"), # VLset
3304 (0b10, 0b11, "ctr"), # CTR mode
3305 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
3306 )
3307 # slightly weird: doesn't have a 5-bit "mode" field like others
3308 search = int(self.insn.prefix.rm.branch.mode.sel)
3309
3310 # look up in table
3311 if table is not None:
3312 for (value, mask, field) in table:
3313 if field.startswith("rsvd"):
3314 continue
3315 if ((value & mask) == (search & mask)):
3316 return getattr(rm, field)
3317
3318 return rm
3319
3320 def __getattr__(self, key):
3321 if key.startswith(f"_{self.__class__.__name__}__"):
3322 return super().__getattribute__(key)
3323
3324 return getattr(self.rm, key)
3325
3326 def __setattr__(self, key, value):
3327 if key.startswith(f"_{self.__class__.__name__}__"):
3328 return super().__setattr__(key, value)
3329
3330 rm = self.rm
3331 if not hasattr(rm, key):
3332 raise AttributeError(key)
3333
3334 return setattr(rm, key, value)
3335
3336
3337 class SVP64Instruction(PrefixedInstruction):
3338 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3339 class Prefix(PrefixedInstruction.Prefix):
3340 id: _Field = (7, 9)
3341 rm: RM.remap((6, 8) + tuple(range(10, 32)))
3342
3343 prefix: Prefix
3344
3345 def select(self, record):
3346 return RMSelector(insn=self, record=record)
3347
3348 @property
3349 def binary(self):
3350 bits = []
3351 for idx in range(64):
3352 bit = int(self[idx])
3353 bits.append(bit)
3354 return "".join(map(str, bits))
3355
3356 @classmethod
3357 def assemble(cls, record, arguments=None, specifiers=None):
3358 insn = super().assemble(record=record, arguments=arguments)
3359
3360 specifiers = Specifiers(items=specifiers, record=record)
3361 for specifier in specifiers:
3362 specifier.assemble(insn=insn)
3363
3364 insn.prefix.PO = 0x1
3365 insn.prefix.id = 0x3
3366
3367 return insn
3368
3369 def disassemble(self, record,
3370 byteorder="little",
3371 style=Style.NORMAL):
3372 def blob(insn):
3373 if style <= Style.SHORT:
3374 return ""
3375 else:
3376 blob = insn.bytes(byteorder=byteorder)
3377 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
3378 return f"{blob} "
3379
3380 blob_prefix = blob(self.prefix)
3381 blob_suffix = blob(self.suffix)
3382 if record is None:
3383 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3384 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
3385 return
3386
3387 assert record.svp64 is not None
3388
3389 name = f"sv.{record.name}"
3390
3391 rm = self.select(record=record)
3392
3393 # convert specifiers to /x/y/z (sorted lexicographically)
3394 specifiers = sorted(rm.specifiers(record=record))
3395 if specifiers: # if any add one extra to get the extra "/"
3396 specifiers = ([""] + specifiers)
3397 specifiers = "/".join(specifiers)
3398
3399 # convert operands to " ,x,y,z"
3400 operands = tuple(map(_operator.itemgetter(1),
3401 self.spec_dynamic_operands(record=record, style=style)))
3402 operands = ",".join(operands)
3403 if len(operands) > 0: # if any separate with a space
3404 operands = (" " + operands)
3405
3406 if style <= Style.LEGACY:
3407 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3408 suffix = WordInstruction.integer(value=int(self.suffix))
3409 yield from suffix.disassemble(record=record,
3410 byteorder=byteorder, style=style)
3411 else:
3412 yield f"{blob_prefix}{name}{specifiers}{operands}"
3413 if blob_suffix:
3414 yield f"{blob_suffix}"
3415
3416 if style >= Style.VERBOSE:
3417 indent = (" " * 4)
3418 binary = self.binary
3419 spec = self.spec(record=record, prefix="sv.")
3420
3421 yield f"{indent}spec"
3422 yield f"{indent}{indent}{spec}"
3423 yield f"{indent}pcode"
3424 for stmt in record.mdwn.pcode:
3425 yield f"{indent}{indent}{stmt}"
3426 yield f"{indent}binary"
3427 yield f"{indent}{indent}[0:8] {binary[0:8]}"
3428 yield f"{indent}{indent}[8:16] {binary[8:16]}"
3429 yield f"{indent}{indent}[16:24] {binary[16:24]}"
3430 yield f"{indent}{indent}[24:32] {binary[24:32]}"
3431 yield f"{indent}{indent}[32:40] {binary[32:40]}"
3432 yield f"{indent}{indent}[40:48] {binary[40:48]}"
3433 yield f"{indent}{indent}[48:56] {binary[48:56]}"
3434 yield f"{indent}{indent}[56:64] {binary[56:64]}"
3435 yield f"{indent}opcodes"
3436 for opcode in record.opcodes:
3437 yield f"{indent}{indent}{opcode!r}"
3438 for operand in self.operands(record=record):
3439 yield from operand.disassemble(insn=self,
3440 style=style, indent=indent)
3441 yield f"{indent}RM"
3442 yield f"{indent}{indent}{str(rm)}"
3443 for line in rm.disassemble(style=style):
3444 yield f"{indent}{indent}{line}"
3445 yield ""
3446
3447 @classmethod
3448 def operands(cls, record):
3449 for operand in super().operands(record=record):
3450 parent = operand.__class__
3451 name = f"SVP64{parent.__name__}"
3452 bases = (SVP64Operand, parent)
3453 child = type(name, bases, {})
3454 yield child(**dict(operand))
3455
3456
3457 def parse(stream, factory):
3458 def match(entry):
3459 return ("TODO" not in frozenset(entry.values()))
3460
3461 lines = filter(lambda line: not line.strip().startswith("#"), stream)
3462 entries = _csv.DictReader(lines)
3463 entries = filter(match, entries)
3464 return tuple(map(factory, entries))
3465
3466
3467 class MarkdownDatabase:
3468 def __init__(self):
3469 db = {}
3470 for (name, desc) in _ISA():
3471 operands = []
3472 if desc.regs:
3473 (dynamic, *static) = desc.regs
3474 operands.extend(dynamic)
3475 operands.extend(static)
3476 pcode = PCode(iterable=desc.pcode)
3477 operands = Operands(insn=name, operands=operands)
3478 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
3479
3480 self.__db = dict(sorted(db.items()))
3481
3482 return super().__init__()
3483
3484 def __iter__(self):
3485 yield from self.__db.items()
3486
3487 def __contains__(self, key):
3488 return self.__db.__contains__(key)
3489
3490 def __getitem__(self, key):
3491 return self.__db.__getitem__(key)
3492
3493
3494 class FieldsDatabase:
3495 def __init__(self):
3496 db = {}
3497 df = _DecodeFields()
3498 df.create_specs()
3499 for (form, fields) in df.instrs.items():
3500 if form in {"DQE", "TX"}:
3501 continue
3502 if form == "all":
3503 form = "NONE"
3504 db[_Form[form]] = Fields(fields)
3505
3506 self.__db = db
3507
3508 return super().__init__()
3509
3510 def __getitem__(self, key):
3511 return self.__db.__getitem__(key)
3512
3513
3514 class PPCDatabase:
3515 def __init__(self, root, mdwndb):
3516 # The code below groups the instructions by name:section.
3517 # There can be multiple names for the same instruction.
3518 # The point is to capture different opcodes for the same instruction.
3519 sections = {}
3520 records = _collections.defaultdict(set)
3521 path = (root / "insndb.csv")
3522 with open(path, "r", encoding="UTF-8") as stream:
3523 for section in sorted(parse(stream, Section.CSV)):
3524 path = (root / section.path)
3525 opcode_cls = {
3526 section.Mode.INTEGER: IntegerOpcode,
3527 section.Mode.PATTERN: PatternOpcode,
3528 }[section.mode]
3529 factory = _functools.partial(
3530 PPCRecord.CSV, opcode_cls=opcode_cls)
3531 with open(path, "r", encoding="UTF-8") as stream:
3532 for insn in parse(stream, factory):
3533 for name in insn.names:
3534 records[name].add(insn)
3535 sections[name] = section
3536
3537 items = sorted(records.items())
3538 records = {}
3539 for (name, multirecord) in items:
3540 records[name] = PPCMultiRecord(sorted(multirecord))
3541
3542 def exact_match(name):
3543 record = records.get(name)
3544 if record is None:
3545 return None
3546 return name
3547
3548 def LK_match(name):
3549 if not name.endswith("l"):
3550 return None
3551 alias = exact_match(name[:-1])
3552 if alias is None:
3553 return None
3554 record = records[alias]
3555 if "lk" not in record.flags:
3556 raise ValueError(record)
3557 return alias
3558
3559 def AA_match(name):
3560 if not name.endswith("a"):
3561 return None
3562 alias = LK_match(name[:-1])
3563 if alias is None:
3564 alias = name[:-1]
3565 record = records[alias]
3566 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
3567 raise ValueError(record)
3568 if "AA" not in mdwndb[name].operands:
3569 raise ValueError(record)
3570 return alias
3571
3572 def Rc_match(name):
3573 if not name.endswith("."):
3574 return None
3575 alias = exact_match(name[:-1])
3576 if alias is None:
3577 return None
3578 record = records[alias]
3579 if record.Rc is _RCOE.NONE:
3580 raise ValueError(record)
3581 return alias
3582
3583 db = {}
3584 matches = (exact_match, LK_match, AA_match, Rc_match)
3585 for (name, _) in mdwndb:
3586 if name.startswith("sv."):
3587 continue
3588 alias = None
3589 for match in matches:
3590 alias = match(name)
3591 if alias is not None:
3592 break
3593 if alias is None:
3594 continue
3595 section = sections[alias]
3596 record = records[alias]
3597 db[name] = (section, record)
3598
3599 self.__db = dict(sorted(db.items()))
3600
3601 return super().__init__()
3602
3603 @_functools.lru_cache(maxsize=512, typed=False)
3604 def __getitem__(self, key):
3605 return self.__db.get(key, (None, None))
3606
3607
3608 class SVP64Database:
3609 def __init__(self, root, ppcdb):
3610 db = set()
3611 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3612 for (prefix, _, names) in _os.walk(root):
3613 prefix = _pathlib.Path(prefix)
3614 for name in filter(lambda name: pattern.match(name), names):
3615 path = (prefix / _pathlib.Path(name))
3616 with open(path, "r", encoding="UTF-8") as stream:
3617 db.update(parse(stream, SVP64Record.CSV))
3618 db = {record.name:record for record in db}
3619
3620 self.__db = dict(sorted(db.items()))
3621 self.__ppcdb = ppcdb
3622
3623 return super().__init__()
3624
3625 def __getitem__(self, key):
3626 (_, record) = self.__ppcdb[key]
3627 if record is None:
3628 return None
3629
3630 for name in record.names:
3631 record = self.__db.get(name, None)
3632 if record is not None:
3633 return record
3634
3635 return None
3636
3637
3638 class Database:
3639 def __init__(self, root):
3640 root = _pathlib.Path(root)
3641 mdwndb = MarkdownDatabase()
3642 fieldsdb = FieldsDatabase()
3643 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
3644 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
3645
3646 db = set()
3647 names = {}
3648 opcodes = _collections.defaultdict(
3649 lambda: _collections.defaultdict(set))
3650
3651 for (name, mdwn) in mdwndb:
3652 if name.startswith("sv."):
3653 continue
3654 (section, ppc) = ppcdb[name]
3655 if ppc is None:
3656 continue
3657 svp64 = svp64db[name]
3658 fields = fieldsdb[ppc.form]
3659 record = Record(name=name,
3660 section=section, ppc=ppc, svp64=svp64,
3661 mdwn=mdwn, fields=fields)
3662 db.add(record)
3663 names[record.name] = record
3664 opcodes[section][record.PO].add(record)
3665
3666 self.__db = sorted(db)
3667 self.__names = dict(sorted(names.items()))
3668 self.__opcodes = dict(sorted(opcodes.items()))
3669
3670 return super().__init__()
3671
3672 def __repr__(self):
3673 return repr(self.__db)
3674
3675 def __iter__(self):
3676 yield from self.__db
3677
3678 @_functools.lru_cache(maxsize=None)
3679 def __contains__(self, key):
3680 return self.__getitem__(key) is not None
3681
3682 @_functools.lru_cache(maxsize=None)
3683 def __getitem__(self, key):
3684 if isinstance(key, SVP64Instruction):
3685 key = key.suffix
3686
3687 if isinstance(key, Instruction):
3688 PO = int(key.PO)
3689 key = int(key)
3690 sections = sorted(self.__opcodes)
3691 for section in sections:
3692 group = self.__opcodes[section]
3693 for record in group[PO]:
3694 if record.match(key=key):
3695 return record
3696
3697 return None
3698
3699 elif isinstance(key, str):
3700 return self.__names.get(key)
3701
3702 raise ValueError("instruction or name expected")