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