d498e21bbf4dde4c47da3a8a7c60d394e714e7dd
[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 assemble(self, value, insn):
929 span = self.span
930 if isinstance(value, str):
931 value = int(value, 0)
932 insn[span] = value
933
934 def disassemble(self, insn,
935 verbosity=Verbosity.NORMAL, indent=""):
936 span = self.span
937 value = insn[span]
938
939 if verbosity >= Verbosity.VERBOSE:
940 span = map(str, span)
941 yield f"{indent}{self.name}"
942 yield f"{indent}{indent}{int(value):0{value.bits}b}"
943 yield f"{indent}{indent}{', '.join(span)}"
944 else:
945 yield str(value.to_signed_int())
946
947
948 @_dataclasses.dataclass(eq=True, frozen=True)
949 class StaticOperand(Operand):
950 value: int
951
952 def assemble(self, insn):
953 return super().assemble(value=self.value, insn=insn)
954
955 def disassemble(self, insn,
956 verbosity=Verbosity.NORMAL, indent=""):
957 span = self.span
958 value = insn[span]
959
960 if verbosity >= Verbosity.VERBOSE:
961 span = map(str, span)
962 yield f"{indent}{self.name}"
963 yield f"{indent}{indent}{int(value):0{value.bits}b}"
964 yield f"{indent}{indent}{', '.join(span)}"
965 else:
966 yield str(int(value))
967
968
969 @_dataclasses.dataclass(eq=True, frozen=True)
970 class POStaticOperand(StaticOperand):
971 mask: int
972
973 @cached_property
974 def span(self):
975 span = tuple(range(0, 6))
976 if self.record.svp64 is not None:
977 span = tuple(map(lambda bit: (bit + 32), span))
978 return span
979
980
981 @_dataclasses.dataclass(eq=True, frozen=True)
982 class XOStaticOperand(StaticOperand):
983 mask: int
984
985 def __post_init__(self):
986 if self.record.section.opcode is None:
987 assert self.value == 0
988 assert self.mask == 0
989 object.__setattr__(self, "span", ())
990 return
991
992 bits = self.record.section.bitsel
993 value = _SelectableInt(value=self.value, bits=len(bits))
994 span = dict(zip(bits, range(len(bits))))
995 span_rev = {value:key for (key, value) in span.items()}
996
997 # This part is tricky: we could have used self.record.static_operands,
998 # but this would cause an infinite recursion, since this code is called
999 # from the self.record.static_operands method already.
1000 operands = []
1001 operands.extend(self.record.mdwn.operands.static)
1002 operands.extend(self.record.mdwn.operands.dynamic)
1003 for (cls, kwargs) in operands:
1004 operand = cls(record=self.record, **kwargs)
1005 for idx in operand.span:
1006 rev = span.pop(idx, None)
1007 if rev is not None:
1008 span_rev.pop(rev, None)
1009
1010 # This part is simpler: we drop bits which are not in the mask.
1011 for bit in tuple(span.values()):
1012 rev = (len(bits) - bit - 1)
1013 if ((self.mask & (1 << bit)) == 0):
1014 idx = span_rev.pop(rev, None)
1015 if idx is not None:
1016 span.pop(idx, None)
1017
1018 value = int(_selectconcat(*(value[bit] for bit in span.values())))
1019 span = tuple(span.keys())
1020 if self.record.svp64 is not None:
1021 span = tuple(map(lambda bit: (bit + 32), span))
1022
1023 object.__setattr__(self, "value", value)
1024 object.__setattr__(self, "span", span)
1025
1026 return super().__post_init__()
1027
1028
1029 @_dataclasses.dataclass(eq=True, frozen=True)
1030 class ImmediateOperand(DynamicOperand):
1031 pass
1032
1033
1034 @_dataclasses.dataclass(eq=True, frozen=True)
1035 class SignedImmediateOperand(SignedOperand, ImmediateOperand):
1036 pass
1037
1038
1039 @_dataclasses.dataclass(eq=True, frozen=True)
1040 class NonZeroOperand(DynamicOperand):
1041 def assemble(self, value, insn):
1042 if isinstance(value, str):
1043 value = int(value, 0)
1044 if not isinstance(value, int):
1045 raise ValueError("non-integer operand")
1046 value -= 1
1047 return super().assemble(value=value, insn=insn)
1048
1049 def disassemble(self, insn,
1050 verbosity=Verbosity.NORMAL, indent=""):
1051 span = self.span
1052 value = insn[span]
1053
1054 if verbosity >= Verbosity.VERBOSE:
1055 span = map(str, span)
1056 yield f"{indent}{self.name}"
1057 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1058 yield f"{indent}{indent}{', '.join(span)}"
1059 else:
1060 yield str(int(value) + 1)
1061
1062
1063 @_dataclasses.dataclass(eq=True, frozen=True)
1064 class ExtendableOperand(DynamicOperand):
1065 def sv_spec_enter(self, value, span):
1066 return (value, span)
1067
1068 def sv_spec_leave(self, value, span, origin_value, origin_span):
1069 return (value, span)
1070
1071 def spec(self, insn):
1072 vector = False
1073 span = self.span
1074 value = insn[span]
1075 span = tuple(map(str, span))
1076
1077 if isinstance(insn, SVP64Instruction):
1078 (origin_value, origin_span) = (value, span)
1079 (value, span) = self.sv_spec_enter(value=value, span=span)
1080
1081 extra_idx = self.extra_idx
1082 if extra_idx is _SVExtra.NONE:
1083 return (vector, value, span)
1084
1085 if self.record.etype is _SVEType.EXTRA3:
1086 spec = insn.prefix.rm.extra3[extra_idx]
1087 elif self.record.etype is _SVEType.EXTRA2:
1088 spec = insn.prefix.rm.extra2[extra_idx]
1089 else:
1090 raise ValueError(self.record.etype)
1091
1092 if spec != 0:
1093 vector = bool(spec[0])
1094 spec_span = spec.__class__
1095 if self.record.etype is _SVEType.EXTRA3:
1096 spec_span = tuple(map(str, spec_span[1, 2]))
1097 spec = spec[1, 2]
1098 elif self.record.etype is _SVEType.EXTRA2:
1099 spec_span = tuple(map(str, spec_span[1,]))
1100 spec = _SelectableInt(value=spec[1].value, bits=2)
1101 if vector:
1102 spec <<= 1
1103 spec_span = (spec_span + ("{0}",))
1104 else:
1105 spec_span = (("{0}",) + spec_span)
1106 else:
1107 raise ValueError(self.record.etype)
1108
1109 vector_shift = (2 + (5 - value.bits))
1110 scalar_shift = value.bits
1111 spec_shift = (5 - value.bits)
1112
1113 bits = (len(span) + len(spec_span))
1114 value = _SelectableInt(value=value.value, bits=bits)
1115 spec = _SelectableInt(value=spec.value, bits=bits)
1116 if vector:
1117 value = ((value << vector_shift) | (spec << spec_shift))
1118 span = (span + spec_span + ((spec_shift * ("{0}",))))
1119 else:
1120 value = ((spec << scalar_shift) | value)
1121 span = ((spec_shift * ("{0}",)) + spec_span + span)
1122
1123 (value, span) = self.sv_spec_leave(value=value, span=span,
1124 origin_value=origin_value, origin_span=origin_span)
1125
1126 return (vector, value, span)
1127
1128 @property
1129 def extra_reg(self):
1130 return _SVExtraReg(self.name)
1131
1132 @property
1133 def extra_idx(self):
1134 for key in frozenset({
1135 "in1", "in2", "in3", "cr_in", "cr_in2",
1136 "out", "out2", "cr_out",
1137 }):
1138 extra_reg = self.record.svp64.extra_reg(key=key)
1139 if extra_reg is self.extra_reg:
1140 return self.record.extra_idx(key=key)
1141
1142 return _SVExtra.NONE
1143
1144 def remap(self, value, vector):
1145 raise NotImplementedError
1146
1147 def assemble(self, value, insn, prefix):
1148 vector = False
1149
1150 if isinstance(value, str):
1151 value = value.lower()
1152 if value.startswith("%"):
1153 value = value[1:]
1154 if value.startswith("*"):
1155 if not isinstance(insn, SVP64Instruction):
1156 raise ValueError(value)
1157 value = value[1:]
1158 vector = True
1159 if value.startswith(prefix):
1160 value = value[len(prefix):]
1161 value = int(value, 0)
1162
1163 if isinstance(insn, SVP64Instruction):
1164 (value, extra) = self.remap(value=value, vector=vector)
1165
1166 extra_idx = self.extra_idx
1167 if extra_idx is _SVExtra.NONE:
1168 raise ValueError(self.record)
1169
1170 if self.record.etype is _SVEType.EXTRA3:
1171 insn.prefix.rm.extra3[extra_idx] = extra
1172 elif self.record.etype is _SVEType.EXTRA2:
1173 insn.prefix.rm.extra2[extra_idx] = extra
1174 else:
1175 raise ValueError(self.record.etype)
1176
1177 return super().assemble(value=value, insn=insn)
1178
1179 return super().assemble(value=value, insn=insn)
1180
1181 def disassemble(self, insn,
1182 verbosity=Verbosity.NORMAL, prefix="", indent=""):
1183 (vector, value, span) = self.spec(insn=insn)
1184
1185 if verbosity >= Verbosity.VERBOSE:
1186 mode = "vector" if vector else "scalar"
1187 yield f"{indent}{self.name} ({mode})"
1188 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1189 yield f"{indent}{indent}{', '.join(span)}"
1190 if isinstance(insn, SVP64Instruction):
1191 extra_idx = self.extra_idx
1192 if self.record.etype is _SVEType.NONE:
1193 yield f"{indent}{indent}extra[none]"
1194 else:
1195 etype = repr(self.record.etype).lower()
1196 yield f"{indent}{indent}{etype}{extra_idx!r}"
1197 else:
1198 vector = "*" if vector else ""
1199 yield f"{vector}{prefix}{int(value)}"
1200
1201
1202 @_dataclasses.dataclass(eq=True, frozen=True)
1203 class SimpleRegisterOperand(ExtendableOperand):
1204 def remap(self, value, vector):
1205 if vector:
1206 extra = (value & 0b11)
1207 value = (value >> 2)
1208 else:
1209 extra = (value >> 5)
1210 value = (value & 0b11111)
1211
1212 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1213 # (and shrink to a single bit if ok)
1214 if self.record.etype is _SVEType.EXTRA2:
1215 if vector:
1216 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1217 assert (extra & 0b01) == 0, \
1218 ("vector field %s cannot fit into EXTRA2" % value)
1219 extra = (0b10 | (extra >> 1))
1220 else:
1221 # range is r0-r63 in increments of 1
1222 assert (extra >> 1) == 0, \
1223 ("scalar GPR %d cannot fit into EXTRA2" % value)
1224 extra &= 0b01
1225 elif self.record.etype is _SVEType.EXTRA3:
1226 if vector:
1227 # EXTRA3 vector bit needs marking
1228 extra |= 0b100
1229 else:
1230 raise ValueError(self.record.etype)
1231
1232 return (value, extra)
1233
1234
1235 @_dataclasses.dataclass(eq=True, frozen=True)
1236 class GPROperand(SimpleRegisterOperand):
1237 def assemble(self, value, insn):
1238 return super().assemble(value=value, insn=insn, prefix="r")
1239
1240 def disassemble(self, insn,
1241 verbosity=Verbosity.NORMAL, indent=""):
1242 prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
1243 yield from super().disassemble(prefix=prefix, insn=insn,
1244 verbosity=verbosity, indent=indent)
1245
1246
1247 @_dataclasses.dataclass(eq=True, frozen=True)
1248 class FPROperand(SimpleRegisterOperand):
1249 def assemble(self, value, insn):
1250 return super().assemble(value=value, insn=insn, prefix="f")
1251
1252 def disassemble(self, insn,
1253 verbosity=Verbosity.NORMAL, indent=""):
1254 prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
1255 yield from super().disassemble(prefix=prefix, insn=insn,
1256 verbosity=verbosity, indent=indent)
1257
1258
1259 @_dataclasses.dataclass(eq=True, frozen=True)
1260 class ConditionRegisterFieldOperand(ExtendableOperand):
1261 def pattern(name_pattern):
1262 (name, pattern) = name_pattern
1263 return (name, _re.compile(f"^{pattern}$", _re.S))
1264
1265 CONDS = {
1266 "lt": 0,
1267 "gt": 1,
1268 "eq": 2,
1269 "so": 3,
1270 "un": 3,
1271 }
1272 CR = r"(?:CR|cr)([0-9]+)"
1273 N = r"([0-9]+)"
1274 BIT = rf"({'|'.join(CONDS.keys())})"
1275 LBIT = fr"{BIT}\s*\+\s*" # BIT+
1276 RBIT = fr"\s*\+\s*{BIT}" # +BIT
1277 CRN = fr"{CR}\s*\*\s*{N}" # CR*N
1278 NCR = fr"{N}\s*\*\s*{CR}" # N*CR
1279 XCR = fr"{CR}\.{BIT}"
1280 PATTERNS = tuple(map(pattern, (
1281 ("CR", CR),
1282 ("XCR", XCR),
1283 ("CR*N", CRN),
1284 ("N*CR", NCR),
1285 ("BIT+CR", (LBIT + CR)),
1286 ("CR+BIT", (CR + RBIT)),
1287 ("BIT+CR*N", (LBIT + CRN)),
1288 ("CR*N+BIT", (CRN + RBIT)),
1289 ("BIT+N*CR", (LBIT + NCR)),
1290 ("N*CR+BIT", (NCR + RBIT)),
1291 )))
1292
1293 def remap(self, value, vector, regtype):
1294 if regtype is _RegType.CR_5BIT:
1295 subvalue = (value & 0x3)
1296 value >>= 2
1297
1298 if vector:
1299 extra = (value & 0xf)
1300 value >>= 4
1301 else:
1302 extra = (value >> 3)
1303 value &= 0x7
1304
1305 if self.record.etype is _SVEType.EXTRA2:
1306 if vector:
1307 assert (extra & 0x7) == 0, \
1308 "vector CR cannot fit into EXTRA2"
1309 extra = (0x2 | (extra >> 3))
1310 else:
1311 assert (extra >> 1) == 0, \
1312 "scalar CR cannot fit into EXTRA2"
1313 extra &= 0x1
1314 elif self.record.etype is _SVEType.EXTRA3:
1315 if vector:
1316 assert (extra & 0x3) == 0, \
1317 "vector CR cannot fit into EXTRA3"
1318 extra = (0x4 | (extra >> 2))
1319 else:
1320 assert (extra >> 2) == 0, \
1321 "scalar CR cannot fit into EXTRA3"
1322 extra &= 0x3
1323
1324 if regtype is _RegType.CR_5BIT:
1325 value = ((value << 2) | subvalue)
1326
1327 return (value, extra)
1328
1329 def assemble(self, value, insn):
1330 if isinstance(value, str):
1331 vector = False
1332
1333 if value.startswith("*"):
1334 if not isinstance(insn, SVP64Instruction):
1335 raise ValueError(value)
1336 value = value[1:]
1337 vector = True
1338
1339 for (name, pattern) in reversed(self.__class__.PATTERNS):
1340 match = pattern.match(value)
1341 if match is not None:
1342 keys = name.replace("+", "_").replace("*", "_").split("_")
1343 values = match.groups()
1344 match = dict(zip(keys, values))
1345 CR = int(match["CR"])
1346 if name == "XCR":
1347 N = 4
1348 else:
1349 N = int(match.get("N", "1"))
1350 BIT = self.__class__.CONDS[match.get("BIT", "lt")]
1351 value = ((CR * N) + BIT)
1352 break
1353
1354 return super().assemble(value=value, insn=insn, prefix="cr")
1355
1356 def disassemble(self, insn,
1357 verbosity=Verbosity.NORMAL, prefix="", indent=""):
1358 (vector, value, span) = self.spec(insn=insn)
1359
1360 if verbosity >= Verbosity.VERBOSE:
1361 mode = "vector" if vector else "scalar"
1362 yield f"{indent}{self.name} ({mode})"
1363 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1364 yield f"{indent}{indent}{', '.join(span)}"
1365 if isinstance(insn, SVP64Instruction):
1366 extra_idx = self.extra_idx
1367 if self.record.etype is _SVEType.NONE:
1368 yield f"{indent}{indent}extra[none]"
1369 else:
1370 etype = repr(self.record.etype).lower()
1371 yield f"{indent}{indent}{etype}{extra_idx!r}"
1372 else:
1373 vector = "*" if vector else ""
1374 cr = int(value >> 2)
1375 cc = int(value & 3)
1376 cond = ("lt", "gt", "eq", "so")[cc]
1377 if verbosity >= Verbosity.NORMAL:
1378 if cr != 0:
1379 if isinstance(insn, SVP64Instruction):
1380 yield f"{vector}cr{cr}.{cond}"
1381 else:
1382 yield f"4*cr{cr}+{cond}"
1383 else:
1384 yield cond
1385 else:
1386 yield f"{vector}{prefix}{int(value)}"
1387
1388
1389 @_dataclasses.dataclass(eq=True, frozen=True)
1390 class CR3Operand(ConditionRegisterFieldOperand):
1391 def remap(self, value, vector):
1392 return super().remap(value=value, vector=vector,
1393 regtype=_RegType.CR_3BIT)
1394
1395
1396 @_dataclasses.dataclass(eq=True, frozen=True)
1397 class CR5Operand(ConditionRegisterFieldOperand):
1398 def remap(self, value, vector):
1399 return super().remap(value=value, vector=vector,
1400 regtype=_RegType.CR_5BIT)
1401
1402 def sv_spec_enter(self, value, span):
1403 value = _SelectableInt(value=(value.value >> 2), bits=3)
1404 return (value, span)
1405
1406 def sv_spec_leave(self, value, span, origin_value, origin_span):
1407 value = _selectconcat(value, origin_value[3:5])
1408 span += origin_span
1409 return (value, span)
1410
1411
1412 @_dataclasses.dataclass(eq=True, frozen=True)
1413 class EXTSOperand(SignedOperand):
1414 field: str # real name to report
1415 nz: int = 0 # number of zeros
1416 fmt: str = "d" # integer formatter
1417
1418 def __post_init__(self):
1419 if not self.field:
1420 object.__setattr__(self, "field", self.name)
1421
1422 @cached_property
1423 def span(self):
1424 span = self.record.fields[self.field]
1425 if self.record.svp64 is not None:
1426 span = tuple(map(lambda bit: (bit + 32), span))
1427 return span
1428
1429 def disassemble(self, insn,
1430 verbosity=Verbosity.NORMAL, indent=""):
1431 span = self.span
1432 value = insn[span]
1433
1434 if verbosity >= Verbosity.VERBOSE:
1435 span = (tuple(map(str, span)) + (("{0}",) * self.nz))
1436 zeros = ("0" * self.nz)
1437 hint = f"{self.name} = EXTS({self.field} || {zeros})"
1438 yield f"{indent * 1}{hint}"
1439 yield f"{indent * 2}{self.field}"
1440 yield f"{indent * 3}{int(value):0{value.bits}b}{zeros}"
1441 yield f"{indent * 3}{', '.join(span)}"
1442 else:
1443 value = _selectconcat(value,
1444 _SelectableInt(value=0, bits=self.nz)).to_signed_int()
1445 yield f"{value:{self.fmt}}"
1446
1447
1448 @_dataclasses.dataclass(eq=True, frozen=True)
1449 class TargetAddrOperand(EXTSOperand):
1450 nz: int = 2
1451 fmt: str = "#x"
1452
1453
1454 @_dataclasses.dataclass(eq=True, frozen=True)
1455 class TargetAddrOperandLI(TargetAddrOperand):
1456 field: str = "LI"
1457
1458
1459 @_dataclasses.dataclass(eq=True, frozen=True)
1460 class TargetAddrOperandBD(TargetAddrOperand):
1461 field: str = "BD"
1462
1463
1464 @_dataclasses.dataclass(eq=True, frozen=True)
1465 class EXTSOperandDS(EXTSOperand, ImmediateOperand):
1466 field: str = "DS"
1467 nz: int = 2
1468
1469
1470 @_dataclasses.dataclass(eq=True, frozen=True)
1471 class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
1472 field: str = "DQ"
1473 nz: int = 4
1474
1475
1476 @_dataclasses.dataclass(eq=True, frozen=True)
1477 class DOperandDX(SignedOperand):
1478 @cached_property
1479 def span(self):
1480 cls = lambda name: DynamicOperand(record=self.record, name=name)
1481 operands = map(cls, ("d0", "d1", "d2"))
1482 spans = map(lambda operand: operand.span, operands)
1483 span = sum(spans, tuple())
1484 if self.record.svp64 is not None:
1485 span = tuple(map(lambda bit: (bit + 32), span))
1486 return span
1487
1488 def disassemble(self, insn,
1489 verbosity=Verbosity.NORMAL, indent=""):
1490 span = self.span
1491 value = insn[span]
1492
1493 if verbosity >= Verbosity.VERBOSE:
1494 yield f"{indent}D"
1495 mapping = {
1496 "d0": "[0:9]",
1497 "d1": "[10:15]",
1498 "d2": "[16]",
1499 }
1500 for (subname, subspan) in mapping.items():
1501 operand = DynamicOperand(name=subname)
1502 span = operand.span
1503 value = insn[span]
1504 span = map(str, span)
1505 yield f"{indent}{indent}{operand.name} = D{subspan}"
1506 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
1507 yield f"{indent}{indent}{indent}{', '.join(span)}"
1508 else:
1509 yield str(value.to_signed_int())
1510
1511
1512 class Instruction(_Mapping):
1513 @classmethod
1514 def integer(cls, value=0, bits=None, byteorder="little"):
1515 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1516 raise ValueError(bits)
1517
1518 if isinstance(value, bytes):
1519 if ((len(value) * 8) != bits):
1520 raise ValueError(f"bit length mismatch")
1521 value = int.from_bytes(value, byteorder=byteorder)
1522
1523 if isinstance(value, int):
1524 value = _SelectableInt(value=value, bits=bits)
1525 elif isinstance(value, Instruction):
1526 value = value.storage
1527
1528 if not isinstance(value, _SelectableInt):
1529 raise ValueError(value)
1530 if bits is None:
1531 bits = len(cls)
1532 if len(value) != bits:
1533 raise ValueError(value)
1534
1535 value = _SelectableInt(value=value, bits=bits)
1536
1537 return cls(storage=value)
1538
1539 def __hash__(self):
1540 return hash(int(self))
1541
1542 def __getitem__(self, key):
1543 return self.storage.__getitem__(key)
1544
1545 def __setitem__(self, key, value):
1546 return self.storage.__setitem__(key, value)
1547
1548 def bytes(self, byteorder="little"):
1549 nr_bytes = (len(self.__class__) // 8)
1550 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1551
1552 def record(self, db):
1553 record = db[self]
1554 if record is None:
1555 raise KeyError(self)
1556 return record
1557
1558 def spec(self, db, prefix):
1559 record = self.record(db=db)
1560
1561 dynamic_operands = tuple(map(_operator.itemgetter(0),
1562 self.dynamic_operands(db=db)))
1563
1564 static_operands = []
1565 for (name, value) in self.static_operands(db=db):
1566 static_operands.append(f"{name}={value}")
1567
1568 operands = ""
1569 if dynamic_operands:
1570 operands += " "
1571 operands += ",".join(dynamic_operands)
1572 if static_operands:
1573 operands += " "
1574 operands += " ".join(static_operands)
1575
1576 return f"{prefix}{record.name}{operands}"
1577
1578 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
1579 record = self.record(db=db)
1580
1581 imm = False
1582 imm_name = ""
1583 imm_value = ""
1584 for operand in record.dynamic_operands:
1585 name = operand.name
1586 value = " ".join(operand.disassemble(insn=self,
1587 verbosity=min(verbosity, Verbosity.NORMAL)))
1588 if imm:
1589 name = f"{imm_name}({name})"
1590 value = f"{imm_value}({value})"
1591 imm = False
1592 if isinstance(operand, ImmediateOperand):
1593 imm_name = name
1594 imm_value = value
1595 imm = True
1596 if not imm:
1597 yield (name, value)
1598
1599 def static_operands(self, db):
1600 record = self.record(db=db)
1601 for operand in record.static_operands:
1602 yield (operand.name, operand.value)
1603
1604 @classmethod
1605 def assemble(cls, db, opcode, arguments=None):
1606 raise NotImplementedError(f"{cls.__name__}.assemble")
1607
1608 def disassemble(self, db,
1609 byteorder="little",
1610 verbosity=Verbosity.NORMAL):
1611 raise NotImplementedError
1612
1613
1614 class WordInstruction(Instruction):
1615 _: _Field = range(0, 32)
1616 PO: _Field = range(0, 6)
1617
1618 @classmethod
1619 def integer(cls, value, byteorder="little"):
1620 return super().integer(bits=32, value=value, byteorder=byteorder)
1621
1622 @property
1623 def binary(self):
1624 bits = []
1625 for idx in range(32):
1626 bit = int(self[idx])
1627 bits.append(bit)
1628 return "".join(map(str, bits))
1629
1630 @classmethod
1631 def assemble(cls, db, opcode, arguments=None):
1632 if arguments is None:
1633 arguments = ()
1634
1635 record = db[opcode]
1636 record = _dataclasses.replace(record, svp64=None)
1637 insn = cls.integer(value=0)
1638 for operand in record.static_operands:
1639 operand.assemble(insn=insn)
1640
1641 dynamic_operands = tuple(record.dynamic_operands)
1642 if len(dynamic_operands) != len(arguments):
1643 raise ValueError("operands count mismatch")
1644 for (value, operand) in zip(arguments, dynamic_operands):
1645 operand.assemble(value=value, insn=insn)
1646
1647 return insn
1648
1649 def disassemble(self, db,
1650 byteorder="little",
1651 verbosity=Verbosity.NORMAL):
1652 if verbosity <= Verbosity.SHORT:
1653 blob = ""
1654 else:
1655 blob = self.bytes(byteorder=byteorder)
1656 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1657 blob += " "
1658
1659 record = db[self]
1660 if record is None:
1661 yield f"{blob}.long 0x{int(self):08x}"
1662 return
1663
1664 operands = tuple(map(_operator.itemgetter(1),
1665 self.dynamic_operands(db=db, verbosity=verbosity)))
1666 if operands:
1667 operands = ",".join(operands)
1668 yield f"{blob}{record.name} {operands}"
1669 else:
1670 yield f"{blob}{record.name}"
1671
1672 if verbosity >= Verbosity.VERBOSE:
1673 indent = (" " * 4)
1674 binary = self.binary
1675 spec = self.spec(db=db, prefix="")
1676 yield f"{indent}spec"
1677 yield f"{indent}{indent}{spec}"
1678 yield f"{indent}pcode"
1679 for stmt in record.mdwn.pcode:
1680 yield f"{indent}{indent}{stmt}"
1681 yield f"{indent}binary"
1682 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1683 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1684 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1685 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1686 yield f"{indent}opcodes"
1687 for opcode in record.opcodes:
1688 yield f"{indent}{indent}{opcode!r}"
1689 for (cls, kwargs) in record.mdwn.operands:
1690 operand = cls(record=record, **kwargs)
1691 yield from operand.disassemble(insn=self,
1692 verbosity=verbosity, indent=indent)
1693 yield ""
1694
1695
1696 class PrefixedInstruction(Instruction):
1697 class Prefix(WordInstruction.remap(range(0, 32))):
1698 pass
1699
1700 class Suffix(WordInstruction.remap(range(32, 64))):
1701 pass
1702
1703 _: _Field = range(64)
1704 prefix: Prefix
1705 suffix: Suffix
1706 PO: Suffix.PO
1707
1708 @classmethod
1709 def integer(cls, value, byteorder="little"):
1710 return super().integer(bits=64, value=value, byteorder=byteorder)
1711
1712 @classmethod
1713 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1714 def transform(value):
1715 return WordInstruction.integer(value=value,
1716 byteorder=byteorder)[0:32]
1717
1718 (prefix, suffix) = map(transform, (prefix, suffix))
1719 value = _selectconcat(prefix, suffix)
1720
1721 return super().integer(bits=64, value=value)
1722
1723
1724 class Mode(_Mapping):
1725 _: _Field = range(0, 5)
1726 sel: _Field = (0, 1)
1727
1728
1729 class Extra(_Mapping):
1730 _: _Field = range(0, 9)
1731
1732
1733 class Extra2(Extra):
1734 idx0: _Field = range(0, 2)
1735 idx1: _Field = range(2, 4)
1736 idx2: _Field = range(4, 6)
1737 idx3: _Field = range(6, 8)
1738
1739 def __getitem__(self, key):
1740 return {
1741 0: self.idx0,
1742 1: self.idx1,
1743 2: self.idx2,
1744 3: self.idx3,
1745 _SVExtra.Idx0: self.idx0,
1746 _SVExtra.Idx1: self.idx1,
1747 _SVExtra.Idx2: self.idx2,
1748 _SVExtra.Idx3: self.idx3,
1749 }[key]
1750
1751 def __setitem__(self, key, value):
1752 self[key].assign(value)
1753
1754
1755 class Extra3(Extra):
1756 idx0: _Field = range(0, 3)
1757 idx1: _Field = range(3, 6)
1758 idx2: _Field = range(6, 9)
1759
1760 def __getitem__(self, key):
1761 return {
1762 0: self.idx0,
1763 1: self.idx1,
1764 2: self.idx2,
1765 _SVExtra.Idx0: self.idx0,
1766 _SVExtra.Idx1: self.idx1,
1767 _SVExtra.Idx2: self.idx2,
1768 }[key]
1769
1770 def __setitem__(self, key, value):
1771 self[key].assign(value)
1772
1773
1774 class BaseRM(_Mapping):
1775 _: _Field = range(24)
1776 mmode: _Field = (0,)
1777 mask: _Field = range(1, 4)
1778 elwidth: _Field = range(4, 6)
1779 ewsrc: _Field = range(6, 8)
1780 subvl: _Field = range(8, 10)
1781 mode: Mode.remap(range(19, 24))
1782 smask: _Field = range(16, 19)
1783 extra: Extra.remap(range(10, 19))
1784 extra2: Extra2.remap(range(10, 19))
1785 extra3: Extra3.remap(range(10, 19))
1786
1787 def specifiers(self, record):
1788 subvl = int(self.subvl)
1789 if subvl > 0:
1790 yield {
1791 1: "vec2",
1792 2: "vec3",
1793 3: "vec4",
1794 }[subvl]
1795
1796 def disassemble(self, verbosity=Verbosity.NORMAL):
1797 if verbosity >= Verbosity.VERBOSE:
1798 indent = (" " * 4)
1799 for (name, span) in self.traverse(path="RM"):
1800 value = self.storage[span]
1801 yield f"{name}"
1802 yield f"{indent}{int(value):0{value.bits}b}"
1803 yield f"{indent}{', '.join(map(str, span))}"
1804
1805
1806 class FFPRRc1BaseRM(BaseRM):
1807 def specifiers(self, record, mode):
1808 inv = _SelectableInt(value=int(self.inv), bits=1)
1809 CR = _SelectableInt(value=int(self.CR), bits=2)
1810 mask = int(_selectconcat(CR, inv))
1811 predicate = PredicateBaseRM.predicate(True, mask)
1812 yield f"{mode}={predicate}"
1813
1814 yield from super().specifiers(record=record)
1815
1816
1817 class FFPRRc0BaseRM(BaseRM):
1818 def specifiers(self, record, mode):
1819 if self.RC1:
1820 inv = "~" if self.inv else ""
1821 yield f"{mode}={inv}RC1"
1822
1823 yield from super().specifiers(record=record)
1824
1825
1826 class SatBaseRM(BaseRM):
1827 def specifiers(self, record):
1828 if self.N:
1829 yield "sats"
1830 else:
1831 yield "satu"
1832
1833 yield from super().specifiers(record=record)
1834
1835
1836 class ZZBaseRM(BaseRM):
1837 def specifiers(self, record):
1838 if self.zz:
1839 yield "zz"
1840
1841 yield from super().specifiers(record=record)
1842
1843
1844 class ZZCombinedBaseRM(BaseRM):
1845 def specifiers(self, record):
1846 if self.sz and self.dz:
1847 yield "zz"
1848 elif self.sz:
1849 yield "sz"
1850 elif self.dz:
1851 yield "dz"
1852
1853 yield from super().specifiers(record=record)
1854
1855
1856 class DZBaseRM(BaseRM):
1857 def specifiers(self, record):
1858 if self.dz:
1859 yield "dz"
1860
1861 yield from super().specifiers(record=record)
1862
1863
1864 class SZBaseRM(BaseRM):
1865 def specifiers(self, record):
1866 if self.sz:
1867 yield "sz"
1868
1869 yield from super().specifiers(record=record)
1870
1871
1872 class MRBaseRM(BaseRM):
1873 def specifiers(self, record):
1874 if self.RG:
1875 yield "mrr"
1876 else:
1877 yield "mr"
1878
1879 yield from super().specifiers(record=record)
1880
1881
1882 class ElsBaseRM(BaseRM):
1883 def specifiers(self, record):
1884 if self.els:
1885 yield "els"
1886
1887 yield from super().specifiers(record=record)
1888
1889
1890 class WidthBaseRM(BaseRM):
1891 @staticmethod
1892 def width(FP, width):
1893 width = {
1894 0b11: "8",
1895 0b10: "16",
1896 0b01: "32",
1897 }.get(width)
1898 if width is None:
1899 return None
1900 if FP:
1901 width = ("fp" + width)
1902 return width
1903
1904 def specifiers(self, record):
1905 # elwidths: use "w=" if same otherwise dw/sw
1906 # FIXME this should consider FP instructions
1907 FP = False
1908 dw = WidthBaseRM.width(FP, int(self.elwidth))
1909 sw = WidthBaseRM.width(FP, int(self.ewsrc))
1910 if dw == sw and dw:
1911 yield ("w=" + dw)
1912 else:
1913 if dw:
1914 yield ("dw=" + dw)
1915 if sw:
1916 yield ("sw=" + sw)
1917
1918 yield from super().specifiers(record=record)
1919
1920
1921 class PredicateBaseRM(BaseRM):
1922 @staticmethod
1923 def predicate(CR, mask):
1924 return {
1925 # integer
1926 (False, 0b001): "1<<r3",
1927 (False, 0b010): "r3",
1928 (False, 0b011): "~r3",
1929 (False, 0b100): "r10",
1930 (False, 0b101): "~r10",
1931 (False, 0b110): "r30",
1932 (False, 0b111): "~r30",
1933 # CRs
1934 (True, 0b000): "lt",
1935 (True, 0b001): "ge",
1936 (True, 0b010): "gt",
1937 (True, 0b011): "le",
1938 (True, 0b100): "eq",
1939 (True, 0b101): "ne",
1940 (True, 0b110): "so",
1941 (True, 0b111): "ns",
1942 }.get((CR, mask))
1943
1944 def specifiers(self, record):
1945 # predication - single and twin
1946 # use "m=" if same otherwise sm/dm
1947 CR = (int(self.mmode) == 1)
1948 mask = int(self.mask)
1949 sm = dm = PredicateBaseRM.predicate(CR, mask)
1950 if record.svp64.ptype is _SVPType.P2:
1951 smask = int(self.smask)
1952 sm = PredicateBaseRM.predicate(CR, smask)
1953 if sm == dm and dm:
1954 yield ("m=" + dm)
1955 else:
1956 if sm:
1957 yield ("sm=" + sm)
1958 if dm:
1959 yield ("dm=" + dm)
1960
1961 yield from super().specifiers(record=record)
1962
1963
1964 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
1965 pass
1966
1967
1968 class SEABaseRM(BaseRM):
1969 def specifiers(self, record):
1970 if self.SEA:
1971 yield "sea"
1972
1973 yield from super().specifiers(record=record)
1974
1975
1976 class VLiBaseRM(BaseRM):
1977 def specifiers(self, record):
1978 if self.VLi:
1979 yield "vli"
1980
1981 yield from super().specifiers(record=record)
1982
1983
1984 class NormalBaseRM(PredicateWidthBaseRM):
1985 """
1986 Normal mode
1987 https://libre-soc.org/openpower/sv/normal/
1988 """
1989 pass
1990
1991
1992 class NormalSimpleRM(ZZCombinedBaseRM, NormalBaseRM):
1993 """normal: simple mode"""
1994 dz: BaseRM.mode[3]
1995 sz: BaseRM.mode[4]
1996
1997 def specifiers(self, record):
1998 yield from super().specifiers(record=record)
1999
2000
2001 class NormalMRRM(MRBaseRM, NormalBaseRM):
2002 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2003 RG: BaseRM.mode[4]
2004
2005
2006 class NormalFFRc1RM(FFPRRc1BaseRM, NormalBaseRM):
2007 """normal: Rc=1: ffirst CR sel"""
2008 inv: BaseRM.mode[2]
2009 CR: BaseRM.mode[3, 4]
2010
2011 def specifiers(self, record):
2012 yield from super().specifiers(record=record, mode="ff")
2013
2014
2015 class NormalFFRc0RM(FFPRRc0BaseRM, VLiBaseRM, NormalBaseRM):
2016 """normal: Rc=0: ffirst z/nonz"""
2017 inv: BaseRM.mode[2]
2018 VLi: BaseRM.mode[3]
2019 RC1: BaseRM.mode[4]
2020
2021 def specifiers(self, record):
2022 yield from super().specifiers(record=record, mode="ff")
2023
2024
2025 class NormalSatRM(SatBaseRM, ZZCombinedBaseRM, NormalBaseRM):
2026 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2027 N: BaseRM.mode[2]
2028 dz: BaseRM.mode[3]
2029 sz: BaseRM.mode[4]
2030
2031
2032 class NormalPRRc1RM(FFPRRc1BaseRM, NormalBaseRM):
2033 """normal: Rc=1: pred-result CR sel"""
2034 inv: BaseRM.mode[2]
2035 CR: BaseRM.mode[3, 4]
2036
2037 def specifiers(self, record):
2038 yield from super().specifiers(record=record, mode="pr")
2039
2040
2041 class NormalPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, NormalBaseRM):
2042 """normal: Rc=0: pred-result z/nonz"""
2043 inv: BaseRM.mode[2]
2044 zz: BaseRM.mode[3]
2045 RC1: BaseRM.mode[4]
2046 dz: BaseRM.mode[3]
2047 sz: BaseRM.mode[3]
2048
2049 def specifiers(self, record):
2050 yield from super().specifiers(record=record, mode="pr")
2051
2052
2053 class NormalRM(NormalBaseRM):
2054 simple: NormalSimpleRM
2055 mr: NormalMRRM
2056 ffrc1: NormalFFRc1RM
2057 ffrc0: NormalFFRc0RM
2058 sat: NormalSatRM
2059 prrc1: NormalPRRc1RM
2060 prrc0: NormalPRRc0RM
2061
2062
2063 class LDSTImmBaseRM(PredicateWidthBaseRM):
2064 """
2065 LD/ST Immediate mode
2066 https://libre-soc.org/openpower/sv/ldst/
2067 """
2068 pass
2069
2070
2071 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
2072 """ld/st immediate: simple mode"""
2073 zz: BaseRM.mode[3]
2074 els: BaseRM.mode[4]
2075 dz: BaseRM.mode[3]
2076 sz: BaseRM.mode[3]
2077
2078
2079 class LDSTImmPostRM(LDSTImmBaseRM):
2080 """ld/st immediate: postinc mode (and load-fault)"""
2081 pi: BaseRM.mode[3] # Post-Increment Mode
2082 lf: BaseRM.mode[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2083
2084 def specifiers(self, record):
2085 if self.pi:
2086 yield "pi"
2087 if self.lf:
2088 yield "lf"
2089
2090
2091 class LDSTImmFFRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
2092 """ld/st immediate: Rc=1: ffirst CR sel"""
2093 inv: BaseRM.mode[2]
2094 CR: BaseRM.mode[3, 4]
2095
2096 def specifiers(self, record):
2097 yield from super().specifiers(record=record, mode="ff")
2098
2099
2100 class LDSTImmFFRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
2101 """ld/st immediate: Rc=0: ffirst z/nonz"""
2102 inv: BaseRM.mode[2]
2103 els: BaseRM.mode[3]
2104 RC1: BaseRM.mode[4]
2105
2106 def specifiers(self, record):
2107 yield from super().specifiers(record=record, mode="ff")
2108
2109
2110 class LDSTImmSatRM(ElsBaseRM, SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
2111 """ld/st immediate: sat mode: N=0/1 u/s"""
2112 N: BaseRM.mode[2]
2113 zz: BaseRM.mode[3]
2114 els: BaseRM.mode[4]
2115 dz: BaseRM.mode[3]
2116 sz: BaseRM.mode[3]
2117
2118
2119 class LDSTImmPRRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
2120 """ld/st immediate: Rc=1: pred-result CR sel"""
2121 inv: BaseRM.mode[2]
2122 CR: BaseRM.mode[3, 4]
2123
2124 def specifiers(self, record):
2125 yield from super().specifiers(record=record, mode="pr")
2126
2127
2128 class LDSTImmPRRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
2129 """ld/st immediate: Rc=0: pred-result z/nonz"""
2130 inv: BaseRM.mode[2]
2131 els: BaseRM.mode[3]
2132 RC1: BaseRM.mode[4]
2133
2134 def specifiers(self, record):
2135 yield from super().specifiers(record=record, mode="pr")
2136
2137
2138 class LDSTImmRM(LDSTImmBaseRM):
2139 simple: LDSTImmSimpleRM
2140 post: LDSTImmPostRM
2141 ffrc1: LDSTImmFFRc1RM
2142 ffrc0: LDSTImmFFRc0RM
2143 sat: LDSTImmSatRM
2144 prrc1: LDSTImmPRRc1RM
2145 prrc0: LDSTImmPRRc0RM
2146
2147
2148 class LDSTIdxBaseRM(PredicateWidthBaseRM):
2149 """
2150 LD/ST Indexed mode
2151 https://libre-soc.org/openpower/sv/ldst/
2152 """
2153 pass
2154
2155
2156 class LDSTIdxSimpleRM(SEABaseRM, ZZCombinedBaseRM, LDSTIdxBaseRM):
2157 """ld/st index: simple mode"""
2158 SEA: BaseRM.mode[2]
2159 dz: BaseRM.mode[3]
2160 sz: BaseRM.mode[4]
2161
2162
2163 class LDSTIdxStrideRM(SEABaseRM, ZZCombinedBaseRM, LDSTIdxBaseRM):
2164 """ld/st index: strided (scalar only source)"""
2165 SEA: BaseRM.mode[2]
2166 dz: BaseRM.mode[3]
2167 sz: BaseRM.mode[4]
2168
2169 def specifiers(self, record):
2170 yield "els"
2171
2172 yield from super().specifiers(record=record)
2173
2174
2175 class LDSTIdxSatRM(SatBaseRM, ZZCombinedBaseRM, LDSTIdxBaseRM):
2176 """ld/st index: sat mode: N=0/1 u/s"""
2177 N: BaseRM.mode[2]
2178 dz: BaseRM.mode[3]
2179 sz: BaseRM.mode[4]
2180
2181
2182 class LDSTIdxPRRc1RM(LDSTIdxBaseRM):
2183 """ld/st index: Rc=1: pred-result CR sel"""
2184 inv: BaseRM.mode[2]
2185 CR: BaseRM.mode[3, 4]
2186
2187 def specifiers(self, record):
2188 yield from super().specifiers(record=record, mode="pr")
2189
2190
2191 class LDSTIdxPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, LDSTIdxBaseRM):
2192 """ld/st index: Rc=0: pred-result z/nonz"""
2193 inv: BaseRM.mode[2]
2194 zz: BaseRM.mode[3]
2195 RC1: BaseRM.mode[4]
2196 dz: BaseRM.mode[3]
2197 sz: BaseRM.mode[3]
2198
2199 def specifiers(self, record):
2200 yield from super().specifiers(record=record, mode="pr")
2201
2202
2203 class LDSTIdxRM(LDSTIdxBaseRM):
2204 simple: LDSTIdxSimpleRM
2205 stride: LDSTIdxStrideRM
2206 sat: LDSTIdxSatRM
2207 prrc1: LDSTIdxPRRc1RM
2208 prrc0: LDSTIdxPRRc0RM
2209
2210
2211
2212 class CROpBaseRM(BaseRM):
2213 """
2214 CR ops mode
2215 https://libre-soc.org/openpower/sv/cr_ops/
2216 """
2217 SNZ: BaseRM[7]
2218
2219
2220 class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2221 """cr_op: simple mode"""
2222 RG: BaseRM[20]
2223 dz: BaseRM[22]
2224 sz: BaseRM[23]
2225
2226 def specifiers(self, record):
2227 if self.RG:
2228 yield "rg" # simple CR Mode reports /rg
2229
2230 yield from super().specifiers(record=record)
2231
2232 class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2233 """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
2234 RG: BaseRM[20]
2235 dz: BaseRM[22]
2236 sz: BaseRM[23]
2237
2238
2239 class CROpFF3RM(FFPRRc1BaseRM, VLiBaseRM, ZZBaseRM, PredicateBaseRM, CROpBaseRM):
2240 """cr_op: ffirst 3-bit mode"""
2241 VLi: BaseRM[20]
2242 inv: BaseRM[21]
2243 CR: BaseRM[22, 23]
2244 zz: BaseRM[6]
2245 sz: BaseRM[6]
2246 dz: BaseRM[6]
2247
2248 def specifiers(self, record):
2249 yield from super().specifiers(record=record, mode="ff")
2250
2251
2252 class CROpFF5RM(FFPRRc0BaseRM, PredicateBaseRM,
2253 VLiBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2254 """cr_op: ffirst 5-bit mode"""
2255 VLi: BaseRM[20]
2256 inv: BaseRM[21]
2257 RC1: BaseRM[19] # cheat: set RC=1 based on ffirst mode being set
2258 dz: BaseRM[22]
2259 sz: BaseRM[23]
2260
2261 def specifiers(self, record):
2262 yield from super().specifiers(record=record, mode="ff")
2263
2264
2265 class CROpRM(CROpBaseRM):
2266 simple: CROpSimpleRM
2267 mr: CROpMRRM
2268 ff3: CROpFF3RM
2269 ff5: CROpFF5RM
2270
2271
2272 # ********************
2273 # Branches mode
2274 # https://libre-soc.org/openpower/sv/branches/
2275 class BranchBaseRM(BaseRM):
2276 ALL: BaseRM[4]
2277 SNZ: BaseRM[5]
2278 SL: BaseRM[17]
2279 SLu: BaseRM[18]
2280 LRu: BaseRM[22]
2281 sz: BaseRM[23]
2282 CTR: BaseRM[19]
2283 VLS: BaseRM[20]
2284
2285 def specifiers(self, record):
2286 if self.ALL:
2287 yield "all"
2288
2289 # /sz
2290 # branch.sz=1
2291 # branch.snz=0
2292 # /snz
2293 # branch.sz=1
2294 # branch.snz=1
2295 if self.SNZ:
2296 if not self.sz:
2297 raise ValueError(self.sz)
2298 yield "snz"
2299 elif self.sz:
2300 yield "sz"
2301
2302 if self.SL:
2303 yield "sl"
2304 if self.SLu:
2305 yield "slu"
2306 if self.LRu:
2307 yield "lru"
2308
2309 # Branch modes lack source mask.
2310 # Therefore a custom code is needed.
2311 CR = (int(self.mmode) == 1)
2312 mask = int(self.mask)
2313 m = PredicateBaseRM.predicate(CR, mask)
2314 if m is not None:
2315 yield ("m=" + m)
2316
2317 yield from super().specifiers(record=record)
2318
2319
2320 class BranchSimpleRM(BranchBaseRM):
2321 """branch: simple mode"""
2322 pass
2323
2324
2325 class BranchVLSRM(BranchBaseRM):
2326 """branch: VLSET mode"""
2327 VSb: BaseRM[7]
2328 VLi: BaseRM[21]
2329
2330 def specifiers(self, record):
2331 yield {
2332 (0b0, 0b0): "vs",
2333 (0b0, 0b1): "vsi",
2334 (0b1, 0b0): "vsb",
2335 (0b1, 0b1): "vsbi",
2336 }[int(self.VSb), int(self.VLi)]
2337
2338 yield from super().specifiers(record=record)
2339
2340
2341 class BranchCTRRM(BranchBaseRM):
2342 """branch: CTR-test mode"""
2343 CTi: BaseRM[6]
2344
2345 def specifiers(self, record):
2346 if self.CTi:
2347 yield "cti"
2348 else:
2349 yield "ctr"
2350
2351 yield from super().specifiers(record=record)
2352
2353
2354 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
2355 """branch: CTR-test+VLSET mode"""
2356 pass
2357
2358
2359 class BranchRM(BranchBaseRM):
2360 simple: BranchSimpleRM
2361 vls: BranchVLSRM
2362 ctr: BranchCTRRM
2363 ctrvls: BranchCTRVLSRM
2364
2365
2366 class RM(BaseRM):
2367 normal: NormalRM
2368 ldst_imm: LDSTImmRM
2369 ldst_idx: LDSTIdxRM
2370 cr_op: CROpRM
2371 branch: BranchRM
2372
2373 def select(self, record):
2374 rm = self
2375 Rc = record.Rc
2376
2377 # the idea behind these tables is that they are now literally
2378 # in identical format to insndb.csv and minor_xx.csv and can
2379 # be done precisely as that. the only thing to watch out for
2380 # is the insertion of Rc=1 as a "mask/value" bit and likewise
2381 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
2382 # as the LSB.
2383 table = None
2384 if record.svp64.mode is _SVMode.NORMAL:
2385 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
2386 # mode Rc mask Rc member
2387 table = (
2388 (0b000000, 0b111000, "simple"), # simple (no Rc)
2389 (0b001000, 0b111000, "mr"), # mapreduce (no Rc)
2390 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
2391 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
2392 (0b100000, 0b110000, "sat"), # saturation (no Rc)
2393 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
2394 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
2395 )
2396 rm = rm.normal
2397 search = ((int(rm.mode) << 1) | Rc)
2398
2399 elif record.svp64.mode is _SVMode.LDST_IMM:
2400 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
2401 # mode Rc mask Rc member
2402 # ironically/coincidentally this table is identical to NORMAL
2403 # mode except reserved in place of mr
2404 table = (
2405 (0b000000, 0b111000, "simple"), # simple (no Rc)
2406 (0b001000, 0b111000, "post"), # post (no Rc)
2407 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
2408 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
2409 (0b100000, 0b110000, "sat"), # saturation (no Rc)
2410 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
2411 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
2412 )
2413 rm = rm.ldst_imm
2414 search = ((int(rm.mode) << 1) | Rc)
2415
2416 elif record.svp64.mode is _SVMode.LDST_IDX:
2417 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
2418 # mode Rc mask Rc member
2419 table = (
2420 (0b000000, 0b110000, "simple"), # simple (no Rc)
2421 (0b010000, 0b110000, "stride"), # strided, (no Rc)
2422 (0b100000, 0b110000, "sat"), # saturation (no Rc)
2423 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
2424 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
2425 )
2426 rm = rm.ldst_idx
2427 search = ((int(rm.mode) << 1) | Rc)
2428
2429 elif record.svp64.mode is _SVMode.CROP:
2430 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
2431 # mode 3b mask 3b member
2432 table = (
2433 (0b000000, 0b111000, "simple"), # simple
2434 (0b001000, 0b111000, "mr"), # mapreduce
2435 (0b100001, 0b100001, "ff3"), # ffirst, 3-bit CR
2436 (0b100000, 0b100000, "ff5"), # ffirst, 5-bit CR
2437 )
2438 rm = rm.cr_op
2439 search = ((int(rm.mode) << 1) | int(record.svp64.cr_3bit))
2440
2441 elif record.svp64.mode is _SVMode.BRANCH:
2442 # just mode 2-bit
2443 # mode mask member
2444 table = (
2445 (0b00, 0b11, "simple"), # simple
2446 (0b01, 0b11, "vls"), # VLset
2447 (0b10, 0b11, "ctr"), # CTR mode
2448 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
2449 )
2450 # slightly weird: doesn't have a 5-bit "mode" field like others
2451 rm = rm.branch
2452 search = int(rm.mode.sel)
2453
2454 # look up in table
2455 if table is not None:
2456 for (value, mask, member) in table:
2457 if ((value & mask) == (search & mask)):
2458 rm = getattr(rm, member)
2459 break
2460
2461 if rm.__class__ is self.__class__:
2462 raise ValueError(self)
2463
2464 return rm
2465
2466
2467 @_dataclasses.dataclass(eq=True, frozen=True)
2468 class Specifier:
2469 record: Record
2470
2471 @classmethod
2472 def match(cls, desc, record):
2473 raise NotImplementedError
2474
2475 def validate(self, others):
2476 pass
2477
2478 def assemble(self, insn):
2479 raise NotImplementedError
2480
2481
2482 @_dataclasses.dataclass(eq=True, frozen=True)
2483 class SpecifierWidth(Specifier):
2484 value: _SVP64Width
2485
2486 @classmethod
2487 def match(cls, desc, record, etalon):
2488 (mode, _, value) = desc.partition("=")
2489 mode = mode.strip()
2490 value = value.strip()
2491 if mode != etalon:
2492 return None
2493 value = _SVP64Width(value)
2494
2495 return cls(record=record, mode=mode, value=value)
2496
2497
2498 @_dataclasses.dataclass(eq=True, frozen=True)
2499 class SpecifierW(SpecifierWidth):
2500 @classmethod
2501 def match(cls, desc, record):
2502 return super().match(desc=desc, record=record, etalon="w")
2503
2504 def assemble(self, insn):
2505 insn.prefix.rm.ewsrc = int(self.value)
2506 insn.prefix.rm.elwidth = int(self.value)
2507
2508
2509 @_dataclasses.dataclass(eq=True, frozen=True)
2510 class SpecifierSW(SpecifierWidth):
2511 @classmethod
2512 def match(cls, desc, record):
2513 return super().match(desc=desc, record=record, etalon="sw")
2514
2515 def assemble(self, insn):
2516 insn.prefix.rm.ewsrc = int(self.value)
2517
2518
2519 @_dataclasses.dataclass(eq=True, frozen=True)
2520 class SpecifierDW(SpecifierWidth):
2521 @classmethod
2522 def match(cls, desc, record):
2523 return super().match(desc=desc, record=record, etalon="dw")
2524
2525 def assemble(self, insn):
2526 insn.prefix.rm.elwidth = int(self.value)
2527
2528
2529 @_dataclasses.dataclass(eq=True, frozen=True)
2530 class SpecifierSubVL(Specifier):
2531 value: _SVP64SubVL
2532
2533 @classmethod
2534 def match(cls, desc, record):
2535 try:
2536 value = _SVP64SubVL(desc)
2537 except ValueError:
2538 return None
2539
2540 return cls(record=record, value=value)
2541
2542 def assemble(self, insn):
2543 insn.prefix.rm.subvl = int(self.value.value)
2544
2545
2546 @_dataclasses.dataclass(eq=True, frozen=True)
2547 class SpecifierPredicate(Specifier):
2548 mode: str
2549 pred: _SVP64Pred
2550
2551 @classmethod
2552 def match(cls, desc, record, mode_match, pred_match):
2553 (mode, _, pred) = desc.partition("=")
2554
2555 mode = mode.strip()
2556 if not mode_match(mode):
2557 return None
2558
2559 pred = _SVP64Pred(pred.strip())
2560 if not pred_match(pred):
2561 raise ValueError(pred)
2562
2563 return cls(record=record, mode=mode, pred=pred)
2564
2565
2566 @_dataclasses.dataclass(eq=True, frozen=True)
2567 class SpecifierFFPR(SpecifierPredicate):
2568 @classmethod
2569 def match(cls, desc, record, mode):
2570 return super().match(desc=desc, record=record,
2571 mode_match=lambda mode_arg: mode_arg == mode,
2572 pred_match=lambda pred_arg: pred_arg.mode in (
2573 _SVP64PredMode.CR,
2574 _SVP64PredMode.RC1,
2575 ))
2576
2577 def assemble(self, insn):
2578 rm = insn.prefix.rm
2579 if rm.mode.sel != 0:
2580 raise ValueError("cannot override mode")
2581
2582 if self.record.svp64.mode is _SVMode.CROP:
2583 if self.mode == "pr":
2584 raise ValueError("crop: 'pr' mode not supported")
2585 rm.mode.sel = 0b10
2586 if self.record.svp64.cr_3bit:
2587 rm = rm.cr_op.ff3
2588 else:
2589 rm = rm.cr_op.ff5
2590 else:
2591 if self.record.svp64.mode is _SVMode.NORMAL:
2592 rm = rm.normal
2593 elif self.record.svp64.mode is _SVMode.LDST_IMM:
2594 rm = rm.ldst_imm
2595 elif self.record.svp64.mode is _SVMode.LDST_IDX:
2596 rm = rm.ldst_idx
2597 if self.mode == "ff":
2598 raise ValueError("ld/st idx: 'ff' mode not supported")
2599 else:
2600 raise ValueError(f"{self.mode!r} not supported")
2601
2602 # These 2-bit values should have bits swapped
2603 def bitswap(value):
2604 return (((value & 0b10) >> 1) | ((value & 0b01) << 1))
2605
2606 rm.mode.sel = {
2607 "ff": bitswap(_SVP64RMMode.FFIRST.value),
2608 "pr": bitswap(_SVP64RMMode.PREDRES.value),
2609 }[self.mode]
2610
2611 Rc = int(self.record.Rc)
2612 rm = getattr(rm, f"{self.mode}rc{Rc}")
2613 rm.inv = self.pred.inv
2614 if Rc:
2615 rm.CR = self.pred.state
2616 else:
2617 rm.RC1 = self.pred.state
2618
2619
2620 @_dataclasses.dataclass(eq=True, frozen=True)
2621 class SpecifierFF(SpecifierFFPR):
2622 @classmethod
2623 def match(cls, desc, record):
2624 return super().match(desc=desc, record=record, mode="ff")
2625
2626
2627 @_dataclasses.dataclass(eq=True, frozen=True)
2628 class SpecifierPR(SpecifierFFPR):
2629 @classmethod
2630 def match(cls, desc, record):
2631 return super().match(desc=desc, record=record, mode="pr")
2632
2633
2634 @_dataclasses.dataclass(eq=True, frozen=True)
2635 class SpecifierMask(SpecifierPredicate):
2636 @classmethod
2637 def match(cls, desc, record, mode):
2638 return super().match(desc=desc, record=record,
2639 mode_match=lambda mode_arg: mode_arg == mode,
2640 pred_match=lambda pred_arg: pred_arg.mode in (
2641 _SVP64PredMode.INT,
2642 _SVP64PredMode.CR,
2643 ))
2644
2645 def assemble(self, insn):
2646 raise NotImplementedError
2647
2648
2649 @_dataclasses.dataclass(eq=True, frozen=True)
2650 class SpecifierM(SpecifierMask):
2651 @classmethod
2652 def match(cls, desc, record):
2653 return super().match(desc=desc, record=record, mode="m")
2654
2655 def validate(self, others):
2656 for spec in others:
2657 if isinstance(spec, SpecifierSM):
2658 raise ValueError("source-mask and predicate mask conflict")
2659 elif isinstance(spec, SpecifierDM):
2660 raise ValueError("dest-mask and predicate mask conflict")
2661
2662 def assemble(self, insn):
2663 insn.prefix.rm.mask = int(self.pred)
2664
2665
2666 @_dataclasses.dataclass(eq=True, frozen=True)
2667 class SpecifierSM(SpecifierMask):
2668 @classmethod
2669 def match(cls, desc, record):
2670 return super().match(desc=desc, record=record, mode="sm")
2671
2672 def validate(self, others):
2673 if self.record.svp64.ptype is _SVPType.P1:
2674 raise ValueError("source-mask on non-twin predicate")
2675
2676 if self.pred.mode is _SVP64PredMode.CR:
2677 twin = None
2678 for spec in others:
2679 if isinstance(spec, SpecifierDM):
2680 twin = spec
2681
2682 if twin is None:
2683 raise ValueError("missing dest-mask in CR twin predication")
2684 if self.pred != twin.pred:
2685 raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
2686
2687 def assemble(self, insn):
2688 insn.prefix.rm.smask = int(self.pred)
2689
2690
2691 @_dataclasses.dataclass(eq=True, frozen=True)
2692 class SpecifierDM(SpecifierMask):
2693 @classmethod
2694 def match(cls, desc, record):
2695 return super().match(desc=desc, record=record, mode="dm")
2696
2697 def validate(self, others):
2698 if self.record.svp64.ptype is _SVPType.P1:
2699 raise ValueError("dest-mask on non-twin predicate")
2700
2701 if self.pred.mode is _SVP64PredMode.CR:
2702 twin = None
2703 for spec in others:
2704 if isinstance(spec, SpecifierSM):
2705 twin = spec
2706
2707 if twin is None:
2708 raise ValueError("missing source-mask in CR twin predication")
2709 if self.pred != twin.pred:
2710 raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
2711
2712 def assemble(self, insn):
2713 insn.prefix.rm.mask = int(self.pred)
2714
2715
2716
2717 @_dataclasses.dataclass(eq=True, frozen=True)
2718 class SpecifierZZ(Specifier):
2719 @classmethod
2720 def match(cls, desc, record):
2721 if desc != "zz":
2722 return None
2723
2724 return cls(record=record)
2725
2726 def validate(self, others):
2727 for spec in others:
2728 # Since m=xx takes precedence (overrides) sm=xx and dm=xx,
2729 # treat them as mutually exclusive.
2730 if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
2731 raise ValueError("mutually exclusive predicate masks")
2732
2733 def assemble(self, insn):
2734 rm = insn.prefix.rm.select(record=self.record)
2735 if hasattr(rm, "zz"):
2736 rm.zz = 1
2737 else:
2738 rm.sz = 1
2739 rm.dz = 1
2740
2741
2742 @_dataclasses.dataclass(eq=True, frozen=True)
2743 class SpecifierXZ(Specifier):
2744 desc: str
2745 hint: str = _dataclasses.field(repr=False)
2746
2747 @classmethod
2748 def match(cls, desc, record, etalon, hint):
2749 if not desc != etalon:
2750 return None
2751
2752 return cls(desc=desc, record=record, hint=hint)
2753
2754 def validate(self, others):
2755 if self.record.svp64.ptype is _SVPType.P1:
2756 raise ValueError(f"{self.hint} on non-twin predicate")
2757
2758 if self.pred.mode is _SVP64PredMode.CR:
2759 twin = None
2760 for spec in others:
2761 if isinstance(spec, SpecifierSM):
2762 twin = spec
2763
2764 if twin is None:
2765 raise ValueError(f"missing {self.hint} in CR twin predication")
2766 if self.pred != twin.pred:
2767 raise ValueError(f"predicate masks mismatch: {self!r} vs {twin!r}")
2768
2769 def assemble(self, insn):
2770 rm = insn.prefix.rm.select(record=self.record)
2771 setattr(rm, self.desc, 1)
2772
2773
2774 @_dataclasses.dataclass(eq=True, frozen=True)
2775 class SpecifierSZ(SpecifierXZ):
2776 @classmethod
2777 def match(cls, desc, record):
2778 return super().match(desc=desc, record=record,
2779 etalon="sz", hint="source-mask")
2780
2781 def validate(self, others):
2782 for spec in others:
2783 if isinstance(spec, SpecifierFF):
2784 raise ValueError("source-zero not allowed in ff mode")
2785 elif isinstance(spec, SpecifierPR):
2786 raise ValueError("source-zero not allowed in pr mode")
2787
2788
2789 @_dataclasses.dataclass(eq=True, frozen=True)
2790 class SpecifierDZ(SpecifierXZ):
2791 @classmethod
2792 def match(cls, desc, record):
2793 return super().match(desc=desc, record=record,
2794 etalon="dz", hint="dest-mask")
2795
2796 def validate(self, others):
2797 for spec in others:
2798 if (isinstance(spec, (SpecifierFF, SpecifierPR)) and
2799 (spec.pred.mode is _SVP64PredMode.RC1)):
2800 mode = "ff" if isinstance(spec, SpecifierFF) else "pr"
2801 raise ValueError(f"dest-zero not allowed in {mode} mode BO")
2802
2803
2804 @_dataclasses.dataclass(eq=True, frozen=True)
2805 class SpecifierEls(Specifier):
2806 @classmethod
2807 def match(cls, desc, record):
2808 if desc != "els":
2809 return None
2810
2811 return cls(record=record)
2812
2813 def assemble(self, insn):
2814 rm = insn.prefix.rm.select(record=self.record)
2815 rm.els = 1
2816 if self.record.svp64.mode is _SVMode.LDST_IDX:
2817 rm.mode.sel = 1
2818
2819
2820 @_dataclasses.dataclass(eq=True, frozen=True)
2821 class SpecifierSEA(Specifier):
2822 @classmethod
2823 def match(cls, desc, record):
2824 if desc != "els":
2825 return None
2826
2827 return cls(record=record)
2828
2829 def validate(self, others):
2830 if self.record.svp64.mode is not _SVMode.LDST_IDX:
2831 raise ValueError("sea is only valid in ld/st modes")
2832
2833 for spec in others:
2834 if isinstance(spec, SpecifierFF):
2835 raise ValueError(f"sea cannot be used in ff mode")
2836
2837 def assemble(self, insn):
2838 rm = insn.prefix.rm.select(record=self.record)
2839 if rm.mode.sel not in (0b00, 0b01):
2840 raise ValueError("sea is only valid for normal and els modes")
2841 rm.sea = 1
2842
2843
2844 @_dataclasses.dataclass(eq=True, frozen=True)
2845 class SpecifierSat(Specifier):
2846 desc: str
2847 sign: bool
2848
2849 @classmethod
2850 def match(cls, desc, record, etalon, sign):
2851 if desc != etalon:
2852 return None
2853
2854 return cls(record=record, desc=desc, sign=sign)
2855
2856 def assemble(self, insn):
2857 rm = insn.prefix.rm.select(record=self.record)
2858 rm.mode.sel = 2
2859 rm.sat = 1 if self.sign else 0
2860
2861
2862 @_dataclasses.dataclass(eq=True, frozen=True)
2863 class SpecifierSatS(Specifier):
2864 @classmethod
2865 def match(cls, desc, record):
2866 return super().match(desc=desc, record=record,
2867 etalon="sats", sign=True)
2868
2869
2870 @_dataclasses.dataclass(eq=True, frozen=True)
2871 class SpecifierSatU(Specifier):
2872 @classmethod
2873 def match(cls, desc, record):
2874 return super().match(desc=desc, record=record,
2875 etalon="satu", sign=False)
2876
2877
2878 @_dataclasses.dataclass(eq=True, frozen=True)
2879 class SpecifierMR(Specifier):
2880 @classmethod
2881 def match(cls, desc, record):
2882 if desc != "mr":
2883 return None
2884
2885 return cls(record=record)
2886
2887 def assemble(self, insn):
2888 rm = insn.prefix.rm.select(record=self.record)
2889 rm.mode.sel = 0
2890 rm.mr = 1
2891 rm.RG = 0
2892
2893
2894 @_dataclasses.dataclass(eq=True, frozen=True)
2895 class SpecifierMRR(Specifier):
2896 @classmethod
2897 def match(cls, desc, record):
2898 if desc != "mr":
2899 return None
2900
2901 return cls(record=record)
2902
2903 def assemble(self, insn):
2904 rm = insn.prefix.rm.select(record=self.record)
2905 rm.mode.sel = 0
2906 rm.mr = 1
2907 rm.RG = 1
2908
2909
2910 @_dataclasses.dataclass(eq=True, frozen=True)
2911 class SpecifierCRM(Specifier):
2912 @classmethod
2913 def match(cls, desc, record):
2914 if desc != "crm":
2915 return None
2916
2917 return cls(record=record)
2918
2919 def assemble(self, insn):
2920 rm = insn.prefix.rm.select(record=self.record)
2921 rm.mode.sel = 0
2922 rm.crm = 1
2923
2924
2925 @_dataclasses.dataclass(eq=True, frozen=True)
2926 class SpecifierBranch(Specifier):
2927 @classmethod
2928 def match(cls, desc, record, etalon):
2929 if desc != etalon:
2930 return None
2931
2932 return cls(record=record)
2933
2934 def validate(self, others):
2935 if self.record.svp64.mode != _SVMode.BRANCH:
2936 raise ValueError("only branch modes supported")
2937
2938
2939 @_dataclasses.dataclass(eq=True, frozen=True)
2940 class SpecifierAll(SpecifierBranch):
2941 @classmethod
2942 def match(cls, desc, record):
2943 return super().match(desc=desc, record=record, etalon="all")
2944
2945 def assemble(self, insn):
2946 rm = insn.prefix.rm.select(record=self.record)
2947 rm.ALL = 1
2948
2949
2950 @_dataclasses.dataclass(eq=True, frozen=True)
2951 class SpecifierSNZ(SpecifierBranch):
2952 @classmethod
2953 def match(cls, desc, record):
2954 return super().match(desc=desc, record=record, etalon="snz")
2955
2956 def assemble(self, insn):
2957 rm = insn.prefix.rm.select(record=self.record)
2958 rm.sz = 1
2959 rm.SNZ = 1
2960
2961
2962 @_dataclasses.dataclass(eq=True, frozen=True)
2963 class SpecifierSL(SpecifierBranch):
2964 @classmethod
2965 def match(cls, desc, record):
2966 return super().match(desc=desc, record=record, etalon="sl")
2967
2968 def assemble(self, insn):
2969 rm = insn.prefix.rm.select(record=self.record)
2970 rm.SL = 1
2971
2972
2973 @_dataclasses.dataclass(eq=True, frozen=True)
2974 class SpecifierSLu(SpecifierBranch):
2975 @classmethod
2976 def match(cls, desc, record):
2977 return super().match(desc=desc, record=record, etalon="slu")
2978
2979 def assemble(self, insn):
2980 rm = insn.prefix.rm.select(record=self.record)
2981 rm.SLu = 1
2982
2983
2984 @_dataclasses.dataclass(eq=True, frozen=True)
2985 class SpecifierLRu(SpecifierBranch):
2986 @classmethod
2987 def match(cls, desc, record):
2988 return super().match(desc=desc, record=record, etalon="lru")
2989
2990 def assemble(self, insn):
2991 rm = insn.prefix.rm.select(record=self.record)
2992 rm.LRu = 1
2993
2994
2995 @_dataclasses.dataclass(eq=True, frozen=True)
2996 class SpecifierVS(SpecifierBranch):
2997 @classmethod
2998 def match(cls, desc, record):
2999 return super().match(desc=desc, record=record, etalon="vs")
3000
3001 def assemble(self, insn):
3002 rm = insn.prefix.rm.select(record=self.record)
3003 rm.VLS = 1
3004 rm.VLi = 0
3005 rm.VSb = 0
3006
3007
3008 @_dataclasses.dataclass(eq=True, frozen=True)
3009 class SpecifierVSi(SpecifierVS):
3010 @classmethod
3011 def match(cls, desc, record):
3012 return super().match(desc=desc, record=record, etalon="vsi")
3013
3014 def assemble(self, insn):
3015 rm = insn.prefix.rm.select(record=self.record)
3016 rm.VLS = 1
3017 rm.VLi = 1
3018 rm.VSb = 0
3019
3020
3021 @_dataclasses.dataclass(eq=True, frozen=True)
3022 class SpecifierVSb(SpecifierVS):
3023 @classmethod
3024 def match(cls, desc, record):
3025 return super().match(desc=desc, record=record, etalon="vsb")
3026
3027 def assemble(self, insn):
3028 rm = insn.prefix.rm.select(record=self.record)
3029 rm.VLS = 1
3030 rm.VLi = 0
3031 rm.VSb = 1
3032
3033
3034 @_dataclasses.dataclass(eq=True, frozen=True)
3035 class SpecifierVSbi(SpecifierVS):
3036 @classmethod
3037 def match(cls, desc, record):
3038 return super().match(desc=desc, record=record, etalon="vsbi")
3039
3040 def assemble(self, insn):
3041 rm = insn.prefix.rm.select(record=self.record)
3042 rm.VLS = 1
3043 rm.VLi = 1
3044 rm.VSb = 1
3045
3046
3047 @_dataclasses.dataclass(eq=True, frozen=True)
3048 class SpecifierCTR(SpecifierVS):
3049 @classmethod
3050 def match(cls, desc, record):
3051 if desc != "ctr":
3052 return None
3053
3054 return cls(record=record)
3055
3056 def assemble(self, insn):
3057 rm = insn.prefix.rm.select(record=self.record)
3058 rm.CTR = 1
3059
3060
3061 @_dataclasses.dataclass(eq=True, frozen=True)
3062 class SpecifierCTi(SpecifierVS):
3063 @classmethod
3064 def match(cls, desc, record):
3065 if desc != "cti":
3066 return None
3067
3068 return cls(record=record)
3069
3070 def assemble(self, insn):
3071 rm = insn.prefix.rm.select(record=self.record)
3072 rm.CTR = 1
3073 rm.CTi = 1
3074
3075
3076 @_dataclasses.dataclass(eq=True, frozen=True)
3077 class SpecifierPI(Specifier):
3078 @classmethod
3079 def match(cls, desc, record):
3080 if desc != "pi":
3081 return None
3082
3083 return cls(record=record)
3084
3085 def assemble(self, insn):
3086 rm = insn.prefix.rm.select(record=self.record)
3087 rm.pi = 1
3088
3089
3090 @_dataclasses.dataclass(eq=True, frozen=True)
3091 class SpecifierLF(Specifier):
3092 @classmethod
3093 def match(cls, desc, record):
3094 if desc != "lf":
3095 return None
3096
3097 return cls(record=record)
3098
3099 def assemble(self, insn):
3100 rm = insn.prefix.rm.select(record=self.record)
3101 rm.lf = 1
3102
3103
3104 class Specifiers(tuple):
3105 SPECS = (
3106 SpecifierW,
3107 SpecifierSW,
3108 SpecifierDW,
3109 SpecifierSubVL,
3110 SpecifierFF,
3111 SpecifierPR,
3112 SpecifierM,
3113 SpecifierSM,
3114 SpecifierDM,
3115 SpecifierZZ,
3116 SpecifierSZ,
3117 SpecifierDZ,
3118 SpecifierEls,
3119 SpecifierSatS,
3120 SpecifierSatU,
3121 SpecifierMR,
3122 SpecifierMRR,
3123 SpecifierCRM,
3124 SpecifierAll,
3125 SpecifierSNZ,
3126 SpecifierSL,
3127 SpecifierSLu,
3128 SpecifierLRu,
3129 SpecifierVS,
3130 SpecifierVSi,
3131 SpecifierVSb,
3132 SpecifierVSbi,
3133 SpecifierCTR,
3134 SpecifierCTi,
3135 SpecifierPI,
3136 SpecifierLF,
3137 )
3138
3139 def __new__(cls, items, record):
3140 def transform(item):
3141 for spec_cls in cls.SPECS:
3142 spec = spec_cls.match(item, record=record)
3143 if spec is not None:
3144 return spec
3145 raise ValueError(item)
3146
3147 specs = tuple(map(transform, items))
3148 for (index, spec) in enumerate(specs):
3149 head = specs[:index]
3150 tail = specs[index + 1:]
3151 spec.validate(others=(head + tail))
3152
3153 return super().__new__(cls, specs)
3154
3155
3156 class SVP64Instruction(PrefixedInstruction):
3157 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3158 class Prefix(PrefixedInstruction.Prefix):
3159 id: _Field = (7, 9)
3160 rm: RM.remap((6, 8) + tuple(range(10, 32)))
3161
3162 prefix: Prefix
3163
3164 def record(self, db):
3165 record = db[self.suffix]
3166 if record is None:
3167 raise KeyError(self)
3168 return record
3169
3170 @property
3171 def binary(self):
3172 bits = []
3173 for idx in range(64):
3174 bit = int(self[idx])
3175 bits.append(bit)
3176 return "".join(map(str, bits))
3177
3178 @classmethod
3179 def assemble(cls, db, opcode, arguments=None, specifiers=None):
3180 if arguments is None:
3181 arguments = ()
3182 if specifiers is None:
3183 specifiers = ()
3184
3185 record = db[opcode]
3186 insn = cls.integer(value=0)
3187
3188 specifiers = Specifiers(items=specifiers, record=record)
3189 for specifier in specifiers:
3190 specifier.assemble(insn=insn)
3191
3192 for operand in record.static_operands:
3193 operand.assemble(insn=insn)
3194
3195 dynamic_operands = tuple(record.dynamic_operands)
3196 if len(dynamic_operands) != len(arguments):
3197 raise ValueError("operands count mismatch")
3198 for (value, operand) in zip(arguments, dynamic_operands):
3199 operand.assemble(value=value, insn=insn)
3200
3201 insn.prefix.PO = 0x1
3202 insn.prefix.id = 0x3
3203
3204 return insn
3205
3206 def disassemble(self, db,
3207 byteorder="little",
3208 verbosity=Verbosity.NORMAL):
3209 def blob(insn):
3210 if verbosity <= Verbosity.SHORT:
3211 return ""
3212 else:
3213 blob = insn.bytes(byteorder=byteorder)
3214 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
3215 return f"{blob} "
3216
3217 record = self.record(db=db)
3218 blob_prefix = blob(self.prefix)
3219 blob_suffix = blob(self.suffix)
3220 if record is None or record.svp64 is None:
3221 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3222 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
3223 return
3224
3225 name = f"sv.{record.name}"
3226
3227 rm = self.prefix.rm.select(record=record)
3228
3229 # convert specifiers to /x/y/z (sorted lexicographically)
3230 specifiers = sorted(rm.specifiers(record=record))
3231 if specifiers: # if any add one extra to get the extra "/"
3232 specifiers = ([""] + specifiers)
3233 specifiers = "/".join(specifiers)
3234
3235 # convert operands to " ,x,y,z"
3236 operands = tuple(map(_operator.itemgetter(1),
3237 self.dynamic_operands(db=db, verbosity=verbosity)))
3238 operands = ",".join(operands)
3239 if len(operands) > 0: # if any separate with a space
3240 operands = (" " + operands)
3241
3242 yield f"{blob_prefix}{name}{specifiers}{operands}"
3243 if blob_suffix:
3244 yield f"{blob_suffix}"
3245
3246 if verbosity >= Verbosity.VERBOSE:
3247 indent = (" " * 4)
3248 binary = self.binary
3249 spec = self.spec(db=db, prefix="sv.")
3250
3251 yield f"{indent}spec"
3252 yield f"{indent}{indent}{spec}"
3253 yield f"{indent}pcode"
3254 for stmt in record.mdwn.pcode:
3255 yield f"{indent}{indent}{stmt}"
3256 yield f"{indent}binary"
3257 yield f"{indent}{indent}[0:8] {binary[0:8]}"
3258 yield f"{indent}{indent}[8:16] {binary[8:16]}"
3259 yield f"{indent}{indent}[16:24] {binary[16:24]}"
3260 yield f"{indent}{indent}[24:32] {binary[24:32]}"
3261 yield f"{indent}{indent}[32:40] {binary[32:40]}"
3262 yield f"{indent}{indent}[40:48] {binary[40:48]}"
3263 yield f"{indent}{indent}[48:56] {binary[48:56]}"
3264 yield f"{indent}{indent}[56:64] {binary[56:64]}"
3265 yield f"{indent}opcodes"
3266 for opcode in record.opcodes:
3267 yield f"{indent}{indent}{opcode!r}"
3268 for (cls, kwargs) in record.mdwn.operands:
3269 operand = cls(record=record, **kwargs)
3270 yield from operand.disassemble(insn=self,
3271 verbosity=verbosity, indent=indent)
3272 yield f"{indent}RM"
3273 yield f"{indent}{indent}{rm.__doc__}"
3274 for line in rm.disassemble(verbosity=verbosity):
3275 yield f"{indent}{indent}{line}"
3276 yield ""
3277
3278
3279 def parse(stream, factory):
3280 def match(entry):
3281 return ("TODO" not in frozenset(entry.values()))
3282
3283 lines = filter(lambda line: not line.strip().startswith("#"), stream)
3284 entries = _csv.DictReader(lines)
3285 entries = filter(match, entries)
3286 return tuple(map(factory, entries))
3287
3288
3289 class MarkdownDatabase:
3290 def __init__(self):
3291 db = {}
3292 for (name, desc) in _ISA():
3293 operands = []
3294 if desc.regs:
3295 (dynamic, *static) = desc.regs
3296 operands.extend(dynamic)
3297 operands.extend(static)
3298 pcode = PCode(iterable=desc.pcode)
3299 operands = Operands(insn=name, iterable=operands)
3300 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
3301
3302 self.__db = dict(sorted(db.items()))
3303
3304 return super().__init__()
3305
3306 def __iter__(self):
3307 yield from self.__db.items()
3308
3309 def __contains__(self, key):
3310 return self.__db.__contains__(key)
3311
3312 def __getitem__(self, key):
3313 return self.__db.__getitem__(key)
3314
3315
3316 class FieldsDatabase:
3317 def __init__(self):
3318 db = {}
3319 df = _DecodeFields()
3320 df.create_specs()
3321 for (form, fields) in df.instrs.items():
3322 if form in {"DQE", "TX"}:
3323 continue
3324 if form == "all":
3325 form = "NONE"
3326 db[_Form[form]] = Fields(fields)
3327
3328 self.__db = db
3329
3330 return super().__init__()
3331
3332 def __getitem__(self, key):
3333 return self.__db.__getitem__(key)
3334
3335
3336 class PPCDatabase:
3337 def __init__(self, root, mdwndb):
3338 # The code below groups the instructions by name:section.
3339 # There can be multiple names for the same instruction.
3340 # The point is to capture different opcodes for the same instruction.
3341 dd = _collections.defaultdict
3342 sections = {}
3343 records = _collections.defaultdict(set)
3344 path = (root / "insndb.csv")
3345 with open(path, "r", encoding="UTF-8") as stream:
3346 for section in sorted(parse(stream, Section.CSV)):
3347 path = (root / section.path)
3348 opcode_cls = {
3349 section.Mode.INTEGER: IntegerOpcode,
3350 section.Mode.PATTERN: PatternOpcode,
3351 }[section.mode]
3352 factory = _functools.partial(
3353 PPCRecord.CSV, opcode_cls=opcode_cls)
3354 with open(path, "r", encoding="UTF-8") as stream:
3355 for insn in parse(stream, factory):
3356 for name in insn.names:
3357 records[name].add(insn)
3358 sections[name] = section
3359
3360 items = sorted(records.items())
3361 records = {}
3362 for (name, multirecord) in items:
3363 records[name] = PPCMultiRecord(sorted(multirecord))
3364
3365 def exact_match(name):
3366 record = records.get(name)
3367 if record is None:
3368 return None
3369 return name
3370
3371 def LK_match(name):
3372 if not name.endswith("l"):
3373 return None
3374 alias = exact_match(name[:-1])
3375 if alias is None:
3376 return None
3377 record = records[alias]
3378 if "lk" not in record.flags:
3379 raise ValueError(record)
3380 return alias
3381
3382 def AA_match(name):
3383 if not name.endswith("a"):
3384 return None
3385 alias = LK_match(name[:-1])
3386 if alias is None:
3387 alias = name[:-1]
3388 record = records[alias]
3389 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
3390 raise ValueError(record)
3391 if "AA" not in mdwndb[name].operands:
3392 raise ValueError(record)
3393 return alias
3394
3395 def Rc_match(name):
3396 if not name.endswith("."):
3397 return None
3398 alias = exact_match(name[:-1])
3399 if alias is None:
3400 return None
3401 record = records[alias]
3402 if record.Rc is _RCOE.NONE:
3403 raise ValueError(record)
3404 return alias
3405
3406 db = {}
3407 matches = (exact_match, LK_match, AA_match, Rc_match)
3408 for (name, _) in mdwndb:
3409 if name.startswith("sv."):
3410 continue
3411 alias = None
3412 for match in matches:
3413 alias = match(name)
3414 if alias is not None:
3415 break
3416 if alias is None:
3417 continue
3418 section = sections[alias]
3419 record = records[alias]
3420 db[name] = (section, record)
3421
3422 self.__db = dict(sorted(db.items()))
3423
3424 return super().__init__()
3425
3426 @_functools.lru_cache(maxsize=512, typed=False)
3427 def __getitem__(self, key):
3428 return self.__db.get(key, (None, None))
3429
3430
3431 class SVP64Database:
3432 def __init__(self, root, ppcdb):
3433 db = set()
3434 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3435 for (prefix, _, names) in _os.walk(root):
3436 prefix = _pathlib.Path(prefix)
3437 for name in filter(lambda name: pattern.match(name), names):
3438 path = (prefix / _pathlib.Path(name))
3439 with open(path, "r", encoding="UTF-8") as stream:
3440 db.update(parse(stream, SVP64Record.CSV))
3441 db = {record.name:record for record in db}
3442
3443 self.__db = dict(sorted(db.items()))
3444 self.__ppcdb = ppcdb
3445
3446 return super().__init__()
3447
3448 def __getitem__(self, key):
3449 (_, record) = self.__ppcdb[key]
3450 if record is None:
3451 return None
3452
3453 for name in record.names:
3454 record = self.__db.get(name, None)
3455 if record is not None:
3456 return record
3457
3458 return None
3459
3460
3461 class Database:
3462 def __init__(self, root):
3463 root = _pathlib.Path(root)
3464 mdwndb = MarkdownDatabase()
3465 fieldsdb = FieldsDatabase()
3466 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
3467 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
3468
3469 db = set()
3470 names = {}
3471 opcodes = _collections.defaultdict(
3472 lambda: _collections.defaultdict(set))
3473
3474 for (name, mdwn) in mdwndb:
3475 if name.startswith("sv."):
3476 continue
3477 (section, ppc) = ppcdb[name]
3478 if ppc is None:
3479 continue
3480 svp64 = svp64db[name]
3481 fields = fieldsdb[ppc.form]
3482 record = Record(name=name,
3483 section=section, ppc=ppc, svp64=svp64,
3484 mdwn=mdwn, fields=fields)
3485 db.add(record)
3486 names[record.name] = record
3487 PO = section.opcode
3488 if PO is None:
3489 PO = ppc[0].opcode
3490 opcodes[section][PO.value].add(record)
3491
3492 self.__db = sorted(db)
3493 self.__names = dict(sorted(names.items()))
3494 self.__opcodes = dict(sorted(opcodes.items()))
3495
3496 return super().__init__()
3497
3498 def __repr__(self):
3499 return repr(self.__db)
3500
3501 def __iter__(self):
3502 yield from self.__db
3503
3504 @_functools.lru_cache(maxsize=None)
3505 def __contains__(self, key):
3506 return self.__getitem__(key) is not None
3507
3508 @_functools.lru_cache(maxsize=None)
3509 def __getitem__(self, key):
3510 if isinstance(key, Instruction):
3511 PO = int(key.PO)
3512 key = int(key)
3513 for (section, group) in self.__opcodes.items():
3514 for record in group[PO]:
3515 if record.match(key=key):
3516 return record
3517
3518 return None
3519
3520 elif isinstance(key, str):
3521 return self.__names.get(key)
3522
3523 raise ValueError("instruction or name expected")