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