insndb/db: support pcode command
[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 @property
830 def pcode(self):
831 return self.mdwn.pcode
832
833 def __lt__(self, other):
834 if not isinstance(other, Record):
835 return NotImplemented
836 lhs = (min(self.opcodes), self.name)
837 rhs = (min(other.opcodes), other.name)
838 return (lhs < rhs)
839
840 @cached_property
841 def operands(self):
842 return (self.static_operands + self.dynamic_operands)
843
844 @cached_property
845 def static_operands(self):
846 operands = []
847 operands.append(POStaticOperand(record=self, value=self.PO))
848 for ppc in self.ppc:
849 operands.append(XOStaticOperand(
850 record=self,
851 value=ppc.opcode.value,
852 span=self.section.bitsel,
853 ))
854 for (cls, kwargs) in self.mdwn.operands.static:
855 operands.append(cls(record=self, **kwargs))
856 return tuple(operands)
857
858 @cached_property
859 def dynamic_operands(self):
860 operands = []
861 for (cls, kwargs) in self.mdwn.operands.dynamic:
862 operands.append(cls(record=self, **kwargs))
863 return tuple(operands)
864
865 @cached_property
866 def opcodes(self):
867 def binary(mapping):
868 return int("".join(str(int(mapping[bit])) \
869 for bit in sorted(mapping)), 2)
870
871 def PO_XO(value, mask, opcode, bits):
872 value = dict(value)
873 mask = dict(mask)
874 for (src, dst) in enumerate(reversed(bits)):
875 value[dst] = ((opcode.value & (1 << src)) != 0)
876 mask[dst] = ((opcode.mask & (1 << src)) != 0)
877 return (value, mask)
878
879 def PO(value, mask, opcode, bits):
880 return PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
881
882 def XO(value, mask, opcode, bits):
883 (value, mask) = PO_XO(value=value, mask=mask,
884 opcode=opcode, bits=bits)
885 for (op_cls, op_kwargs) in self.mdwn.operands.static:
886 operand = op_cls(record=self, **op_kwargs)
887 for (src, dst) in enumerate(reversed(operand.span)):
888 value[dst] = ((operand.value & (1 << src)) != 0)
889 mask[dst] = True
890 return (value, mask)
891
892 pairs = []
893 value = {bit:False for bit in range(32)}
894 mask = {bit:False for bit in range(32)}
895 if self.section.opcode is not None:
896 (value, mask) = PO(value=value, mask=mask,
897 opcode=self.section.opcode, bits=range(0, 6))
898 for ppc in self.ppc:
899 pairs.append(XO(value=value, mask=mask,
900 opcode=ppc.opcode, bits=self.section.bitsel))
901
902 result = []
903 for (value, mask) in pairs:
904 value = Opcode.Value(binary(value))
905 mask = Opcode.Mask(binary(mask))
906 result.append(Opcode(value=value, mask=mask))
907
908 return tuple(result)
909
910 @cached_property
911 def PO(self):
912 opcode = self.section.opcode
913 if opcode is None:
914 opcode = self.ppc[0].opcode
915 if isinstance(opcode, PatternOpcode):
916 value = int(opcode.value)
917 bits = opcode.value.bit_length()
918 return int(_SelectableInt(value=value, bits=bits)[0:6])
919
920 return int(opcode.value)
921
922 @cached_property
923 def XO(self):
924 return tuple(ppc.opcode for ppc in self.ppc)
925
926 def match(self, key):
927 for opcode in self.opcodes:
928 if opcode.match(key):
929 return True
930
931 return False
932
933 @property
934 def mode(self):
935 return self.svp64.mode
936
937 @property
938 def in1(self):
939 return self.ppc.in1
940
941 @property
942 def in2(self):
943 return self.ppc.in2
944
945 @property
946 def in3(self):
947 return self.ppc.in3
948
949 @property
950 def out(self):
951 return self.ppc.out
952
953 @property
954 def out2(self):
955 if self.svp64 is None:
956 return _OutSel.NONE
957 return self.ppc.out
958
959 @property
960 def cr_in(self):
961 return self.ppc.cr_in
962
963 @property
964 def cr_in2(self):
965 return self.ppc.cr_in2
966
967 @property
968 def cr_out(self):
969 return self.ppc.cr_out
970
971 ptype = property(lambda self: self.svp64.ptype)
972 etype = property(lambda self: self.svp64.etype)
973
974 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
975 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
976 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
977 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
978 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
979 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
980 extra_idx_cr_in2 = property(lambda self: self.svp64.extra_idx_cr_in2)
981 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
982
983 def __contains__(self, key):
984 return self.mdwn.operands.__contains__(key)
985
986 def __getitem__(self, key):
987 (cls, kwargs) = self.mdwn.operands.__getitem__(key)
988 return cls(record=self, **kwargs)
989
990 @cached_property
991 def Rc(self):
992 if "Rc" not in self:
993 return False
994 return self["Rc"].value
995
996
997 class Operand:
998 def __init__(self, record, name):
999 self.__record = record
1000 self.__name = name
1001
1002 def __iter__(self):
1003 yield ("record", self.record)
1004 yield ("name", self.__name)
1005
1006 def __repr__(self):
1007 return f"{self.__class__.__name__}({self.name})"
1008
1009 @property
1010 def name(self):
1011 return self.__name
1012
1013 @property
1014 def record(self):
1015 return self.__record
1016
1017 @cached_property
1018 def span(self):
1019 return self.record.fields[self.name]
1020
1021 def assemble(self, insn):
1022 raise NotImplementedError()
1023
1024 def disassemble(self, insn,
1025 style=Style.NORMAL, indent=""):
1026 raise NotImplementedError()
1027
1028
1029 class DynamicOperand(Operand):
1030 def assemble(self, insn, value):
1031 span = self.span
1032 if isinstance(value, str):
1033 value = int(value, 0)
1034 if value < 0:
1035 raise ValueError("signed operands not allowed")
1036 insn[span] = value
1037
1038 def disassemble(self, insn,
1039 style=Style.NORMAL, indent=""):
1040 span = self.span
1041 value = insn[span]
1042
1043 if style >= Style.VERBOSE:
1044 span = map(str, span)
1045 yield f"{indent}{self.name}"
1046 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1047 yield f"{indent}{indent}{', '.join(span)}"
1048 else:
1049 yield str(int(value))
1050
1051
1052 class SignedOperand(DynamicOperand):
1053 def assemble(self, insn, value):
1054 if isinstance(value, str):
1055 value = int(value, 0)
1056 return super().assemble(value=value, insn=insn)
1057
1058 def assemble(self, insn, value):
1059 span = self.span
1060 if isinstance(value, str):
1061 value = int(value, 0)
1062 insn[span] = value
1063
1064 def disassemble(self, insn,
1065 style=Style.NORMAL, indent=""):
1066 span = self.span
1067 value = insn[span].to_signed_int()
1068 sign = "-" if (value < 0) else ""
1069 value = abs(value)
1070
1071 if style >= Style.VERBOSE:
1072 span = map(str, span)
1073 yield f"{indent}{self.name}"
1074 yield f"{indent}{indent}{sign}{value}"
1075 yield f"{indent}{indent}{', '.join(span)}"
1076 else:
1077 yield f"{sign}{value}"
1078
1079
1080 class StaticOperand(Operand):
1081 def __init__(self, record, name, value):
1082 self.__value = value
1083 return super().__init__(record=record, name=name)
1084
1085 def __iter__(self):
1086 yield ("value", self.__value)
1087 yield from super().__iter__()
1088
1089 def __repr__(self):
1090 return f"{self.__class__.__name__}({self.name}, value={self.value})"
1091
1092 @property
1093 def value(self):
1094 return self.__value
1095
1096 def assemble(self, insn):
1097 insn[self.span] = self.value
1098
1099 def disassemble(self, insn,
1100 style=Style.NORMAL, indent=""):
1101 span = self.span
1102 value = insn[span]
1103
1104 if style >= Style.VERBOSE:
1105 span = map(str, span)
1106 yield f"{indent}{self.name}"
1107 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1108 yield f"{indent}{indent}{', '.join(span)}"
1109 else:
1110 yield str(int(value))
1111
1112
1113 class SpanStaticOperand(StaticOperand):
1114 def __init__(self, record, name, value, span):
1115 self.__span = tuple(span)
1116 return super().__init__(record=record, name=name, value=value)
1117
1118 def __iter__(self):
1119 yield ("span", self.__span)
1120 yield from super().__iter__()
1121
1122 @property
1123 def span(self):
1124 return self.__span
1125
1126
1127 class POStaticOperand(SpanStaticOperand):
1128 def __init__(self, record, value):
1129 return super().__init__(record=record, name="PO",
1130 value=value, span=range(0, 6))
1131
1132 def __iter__(self):
1133 for (key, value) in super().__iter__():
1134 if key not in {"name", "span"}:
1135 yield (key, value)
1136
1137
1138 class XOStaticOperand(SpanStaticOperand):
1139 def __init__(self, record, value, span):
1140 bits = record.section.bitsel
1141 value = _SelectableInt(value=value, bits=len(bits))
1142 span = dict(zip(bits, range(len(bits))))
1143 span_rev = {value:key for (key, value) in span.items()}
1144
1145 # This part is tricky: we cannot use record.operands,
1146 # as this code is called by record.static_operands method.
1147 for (cls, kwargs) in record.mdwn.operands:
1148 operand = cls(record=record, **kwargs)
1149 for idx in operand.span:
1150 rev = span.pop(idx, None)
1151 if rev is not None:
1152 span_rev.pop(rev, None)
1153
1154 value = int(_selectconcat(*(value[bit] for bit in span.values())))
1155 span = tuple(span.keys())
1156
1157 return super().__init__(record=record, name="XO",
1158 value=value, span=span)
1159
1160 def __iter__(self):
1161 for (key, value) in super().__iter__():
1162 if key not in {"name"}:
1163 yield (key, value)
1164
1165
1166 class ImmediateOperand(DynamicOperand):
1167 pass
1168
1169
1170 class SignedImmediateOperand(SignedOperand, ImmediateOperand):
1171 pass
1172
1173
1174 class NonZeroOperand(DynamicOperand):
1175 def assemble(self, insn, value):
1176 if isinstance(value, str):
1177 value = int(value, 0)
1178 if not isinstance(value, int):
1179 raise ValueError("non-integer operand")
1180 if value == 0:
1181 raise ValueError("non-zero operand")
1182 value -= 1
1183 return super().assemble(value=value, insn=insn)
1184
1185 def disassemble(self, insn,
1186 style=Style.NORMAL, indent=""):
1187 span = self.span
1188 value = insn[span]
1189
1190 if style >= Style.VERBOSE:
1191 span = map(str, span)
1192 yield f"{indent}{self.name}"
1193 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1194 yield f"{indent}{indent}{', '.join(span)}"
1195 else:
1196 yield str(int(value) + 1)
1197
1198
1199 class ExtendableOperand(DynamicOperand):
1200 def sv_spec_enter(self, value, span):
1201 return (value, span)
1202
1203 def sv_spec(self, insn):
1204 vector = False
1205 span = self.span
1206 value = insn[span]
1207 span = tuple(map(str, span))
1208
1209 if isinstance(insn, SVP64Instruction):
1210 (origin_value, origin_span) = (value, span)
1211 (value, span) = self.sv_spec_enter(value=value, span=span)
1212
1213 for extra_idx in self.extra_idx:
1214 if self.record.etype is _SVEType.EXTRA3:
1215 spec = insn.prefix.rm.extra3[extra_idx]
1216 elif self.record.etype is _SVEType.EXTRA2:
1217 spec = insn.prefix.rm.extra2[extra_idx]
1218 else:
1219 raise ValueError(self.record.etype)
1220
1221 if spec != 0:
1222 vector = bool(spec[0])
1223 spec_span = spec.__class__
1224 if self.record.etype is _SVEType.EXTRA3:
1225 spec_span = tuple(map(str, spec_span[1, 2]))
1226 spec = spec[1, 2]
1227 elif self.record.etype is _SVEType.EXTRA2:
1228 spec_span = tuple(map(str, spec_span[1,]))
1229 spec = _SelectableInt(value=spec[1].value, bits=2)
1230 if vector:
1231 spec <<= 1
1232 spec_span = (spec_span + ("{0}",))
1233 else:
1234 spec_span = (("{0}",) + spec_span)
1235 else:
1236 raise ValueError(self.record.etype)
1237
1238 vector_shift = (2 + (5 - value.bits))
1239 scalar_shift = value.bits
1240 spec_shift = (5 - value.bits)
1241
1242 bits = (len(span) + len(spec_span))
1243 value = _SelectableInt(value=value.value, bits=bits)
1244 spec = _SelectableInt(value=spec.value, bits=bits)
1245 if vector:
1246 value = ((value << vector_shift) | (spec << spec_shift))
1247 span = (span + spec_span + ((spec_shift * ("{0}",))))
1248 else:
1249 value = ((spec << scalar_shift) | value)
1250 span = ((spec_shift * ("{0}",)) + spec_span + span)
1251
1252 (value, span) = self.sv_spec_leave(value=value, span=span,
1253 origin_value=origin_value, origin_span=origin_span)
1254
1255 return (vector, value, span)
1256
1257 def sv_spec_leave(self, value, span, origin_value, origin_span):
1258 return (value, span)
1259
1260 @property
1261 def extra_idx(self):
1262 for (key, record) in self.record.svp64.extras.items():
1263 if record["reg"].alias is self.extra_reg.alias:
1264 yield record["idx"]
1265
1266 @cached_property
1267 def extra_reg(self):
1268 return _Reg(self.name)
1269
1270 def remap(self, value, vector):
1271 raise NotImplementedError()
1272
1273 def assemble(self, value, insn, prefix):
1274 vector = False
1275
1276 if isinstance(value, str):
1277 value = value.lower()
1278 if value.startswith("%"):
1279 value = value[1:]
1280 if value.startswith("*"):
1281 if not isinstance(insn, SVP64Instruction):
1282 raise ValueError(value)
1283 value = value[1:]
1284 vector = True
1285 if value.startswith(prefix):
1286 if (self.extra_reg.or_zero and (value == f"{prefix}0")):
1287 raise ValueError(value)
1288 value = value[len(prefix):]
1289 value = int(value, 0)
1290
1291 if isinstance(insn, SVP64Instruction):
1292 (value, extra) = self.remap(value=value, vector=vector)
1293
1294 for extra_idx in self.extra_idx:
1295 if self.record.etype is _SVEType.EXTRA3:
1296 insn.prefix.rm.extra3[extra_idx] = extra
1297 elif self.record.etype is _SVEType.EXTRA2:
1298 insn.prefix.rm.extra2[extra_idx] = extra
1299 else:
1300 raise ValueError(self.record.etype)
1301
1302 return super().assemble(value=value, insn=insn)
1303
1304 def disassemble(self, insn,
1305 style=Style.NORMAL, prefix="", indent=""):
1306 (vector, value, span) = self.sv_spec(insn=insn)
1307
1308 if (self.extra_reg.or_zero and (value == 0)):
1309 prefix = ""
1310
1311 if style >= Style.VERBOSE:
1312 mode = "vector" if vector else "scalar"
1313 yield f"{indent}{self.name} ({mode})"
1314 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1315 yield f"{indent}{indent}{', '.join(span)}"
1316 if isinstance(insn, SVP64Instruction):
1317 for extra_idx in frozenset(self.extra_idx):
1318 if self.record.etype is _SVEType.NONE:
1319 yield f"{indent}{indent}extra[none]"
1320 else:
1321 etype = repr(self.record.etype).lower()
1322 yield f"{indent}{indent}{etype}{extra_idx!r}"
1323 else:
1324 vector = "*" if vector else ""
1325 yield f"{vector}{prefix}{int(value)}"
1326
1327
1328 class SimpleRegisterOperand(ExtendableOperand):
1329 def remap(self, value, vector):
1330 if vector:
1331 extra = (value & 0b11)
1332 value = (value >> 2)
1333 else:
1334 extra = (value >> 5)
1335 value = (value & 0b11111)
1336
1337 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1338 # (and shrink to a single bit if ok)
1339 if self.record.etype is _SVEType.EXTRA2:
1340 if vector:
1341 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1342 assert (extra & 0b01) == 0, \
1343 ("vector field %s cannot fit into EXTRA2" % value)
1344 extra = (0b10 | (extra >> 1))
1345 else:
1346 # range is r0-r63 in increments of 1
1347 assert (extra >> 1) == 0, \
1348 ("scalar GPR %d cannot fit into EXTRA2" % value)
1349 extra &= 0b01
1350 elif self.record.etype is _SVEType.EXTRA3:
1351 if vector:
1352 # EXTRA3 vector bit needs marking
1353 extra |= 0b100
1354 else:
1355 raise ValueError(self.record.etype)
1356
1357 return (value, extra)
1358
1359
1360 class GPROperand(SimpleRegisterOperand):
1361 def assemble(self, insn, value):
1362 return super().assemble(value=value, insn=insn, prefix="r")
1363
1364 def disassemble(self, insn,
1365 style=Style.NORMAL, indent=""):
1366 prefix = "" if (style <= Style.SHORT) else "r"
1367 yield from super().disassemble(prefix=prefix, insn=insn,
1368 style=style, indent=indent)
1369
1370
1371 class GPRPairOperand(GPROperand):
1372 pass
1373
1374
1375 class FPROperand(SimpleRegisterOperand):
1376 def assemble(self, insn, value):
1377 return super().assemble(value=value, insn=insn, prefix="f")
1378
1379 def disassemble(self, insn,
1380 style=Style.NORMAL, indent=""):
1381 prefix = "" if (style <= Style.SHORT) else "f"
1382 yield from super().disassemble(prefix=prefix, insn=insn,
1383 style=style, indent=indent)
1384
1385
1386 class FPRPairOperand(FPROperand):
1387 pass
1388
1389
1390 class ConditionRegisterFieldOperand(ExtendableOperand):
1391 def pattern(name_pattern):
1392 (name, pattern) = name_pattern
1393 return (name, _re.compile(f"^{pattern}$", _re.S))
1394
1395 CONDS = {
1396 "lt": 0,
1397 "gt": 1,
1398 "eq": 2,
1399 "so": 3,
1400 "un": 3,
1401 }
1402 CR = r"(?:CR|cr)([0-9]+)"
1403 N = r"([0-9]+)"
1404 BIT = rf"({'|'.join(CONDS.keys())})"
1405 LBIT = fr"{BIT}\s*\+\s*" # BIT+
1406 RBIT = fr"\s*\+\s*{BIT}" # +BIT
1407 CRN = fr"{CR}\s*\*\s*{N}" # CR*N
1408 NCR = fr"{N}\s*\*\s*{CR}" # N*CR
1409 XCR = fr"{CR}\.{BIT}"
1410 PATTERNS = tuple(map(pattern, (
1411 ("CR", CR),
1412 ("XCR", XCR),
1413 ("CR*N", CRN),
1414 ("N*CR", NCR),
1415 ("BIT+CR", (LBIT + CR)),
1416 ("CR+BIT", (CR + RBIT)),
1417 ("BIT+CR*N", (LBIT + CRN)),
1418 ("CR*N+BIT", (CRN + RBIT)),
1419 ("BIT+N*CR", (LBIT + NCR)),
1420 ("N*CR+BIT", (NCR + RBIT)),
1421 )))
1422
1423 def remap(self, value, vector, regtype):
1424 if regtype is _RegType.CR_5BIT:
1425 subvalue = (value & 0b11)
1426 value >>= 2
1427
1428 if vector:
1429 extra = (value & 0b1111)
1430 value >>= 4
1431 else:
1432 extra = (value >> 3)
1433 value &= 0b111
1434
1435 if self.record.etype is _SVEType.EXTRA2:
1436 if vector:
1437 assert (extra & 0b111) == 0, \
1438 "vector CR cannot fit into EXTRA2"
1439 extra = (0b10 | (extra >> 3))
1440 else:
1441 assert (extra >> 1) == 0, \
1442 "scalar CR cannot fit into EXTRA2"
1443 extra &= 0b01
1444 elif self.record.etype is _SVEType.EXTRA3:
1445 if vector:
1446 assert (extra & 0b11) == 0, \
1447 "vector CR cannot fit into EXTRA3"
1448 extra = (0b100 | (extra >> 2))
1449 else:
1450 assert (extra >> 2) == 0, \
1451 "scalar CR cannot fit into EXTRA3"
1452 extra &= 0b11
1453
1454 if regtype is _RegType.CR_5BIT:
1455 value = ((value << 2) | subvalue)
1456
1457 return (value, extra)
1458
1459 def assemble(self, insn, value):
1460 if isinstance(value, str):
1461 vector = False
1462
1463 if value.startswith("*"):
1464 if not isinstance(insn, SVP64Instruction):
1465 raise ValueError(value)
1466 value = value[1:]
1467 vector = True
1468
1469 for (name, pattern) in reversed(self.__class__.PATTERNS):
1470 match = pattern.match(value)
1471 if match is not None:
1472 keys = name.replace("+", "_").replace("*", "_").split("_")
1473 values = match.groups()
1474 match = dict(zip(keys, values))
1475 CR = int(match["CR"])
1476 if name == "XCR":
1477 N = 4
1478 else:
1479 N = int(match.get("N", "1"))
1480 BIT = self.__class__.CONDS[match.get("BIT", "lt")]
1481 value = ((CR * N) + BIT)
1482 break
1483
1484 value = str(value)
1485 if vector:
1486 value = f"*{value}"
1487
1488 return super().assemble(value=value, insn=insn, prefix="cr")
1489
1490 def disassemble(self, insn,
1491 style=Style.NORMAL, prefix="", indent=""):
1492 (vector, value, span) = self.sv_spec(insn=insn)
1493
1494 if style >= Style.VERBOSE:
1495 mode = "vector" if vector else "scalar"
1496 yield f"{indent}{self.name} ({mode})"
1497 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1498 yield f"{indent}{indent}{', '.join(span)}"
1499 if isinstance(insn, SVP64Instruction):
1500 for extra_idx in frozenset(self.extra_idx):
1501 if self.record.etype is _SVEType.NONE:
1502 yield f"{indent}{indent}extra[none]"
1503 else:
1504 etype = repr(self.record.etype).lower()
1505 yield f"{indent}{indent}{etype}{extra_idx!r}"
1506 else:
1507 vector = "*" if vector else ""
1508 CR = int(value >> 2)
1509 CC = int(value & 3)
1510 cond = ("lt", "gt", "eq", "so")[CC]
1511 if style >= Style.NORMAL:
1512 if CR != 0:
1513 if isinstance(insn, SVP64Instruction):
1514 yield f"{vector}cr{CR}.{cond}"
1515 else:
1516 yield f"4*cr{CR}+{cond}"
1517 else:
1518 yield cond
1519 else:
1520 yield f"{vector}{prefix}{int(value)}"
1521
1522
1523 class CR3Operand(ConditionRegisterFieldOperand):
1524 def remap(self, value, vector):
1525 return super().remap(value=value, vector=vector,
1526 regtype=_RegType.CR_3BIT)
1527
1528
1529 class CR5Operand(ConditionRegisterFieldOperand):
1530 def remap(self, value, vector):
1531 return super().remap(value=value, vector=vector,
1532 regtype=_RegType.CR_5BIT)
1533
1534 def sv_spec_enter(self, value, span):
1535 value = _SelectableInt(value=(value.value >> 2), bits=3)
1536 return (value, span)
1537
1538 def sv_spec_leave(self, value, span, origin_value, origin_span):
1539 value = _selectconcat(value, origin_value[3:5])
1540 span += origin_span
1541 return (value, span)
1542
1543
1544 class EXTSOperand(SignedOperand):
1545 field: str # real name to report
1546 nz: int = 0 # number of zeros
1547 fmt: str = "d" # integer formatter
1548
1549 def __init__(self, record, name, field, nz=0, fmt="d"):
1550 self.__field = field
1551 self.__nz = nz
1552 self.__fmt = fmt
1553 return super().__init__(record=record, name=name)
1554
1555 @property
1556 def field(self):
1557 return self.__field
1558
1559 @property
1560 def nz(self):
1561 return self.__nz
1562
1563 @property
1564 def fmt(self):
1565 return self.__fmt
1566
1567 @cached_property
1568 def span(self):
1569 return self.record.fields[self.field]
1570
1571 def assemble(self, insn, value):
1572 span = self.span
1573 if isinstance(value, str):
1574 value = int(value, 0)
1575 insn[span] = (value >> self.nz)
1576
1577 def disassemble(self, insn,
1578 style=Style.NORMAL, indent=""):
1579 span = self.span
1580 value = insn[span].to_signed_int()
1581 sign = "-" if (value < 0) else ""
1582 value = (abs(value) << self.nz)
1583
1584 if style >= Style.VERBOSE:
1585 span = (tuple(map(str, span)) + (("{0}",) * self.nz))
1586 zeros = ("0" * self.nz)
1587 hint = f"{self.name} = EXTS({self.field} || {zeros})"
1588 yield f"{indent * 1}{hint}"
1589 yield f"{indent * 2}{self.field}"
1590 yield f"{indent * 3}{sign}{value:{self.fmt}}"
1591 yield f"{indent * 3}{', '.join(span)}"
1592 else:
1593 yield f"{sign}{value:{self.fmt}}"
1594
1595
1596 class TargetAddrOperand(EXTSOperand):
1597 def __init__(self, record, name, field):
1598 return super().__init__(record=record, name=name, field=field,
1599 nz=2, fmt="#x")
1600
1601
1602 class TargetAddrOperandLI(TargetAddrOperand):
1603 def __init__(self, record, name):
1604 return super().__init__(record=record, name=name, field="LI")
1605
1606
1607 class TargetAddrOperandBD(TargetAddrOperand):
1608 def __init__(self, record, name):
1609 return super().__init__(record=record, name=name, field="BD")
1610
1611
1612 class EXTSOperandDS(EXTSOperand, ImmediateOperand):
1613 def __init__(self, record, name):
1614 return super().__init__(record=record, name=name, field="DS", nz=2)
1615
1616
1617 class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
1618 def __init__(self, record, name):
1619 return super().__init__(record=record, name=name, field="DQ", nz=4)
1620
1621
1622 class DOperandDX(SignedOperand):
1623 @cached_property
1624 def span(self):
1625 cls = lambda name: DynamicOperand(record=self.record, name=name)
1626 operands = map(cls, ("d0", "d1", "d2"))
1627 spans = map(lambda operand: operand.span, operands)
1628 return sum(spans, tuple())
1629
1630 def disassemble(self, insn,
1631 style=Style.NORMAL, indent=""):
1632 span = self.span
1633 value = insn[span].to_signed_int()
1634 sign = "-" if (value < 0) else ""
1635 value = abs(value)
1636
1637 if style >= Style.VERBOSE:
1638 yield f"{indent}D"
1639 mapping = {
1640 "d0": "[0:9]",
1641 "d1": "[10:15]",
1642 "d2": "[16]",
1643 }
1644 for (subname, subspan) in mapping.items():
1645 operand = DynamicOperand(name=subname)
1646 span = operand.span
1647 span = map(str, span)
1648 yield f"{indent}{indent}{operand.name} = D{subspan}"
1649 yield f"{indent}{indent}{indent}{sign}{value}"
1650 yield f"{indent}{indent}{indent}{', '.join(span)}"
1651 else:
1652 yield f"{sign}{value}"
1653
1654
1655 class Instruction(_Mapping):
1656 @classmethod
1657 def integer(cls, value=0, bits=None, byteorder="little"):
1658 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1659 raise ValueError(bits)
1660
1661 if isinstance(value, bytes):
1662 if ((len(value) * 8) != bits):
1663 raise ValueError(f"bit length mismatch")
1664 value = int.from_bytes(value, byteorder=byteorder)
1665
1666 if isinstance(value, int):
1667 value = _SelectableInt(value=value, bits=bits)
1668 elif isinstance(value, Instruction):
1669 value = value.storage
1670
1671 if not isinstance(value, _SelectableInt):
1672 raise ValueError(value)
1673 if bits is None:
1674 bits = len(cls)
1675 if len(value) != bits:
1676 raise ValueError(value)
1677
1678 value = _SelectableInt(value=value, bits=bits)
1679
1680 return cls(storage=value)
1681
1682 def __hash__(self):
1683 return hash(int(self))
1684
1685 def __getitem__(self, key):
1686 return self.storage.__getitem__(key)
1687
1688 def __setitem__(self, key, value):
1689 return self.storage.__setitem__(key, value)
1690
1691 def bytes(self, byteorder="little"):
1692 nr_bytes = (len(self.__class__) // 8)
1693 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1694
1695 @classmethod
1696 def record(cls, db, entry):
1697 record = db[entry]
1698 if record is None:
1699 raise KeyError(entry)
1700 return record
1701
1702 @classmethod
1703 def operands(cls, record):
1704 yield from record.operands
1705
1706 @classmethod
1707 def static_operands(cls, record):
1708 return filter(lambda operand: isinstance(operand, StaticOperand),
1709 cls.operands(record=record))
1710
1711 @classmethod
1712 def dynamic_operands(cls, record):
1713 return filter(lambda operand: isinstance(operand, DynamicOperand),
1714 cls.operands(record=record))
1715
1716 def spec(self, record, prefix):
1717 dynamic_operands = tuple(map(_operator.itemgetter(0),
1718 self.spec_dynamic_operands(record=record)))
1719
1720 static_operands = []
1721 for (name, value) in self.spec_static_operands(record=record):
1722 static_operands.append(f"{name}={value}")
1723
1724 operands = ""
1725 if dynamic_operands:
1726 operands += " "
1727 operands += ",".join(dynamic_operands)
1728 if static_operands:
1729 operands += " "
1730 operands += " ".join(static_operands)
1731
1732 return f"{prefix}{record.name}{operands}"
1733
1734 def spec_static_operands(self, record):
1735 for operand in self.static_operands(record=record):
1736 if not isinstance(operand, (POStaticOperand, XOStaticOperand)):
1737 yield (operand.name, operand.value)
1738
1739 def spec_dynamic_operands(self, record, style=Style.NORMAL):
1740 imm = False
1741 imm_name = ""
1742 imm_value = ""
1743 for operand in self.dynamic_operands(record=record):
1744 name = operand.name
1745 value = " ".join(operand.disassemble(insn=self,
1746 style=min(style, Style.NORMAL)))
1747 if imm:
1748 name = f"{imm_name}({name})"
1749 value = f"{imm_value}({value})"
1750 imm = False
1751 if isinstance(operand, ImmediateOperand):
1752 imm_name = name
1753 imm_value = value
1754 imm = True
1755 if not imm:
1756 yield (name, value)
1757
1758 @classmethod
1759 def assemble(cls, record, arguments=None):
1760 if arguments is None:
1761 arguments = ()
1762
1763 insn = cls.integer(value=0)
1764
1765 for operand in cls.static_operands(record=record):
1766 operand.assemble(insn=insn)
1767
1768 arguments = Arguments(record=record,
1769 arguments=arguments, operands=cls.dynamic_operands(record=record))
1770 for (value, operand) in arguments:
1771 operand.assemble(insn=insn, value=value)
1772
1773 return insn
1774
1775 def disassemble(self, record,
1776 byteorder="little",
1777 style=Style.NORMAL):
1778 raise NotImplementedError()
1779
1780
1781 class WordInstruction(Instruction):
1782 _: _Field = range(0, 32)
1783 PO: _Field = range(0, 6)
1784
1785 @classmethod
1786 def integer(cls, value, byteorder="little"):
1787 return super().integer(bits=32, value=value, byteorder=byteorder)
1788
1789 @property
1790 def binary(self):
1791 bits = []
1792 for idx in range(32):
1793 bit = int(self[idx])
1794 bits.append(bit)
1795 return "".join(map(str, bits))
1796
1797 def disassemble(self, record,
1798 byteorder="little",
1799 style=Style.NORMAL):
1800 if style <= Style.SHORT:
1801 blob = ""
1802 else:
1803 blob = self.bytes(byteorder=byteorder)
1804 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1805 blob += " "
1806
1807 if record is None:
1808 yield f"{blob}.long 0x{int(self):08x}"
1809 return
1810
1811 # awful temporary hack: workaround for ld-update
1812 # https://bugs.libre-soc.org/show_bug.cgi?id=1056#c2
1813 # XXX TODO must check that *EXTENDED* RA != extended-RT
1814 if (record.svp64 is not None and
1815 record.mode == _SVMode.LDST_IMM and
1816 'u' in record.name):
1817 yield f"{blob}.long 0x{int(self):08x}"
1818 return
1819
1820 paired = False
1821 if style is Style.LEGACY:
1822 paired = False
1823 for operand in self.dynamic_operands(record=record):
1824 if isinstance(operand, (GPRPairOperand, FPRPairOperand)):
1825 paired = True
1826
1827 if style is Style.LEGACY and (paired or record.ppc.unofficial):
1828 yield f"{blob}.long 0x{int(self):08x}"
1829 else:
1830 operands = tuple(map(_operator.itemgetter(1),
1831 self.spec_dynamic_operands(record=record, style=style)))
1832 if operands:
1833 operands = ",".join(operands)
1834 yield f"{blob}{record.name} {operands}"
1835 else:
1836 yield f"{blob}{record.name}"
1837
1838 if style >= Style.VERBOSE:
1839 indent = (" " * 4)
1840 binary = self.binary
1841 spec = self.spec(record=record, prefix="")
1842 yield f"{indent}spec"
1843 yield f"{indent}{indent}{spec}"
1844 yield f"{indent}pcode"
1845 for stmt in record.mdwn.pcode:
1846 yield f"{indent}{indent}{stmt}"
1847 yield f"{indent}binary"
1848 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1849 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1850 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1851 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1852 yield f"{indent}opcodes"
1853 for opcode in record.opcodes:
1854 yield f"{indent}{indent}{opcode!r}"
1855 for operand in self.operands(record=record):
1856 yield from operand.disassemble(insn=self,
1857 style=style, indent=indent)
1858 yield ""
1859
1860
1861 class PrefixedInstruction(Instruction):
1862 class Prefix(WordInstruction.remap(range(0, 32))):
1863 pass
1864
1865 class Suffix(WordInstruction.remap(range(32, 64))):
1866 pass
1867
1868 _: _Field = range(64)
1869 prefix: Prefix
1870 suffix: Suffix
1871 PO: Suffix.PO
1872
1873 @classmethod
1874 def integer(cls, value, byteorder="little"):
1875 return super().integer(bits=64, value=value, byteorder=byteorder)
1876
1877 @classmethod
1878 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1879 def transform(value):
1880 return WordInstruction.integer(value=value,
1881 byteorder=byteorder)[0:32]
1882
1883 (prefix, suffix) = map(transform, (prefix, suffix))
1884 value = _selectconcat(prefix, suffix)
1885
1886 return super().integer(bits=64, value=value)
1887
1888
1889 class Mode(_Mapping):
1890 _: _Field = range(0, 5)
1891 sel: _Field = (0, 1)
1892
1893
1894 class Extra(_Mapping):
1895 _: _Field = range(0, 9)
1896
1897
1898 class Extra2(Extra):
1899 idx0: _Field = range(0, 2)
1900 idx1: _Field = range(2, 4)
1901 idx2: _Field = range(4, 6)
1902 idx3: _Field = range(6, 8)
1903
1904 def __getitem__(self, key):
1905 return {
1906 0: self.idx0,
1907 1: self.idx1,
1908 2: self.idx2,
1909 3: self.idx3,
1910 _SVExtra.Idx0: self.idx0,
1911 _SVExtra.Idx1: self.idx1,
1912 _SVExtra.Idx2: self.idx2,
1913 _SVExtra.Idx3: self.idx3,
1914 }[key]
1915
1916 def __setitem__(self, key, value):
1917 self[key].assign(value)
1918
1919
1920 class Extra3(Extra):
1921 idx0: _Field = range(0, 3)
1922 idx1: _Field = range(3, 6)
1923 idx2: _Field = range(6, 9)
1924
1925 def __getitem__(self, key):
1926 return {
1927 0: self.idx0,
1928 1: self.idx1,
1929 2: self.idx2,
1930 _SVExtra.Idx0: self.idx0,
1931 _SVExtra.Idx1: self.idx1,
1932 _SVExtra.Idx2: self.idx2,
1933 }[key]
1934
1935 def __setitem__(self, key, value):
1936 self[key].assign(value)
1937
1938
1939 class BaseRM(_Mapping):
1940 _: _Field = range(24)
1941 mmode: _Field = (0,)
1942 mask: _Field = range(1, 4)
1943 elwidth: _Field = range(4, 6)
1944 ewsrc: _Field = range(6, 8)
1945 subvl: _Field = range(8, 10)
1946 mode: Mode.remap(range(19, 24))
1947 smask_extra322: _Field = (6,7,18,) # LDST_IDX is EXTRA332
1948 smask: _Field = range(16, 19) # everything else use this
1949 extra: Extra.remap(range(10, 19))
1950 extra2: Extra2.remap(range(10, 19))
1951 extra3: Extra3.remap(range(10, 19))
1952 # XXX extra332 = (extra3[0], extra3[1], extra2[3])
1953
1954 def specifiers(self, record):
1955 subvl = int(self.subvl)
1956 if subvl > 0:
1957 yield {
1958 1: "vec2",
1959 2: "vec3",
1960 3: "vec4",
1961 }[subvl]
1962
1963 def disassemble(self, style=Style.NORMAL):
1964 if style >= Style.VERBOSE:
1965 indent = (" " * 4)
1966 for (name, span) in self.traverse(path="RM"):
1967 value = self.storage[span]
1968 yield f"{name}"
1969 yield f"{indent}{int(value):0{value.bits}b}"
1970 yield f"{indent}{', '.join(map(str, span))}"
1971
1972
1973 class FFRc1BaseRM(BaseRM):
1974 def specifiers(self, record, mode):
1975 inv = _SelectableInt(value=int(self.inv), bits=1)
1976 CR = _SelectableInt(value=int(self.CR), bits=2)
1977 mask = int(_selectconcat(CR, inv))
1978 predicate = PredicateBaseRM.predicate(True, mask)
1979 yield f"{mode}={predicate}"
1980
1981 yield from super().specifiers(record=record)
1982
1983
1984 class FFRc0BaseRM(BaseRM):
1985 def specifiers(self, record, mode):
1986 if self.RC1:
1987 inv = "~" if self.inv else ""
1988 yield f"{mode}={inv}RC1"
1989
1990 yield from super().specifiers(record=record)
1991
1992
1993 class SatBaseRM(BaseRM):
1994 def specifiers(self, record):
1995 if self.N:
1996 yield "sats"
1997 else:
1998 yield "satu"
1999
2000 yield from super().specifiers(record=record)
2001
2002
2003 class ZZBaseRM(BaseRM):
2004 def specifiers(self, record):
2005 if self.zz:
2006 yield "zz"
2007
2008 yield from super().specifiers(record=record)
2009
2010
2011 class ZZCombinedBaseRM(BaseRM):
2012 def specifiers(self, record):
2013 if self.sz and self.dz:
2014 yield "zz"
2015 elif self.sz:
2016 yield "sz"
2017 elif self.dz:
2018 yield "dz"
2019
2020 yield from super().specifiers(record=record)
2021
2022
2023 class DZBaseRM(BaseRM):
2024 def specifiers(self, record):
2025 if self.dz:
2026 yield "dz"
2027
2028 yield from super().specifiers(record=record)
2029
2030
2031 class SZBaseRM(BaseRM):
2032 def specifiers(self, record):
2033 if self.sz:
2034 yield "sz"
2035
2036 yield from super().specifiers(record=record)
2037
2038
2039 class MRBaseRM(BaseRM):
2040 def specifiers(self, record):
2041 if self.RG:
2042 yield "mrr"
2043 else:
2044 yield "mr"
2045
2046 yield from super().specifiers(record=record)
2047
2048
2049 class ElsBaseRM(BaseRM):
2050 def specifiers(self, record):
2051 if self.els:
2052 yield "els"
2053
2054 yield from super().specifiers(record=record)
2055
2056
2057 class WidthBaseRM(BaseRM):
2058 @staticmethod
2059 def width(FP, width):
2060 width = {
2061 0b11: "8",
2062 0b10: "16",
2063 0b01: "32",
2064 }.get(width)
2065 if width is None:
2066 return None
2067 if FP:
2068 width = ("fp" + width)
2069 return width
2070
2071 def specifiers(self, record):
2072 # elwidths: use "w=" if same otherwise dw/sw
2073 # FIXME this should consider FP instructions
2074 FP = False
2075 dw = WidthBaseRM.width(FP, int(self.elwidth))
2076 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2077 if record.svp64.mode is _SVMode.CROP:
2078 if dw:
2079 yield ("dw=" + dw)
2080 else:
2081 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2082 if dw == sw and dw:
2083 yield ("w=" + dw)
2084 else:
2085 if dw:
2086 yield ("dw=" + dw)
2087 if sw:
2088 yield ("sw=" + sw)
2089
2090 yield from super().specifiers(record=record)
2091
2092
2093 class PredicateBaseRM(BaseRM):
2094 @staticmethod
2095 def predicate(CR, mask):
2096 return {
2097 # integer
2098 (False, 0b001): "1<<r3",
2099 (False, 0b010): "r3",
2100 (False, 0b011): "~r3",
2101 (False, 0b100): "r10",
2102 (False, 0b101): "~r10",
2103 (False, 0b110): "r30",
2104 (False, 0b111): "~r30",
2105 # CRs
2106 (True, 0b000): "lt",
2107 (True, 0b001): "ge",
2108 (True, 0b010): "gt",
2109 (True, 0b011): "le",
2110 (True, 0b100): "eq",
2111 (True, 0b101): "ne",
2112 (True, 0b110): "so",
2113 (True, 0b111): "ns",
2114 }.get((CR, mask))
2115
2116 def specifiers(self, record):
2117 # predication - single and twin
2118 # use "m=" if same otherwise sm/dm
2119 CR = (int(self.mmode) == 1)
2120 mask = int(self.mask)
2121 sm = dm = PredicateBaseRM.predicate(CR, mask)
2122 if record.svp64.ptype is _SVPType.P2:
2123 # LDST_IDX smask moving to extra322 but not straight away (False)
2124 if False and record.svp64.mode is _SVMode.LDST_IDX:
2125 smask = int(self.smask_extra332)
2126 else:
2127 smask = int(self.smask)
2128 sm = PredicateBaseRM.predicate(CR, smask)
2129 if sm == dm and dm:
2130 yield ("m=" + dm)
2131 else:
2132 if sm:
2133 yield ("sm=" + sm)
2134 if dm:
2135 yield ("dm=" + dm)
2136
2137 yield from super().specifiers(record=record)
2138
2139
2140 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
2141 pass
2142
2143
2144 class SEABaseRM(BaseRM):
2145 def specifiers(self, record):
2146 if self.SEA:
2147 yield "sea"
2148
2149 yield from super().specifiers(record=record)
2150
2151
2152 class VLiBaseRM(BaseRM):
2153 def specifiers(self, record):
2154 if self.VLi:
2155 yield "vli"
2156
2157 yield from super().specifiers(record=record)
2158
2159
2160 class NormalBaseRM(PredicateWidthBaseRM):
2161 """
2162 Normal mode
2163 https://libre-soc.org/openpower/sv/normal/
2164 """
2165 pass
2166
2167
2168 class NormalSimpleRM(ZZCombinedBaseRM, NormalBaseRM):
2169 """normal: simple mode"""
2170 dz: BaseRM.mode[3]
2171 sz: BaseRM.mode[4]
2172
2173 def specifiers(self, record):
2174 yield from super().specifiers(record=record)
2175
2176
2177 class NormalMRRM(MRBaseRM, NormalBaseRM):
2178 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2179 RG: BaseRM.mode[4]
2180
2181
2182 class NormalFFRc1RM(FFRc1BaseRM, VLiBaseRM, NormalBaseRM):
2183 """normal: Rc=1: ffirst CR sel"""
2184 VLi: BaseRM.mode[0]
2185 inv: BaseRM.mode[2]
2186 CR: BaseRM.mode[3, 4]
2187
2188 def specifiers(self, record):
2189 yield from super().specifiers(record=record, mode="ff")
2190
2191
2192 class NormalFFRc0RM(FFRc0BaseRM, VLiBaseRM, NormalBaseRM):
2193 """normal: Rc=0: ffirst z/nonz"""
2194 VLi: BaseRM.mode[0]
2195 inv: BaseRM.mode[2]
2196 RC1: BaseRM.mode[4]
2197
2198 def specifiers(self, record):
2199 yield from super().specifiers(record=record, mode="ff")
2200
2201
2202 class NormalSatRM(SatBaseRM, ZZCombinedBaseRM, NormalBaseRM):
2203 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2204 N: BaseRM.mode[2]
2205 dz: BaseRM.mode[3]
2206 sz: BaseRM.mode[4]
2207
2208
2209 class NormalRM(NormalBaseRM):
2210 simple: NormalSimpleRM
2211 mr: NormalMRRM
2212 ffrc1: NormalFFRc1RM
2213 ffrc0: NormalFFRc0RM
2214 sat: NormalSatRM
2215
2216
2217 class LDSTImmBaseRM(PredicateWidthBaseRM):
2218 """
2219 LD/ST Immediate mode
2220 https://libre-soc.org/openpower/sv/ldst/
2221 """
2222 pass
2223
2224
2225 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
2226 """ld/st immediate: simple mode"""
2227 pi: BaseRM.mode[2] # Post-Increment Mode
2228 lf: BaseRM.mode[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2229 zz: BaseRM.mode[3]
2230 els: BaseRM.mode[0]
2231 dz: BaseRM.mode[3]
2232 sz: BaseRM.mode[3]
2233
2234 def specifiers(self, record):
2235 if self.pi:
2236 yield "pi"
2237 if self.lf:
2238 yield "lf"
2239
2240 yield from super().specifiers(record=record)
2241
2242
2243 class LDSTFFRc1RM(FFRc1BaseRM, VLiBaseRM, LDSTImmBaseRM):
2244 """ld/st immediate&indexed: Rc=1: ffirst CR sel"""
2245 VLi: BaseRM.mode[0]
2246 inv: BaseRM.mode[2]
2247 CR: BaseRM.mode[3, 4]
2248
2249 def specifiers(self, record):
2250 yield from super().specifiers(record=record, mode="ff")
2251
2252
2253 class LDSTFFRc0RM(FFRc0BaseRM, VLiBaseRM, LDSTImmBaseRM):
2254 """ld/st immediate&indexed: Rc=0: ffirst z/nonz"""
2255 VLi: BaseRM.mode[0]
2256 inv: BaseRM.mode[2]
2257 RC1: BaseRM.mode[4]
2258
2259 def specifiers(self, record):
2260 yield from super().specifiers(record=record, mode="ff")
2261
2262
2263 class LDSTImmRM(LDSTImmBaseRM):
2264 simple: LDSTImmSimpleRM
2265 ffrc1: LDSTFFRc1RM
2266 ffrc0: LDSTFFRc0RM
2267
2268
2269 class LDSTIdxBaseRM(PredicateWidthBaseRM):
2270 """
2271 LD/ST Indexed mode
2272 https://libre-soc.org/openpower/sv/ldst/
2273 """
2274 pass
2275
2276
2277 class LDSTIdxSimpleRM(SEABaseRM, ZZBaseRM, LDSTIdxBaseRM):
2278 """ld/st index: simple mode (includes element-strided and Signed-EA)"""
2279 pi: BaseRM.mode[2] # Post-Increment Mode
2280 els: BaseRM.mode[0]
2281 SEA: BaseRM.mode[4]
2282 zz: BaseRM.mode[3]
2283 dz: BaseRM.mode[3]
2284 sz: BaseRM.mode[3]
2285
2286 def specifiers(self, record):
2287 if self.els:
2288 yield "els"
2289 if self.pi:
2290 yield "pi"
2291
2292 yield from super().specifiers(record=record)
2293
2294
2295 class LDSTIdxRM(LDSTIdxBaseRM):
2296 simple: LDSTIdxSimpleRM
2297 ffrc1: LDSTFFRc1RM
2298 ffrc0: LDSTFFRc0RM
2299
2300
2301
2302 class CROpBaseRM(BaseRM):
2303 """
2304 CR ops mode
2305 https://libre-soc.org/openpower/sv/cr_ops/
2306 """
2307 SNZ: BaseRM[7]
2308
2309
2310 class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2311 """crop: simple mode"""
2312 RG: BaseRM[21]
2313 dz: BaseRM[22]
2314 sz: BaseRM[23]
2315
2316 def specifiers(self, record):
2317 if self.RG:
2318 yield "rg" # simple CR Mode reports /rg
2319
2320 yield from super().specifiers(record=record)
2321
2322
2323 class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2324 """crop: scalar reduce mode (mapreduce)"""
2325 RG: BaseRM[21]
2326 dz: BaseRM[22]
2327 sz: BaseRM[23]
2328
2329
2330 class CROpFF5RM(FFRc0BaseRM, PredicateBaseRM, VLiBaseRM, DZBaseRM,
2331 SZBaseRM, CROpBaseRM):
2332 """crop: ffirst 5-bit mode"""
2333 VLi: BaseRM[19]
2334 RC1 = 1
2335 inv: BaseRM[21]
2336 dz: BaseRM[22]
2337 sz: BaseRM[23]
2338
2339 def specifiers(self, record):
2340 yield from super().specifiers(record=record, mode="ff")
2341
2342
2343 # FIXME: almost everything in this class contradicts the specs (it doesn't)
2344 # The modes however are swapped: 5-bit is 3-bit, 3-bit is 5-bit
2345 class CROpFF3RM(FFRc1BaseRM, PredicateBaseRM, VLiBaseRM, ZZBaseRM, CROpBaseRM):
2346 """cr_op: ffirst 3-bit mode"""
2347 VLi: BaseRM[19]
2348 inv: BaseRM[21]
2349 CR: BaseRM[22, 23]
2350 zz: BaseRM[6]
2351
2352 def specifiers(self, record):
2353 yield from super().specifiers(record=record, mode="ff")
2354
2355
2356 class CROpRM(CROpBaseRM):
2357 simple: CROpSimpleRM
2358 mr: CROpMRRM
2359 ff3: CROpFF3RM
2360 ff5: CROpFF5RM
2361
2362
2363 # ********************
2364 # Branches mode
2365 # https://libre-soc.org/openpower/sv/branches/
2366 class BranchBaseRM(BaseRM):
2367 ALL: BaseRM[4]
2368 SNZ: BaseRM[5]
2369 SL: BaseRM[17]
2370 SLu: BaseRM[18]
2371 LRu: BaseRM[22]
2372 sz: BaseRM[23]
2373 CTR: BaseRM[19]
2374 VLS: BaseRM[20]
2375
2376 def specifiers(self, record):
2377 if self.ALL:
2378 yield "all"
2379
2380 # /sz
2381 # branch.sz=1
2382 # branch.snz=0
2383 # /snz
2384 # branch.sz=1
2385 # branch.snz=1
2386 if self.SNZ:
2387 if not self.sz:
2388 raise ValueError(self.sz)
2389 yield "snz"
2390 elif self.sz:
2391 yield "sz"
2392
2393 if self.SL:
2394 yield "sl"
2395 if self.SLu:
2396 yield "slu"
2397 if self.LRu:
2398 yield "lru"
2399
2400 # Branch modes lack source mask.
2401 # Therefore a custom code is needed.
2402 CR = (int(self.mmode) == 1)
2403 mask = int(self.mask)
2404 m = PredicateBaseRM.predicate(CR, mask)
2405 if m is not None:
2406 yield ("m=" + m)
2407
2408 yield from super().specifiers(record=record)
2409
2410
2411 class BranchSimpleRM(BranchBaseRM):
2412 """branch: simple mode"""
2413 pass
2414
2415
2416 class BranchVLSRM(BranchBaseRM):
2417 """branch: VLSET mode"""
2418 VSb: BaseRM[7]
2419 VLi: BaseRM[21]
2420
2421 def specifiers(self, record):
2422 yield {
2423 (0b0, 0b0): "vs",
2424 (0b0, 0b1): "vsi",
2425 (0b1, 0b0): "vsb",
2426 (0b1, 0b1): "vsbi",
2427 }[int(self.VSb), int(self.VLi)]
2428
2429 yield from super().specifiers(record=record)
2430
2431
2432 class BranchCTRRM(BranchBaseRM):
2433 """branch: CTR-test mode"""
2434 CTi: BaseRM[6]
2435
2436 def specifiers(self, record):
2437 if self.CTi:
2438 yield "cti"
2439 else:
2440 yield "ctr"
2441
2442 yield from super().specifiers(record=record)
2443
2444
2445 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
2446 """branch: CTR-test+VLSET mode"""
2447 pass
2448
2449
2450 class BranchRM(BranchBaseRM):
2451 simple: BranchSimpleRM
2452 vls: BranchVLSRM
2453 ctr: BranchCTRRM
2454 ctrvls: BranchCTRVLSRM
2455
2456
2457 class RM(BaseRM):
2458 normal: NormalRM
2459 ldst_imm: LDSTImmRM
2460 ldst_idx: LDSTIdxRM
2461 crop: CROpRM
2462 branch: BranchRM
2463
2464
2465 @_dataclasses.dataclass(eq=True, frozen=True)
2466 class Specifier:
2467 record: Record
2468
2469 @classmethod
2470 def match(cls, desc, record):
2471 raise NotImplementedError()
2472
2473 def validate(self, others):
2474 pass
2475
2476 def assemble(self, insn):
2477 raise NotImplementedError()
2478
2479
2480 @_dataclasses.dataclass(eq=True, frozen=True)
2481 class SpecifierWidth(Specifier):
2482 width: _SVP64Width
2483
2484 @classmethod
2485 def match(cls, desc, record, etalon):
2486 (mode, _, value) = desc.partition("=")
2487 mode = mode.strip()
2488 value = value.strip()
2489 if mode != etalon:
2490 return None
2491 width = _SVP64Width(value)
2492
2493 return cls(record=record, width=width)
2494
2495
2496 @_dataclasses.dataclass(eq=True, frozen=True)
2497 class SpecifierW(SpecifierWidth):
2498 @classmethod
2499 def match(cls, desc, record):
2500 return super().match(desc=desc, record=record, etalon="w")
2501
2502 def assemble(self, insn):
2503 selector = insn.select(record=self.record)
2504 if self.record.svp64.mode is not _SVMode.CROP:
2505 selector.ewsrc = self.width.value
2506 selector.elwidth = self.width.value
2507
2508
2509 @_dataclasses.dataclass(eq=True, frozen=True)
2510 class SpecifierSW(SpecifierWidth):
2511 @classmethod
2512 def match(cls, desc, record):
2513 if record.svp64.mode is _SVMode.CROP:
2514 return None
2515 return super().match(desc=desc, record=record, etalon="sw")
2516
2517 def assemble(self, insn):
2518 selector = insn.select(record=self.record)
2519 selector.ewsrc = self.width.value
2520
2521
2522 @_dataclasses.dataclass(eq=True, frozen=True)
2523 class SpecifierDW(SpecifierWidth):
2524 @classmethod
2525 def match(cls, desc, record):
2526 return super().match(desc=desc, record=record, etalon="dw")
2527
2528 def assemble(self, insn):
2529 selector = insn.select(record=self.record)
2530 selector.elwidth = self.width.value
2531
2532
2533 @_dataclasses.dataclass(eq=True, frozen=True)
2534 class SpecifierSubVL(Specifier):
2535 value: _SVP64SubVL
2536
2537 @classmethod
2538 def match(cls, desc, record):
2539 try:
2540 value = _SVP64SubVL(desc)
2541 except ValueError:
2542 return None
2543
2544 return cls(record=record, value=value)
2545
2546 def assemble(self, insn):
2547 selector = insn.select(record=self.record)
2548 selector.subvl = int(self.value.value)
2549
2550
2551 @_dataclasses.dataclass(eq=True, frozen=True)
2552 class SpecifierPredicate(Specifier):
2553 mode: str
2554 pred: _SVP64Pred
2555
2556 @classmethod
2557 def match(cls, desc, record, mode_match, pred_match):
2558 (mode, _, pred) = desc.partition("=")
2559
2560 mode = mode.strip()
2561 if not mode_match(mode):
2562 return None
2563
2564 pred = _SVP64Pred(pred.strip())
2565 if not pred_match(pred):
2566 raise ValueError(pred)
2567
2568 return cls(record=record, mode=mode, pred=pred)
2569
2570
2571 @_dataclasses.dataclass(eq=True, frozen=True)
2572 class SpecifierFF(SpecifierPredicate):
2573 @classmethod
2574 def match(cls, desc, record):
2575 return super().match(desc=desc, record=record,
2576 mode_match=lambda mode_arg: mode_arg == "ff",
2577 pred_match=lambda pred_arg: pred_arg.mode in (
2578 _SVP64PredMode.CR,
2579 _SVP64PredMode.RC1,
2580 ))
2581
2582 def assemble(self, insn):
2583 selector = insn.select(record=self.record)
2584 if selector.mode.sel != 0:
2585 raise ValueError("cannot override mode")
2586 if self.record.svp64.mode is _SVMode.CROP:
2587 selector.mode.sel = 0b01
2588 # HACK: please finally provide correct logic for CRs.
2589 if self.pred in (_SVP64Pred.RC1, _SVP64Pred.RC1_N):
2590 selector.mode[2] = (self.pred is _SVP64Pred.RC1_N)
2591 else:
2592 selector.mode[2] = self.pred.inv
2593 selector.mode[3, 4] = self.pred.state
2594 else:
2595 selector.mode.sel = 0b01 if self.mode == "ff" else 0b11
2596 selector.inv = self.pred.inv
2597 if self.record.Rc:
2598 selector.CR = self.pred.state
2599 else:
2600 selector.RC1 = self.pred.state
2601
2602
2603 @_dataclasses.dataclass(eq=True, frozen=True)
2604 class SpecifierMask(SpecifierPredicate):
2605 @classmethod
2606 def match(cls, desc, record, mode):
2607 return super().match(desc=desc, record=record,
2608 mode_match=lambda mode_arg: mode_arg == mode,
2609 pred_match=lambda pred_arg: pred_arg.mode in (
2610 _SVP64PredMode.INT,
2611 _SVP64PredMode.CR,
2612 ))
2613
2614 def assemble(self, insn):
2615 raise NotImplementedError()
2616
2617
2618 @_dataclasses.dataclass(eq=True, frozen=True)
2619 class SpecifierM(SpecifierMask):
2620 @classmethod
2621 def match(cls, desc, record):
2622 return super().match(desc=desc, record=record, mode="m")
2623
2624 def validate(self, others):
2625 for spec in others:
2626 if isinstance(spec, SpecifierSM):
2627 raise ValueError("source-mask and predicate mask conflict")
2628 elif isinstance(spec, SpecifierDM):
2629 raise ValueError("dest-mask and predicate mask conflict")
2630
2631 def assemble(self, insn):
2632 selector = insn.select(record=self.record)
2633 selector.mask = int(self.pred)
2634 if ((self.record.ptype is _SVPType.P2) and
2635 (self.record.svp64.mode is not _SVMode.BRANCH)):
2636 selector.smask = int(self.pred)
2637 # LDST_IDX smask moving to extra322 but not straight away (False)
2638 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2639 selector.smask_extra332 = int(self.pred)
2640 else:
2641 selector.smask = int(self.pred)
2642
2643 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2644
2645
2646 @_dataclasses.dataclass(eq=True, frozen=True)
2647 class SpecifierSM(SpecifierMask):
2648 @classmethod
2649 def match(cls, desc, record):
2650 return super().match(desc=desc, record=record, mode="sm")
2651
2652 def validate(self, others):
2653 if self.record.svp64.ptype is _SVPType.P1:
2654 raise ValueError("source-mask on non-twin predicate")
2655
2656 if self.pred.mode is _SVP64PredMode.CR:
2657 twin = None
2658 for spec in others:
2659 if isinstance(spec, SpecifierDM):
2660 twin = spec
2661
2662 if twin is None:
2663 raise ValueError("missing dest-mask in CR twin predication")
2664 if self.pred.mode != twin.pred.mode:
2665 raise ValueError(f"predicate masks mismatch: "
2666 f"{self.pred!r} vs {twin.pred!r}")
2667
2668 def assemble(self, insn):
2669 selector = insn.select(record=self.record)
2670 # LDST_IDX smask moving to extra322 but not straight away (False)
2671 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2672 selector.smask_extra332 = int(self.pred)
2673 else:
2674 selector.smask = int(self.pred)
2675 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2676
2677
2678 @_dataclasses.dataclass(eq=True, frozen=True)
2679 class SpecifierDM(SpecifierMask):
2680 @classmethod
2681 def match(cls, desc, record):
2682 return super().match(desc=desc, record=record, mode="dm")
2683
2684 def validate(self, others):
2685 if self.record.svp64.ptype is _SVPType.P1:
2686 raise ValueError("dest-mask on non-twin predicate")
2687
2688 if self.pred.mode is _SVP64PredMode.CR:
2689 twin = None
2690 for spec in others:
2691 if isinstance(spec, SpecifierSM):
2692 twin = spec
2693
2694 if twin is None:
2695 raise ValueError("missing source-mask in CR twin predication")
2696 if self.pred.mode != twin.pred.mode:
2697 raise ValueError(f"predicate masks mismatch: "
2698 f"{self.pred!r} vs {twin.pred!r}")
2699
2700 def assemble(self, insn):
2701 selector = insn.select(record=self.record)
2702 selector.mask = int(self.pred)
2703 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2704
2705
2706 @_dataclasses.dataclass(eq=True, frozen=True)
2707 class SpecifierZZ(Specifier):
2708 @classmethod
2709 def match(cls, desc, record):
2710 if desc != "zz":
2711 return None
2712
2713 return cls(record=record)
2714
2715 def validate(self, others):
2716 for spec in others:
2717 # Since zz takes precedence (overrides) sz and dz,
2718 # treat them as mutually exclusive.
2719 if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
2720 raise ValueError("mutually exclusive predicate masks")
2721
2722 def assemble(self, insn):
2723 selector = insn.select(record=self.record)
2724 if hasattr(selector, "zz"): # this should be done in a different way
2725 selector.zz = 1
2726 else:
2727 selector.sz = 1
2728 selector.dz = 1
2729
2730
2731 @_dataclasses.dataclass(eq=True, frozen=True)
2732 class SpecifierXZ(Specifier):
2733 desc: str
2734 hint: str = _dataclasses.field(repr=False)
2735
2736 @classmethod
2737 def match(cls, desc, record, etalon, hint):
2738 if desc != etalon:
2739 return None
2740
2741 return cls(desc=desc, record=record, hint=hint)
2742
2743 def validate(self, others):
2744 if self.record.svp64.ptype is _SVPType.P1:
2745 raise ValueError(f"{self.hint} on non-twin predicate")
2746
2747 if self.pred.mode is _SVP64PredMode.CR:
2748 twin = None
2749 for spec in others:
2750 if isinstance(spec, SpecifierXZ):
2751 twin = spec
2752
2753 if twin is None:
2754 raise ValueError(f"missing {self.hint} in CR twin predication")
2755 if self.pred != twin.pred:
2756 raise ValueError(f"predicate masks mismatch: "
2757 f"{self.pred!r} vs {twin.pred!r}")
2758
2759 def assemble(self, insn):
2760 selector = insn.select(record=self.record)
2761 setattr(selector, self.desc, 1)
2762
2763
2764 @_dataclasses.dataclass(eq=True, frozen=True)
2765 class SpecifierSZ(SpecifierXZ):
2766 @classmethod
2767 def match(cls, desc, record):
2768 return super().match(desc=desc, record=record,
2769 etalon="sz", hint="source-mask")
2770
2771 def validate(self, others):
2772 for spec in others:
2773 if self.record.svp64.mode is not _SVMode.CROP:
2774 if isinstance(spec, SpecifierFF):
2775 raise ValueError("source-zero not allowed in ff mode")
2776
2777
2778 @_dataclasses.dataclass(eq=True, frozen=True)
2779 class SpecifierDZ(SpecifierXZ):
2780 @classmethod
2781 def match(cls, desc, record):
2782 return super().match(desc=desc, record=record,
2783 etalon="dz", hint="dest-mask")
2784
2785 def validate(self, others):
2786 for spec in others:
2787 if ((self.record.svp64.mode is not _SVMode.CROP) and
2788 isinstance(spec, SpecifierFF) and
2789 (spec.pred.mode is _SVP64PredMode.RC1)):
2790 raise ValueError(f"dest-zero not allowed in ff mode BO")
2791
2792
2793 @_dataclasses.dataclass(eq=True, frozen=True)
2794 class SpecifierEls(Specifier):
2795 @classmethod
2796 def match(cls, desc, record):
2797 if desc != "els":
2798 return None
2799
2800 if record.svp64.mode not in (_SVMode.LDST_IMM, _SVMode.LDST_IDX):
2801 raise ValueError("els is only valid in ld/st modes, not "
2802 "%s" % str(self.record.svp64.mode))
2803
2804 return cls(record=record)
2805
2806 def assemble(self, insn):
2807 if self.record.svp64.mode is _SVMode.LDST_IDX: # stride mode
2808 insn.prefix.rm.mode[1] = 0
2809
2810 selector = insn.select(record=self.record)
2811 selector.els = 1
2812
2813
2814
2815 @_dataclasses.dataclass(eq=True, frozen=True)
2816 class SpecifierSEA(Specifier):
2817 @classmethod
2818 def match(cls, desc, record):
2819 if desc != "sea":
2820 return None
2821
2822 return cls(record=record)
2823
2824 def validate(self, others):
2825 if self.record.svp64.mode is not _SVMode.LDST_IDX:
2826 raise ValueError("sea is only valid in ld/st modes, not "
2827 "%s" % str(self.record.svp64.mode))
2828
2829 for spec in others:
2830 if isinstance(spec, SpecifierFF):
2831 raise ValueError(f"sea cannot be used in ff mode")
2832
2833 def assemble(self, insn):
2834 selector = insn.select(record=self.record)
2835 if selector.mode.sel not in (0b10, 0b00):
2836 raise ValueError("sea is only valid for normal and els modes, "
2837 "not %d" % int(selector.mode.sel))
2838 selector.SEA = 1
2839
2840
2841 @_dataclasses.dataclass(eq=True, frozen=True)
2842 class SpecifierSat(Specifier):
2843 desc: str
2844 sign: bool
2845
2846 @classmethod
2847 def match(cls, desc, record, etalon, sign):
2848 if desc != etalon:
2849 return None
2850
2851 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.LDST_IMM,
2852 _SVMode.LDST_IDX):
2853 raise ValueError("only normal, ld/st imm and "
2854 "ld/st idx modes supported")
2855
2856 return cls(record=record, desc=desc, sign=sign)
2857
2858 def assemble(self, insn):
2859 selector = insn.select(record=self.record)
2860 selector.mode[0] = 0b1
2861 selector.mode[1] = 0b0
2862 selector.N = int(self.sign)
2863
2864
2865 @_dataclasses.dataclass(eq=True, frozen=True)
2866 class SpecifierSatS(SpecifierSat):
2867 @classmethod
2868 def match(cls, desc, record):
2869 return super().match(desc=desc, record=record,
2870 etalon="sats", sign=True)
2871
2872
2873 @_dataclasses.dataclass(eq=True, frozen=True)
2874 class SpecifierSatU(SpecifierSat):
2875 @classmethod
2876 def match(cls, desc, record):
2877 return super().match(desc=desc, record=record,
2878 etalon="satu", sign=False)
2879
2880
2881 @_dataclasses.dataclass(eq=True, frozen=True)
2882 class SpecifierMapReduce(Specifier):
2883 RG: bool
2884
2885 @classmethod
2886 def match(cls, record, RG):
2887 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2888 raise ValueError("only normal and crop modes supported")
2889
2890 return cls(record=record, RG=RG)
2891
2892 def assemble(self, insn):
2893 selector = insn.select(record=self.record)
2894 if self.record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2895 raise ValueError("only normal and crop modes supported")
2896 selector.mode[0] = 0
2897 selector.mode[1] = 0
2898 selector.mode[2] = 1
2899 selector.RG = self.RG
2900
2901
2902 @_dataclasses.dataclass(eq=True, frozen=True)
2903 class SpecifierMR(SpecifierMapReduce):
2904 @classmethod
2905 def match(cls, desc, record):
2906 if desc != "mr":
2907 return None
2908
2909 return super().match(record=record, RG=False)
2910
2911
2912 @_dataclasses.dataclass(eq=True, frozen=True)
2913 class SpecifierMRR(SpecifierMapReduce):
2914 @classmethod
2915 def match(cls, desc, record):
2916 if desc != "mrr":
2917 return None
2918
2919 return super().match(record=record, RG=True)
2920
2921
2922 @_dataclasses.dataclass(eq=True, frozen=True)
2923 class SpecifierBranch(Specifier):
2924 @classmethod
2925 def match(cls, desc, record, etalon):
2926 if desc != etalon:
2927 return None
2928
2929 if record.svp64.mode is not _SVMode.BRANCH:
2930 raise ValueError("only branch modes supported")
2931
2932 return cls(record=record)
2933
2934
2935 @_dataclasses.dataclass(eq=True, frozen=True)
2936 class SpecifierAll(SpecifierBranch):
2937 @classmethod
2938 def match(cls, desc, record):
2939 return super().match(desc=desc, record=record, etalon="all")
2940
2941 def assemble(self, insn):
2942 selector = insn.select(record=self.record)
2943 selector.ALL = 1
2944
2945
2946 @_dataclasses.dataclass(eq=True, frozen=True)
2947 class SpecifierSNZ(Specifier):
2948 @classmethod
2949 def match(cls, desc, record):
2950 if desc != "snz":
2951 return None
2952
2953 if record.svp64.mode not in (_SVMode.BRANCH, _SVMode.CROP):
2954 raise ValueError("only branch and crop modes supported")
2955
2956 return cls(record=record)
2957
2958 def assemble(self, insn):
2959 selector = insn.select(record=self.record)
2960 if self.record.svp64.mode in (_SVMode.CROP, _SVMode.BRANCH):
2961 selector.SNZ = 1
2962 if self.record.svp64.mode is _SVMode.BRANCH:
2963 selector.sz = 1
2964 else:
2965 raise ValueError("only branch and crop modes supported")
2966
2967
2968 @_dataclasses.dataclass(eq=True, frozen=True)
2969 class SpecifierSL(SpecifierBranch):
2970 @classmethod
2971 def match(cls, desc, record):
2972 return super().match(desc=desc, record=record, etalon="sl")
2973
2974 def assemble(self, insn):
2975 selector = insn.select(record=self.record)
2976 selector.SL = 1
2977
2978
2979 @_dataclasses.dataclass(eq=True, frozen=True)
2980 class SpecifierSLu(SpecifierBranch):
2981 @classmethod
2982 def match(cls, desc, record):
2983 return super().match(desc=desc, record=record, etalon="slu")
2984
2985 def assemble(self, insn):
2986 selector = insn.select(record=self.record)
2987 selector.SLu = 1
2988
2989
2990 @_dataclasses.dataclass(eq=True, frozen=True)
2991 class SpecifierLRu(SpecifierBranch):
2992 @classmethod
2993 def match(cls, desc, record):
2994 return super().match(desc=desc, record=record, etalon="lru")
2995
2996 def assemble(self, insn):
2997 selector = insn.select(record=self.record)
2998 selector.LRu = 1
2999
3000
3001 @_dataclasses.dataclass(eq=True, frozen=True)
3002 class SpecifierVSXX(SpecifierBranch):
3003 VSb: bool
3004 VLi: bool
3005
3006 @classmethod
3007 def match(cls, desc, record, etalon, VSb, VLi):
3008 if desc != etalon:
3009 return None
3010
3011 if record.svp64.mode is not _SVMode.BRANCH:
3012 raise ValueError("only branch modes supported")
3013
3014 return cls(record=record, VSb=VSb, VLi=VLi)
3015
3016 def assemble(self, insn):
3017 selector = insn.select(record=self.record)
3018 selector.VLS = 1
3019 selector.VSb = int(self.VSb)
3020 selector.VLi = int(self.VLi)
3021
3022
3023 @_dataclasses.dataclass(eq=True, frozen=True)
3024 class SpecifierVS(SpecifierVSXX):
3025 @classmethod
3026 def match(cls, desc, record):
3027 return super().match(desc=desc, record=record,
3028 etalon="vs", VSb=False, VLi=False)
3029
3030
3031 @_dataclasses.dataclass(eq=True, frozen=True)
3032 class SpecifierVSi(SpecifierVSXX):
3033 @classmethod
3034 def match(cls, desc, record):
3035 return super().match(desc=desc, record=record,
3036 etalon="vsi", VSb=False, VLi=True)
3037
3038
3039 @_dataclasses.dataclass(eq=True, frozen=True)
3040 class SpecifierVSb(SpecifierVSXX):
3041 @classmethod
3042 def match(cls, desc, record):
3043 return super().match(desc=desc, record=record,
3044 etalon="vsb", VSb=True, VLi=False)
3045
3046
3047 @_dataclasses.dataclass(eq=True, frozen=True)
3048 class SpecifierVSbi(SpecifierVSXX):
3049 @classmethod
3050 def match(cls, desc, record):
3051 return super().match(desc=desc, record=record,
3052 etalon="vsbi", VSb=True, VLi=True)
3053
3054
3055 @_dataclasses.dataclass(eq=True, frozen=True)
3056 class SpecifierCTX(Specifier):
3057 CTi: bool
3058
3059 @classmethod
3060 def match(cls, desc, record, etalon, CTi):
3061 if desc != etalon:
3062 return None
3063
3064 if record.svp64.mode is not _SVMode.BRANCH:
3065 raise ValueError("only branch modes supported")
3066
3067 return cls(record=record, CTi=CTi)
3068
3069 def assemble(self, insn):
3070 selector = insn.select(record=self.record)
3071 selector.CTR = 1
3072 selector.CTi = int(self.CTi)
3073
3074
3075 @_dataclasses.dataclass(eq=True, frozen=True)
3076 class SpecifierCTR(SpecifierCTX):
3077 @classmethod
3078 def match(cls, desc, record):
3079 return super().match(desc=desc, record=record,
3080 etalon="ctr", CTi=False)
3081
3082
3083 @_dataclasses.dataclass(eq=True, frozen=True)
3084 class SpecifierCTi(SpecifierCTX):
3085 @classmethod
3086 def match(cls, desc, record):
3087 return super().match(desc=desc, record=record,
3088 etalon="cti", CTi=True)
3089
3090
3091 @_dataclasses.dataclass(eq=True, frozen=True)
3092 class SpecifierPI(Specifier):
3093 @classmethod
3094 def match(cls, desc, record):
3095 if desc != "pi":
3096 return None
3097
3098 if record.svp64.mode not in [_SVMode.LDST_IMM, _SVMode.LDST_IDX]:
3099 raise ValueError("only ld/st imm/idx mode supported")
3100
3101 return cls(record=record)
3102
3103 def assemble(self, insn):
3104 selector = insn.select(record=self.record)
3105 selector.mode[2] = 0b1
3106 selector.pi = 0b1
3107
3108
3109 @_dataclasses.dataclass(eq=True, frozen=True)
3110 class SpecifierLF(Specifier):
3111 @classmethod
3112 def match(cls, desc, record):
3113 if desc != "lf":
3114 return None
3115
3116 if record.svp64.mode is not _SVMode.LDST_IMM:
3117 raise ValueError("only ld/st imm mode supported")
3118
3119 return cls(record=record)
3120
3121 def assemble(self, insn):
3122 selector = insn.select(record=self.record)
3123 selector.mode[1] = 0
3124 selector.lf = 0b1
3125
3126
3127 @_dataclasses.dataclass(eq=True, frozen=True)
3128 class SpecifierVLi(Specifier):
3129 @classmethod
3130 def match(cls, desc, record):
3131 if desc != "vli":
3132 return None
3133
3134 return cls(record=record)
3135
3136 def validate(self, others):
3137 for spec in others:
3138 if isinstance(spec, SpecifierFF):
3139 return
3140
3141 raise ValueError("VLi only allowed in failfirst")
3142
3143 def assemble(self, insn):
3144 selector = insn.select(record=self.record)
3145 selector.mode[1] = 1
3146 selector.VLi = 1
3147
3148
3149 class Specifiers(tuple):
3150 SPECS = (
3151 SpecifierW,
3152 SpecifierSW,
3153 SpecifierDW,
3154 SpecifierSubVL,
3155 SpecifierFF,
3156 SpecifierM,
3157 SpecifierSM,
3158 SpecifierDM,
3159 SpecifierZZ,
3160 SpecifierSZ,
3161 SpecifierDZ,
3162 SpecifierEls,
3163 SpecifierSEA,
3164 SpecifierSatS,
3165 SpecifierSatU,
3166 SpecifierMR,
3167 SpecifierMRR,
3168 SpecifierAll,
3169 SpecifierSNZ,
3170 SpecifierSL,
3171 SpecifierSLu,
3172 SpecifierLRu,
3173 SpecifierVS,
3174 SpecifierVSi,
3175 SpecifierVSb,
3176 SpecifierVSbi,
3177 SpecifierVLi,
3178 SpecifierCTR,
3179 SpecifierCTi,
3180 SpecifierPI,
3181 SpecifierLF,
3182 )
3183
3184 def __new__(cls, items, record):
3185 def transform(item):
3186 for spec_cls in cls.SPECS:
3187 spec = spec_cls.match(item, record=record)
3188 if spec is not None:
3189 return spec
3190 raise ValueError(item)
3191
3192 # TODO: remove this hack
3193 items = dict.fromkeys(items)
3194 if "vli" in items:
3195 del items["vli"]
3196 items["vli"] = None
3197 items = tuple(items)
3198
3199 specs = tuple(map(transform, items))
3200 for (index, spec) in enumerate(specs):
3201 head = specs[:index]
3202 tail = specs[index + 1:]
3203 spec.validate(others=(head + tail))
3204
3205 return super().__new__(cls, specs)
3206
3207
3208 class SVP64OperandMeta(type):
3209 class SVP64NonZeroOperand(NonZeroOperand):
3210 def assemble(self, insn, value):
3211 if isinstance(value, str):
3212 value = int(value, 0)
3213 if not isinstance(value, int):
3214 raise ValueError("non-integer operand")
3215
3216 # FIXME: this is really weird
3217 if self.record.name in ("svstep", "svstep."):
3218 value += 1 # compensation
3219
3220 return super().assemble(value=value, insn=insn)
3221
3222 class SVP64XOStaticOperand(SpanStaticOperand):
3223 def __init__(self, record, value, span):
3224 return super().__init__(record=record, name="XO",
3225 value=value, span=span)
3226
3227 __TRANSFORM = {
3228 NonZeroOperand: SVP64NonZeroOperand,
3229 XOStaticOperand: SVP64XOStaticOperand,
3230 }
3231
3232 def __new__(metacls, name, bases, ns):
3233 bases = list(bases)
3234 for (index, base_cls) in enumerate(bases):
3235 bases[index] = metacls.__TRANSFORM.get(base_cls, base_cls)
3236
3237 bases = tuple(bases)
3238
3239 return super().__new__(metacls, name, bases, ns)
3240
3241
3242 class SVP64Operand(Operand, metaclass=SVP64OperandMeta):
3243 @property
3244 def span(self):
3245 return tuple(map(lambda bit: (bit + 32), super().span))
3246
3247
3248 class RMSelector:
3249 def __init__(self, insn, record):
3250 self.__insn = insn
3251 self.__record = record
3252 return super().__init__()
3253
3254 def __str__(self):
3255 return self.rm.__doc__
3256
3257 def __repr__(self):
3258 return repr(self.rm)
3259
3260 @property
3261 def insn(self):
3262 return self.__insn
3263
3264 @property
3265 def record(self):
3266 return self.__record
3267
3268 @property
3269 def rm(self):
3270 rm = getattr(self.insn.prefix.rm, self.record.svp64.mode.name.lower())
3271
3272 # The idea behind these tables is that they are now literally
3273 # in identical format to insndb.csv and minor_xx.csv and can
3274 # be done precisely as that. The only thing to watch out for
3275 # is the insertion of Rc=1 as a "mask/value" bit and likewise
3276 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
3277 # as the LSB.
3278 table = None
3279 if self.record.svp64.mode is _SVMode.NORMAL:
3280 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3281 # mode Rc mask Rc member
3282 table = (
3283 (0b000000, 0b111000, "simple"), # simple (no Rc)
3284 (0b001000, 0b111100, "mr"), # mapreduce (no Rc)
3285 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3286 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3287 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3288 (0b001100, 0b111100, "rsvd"), # reserved
3289 )
3290 mode = int(self.insn.prefix.rm.normal.mode)
3291 search = ((mode << 1) | self.record.Rc)
3292
3293 elif self.record.svp64.mode is _SVMode.LDST_IMM:
3294 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3295 # mode Rc mask Rc member
3296 # ironically/coincidentally this table is identical to NORMAL
3297 # mode except reserved in place of mr
3298 table = (
3299 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3300 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3301 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3302 )
3303 search = ((int(self.insn.prefix.rm.ldst_imm.mode) << 1) |
3304 self.record.Rc)
3305
3306 elif self.record.svp64.mode is _SVMode.LDST_IDX:
3307 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3308 # mode Rc mask Rc member
3309 table = (
3310 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3311 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3312 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3313 )
3314 search = ((int(self.insn.prefix.rm.ldst_idx.mode) << 1) |
3315 self.record.Rc)
3316
3317 elif self.record.svp64.mode is _SVMode.CROP:
3318 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
3319 # mode 3b mask 3b member
3320 table = (
3321 (0b000000, 0b111000, "simple"), # simple
3322 (0b001000, 0b111000, "mr"), # mapreduce
3323 (0b010001, 0b010001, "ff3"), # ffirst, 3-bit CR
3324 (0b010000, 0b010000, "ff5"), # ffirst, 5-bit CR
3325 )
3326 search = ((int(self.insn.prefix.rm.crop.mode) << 1) |
3327 int(self.record.svp64.extra_CR_3bit))
3328
3329 elif self.record.svp64.mode is _SVMode.BRANCH:
3330 # just mode 2-bit
3331 # mode mask member
3332 table = (
3333 (0b00, 0b11, "simple"), # simple
3334 (0b01, 0b11, "vls"), # VLset
3335 (0b10, 0b11, "ctr"), # CTR mode
3336 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
3337 )
3338 # slightly weird: doesn't have a 5-bit "mode" field like others
3339 search = int(self.insn.prefix.rm.branch.mode.sel)
3340
3341 # look up in table
3342 if table is not None:
3343 for (value, mask, field) in table:
3344 if field.startswith("rsvd"):
3345 continue
3346 if ((value & mask) == (search & mask)):
3347 return getattr(rm, field)
3348
3349 return rm
3350
3351 def __getattr__(self, key):
3352 if key.startswith(f"_{self.__class__.__name__}__"):
3353 return super().__getattribute__(key)
3354
3355 return getattr(self.rm, key)
3356
3357 def __setattr__(self, key, value):
3358 if key.startswith(f"_{self.__class__.__name__}__"):
3359 return super().__setattr__(key, value)
3360
3361 rm = self.rm
3362 if not hasattr(rm, key):
3363 raise AttributeError(key)
3364
3365 return setattr(rm, key, value)
3366
3367
3368 class SVP64Instruction(PrefixedInstruction):
3369 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3370 class Prefix(PrefixedInstruction.Prefix):
3371 id: _Field = (7, 9)
3372 rm: RM.remap((6, 8) + tuple(range(10, 32)))
3373
3374 prefix: Prefix
3375
3376 def select(self, record):
3377 return RMSelector(insn=self, record=record)
3378
3379 @property
3380 def binary(self):
3381 bits = []
3382 for idx in range(64):
3383 bit = int(self[idx])
3384 bits.append(bit)
3385 return "".join(map(str, bits))
3386
3387 @classmethod
3388 def assemble(cls, record, arguments=None, specifiers=None):
3389 insn = super().assemble(record=record, arguments=arguments)
3390
3391 specifiers = Specifiers(items=specifiers, record=record)
3392 for specifier in specifiers:
3393 specifier.assemble(insn=insn)
3394
3395 insn.prefix.PO = 0x1
3396 insn.prefix.id = 0x3
3397
3398 return insn
3399
3400 def disassemble(self, record,
3401 byteorder="little",
3402 style=Style.NORMAL):
3403 def blob(insn):
3404 if style <= Style.SHORT:
3405 return ""
3406 else:
3407 blob = insn.bytes(byteorder=byteorder)
3408 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
3409 return f"{blob} "
3410
3411 blob_prefix = blob(self.prefix)
3412 blob_suffix = blob(self.suffix)
3413 if record is None:
3414 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3415 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
3416 return
3417
3418 assert record.svp64 is not None
3419
3420 name = f"sv.{record.name}"
3421
3422 rm = self.select(record=record)
3423
3424 # convert specifiers to /x/y/z (sorted lexicographically)
3425 specifiers = sorted(rm.specifiers(record=record))
3426 if specifiers: # if any add one extra to get the extra "/"
3427 specifiers = ([""] + specifiers)
3428 specifiers = "/".join(specifiers)
3429
3430 # convert operands to " ,x,y,z"
3431 operands = tuple(map(_operator.itemgetter(1),
3432 self.spec_dynamic_operands(record=record, style=style)))
3433 operands = ",".join(operands)
3434 if len(operands) > 0: # if any separate with a space
3435 operands = (" " + operands)
3436
3437 if style <= Style.LEGACY:
3438 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3439 suffix = WordInstruction.integer(value=int(self.suffix))
3440 yield from suffix.disassemble(record=record,
3441 byteorder=byteorder, style=style)
3442 else:
3443 yield f"{blob_prefix}{name}{specifiers}{operands}"
3444 if blob_suffix:
3445 yield f"{blob_suffix}"
3446
3447 if style >= Style.VERBOSE:
3448 indent = (" " * 4)
3449 binary = self.binary
3450 spec = self.spec(record=record, prefix="sv.")
3451
3452 yield f"{indent}spec"
3453 yield f"{indent}{indent}{spec}"
3454 yield f"{indent}pcode"
3455 for stmt in record.mdwn.pcode:
3456 yield f"{indent}{indent}{stmt}"
3457 yield f"{indent}binary"
3458 yield f"{indent}{indent}[0:8] {binary[0:8]}"
3459 yield f"{indent}{indent}[8:16] {binary[8:16]}"
3460 yield f"{indent}{indent}[16:24] {binary[16:24]}"
3461 yield f"{indent}{indent}[24:32] {binary[24:32]}"
3462 yield f"{indent}{indent}[32:40] {binary[32:40]}"
3463 yield f"{indent}{indent}[40:48] {binary[40:48]}"
3464 yield f"{indent}{indent}[48:56] {binary[48:56]}"
3465 yield f"{indent}{indent}[56:64] {binary[56:64]}"
3466 yield f"{indent}opcodes"
3467 for opcode in record.opcodes:
3468 yield f"{indent}{indent}{opcode!r}"
3469 for operand in self.operands(record=record):
3470 yield from operand.disassemble(insn=self,
3471 style=style, indent=indent)
3472 yield f"{indent}RM"
3473 yield f"{indent}{indent}{str(rm)}"
3474 for line in rm.disassemble(style=style):
3475 yield f"{indent}{indent}{line}"
3476 yield ""
3477
3478 @classmethod
3479 def operands(cls, record):
3480 for operand in super().operands(record=record):
3481 parent = operand.__class__
3482 name = f"SVP64{parent.__name__}"
3483 bases = (SVP64Operand, parent)
3484 child = type(name, bases, {})
3485 yield child(**dict(operand))
3486
3487
3488 def parse(stream, factory):
3489 def match(entry):
3490 return ("TODO" not in frozenset(entry.values()))
3491
3492 lines = filter(lambda line: not line.strip().startswith("#"), stream)
3493 entries = _csv.DictReader(lines)
3494 entries = filter(match, entries)
3495 return tuple(map(factory, entries))
3496
3497
3498 class MarkdownDatabase:
3499 def __init__(self):
3500 db = {}
3501 for (name, desc) in _ISA():
3502 operands = []
3503 if desc.regs:
3504 (dynamic, *static) = desc.regs
3505 operands.extend(dynamic)
3506 operands.extend(static)
3507 pcode = PCode(iterable=filter(str.strip, desc.pcode))
3508 operands = Operands(insn=name, operands=operands)
3509 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
3510
3511 self.__db = dict(sorted(db.items()))
3512
3513 return super().__init__()
3514
3515 def __iter__(self):
3516 yield from self.__db.items()
3517
3518 def __contains__(self, key):
3519 return self.__db.__contains__(key)
3520
3521 def __getitem__(self, key):
3522 return self.__db.__getitem__(key)
3523
3524
3525 class FieldsDatabase:
3526 def __init__(self):
3527 db = {}
3528 df = _DecodeFields()
3529 df.create_specs()
3530 for (form, fields) in df.instrs.items():
3531 if form in {"DQE", "TX"}:
3532 continue
3533 if form == "all":
3534 form = "NONE"
3535 db[_Form[form]] = Fields(fields)
3536
3537 self.__db = db
3538
3539 return super().__init__()
3540
3541 def __getitem__(self, key):
3542 return self.__db.__getitem__(key)
3543
3544
3545 class PPCDatabase:
3546 def __init__(self, root, mdwndb):
3547 # The code below groups the instructions by name:section.
3548 # There can be multiple names for the same instruction.
3549 # The point is to capture different opcodes for the same instruction.
3550 sections = {}
3551 records = _collections.defaultdict(set)
3552 path = (root / "insndb.csv")
3553 with open(path, "r", encoding="UTF-8") as stream:
3554 for section in sorted(parse(stream, Section.CSV)):
3555 path = (root / section.path)
3556 opcode_cls = {
3557 section.Mode.INTEGER: IntegerOpcode,
3558 section.Mode.PATTERN: PatternOpcode,
3559 }[section.mode]
3560 factory = _functools.partial(
3561 PPCRecord.CSV, opcode_cls=opcode_cls)
3562 with open(path, "r", encoding="UTF-8") as stream:
3563 for insn in parse(stream, factory):
3564 for name in insn.names:
3565 records[name].add(insn)
3566 sections[name] = section
3567
3568 items = sorted(records.items())
3569 records = {}
3570 for (name, multirecord) in items:
3571 records[name] = PPCMultiRecord(sorted(multirecord))
3572
3573 def exact_match(name):
3574 record = records.get(name)
3575 if record is None:
3576 return None
3577 return name
3578
3579 def LK_match(name):
3580 if not name.endswith("l"):
3581 return None
3582 alias = exact_match(name[:-1])
3583 if alias is None:
3584 return None
3585 record = records[alias]
3586 if "lk" not in record.flags:
3587 raise ValueError(record)
3588 return alias
3589
3590 def AA_match(name):
3591 if not name.endswith("a"):
3592 return None
3593 alias = LK_match(name[:-1])
3594 if alias is None:
3595 alias = name[:-1]
3596 record = records[alias]
3597 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
3598 raise ValueError(record)
3599 if "AA" not in mdwndb[name].operands:
3600 raise ValueError(record)
3601 return alias
3602
3603 def Rc_match(name):
3604 if not name.endswith("."):
3605 return None
3606 alias = exact_match(name[:-1])
3607 if alias is None:
3608 return None
3609 record = records[alias]
3610 if record.Rc is _RCOE.NONE:
3611 raise ValueError(record)
3612 return alias
3613
3614 db = {}
3615 matches = (exact_match, LK_match, AA_match, Rc_match)
3616 for (name, _) in mdwndb:
3617 if name.startswith("sv."):
3618 continue
3619 alias = None
3620 for match in matches:
3621 alias = match(name)
3622 if alias is not None:
3623 break
3624 if alias is None:
3625 continue
3626 section = sections[alias]
3627 record = records[alias]
3628 db[name] = (section, record)
3629
3630 self.__db = dict(sorted(db.items()))
3631
3632 return super().__init__()
3633
3634 @_functools.lru_cache(maxsize=512, typed=False)
3635 def __getitem__(self, key):
3636 return self.__db.get(key, (None, None))
3637
3638
3639 class SVP64Database:
3640 def __init__(self, root, ppcdb):
3641 db = set()
3642 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3643 for (prefix, _, names) in _os.walk(root):
3644 prefix = _pathlib.Path(prefix)
3645 for name in filter(lambda name: pattern.match(name), names):
3646 path = (prefix / _pathlib.Path(name))
3647 with open(path, "r", encoding="UTF-8") as stream:
3648 db.update(parse(stream, SVP64Record.CSV))
3649 db = {record.name:record for record in db}
3650
3651 self.__db = dict(sorted(db.items()))
3652 self.__ppcdb = ppcdb
3653
3654 return super().__init__()
3655
3656 def __getitem__(self, key):
3657 (_, record) = self.__ppcdb[key]
3658 if record is None:
3659 return None
3660
3661 for name in record.names:
3662 record = self.__db.get(name, None)
3663 if record is not None:
3664 return record
3665
3666 return None
3667
3668
3669 class Database:
3670 def __init__(self, root):
3671 root = _pathlib.Path(root)
3672 mdwndb = MarkdownDatabase()
3673 fieldsdb = FieldsDatabase()
3674 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
3675 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
3676
3677 db = set()
3678 names = {}
3679 opcodes = _collections.defaultdict(
3680 lambda: _collections.defaultdict(set))
3681
3682 for (name, mdwn) in mdwndb:
3683 if name.startswith("sv."):
3684 continue
3685 (section, ppc) = ppcdb[name]
3686 if ppc is None:
3687 continue
3688 svp64 = svp64db[name]
3689 fields = fieldsdb[ppc.form]
3690 record = Record(name=name,
3691 section=section, ppc=ppc, svp64=svp64,
3692 mdwn=mdwn, fields=fields)
3693 db.add(record)
3694 names[record.name] = record
3695 opcodes[section][record.PO].add(record)
3696
3697 self.__db = sorted(db)
3698 self.__names = dict(sorted(names.items()))
3699 self.__opcodes = dict(sorted(opcodes.items()))
3700
3701 return super().__init__()
3702
3703 def visit(self, visitor):
3704 with visitor.db(db=self) as db:
3705 for record in self.__db:
3706 record.visit(visitor=visitor)
3707
3708 def __repr__(self):
3709 return repr(self.__db)
3710
3711 def __iter__(self):
3712 yield from self.__db
3713
3714 @_functools.lru_cache(maxsize=None)
3715 def __contains__(self, key):
3716 return self.__getitem__(key) is not None
3717
3718 @_functools.lru_cache(maxsize=None)
3719 def __getitem__(self, key):
3720 if isinstance(key, SVP64Instruction):
3721 key = key.suffix
3722
3723 if isinstance(key, Instruction):
3724 PO = int(key.PO)
3725 key = int(key)
3726 sections = sorted(self.__opcodes)
3727 for section in sections:
3728 group = self.__opcodes[section]
3729 for record in group[PO]:
3730 if record.match(key=key):
3731 return record
3732
3733 return None
3734
3735 elif isinstance(key, str):
3736 return self.__names.get(key)
3737
3738 raise ValueError("instruction or name expected")