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