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