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