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