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