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