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