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