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