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