remove accidental print
[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 5-bit, take out the lower 2 bits (EQ/LT/GT/SO)
1443 # and reduce the value down to the CR Field number only
1444 if regtype is _RegType.CR_5BIT:
1445 subvalue = (value & 0b11)
1446 value >>= 2
1447
1448 if self.record.etype is _SVEType.EXTRA2:
1449 # very reduced range
1450 if vector:
1451 # vector range is CR0-CR120 in increments of 8
1452 assert value % 8 == 0, "vector CR cannot fit into EXTRA2"
1453 extra = 0b10 | ((value>>3)&0b1)
1454 value >>= 4
1455 else:
1456 # scalar range is CR0-CR15 in increments of 1
1457 assert value < 16, "scalar CR cannot fit into EXTRA2"
1458 extra = (value >> 4)
1459 value &= 0b1111
1460 elif self.record.etype is _SVEType.EXTRA3:
1461 if vector:
1462 # vector range is CR0-CR124 in increments of 4
1463 assert value % 4 == 0, "vector CR cannot fit into EXTRA3"
1464 extra = 0b100 | ((value>>2)&0b1)
1465 value >>= 3
1466 else:
1467 # scalar range is CR0-CR31 in increments of 1
1468 assert value < 32, "scalar CR cannot fit into EXTRA3"
1469 extra = (value >> 3)
1470 value &= 0b111
1471
1472 # if 5-bit, restore the 2 lower 2 bits
1473 if regtype is _RegType.CR_5BIT:
1474 value = ((value << 2) | subvalue)
1475
1476 return (value, extra)
1477
1478 def assemble(self, insn, value):
1479 if isinstance(value, str):
1480 vector = False
1481
1482 if value.startswith("*"):
1483 if not isinstance(insn, SVP64Instruction):
1484 raise ValueError(value)
1485 value = value[1:]
1486 vector = True
1487
1488 for (name, pattern) in reversed(self.__class__.PATTERNS):
1489 match = pattern.match(value)
1490 if match is not None:
1491 keys = name.replace("+", "_").replace("*", "_").split("_")
1492 values = match.groups()
1493 match = dict(zip(keys, values))
1494 CR = int(match["CR"])
1495 if name == "XCR":
1496 N = 4
1497 else:
1498 N = int(match.get("N", "1"))
1499 BIT = self.__class__.CONDS[match.get("BIT", "lt")]
1500 value = ((CR * N) + BIT)
1501 break
1502
1503 value = str(value)
1504 if vector:
1505 value = f"*{value}"
1506
1507 return super().assemble(value=value, insn=insn, prefix="cr")
1508
1509 def disassemble(self, insn,
1510 style=Style.NORMAL, prefix="", indent=""):
1511 (vector, value, span) = self.sv_spec(insn=insn)
1512
1513 if style >= Style.VERBOSE:
1514 mode = "vector" if vector else "scalar"
1515 yield f"{indent}{self.name} ({mode})"
1516 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1517 yield f"{indent}{indent}{', '.join(span)}"
1518 if isinstance(insn, SVP64Instruction):
1519 for extra_idx in frozenset(self.extra_idx):
1520 if self.record.etype is _SVEType.NONE:
1521 yield f"{indent}{indent}extra[none]"
1522 else:
1523 etype = repr(self.record.etype).lower()
1524 yield f"{indent}{indent}{etype}{extra_idx!r}"
1525 else:
1526 vector = "*" if vector else ""
1527 CR = int(value >> 2)
1528 CC = int(value & 3)
1529 cond = ("lt", "gt", "eq", "so")[CC]
1530 if style >= Style.NORMAL:
1531 if CR != 0:
1532 if isinstance(insn, SVP64Instruction):
1533 yield f"{vector}cr{CR}.{cond}"
1534 else:
1535 yield f"4*cr{CR}+{cond}"
1536 else:
1537 yield cond
1538 else:
1539 yield f"{vector}{prefix}{int(value)}"
1540
1541
1542 class CR3Operand(ConditionRegisterFieldOperand):
1543 def remap(self, value, vector):
1544 return super().remap(value=value, vector=vector,
1545 regtype=_RegType.CR_3BIT)
1546
1547
1548 class CR5Operand(ConditionRegisterFieldOperand):
1549 def remap(self, value, vector):
1550 return super().remap(value=value, vector=vector,
1551 regtype=_RegType.CR_5BIT)
1552
1553 def sv_spec_enter(self, value, span):
1554 value = _SelectableInt(value=(value.value >> 2), bits=3)
1555 return (value, span)
1556
1557 def sv_spec_leave(self, value, span, origin_value, origin_span):
1558 value = _selectconcat(value, origin_value[3:5])
1559 span += origin_span
1560 return (value, span)
1561
1562
1563 class EXTSOperand(SignedOperand):
1564 field: str # real name to report
1565 nz: int = 0 # number of zeros
1566 fmt: str = "d" # integer formatter
1567
1568 def __init__(self, record, name, field, nz=0, fmt="d"):
1569 self.__field = field
1570 self.__nz = nz
1571 self.__fmt = fmt
1572 return super().__init__(record=record, name=name)
1573
1574 @property
1575 def field(self):
1576 return self.__field
1577
1578 @property
1579 def nz(self):
1580 return self.__nz
1581
1582 @property
1583 def fmt(self):
1584 return self.__fmt
1585
1586 @cached_property
1587 def span(self):
1588 return self.record.fields[self.field]
1589
1590 def assemble(self, insn, value):
1591 span = self.span
1592 if isinstance(value, str):
1593 value = int(value, 0)
1594 insn[span] = (value >> self.nz)
1595
1596 def disassemble(self, insn,
1597 style=Style.NORMAL, indent=""):
1598 span = self.span
1599 value = insn[span].to_signed_int()
1600 sign = "-" if (value < 0) else ""
1601 value = (abs(value) << self.nz)
1602
1603 if style >= Style.VERBOSE:
1604 span = (tuple(map(str, span)) + (("{0}",) * self.nz))
1605 zeros = ("0" * self.nz)
1606 hint = f"{self.name} = EXTS({self.field} || {zeros})"
1607 yield f"{indent * 1}{hint}"
1608 yield f"{indent * 2}{self.field}"
1609 yield f"{indent * 3}{sign}{value:{self.fmt}}"
1610 yield f"{indent * 3}{', '.join(span)}"
1611 else:
1612 yield f"{sign}{value:{self.fmt}}"
1613
1614
1615 class TargetAddrOperand(EXTSOperand):
1616 def __init__(self, record, name, field):
1617 return super().__init__(record=record, name=name, field=field,
1618 nz=2, fmt="#x")
1619
1620
1621 class TargetAddrOperandLI(TargetAddrOperand):
1622 def __init__(self, record, name):
1623 return super().__init__(record=record, name=name, field="LI")
1624
1625
1626 class TargetAddrOperandBD(TargetAddrOperand):
1627 def __init__(self, record, name):
1628 return super().__init__(record=record, name=name, field="BD")
1629
1630
1631 class EXTSOperandDS(EXTSOperand, ImmediateOperand):
1632 def __init__(self, record, name):
1633 return super().__init__(record=record, name=name, field="DS", nz=2)
1634
1635
1636 class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
1637 def __init__(self, record, name):
1638 return super().__init__(record=record, name=name, field="DQ", nz=4)
1639
1640
1641 class DOperandDX(SignedOperand):
1642 @cached_property
1643 def span(self):
1644 cls = lambda name: DynamicOperand(record=self.record, name=name)
1645 operands = map(cls, ("d0", "d1", "d2"))
1646 spans = map(lambda operand: operand.span, operands)
1647 return sum(spans, tuple())
1648
1649 def disassemble(self, insn,
1650 style=Style.NORMAL, indent=""):
1651 span = self.span
1652 value = insn[span].to_signed_int()
1653 sign = "-" if (value < 0) else ""
1654 value = abs(value)
1655
1656 if style >= Style.VERBOSE:
1657 yield f"{indent}D"
1658 mapping = {
1659 "d0": "[0:9]",
1660 "d1": "[10:15]",
1661 "d2": "[16]",
1662 }
1663 for (subname, subspan) in mapping.items():
1664 operand = DynamicOperand(name=subname)
1665 span = operand.span
1666 span = map(str, span)
1667 yield f"{indent}{indent}{operand.name} = D{subspan}"
1668 yield f"{indent}{indent}{indent}{sign}{value}"
1669 yield f"{indent}{indent}{indent}{', '.join(span)}"
1670 else:
1671 yield f"{sign}{value}"
1672
1673
1674 class Instruction(_Mapping):
1675 @classmethod
1676 def integer(cls, value=0, bits=None, byteorder="little"):
1677 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1678 raise ValueError(bits)
1679
1680 if isinstance(value, bytes):
1681 if ((len(value) * 8) != bits):
1682 raise ValueError(f"bit length mismatch")
1683 value = int.from_bytes(value, byteorder=byteorder)
1684
1685 if isinstance(value, int):
1686 value = _SelectableInt(value=value, bits=bits)
1687 elif isinstance(value, Instruction):
1688 value = value.storage
1689
1690 if not isinstance(value, _SelectableInt):
1691 raise ValueError(value)
1692 if bits is None:
1693 bits = len(cls)
1694 if len(value) != bits:
1695 raise ValueError(value)
1696
1697 value = _SelectableInt(value=value, bits=bits)
1698
1699 return cls(storage=value)
1700
1701 def __hash__(self):
1702 return hash(int(self))
1703
1704 def __getitem__(self, key):
1705 return self.storage.__getitem__(key)
1706
1707 def __setitem__(self, key, value):
1708 return self.storage.__setitem__(key, value)
1709
1710 def bytes(self, byteorder="little"):
1711 nr_bytes = (len(self.__class__) // 8)
1712 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1713
1714 @classmethod
1715 def record(cls, db, entry):
1716 record = db[entry]
1717 if record is None:
1718 raise KeyError(entry)
1719 return record
1720
1721 @classmethod
1722 def operands(cls, record):
1723 yield from record.operands
1724
1725 @classmethod
1726 def static_operands(cls, record):
1727 return filter(lambda operand: isinstance(operand, StaticOperand),
1728 cls.operands(record=record))
1729
1730 @classmethod
1731 def dynamic_operands(cls, record):
1732 return filter(lambda operand: isinstance(operand, DynamicOperand),
1733 cls.operands(record=record))
1734
1735 def spec(self, record, prefix):
1736 dynamic_operands = tuple(map(_operator.itemgetter(0),
1737 self.spec_dynamic_operands(record=record)))
1738
1739 static_operands = []
1740 for (name, value) in self.spec_static_operands(record=record):
1741 static_operands.append(f"{name}={value}")
1742
1743 operands = ""
1744 if dynamic_operands:
1745 operands += " "
1746 operands += ",".join(dynamic_operands)
1747 if static_operands:
1748 operands += " "
1749 operands += " ".join(static_operands)
1750
1751 return f"{prefix}{record.name}{operands}"
1752
1753 def spec_static_operands(self, record):
1754 for operand in self.static_operands(record=record):
1755 if not isinstance(operand, (POStaticOperand, XOStaticOperand)):
1756 yield (operand.name, operand.value)
1757
1758 def spec_dynamic_operands(self, record, style=Style.NORMAL):
1759 imm = False
1760 imm_name = ""
1761 imm_value = ""
1762 for operand in self.dynamic_operands(record=record):
1763 name = operand.name
1764 value = " ".join(operand.disassemble(insn=self,
1765 style=min(style, Style.NORMAL)))
1766 if imm:
1767 name = f"{imm_name}({name})"
1768 value = f"{imm_value}({value})"
1769 imm = False
1770 if isinstance(operand, ImmediateOperand):
1771 imm_name = name
1772 imm_value = value
1773 imm = True
1774 if not imm:
1775 yield (name, value)
1776
1777 @classmethod
1778 def assemble(cls, record, arguments=None):
1779 if arguments is None:
1780 arguments = ()
1781
1782 insn = cls.integer(value=0)
1783
1784 for operand in cls.static_operands(record=record):
1785 operand.assemble(insn=insn)
1786
1787 arguments = Arguments(record=record,
1788 arguments=arguments, operands=cls.dynamic_operands(record=record))
1789 for (value, operand) in arguments:
1790 operand.assemble(insn=insn, value=value)
1791
1792 return insn
1793
1794 def disassemble(self, record,
1795 byteorder="little",
1796 style=Style.NORMAL):
1797 raise NotImplementedError()
1798
1799
1800 class WordInstruction(Instruction):
1801 _: _Field = range(0, 32)
1802 PO: _Field = range(0, 6)
1803
1804 @classmethod
1805 def integer(cls, value, byteorder="little"):
1806 return super().integer(bits=32, value=value, byteorder=byteorder)
1807
1808 @property
1809 def binary(self):
1810 bits = []
1811 for idx in range(32):
1812 bit = int(self[idx])
1813 bits.append(bit)
1814 return "".join(map(str, bits))
1815
1816 def disassemble(self, record,
1817 byteorder="little",
1818 style=Style.NORMAL):
1819 if style <= Style.SHORT:
1820 blob = ""
1821 else:
1822 blob = self.bytes(byteorder=byteorder)
1823 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1824 blob += " "
1825
1826 if record is None:
1827 yield f"{blob}.long 0x{int(self):08x}"
1828 return
1829
1830 # awful temporary hack: workaround for ld-update
1831 # https://bugs.libre-soc.org/show_bug.cgi?id=1056#c2
1832 # XXX TODO must check that *EXTENDED* RA != extended-RT
1833 if (record.svp64 is not None and
1834 record.mode == _SVMode.LDST_IMM and
1835 'u' in record.name):
1836 yield f"{blob}.long 0x{int(self):08x}"
1837 return
1838
1839 paired = False
1840 if style is Style.LEGACY:
1841 paired = False
1842 for operand in self.dynamic_operands(record=record):
1843 if isinstance(operand, (GPRPairOperand, FPRPairOperand)):
1844 paired = True
1845
1846 # unofficial == "0" means an official instruction that needs .long
1847 if style is Style.LEGACY and (paired or record.ppc.unofficial != ""):
1848 yield f"{blob}.long 0x{int(self):08x}"
1849 else:
1850 operands = tuple(map(_operator.itemgetter(1),
1851 self.spec_dynamic_operands(record=record, style=style)))
1852 if operands:
1853 operands = ",".join(operands)
1854 yield f"{blob}{record.name} {operands}"
1855 else:
1856 yield f"{blob}{record.name}"
1857
1858 if style >= Style.VERBOSE:
1859 indent = (" " * 4)
1860 binary = self.binary
1861 spec = self.spec(record=record, prefix="")
1862 yield f"{indent}spec"
1863 yield f"{indent}{indent}{spec}"
1864 yield f"{indent}pcode"
1865 for stmt in record.mdwn.pcode:
1866 yield f"{indent}{indent}{stmt}"
1867 yield f"{indent}binary"
1868 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1869 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1870 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1871 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1872 yield f"{indent}opcodes"
1873 for opcode in record.opcodes:
1874 yield f"{indent}{indent}{opcode!r}"
1875 for operand in self.operands(record=record):
1876 yield from operand.disassemble(insn=self,
1877 style=style, indent=indent)
1878 yield ""
1879
1880
1881 class PrefixedInstruction(Instruction):
1882 class Prefix(WordInstruction.remap(range(0, 32))):
1883 pass
1884
1885 class Suffix(WordInstruction.remap(range(32, 64))):
1886 pass
1887
1888 _: _Field = range(64)
1889 prefix: Prefix
1890 suffix: Suffix
1891 PO: Suffix.PO
1892
1893 @classmethod
1894 def integer(cls, value, byteorder="little"):
1895 return super().integer(bits=64, value=value, byteorder=byteorder)
1896
1897 @classmethod
1898 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1899 def transform(value):
1900 return WordInstruction.integer(value=value,
1901 byteorder=byteorder)[0:32]
1902
1903 (prefix, suffix) = map(transform, (prefix, suffix))
1904 value = _selectconcat(prefix, suffix)
1905
1906 return super().integer(bits=64, value=value)
1907
1908
1909 class Mode(_Mapping):
1910 _: _Field = range(0, 5)
1911 sel: _Field = (0, 1)
1912
1913
1914 class ExtraRM(_Mapping):
1915 _: _Field = range(0, 9)
1916
1917
1918 class Extra2RM(ExtraRM):
1919 idx0: _Field = range(0, 2)
1920 idx1: _Field = range(2, 4)
1921 idx2: _Field = range(4, 6)
1922 idx3: _Field = range(6, 8)
1923
1924 def __getitem__(self, key):
1925 return {
1926 0: self.idx0,
1927 1: self.idx1,
1928 2: self.idx2,
1929 3: self.idx3,
1930 _SVExtra.Idx0: self.idx0,
1931 _SVExtra.Idx1: self.idx1,
1932 _SVExtra.Idx2: self.idx2,
1933 _SVExtra.Idx3: self.idx3,
1934 }[key]
1935
1936 def __setitem__(self, key, value):
1937 self[key].assign(value)
1938
1939
1940 class Extra3RM(ExtraRM):
1941 idx0: _Field = range(0, 3)
1942 idx1: _Field = range(3, 6)
1943 idx2: _Field = range(6, 9)
1944
1945 def __getitem__(self, key):
1946 return {
1947 0: self.idx0,
1948 1: self.idx1,
1949 2: self.idx2,
1950 _SVExtra.Idx0: self.idx0,
1951 _SVExtra.Idx1: self.idx1,
1952 _SVExtra.Idx2: self.idx2,
1953 }[key]
1954
1955 def __setitem__(self, key, value):
1956 self[key].assign(value)
1957
1958
1959 class BaseRM(_Mapping):
1960 _: _Field = range(24)
1961 mmode: _Field = (0,)
1962 mask: _Field = range(1, 4)
1963 elwidth: _Field = range(4, 6)
1964 ewsrc: _Field = range(6, 8)
1965 subvl: _Field = range(8, 10)
1966 mode: Mode.remap(range(19, 24))
1967 smask_extra322: _Field = (6,7,18,) # LDST_IDX is EXTRA332
1968 smask: _Field = range(16, 19) # everything else use this
1969 extra: ExtraRM.remap(range(10, 19))
1970 extra2: Extra2RM.remap(range(10, 19))
1971 extra3: Extra3RM.remap(range(10, 19))
1972 # XXX extra332 = (extra3[0], extra3[1], extra2[3])
1973
1974 def specifiers(self, record):
1975 subvl = int(self.subvl)
1976 if subvl > 0:
1977 yield {
1978 1: "vec2",
1979 2: "vec3",
1980 3: "vec4",
1981 }[subvl]
1982
1983 def disassemble(self, style=Style.NORMAL):
1984 if style >= Style.VERBOSE:
1985 indent = (" " * 4)
1986 for (name, span) in self.traverse(path="RM"):
1987 value = self.storage[span]
1988 yield f"{name}"
1989 yield f"{indent}{int(value):0{value.bits}b}"
1990 yield f"{indent}{', '.join(map(str, span))}"
1991
1992
1993 class FFRc1BaseRM(BaseRM):
1994 def specifiers(self, record, mode):
1995 inv = _SelectableInt(value=int(self.inv), bits=1)
1996 CR = _SelectableInt(value=int(self.CR), bits=2)
1997 mask = int(_selectconcat(CR, inv))
1998 predicate = PredicateBaseRM.predicate(True, mask)
1999 yield f"{mode}={predicate}"
2000
2001 yield from super().specifiers(record=record)
2002
2003
2004 class FFRc0BaseRM(BaseRM):
2005 def specifiers(self, record, mode):
2006 if self.RC1:
2007 inv = "~" if self.inv else ""
2008 yield f"{mode}={inv}RC1"
2009
2010 yield from super().specifiers(record=record)
2011
2012
2013 class SatBaseRM(BaseRM):
2014 def specifiers(self, record):
2015 if self.N:
2016 yield "sats"
2017 else:
2018 yield "satu"
2019
2020 yield from super().specifiers(record=record)
2021
2022
2023 class ZZBaseRM(BaseRM):
2024 def specifiers(self, record):
2025 if self.zz:
2026 yield "zz"
2027
2028 yield from super().specifiers(record=record)
2029
2030
2031 class ZZCombinedBaseRM(BaseRM):
2032 def specifiers(self, record):
2033 if self.sz and self.dz:
2034 yield "zz"
2035 elif self.sz:
2036 yield "sz"
2037 elif self.dz:
2038 yield "dz"
2039
2040 yield from super().specifiers(record=record)
2041
2042
2043 class DZBaseRM(BaseRM):
2044 def specifiers(self, record):
2045 if self.dz:
2046 yield "dz"
2047
2048 yield from super().specifiers(record=record)
2049
2050
2051 class SZBaseRM(BaseRM):
2052 def specifiers(self, record):
2053 if self.sz:
2054 yield "sz"
2055
2056 yield from super().specifiers(record=record)
2057
2058
2059 class MRBaseRM(BaseRM):
2060 def specifiers(self, record):
2061 if self.RG:
2062 yield "mrr"
2063 else:
2064 yield "mr"
2065
2066 yield from super().specifiers(record=record)
2067
2068
2069 class ElsBaseRM(BaseRM):
2070 def specifiers(self, record):
2071 if self.els:
2072 yield "els"
2073
2074 yield from super().specifiers(record=record)
2075
2076
2077 class WidthBaseRM(BaseRM):
2078 @staticmethod
2079 def width(FP, width):
2080 width = {
2081 0b11: "8",
2082 0b10: "16",
2083 0b01: "32",
2084 }.get(width)
2085 if width is None:
2086 return None
2087 if FP:
2088 width = ("fp" + width)
2089 return width
2090
2091 def specifiers(self, record):
2092 # elwidths: use "w=" if same otherwise dw/sw
2093 # FIXME this should consider FP instructions
2094 FP = False
2095 dw = WidthBaseRM.width(FP, int(self.elwidth))
2096 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2097 if record.svp64.mode is _SVMode.CROP:
2098 if dw:
2099 yield ("dw=" + dw)
2100 else:
2101 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2102 if dw == sw and dw:
2103 yield ("w=" + dw)
2104 else:
2105 if dw:
2106 yield ("dw=" + dw)
2107 if sw:
2108 yield ("sw=" + sw)
2109
2110 yield from super().specifiers(record=record)
2111
2112
2113 class PredicateBaseRM(BaseRM):
2114 @staticmethod
2115 def predicate(CR, mask):
2116 return {
2117 # integer
2118 (False, 0b001): "1<<r3",
2119 (False, 0b010): "r3",
2120 (False, 0b011): "~r3",
2121 (False, 0b100): "r10",
2122 (False, 0b101): "~r10",
2123 (False, 0b110): "r30",
2124 (False, 0b111): "~r30",
2125 # CRs
2126 (True, 0b000): "lt",
2127 (True, 0b001): "ge",
2128 (True, 0b010): "gt",
2129 (True, 0b011): "le",
2130 (True, 0b100): "eq",
2131 (True, 0b101): "ne",
2132 (True, 0b110): "so",
2133 (True, 0b111): "ns",
2134 }.get((CR, mask))
2135
2136 def specifiers(self, record):
2137 # predication - single and twin
2138 # use "m=" if same otherwise sm/dm
2139 CR = (int(self.mmode) == 1)
2140 mask = int(self.mask)
2141 sm = dm = PredicateBaseRM.predicate(CR, mask)
2142 if record.svp64.ptype is _SVPType.P2:
2143 # LDST_IDX smask moving to extra322 but not straight away (False)
2144 if False and record.svp64.mode is _SVMode.LDST_IDX:
2145 smask = int(self.smask_extra332)
2146 else:
2147 smask = int(self.smask)
2148 sm = PredicateBaseRM.predicate(CR, smask)
2149 if sm == dm and dm:
2150 yield ("m=" + dm)
2151 else:
2152 if sm:
2153 yield ("sm=" + sm)
2154 if dm:
2155 yield ("dm=" + dm)
2156
2157 yield from super().specifiers(record=record)
2158
2159
2160 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
2161 pass
2162
2163
2164 class SEABaseRM(BaseRM):
2165 def specifiers(self, record):
2166 if self.SEA:
2167 yield "sea"
2168
2169 yield from super().specifiers(record=record)
2170
2171
2172 class VLiBaseRM(BaseRM):
2173 def specifiers(self, record):
2174 if self.VLi:
2175 yield "vli"
2176
2177 yield from super().specifiers(record=record)
2178
2179
2180 class NormalBaseRM(PredicateWidthBaseRM):
2181 """
2182 Normal mode
2183 https://libre-soc.org/openpower/sv/normal/
2184 """
2185 pass
2186
2187
2188 class NormalSimpleRM(ZZCombinedBaseRM, NormalBaseRM):
2189 """normal: simple mode"""
2190 dz: BaseRM.mode[3]
2191 sz: BaseRM.mode[4]
2192
2193 def specifiers(self, record):
2194 yield from super().specifiers(record=record)
2195
2196
2197 class NormalMRRM(MRBaseRM, NormalBaseRM):
2198 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2199 RG: BaseRM.mode[4]
2200
2201
2202 class NormalFFRc1RM(FFRc1BaseRM, VLiBaseRM, NormalBaseRM):
2203 """normal: Rc=1: ffirst CR sel"""
2204 VLi: BaseRM.mode[0]
2205 inv: BaseRM.mode[2]
2206 CR: BaseRM.mode[3, 4]
2207
2208 def specifiers(self, record):
2209 yield from super().specifiers(record=record, mode="ff")
2210
2211
2212 class NormalFFRc0RM(FFRc0BaseRM, VLiBaseRM, NormalBaseRM):
2213 """normal: Rc=0: ffirst z/nonz"""
2214 VLi: BaseRM.mode[0]
2215 inv: BaseRM.mode[2]
2216 RC1: BaseRM.mode[4]
2217
2218 def specifiers(self, record):
2219 yield from super().specifiers(record=record, mode="ff")
2220
2221
2222 class NormalSatRM(SatBaseRM, ZZCombinedBaseRM, NormalBaseRM):
2223 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2224 N: BaseRM.mode[2]
2225 dz: BaseRM.mode[3]
2226 sz: BaseRM.mode[4]
2227
2228
2229 class NormalRM(NormalBaseRM):
2230 simple: NormalSimpleRM
2231 mr: NormalMRRM
2232 ffrc1: NormalFFRc1RM
2233 ffrc0: NormalFFRc0RM
2234 sat: NormalSatRM
2235
2236
2237 class LDSTImmBaseRM(PredicateWidthBaseRM):
2238 """
2239 LD/ST Immediate mode
2240 https://libre-soc.org/openpower/sv/ldst/
2241 """
2242 pass
2243
2244
2245 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
2246 """ld/st immediate: simple mode"""
2247 pi: BaseRM.mode[2] # Post-Increment Mode
2248 lf: BaseRM.mode[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2249 zz: BaseRM.mode[3]
2250 els: BaseRM.mode[0]
2251 dz: BaseRM.mode[3]
2252 sz: BaseRM.mode[3]
2253
2254 def specifiers(self, record):
2255 if self.pi:
2256 yield "pi"
2257 if self.lf:
2258 yield "lf"
2259
2260 yield from super().specifiers(record=record)
2261
2262
2263 class LDSTFFRc1RM(FFRc1BaseRM, VLiBaseRM, LDSTImmBaseRM):
2264 """ld/st immediate&indexed: Rc=1: ffirst CR sel"""
2265 VLi: BaseRM.mode[0]
2266 inv: BaseRM.mode[2]
2267 CR: BaseRM.mode[3, 4]
2268
2269 def specifiers(self, record):
2270 yield from super().specifiers(record=record, mode="ff")
2271
2272
2273 class LDSTFFRc0RM(FFRc0BaseRM, VLiBaseRM, LDSTImmBaseRM):
2274 """ld/st immediate&indexed: Rc=0: ffirst z/nonz"""
2275 VLi: BaseRM.mode[0]
2276 inv: BaseRM.mode[2]
2277 RC1: BaseRM.mode[4]
2278
2279 def specifiers(self, record):
2280 yield from super().specifiers(record=record, mode="ff")
2281
2282
2283 class LDSTImmRM(LDSTImmBaseRM):
2284 simple: LDSTImmSimpleRM
2285 ffrc1: LDSTFFRc1RM
2286 ffrc0: LDSTFFRc0RM
2287
2288
2289 class LDSTIdxBaseRM(PredicateWidthBaseRM):
2290 """
2291 LD/ST Indexed mode
2292 https://libre-soc.org/openpower/sv/ldst/
2293 """
2294 pass
2295
2296
2297 class LDSTIdxSimpleRM(SEABaseRM, ZZBaseRM, LDSTIdxBaseRM):
2298 """ld/st index: simple mode (includes element-strided and Signed-EA)"""
2299 pi: BaseRM.mode[2] # Post-Increment Mode
2300 els: BaseRM.mode[0]
2301 SEA: BaseRM.mode[4]
2302 zz: BaseRM.mode[3]
2303 dz: BaseRM.mode[3]
2304 sz: BaseRM.mode[3]
2305
2306 def specifiers(self, record):
2307 if self.els:
2308 yield "els"
2309 if self.pi:
2310 yield "pi"
2311
2312 yield from super().specifiers(record=record)
2313
2314
2315 class LDSTIdxRM(LDSTIdxBaseRM):
2316 simple: LDSTIdxSimpleRM
2317 ffrc1: LDSTFFRc1RM
2318 ffrc0: LDSTFFRc0RM
2319
2320
2321
2322 class CROpBaseRM(BaseRM):
2323 """
2324 CR ops mode
2325 https://libre-soc.org/openpower/sv/cr_ops/
2326 """
2327 SNZ: BaseRM[7]
2328
2329
2330 class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2331 """crop: simple mode"""
2332 RG: BaseRM[21]
2333 dz: BaseRM[22]
2334 sz: BaseRM[23]
2335
2336 def specifiers(self, record):
2337 if self.RG:
2338 yield "rg" # simple CR Mode reports /rg
2339
2340 yield from super().specifiers(record=record)
2341
2342
2343 class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2344 """crop: scalar reduce mode (mapreduce)"""
2345 RG: BaseRM[21]
2346 dz: BaseRM[22]
2347 sz: BaseRM[23]
2348
2349
2350 class CROpFF5RM(FFRc0BaseRM, PredicateBaseRM, VLiBaseRM, DZBaseRM,
2351 SZBaseRM, CROpBaseRM):
2352 """crop: ffirst 5-bit mode"""
2353 VLi: BaseRM[19]
2354 RC1 = 1
2355 inv: BaseRM[21]
2356 dz: BaseRM[22]
2357 sz: BaseRM[23]
2358
2359 def specifiers(self, record):
2360 yield from super().specifiers(record=record, mode="ff")
2361
2362
2363 # FIXME: almost everything in this class contradicts the specs (it doesn't)
2364 # The modes however are swapped: 5-bit is 3-bit, 3-bit is 5-bit
2365 class CROpFF3RM(FFRc1BaseRM, PredicateBaseRM, VLiBaseRM, ZZBaseRM, CROpBaseRM):
2366 """cr_op: ffirst 3-bit mode"""
2367 VLi: BaseRM[19]
2368 inv: BaseRM[21]
2369 CR: BaseRM[22, 23]
2370 zz: BaseRM[6]
2371
2372 def specifiers(self, record):
2373 yield from super().specifiers(record=record, mode="ff")
2374
2375
2376 class CROpRM(CROpBaseRM):
2377 simple: CROpSimpleRM
2378 mr: CROpMRRM
2379 ff3: CROpFF3RM
2380 ff5: CROpFF5RM
2381
2382
2383 # ********************
2384 # Branches mode
2385 # https://libre-soc.org/openpower/sv/branches/
2386 class BranchBaseRM(BaseRM):
2387 ALL: BaseRM[4]
2388 SNZ: BaseRM[5]
2389 SL: BaseRM[17]
2390 SLu: BaseRM[18]
2391 LRu: BaseRM[22]
2392 sz: BaseRM[23]
2393 CTR: BaseRM[19]
2394 VLS: BaseRM[20]
2395
2396 def specifiers(self, record):
2397 if self.ALL:
2398 yield "all"
2399
2400 # /sz
2401 # branch.sz=1
2402 # branch.snz=0
2403 # /snz
2404 # branch.sz=1
2405 # branch.snz=1
2406 if self.SNZ:
2407 if not self.sz:
2408 raise ValueError(self.sz)
2409 yield "snz"
2410 elif self.sz:
2411 yield "sz"
2412
2413 if self.SL:
2414 yield "sl"
2415 if self.SLu:
2416 yield "slu"
2417 if self.LRu:
2418 yield "lru"
2419
2420 # Branch modes lack source mask.
2421 # Therefore a custom code is needed.
2422 CR = (int(self.mmode) == 1)
2423 mask = int(self.mask)
2424 m = PredicateBaseRM.predicate(CR, mask)
2425 if m is not None:
2426 yield ("m=" + m)
2427
2428 yield from super().specifiers(record=record)
2429
2430
2431 class BranchSimpleRM(BranchBaseRM):
2432 """branch: simple mode"""
2433 pass
2434
2435
2436 class BranchVLSRM(BranchBaseRM):
2437 """branch: VLSET mode"""
2438 VSb: BaseRM[7]
2439 VLi: BaseRM[21]
2440
2441 def specifiers(self, record):
2442 yield {
2443 (0b0, 0b0): "vs",
2444 (0b0, 0b1): "vsi",
2445 (0b1, 0b0): "vsb",
2446 (0b1, 0b1): "vsbi",
2447 }[int(self.VSb), int(self.VLi)]
2448
2449 yield from super().specifiers(record=record)
2450
2451
2452 class BranchCTRRM(BranchBaseRM):
2453 """branch: CTR-test mode"""
2454 CTi: BaseRM[6]
2455
2456 def specifiers(self, record):
2457 if self.CTi:
2458 yield "cti"
2459 else:
2460 yield "ctr"
2461
2462 yield from super().specifiers(record=record)
2463
2464
2465 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
2466 """branch: CTR-test+VLSET mode"""
2467 pass
2468
2469
2470 class BranchRM(BranchBaseRM):
2471 simple: BranchSimpleRM
2472 vls: BranchVLSRM
2473 ctr: BranchCTRRM
2474 ctrvls: BranchCTRVLSRM
2475
2476
2477 class RM(BaseRM):
2478 normal: NormalRM
2479 ldst_imm: LDSTImmRM
2480 ldst_idx: LDSTIdxRM
2481 crop: CROpRM
2482 branch: BranchRM
2483
2484
2485 @_dataclasses.dataclass(eq=True, frozen=True)
2486 class Specifier:
2487 record: Record
2488
2489 @classmethod
2490 def match(cls, desc, record):
2491 raise NotImplementedError()
2492
2493 def validate(self, others):
2494 pass
2495
2496 def assemble(self, insn):
2497 raise NotImplementedError()
2498
2499
2500 @_dataclasses.dataclass(eq=True, frozen=True)
2501 class SpecifierWidth(Specifier):
2502 width: _SVP64Width
2503
2504 @classmethod
2505 def match(cls, desc, record, etalon):
2506 (mode, _, value) = desc.partition("=")
2507 mode = mode.strip()
2508 value = value.strip()
2509 if mode != etalon:
2510 return None
2511 width = _SVP64Width(value)
2512
2513 return cls(record=record, width=width)
2514
2515
2516 @_dataclasses.dataclass(eq=True, frozen=True)
2517 class SpecifierW(SpecifierWidth):
2518 @classmethod
2519 def match(cls, desc, record):
2520 return super().match(desc=desc, record=record, etalon="w")
2521
2522 def assemble(self, insn):
2523 selector = insn.select(record=self.record)
2524 if self.record.svp64.mode is not _SVMode.CROP:
2525 selector.ewsrc = self.width.value
2526 selector.elwidth = self.width.value
2527
2528
2529 @_dataclasses.dataclass(eq=True, frozen=True)
2530 class SpecifierSW(SpecifierWidth):
2531 @classmethod
2532 def match(cls, desc, record):
2533 if record.svp64.mode is _SVMode.CROP:
2534 return None
2535 return super().match(desc=desc, record=record, etalon="sw")
2536
2537 def assemble(self, insn):
2538 selector = insn.select(record=self.record)
2539 selector.ewsrc = self.width.value
2540
2541
2542 @_dataclasses.dataclass(eq=True, frozen=True)
2543 class SpecifierDW(SpecifierWidth):
2544 @classmethod
2545 def match(cls, desc, record):
2546 return super().match(desc=desc, record=record, etalon="dw")
2547
2548 def assemble(self, insn):
2549 selector = insn.select(record=self.record)
2550 selector.elwidth = self.width.value
2551
2552
2553 @_dataclasses.dataclass(eq=True, frozen=True)
2554 class SpecifierSubVL(Specifier):
2555 value: _SVP64SubVL
2556
2557 @classmethod
2558 def match(cls, desc, record):
2559 try:
2560 value = _SVP64SubVL(desc)
2561 except ValueError:
2562 return None
2563
2564 return cls(record=record, value=value)
2565
2566 def assemble(self, insn):
2567 selector = insn.select(record=self.record)
2568 selector.subvl = int(self.value.value)
2569
2570
2571 @_dataclasses.dataclass(eq=True, frozen=True)
2572 class SpecifierPredicate(Specifier):
2573 mode: str
2574 pred: _SVP64Pred
2575
2576 @classmethod
2577 def match(cls, desc, record, mode_match, pred_match):
2578 (mode, _, pred) = desc.partition("=")
2579
2580 mode = mode.strip()
2581 if not mode_match(mode):
2582 return None
2583
2584 pred = _SVP64Pred(pred.strip())
2585 if not pred_match(pred):
2586 raise ValueError(pred)
2587
2588 return cls(record=record, mode=mode, pred=pred)
2589
2590
2591 @_dataclasses.dataclass(eq=True, frozen=True)
2592 class SpecifierFF(SpecifierPredicate):
2593 @classmethod
2594 def match(cls, desc, record):
2595 return super().match(desc=desc, record=record,
2596 mode_match=lambda mode_arg: mode_arg == "ff",
2597 pred_match=lambda pred_arg: pred_arg.mode in (
2598 _SVP64PredMode.CR,
2599 _SVP64PredMode.RC1,
2600 ))
2601
2602 def assemble(self, insn):
2603 selector = insn.select(record=self.record)
2604 if selector.mode.sel != 0:
2605 raise ValueError("cannot override mode")
2606 if self.record.svp64.mode is _SVMode.CROP:
2607 selector.mode.sel = 0b01
2608 # HACK: please finally provide correct logic for CRs.
2609 if self.pred in (_SVP64Pred.RC1, _SVP64Pred.RC1_N):
2610 selector.mode[2] = (self.pred is _SVP64Pred.RC1_N)
2611 else:
2612 selector.mode[2] = self.pred.inv
2613 selector.mode[3, 4] = self.pred.state
2614 else:
2615 selector.mode.sel = 0b01 if self.mode == "ff" else 0b11
2616 selector.inv = self.pred.inv
2617 if self.record.Rc:
2618 selector.CR = self.pred.state
2619 else:
2620 selector.RC1 = self.pred.state
2621
2622
2623 @_dataclasses.dataclass(eq=True, frozen=True)
2624 class SpecifierMask(SpecifierPredicate):
2625 @classmethod
2626 def match(cls, desc, record, mode):
2627 return super().match(desc=desc, record=record,
2628 mode_match=lambda mode_arg: mode_arg == mode,
2629 pred_match=lambda pred_arg: pred_arg.mode in (
2630 _SVP64PredMode.INT,
2631 _SVP64PredMode.CR,
2632 ))
2633
2634 def assemble(self, insn):
2635 raise NotImplementedError()
2636
2637
2638 @_dataclasses.dataclass(eq=True, frozen=True)
2639 class SpecifierM(SpecifierMask):
2640 @classmethod
2641 def match(cls, desc, record):
2642 return super().match(desc=desc, record=record, mode="m")
2643
2644 def validate(self, others):
2645 for spec in others:
2646 if isinstance(spec, SpecifierSM):
2647 raise ValueError("source-mask and predicate mask conflict")
2648 elif isinstance(spec, SpecifierDM):
2649 raise ValueError("dest-mask and predicate mask conflict")
2650
2651 def assemble(self, insn):
2652 selector = insn.select(record=self.record)
2653 selector.mask = int(self.pred)
2654 if ((self.record.ptype is _SVPType.P2) and
2655 (self.record.svp64.mode is not _SVMode.BRANCH)):
2656 selector.smask = int(self.pred)
2657 # LDST_IDX smask moving to extra322 but not straight away (False)
2658 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2659 selector.smask_extra332 = int(self.pred)
2660 else:
2661 selector.smask = int(self.pred)
2662
2663 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2664
2665
2666 @_dataclasses.dataclass(eq=True, frozen=True)
2667 class SpecifierSM(SpecifierMask):
2668 @classmethod
2669 def match(cls, desc, record):
2670 return super().match(desc=desc, record=record, mode="sm")
2671
2672 def validate(self, others):
2673 if self.record.svp64.ptype is _SVPType.P1:
2674 raise ValueError("source-mask on non-twin predicate")
2675
2676 if self.pred.mode is _SVP64PredMode.CR:
2677 twin = None
2678 for spec in others:
2679 if isinstance(spec, SpecifierDM):
2680 twin = spec
2681
2682 if twin is None:
2683 raise ValueError("missing dest-mask in CR twin predication")
2684 if self.pred.mode != twin.pred.mode:
2685 raise ValueError(f"predicate masks mismatch: "
2686 f"{self.pred!r} vs {twin.pred!r}")
2687
2688 def assemble(self, insn):
2689 selector = insn.select(record=self.record)
2690 # LDST_IDX smask moving to extra322 but not straight away (False)
2691 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2692 selector.smask_extra332 = int(self.pred)
2693 else:
2694 selector.smask = int(self.pred)
2695 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2696
2697
2698 @_dataclasses.dataclass(eq=True, frozen=True)
2699 class SpecifierDM(SpecifierMask):
2700 @classmethod
2701 def match(cls, desc, record):
2702 return super().match(desc=desc, record=record, mode="dm")
2703
2704 def validate(self, others):
2705 if self.record.svp64.ptype is _SVPType.P1:
2706 raise ValueError("dest-mask on non-twin predicate")
2707
2708 if self.pred.mode is _SVP64PredMode.CR:
2709 twin = None
2710 for spec in others:
2711 if isinstance(spec, SpecifierSM):
2712 twin = spec
2713
2714 if twin is None:
2715 raise ValueError("missing source-mask in CR twin predication")
2716 if self.pred.mode != twin.pred.mode:
2717 raise ValueError(f"predicate masks mismatch: "
2718 f"{self.pred!r} vs {twin.pred!r}")
2719
2720 def assemble(self, insn):
2721 selector = insn.select(record=self.record)
2722 selector.mask = int(self.pred)
2723 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2724
2725
2726 @_dataclasses.dataclass(eq=True, frozen=True)
2727 class SpecifierZZ(Specifier):
2728 @classmethod
2729 def match(cls, desc, record):
2730 if desc != "zz":
2731 return None
2732
2733 return cls(record=record)
2734
2735 def validate(self, others):
2736 for spec in others:
2737 # Since zz takes precedence (overrides) sz and dz,
2738 # treat them as mutually exclusive.
2739 if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
2740 raise ValueError("mutually exclusive predicate masks")
2741
2742 def assemble(self, insn):
2743 selector = insn.select(record=self.record)
2744 if hasattr(selector, "zz"): # this should be done in a different way
2745 selector.zz = 1
2746 else:
2747 selector.sz = 1
2748 selector.dz = 1
2749
2750
2751 @_dataclasses.dataclass(eq=True, frozen=True)
2752 class SpecifierXZ(Specifier):
2753 desc: str
2754 hint: str = _dataclasses.field(repr=False)
2755
2756 @classmethod
2757 def match(cls, desc, record, etalon, hint):
2758 if desc != etalon:
2759 return None
2760
2761 return cls(desc=desc, record=record, hint=hint)
2762
2763 def validate(self, others):
2764 if self.record.svp64.ptype is _SVPType.P1:
2765 raise ValueError(f"{self.hint} on non-twin predicate")
2766
2767 if self.pred.mode is _SVP64PredMode.CR:
2768 twin = None
2769 for spec in others:
2770 if isinstance(spec, SpecifierXZ):
2771 twin = spec
2772
2773 if twin is None:
2774 raise ValueError(f"missing {self.hint} in CR twin predication")
2775 if self.pred != twin.pred:
2776 raise ValueError(f"predicate masks mismatch: "
2777 f"{self.pred!r} vs {twin.pred!r}")
2778
2779 def assemble(self, insn):
2780 selector = insn.select(record=self.record)
2781 setattr(selector, self.desc, 1)
2782
2783
2784 @_dataclasses.dataclass(eq=True, frozen=True)
2785 class SpecifierSZ(SpecifierXZ):
2786 @classmethod
2787 def match(cls, desc, record):
2788 return super().match(desc=desc, record=record,
2789 etalon="sz", hint="source-mask")
2790
2791 def validate(self, others):
2792 for spec in others:
2793 if self.record.svp64.mode is not _SVMode.CROP:
2794 if isinstance(spec, SpecifierFF):
2795 raise ValueError("source-zero not allowed in ff mode")
2796
2797
2798 @_dataclasses.dataclass(eq=True, frozen=True)
2799 class SpecifierDZ(SpecifierXZ):
2800 @classmethod
2801 def match(cls, desc, record):
2802 return super().match(desc=desc, record=record,
2803 etalon="dz", hint="dest-mask")
2804
2805 def validate(self, others):
2806 for spec in others:
2807 if ((self.record.svp64.mode is not _SVMode.CROP) and
2808 isinstance(spec, SpecifierFF) and
2809 (spec.pred.mode is _SVP64PredMode.RC1)):
2810 raise ValueError(f"dest-zero not allowed in ff mode BO")
2811
2812
2813 @_dataclasses.dataclass(eq=True, frozen=True)
2814 class SpecifierEls(Specifier):
2815 @classmethod
2816 def match(cls, desc, record):
2817 if desc != "els":
2818 return None
2819
2820 if record.svp64.mode not in (_SVMode.LDST_IMM, _SVMode.LDST_IDX):
2821 raise ValueError("els is only valid in ld/st modes, not "
2822 "%s" % str(self.record.svp64.mode))
2823
2824 return cls(record=record)
2825
2826 def assemble(self, insn):
2827 if self.record.svp64.mode is _SVMode.LDST_IDX: # stride mode
2828 insn.prefix.rm.mode[1] = 0
2829
2830 selector = insn.select(record=self.record)
2831 selector.els = 1
2832
2833
2834
2835 @_dataclasses.dataclass(eq=True, frozen=True)
2836 class SpecifierSEA(Specifier):
2837 @classmethod
2838 def match(cls, desc, record):
2839 if desc != "sea":
2840 return None
2841
2842 return cls(record=record)
2843
2844 def validate(self, others):
2845 if self.record.svp64.mode is not _SVMode.LDST_IDX:
2846 raise ValueError("sea is only valid in ld/st modes, not "
2847 "%s" % str(self.record.svp64.mode))
2848
2849 for spec in others:
2850 if isinstance(spec, SpecifierFF):
2851 raise ValueError(f"sea cannot be used in ff mode")
2852
2853 def assemble(self, insn):
2854 selector = insn.select(record=self.record)
2855 if selector.mode.sel not in (0b10, 0b00):
2856 raise ValueError("sea is only valid for normal and els modes, "
2857 "not %d" % int(selector.mode.sel))
2858 selector.SEA = 1
2859
2860
2861 @_dataclasses.dataclass(eq=True, frozen=True)
2862 class SpecifierSat(Specifier):
2863 desc: str
2864 sign: bool
2865
2866 @classmethod
2867 def match(cls, desc, record, etalon, sign):
2868 if desc != etalon:
2869 return None
2870
2871 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.LDST_IMM,
2872 _SVMode.LDST_IDX):
2873 raise ValueError("only normal, ld/st imm and "
2874 "ld/st idx modes supported")
2875
2876 return cls(record=record, desc=desc, sign=sign)
2877
2878 def assemble(self, insn):
2879 selector = insn.select(record=self.record)
2880 selector.mode[0] = 0b1
2881 selector.mode[1] = 0b0
2882 selector.N = int(self.sign)
2883
2884
2885 @_dataclasses.dataclass(eq=True, frozen=True)
2886 class SpecifierSatS(SpecifierSat):
2887 @classmethod
2888 def match(cls, desc, record):
2889 return super().match(desc=desc, record=record,
2890 etalon="sats", sign=True)
2891
2892
2893 @_dataclasses.dataclass(eq=True, frozen=True)
2894 class SpecifierSatU(SpecifierSat):
2895 @classmethod
2896 def match(cls, desc, record):
2897 return super().match(desc=desc, record=record,
2898 etalon="satu", sign=False)
2899
2900
2901 @_dataclasses.dataclass(eq=True, frozen=True)
2902 class SpecifierMapReduce(Specifier):
2903 RG: bool
2904
2905 @classmethod
2906 def match(cls, record, RG):
2907 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2908 raise ValueError("only normal and crop modes supported")
2909
2910 return cls(record=record, RG=RG)
2911
2912 def assemble(self, insn):
2913 selector = insn.select(record=self.record)
2914 if self.record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2915 raise ValueError("only normal and crop modes supported")
2916 selector.mode[0] = 0
2917 selector.mode[1] = 0
2918 selector.mode[2] = 1
2919 selector.RG = self.RG
2920
2921
2922 @_dataclasses.dataclass(eq=True, frozen=True)
2923 class SpecifierMR(SpecifierMapReduce):
2924 @classmethod
2925 def match(cls, desc, record):
2926 if desc != "mr":
2927 return None
2928
2929 return super().match(record=record, RG=False)
2930
2931
2932 @_dataclasses.dataclass(eq=True, frozen=True)
2933 class SpecifierMRR(SpecifierMapReduce):
2934 @classmethod
2935 def match(cls, desc, record):
2936 if desc != "mrr":
2937 return None
2938
2939 return super().match(record=record, RG=True)
2940
2941
2942 @_dataclasses.dataclass(eq=True, frozen=True)
2943 class SpecifierBranch(Specifier):
2944 @classmethod
2945 def match(cls, desc, record, etalon):
2946 if desc != etalon:
2947 return None
2948
2949 if record.svp64.mode is not _SVMode.BRANCH:
2950 raise ValueError("only branch modes supported")
2951
2952 return cls(record=record)
2953
2954
2955 @_dataclasses.dataclass(eq=True, frozen=True)
2956 class SpecifierAll(SpecifierBranch):
2957 @classmethod
2958 def match(cls, desc, record):
2959 return super().match(desc=desc, record=record, etalon="all")
2960
2961 def assemble(self, insn):
2962 selector = insn.select(record=self.record)
2963 selector.ALL = 1
2964
2965
2966 @_dataclasses.dataclass(eq=True, frozen=True)
2967 class SpecifierSNZ(Specifier):
2968 @classmethod
2969 def match(cls, desc, record):
2970 if desc != "snz":
2971 return None
2972
2973 if record.svp64.mode not in (_SVMode.BRANCH, _SVMode.CROP):
2974 raise ValueError("only branch and crop modes supported")
2975
2976 return cls(record=record)
2977
2978 def assemble(self, insn):
2979 selector = insn.select(record=self.record)
2980 if self.record.svp64.mode in (_SVMode.CROP, _SVMode.BRANCH):
2981 selector.SNZ = 1
2982 if self.record.svp64.mode is _SVMode.BRANCH:
2983 selector.sz = 1
2984 else:
2985 raise ValueError("only branch and crop modes supported")
2986
2987
2988 @_dataclasses.dataclass(eq=True, frozen=True)
2989 class SpecifierSL(SpecifierBranch):
2990 @classmethod
2991 def match(cls, desc, record):
2992 return super().match(desc=desc, record=record, etalon="sl")
2993
2994 def assemble(self, insn):
2995 selector = insn.select(record=self.record)
2996 selector.SL = 1
2997
2998
2999 @_dataclasses.dataclass(eq=True, frozen=True)
3000 class SpecifierSLu(SpecifierBranch):
3001 @classmethod
3002 def match(cls, desc, record):
3003 return super().match(desc=desc, record=record, etalon="slu")
3004
3005 def assemble(self, insn):
3006 selector = insn.select(record=self.record)
3007 selector.SLu = 1
3008
3009
3010 @_dataclasses.dataclass(eq=True, frozen=True)
3011 class SpecifierLRu(SpecifierBranch):
3012 @classmethod
3013 def match(cls, desc, record):
3014 return super().match(desc=desc, record=record, etalon="lru")
3015
3016 def assemble(self, insn):
3017 selector = insn.select(record=self.record)
3018 selector.LRu = 1
3019
3020
3021 @_dataclasses.dataclass(eq=True, frozen=True)
3022 class SpecifierVSXX(SpecifierBranch):
3023 VSb: bool
3024 VLi: bool
3025
3026 @classmethod
3027 def match(cls, desc, record, etalon, VSb, VLi):
3028 if desc != etalon:
3029 return None
3030
3031 if record.svp64.mode is not _SVMode.BRANCH:
3032 raise ValueError("only branch modes supported")
3033
3034 return cls(record=record, VSb=VSb, VLi=VLi)
3035
3036 def assemble(self, insn):
3037 selector = insn.select(record=self.record)
3038 selector.VLS = 1
3039 selector.VSb = int(self.VSb)
3040 selector.VLi = int(self.VLi)
3041
3042
3043 @_dataclasses.dataclass(eq=True, frozen=True)
3044 class SpecifierVS(SpecifierVSXX):
3045 @classmethod
3046 def match(cls, desc, record):
3047 return super().match(desc=desc, record=record,
3048 etalon="vs", VSb=False, VLi=False)
3049
3050
3051 @_dataclasses.dataclass(eq=True, frozen=True)
3052 class SpecifierVSi(SpecifierVSXX):
3053 @classmethod
3054 def match(cls, desc, record):
3055 return super().match(desc=desc, record=record,
3056 etalon="vsi", VSb=False, VLi=True)
3057
3058
3059 @_dataclasses.dataclass(eq=True, frozen=True)
3060 class SpecifierVSb(SpecifierVSXX):
3061 @classmethod
3062 def match(cls, desc, record):
3063 return super().match(desc=desc, record=record,
3064 etalon="vsb", VSb=True, VLi=False)
3065
3066
3067 @_dataclasses.dataclass(eq=True, frozen=True)
3068 class SpecifierVSbi(SpecifierVSXX):
3069 @classmethod
3070 def match(cls, desc, record):
3071 return super().match(desc=desc, record=record,
3072 etalon="vsbi", VSb=True, VLi=True)
3073
3074
3075 @_dataclasses.dataclass(eq=True, frozen=True)
3076 class SpecifierCTX(Specifier):
3077 CTi: bool
3078
3079 @classmethod
3080 def match(cls, desc, record, etalon, CTi):
3081 if desc != etalon:
3082 return None
3083
3084 if record.svp64.mode is not _SVMode.BRANCH:
3085 raise ValueError("only branch modes supported")
3086
3087 return cls(record=record, CTi=CTi)
3088
3089 def assemble(self, insn):
3090 selector = insn.select(record=self.record)
3091 selector.CTR = 1
3092 selector.CTi = int(self.CTi)
3093
3094
3095 @_dataclasses.dataclass(eq=True, frozen=True)
3096 class SpecifierCTR(SpecifierCTX):
3097 @classmethod
3098 def match(cls, desc, record):
3099 return super().match(desc=desc, record=record,
3100 etalon="ctr", CTi=False)
3101
3102
3103 @_dataclasses.dataclass(eq=True, frozen=True)
3104 class SpecifierCTi(SpecifierCTX):
3105 @classmethod
3106 def match(cls, desc, record):
3107 return super().match(desc=desc, record=record,
3108 etalon="cti", CTi=True)
3109
3110
3111 @_dataclasses.dataclass(eq=True, frozen=True)
3112 class SpecifierPI(Specifier):
3113 @classmethod
3114 def match(cls, desc, record):
3115 if desc != "pi":
3116 return None
3117
3118 if record.svp64.mode not in [_SVMode.LDST_IMM, _SVMode.LDST_IDX]:
3119 raise ValueError("only ld/st imm/idx mode supported")
3120
3121 return cls(record=record)
3122
3123 def assemble(self, insn):
3124 selector = insn.select(record=self.record)
3125 selector.mode[2] = 0b1
3126 selector.pi = 0b1
3127
3128
3129 @_dataclasses.dataclass(eq=True, frozen=True)
3130 class SpecifierLF(Specifier):
3131 @classmethod
3132 def match(cls, desc, record):
3133 if desc != "lf":
3134 return None
3135
3136 if record.svp64.mode is not _SVMode.LDST_IMM:
3137 raise ValueError("only ld/st imm mode supported")
3138
3139 return cls(record=record)
3140
3141 def assemble(self, insn):
3142 selector = insn.select(record=self.record)
3143 selector.mode[1] = 0
3144 selector.lf = 0b1
3145
3146
3147 @_dataclasses.dataclass(eq=True, frozen=True)
3148 class SpecifierVLi(Specifier):
3149 @classmethod
3150 def match(cls, desc, record):
3151 if desc != "vli":
3152 return None
3153
3154 return cls(record=record)
3155
3156 def validate(self, others):
3157 for spec in others:
3158 if isinstance(spec, SpecifierFF):
3159 return
3160
3161 raise ValueError("VLi only allowed in failfirst")
3162
3163 def assemble(self, insn):
3164 selector = insn.select(record=self.record)
3165 selector.mode[1] = 1
3166 selector.VLi = 1
3167
3168
3169 class Specifiers(tuple):
3170 SPECS = (
3171 SpecifierW,
3172 SpecifierSW,
3173 SpecifierDW,
3174 SpecifierSubVL,
3175 SpecifierFF,
3176 SpecifierM,
3177 SpecifierSM,
3178 SpecifierDM,
3179 SpecifierZZ,
3180 SpecifierSZ,
3181 SpecifierDZ,
3182 SpecifierEls,
3183 SpecifierSEA,
3184 SpecifierSatS,
3185 SpecifierSatU,
3186 SpecifierMR,
3187 SpecifierMRR,
3188 SpecifierAll,
3189 SpecifierSNZ,
3190 SpecifierSL,
3191 SpecifierSLu,
3192 SpecifierLRu,
3193 SpecifierVS,
3194 SpecifierVSi,
3195 SpecifierVSb,
3196 SpecifierVSbi,
3197 SpecifierVLi,
3198 SpecifierCTR,
3199 SpecifierCTi,
3200 SpecifierPI,
3201 SpecifierLF,
3202 )
3203
3204 def __new__(cls, items, record):
3205 def transform(item):
3206 for spec_cls in cls.SPECS:
3207 spec = spec_cls.match(item, record=record)
3208 if spec is not None:
3209 return spec
3210 raise ValueError(item)
3211
3212 # TODO: remove this hack
3213 items = dict.fromkeys(items)
3214 if "vli" in items:
3215 del items["vli"]
3216 items["vli"] = None
3217 items = tuple(items)
3218
3219 specs = tuple(map(transform, items))
3220 for (index, spec) in enumerate(specs):
3221 head = specs[:index]
3222 tail = specs[index + 1:]
3223 spec.validate(others=(head + tail))
3224
3225 return super().__new__(cls, specs)
3226
3227
3228 class SVP64OperandMeta(type):
3229 class SVP64NonZeroOperand(NonZeroOperand):
3230 def assemble(self, insn, value):
3231 if isinstance(value, str):
3232 value = int(value, 0)
3233 if not isinstance(value, int):
3234 raise ValueError("non-integer operand")
3235
3236 # FIXME: this is really weird
3237 if self.record.name in ("svstep", "svstep."):
3238 value += 1 # compensation
3239
3240 return super().assemble(value=value, insn=insn)
3241
3242 class SVP64XOStaticOperand(SpanStaticOperand):
3243 def __init__(self, record, value, span):
3244 return super().__init__(record=record, name="XO",
3245 value=value, span=span)
3246
3247 __TRANSFORM = {
3248 NonZeroOperand: SVP64NonZeroOperand,
3249 XOStaticOperand: SVP64XOStaticOperand,
3250 }
3251
3252 def __new__(metacls, name, bases, ns):
3253 bases = list(bases)
3254 for (index, base_cls) in enumerate(bases):
3255 bases[index] = metacls.__TRANSFORM.get(base_cls, base_cls)
3256
3257 bases = tuple(bases)
3258
3259 return super().__new__(metacls, name, bases, ns)
3260
3261
3262 class SVP64Operand(Operand, metaclass=SVP64OperandMeta):
3263 @property
3264 def span(self):
3265 return tuple(map(lambda bit: (bit + 32), super().span))
3266
3267
3268 class RMSelector:
3269 def __init__(self, insn, record):
3270 self.__insn = insn
3271 self.__record = record
3272 return super().__init__()
3273
3274 def __str__(self):
3275 return self.rm.__doc__
3276
3277 def __repr__(self):
3278 return repr(self.rm)
3279
3280 @property
3281 def insn(self):
3282 return self.__insn
3283
3284 @property
3285 def record(self):
3286 return self.__record
3287
3288 @property
3289 def rm(self):
3290 rm = getattr(self.insn.prefix.rm, self.record.svp64.mode.name.lower())
3291
3292 # The idea behind these tables is that they are now literally
3293 # in identical format to insndb.csv and minor_xx.csv and can
3294 # be done precisely as that. The only thing to watch out for
3295 # is the insertion of Rc=1 as a "mask/value" bit and likewise
3296 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
3297 # as the LSB.
3298 table = None
3299 if self.record.svp64.mode is _SVMode.NORMAL:
3300 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3301 # mode Rc mask Rc member
3302 table = (
3303 (0b000000, 0b111000, "simple"), # simple (no Rc)
3304 (0b001000, 0b111100, "mr"), # mapreduce (no Rc)
3305 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3306 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3307 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3308 (0b001100, 0b111100, "rsvd"), # reserved
3309 )
3310 mode = int(self.insn.prefix.rm.normal.mode)
3311 search = ((mode << 1) | self.record.Rc)
3312
3313 elif self.record.svp64.mode is _SVMode.LDST_IMM:
3314 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3315 # mode Rc mask Rc member
3316 # ironically/coincidentally this table is identical to NORMAL
3317 # mode except reserved in place of mr
3318 table = (
3319 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3320 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3321 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3322 )
3323 search = ((int(self.insn.prefix.rm.ldst_imm.mode) << 1) |
3324 self.record.Rc)
3325
3326 elif self.record.svp64.mode is _SVMode.LDST_IDX:
3327 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3328 # mode Rc mask Rc member
3329 table = (
3330 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3331 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3332 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3333 )
3334 search = ((int(self.insn.prefix.rm.ldst_idx.mode) << 1) |
3335 self.record.Rc)
3336
3337 elif self.record.svp64.mode is _SVMode.CROP:
3338 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
3339 # mode 3b mask 3b member
3340 table = (
3341 (0b000000, 0b111000, "simple"), # simple
3342 (0b001000, 0b111000, "mr"), # mapreduce
3343 (0b010001, 0b010001, "ff3"), # ffirst, 3-bit CR
3344 (0b010000, 0b010000, "ff5"), # ffirst, 5-bit CR
3345 )
3346 search = ((int(self.insn.prefix.rm.crop.mode) << 1) |
3347 int(self.record.svp64.extra_CR_3bit))
3348
3349 elif self.record.svp64.mode is _SVMode.BRANCH:
3350 # just mode 2-bit
3351 # mode mask member
3352 table = (
3353 (0b00, 0b11, "simple"), # simple
3354 (0b01, 0b11, "vls"), # VLset
3355 (0b10, 0b11, "ctr"), # CTR mode
3356 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
3357 )
3358 # slightly weird: doesn't have a 5-bit "mode" field like others
3359 search = int(self.insn.prefix.rm.branch.mode.sel)
3360
3361 # look up in table
3362 if table is not None:
3363 for (value, mask, field) in table:
3364 if field.startswith("rsvd"):
3365 continue
3366 if ((value & mask) == (search & mask)):
3367 return getattr(rm, field)
3368
3369 return rm
3370
3371 def __getattr__(self, key):
3372 if key.startswith(f"_{self.__class__.__name__}__"):
3373 return super().__getattribute__(key)
3374
3375 return getattr(self.rm, key)
3376
3377 def __setattr__(self, key, value):
3378 if key.startswith(f"_{self.__class__.__name__}__"):
3379 return super().__setattr__(key, value)
3380
3381 rm = self.rm
3382 if not hasattr(rm, key):
3383 raise AttributeError(key)
3384
3385 return setattr(rm, key, value)
3386
3387
3388 class SVP64Instruction(PrefixedInstruction):
3389 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3390 class Prefix(PrefixedInstruction.Prefix):
3391 id: _Field = (7, 9)
3392 rm: RM.remap((6, 8) + tuple(range(10, 32)))
3393
3394 prefix: Prefix
3395
3396 def select(self, record):
3397 return RMSelector(insn=self, record=record)
3398
3399 @property
3400 def binary(self):
3401 bits = []
3402 for idx in range(64):
3403 bit = int(self[idx])
3404 bits.append(bit)
3405 return "".join(map(str, bits))
3406
3407 @classmethod
3408 def assemble(cls, record, arguments=None, specifiers=None):
3409 insn = super().assemble(record=record, arguments=arguments)
3410
3411 specifiers = Specifiers(items=specifiers, record=record)
3412 for specifier in specifiers:
3413 specifier.assemble(insn=insn)
3414
3415 insn.prefix.PO = 0x1
3416 insn.prefix.id = 0x3
3417
3418 return insn
3419
3420 def disassemble(self, record,
3421 byteorder="little",
3422 style=Style.NORMAL):
3423 def blob(insn):
3424 if style <= Style.SHORT:
3425 return ""
3426 else:
3427 blob = insn.bytes(byteorder=byteorder)
3428 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
3429 return f"{blob} "
3430
3431 blob_prefix = blob(self.prefix)
3432 blob_suffix = blob(self.suffix)
3433 if record is None:
3434 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3435 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
3436 return
3437
3438 assert record.svp64 is not None
3439
3440 name = f"sv.{record.name}"
3441
3442 rm = self.select(record=record)
3443
3444 # convert specifiers to /x/y/z (sorted lexicographically)
3445 specifiers = sorted(rm.specifiers(record=record))
3446 if specifiers: # if any add one extra to get the extra "/"
3447 specifiers = ([""] + specifiers)
3448 specifiers = "/".join(specifiers)
3449
3450 # convert operands to " ,x,y,z"
3451 operands = tuple(map(_operator.itemgetter(1),
3452 self.spec_dynamic_operands(record=record, style=style)))
3453 operands = ",".join(operands)
3454 if len(operands) > 0: # if any separate with a space
3455 operands = (" " + operands)
3456
3457 if style <= Style.LEGACY:
3458 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3459 suffix = WordInstruction.integer(value=int(self.suffix))
3460 yield from suffix.disassemble(record=record,
3461 byteorder=byteorder, style=style)
3462 else:
3463 yield f"{blob_prefix}{name}{specifiers}{operands}"
3464 if blob_suffix:
3465 yield f"{blob_suffix}"
3466
3467 if style >= Style.VERBOSE:
3468 indent = (" " * 4)
3469 binary = self.binary
3470 spec = self.spec(record=record, prefix="sv.")
3471
3472 yield f"{indent}spec"
3473 yield f"{indent}{indent}{spec}"
3474 yield f"{indent}pcode"
3475 for stmt in record.mdwn.pcode:
3476 yield f"{indent}{indent}{stmt}"
3477 yield f"{indent}binary"
3478 yield f"{indent}{indent}[0:8] {binary[0:8]}"
3479 yield f"{indent}{indent}[8:16] {binary[8:16]}"
3480 yield f"{indent}{indent}[16:24] {binary[16:24]}"
3481 yield f"{indent}{indent}[24:32] {binary[24:32]}"
3482 yield f"{indent}{indent}[32:40] {binary[32:40]}"
3483 yield f"{indent}{indent}[40:48] {binary[40:48]}"
3484 yield f"{indent}{indent}[48:56] {binary[48:56]}"
3485 yield f"{indent}{indent}[56:64] {binary[56:64]}"
3486 yield f"{indent}opcodes"
3487 for opcode in record.opcodes:
3488 yield f"{indent}{indent}{opcode!r}"
3489 for operand in self.operands(record=record):
3490 yield from operand.disassemble(insn=self,
3491 style=style, indent=indent)
3492 yield f"{indent}RM"
3493 yield f"{indent}{indent}{str(rm)}"
3494 for line in rm.disassemble(style=style):
3495 yield f"{indent}{indent}{line}"
3496 yield ""
3497
3498 @classmethod
3499 def operands(cls, record):
3500 for operand in super().operands(record=record):
3501 parent = operand.__class__
3502 name = f"SVP64{parent.__name__}"
3503 bases = (SVP64Operand, parent)
3504 child = type(name, bases, {})
3505 yield child(**dict(operand))
3506
3507
3508 def parse(stream, factory):
3509 def match(entry):
3510 return ("TODO" not in frozenset(entry.values()))
3511
3512 lines = filter(lambda line: not line.strip().startswith("#"), stream)
3513 entries = _csv.DictReader(lines)
3514 entries = filter(match, entries)
3515 return tuple(map(factory, entries))
3516
3517
3518 class MarkdownDatabase:
3519 def __init__(self):
3520 db = {}
3521 for (name, desc) in _ISA():
3522 operands = []
3523 if desc.regs:
3524 (dynamic, *static) = desc.regs
3525 operands.extend(dynamic)
3526 operands.extend(static)
3527 pcode = PCode(filter(str.strip, desc.pcode))
3528 operands = Operands(insn=name, operands=operands)
3529 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
3530
3531 self.__db = dict(sorted(db.items()))
3532
3533 return super().__init__()
3534
3535 def __iter__(self):
3536 yield from self.__db.items()
3537
3538 def __contains__(self, key):
3539 return self.__db.__contains__(key)
3540
3541 def __getitem__(self, key):
3542 return self.__db.__getitem__(key)
3543
3544
3545 class FieldsDatabase:
3546 def __init__(self):
3547 db = {}
3548 df = _DecodeFields()
3549 df.create_specs()
3550 for (form, fields) in df.instrs.items():
3551 if form in {"DQE", "TX"}:
3552 continue
3553 if form == "all":
3554 form = "NONE"
3555 db[_Form[form]] = Fields(fields)
3556
3557 self.__db = db
3558
3559 return super().__init__()
3560
3561 def __getitem__(self, key):
3562 return self.__db.__getitem__(key)
3563
3564
3565 class PPCDatabase:
3566 def __init__(self, root, mdwndb):
3567 # The code below groups the instructions by name:section.
3568 # There can be multiple names for the same instruction.
3569 # The point is to capture different opcodes for the same instruction.
3570 sections = {}
3571 records = _collections.defaultdict(set)
3572 path = (root / "insndb.csv")
3573 with open(path, "r", encoding="UTF-8") as stream:
3574 for section in sorted(parse(stream, Section.CSV)):
3575 path = (root / section.csv)
3576 opcode_cls = {
3577 section.Mode.INTEGER: IntegerOpcode,
3578 section.Mode.PATTERN: PatternOpcode,
3579 }[section.mode]
3580 factory = _functools.partial(PPCRecord.CSV,
3581 opcode_cls=opcode_cls)
3582 with open(path, "r", encoding="UTF-8") as stream:
3583 for insn in parse(stream, factory):
3584 for name in insn.names:
3585 records[name].add(insn)
3586 sections[name] = section
3587
3588 items = sorted(records.items())
3589 records = {}
3590 for (name, multirecord) in items:
3591 records[name] = PPCMultiRecord(sorted(multirecord))
3592
3593 def exact_match(name):
3594 record = records.get(name)
3595 if record is None:
3596 return None
3597 return name
3598
3599 def LK_match(name):
3600 if not name.endswith("l"):
3601 return None
3602 alias = exact_match(name[:-1])
3603 if alias is None:
3604 return None
3605 record = records[alias]
3606 if "lk" not in record.flags:
3607 raise ValueError(record)
3608 return alias
3609
3610 def AA_match(name):
3611 if not name.endswith("a"):
3612 return None
3613 alias = LK_match(name[:-1])
3614 if alias is None:
3615 alias = name[:-1]
3616 record = records[alias]
3617 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
3618 raise ValueError(record)
3619 if "AA" not in mdwndb[name].operands:
3620 raise ValueError(record)
3621 return alias
3622
3623 def Rc_match(name):
3624 if not name.endswith("."):
3625 return None
3626 alias = exact_match(name[:-1])
3627 if alias is None:
3628 return None
3629 record = records[alias]
3630 if record.Rc is _RCOE.NONE:
3631 raise ValueError(record)
3632 return alias
3633
3634 db = {}
3635 matches = (exact_match, LK_match, AA_match, Rc_match)
3636 for (name, _) in mdwndb:
3637 if name.startswith("sv."):
3638 continue
3639 alias = None
3640 for match in matches:
3641 alias = match(name)
3642 if alias is not None:
3643 break
3644 if alias is None:
3645 continue
3646 section = sections[alias]
3647 record = records[alias]
3648 db[name] = (section, record)
3649
3650 self.__db = dict(sorted(db.items()))
3651
3652 return super().__init__()
3653
3654 @_functools.lru_cache(maxsize=512, typed=False)
3655 def __getitem__(self, key):
3656 return self.__db.get(key, (None, None))
3657
3658
3659 class SVP64Database:
3660 def __init__(self, root, ppcdb):
3661 db = set()
3662 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3663 for (prefix, _, names) in _os.walk(root):
3664 prefix = _pathlib.Path(prefix)
3665 for name in filter(lambda name: pattern.match(name), names):
3666 path = (prefix / _pathlib.Path(name))
3667 with open(path, "r", encoding="UTF-8") as stream:
3668 db.update(parse(stream, SVP64Record.CSV))
3669 db = {record.name:record for record in db}
3670
3671 self.__db = dict(sorted(db.items()))
3672 self.__ppcdb = ppcdb
3673
3674 return super().__init__()
3675
3676 def __getitem__(self, key):
3677 (_, record) = self.__ppcdb[key]
3678 if record is None:
3679 return None
3680
3681 for name in record.names:
3682 record = self.__db.get(name, None)
3683 if record is not None:
3684 return record
3685
3686 return None
3687
3688
3689 class Records(tuple):
3690 def __new__(cls, records):
3691 return super().__new__(cls, sorted(records))
3692
3693
3694 class Database:
3695 def __init__(self, root):
3696 root = _pathlib.Path(root)
3697 mdwndb = MarkdownDatabase()
3698 fieldsdb = FieldsDatabase()
3699 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
3700 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
3701
3702 db = set()
3703 names = {}
3704 opcodes = _collections.defaultdict(
3705 lambda: _collections.defaultdict(set))
3706
3707 for (name, mdwn) in mdwndb:
3708 if name.startswith("sv."):
3709 continue
3710 (section, ppc) = ppcdb[name]
3711 if ppc is None:
3712 continue
3713 svp64 = svp64db[name]
3714 fields = fieldsdb[ppc.form]
3715 record = Record(name=name,
3716 section=section, ppc=ppc, svp64=svp64,
3717 mdwn=mdwn, fields=fields)
3718 db.add(record)
3719 names[record.name] = record
3720 opcodes[section][record.PO].add(record)
3721
3722 self.__db = Records(db)
3723 self.__names = dict(sorted(names.items()))
3724 self.__opcodes = dict(sorted(opcodes.items()))
3725
3726 return super().__init__()
3727
3728 def __repr__(self):
3729 return repr(self.__db)
3730
3731 def __iter__(self):
3732 yield from self.__db
3733
3734 @_functools.lru_cache(maxsize=None)
3735 def __contains__(self, key):
3736 return self.__getitem__(key) is not None
3737
3738 @_functools.lru_cache(maxsize=None)
3739 def __getitem__(self, key):
3740 if isinstance(key, SVP64Instruction):
3741 key = key.suffix
3742
3743 if isinstance(key, Instruction):
3744 PO = int(key.PO)
3745 key = int(key)
3746 sections = sorted(self.__opcodes)
3747 for section in sections:
3748 group = self.__opcodes[section]
3749 for record in group[PO]:
3750 if record.match(key=key):
3751 return record
3752
3753 return None
3754
3755 elif isinstance(key, str):
3756 return self.__names.get(key)
3757
3758 raise ValueError("instruction or name expected")
3759
3760
3761 class Walker(mdis.walker.Walker):
3762 @mdis.dispatcher.Hook(Database)
3763 def dispatch_database(self, node):
3764 yield from self(tuple(node))