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