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