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