power_insn: inherit Operands from tuple
[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 pathlib as _pathlib
8 import re as _re
9
10 try:
11 from functools import cached_property
12 except ImportError:
13 from cached_property import cached_property
14
15 from openpower.decoder.power_enums import (
16 Function as _Function,
17 MicrOp as _MicrOp,
18 In1Sel as _In1Sel,
19 In2Sel as _In2Sel,
20 In3Sel as _In3Sel,
21 OutSel as _OutSel,
22 CRInSel as _CRInSel,
23 CROutSel as _CROutSel,
24 LDSTLen as _LDSTLen,
25 LDSTMode as _LDSTMode,
26 RCOE as _RCOE,
27 CryIn as _CryIn,
28 Form as _Form,
29 SVEtype as _SVEtype,
30 SVMode as _SVMode,
31 SVPtype as _SVPtype,
32 SVExtra as _SVExtra,
33 RegType as _RegType,
34 SVExtraRegType as _SVExtraRegType,
35 SVExtraReg as _SVExtraReg,
36 )
37 from openpower.decoder.selectable_int import (
38 SelectableInt as _SelectableInt,
39 selectconcat as _selectconcat,
40 )
41 from openpower.decoder.power_fields import (
42 Field as _Field,
43 Array as _Array,
44 Mapping as _Mapping,
45 DecodeFields as _DecodeFields,
46 )
47 from openpower.decoder.pseudo.pagereader import ISA as _ISA
48
49
50 def dataclass(cls, record, keymap=None, typemap=None):
51 if keymap is None:
52 keymap = {}
53 if typemap is None:
54 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
55
56 def transform(key_value):
57 (key, value) = key_value
58 key = keymap.get(key, key)
59 hook = typemap.get(key, lambda value: value)
60 if hook is bool and value in ("", "0"):
61 value = False
62 else:
63 value = hook(value)
64 return (key, value)
65
66 record = dict(map(transform, record.items()))
67 for key in frozenset(record.keys()):
68 if record[key] == "":
69 record.pop(key)
70
71 return cls(**record)
72
73
74 @_functools.total_ordering
75 @_dataclasses.dataclass(eq=True, frozen=True)
76 class Opcode:
77 class Value(int):
78 def __repr__(self):
79 if self.bit_length() <= 32:
80 return f"0x{self:08x}"
81 else:
82 return f"0x{self:016x}"
83
84 class Mask(int):
85 def __repr__(self):
86 if self.bit_length() <= 32:
87 return f"0x{self:08x}"
88 else:
89 return f"0x{self:016x}"
90
91 value: Value
92 mask: Mask = None
93
94 def __lt__(self, other):
95 if not isinstance(other, Opcode):
96 return NotImplemented
97 return ((self.value, self.mask) < (other.value, other.mask))
98
99 def __post_init__(self):
100 (value, mask) = (self.value, self.mask)
101
102 if isinstance(value, Opcode):
103 if mask is not None:
104 raise ValueError(mask)
105 (value, mask) = (value.value, value.mask)
106 elif isinstance(value, str):
107 if mask is not None:
108 raise ValueError(mask)
109 value = int(value, 0)
110
111 if not isinstance(value, int):
112 raise ValueError(value)
113 if mask is None:
114 mask = value
115 if not isinstance(mask, int):
116 raise ValueError(mask)
117
118 object.__setattr__(self, "value", self.__class__.Value(value))
119 object.__setattr__(self, "mask", self.__class__.Mask(mask))
120
121
122 class IntegerOpcode(Opcode):
123 def __init__(self, value):
124 if isinstance(value, str):
125 value = int(value, 0)
126 return super().__init__(value=value, mask=None)
127
128
129 class PatternOpcode(Opcode):
130 def __init__(self, value):
131 (pattern, value, mask) = (value, 0, 0)
132
133 for symbol in pattern:
134 if symbol not in {"0", "1", "-"}:
135 raise ValueError(pattern)
136 value |= (symbol == "1")
137 mask |= (symbol != "-")
138 value <<= 1
139 mask <<= 1
140 value >>= 1
141 mask >>= 1
142
143 return super().__init__(value=value, mask=mask)
144
145
146 class FieldsOpcode(Opcode):
147 def __init__(self, fields):
148 def field(opcode, field):
149 (value, mask) = opcode
150 (field, bits) = field
151 shifts = map(lambda bit: (31 - bit), reversed(tuple(bits)))
152 for (index, shift) in enumerate(shifts):
153 bit = ((field & (1 << index)) != 0)
154 value |= (bit << shift)
155 mask |= (1 << shift)
156 return (value, mask)
157
158 (value, mask) = _functools.reduce(field, fields, (0, 0))
159
160 return super().__init__(value=value, mask=mask)
161
162
163 @_dataclasses.dataclass(eq=True, frozen=True)
164 class PPCRecord:
165 class FlagsMeta(type):
166 def __iter__(cls):
167 yield from (
168 "inv A",
169 "inv out",
170 "cry out",
171 "BR",
172 "sgn ext",
173 "rsrv",
174 "32b",
175 "sgn",
176 "lk",
177 "sgl pipe",
178 )
179
180 class Flags(frozenset, metaclass=FlagsMeta):
181 def __new__(cls, flags=frozenset()):
182 flags = frozenset(flags)
183 diff = (flags - frozenset(cls))
184 if diff:
185 raise ValueError(flags)
186 return super().__new__(cls, flags)
187
188 opcode: Opcode
189 comment: str
190 flags: Flags = Flags()
191 comment2: str = ""
192 function: _Function = _Function.NONE
193 intop: _MicrOp = _MicrOp.OP_ILLEGAL
194 in1: _In1Sel = _In1Sel.RA
195 in2: _In2Sel = _In2Sel.NONE
196 in3: _In3Sel = _In3Sel.NONE
197 out: _OutSel = _OutSel.NONE
198 cr_in: _CRInSel = _CRInSel.NONE
199 cr_out: _CROutSel = _CROutSel.NONE
200 cry_in: _CryIn = _CryIn.ZERO
201 ldst_len: _LDSTLen = _LDSTLen.NONE
202 upd: _LDSTMode = _LDSTMode.NONE
203 Rc: _RCOE = _RCOE.NONE
204 form: _Form = _Form.NONE
205 conditions: str = ""
206 unofficial: bool = False
207
208 __KEYMAP = {
209 "unit": "function",
210 "internal op": "intop",
211 "CR in": "cr_in",
212 "CR out": "cr_out",
213 "cry in": "cry_in",
214 "ldst len": "ldst_len",
215 "rc": "Rc",
216 "CONDITIONS": "conditions",
217 }
218
219 @classmethod
220 def CSV(cls, record, opcode_cls=Opcode):
221 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
222 typemap["opcode"] = opcode_cls
223
224 flags = set()
225 for flag in frozenset(PPCRecord.Flags):
226 if bool(record.pop(flag, "")):
227 flags.add(flag)
228 record["flags"] = PPCRecord.Flags(flags)
229
230 return dataclass(cls, record, keymap=PPCRecord.__KEYMAP, typemap=typemap)
231
232 @cached_property
233 def names(self):
234 return frozenset(self.comment.split("=")[-1].split("/"))
235
236
237 class PPCMultiRecord(tuple):
238 @cached_property
239 def unified(self):
240 def merge(lhs, rhs):
241 value = 0
242 mask = 0
243 lvalue = lhs.opcode.value
244 rvalue = rhs.opcode.value
245 lmask = lhs.opcode.mask
246 rmask = rhs.opcode.mask
247 bits = max(lmask.bit_length(), rmask.bit_length())
248 for bit in range(bits):
249 lvstate = ((lvalue & (1 << bit)) != 0)
250 rvstate = ((rvalue & (1 << bit)) != 0)
251 lmstate = ((lmask & (1 << bit)) != 0)
252 rmstate = ((rmask & (1 << bit)) != 0)
253 vstate = lvstate
254 mstate = True
255 if (not lmstate or not rmstate) or (lvstate != rvstate):
256 vstate = 0
257 mstate = 0
258 value |= (vstate << bit)
259 mask |= (mstate << bit)
260
261 return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
262
263 return _functools.reduce(merge, self)
264
265 def __getattr__(self, attr):
266 return getattr(self.unified, attr)
267
268
269 @_dataclasses.dataclass(eq=True, frozen=True)
270 class SVP64Record:
271 class ExtraMap(tuple):
272 class Extra(tuple):
273 @_dataclasses.dataclass(eq=True, frozen=True)
274 class Entry:
275 regtype: _SVExtraRegType = _SVExtraRegType.NONE
276 reg: _SVExtraReg = _SVExtraReg.NONE
277
278 def __repr__(self):
279 return f"{self.regtype.value}:{self.reg.name}"
280
281 def __new__(cls, value="0"):
282 if isinstance(value, str):
283 def transform(value):
284 (regtype, reg) = value.split(":")
285 regtype = _SVExtraRegType(regtype)
286 reg = _SVExtraReg(reg)
287 return cls.Entry(regtype=regtype, reg=reg)
288
289 if value == "0":
290 value = tuple()
291 else:
292 value = map(transform, value.split(";"))
293
294 return super().__new__(cls, value)
295
296 def __repr__(self):
297 return repr(list(self))
298
299 def __new__(cls, value=tuple()):
300 value = tuple(value)
301 if len(value) == 0:
302 value = (("0",) * 4)
303 return super().__new__(cls, map(cls.Extra, value))
304
305 def __repr__(self):
306 return repr({index:self[index] for index in range(0, 4)})
307
308 name: str
309 ptype: _SVPtype = _SVPtype.NONE
310 etype: _SVEtype = _SVEtype.NONE
311 in1: _In1Sel = _In1Sel.NONE
312 in2: _In2Sel = _In2Sel.NONE
313 in3: _In3Sel = _In3Sel.NONE
314 out: _OutSel = _OutSel.NONE
315 out2: _OutSel = _OutSel.NONE
316 cr_in: _CRInSel = _CRInSel.NONE
317 cr_out: _CROutSel = _CROutSel.NONE
318 extra: ExtraMap = ExtraMap()
319 conditions: str = ""
320 mode: _SVMode = _SVMode.NORMAL
321
322 __KEYMAP = {
323 "insn": "name",
324 "CONDITIONS": "conditions",
325 "Ptype": "ptype",
326 "Etype": "etype",
327 "CR in": "cr_in",
328 "CR out": "cr_out",
329 }
330
331 @classmethod
332 def CSV(cls, record):
333 for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
334 value = record[key]
335 if value == "0":
336 record[key] = "NONE"
337
338 record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
339
340 return dataclass(cls, record, keymap=cls.__KEYMAP)
341
342
343 class BitSel:
344 def __init__(self, value=(0, 32)):
345 if isinstance(value, str):
346 (start, end) = map(int, value.split(":"))
347 else:
348 (start, end) = value
349 if start < 0 or end < 0 or start >= end:
350 raise ValueError(value)
351
352 self.__start = start
353 self.__end = end
354
355 return super().__init__()
356
357 def __repr__(self):
358 return f"[{self.__start}:{self.__end}]"
359
360 def __iter__(self):
361 yield from range(self.start, (self.end + 1))
362
363 @property
364 def start(self):
365 return self.__start
366
367 @property
368 def end(self):
369 return self.__end
370
371
372 @_dataclasses.dataclass(eq=True, frozen=True)
373 class Section:
374 class Mode(_enum.Enum):
375 INTEGER = _enum.auto()
376 PATTERN = _enum.auto()
377
378 @classmethod
379 def _missing_(cls, value):
380 if isinstance(value, str):
381 return cls[value.upper()]
382 return super()._missing_(value)
383
384 class Suffix(int):
385 def __new__(cls, value=None):
386 if isinstance(value, str):
387 if value.upper() == "NONE":
388 value = None
389 else:
390 value = int(value, 0)
391 if value is None:
392 value = 0
393
394 return super().__new__(cls, value)
395
396 def __str__(self):
397 return repr(self)
398
399 def __repr__(self):
400 return (bin(self) if self else "None")
401
402 path: _pathlib.Path
403 opcode: Opcode
404 bitsel: BitSel
405 suffix: Suffix
406 mode: Mode
407
408 @classmethod
409 def CSV(cls, record):
410 return dataclass(cls, record)
411
412
413 class Fields:
414 def __init__(self, items):
415 if isinstance(items, dict):
416 items = items.items()
417
418 def transform(item):
419 (name, bitrange) = item
420 return (name, list(bitrange.values()))
421
422 self.__mapping = dict(map(transform, items))
423
424 return super().__init__()
425
426 def __repr__(self):
427 return repr(self.__mapping)
428
429 def __iter__(self):
430 yield from self.__mapping.items()
431
432 def __contains__(self, key):
433 return self.__mapping.__contains__(key)
434
435 def __getitem__(self, key):
436 return self.__mapping.get(key, None)
437
438
439 @_dataclasses.dataclass(eq=True, frozen=True)
440 class Operand:
441 name: str
442
443 def disassemble(self, value, record, verbose=False):
444 raise NotImplementedError
445
446
447 @_dataclasses.dataclass(eq=True, frozen=True)
448 class DynamicOperand(Operand):
449 def disassemble(self, value, record, verbose=False):
450 span = record.fields[self.name]
451 value = value[span]
452 if verbose:
453 yield f"{int(value):0{value.bits}b}"
454 yield repr(span)
455 else:
456 yield str(int(value))
457
458
459 @_dataclasses.dataclass(eq=True, frozen=True)
460 class StaticOperand(Operand):
461 value: int
462
463 def disassemble(self, value, record, verbose=False):
464 span = record.fields[self.name]
465 value = value[span]
466 if verbose:
467 yield f"{int(value):0{value.bits}b}"
468 yield repr(span)
469 else:
470 yield str(int(value))
471
472
473 @_dataclasses.dataclass(eq=True, frozen=True)
474 class DynamicOperandTargetAddrLI(DynamicOperand):
475 @property
476 def name(self):
477 return "LI"
478
479 @name.setter
480 def name(self, _):
481 pass
482
483 def disassemble(self, value, record, verbose=False):
484 span = record.fields["LI"]
485 value = value[span]
486 if verbose:
487 yield f"{int(value):0{value.bits}b}"
488 yield repr(span)
489 yield "target_addr = EXTS(LI || 0b00))"
490 else:
491 yield hex(int(_selectconcat(value,
492 _SelectableInt(value=0b00, bits=2))))
493
494
495 class DynamicOperandTargetAddrBD(DynamicOperand):
496 @property
497 def name(self):
498 return "BD"
499
500 @name.setter
501 def name(self, _):
502 pass
503
504 def disassemble(self, value, record, verbose=False):
505 span = record.fields["BD"]
506 value = value[span]
507 if verbose:
508 yield f"{int(value):0{value.bits}b}"
509 yield repr(span)
510 yield "target_addr = EXTS(BD || 0b00))"
511 else:
512 yield hex(int(_selectconcat(value,
513 _SelectableInt(value=0b00, bits=2))))
514
515
516 @_dataclasses.dataclass(eq=True, frozen=True)
517 class DynamicOperandGPR(DynamicOperand):
518 def disassemble(self, value, record, verbose=False):
519 span = record.fields[self.name]
520 value = value[span]
521 if verbose:
522 yield f"{int(value):0{value.bits}b}"
523 yield repr(span)
524 else:
525 yield f"r{str(int(value))}"
526
527
528 @_dataclasses.dataclass(eq=True, frozen=True)
529 class DynamicOperandFPR(DynamicOperand):
530 def disassemble(self, value, record, verbose=False):
531 span = record.fields[self.name]
532 value = value[span]
533 if verbose:
534 yield f"{int(value):0{value.bits}b}"
535 yield repr(span)
536 else:
537 yield f"f{str(int(value))}"
538
539
540 class Operands(tuple):
541 def __new__(cls, insn, iterable):
542 branches = {
543 "b": {"target_addr": DynamicOperandTargetAddrLI},
544 "ba": {"target_addr": DynamicOperandTargetAddrLI},
545 "bl": {"target_addr": DynamicOperandTargetAddrLI},
546 "bla": {"target_addr": DynamicOperandTargetAddrLI},
547 "bc": {"target_addr": DynamicOperandTargetAddrBD},
548 "bca": {"target_addr": DynamicOperandTargetAddrBD},
549 "bcl": {"target_addr": DynamicOperandTargetAddrBD},
550 "bcla": {"target_addr": DynamicOperandTargetAddrBD},
551 }
552
553 operands = []
554 for operand in iterable:
555 dynamic_cls = DynamicOperand
556 static_cls = StaticOperand
557
558 if "=" in operand:
559 (name, value) = operand.split("=")
560 operand = static_cls(name=name, value=int(value))
561 operands.append(operand)
562 else:
563 if operand.endswith(")"):
564 operand = operand.replace("(", " ").replace(")", "")
565 all_operands = operand.split(" ")
566 else:
567 all_operands = [operand]
568
569 for operand in all_operands:
570 if insn in branches and operand in branches[insn]:
571 dynamic_cls = branches[insn][operand]
572
573 if operand in _RegType.__members__:
574 regtype = _RegType[operand]
575 if regtype is _RegType.GPR:
576 dynamic_cls = DynamicOperandGPR
577 elif regtype is _RegType.FPR:
578 dynamic_cls = DynamicOperandFPR
579
580 operand = dynamic_cls(name=operand)
581 operands.append(operand)
582
583 return super().__new__(cls, operands)
584
585 def __contains__(self, key):
586 return self.__getitem__(key) is not None
587
588 def __getitem__(self, key):
589 for operand in self:
590 if operand.name == key:
591 return operand
592
593 return None
594
595 @property
596 def dynamic(self):
597 for operand in self:
598 if isinstance(operand, DynamicOperand):
599 yield operand
600
601 @property
602 def static(self):
603 for operand in self:
604 if isinstance(operand, StaticOperand):
605 yield operand
606
607
608 @_functools.total_ordering
609 @_dataclasses.dataclass(eq=True, frozen=True)
610 class Record:
611 name: str
612 section: Section
613 ppc: PPCRecord
614 fields: Fields
615 operands: Operands
616 svp64: SVP64Record = None
617
618 __EXTRA = (
619 _SVExtra.Idx0,
620 _SVExtra.Idx1,
621 _SVExtra.Idx2,
622 _SVExtra.Idx3,
623 )
624
625 def __lt__(self, other):
626 if not isinstance(other, Record):
627 return NotImplemented
628 return (self.opcode < other.opcode)
629
630 @cached_property
631 def opcode(self):
632 fields = []
633 if self.section.opcode:
634 fields += [(self.section.opcode.value, BitSel((0, 5)))]
635 fields += [(self.ppc.opcode.value, self.section.bitsel)]
636 else:
637 fields += [(self.ppc.opcode.value, self.section.bitsel)]
638
639 for operand in self.operands.static:
640 fields += [(operand.value, self.fields[operand.name])]
641
642 return FieldsOpcode(fields)
643
644 @property
645 def function(self):
646 return self.ppc.function
647
648 @property
649 def in1(self):
650 return self.ppc.in1
651
652 @property
653 def in2(self):
654 return self.ppc.in2
655
656 @property
657 def in3(self):
658 return self.ppc.in3
659
660 @property
661 def out(self):
662 return self.ppc.out
663
664 @property
665 def out2(self):
666 if self.svp64 is None:
667 return _OutSel.NONE
668 return self.ppc.out
669
670 @property
671 def cr_in(self):
672 return self.ppc.cr_in
673
674 @property
675 def cr_out(self):
676 return self.ppc.cr_out
677
678 def sv_extra(self, key):
679 if key not in frozenset({
680 "in1", "in2", "in3", "cr_in",
681 "out", "out2", "cr_out",
682 }):
683 raise KeyError(key)
684
685 sel = getattr(self.svp64, key)
686 if sel is _CRInSel.BA_BB:
687 return _SVExtra.Idx_1_2
688 reg = _SVExtraReg(sel)
689 if reg is _SVExtraReg.NONE:
690 return _SVExtra.NONE
691
692 extra_map = {
693 _SVExtraRegType.SRC: {},
694 _SVExtraRegType.DST: {},
695 }
696 for index in range(0, 4):
697 for entry in self.svp64.extra[index]:
698 extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
699
700 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
701 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
702 if extra is not _SVExtra.NONE:
703 return extra
704
705 return _SVExtra.NONE
706
707 sv_in1 = property(_functools.partial(sv_extra, key="in1"))
708 sv_in2 = property(_functools.partial(sv_extra, key="in2"))
709 sv_in3 = property(_functools.partial(sv_extra, key="in3"))
710 sv_out = property(_functools.partial(sv_extra, key="out"))
711 sv_out2 = property(_functools.partial(sv_extra, key="out2"))
712 sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
713 sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
714
715 @property
716 def sv_ptype(self):
717 if self.svp64 is None:
718 return _SVPtype.NONE
719 return self.svp64.ptype
720
721 @property
722 def sv_etype(self):
723 if self.svp64 is None:
724 return _SVEtype.NONE
725 return self.svp64.etype
726
727
728 class Instruction(_Mapping):
729 @classmethod
730 def integer(cls, value=0, bits=None, byteorder="little"):
731 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
732 raise ValueError(bits)
733
734 if isinstance(value, bytes):
735 if ((len(value) * 8) != bits):
736 raise ValueError(f"bit length mismatch")
737 value = int.from_bytes(value, byteorder=byteorder)
738
739 if isinstance(value, int):
740 value = _SelectableInt(value=value, bits=bits)
741 elif isinstance(value, Instruction):
742 value = value.storage
743
744 if not isinstance(value, _SelectableInt):
745 raise ValueError(value)
746 if bits is None:
747 bits = len(cls)
748 if len(value) != bits:
749 raise ValueError(value)
750
751 value = _SelectableInt(value=value, bits=bits)
752
753 return cls(storage=value)
754
755 def __hash__(self):
756 return hash(int(self))
757
758 def disassemble(self, db, byteorder="little", verbose=False):
759 raise NotImplementedError
760
761
762 class WordInstruction(Instruction):
763 _: _Field = range(0, 32)
764 po: _Field = range(0, 6)
765
766 @classmethod
767 def integer(cls, value, byteorder="little"):
768 return super().integer(bits=32, value=value, byteorder=byteorder)
769
770 @property
771 def binary(self):
772 bits = []
773 for idx in range(32):
774 bit = int(self[idx])
775 bits.append(bit)
776 return "".join(map(str, bits))
777
778 def spec(self, record):
779 dynamic_operands = []
780 for operand in record.operands.dynamic:
781 dynamic_operands.append(operand.name)
782 static_operands = []
783 for operand in record.operands.static:
784 static_operands.append(f"{operand.name}={operand.value}")
785 operands = ""
786 if dynamic_operands:
787 operands += f" {','.join(dynamic_operands)}"
788 if static_operands:
789 operands += f" ({' '.join(static_operands)})"
790 return f"{record.name}{operands}"
791
792 def opcode(self, record):
793 return f"0x{record.opcode.value:08x}"
794
795 def mask(self, record):
796 return f"0x{record.opcode.mask:08x}"
797
798 def disassemble(self, db, byteorder="little", verbose=False):
799 integer = int(self)
800 blob = integer.to_bytes(length=4, byteorder=byteorder)
801 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
802
803 record = db[self]
804 if record is None:
805 yield f"{blob} .long 0x{integer:08x}"
806 return
807
808 operands = []
809 for operand in record.operands.dynamic:
810 operand = " ".join(operand.disassemble(value=self,
811 record=record, verbose=False))
812 operands.append(operand)
813 if operands:
814 operands = ",".join(operands)
815 operands = f" {operands}"
816 else:
817 operands = ""
818
819 yield f"{blob} {record.name}{operands}"
820
821 if verbose:
822 indent = (" " * 4)
823 binary = self.binary
824 spec = self.spec(record=record)
825 opcode = self.opcode(record=record)
826 mask = self.mask(record=record)
827 yield f"{indent}spec"
828 yield f"{indent}{indent}{spec}"
829 yield f"{indent}binary"
830 yield f"{indent}{indent}[0:8] {binary[0:8]}"
831 yield f"{indent}{indent}[8:16] {binary[8:16]}"
832 yield f"{indent}{indent}[16:24] {binary[16:24]}"
833 yield f"{indent}{indent}[24:32] {binary[24:32]}"
834 yield f"{indent}opcode"
835 yield f"{indent}{indent}{opcode}"
836 yield f"{indent}mask"
837 yield f"{indent}{indent}{mask}"
838 for operand in record.operands:
839 name = operand.name
840 yield f"{indent}{name}"
841 parts = operand.disassemble(value=self,
842 record=record, verbose=True)
843 for part in parts:
844 yield f"{indent}{indent}{part}"
845 yield ""
846
847
848 class PrefixedInstruction(Instruction):
849 class Prefix(WordInstruction.remap(range(0, 32))):
850 pass
851
852 class Suffix(WordInstruction.remap(range(32, 64))):
853 pass
854
855 _: _Field = range(64)
856 prefix: Prefix
857 suffix: Suffix
858 po: Suffix.po
859
860 @classmethod
861 def integer(cls, value, byteorder="little"):
862 return super().integer(bits=64, value=value, byteorder=byteorder)
863
864 @classmethod
865 def pair(cls, prefix=0, suffix=0, byteorder="little"):
866 def transform(value):
867 return WordInstruction.integer(value=value,
868 byteorder=byteorder)[0:32]
869
870 (prefix, suffix) = map(transform, (prefix, suffix))
871 value = _selectconcat(prefix, suffix)
872
873 return super().integer(value=value)
874
875
876 class Mode(_Mapping):
877 _: _Field = range(0, 5)
878 sel: _Field = range(0, 2)
879
880
881 class NormalMode(Mode):
882 class simple(Mode):
883 """simple mode"""
884 dz: Mode[3]
885 sz: Mode[4]
886
887 class smr(Mode):
888 """scalar reduce mode (mapreduce), SUBVL=1"""
889 RG: Mode[4]
890
891 class pmr(Mode):
892 """parallel reduce mode (mapreduce), SUBVL=1"""
893 pass
894
895 class svmr(Mode):
896 """subvector reduce mode, SUBVL>1"""
897 SVM: Mode[3]
898
899 class pu(Mode):
900 """Pack/Unpack mode, SUBVL>1"""
901 SVM: Mode[3]
902
903 class ffrc1(Mode):
904 """Rc=1: ffirst CR sel"""
905 inv: Mode[2]
906 CRbit: Mode[3, 4]
907
908 class ffrc0(Mode):
909 """Rc=0: ffirst z/nonz"""
910 inv: Mode[2]
911 VLi: Mode[3]
912 RC1: Mode[4]
913
914 class sat(Mode):
915 """sat mode: N=0/1 u/s, SUBVL=1"""
916 N: Mode[2]
917 dz: Mode[3]
918 sz: Mode[4]
919
920 class satx(Mode):
921 """sat mode: N=0/1 u/s, SUBVL>1"""
922 N: Mode[2]
923 zz: Mode[3]
924 dz: Mode[3]
925 sz: Mode[3]
926
927 class satpu(Mode):
928 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
929 N: Mode[2]
930 zz: Mode[3]
931 dz: Mode[3]
932 sz: Mode[3]
933
934 class prrc1(Mode):
935 """Rc=1: pred-result CR sel"""
936 inv: Mode[2]
937 CRbit: Mode[3, 4]
938
939 class prrc0(Mode):
940 """Rc=0: pred-result z/nonz"""
941 inv: Mode[2]
942 zz: Mode[3]
943 RC1: Mode[4]
944 dz: Mode[3]
945 sz: Mode[3]
946
947 simple: simple
948 smr: smr
949 pmr: pmr
950 svmr: svmr
951 pu: pu
952 ffrc1: ffrc1
953 ffrc0: ffrc0
954 sat: sat
955 satx: satx
956 satpu: satpu
957 prrc1: prrc1
958 prrc0: prrc0
959
960
961 class LDSTImmMode(Mode):
962 class simple(Mode):
963 """simple mode"""
964 zz: Mode[3]
965 els: Mode[4]
966 dz: Mode[3]
967 sz: Mode[3]
968
969 class spu(Mode):
970 """Structured Pack/Unpack"""
971 zz: Mode[3]
972 els: Mode[4]
973 dz: Mode[3]
974 sz: Mode[3]
975
976 class ffrc1(Mode):
977 """Rc=1: ffirst CR sel"""
978 inv: Mode[2]
979 CRbit: Mode[3, 4]
980
981 class ffrc0(Mode):
982 """Rc=0: ffirst z/nonz"""
983 inv: Mode[2]
984 els: Mode[3]
985 RC1: Mode[4]
986
987 class sat(Mode):
988 """sat mode: N=0/1 u/s"""
989 N: Mode[2]
990 zz: Mode[3]
991 els: Mode[4]
992 dz: Mode[3]
993 sz: Mode[3]
994
995 class prrc1(Mode):
996 """Rc=1: pred-result CR sel"""
997 inv: Mode[2]
998 CRbit: Mode[3, 4]
999
1000 class prrc0(Mode):
1001 """Rc=0: pred-result z/nonz"""
1002 inv: Mode[2]
1003 els: Mode[3]
1004 RC1: Mode[4]
1005
1006 simple: simple
1007 spu: spu
1008 ffrc1: ffrc1
1009 ffrc0: ffrc0
1010 sat: sat
1011 prrc1: prrc1
1012 prrc0: prrc0
1013
1014
1015 class LDSTIdxMode(Mode):
1016 class simple(Mode):
1017 """simple mode"""
1018 SEA: Mode[2]
1019 sz: Mode[3]
1020 dz: Mode[3]
1021
1022 class stride(Mode):
1023 """strided (scalar only source)"""
1024 SEA: Mode[2]
1025 dz: Mode[3]
1026 sz: Mode[4]
1027
1028 class sat(Mode):
1029 """sat mode: N=0/1 u/s"""
1030 N: Mode[2]
1031 dz: Mode[3]
1032 sz: Mode[4]
1033
1034 class prrc1(Mode):
1035 """Rc=1: pred-result CR sel"""
1036 inv: Mode[2]
1037 CRbit: Mode[3, 4]
1038
1039 class prrc0(Mode):
1040 """Rc=0: pred-result z/nonz"""
1041 inv: Mode[2]
1042 zz: Mode[3]
1043 RC1: Mode[4]
1044 dz: Mode[3]
1045 sz: Mode[3]
1046
1047 simple: simple
1048 stride: stride
1049 sat: sat
1050 prrc1: prrc1
1051 prrc0: prrc0
1052
1053
1054 class RM(_Mapping):
1055 class Mode(Mode):
1056 normal: NormalMode
1057 ldst_imm: LDSTImmMode
1058 ldst_idx: LDSTIdxMode
1059
1060 _: _Field = range(24)
1061 mmode: _Field = (0,)
1062 mask: _Field = range(1, 4)
1063 elwidth: _Field = range(4, 6)
1064 ewsrc: _Field = range(6, 8)
1065 subvl: _Field = range(8, 10)
1066 extra: _Field = range(10, 19)
1067 mode: Mode.remap(range(19, 24))
1068 extra2: _Array[4] = (
1069 range(10, 12),
1070 range(12, 14),
1071 range(14, 16),
1072 range(16, 18),
1073 )
1074 smask: _Field = range(16, 19)
1075 extra3: _Array[3] = (
1076 range(10, 13),
1077 range(13, 16),
1078 range(16, 19),
1079 )
1080
1081
1082 class SVP64Instruction(PrefixedInstruction):
1083 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1084 class Prefix(PrefixedInstruction.Prefix):
1085 id: _Field = (7, 9)
1086 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1087
1088 prefix: Prefix
1089
1090 @property
1091 def binary(self):
1092 bits = []
1093 for idx in range(64):
1094 bit = int(self[idx])
1095 bits.append(bit)
1096 return "".join(map(str, bits))
1097
1098 def spec(self, record):
1099 return f"sv.{self.suffix.spec(record=record)}"
1100
1101 def opcode(self, record):
1102 return self.suffix.opcode(record=record)
1103
1104 def mask(self, record):
1105 return self.suffix.mask(record=record)
1106
1107 def disassemble(self, db, byteorder="little", verbose=False):
1108 integer_prefix = int(self.prefix)
1109 blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
1110 blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
1111
1112 integer_suffix = int(self.suffix)
1113 blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
1114 blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
1115
1116 record = db[self.suffix]
1117 if record is None or record.svp64 is None:
1118 yield f"{blob_prefix} .long 0x{int(self.prefix):08x}"
1119 yield f"{blob_suffix} .long 0x{int(self.suffix):08x}"
1120 return
1121
1122 Rc = False
1123 if record.operands["Rc"] is not None:
1124 Rc = bool(self[record.fields["Rc"]])
1125
1126 subvl = self.prefix.rm.subvl
1127 mode = self.prefix.rm.mode
1128 sel = mode.sel
1129
1130 if record.svp64.mode is _SVMode.NORMAL:
1131 mode = mode.normal
1132 if sel == 0b00:
1133 if mode[2] == 0b0:
1134 mode = mode.simple
1135 else:
1136 if subvl == 0b00:
1137 if mode[3] == 0b0:
1138 mode = mode.smr
1139 else:
1140 mode = mode.pmr
1141 else:
1142 if mode[4] == 0b0:
1143 mode = mode.svmr
1144 else:
1145 mode = mode.pu
1146 elif sel == 0b01:
1147 if Rc:
1148 mode = mode.ffrc1
1149 else:
1150 mode = mode.ffrc0
1151 elif sel == 0b10:
1152 if subvl == 0b00:
1153 mode = mode.sat
1154 else:
1155 if mode[4]:
1156 mode = mode.satx
1157 else:
1158 mode = mode.satpu
1159 elif sel == 0b11:
1160 if Rc:
1161 mode = mode.prrc1
1162 else:
1163 mode = mode.prrc0
1164 elif record.svp64.mode is _SVMode.LDST_IMM:
1165 mode = mode.ldst_imm
1166 if sel == 0b00:
1167 if mode[2] == 0b0:
1168 mode = mode.simple
1169 else:
1170 mode = mode.spu
1171 elif sel == 0b01:
1172 if Rc:
1173 mode = mode.ffrc1
1174 else:
1175 mode = mode.ffrc0
1176 elif sel == 0b10:
1177 mode = mode.sat
1178 elif sel == 0b11:
1179 if Rc:
1180 mode = mode.prrc1
1181 else:
1182 mode = mode.prrc0
1183 elif record.svp64.mode is _SVMode.LDST_IMM:
1184 mode = mode.ldst_idx
1185 if mode.sel == 0b00:
1186 mode = mode.simple
1187 elif mode.sel == 0b01:
1188 mode = mode.stride
1189 elif mode.sel == 0b10:
1190 mode = mode.sat
1191 elif mode.sel == 0b11:
1192 if Rc:
1193 mode = mode.prrc1
1194 else:
1195 mode = mode.prrc0
1196
1197 if type(mode) is Mode:
1198 raise NotImplementedError
1199
1200 yield f"{blob_prefix} sv.{record.name}"
1201 yield f"{blob_suffix}"
1202
1203 if verbose:
1204 indent = (" " * 4)
1205 binary = self.binary
1206 spec = self.spec(record=record)
1207 opcode = self.opcode(record=record)
1208 mask = self.mask(record=record)
1209 yield f"{indent}spec"
1210 yield f"{indent}{indent}{spec}"
1211 yield f"{indent}binary"
1212 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1213 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1214 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1215 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1216 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1217 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1218 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1219 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1220 yield f"{indent}opcode"
1221 yield f"{indent}{indent}{opcode}"
1222 yield f"{indent}mask"
1223 yield f"{indent}{indent}{mask}"
1224 for operand in record.operands:
1225 name = operand.name
1226 yield f"{indent}{name}"
1227 parts = operand.disassemble(value=self,
1228 record=record, verbose=True)
1229 for part in parts:
1230 yield f"{indent}{indent}{part}"
1231 yield ""
1232
1233
1234 def parse(stream, factory):
1235 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1236 entries = _csv.DictReader(lines)
1237 entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
1238 return tuple(map(factory, entries))
1239
1240
1241 class MarkdownDatabase:
1242 def __init__(self):
1243 db = {}
1244 for (name, desc) in _ISA():
1245 operands = []
1246 if desc.regs:
1247 (dynamic, *static) = desc.regs
1248 operands.extend(dynamic)
1249 operands.extend(static)
1250 db[name] = Operands(insn=name, iterable=operands)
1251 self.__db = db
1252 return super().__init__()
1253
1254 def __iter__(self):
1255 yield from self.__db.items()
1256
1257 def __getitem__(self, key):
1258 return self.__db.__getitem__(key)
1259
1260
1261 class FieldsDatabase:
1262 def __init__(self):
1263 db = {}
1264 df = _DecodeFields()
1265 df.create_specs()
1266 for (form, fields) in df.instrs.items():
1267 if form in {"DQE", "TX"}:
1268 continue
1269 if form == "all":
1270 form = "NONE"
1271 db[_Form[form]] = Fields(fields)
1272
1273 self.__db = db
1274
1275 return super().__init__()
1276
1277 def __getitem__(self, key):
1278 return self.__db.__getitem__(key)
1279
1280
1281 class PPCDatabase:
1282 def __init__(self, root, mdwndb, fieldsdb):
1283 # The code below groups the instructions by section:identifier.
1284 # We use the comment as an identifier, there's nothing better.
1285 # The point is to capture different opcodes for the same instruction.
1286 dd = _collections.defaultdict
1287 records = dd(lambda: dd(set))
1288 path = (root / "insndb.csv")
1289 with open(path, "r", encoding="UTF-8") as stream:
1290 for section in parse(stream, Section.CSV):
1291 path = (root / section.path)
1292 opcode_cls = {
1293 section.Mode.INTEGER: IntegerOpcode,
1294 section.Mode.PATTERN: PatternOpcode,
1295 }[section.mode]
1296 factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
1297 with open(path, "r", encoding="UTF-8") as stream:
1298 for insn in parse(stream, factory):
1299 records[section][insn.comment].add(insn)
1300
1301 db = dd(set)
1302 for (section, group) in records.items():
1303 for records in group.values():
1304 db[section].add(PPCMultiRecord(records))
1305
1306 self.__db = db
1307 self.__mdwndb = mdwndb
1308 self.__fieldsdb = fieldsdb
1309
1310 return super().__init__()
1311
1312 def __getitem__(self, key):
1313 def exact_match(key, record):
1314 for name in record.names:
1315 if name == key:
1316 return True
1317
1318 return False
1319
1320 def Rc_match(key, record):
1321 if not key.endswith("."):
1322 return False
1323
1324 if not record.Rc is _RCOE.RC:
1325 return False
1326
1327 return exact_match(key[:-1], record)
1328
1329 def LK_match(key, record):
1330 if not key.endswith("l"):
1331 return False
1332
1333 if "lk" not in record.flags:
1334 return False
1335
1336 return exact_match(key[:-1], record)
1337
1338 def AA_match(key, record):
1339 if not key.endswith("a"):
1340 return False
1341
1342 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1343 return False
1344
1345 if self.__mdwndb[key]["AA"] is None:
1346 return False
1347
1348 return (exact_match(key[:-1], record) or
1349 LK_match(key[:-1], record))
1350
1351 for (section, records) in self.__db.items():
1352 for record in records:
1353 if (exact_match(key, record) or
1354 Rc_match(key, record) or
1355 LK_match(key, record) or
1356 AA_match(key, record)):
1357 return (section, record)
1358
1359 return (None, None)
1360
1361
1362 class SVP64Database:
1363 def __init__(self, root, ppcdb):
1364 db = set()
1365 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1366 for (prefix, _, names) in _os.walk(root):
1367 prefix = _pathlib.Path(prefix)
1368 for name in filter(lambda name: pattern.match(name), names):
1369 path = (prefix / _pathlib.Path(name))
1370 with open(path, "r", encoding="UTF-8") as stream:
1371 db.update(parse(stream, SVP64Record.CSV))
1372
1373 self.__db = {record.name:record for record in db}
1374 self.__ppcdb = ppcdb
1375
1376 return super().__init__()
1377
1378 def __getitem__(self, key):
1379 (_, record) = self.__ppcdb[key]
1380 if record is None:
1381 return None
1382
1383 for name in record.names:
1384 record = self.__db.get(name, None)
1385 if record is not None:
1386 return record
1387
1388 return None
1389
1390
1391 class Database:
1392 def __init__(self, root):
1393 root = _pathlib.Path(root)
1394
1395 mdwndb = MarkdownDatabase()
1396 fieldsdb = FieldsDatabase()
1397 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb, fieldsdb=fieldsdb)
1398 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1399
1400 db = set()
1401 for (name, operands) in mdwndb:
1402 (section, ppc) = ppcdb[name]
1403 if ppc is None:
1404 continue
1405 svp64 = svp64db[name]
1406 fields = fieldsdb[ppc.form]
1407 record = Record(name=name,
1408 section=section, ppc=ppc, svp64=svp64,
1409 operands=operands, fields=fields)
1410 db.add(record)
1411
1412 self.__db = tuple(sorted(db))
1413
1414 return super().__init__()
1415
1416 def __repr__(self):
1417 return repr(self.__db)
1418
1419 def __iter__(self):
1420 yield from self.__db
1421
1422 @_functools.lru_cache(maxsize=None)
1423 def __contains__(self, key):
1424 return self.__getitem__(key) is not None
1425
1426 @_functools.lru_cache(maxsize=None)
1427 def __getitem__(self, key):
1428 if isinstance(key, (int, Instruction)):
1429 key = int(key)
1430 for record in self:
1431 opcode = record.opcode
1432 if ((opcode.value & opcode.mask) ==
1433 (key & opcode.mask)):
1434 return record
1435 return None
1436 elif isinstance(key, Opcode):
1437 for record in self:
1438 if record.opcode == key:
1439 return record
1440 elif isinstance(key, str):
1441 for record in self:
1442 if record.name == key:
1443 return record
1444 return None