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