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