add BA_BFB decode to PPCRecord and SVP64Record
[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
291 if record["CR in"] == "BA_BFB":
292 record["cr_in"] = "BA"
293 record["cr_in2"] = "BFB"
294 del record["CR in"]
295
296 flags = set()
297 for flag in frozenset(PPCRecord.Flags):
298 if bool(record.pop(flag, "")):
299 flags.add(flag)
300 record["flags"] = PPCRecord.Flags(flags)
301
302 return dataclass(cls, record,
303 keymap=PPCRecord.__KEYMAP,
304 typemap=typemap)
305
306 @cached_property
307 def names(self):
308 return frozenset(self.comment.split("=")[-1].split("/"))
309
310
311 class PPCMultiRecord(tuple):
312 def __getattr__(self, attr):
313 if attr == "opcode":
314 if len(self) != 1:
315 raise AttributeError(attr)
316 return getattr(self[0], attr)
317
318
319 class SVP64Record(Dataclass):
320 class ExtraMap(tuple):
321 class Extra(tuple):
322 @_dataclasses.dataclass(eq=True, frozen=True)
323 class Entry:
324 seltype: _SelType = _SelType.NONE
325 reg: _Reg = _Reg.NONE
326
327 def __repr__(self):
328 return f"{self.seltype.value}:{self.reg.name}"
329
330 def __new__(cls, value="0"):
331 if isinstance(value, str):
332 def transform(value):
333 (seltype, reg) = value.split(":")
334 seltype = _SelType(seltype)
335 reg = _Reg(reg)
336 return cls.Entry(seltype=seltype, reg=reg)
337
338 if value == "0":
339 value = tuple()
340 else:
341 value = map(transform, value.split(";"))
342
343 return super().__new__(cls, value)
344
345 def __repr__(self):
346 return repr(list(self))
347
348 def __new__(cls, value=tuple()):
349 value = tuple(value)
350 if len(value) == 0:
351 value = (("0",) * 4)
352 return super().__new__(cls, map(cls.Extra, value))
353
354 def __repr__(self):
355 return repr({index:self[index] for index in range(0, 4)})
356
357 name: str
358 ptype: _SVPType = _SVPType.NONE
359 etype: _SVEType = _SVEType.NONE
360 msrc: _SVMaskSrc = _SVMaskSrc.NO # MASK_SRC is active
361 in1: _In1Sel = _In1Sel.NONE
362 in2: _In2Sel = _In2Sel.NONE
363 in3: _In3Sel = _In3Sel.NONE
364 out: _OutSel = _OutSel.NONE
365 out2: _OutSel = _OutSel.NONE
366 cr_in: _CRInSel = _CRInSel.NONE
367 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
368 cr_out: _CROutSel = _CROutSel.NONE
369 extra: ExtraMap = ExtraMap()
370 conditions: str = ""
371 mode: _SVMode = _SVMode.NORMAL
372
373 __KEYMAP = {
374 "insn": "name",
375 "CONDITIONS": "conditions",
376 "Ptype": "ptype",
377 "Etype": "etype",
378 "SM": "msrc",
379 "CR in": "cr_in",
380 "CR out": "cr_out",
381 }
382
383 @classmethod
384 def CSV(cls, record):
385 record["insn"] = record["insn"].split("=")[-1]
386
387 for key in frozenset({
388 "in1", "in2", "in3", "CR in",
389 "out", "out2", "CR out",
390 }):
391 value = record[key]
392 if value == "0":
393 record[key] = "NONE"
394
395 if record["CR in"] == "BA_BB":
396 record["cr_in"] = "BA"
397 record["cr_in2"] = "BB"
398 del record["CR in"]
399 elif record["CR in"] == "BFA_BFB_BF":
400 record["cr_in"] = "BFA"
401 record["cr_in2"] = "BFB"
402 #record["cr_out"] = "BF" # only use BFA_BFB_BF when BF is a dest
403 del record["CR in"]
404 if record["CR in"] == "BA_BFB": # maaamma miiiia... enough!
405 record["cr_in"] = "BA"
406 record["cr_in2"] = "BFB"
407 del record["CR in"]
408
409 extra = []
410 for idx in range(0, 4):
411 extra.append(record.pop(f"{idx}"))
412
413 record["extra"] = cls.ExtraMap(extra)
414
415 return dataclass(cls, record, keymap=cls.__KEYMAP)
416
417 @cached_property
418 def extras(self):
419 keys = (
420 "in1", "in2", "in3", "cr_in", "cr_in2",
421 "out", "out2", "cr_out",
422 )
423
424 idxmap = (
425 _SVExtra.Idx0,
426 _SVExtra.Idx1,
427 _SVExtra.Idx2,
428 _SVExtra.Idx3,
429 )
430
431 def extra(reg):
432 extras = {
433 _SelType.DST: {},
434 _SelType.SRC: {},
435 }
436 for index in range(0, 4):
437 for entry in self.extra[index]:
438 extras[entry.seltype][entry.reg] = idxmap[index]
439
440 for (seltype, regs) in extras.items():
441 idx = regs.get(reg, _SVExtra.NONE)
442 if idx is not _SVExtra.NONE:
443 yield (reg, seltype, idx)
444
445 sels = {}
446 idxs = {}
447 regs = {}
448 seltypes = {}
449 for key in keys:
450 # has the word "in", it is a SelType.SRC "out" -> DST
451 # in1/2/3 and CR in are SRC, and must match only against "s:NN"
452 # out/out1 and CR out are DST, and must match only against "d:NN"
453 keytype = _SelType.SRC if ("in" in key) else _SelType.DST
454 sel = sels[key] = getattr(self, key)
455 reg = regs[key] = _Reg(sel)
456 seltypes[key] = _SelType.NONE
457 idxs[key] = _SVExtra.NONE
458 for (reg, seltype, idx) in extra(reg.alias):
459 if keytype != seltype: # only check SRC-to-SRC and DST-to-DST
460 continue
461 if idx != idxs[key] and idxs[key] is not _SVExtra.NONE:
462 raise ValueError(idx)
463 idxs[key] = idx
464 regs[key] = reg
465 seltypes[key] = seltype
466
467 if sels["cr_in"] is _CRInSel.BA_BB:
468 sels["cr_in"] = _CRIn2Sel.BA
469 sels["cr_in2"] = _CRIn2Sel.BB
470 idxs["cr_in2"] = idxs["cr_in"]
471 for key in ("cr_in", "cr_in2"):
472 regs[key] = _Reg(sels[key])
473 seltype[key] = _SelType.SRC
474
475 if sels["cr_in"] is _CRInSel.BA_BFB:
476 sels["cr_in"] = _CRIn2Sel.BA
477 sels["cr_in2"] = _CRIn2Sel.BFB
478 idxs["cr_in2"] = idxs["cr_in"]
479 for key in ("cr_in", "cr_in2"):
480 regs[key] = _Reg(sels[key])
481 seltype[key] = _SelType.SRC
482
483 # should only be used when BF is also a destination
484 if sels["cr_in"] is _CRInSel.BFA_BFB_BF:
485 sels["cr_in"] = _CRIn2Sel.BFA
486 sels["cr_in2"] = _CRIn2Sel.BFB
487 idxs["cr_in2"] = idxs["cr_in"]
488 for key in ("cr_in", "cr_in2"):
489 regs[key] = _Reg(sels[key])
490 seltype[key] = _SelType.SRC
491
492 records = {}
493 for key in keys:
494 records[key] = {
495 "sel": sels[key],
496 "reg": regs[key],
497 "seltype": seltypes[key],
498 "idx": idxs[key],
499 }
500
501 return _types.MappingProxyType(records)
502
503 extra_idx_in1 = property(lambda self: self.extras["in1"]["idx"])
504 extra_idx_in2 = property(lambda self: self.extras["in2"]["idx"])
505 extra_idx_in3 = property(lambda self: self.extras["in3"]["idx"])
506 extra_idx_out = property(lambda self: self.extras["out"]["idx"])
507 extra_idx_out2 = property(lambda self: self.extras["out2"]["idx"])
508 extra_idx_cr_in = property(lambda self: self.extras["cr_in"]["idx"])
509 extra_idx_cr_in2 = property(lambda self: self.extras["cr_in2"]["idx"])
510 extra_idx_cr_out = property(lambda self: self.extras["cr_out"]["idx"])
511
512 @cached_property
513 def extra_CR(self):
514 extra = None
515 for idx in range(0, 4):
516 for entry in self.extra[idx]:
517 if entry.seltype is _SelType.DST:
518 if extra is not None:
519 raise ValueError(self.svp64)
520 extra = entry
521 break
522
523 if _RegType(extra.reg) not in (_RegType.CR_3BIT, _RegType.CR_5BIT):
524 raise ValueError(self.svp64)
525
526 return extra
527
528 @cached_property
529 def extra_CR_3bit(self):
530 return (_RegType(self.extra_CR.reg) is _RegType.CR_3BIT)
531
532
533 class Section(Dataclass):
534 class Path(type(_pathlib.Path("."))):
535 pass
536
537 class BitSel:
538 def __init__(self, value=(0, 32)):
539 if isinstance(value, str):
540 (start, end) = map(int, value.split(":"))
541 else:
542 (start, end) = value
543 if start < 0 or end < 0 or start >= end:
544 raise ValueError(value)
545
546 self.__start = start
547 self.__end = end
548
549 return super().__init__()
550
551 def __len__(self):
552 return (self.__end - self.__start + 1)
553
554 def __repr__(self):
555 return f"[{self.__start}:{self.__end}]"
556
557 def __iter__(self):
558 yield from range(self.start, (self.end + 1))
559
560 def __reversed__(self):
561 return tuple(reversed(tuple(self)))
562
563 @property
564 def start(self):
565 return self.__start
566
567 @property
568 def end(self):
569 return self.__end
570
571 class Mode(_enum.Enum):
572 INTEGER = _enum.auto()
573 PATTERN = _enum.auto()
574
575 @classmethod
576 def _missing_(cls, value):
577 if isinstance(value, str):
578 return cls[value.upper()]
579 return super()._missing_(value)
580
581 class Suffix(int):
582 def __new__(cls, value=None):
583 if isinstance(value, str):
584 if value.upper() == "NONE":
585 value = None
586 else:
587 value = int(value, 0)
588 if value is None:
589 value = 0
590
591 return super().__new__(cls, value)
592
593 def __str__(self):
594 return repr(self)
595
596 def __repr__(self):
597 return (bin(self) if self else "None")
598
599 class Opcode(IntegerOpcode):
600 pass
601
602 @_functools.total_ordering
603 class Priority(_enum.Enum):
604 LOW = -1
605 NORMAL = 0
606 HIGH = +1
607
608 @classmethod
609 def _missing_(cls, value):
610 if isinstance(value, str):
611 value = value.upper()
612 try:
613 return cls[value]
614 except ValueError:
615 return super()._missing_(value)
616
617 def __lt__(self, other):
618 if not isinstance(other, self.__class__):
619 return NotImplemented
620
621 # NOTE: the order is inversed, LOW < NORMAL < HIGH
622 return (self.value > other.value)
623
624 csv: Path
625 bitsel: BitSel
626 suffix: Suffix
627 mode: Mode
628 opcode: Opcode = None
629 priority: Priority = Priority.NORMAL
630
631 def __lt__(self, other):
632 if not isinstance(other, self.__class__):
633 return NotImplemented
634 return (self.priority < other.priority)
635
636 @classmethod
637 def CSV(cls, record):
638 keymap = {"path": "csv"}
639 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
640 if record["opcode"] == "NONE":
641 typemap["opcode"] = lambda _: None
642
643 return dataclass(cls, record, typemap=typemap, keymap=keymap)
644
645
646 class Fields(dict):
647 def __init__(self, items):
648 if isinstance(items, dict):
649 items = items.items()
650
651 def transform(item):
652 (name, bitrange) = item
653 return (name, tuple(bitrange.values()))
654
655 mapping = dict(map(transform, items))
656
657 return super().__init__(mapping)
658
659 def __hash__(self):
660 return hash(tuple(sorted(self.items())))
661
662 def __iter__(self):
663 yield from self.__mapping.items()
664
665
666 class Operands(dict):
667 __GPR_PAIRS = (
668 _Reg.RTp,
669 _Reg.RSp,
670 )
671 __FPR_PAIRS = (
672 _Reg.FRAp,
673 _Reg.FRBp,
674 _Reg.FRSp,
675 _Reg.FRTp,
676 )
677
678 def __init__(self, insn, operands):
679 custom_insns = {
680 "b": {"target_addr": TargetAddrOperandLI},
681 "ba": {"target_addr": TargetAddrOperandLI},
682 "bl": {"target_addr": TargetAddrOperandLI},
683 "bla": {"target_addr": TargetAddrOperandLI},
684 "bc": {"target_addr": TargetAddrOperandBD},
685 "bca": {"target_addr": TargetAddrOperandBD},
686 "bcl": {"target_addr": TargetAddrOperandBD},
687 "bcla": {"target_addr": TargetAddrOperandBD},
688 "addpcis": {"D": DOperandDX},
689 "fishmv": {"D": DOperandDX},
690 "fmvis": {"D": DOperandDX},
691 }
692 custom_fields = {
693 "SVi": NonZeroOperand,
694 "SVd": NonZeroOperand,
695 "SVxd": NonZeroOperand,
696 "SVyd": NonZeroOperand,
697 "SVzd": NonZeroOperand,
698 "BD": SignedOperand,
699 "D": SignedImmediateOperand,
700 "SI": SignedOperand,
701 "IB": SignedOperand,
702 "LI": SignedOperand,
703 "SIM": SignedOperand,
704 "SVD": SignedOperand,
705 "SVDS": SignedOperand,
706 "RSp": GPRPairOperand,
707 "RTp": GPRPairOperand,
708 "FRAp": FPRPairOperand,
709 "FRBp": FPRPairOperand,
710 "FRSp": FPRPairOperand,
711 "FRTp": FPRPairOperand,
712 }
713 custom_immediates = {
714 "DQ": EXTSOperandDQ,
715 "DS": EXTSOperandDS,
716 }
717
718 mapping = {}
719 for operand in operands:
720 cls = DynamicOperand
721
722 if "=" in operand:
723 (name, value) = operand.split("=")
724 mapping[name] = (StaticOperand, (
725 ("name", name),
726 ("value", int(value)),
727 ))
728 else:
729 name = operand
730 if name.endswith(")"):
731 name = name.replace("(", " ").replace(")", "")
732 (imm_name, _, name) = name.partition(" ")
733 else:
734 imm_name = None
735
736 if imm_name is not None:
737 imm_cls = custom_immediates.get(imm_name, ImmediateOperand)
738
739 if insn in custom_insns and name in custom_insns[insn]:
740 cls = custom_insns[insn][name]
741 elif name in custom_fields:
742 cls = custom_fields[name]
743 elif name in _Reg.__members__:
744 reg = _Reg[name]
745 if reg in self.__class__.__GPR_PAIRS:
746 cls = GPRPairOperand
747 elif reg in self.__class__.__FPR_PAIRS:
748 cls = FPRPairOperand
749 else:
750 regtype = _RegType[name]
751 if regtype is _RegType.GPR:
752 cls = GPROperand
753 elif regtype is _RegType.FPR:
754 cls = FPROperand
755 elif regtype is _RegType.CR_3BIT:
756 cls = CR3Operand
757 elif regtype is _RegType.CR_5BIT:
758 cls = CR5Operand
759
760 if imm_name is not None:
761 mapping[imm_name] = (imm_cls, (
762 ("name", imm_name),
763 ))
764 mapping[name] = (cls, (
765 ("name", name),
766 ))
767
768 return super().__init__(mapping)
769
770 def __iter__(self):
771 for (cls, kwargs) in self.values():
772 yield (cls, dict(kwargs))
773
774 def __hash__(self):
775 return hash(tuple(sorted(self.items())))
776
777 @cached_property
778 def static(self):
779 return tuple(filter(lambda pair: issubclass(pair[0], StaticOperand), self))
780
781 @cached_property
782 def dynamic(self):
783 return tuple(filter(lambda pair: issubclass(pair[0], DynamicOperand), self))
784
785
786 class Arguments(tuple):
787 def __new__(cls, record, arguments, operands):
788 operands = iter(tuple(operands))
789 arguments = iter(tuple(arguments))
790
791 items = []
792 while True:
793 try:
794 operand = next(operands)
795 except StopIteration:
796 break
797
798 try:
799 argument = next(arguments)
800 except StopIteration:
801 raise ValueError("operands count mismatch")
802
803 if isinstance(operand, ImmediateOperand):
804 argument = argument.replace("(", " ").replace(")", "")
805 (imm_argument, _, argument) = argument.partition(" ")
806 try:
807 (imm_operand, operand) = (operand, next(operands))
808 except StopIteration:
809 raise ValueError("operands count mismatch")
810 items.append((imm_argument, imm_operand))
811 items.append((argument, operand))
812
813 try:
814 next(arguments)
815 except StopIteration:
816 pass
817 else:
818 raise ValueError("operands count mismatch")
819
820 return super().__new__(cls, items)
821
822
823 class PCode(tuple):
824 pass
825
826
827 class MarkdownRecord(Dataclass):
828 pcode: PCode
829 operands: Operands
830
831
832 @_functools.total_ordering
833 class Record(Dataclass):
834 name: str
835 section: Section
836 ppc: PPCMultiRecord
837 fields: Fields
838 mdwn: MarkdownRecord
839 svp64: SVP64Record = None
840
841 @property
842 def extras(self):
843 if self.svp64 is not None:
844 return self.svp64.extras
845 else:
846 return _types.MappingProxyType({})
847
848 @property
849 def pcode(self):
850 return self.mdwn.pcode
851
852 def __lt__(self, other):
853 if not isinstance(other, Record):
854 return NotImplemented
855 lhs = (min(self.opcodes), self.name)
856 rhs = (min(other.opcodes), other.name)
857 return (lhs < rhs)
858
859 @cached_property
860 def operands(self):
861 return (self.static_operands + self.dynamic_operands)
862
863 @cached_property
864 def static_operands(self):
865 operands = []
866 operands.append(POStaticOperand(record=self, value=self.PO))
867 for ppc in self.ppc:
868 operands.append(XOStaticOperand(
869 record=self,
870 value=ppc.opcode.value,
871 span=self.section.bitsel,
872 ))
873 for (cls, kwargs) in self.mdwn.operands.static:
874 operands.append(cls(record=self, **kwargs))
875 return tuple(operands)
876
877 @cached_property
878 def dynamic_operands(self):
879 operands = []
880 for (cls, kwargs) in self.mdwn.operands.dynamic:
881 operands.append(cls(record=self, **kwargs))
882 return tuple(operands)
883
884 @cached_property
885 def opcodes(self):
886 def binary(mapping):
887 return int("".join(str(int(mapping[bit])) \
888 for bit in sorted(mapping)), 2)
889
890 def PO_XO(value, mask, opcode, bits):
891 value = dict(value)
892 mask = dict(mask)
893 for (src, dst) in enumerate(reversed(bits)):
894 value[dst] = ((opcode.value & (1 << src)) != 0)
895 mask[dst] = ((opcode.mask & (1 << src)) != 0)
896 return (value, mask)
897
898 def PO(value, mask, opcode, bits):
899 return PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
900
901 def XO(value, mask, opcode, bits):
902 (value, mask) = PO_XO(value=value, mask=mask,
903 opcode=opcode, bits=bits)
904 for (op_cls, op_kwargs) in self.mdwn.operands.static:
905 operand = op_cls(record=self, **op_kwargs)
906 for (src, dst) in enumerate(reversed(operand.span)):
907 value[dst] = ((operand.value & (1 << src)) != 0)
908 mask[dst] = True
909 return (value, mask)
910
911 pairs = []
912 value = {bit:False for bit in range(32)}
913 mask = {bit:False for bit in range(32)}
914 if self.section.opcode is not None:
915 (value, mask) = PO(value=value, mask=mask,
916 opcode=self.section.opcode, bits=range(0, 6))
917 for ppc in self.ppc:
918 pairs.append(XO(value=value, mask=mask,
919 opcode=ppc.opcode, bits=self.section.bitsel))
920
921 result = []
922 for (value, mask) in pairs:
923 value = Opcode.Value(binary(value))
924 mask = Opcode.Mask(binary(mask))
925 result.append(Opcode(value=value, mask=mask))
926
927 return tuple(result)
928
929 @cached_property
930 def PO(self):
931 opcode = self.section.opcode
932 if opcode is None:
933 opcode = self.ppc[0].opcode
934 if isinstance(opcode, PatternOpcode):
935 value = int(opcode.value)
936 bits = opcode.value.bit_length()
937 return int(_SelectableInt(value=value, bits=bits)[0:6])
938
939 return int(opcode.value)
940
941 @cached_property
942 def XO(self):
943 return tuple(ppc.opcode for ppc in self.ppc)
944
945 def match(self, key):
946 for opcode in self.opcodes:
947 if opcode.match(key):
948 return True
949
950 return False
951
952 @property
953 def mode(self):
954 return self.svp64.mode
955
956 @property
957 def in1(self):
958 return self.ppc.in1
959
960 @property
961 def in2(self):
962 return self.ppc.in2
963
964 @property
965 def in3(self):
966 return self.ppc.in3
967
968 @property
969 def out(self):
970 return self.ppc.out
971
972 @property
973 def out2(self):
974 if self.svp64 is None:
975 return _OutSel.NONE
976 return self.ppc.out
977
978 @property
979 def cr_in(self):
980 return self.ppc.cr_in
981
982 @property
983 def cr_in2(self):
984 return self.ppc.cr_in2
985
986 @property
987 def cr_out(self):
988 return self.ppc.cr_out
989
990 ptype = property(lambda self: self.svp64.ptype)
991 etype = property(lambda self: self.svp64.etype)
992
993 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
994 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
995 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
996 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
997 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
998 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
999 extra_idx_cr_in2 = property(lambda self: self.svp64.extra_idx_cr_in2)
1000 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
1001
1002 def __contains__(self, key):
1003 return self.mdwn.operands.__contains__(key)
1004
1005 def __getitem__(self, key):
1006 (cls, kwargs) = self.mdwn.operands.__getitem__(key)
1007 return cls(record=self, **dict(kwargs))
1008
1009 @cached_property
1010 def Rc(self):
1011 if "Rc" not in self:
1012 return False
1013 return self["Rc"].value
1014
1015
1016 class Operand:
1017 def __init__(self, record, name):
1018 self.__record = record
1019 self.__name = name
1020
1021 def __iter__(self):
1022 yield ("record", self.record)
1023 yield ("name", self.__name)
1024
1025 def __repr__(self):
1026 return f"{self.__class__.__name__}({self.name})"
1027
1028 @property
1029 def name(self):
1030 return self.__name
1031
1032 @property
1033 def record(self):
1034 return self.__record
1035
1036 @cached_property
1037 def span(self):
1038 return self.record.fields[self.name]
1039
1040 def assemble(self, insn):
1041 raise NotImplementedError()
1042
1043 def disassemble(self, insn,
1044 style=Style.NORMAL, indent=""):
1045 raise NotImplementedError()
1046
1047
1048 class DynamicOperand(Operand):
1049 def assemble(self, insn, value):
1050 span = self.span
1051 if isinstance(value, str):
1052 value = int(value, 0)
1053 if value < 0:
1054 raise ValueError("signed operands not allowed")
1055 insn[span] = value
1056
1057 def disassemble(self, insn,
1058 style=Style.NORMAL, indent=""):
1059 span = self.span
1060 value = insn[span]
1061
1062 if style >= Style.VERBOSE:
1063 span = map(str, span)
1064 yield f"{indent}{self.name}"
1065 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1066 yield f"{indent}{indent}{', '.join(span)}"
1067 else:
1068 yield str(int(value))
1069
1070
1071 class SignedOperand(DynamicOperand):
1072 def assemble(self, insn, value):
1073 if isinstance(value, str):
1074 value = int(value, 0)
1075 return super().assemble(value=value, insn=insn)
1076
1077 def assemble(self, insn, value):
1078 span = self.span
1079 if isinstance(value, str):
1080 value = int(value, 0)
1081 insn[span] = value
1082
1083 def disassemble(self, insn,
1084 style=Style.NORMAL, indent=""):
1085 span = self.span
1086 value = insn[span].to_signed_int()
1087 sign = "-" if (value < 0) else ""
1088 value = abs(value)
1089
1090 if style >= Style.VERBOSE:
1091 span = map(str, span)
1092 yield f"{indent}{self.name}"
1093 yield f"{indent}{indent}{sign}{value}"
1094 yield f"{indent}{indent}{', '.join(span)}"
1095 else:
1096 yield f"{sign}{value}"
1097
1098
1099 class StaticOperand(Operand):
1100 def __init__(self, record, name, value):
1101 self.__value = value
1102 return super().__init__(record=record, name=name)
1103
1104 def __iter__(self):
1105 yield ("value", self.__value)
1106 yield from super().__iter__()
1107
1108 def __repr__(self):
1109 return f"{self.__class__.__name__}({self.name}, value={self.value})"
1110
1111 @property
1112 def value(self):
1113 return self.__value
1114
1115 def assemble(self, insn):
1116 insn[self.span] = self.value
1117
1118 def disassemble(self, insn,
1119 style=Style.NORMAL, indent=""):
1120 span = self.span
1121 value = insn[span]
1122
1123 if style >= Style.VERBOSE:
1124 span = map(str, span)
1125 yield f"{indent}{self.name}"
1126 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1127 yield f"{indent}{indent}{', '.join(span)}"
1128 else:
1129 yield str(int(value))
1130
1131
1132 class SpanStaticOperand(StaticOperand):
1133 def __init__(self, record, name, value, span):
1134 self.__span = tuple(span)
1135 return super().__init__(record=record, name=name, value=value)
1136
1137 def __iter__(self):
1138 yield ("span", self.__span)
1139 yield from super().__iter__()
1140
1141 @property
1142 def span(self):
1143 return self.__span
1144
1145
1146 class POStaticOperand(SpanStaticOperand):
1147 def __init__(self, record, value):
1148 return super().__init__(record=record, name="PO",
1149 value=value, span=range(0, 6))
1150
1151 def __iter__(self):
1152 for (key, value) in super().__iter__():
1153 if key not in {"name", "span"}:
1154 yield (key, value)
1155
1156
1157 class XOStaticOperand(SpanStaticOperand):
1158 def __init__(self, record, value, span):
1159 bits = record.section.bitsel
1160 value = _SelectableInt(value=value, bits=len(bits))
1161 span = dict(zip(bits, range(len(bits))))
1162 span_rev = {value:key for (key, value) in span.items()}
1163
1164 # This part is tricky: we cannot use record.operands,
1165 # as this code is called by record.static_operands method.
1166 for (cls, kwargs) in record.mdwn.operands:
1167 operand = cls(record=record, **kwargs)
1168 for idx in operand.span:
1169 rev = span.pop(idx, None)
1170 if rev is not None:
1171 span_rev.pop(rev, None)
1172
1173 value = int(_selectconcat(*(value[bit] for bit in span.values())))
1174 span = tuple(span.keys())
1175
1176 return super().__init__(record=record, name="XO",
1177 value=value, span=span)
1178
1179 def __iter__(self):
1180 for (key, value) in super().__iter__():
1181 if key not in {"name"}:
1182 yield (key, value)
1183
1184
1185 class ImmediateOperand(DynamicOperand):
1186 pass
1187
1188
1189 class SignedImmediateOperand(SignedOperand, ImmediateOperand):
1190 pass
1191
1192
1193 class NonZeroOperand(DynamicOperand):
1194 def assemble(self, insn, value):
1195 if isinstance(value, str):
1196 value = int(value, 0)
1197 if not isinstance(value, int):
1198 raise ValueError("non-integer operand")
1199 if value == 0:
1200 raise ValueError("non-zero operand")
1201 value -= 1
1202 return super().assemble(value=value, insn=insn)
1203
1204 def disassemble(self, insn,
1205 style=Style.NORMAL, indent=""):
1206 span = self.span
1207 value = insn[span]
1208
1209 if style >= Style.VERBOSE:
1210 span = map(str, span)
1211 yield f"{indent}{self.name}"
1212 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1213 yield f"{indent}{indent}{', '.join(span)}"
1214 else:
1215 yield str(int(value) + 1)
1216
1217
1218 class ExtendableOperand(DynamicOperand):
1219 def sv_spec_enter(self, value, span):
1220 return (value, span)
1221
1222 def sv_spec(self, insn):
1223 vector = False
1224 span = self.span
1225 value = insn[span]
1226 span = tuple(map(str, span))
1227
1228 if isinstance(insn, SVP64Instruction):
1229 (origin_value, origin_span) = (value, span)
1230 (value, span) = self.sv_spec_enter(value=value, span=span)
1231
1232 for extra_idx in self.extra_idx:
1233 if self.record.etype is _SVEType.EXTRA3:
1234 spec = insn.prefix.rm.extra3[extra_idx]
1235 elif self.record.etype is _SVEType.EXTRA2:
1236 spec = insn.prefix.rm.extra2[extra_idx]
1237 else:
1238 raise ValueError(self.record.etype)
1239
1240 if spec != 0:
1241 vector = bool(spec[0])
1242 spec_span = spec.__class__
1243 if self.record.etype is _SVEType.EXTRA3:
1244 spec_span = tuple(map(str, spec_span[1, 2]))
1245 spec = spec[1, 2]
1246 elif self.record.etype is _SVEType.EXTRA2:
1247 spec_span = tuple(map(str, spec_span[1,]))
1248 spec = _SelectableInt(value=spec[1].value, bits=2)
1249 if vector:
1250 spec <<= 1
1251 spec_span = (spec_span + ("{0}",))
1252 else:
1253 spec_span = (("{0}",) + spec_span)
1254 else:
1255 raise ValueError(self.record.etype)
1256
1257 vector_shift = (2 + (5 - value.bits))
1258 scalar_shift = value.bits
1259 spec_shift = (5 - value.bits)
1260
1261 bits = (len(span) + len(spec_span))
1262 value = _SelectableInt(value=value.value, bits=bits)
1263 spec = _SelectableInt(value=spec.value, bits=bits)
1264 if vector:
1265 value = ((value << vector_shift) | (spec << spec_shift))
1266 span = (span + spec_span + ((spec_shift * ("{0}",))))
1267 else:
1268 value = ((spec << scalar_shift) | value)
1269 span = ((spec_shift * ("{0}",)) + spec_span + span)
1270
1271 (value, span) = self.sv_spec_leave(value=value, span=span,
1272 origin_value=origin_value, origin_span=origin_span)
1273
1274 return (vector, value, span)
1275
1276 def sv_spec_leave(self, value, span, origin_value, origin_span):
1277 return (value, span)
1278
1279 @property
1280 def extra_idx(self):
1281 for (key, record) in self.record.svp64.extras.items():
1282 if record["reg"].alias is self.extra_reg.alias:
1283 yield record["idx"]
1284
1285 @cached_property
1286 def extra_reg(self):
1287 return _Reg(self.name)
1288
1289 def remap(self, value, vector):
1290 raise NotImplementedError()
1291
1292 def assemble(self, value, insn, prefix):
1293 vector = False
1294
1295 if isinstance(value, str):
1296 value = value.lower()
1297 if value.startswith("%"):
1298 value = value[1:]
1299 if value.startswith("*"):
1300 if not isinstance(insn, SVP64Instruction):
1301 raise ValueError(value)
1302 value = value[1:]
1303 vector = True
1304 if value.startswith(prefix):
1305 if (self.extra_reg.or_zero and (value == f"{prefix}0")):
1306 raise ValueError(value)
1307 value = value[len(prefix):]
1308 value = int(value, 0)
1309
1310 if isinstance(insn, SVP64Instruction):
1311 (value, extra) = self.remap(value=value, vector=vector)
1312
1313 for extra_idx in self.extra_idx:
1314 if self.record.etype is _SVEType.EXTRA3:
1315 insn.prefix.rm.extra3[extra_idx] = extra
1316 elif self.record.etype is _SVEType.EXTRA2:
1317 insn.prefix.rm.extra2[extra_idx] = extra
1318 else:
1319 raise ValueError(self.record.etype)
1320
1321 return super().assemble(value=value, insn=insn)
1322
1323 def disassemble(self, insn,
1324 style=Style.NORMAL, prefix="", indent=""):
1325 (vector, value, span) = self.sv_spec(insn=insn)
1326
1327 if (self.extra_reg.or_zero and (value == 0)):
1328 prefix = ""
1329
1330 if style >= Style.VERBOSE:
1331 mode = "vector" if vector else "scalar"
1332 yield f"{indent}{self.name} ({mode})"
1333 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1334 yield f"{indent}{indent}{', '.join(span)}"
1335 if isinstance(insn, SVP64Instruction):
1336 for extra_idx in frozenset(self.extra_idx):
1337 if self.record.etype is _SVEType.NONE:
1338 yield f"{indent}{indent}extra[none]"
1339 else:
1340 etype = repr(self.record.etype).lower()
1341 yield f"{indent}{indent}{etype}{extra_idx!r}"
1342 else:
1343 vector = "*" if vector else ""
1344 yield f"{vector}{prefix}{int(value)}"
1345
1346
1347 class SimpleRegisterOperand(ExtendableOperand):
1348 def remap(self, value, vector):
1349 if vector:
1350 extra = (value & 0b11)
1351 value = (value >> 2)
1352 else:
1353 extra = (value >> 5)
1354 value = (value & 0b11111)
1355
1356 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1357 # (and shrink to a single bit if ok)
1358 if self.record.etype is _SVEType.EXTRA2:
1359 if vector:
1360 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1361 assert (extra & 0b01) == 0, \
1362 ("vector field %s cannot fit into EXTRA2" % value)
1363 extra = (0b10 | (extra >> 1))
1364 else:
1365 # range is r0-r63 in increments of 1
1366 assert (extra >> 1) == 0, \
1367 ("scalar GPR %d cannot fit into EXTRA2" % value)
1368 extra &= 0b01
1369 elif self.record.etype is _SVEType.EXTRA3:
1370 if vector:
1371 # EXTRA3 vector bit needs marking
1372 extra |= 0b100
1373 else:
1374 raise ValueError(self.record.etype)
1375
1376 return (value, extra)
1377
1378
1379 class GPROperand(SimpleRegisterOperand):
1380 def assemble(self, insn, value):
1381 return super().assemble(value=value, insn=insn, prefix="r")
1382
1383 def disassemble(self, insn,
1384 style=Style.NORMAL, indent=""):
1385 prefix = "" if (style <= Style.SHORT) else "r"
1386 yield from super().disassemble(prefix=prefix, insn=insn,
1387 style=style, indent=indent)
1388
1389
1390 class GPRPairOperand(GPROperand):
1391 pass
1392
1393
1394 class FPROperand(SimpleRegisterOperand):
1395 def assemble(self, insn, value):
1396 return super().assemble(value=value, insn=insn, prefix="f")
1397
1398 def disassemble(self, insn,
1399 style=Style.NORMAL, indent=""):
1400 prefix = "" if (style <= Style.SHORT) else "f"
1401 yield from super().disassemble(prefix=prefix, insn=insn,
1402 style=style, indent=indent)
1403
1404
1405 class FPRPairOperand(FPROperand):
1406 pass
1407
1408
1409 class ConditionRegisterFieldOperand(ExtendableOperand):
1410 def pattern(name_pattern):
1411 (name, pattern) = name_pattern
1412 return (name, _re.compile(f"^{pattern}$", _re.S))
1413
1414 CONDS = {
1415 "lt": 0,
1416 "gt": 1,
1417 "eq": 2,
1418 "so": 3,
1419 "un": 3,
1420 }
1421 CR = r"(?:CR|cr)([0-9]+)"
1422 N = r"([0-9]+)"
1423 BIT = rf"({'|'.join(CONDS.keys())})"
1424 LBIT = fr"{BIT}\s*\+\s*" # BIT+
1425 RBIT = fr"\s*\+\s*{BIT}" # +BIT
1426 CRN = fr"{CR}\s*\*\s*{N}" # CR*N
1427 NCR = fr"{N}\s*\*\s*{CR}" # N*CR
1428 XCR = fr"{CR}\.{BIT}"
1429 PATTERNS = tuple(map(pattern, (
1430 ("CR", CR),
1431 ("XCR", XCR),
1432 ("CR*N", CRN),
1433 ("N*CR", NCR),
1434 ("BIT+CR", (LBIT + CR)),
1435 ("CR+BIT", (CR + RBIT)),
1436 ("BIT+CR*N", (LBIT + CRN)),
1437 ("CR*N+BIT", (CRN + RBIT)),
1438 ("BIT+N*CR", (LBIT + NCR)),
1439 ("N*CR+BIT", (NCR + RBIT)),
1440 )))
1441
1442 def remap(self, value, vector, regtype):
1443 if regtype is _RegType.CR_5BIT:
1444 subvalue = (value & 0b11)
1445 value >>= 2
1446
1447 if vector:
1448 extra = (value & 0b1111)
1449 value >>= 4
1450 else:
1451 extra = (value >> 3)
1452 value &= 0b111
1453
1454 if self.record.etype is _SVEType.EXTRA2:
1455 if vector:
1456 assert (extra & 0b111) == 0, \
1457 "vector CR cannot fit into EXTRA2"
1458 extra = (0b10 | (extra >> 3))
1459 else:
1460 assert (extra >> 1) == 0, \
1461 "scalar CR cannot fit into EXTRA2"
1462 extra &= 0b01
1463 elif self.record.etype is _SVEType.EXTRA3:
1464 if vector:
1465 assert (extra & 0b11) == 0, \
1466 "vector CR cannot fit into EXTRA3"
1467 extra = (0b100 | (extra >> 2))
1468 else:
1469 assert (extra >> 2) == 0, \
1470 "scalar CR cannot fit into EXTRA3"
1471 extra &= 0b11
1472
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))