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