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