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