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