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