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