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