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