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