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