power_insn: support LD/ST immediate mode
[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 "CONDITIONS": "conditions",
216 }
217
218 @classmethod
219 def CSV(cls, record, opcode_cls=Opcode):
220 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
221 typemap["opcode"] = opcode_cls
222
223 flags = set()
224 for flag in frozenset(PPCRecord.Flags):
225 if bool(record.pop(flag, "")):
226 flags.add(flag)
227 record["flags"] = PPCRecord.Flags(flags)
228
229 return dataclass(cls, record, keymap=PPCRecord.__KEYMAP, typemap=typemap)
230
231 @cached_property
232 def names(self):
233 return frozenset(self.comment.split("=")[-1].split("/"))
234
235
236 @_dataclasses.dataclass(eq=True, frozen=True)
237 class SVP64Record:
238 class ExtraMap(tuple):
239 class Extra(tuple):
240 @_dataclasses.dataclass(eq=True, frozen=True)
241 class Entry:
242 regtype: _SVExtraRegType = _SVExtraRegType.NONE
243 reg: _SVExtraReg = _SVExtraReg.NONE
244
245 def __repr__(self):
246 return f"{self.regtype.value}:{self.reg.name}"
247
248 def __new__(cls, value="0"):
249 if isinstance(value, str):
250 def transform(value):
251 (regtype, reg) = value.split(":")
252 regtype = _SVExtraRegType(regtype)
253 reg = _SVExtraReg(reg)
254 return cls.Entry(regtype=regtype, reg=reg)
255
256 if value == "0":
257 value = tuple()
258 else:
259 value = map(transform, value.split(";"))
260
261 return super().__new__(cls, value)
262
263 def __repr__(self):
264 return repr(list(self))
265
266 def __new__(cls, value=tuple()):
267 value = tuple(value)
268 if len(value) == 0:
269 value = (("0",) * 4)
270 return super().__new__(cls, map(cls.Extra, value))
271
272 def __repr__(self):
273 return repr({index:self[index] for index in range(0, 4)})
274
275 name: str
276 ptype: _SVPtype = _SVPtype.NONE
277 etype: _SVEtype = _SVEtype.NONE
278 in1: _In1Sel = _In1Sel.NONE
279 in2: _In2Sel = _In2Sel.NONE
280 in3: _In3Sel = _In3Sel.NONE
281 out: _OutSel = _OutSel.NONE
282 out2: _OutSel = _OutSel.NONE
283 cr_in: _CRInSel = _CRInSel.NONE
284 cr_out: _CROutSel = _CROutSel.NONE
285 extra: ExtraMap = ExtraMap()
286 pu: bool = False
287 conditions: str = ""
288 mode: _SVMode = _SVMode.NORMAL
289
290 __KEYMAP = {
291 "insn": "name",
292 "CONDITIONS": "conditions",
293 "Ptype": "ptype",
294 "Etype": "etype",
295 "CR in": "cr_in",
296 "CR out": "cr_out",
297 "PU": "pu",
298 }
299
300 @classmethod
301 def CSV(cls, record):
302 for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
303 value = record[key]
304 if value == "0":
305 record[key] = "NONE"
306
307 record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
308
309 return dataclass(cls, record, keymap=cls.__KEYMAP)
310
311
312 class BitSel:
313 def __init__(self, value=(0, 32)):
314 if isinstance(value, str):
315 (start, end) = map(int, value.split(":"))
316 else:
317 (start, end) = value
318 if start < 0 or end < 0 or start >= end:
319 raise ValueError(value)
320
321 self.__start = start
322 self.__end = end
323
324 return super().__init__()
325
326 def __repr__(self):
327 return f"[{self.__start}:{self.__end}]"
328
329 def __iter__(self):
330 yield from range(self.start, (self.end + 1))
331
332 @property
333 def start(self):
334 return self.__start
335
336 @property
337 def end(self):
338 return self.__end
339
340
341 @_dataclasses.dataclass(eq=True, frozen=True)
342 class Section:
343 class Mode(_enum.Enum):
344 INTEGER = _enum.auto()
345 PATTERN = _enum.auto()
346
347 @classmethod
348 def _missing_(cls, value):
349 if isinstance(value, str):
350 return cls[value.upper()]
351 return super()._missing_(value)
352
353 class Suffix(int):
354 def __new__(cls, value=None):
355 if isinstance(value, str):
356 if value.upper() == "NONE":
357 value = None
358 else:
359 value = int(value, 0)
360 if value is None:
361 value = 0
362
363 return super().__new__(cls, value)
364
365 def __str__(self):
366 return repr(self)
367
368 def __repr__(self):
369 return (bin(self) if self else "None")
370
371 path: _pathlib.Path
372 opcode: Opcode
373 bitsel: BitSel
374 suffix: Suffix
375 mode: Mode
376
377 @classmethod
378 def CSV(cls, record):
379 return dataclass(cls, record)
380
381
382 class Fields:
383 def __init__(self, items):
384 if isinstance(items, dict):
385 items = items.items()
386
387 def transform(item):
388 (name, bitrange) = item
389 return (name, tuple(bitrange.values()))
390
391 self.__mapping = dict(map(transform, items))
392
393 return super().__init__()
394
395 def __repr__(self):
396 return repr(self.__mapping)
397
398 def __iter__(self):
399 yield from self.__mapping.items()
400
401 def __contains__(self, key):
402 return self.__mapping.__contains__(key)
403
404 def __getitem__(self, key):
405 return self.__mapping.get(key, None)
406
407
408 class Operands:
409 @_dataclasses.dataclass(eq=True, frozen=True)
410 class Operand:
411 name: str
412
413 def disassemble(self, value, record):
414 raise NotImplementedError
415
416 @_dataclasses.dataclass(eq=True, frozen=True)
417 class DynamicOperand(Operand):
418 def disassemble(self, value, record):
419 return str(int(value[record.fields[self.name]]))
420
421 @_dataclasses.dataclass(eq=True, frozen=True)
422 class StaticOperand(Operand):
423 value: int = None
424
425 @_dataclasses.dataclass(eq=True, frozen=True)
426 class DynamicOperandIFormLI(DynamicOperand):
427 def disassemble(self, value, record):
428 return hex(int(_selectconcat(
429 value[record.fields["LI"]],
430 _SelectableInt(value=0b00, bits=2))))
431
432 class DynamicOperandBFormBD(DynamicOperand):
433 def disassemble(self, value, record):
434 return hex(int(_selectconcat(
435 value[record.fields["BD"]],
436 _SelectableInt(value=0b00, bits=2))))
437
438 @_dataclasses.dataclass(eq=True, frozen=True)
439 class DynamicOperandGPR(DynamicOperand):
440 def disassemble(self, value, record):
441 return f"r{super().disassemble(value=value, record=record)}"
442
443 @_dataclasses.dataclass(eq=True, frozen=True)
444 class DynamicOperandFPR(DynamicOperand):
445 def disassemble(self, value, record):
446 return f"f{super().disassemble(value=value, record=record)}"
447
448 def __init__(self, insn, iterable):
449 branches = {
450 "b": {"LI": self.__class__.DynamicOperandIFormLI},
451 "ba": {"LI": self.__class__.DynamicOperandIFormLI},
452 "bl": {"LI": self.__class__.DynamicOperandIFormLI},
453 "bla": {"LI": self.__class__.DynamicOperandIFormLI},
454 "bc": {"BD": self.__class__.DynamicOperandBFormBD},
455 "bca": {"BD": self.__class__.DynamicOperandBFormBD},
456 "bcl": {"BD": self.__class__.DynamicOperandBFormBD},
457 "bcla": {"BD": self.__class__.DynamicOperandBFormBD},
458 }
459
460 operands = []
461 for operand in iterable:
462 dynamic_cls = self.__class__.DynamicOperand
463 static_cls = self.__class__.StaticOperand
464
465 if "=" in operand:
466 (name, value) = operand.split("=")
467 operand = static_cls(name=name, value=int(value))
468 else:
469 if insn in branches and operand in branches[insn]:
470 dynamic_cls = branches[insn][operand]
471
472 if operand in _RegType.__members__:
473 regtype = _RegType[operand]
474 if regtype is _RegType.GPR:
475 dynamic_cls = self.__class__.DynamicOperandGPR
476 elif regtype is _RegType.FPR:
477 dynamic_cls = self.__class__.DynamicOperandFPR
478
479 operand = dynamic_cls(name=operand)
480
481 operands.append(operand)
482
483 self.__operands = operands
484
485 return super().__init__()
486
487 def __repr__(self):
488 return self.__operands.__repr__()
489
490 def __iter__(self):
491 yield from self.__operands
492
493 def __getitem__(self, key):
494 for operand in self.__operands:
495 if operand.name == key:
496 return operand
497
498 return None
499
500 @property
501 def dynamic(self):
502 for operand in self:
503 if isinstance(operand, self.__class__.DynamicOperand):
504 yield operand
505
506 @property
507 def static(self):
508 for operand in self:
509 if isinstance(operand, self.__class__.StaticOperand):
510 yield operand
511
512
513 @_functools.total_ordering
514 @_dataclasses.dataclass(eq=True, frozen=True)
515 class Record:
516 name: str
517 section: Section
518 ppc: PPCRecord
519 fields: Fields
520 operands: Operands
521 svp64: SVP64Record = None
522
523 __EXTRA = (
524 _SVExtra.Idx0,
525 _SVExtra.Idx1,
526 _SVExtra.Idx2,
527 _SVExtra.Idx3,
528 )
529
530 def __lt__(self, other):
531 if not isinstance(other, Record):
532 return NotImplemented
533 return (self.opcode < other.opcode)
534
535 @cached_property
536 def opcode(self):
537 fields = []
538 if self.section.opcode:
539 fields += [(self.section.opcode.value, BitSel((0, 5)))]
540 fields += [(self.ppc.opcode.value, self.section.bitsel)]
541 else:
542 fields += [(self.ppc.opcode.value, self.section.bitsel)]
543
544 for operand in self.operands.static:
545 fields += [(operand.value, self.fields[operand.name])]
546
547 return FieldsOpcode(fields)
548
549 @property
550 def function(self):
551 return self.ppc.function
552
553 @property
554 def in1(self):
555 return self.ppc.in1
556
557 @property
558 def in2(self):
559 return self.ppc.in2
560
561 @property
562 def in3(self):
563 return self.ppc.in3
564
565 @property
566 def out(self):
567 return self.ppc.out
568
569 @property
570 def out2(self):
571 if self.svp64 is None:
572 return _OutSel.NONE
573 return self.ppc.out
574
575 @property
576 def cr_in(self):
577 return self.ppc.cr_in
578
579 @property
580 def cr_out(self):
581 return self.ppc.cr_out
582
583 def sv_extra(self, key):
584 if key not in frozenset({
585 "in1", "in2", "in3", "cr_in",
586 "out", "out2", "cr_out",
587 }):
588 raise KeyError(key)
589
590 sel = getattr(self.svp64, key)
591 if sel is _CRInSel.BA_BB:
592 return _SVExtra.Idx_1_2
593 reg = _SVExtraReg(sel)
594 if reg is _SVExtraReg.NONE:
595 return _SVExtra.NONE
596
597 extra_map = {
598 _SVExtraRegType.SRC: {},
599 _SVExtraRegType.DST: {},
600 }
601 for index in range(0, 4):
602 for entry in self.svp64.extra[index]:
603 extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
604
605 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
606 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
607 if extra is not _SVExtra.NONE:
608 return extra
609
610 return _SVExtra.NONE
611
612 sv_in1 = property(_functools.partial(sv_extra, key="in1"))
613 sv_in2 = property(_functools.partial(sv_extra, key="in2"))
614 sv_in3 = property(_functools.partial(sv_extra, key="in3"))
615 sv_out = property(_functools.partial(sv_extra, key="out"))
616 sv_out2 = property(_functools.partial(sv_extra, key="out2"))
617 sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
618 sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
619
620 @property
621 def sv_ptype(self):
622 if self.svp64 is None:
623 return _SVPtype.NONE
624 return self.svp64.ptype
625
626 @property
627 def sv_etype(self):
628 if self.svp64 is None:
629 return _SVEtype.NONE
630 return self.svp64.etype
631
632
633 class Instruction(_Mapping):
634 @classmethod
635 def integer(cls, value=0, bits=None, byteorder="little"):
636 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
637 raise ValueError(bits)
638
639 if isinstance(value, bytes):
640 if ((len(value) * 8) != bits):
641 raise ValueError(f"bit length mismatch")
642 value = int.from_bytes(value, byteorder=byteorder)
643
644 if isinstance(value, int):
645 value = _SelectableInt(value=value, bits=bits)
646 elif isinstance(value, Instruction):
647 value = value.storage
648
649 if not isinstance(value, _SelectableInt):
650 raise ValueError(value)
651 if bits is None:
652 bits = len(cls)
653 if len(value) != bits:
654 raise ValueError(value)
655
656 value = _SelectableInt(value=value, bits=bits)
657
658 return cls(storage=value)
659
660 def __hash__(self):
661 return hash(int(self))
662
663 def disassemble(self, db, byteorder="little"):
664 raise NotImplementedError
665
666
667 class WordInstruction(Instruction):
668 _: _Field = range(0, 32)
669 po: _Field = range(0, 6)
670
671 @classmethod
672 def integer(cls, value, byteorder="little"):
673 return super().integer(bits=32, value=value, byteorder=byteorder)
674
675 def disassemble(self, db, byteorder="little"):
676 integer = int(self)
677 blob = integer.to_bytes(length=4, byteorder=byteorder)
678 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
679
680 record = db[self]
681 if record is None:
682 yield f"{blob} .long 0x{integer:08x}"
683 else:
684 operands = []
685 for operand in record.operands.dynamic:
686 operand = operand.disassemble(self, record)
687 operands.append(operand)
688 if operands:
689 operands = ",".join(operands)
690 operands = f" {operands}"
691 else:
692 operands = ""
693 yield f"{blob} {record.name}{operands}"
694
695 class PrefixedInstruction(Instruction):
696 class Prefix(WordInstruction.remap(range(0, 32))):
697 pass
698
699 class Suffix(WordInstruction.remap(range(32, 64))):
700 pass
701
702 _: _Field = range(64)
703 prefix: Prefix
704 suffix: Suffix
705 po: Suffix.po
706
707 @classmethod
708 def integer(cls, value, byteorder="little"):
709 return super().integer(bits=64, value=value, byteorder=byteorder)
710
711 @classmethod
712 def pair(cls, prefix=0, suffix=0, byteorder="little"):
713 def transform(value):
714 return WordInstruction.integer(value=value,
715 byteorder=byteorder)[0:32]
716
717 (prefix, suffix) = map(transform, (prefix, suffix))
718 value = _selectconcat(prefix, suffix)
719
720 return super().integer(value=value)
721
722
723 class Mode(_Mapping):
724 _: _Field = range(0, 5)
725
726
727 class RM(_Mapping):
728 class Mode(Mode):
729 class ldst(Mode):
730 class imm(Mode):
731 class normal(Mode):
732 """normal mode"""
733 _: _Field = range(0, 5)
734 zz: _Field = (3,)
735 els: _Field = (4,)
736 dz: _Field = (3,)
737 sz: _Field = (3,)
738
739 class spu(Mode):
740 """Structured Pack/Unpack"""
741 _: _Field = range(0, 5)
742 zz: _Field = (3,)
743 els: _Field = (4,)
744 dz: _Field = (3,)
745 sz: _Field = (3,)
746
747 class ffrc1(Mode):
748 """Rc=1: ffirst CR sel"""
749 _: _Field = range(0, 5)
750 inv: _Field = (2,)
751 CRbit: _Field = (3, 4)
752
753 class ffrc0(Mode):
754 """Rc=0: ffirst z/nonz"""
755 _: _Field = range(0, 5)
756 inv: _Field = (2,)
757 els: _Field = (3,)
758 RC1: _Field = (4,)
759
760 class sat(Mode):
761 """sat mode: N=0/1 u/s"""
762 _: _Field = range(0, 5)
763 N: _Field = (2,)
764 zz: _Field = (3,)
765 els: _Field = (4,)
766 dz: _Field = (3,)
767 sz: _Field = (3,)
768
769
770 class prrc1(Mode):
771 """Rc=1: pred-result CR sel"""
772 _: _Field = range(0, 5)
773 inv: _Field = (2,)
774 CRbit: _Field = (3, 4)
775
776 class prrc0(Mode):
777 """Rc=0: pred-result z/nonz"""
778 _: _Field = range(0, 5)
779 inv: _Field = (2,)
780 els: _Field = (3,)
781 RC1: _Field = (4,)
782
783 normal: normal
784 spu: spu
785 ffrc1: ffrc1
786 ffrc0: ffrc0
787 sat: sat
788 prrc1: prrc1
789 prrc0: prrc0
790
791 imm: imm
792
793 ldst: ldst
794
795 _: _Field = range(24)
796 mmode: _Field = (0,)
797 mask: _Field = range(1, 4)
798 elwidth: _Field = range(4, 6)
799 ewsrc: _Field = range(6, 8)
800 subvl: _Field = range(8, 10)
801 extra: _Field = range(10, 19)
802 mode: Mode.remap(range(19, 24))
803 extra2: _Array[4] = (
804 range(10, 12),
805 range(12, 14),
806 range(14, 16),
807 range(16, 18),
808 )
809 smask: _Field = range(16, 19)
810 extra3: _Array[3] = (
811 range(10, 13),
812 range(13, 16),
813 range(16, 19),
814 )
815
816
817 class SVP64Instruction(PrefixedInstruction):
818 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
819 class Prefix(PrefixedInstruction.Prefix):
820 id: _Field = (7, 9)
821 rm: RM.remap((6, 8) + tuple(range(10, 32)))
822
823 prefix: Prefix
824
825 def disassemble(self, db, byteorder="little"):
826 integer_prefix = int(self.prefix)
827 blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
828 blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
829
830 integer_suffix = int(self.suffix)
831 blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
832 blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
833
834 record = db[self.suffix]
835 if record is None or record.svp64 is None:
836 yield f"{blob_prefix} .long 0x{int(self.prefix):08x}"
837 yield f"{blob_suffix} .long 0x{int(self.suffix):08x}"
838 else:
839 yield f"{blob_prefix} sv.{record.name}"
840 yield f"{blob_suffix}"
841
842
843 def parse(stream, factory):
844 lines = filter(lambda line: not line.strip().startswith("#"), stream)
845 entries = _csv.DictReader(lines)
846 entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
847 return tuple(map(factory, entries))
848
849
850 class MarkdownDatabase:
851 def __init__(self):
852 db = {}
853 for (name, desc) in _ISA():
854 operands = []
855 if desc.regs:
856 (dynamic, *static) = desc.regs
857 operands.extend(dynamic)
858 operands.extend(static)
859 db[name] = Operands(insn=name, iterable=operands)
860 self.__db = db
861 return super().__init__()
862
863 def __iter__(self):
864 yield from self.__db.items()
865
866 def __getitem__(self, key):
867 return self.__db.__getitem__(key)
868
869
870 class FieldsDatabase:
871 def __init__(self):
872 db = {}
873 df = _DecodeFields()
874 df.create_specs()
875 for (form, fields) in df.instrs.items():
876 if form in {"DQE", "TX"}:
877 continue
878 if form == "all":
879 form = "NONE"
880 db[_Form[form]] = Fields(fields)
881
882 self.__db = db
883
884 return super().__init__()
885
886 def __getitem__(self, key):
887 return self.__db.__getitem__(key)
888
889
890 class PPCDatabase:
891 def __init__(self, root, mdwndb, fieldsdb):
892 # The code below groups the instructions by section:identifier.
893 # We use the comment as an identifier, there's nothing better.
894 # The point is to capture different opcodes for the same instruction.
895 dd = _collections.defaultdict
896 records = dd(lambda: dd(set))
897 path = (root / "insndb.csv")
898 with open(path, "r", encoding="UTF-8") as stream:
899 for section in parse(stream, Section.CSV):
900 path = (root / section.path)
901 opcode_cls = {
902 section.Mode.INTEGER: IntegerOpcode,
903 section.Mode.PATTERN: PatternOpcode,
904 }[section.mode]
905 factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
906 with open(path, "r", encoding="UTF-8") as stream:
907 for insn in parse(stream, factory):
908 records[section][insn.comment].add(insn)
909
910 # Once we collected all instructions with the same identifier,
911 # it's time to merge the different opcodes into the single pattern.
912 # At this point, we only consider masks; the algorithm as follows:
913 # 1. If any of two masks ignores the bit, it's ignored entirely.
914 # 2. If the bit is not equal between masks, it's ignored.
915 # 3. Otherwise the bits are equal and considered.
916 def merge(lhs, rhs):
917 value = 0
918 mask = 0
919 lvalue = lhs.opcode.value
920 rvalue = rhs.opcode.value
921 lmask = lhs.opcode.mask
922 rmask = rhs.opcode.mask
923 bits = max(lmask.bit_length(), rmask.bit_length())
924 for bit in range(bits):
925 lvstate = ((lvalue & (1 << bit)) != 0)
926 rvstate = ((rvalue & (1 << bit)) != 0)
927 lmstate = ((lmask & (1 << bit)) != 0)
928 rmstate = ((rmask & (1 << bit)) != 0)
929 vstate = lvstate
930 mstate = True
931 if (not lmstate or not rmstate) or (lvstate != rvstate):
932 vstate = 0
933 mstate = 0
934 value |= (vstate << bit)
935 mask |= (mstate << bit)
936 return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
937
938 db = dd(set)
939 for (section, group) in records.items():
940 for records in group.values():
941 db[section].add(_functools.reduce(merge, records))
942
943 self.__db = db
944 self.__mdwndb = mdwndb
945 self.__fieldsdb = fieldsdb
946
947 return super().__init__()
948
949 def __getitem__(self, key):
950 def exact_match(key, record):
951 for name in record.names:
952 if name == key:
953 return True
954
955 return False
956
957 def Rc_match(key, record):
958 if not key.endswith("."):
959 return False
960
961 if not record.rc is _RCOE.RC:
962 return False
963
964 return exact_match(key[:-1], record)
965
966 def LK_match(key, record):
967 if not key.endswith("l"):
968 return False
969
970 if "lk" not in record.flags:
971 return False
972
973 return exact_match(key[:-1], record)
974
975 def AA_match(key, record):
976 if not key.endswith("a"):
977 return False
978
979 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
980 return False
981
982 if self.__mdwndb[key]["AA"] is None:
983 return False
984
985 return (exact_match(key[:-1], record) or
986 LK_match(key[:-1], record))
987
988 for (section, records) in self.__db.items():
989 for record in records:
990 if (exact_match(key, record) or
991 Rc_match(key, record) or
992 LK_match(key, record) or
993 AA_match(key, record)):
994 return (section, record)
995
996 return (None, None)
997
998
999 class SVP64Database:
1000 def __init__(self, root, ppcdb):
1001 db = set()
1002 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1003 for (prefix, _, names) in _os.walk(root):
1004 prefix = _pathlib.Path(prefix)
1005 for name in filter(lambda name: pattern.match(name), names):
1006 path = (prefix / _pathlib.Path(name))
1007 with open(path, "r", encoding="UTF-8") as stream:
1008 db.update(parse(stream, SVP64Record.CSV))
1009
1010 self.__db = {record.name:record for record in db}
1011 self.__ppcdb = ppcdb
1012
1013 return super().__init__()
1014
1015 def __getitem__(self, key):
1016 (_, record) = self.__ppcdb[key]
1017 if record is None:
1018 return None
1019
1020 for name in record.names:
1021 record = self.__db.get(name, None)
1022 if record is not None:
1023 return record
1024
1025 return None
1026
1027
1028 class Database:
1029 def __init__(self, root):
1030 root = _pathlib.Path(root)
1031
1032 mdwndb = MarkdownDatabase()
1033 fieldsdb = FieldsDatabase()
1034 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb, fieldsdb=fieldsdb)
1035 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1036
1037 db = set()
1038 for (name, operands) in mdwndb:
1039 (section, ppc) = ppcdb[name]
1040 if ppc is None:
1041 continue
1042 svp64 = svp64db[name]
1043 fields = fieldsdb[ppc.form]
1044 record = Record(name=name,
1045 section=section, ppc=ppc, svp64=svp64,
1046 operands=operands, fields=fields)
1047 db.add(record)
1048
1049 self.__db = tuple(sorted(db))
1050
1051 return super().__init__()
1052
1053 def __repr__(self):
1054 return repr(self.__db)
1055
1056 def __iter__(self):
1057 yield from self.__db
1058
1059 @_functools.lru_cache(maxsize=None)
1060 def __contains__(self, key):
1061 return self.__getitem__(key) is not None
1062
1063 @_functools.lru_cache(maxsize=None)
1064 def __getitem__(self, key):
1065 if isinstance(key, (int, Instruction)):
1066 key = int(key)
1067 for record in self:
1068 opcode = record.opcode
1069 if ((opcode.value & opcode.mask) ==
1070 (key & opcode.mask)):
1071 return record
1072 return None
1073 elif isinstance(key, Opcode):
1074 for record in self:
1075 if record.opcode == key:
1076 return record
1077 elif isinstance(key, str):
1078 for record in self:
1079 if record.name == key:
1080 return record
1081 return None