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