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