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