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