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