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