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