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