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