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