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