use log function for warnings about .mdwn files in pagereader.py
[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(frozenset):
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 record(self, db):
774 record = db[self]
775 if record is None:
776 raise KeyError(self)
777 return record
778
779 def disassemble(self, db, byteorder="little", verbose=False):
780 raise NotImplementedError
781
782
783 class WordInstruction(Instruction):
784 _: _Field = range(0, 32)
785 po: _Field = range(0, 6)
786
787 @classmethod
788 def integer(cls, value, byteorder="little"):
789 return super().integer(bits=32, value=value, byteorder=byteorder)
790
791 @property
792 def binary(self):
793 bits = []
794 for idx in range(32):
795 bit = int(self[idx])
796 bits.append(bit)
797 return "".join(map(str, bits))
798
799 def spec(self, db):
800 record = self.record(db=db)
801
802 immediate = ""
803 dynamic_operands = []
804 for operand in record.operands.dynamic:
805 name = operand.name
806 if immediate:
807 name = f"{immediate}({name})"
808 immediate = ""
809 if isinstance(operand, ImmediateOperand):
810 immediate = operand.name
811 if not immediate:
812 dynamic_operands.append(name)
813
814 static_operands = []
815 for operand in record.operands.static:
816 static_operands.append(f"{operand.name}={operand.value}")
817
818 operands = ""
819 if dynamic_operands:
820 operands += f" {','.join(dynamic_operands)}"
821 if static_operands:
822 operands += f" ({' '.join(static_operands)})"
823
824 return f"{record.name}{operands}"
825
826 def opcode(self, db):
827 record = self.record(db=db)
828 return f"0x{record.opcode.value:08x}"
829
830 def mask(self, db):
831 record = self.record(db=db)
832 return f"0x{record.opcode.mask:08x}"
833
834 def disassemble(self, db, byteorder="little", verbose=False):
835 integer = int(self)
836 blob = integer.to_bytes(length=4, byteorder=byteorder)
837 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
838
839 record = self.record(db=db)
840 if record is None:
841 yield f"{blob} .long 0x{integer:08x}"
842 return
843
844 operands = []
845 for operand in record.operands.dynamic:
846 operand = " ".join(operand.disassemble(value=self,
847 record=record, verbose=False))
848 operands.append(operand)
849 if operands:
850 operands = ",".join(operands)
851 operands = f" {operands}"
852 else:
853 operands = ""
854
855 yield f"{blob} {record.name}{operands}"
856
857 if verbose:
858 indent = (" " * 4)
859 binary = self.binary
860 spec = self.spec(db=db)
861 opcode = self.opcode(db=db)
862 mask = self.mask(db=db)
863 yield f"{indent}spec"
864 yield f"{indent}{indent}{spec}"
865 yield f"{indent}binary"
866 yield f"{indent}{indent}[0:8] {binary[0:8]}"
867 yield f"{indent}{indent}[8:16] {binary[8:16]}"
868 yield f"{indent}{indent}[16:24] {binary[16:24]}"
869 yield f"{indent}{indent}[24:32] {binary[24:32]}"
870 yield f"{indent}opcode"
871 yield f"{indent}{indent}{opcode}"
872 yield f"{indent}mask"
873 yield f"{indent}{indent}{mask}"
874 for operand in record.operands:
875 name = operand.name
876 yield f"{indent}{name}"
877 parts = operand.disassemble(value=self,
878 record=record, verbose=True)
879 for part in parts:
880 yield f"{indent}{indent}{part}"
881 yield ""
882
883
884 class PrefixedInstruction(Instruction):
885 class Prefix(WordInstruction.remap(range(0, 32))):
886 pass
887
888 class Suffix(WordInstruction.remap(range(32, 64))):
889 pass
890
891 _: _Field = range(64)
892 prefix: Prefix
893 suffix: Suffix
894 po: Suffix.po
895
896 @classmethod
897 def integer(cls, value, byteorder="little"):
898 return super().integer(bits=64, value=value, byteorder=byteorder)
899
900 @classmethod
901 def pair(cls, prefix=0, suffix=0, byteorder="little"):
902 def transform(value):
903 return WordInstruction.integer(value=value,
904 byteorder=byteorder)[0:32]
905
906 (prefix, suffix) = map(transform, (prefix, suffix))
907 value = _selectconcat(prefix, suffix)
908
909 return super().integer(value=value)
910
911
912 class Mode(_Mapping):
913 _: _Field = range(0, 5)
914 sel: _Field = range(0, 2)
915
916
917 class NormalMode(Mode):
918 class simple(Mode):
919 """simple mode"""
920 dz: Mode[3]
921 sz: Mode[4]
922
923 class smr(Mode):
924 """scalar reduce mode (mapreduce), SUBVL=1"""
925 RG: Mode[4]
926
927 class pmr(Mode):
928 """parallel reduce mode (mapreduce), SUBVL=1"""
929 pass
930
931 class svmr(Mode):
932 """subvector reduce mode, SUBVL>1"""
933 SVM: Mode[3]
934
935 class pu(Mode):
936 """Pack/Unpack mode, SUBVL>1"""
937 SVM: Mode[3]
938
939 class ffrc1(Mode):
940 """Rc=1: ffirst CR sel"""
941 inv: Mode[2]
942 CRbit: Mode[3, 4]
943
944 class ffrc0(Mode):
945 """Rc=0: ffirst z/nonz"""
946 inv: Mode[2]
947 VLi: Mode[3]
948 RC1: Mode[4]
949
950 class sat(Mode):
951 """sat mode: N=0/1 u/s, SUBVL=1"""
952 N: Mode[2]
953 dz: Mode[3]
954 sz: Mode[4]
955
956 class satx(Mode):
957 """sat mode: N=0/1 u/s, SUBVL>1"""
958 N: Mode[2]
959 zz: Mode[3]
960 dz: Mode[3]
961 sz: Mode[3]
962
963 class satpu(Mode):
964 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
965 N: Mode[2]
966 zz: Mode[3]
967 dz: Mode[3]
968 sz: Mode[3]
969
970 class prrc1(Mode):
971 """Rc=1: pred-result CR sel"""
972 inv: Mode[2]
973 CRbit: Mode[3, 4]
974
975 class prrc0(Mode):
976 """Rc=0: pred-result z/nonz"""
977 inv: Mode[2]
978 zz: Mode[3]
979 RC1: Mode[4]
980 dz: Mode[3]
981 sz: Mode[3]
982
983 simple: simple
984 smr: smr
985 pmr: pmr
986 svmr: svmr
987 pu: pu
988 ffrc1: ffrc1
989 ffrc0: ffrc0
990 sat: sat
991 satx: satx
992 satpu: satpu
993 prrc1: prrc1
994 prrc0: prrc0
995
996
997 class LDSTImmMode(Mode):
998 class simple(Mode):
999 """simple mode"""
1000 zz: Mode[3]
1001 els: Mode[4]
1002 dz: Mode[3]
1003 sz: Mode[3]
1004
1005 class spu(Mode):
1006 """Structured Pack/Unpack"""
1007 zz: Mode[3]
1008 els: Mode[4]
1009 dz: Mode[3]
1010 sz: Mode[3]
1011
1012 class ffrc1(Mode):
1013 """Rc=1: ffirst CR sel"""
1014 inv: Mode[2]
1015 CRbit: Mode[3, 4]
1016
1017 class ffrc0(Mode):
1018 """Rc=0: ffirst z/nonz"""
1019 inv: Mode[2]
1020 els: Mode[3]
1021 RC1: Mode[4]
1022
1023 class sat(Mode):
1024 """sat mode: N=0/1 u/s"""
1025 N: Mode[2]
1026 zz: Mode[3]
1027 els: Mode[4]
1028 dz: Mode[3]
1029 sz: Mode[3]
1030
1031 class prrc1(Mode):
1032 """Rc=1: pred-result CR sel"""
1033 inv: Mode[2]
1034 CRbit: Mode[3, 4]
1035
1036 class prrc0(Mode):
1037 """Rc=0: pred-result z/nonz"""
1038 inv: Mode[2]
1039 els: Mode[3]
1040 RC1: Mode[4]
1041
1042 simple: simple
1043 spu: spu
1044 ffrc1: ffrc1
1045 ffrc0: ffrc0
1046 sat: sat
1047 prrc1: prrc1
1048 prrc0: prrc0
1049
1050
1051 class LDSTIdxMode(Mode):
1052 class simple(Mode):
1053 """simple mode"""
1054 SEA: Mode[2]
1055 sz: Mode[3]
1056 dz: Mode[3]
1057
1058 class stride(Mode):
1059 """strided (scalar only source)"""
1060 SEA: Mode[2]
1061 dz: Mode[3]
1062 sz: Mode[4]
1063
1064 class sat(Mode):
1065 """sat mode: N=0/1 u/s"""
1066 N: Mode[2]
1067 dz: Mode[3]
1068 sz: Mode[4]
1069
1070 class prrc1(Mode):
1071 """Rc=1: pred-result CR sel"""
1072 inv: Mode[2]
1073 CRbit: Mode[3, 4]
1074
1075 class prrc0(Mode):
1076 """Rc=0: pred-result z/nonz"""
1077 inv: Mode[2]
1078 zz: Mode[3]
1079 RC1: Mode[4]
1080 dz: Mode[3]
1081 sz: Mode[3]
1082
1083 simple: simple
1084 stride: stride
1085 sat: sat
1086 prrc1: prrc1
1087 prrc0: prrc0
1088
1089
1090 class RM(_Mapping):
1091 class Mode(Mode):
1092 normal: NormalMode
1093 ldst_imm: LDSTImmMode
1094 ldst_idx: LDSTIdxMode
1095
1096 _: _Field = range(24)
1097 mmode: _Field = (0,)
1098 mask: _Field = range(1, 4)
1099 elwidth: _Field = range(4, 6)
1100 ewsrc: _Field = range(6, 8)
1101 subvl: _Field = range(8, 10)
1102 extra: _Field = range(10, 19)
1103 mode: Mode.remap(range(19, 24))
1104 extra2: _Array[4] = (
1105 range(10, 12),
1106 range(12, 14),
1107 range(14, 16),
1108 range(16, 18),
1109 )
1110 smask: _Field = range(16, 19)
1111 extra3: _Array[3] = (
1112 range(10, 13),
1113 range(13, 16),
1114 range(16, 19),
1115 )
1116
1117
1118 class SVP64Instruction(PrefixedInstruction):
1119 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1120 class Prefix(PrefixedInstruction.Prefix):
1121 id: _Field = (7, 9)
1122 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1123
1124 prefix: Prefix
1125
1126 @property
1127 def binary(self):
1128 bits = []
1129 for idx in range(64):
1130 bit = int(self[idx])
1131 bits.append(bit)
1132 return "".join(map(str, bits))
1133
1134 def spec(self, db):
1135 return f"sv.{self.suffix.spec(db=db)}"
1136
1137 def opcode(self, db):
1138 return self.suffix.opcode(db=db)
1139
1140 def mask(self, db):
1141 return self.suffix.mask(db=db)
1142
1143 def mode(self, db):
1144 record = self.record(db=db)
1145
1146 Rc = False
1147 if record.operands["Rc"] is not None:
1148 Rc = bool(self[record.fields["Rc"]])
1149
1150 record = self.record(db=db)
1151 subvl = self.prefix.rm.subvl
1152 mode = self.prefix.rm.mode
1153 sel = mode.sel
1154
1155 if record.svp64.mode is _SVMode.NORMAL:
1156 mode = mode.normal
1157 if sel == 0b00:
1158 if mode[2] == 0b0:
1159 mode = mode.simple
1160 else:
1161 if subvl == 0b00:
1162 if mode[3] == 0b0:
1163 mode = mode.smr
1164 else:
1165 mode = mode.pmr
1166 else:
1167 if mode[4] == 0b0:
1168 mode = mode.svmr
1169 else:
1170 mode = mode.pu
1171 elif sel == 0b01:
1172 if Rc:
1173 mode = mode.ffrc1
1174 else:
1175 mode = mode.ffrc0
1176 elif sel == 0b10:
1177 if subvl == 0b00:
1178 mode = mode.sat
1179 else:
1180 if mode[4]:
1181 mode = mode.satx
1182 else:
1183 mode = mode.satpu
1184 elif sel == 0b11:
1185 if Rc:
1186 mode = mode.prrc1
1187 else:
1188 mode = mode.prrc0
1189 elif record.svp64.mode is _SVMode.LDST_IMM:
1190 mode = mode.ldst_imm
1191 if sel == 0b00:
1192 if mode[2] == 0b0:
1193 mode = mode.simple
1194 else:
1195 mode = mode.spu
1196 elif sel == 0b01:
1197 if Rc:
1198 mode = mode.ffrc1
1199 else:
1200 mode = mode.ffrc0
1201 elif sel == 0b10:
1202 mode = mode.sat
1203 elif sel == 0b11:
1204 if Rc:
1205 mode = mode.prrc1
1206 else:
1207 mode = mode.prrc0
1208 elif record.svp64.mode is _SVMode.LDST_IMM:
1209 mode = mode.ldst_idx
1210 if mode.sel == 0b00:
1211 mode = mode.simple
1212 elif mode.sel == 0b01:
1213 mode = mode.stride
1214 elif mode.sel == 0b10:
1215 mode = mode.sat
1216 elif mode.sel == 0b11:
1217 if Rc:
1218 mode = mode.prrc1
1219 else:
1220 mode = mode.prrc0
1221
1222 modes = {
1223 NormalMode.simple: "normal: simple",
1224 NormalMode.smr: "normal: smr",
1225 NormalMode.pmr: "normal: pmr",
1226 NormalMode.svmr: "normal: svmr",
1227 NormalMode.pu: "normal: pu",
1228 NormalMode.ffrc1: "normal: ffrc1",
1229 NormalMode.ffrc0: "normal: ffrc0",
1230 NormalMode.sat: "normal: sat",
1231 NormalMode.satx: "normal: satx",
1232 NormalMode.satpu: "normal: satpu",
1233 NormalMode.prrc1: "normal: prrc1",
1234 NormalMode.prrc0: "normal: prrc0",
1235 LDSTImmMode.simple: "ld/st imm: simple",
1236 LDSTImmMode.spu: "ld/st imm: spu",
1237 LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
1238 LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
1239 LDSTImmMode.sat: "ld/st imm: sat",
1240 LDSTImmMode.prrc1: "ld/st imm: prrc1",
1241 LDSTImmMode.prrc0: "ld/st imm: prrc0",
1242 LDSTIdxMode.simple: "ld/st idx simple",
1243 LDSTIdxMode.stride: "ld/st idx stride",
1244 LDSTIdxMode.sat: "ld/st idx sat",
1245 LDSTIdxMode.prrc1: "ld/st idx prrc1",
1246 LDSTIdxMode.prrc0: "ld/st idx prrc0",
1247 }
1248 for (cls, desc) in modes.items():
1249 if isinstance(mode, cls):
1250 return (mode, desc)
1251
1252 raise NotImplementedError
1253
1254 def disassemble(self, db, byteorder="little", verbose=False):
1255 integer_prefix = int(self.prefix)
1256 blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
1257 blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
1258
1259 integer_suffix = int(self.suffix)
1260 blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
1261 blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
1262
1263 record = self.record(db=db)
1264 if record is None or record.svp64 is None:
1265 yield f"{blob_prefix} .long 0x{int(self.prefix):08x}"
1266 yield f"{blob_suffix} .long 0x{int(self.suffix):08x}"
1267 return
1268
1269 yield f"{blob_prefix} sv.{record.name}"
1270 yield f"{blob_suffix}"
1271
1272 (mode, mode_desc) = self.mode(db=db)
1273
1274 if verbose:
1275 indent = (" " * 4)
1276 binary = self.binary
1277 spec = self.spec(db=db)
1278 opcode = self.opcode(db=db)
1279 mask = self.mask(db=db)
1280 yield f"{indent}spec"
1281 yield f"{indent}{indent}{spec}"
1282 yield f"{indent}binary"
1283 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1284 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1285 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1286 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1287 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1288 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1289 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1290 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1291 yield f"{indent}opcode"
1292 yield f"{indent}{indent}{opcode}"
1293 yield f"{indent}mask"
1294 yield f"{indent}{indent}{mask}"
1295 for operand in record.operands:
1296 name = operand.name
1297 yield f"{indent}{name}"
1298 parts = operand.disassemble(value=self,
1299 record=record, verbose=True)
1300 for part in parts:
1301 yield f"{indent}{indent}{part}"
1302
1303 yield f"{indent}mode"
1304 yield f"{indent}{indent}{mode_desc}"
1305 yield ""
1306
1307
1308 def parse(stream, factory):
1309 def match(entry):
1310 return ("TODO" not in frozenset(entry.values()))
1311
1312 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1313 entries = _csv.DictReader(lines)
1314 entries = filter(match, entries)
1315 return tuple(map(factory, entries))
1316
1317
1318 class MarkdownDatabase:
1319 def __init__(self):
1320 db = {}
1321 for (name, desc) in _ISA():
1322 operands = []
1323 if desc.regs:
1324 (dynamic, *static) = desc.regs
1325 operands.extend(dynamic)
1326 operands.extend(static)
1327 db[name] = Operands(insn=name, iterable=operands)
1328 self.__db = db
1329 return super().__init__()
1330
1331 def __iter__(self):
1332 yield from self.__db.items()
1333
1334 def __getitem__(self, key):
1335 return self.__db.__getitem__(key)
1336
1337
1338 class FieldsDatabase:
1339 def __init__(self):
1340 db = {}
1341 df = _DecodeFields()
1342 df.create_specs()
1343 for (form, fields) in df.instrs.items():
1344 if form in {"DQE", "TX"}:
1345 continue
1346 if form == "all":
1347 form = "NONE"
1348 db[_Form[form]] = Fields(fields)
1349
1350 self.__db = db
1351
1352 return super().__init__()
1353
1354 def __getitem__(self, key):
1355 return self.__db.__getitem__(key)
1356
1357
1358 class PPCDatabase:
1359 def __init__(self, root, mdwndb):
1360 # The code below groups the instructions by section:identifier.
1361 # We use the comment as an identifier, there's nothing better.
1362 # The point is to capture different opcodes for the same instruction.
1363 dd = _collections.defaultdict
1364 records = dd(lambda: dd(set))
1365 path = (root / "insndb.csv")
1366 with open(path, "r", encoding="UTF-8") as stream:
1367 for section in parse(stream, Section.CSV):
1368 path = (root / section.path)
1369 opcode_cls = {
1370 section.Mode.INTEGER: IntegerOpcode,
1371 section.Mode.PATTERN: PatternOpcode,
1372 }[section.mode]
1373 factory = _functools.partial(
1374 PPCRecord.CSV, opcode_cls=opcode_cls)
1375 with open(path, "r", encoding="UTF-8") as stream:
1376 for insn in parse(stream, factory):
1377 records[section][insn.comment].add(insn)
1378
1379 db = dd(set)
1380 for (section, group) in records.items():
1381 for records in group.values():
1382 db[section].add(PPCMultiRecord(records))
1383
1384 self.__db = db
1385 self.__mdwndb = mdwndb
1386
1387 return super().__init__()
1388
1389 def __getitem__(self, key):
1390 def exact_match(key, record):
1391 for name in record.names:
1392 if name == key:
1393 return True
1394
1395 return False
1396
1397 def Rc_match(key, record):
1398 if not key.endswith("."):
1399 return False
1400
1401 if not record.Rc is _RCOE.RC:
1402 return False
1403
1404 return exact_match(key[:-1], record)
1405
1406 def LK_match(key, record):
1407 if not key.endswith("l"):
1408 return False
1409
1410 if "lk" not in record.flags:
1411 return False
1412
1413 return exact_match(key[:-1], record)
1414
1415 def AA_match(key, record):
1416 if not key.endswith("a"):
1417 return False
1418
1419 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1420 return False
1421
1422 if self.__mdwndb[key]["AA"] is None:
1423 return False
1424
1425 return (exact_match(key[:-1], record) or
1426 LK_match(key[:-1], record))
1427
1428 for (section, records) in self.__db.items():
1429 for record in records:
1430 if exact_match(key, record):
1431 return (section, record)
1432
1433 for record in records:
1434 if (Rc_match(key, record) or
1435 LK_match(key, record) or
1436 AA_match(key, record)):
1437 return (section, record)
1438
1439 return (None, None)
1440
1441
1442 class SVP64Database:
1443 def __init__(self, root, ppcdb):
1444 db = set()
1445 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1446 for (prefix, _, names) in _os.walk(root):
1447 prefix = _pathlib.Path(prefix)
1448 for name in filter(lambda name: pattern.match(name), names):
1449 path = (prefix / _pathlib.Path(name))
1450 with open(path, "r", encoding="UTF-8") as stream:
1451 db.update(parse(stream, SVP64Record.CSV))
1452
1453 self.__db = {record.name:record for record in db}
1454 self.__ppcdb = ppcdb
1455
1456 return super().__init__()
1457
1458 def __getitem__(self, key):
1459 (_, record) = self.__ppcdb[key]
1460 if record is None:
1461 return None
1462
1463 for name in record.names:
1464 record = self.__db.get(name, None)
1465 if record is not None:
1466 return record
1467
1468 return None
1469
1470
1471 class Database:
1472 def __init__(self, root):
1473 root = _pathlib.Path(root)
1474
1475 mdwndb = MarkdownDatabase()
1476 fieldsdb = FieldsDatabase()
1477 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
1478 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1479
1480 db = set()
1481 for (name, operands) in mdwndb:
1482 (section, ppc) = ppcdb[name]
1483 if ppc is None:
1484 continue
1485 svp64 = svp64db[name]
1486 fields = fieldsdb[ppc.form]
1487 record = Record(name=name,
1488 section=section, ppc=ppc, svp64=svp64,
1489 operands=operands, fields=fields)
1490 db.add(record)
1491
1492 self.__db = tuple(sorted(db))
1493
1494 return super().__init__()
1495
1496 def __repr__(self):
1497 return repr(self.__db)
1498
1499 def __iter__(self):
1500 yield from self.__db
1501
1502 @_functools.lru_cache(maxsize=None)
1503 def __contains__(self, key):
1504 return self.__getitem__(key) is not None
1505
1506 @_functools.lru_cache(maxsize=None)
1507 def __getitem__(self, key):
1508 if isinstance(key, (int, Instruction)):
1509 key = int(key)
1510 for record in self:
1511 opcode = record.opcode
1512 if ((opcode.value & opcode.mask) ==
1513 (key & opcode.mask)):
1514 return record
1515 return None
1516 elif isinstance(key, Opcode):
1517 for record in self:
1518 if record.opcode == key:
1519 return record
1520 elif isinstance(key, str):
1521 for record in self:
1522 if record.name == key:
1523 return record
1524 return None