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