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