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