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