power_insn: implement mode decoding
[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 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 }
298
299 @classmethod
300 def CSV(cls, record):
301 for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
302 value = record[key]
303 if value == "0":
304 record[key] = "NONE"
305
306 record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
307
308 return dataclass(cls, record, keymap=cls.__KEYMAP)
309
310
311 class BitSel:
312 def __init__(self, value=(0, 32)):
313 if isinstance(value, str):
314 (start, end) = map(int, value.split(":"))
315 else:
316 (start, end) = value
317 if start < 0 or end < 0 or start >= end:
318 raise ValueError(value)
319
320 self.__start = start
321 self.__end = end
322
323 return super().__init__()
324
325 def __repr__(self):
326 return f"[{self.__start}:{self.__end}]"
327
328 def __iter__(self):
329 yield from range(self.start, (self.end + 1))
330
331 @property
332 def start(self):
333 return self.__start
334
335 @property
336 def end(self):
337 return self.__end
338
339
340 @_dataclasses.dataclass(eq=True, frozen=True)
341 class Section:
342 class Mode(_enum.Enum):
343 INTEGER = _enum.auto()
344 PATTERN = _enum.auto()
345
346 @classmethod
347 def _missing_(cls, value):
348 if isinstance(value, str):
349 return cls[value.upper()]
350 return super()._missing_(value)
351
352 class Suffix(int):
353 def __new__(cls, value=None):
354 if isinstance(value, str):
355 if value.upper() == "NONE":
356 value = None
357 else:
358 value = int(value, 0)
359 if value is None:
360 value = 0
361
362 return super().__new__(cls, value)
363
364 def __str__(self):
365 return repr(self)
366
367 def __repr__(self):
368 return (bin(self) if self else "None")
369
370 path: _pathlib.Path
371 opcode: Opcode
372 bitsel: BitSel
373 suffix: Suffix
374 mode: Mode
375
376 @classmethod
377 def CSV(cls, record):
378 return dataclass(cls, record)
379
380
381 class Fields:
382 def __init__(self, items):
383 if isinstance(items, dict):
384 items = items.items()
385
386 def transform(item):
387 (name, bitrange) = item
388 return (name, tuple(bitrange.values()))
389
390 self.__mapping = dict(map(transform, items))
391
392 return super().__init__()
393
394 def __repr__(self):
395 return repr(self.__mapping)
396
397 def __iter__(self):
398 yield from self.__mapping.items()
399
400 def __contains__(self, key):
401 return self.__mapping.__contains__(key)
402
403 def __getitem__(self, key):
404 return self.__mapping.get(key, None)
405
406
407 class Operands:
408 @_dataclasses.dataclass(eq=True, frozen=True)
409 class Operand:
410 name: str
411
412 def disassemble(self, value, record):
413 raise NotImplementedError
414
415 @_dataclasses.dataclass(eq=True, frozen=True)
416 class DynamicOperand(Operand):
417 def disassemble(self, value, record):
418 return str(int(value[record.fields[self.name]]))
419
420 @_dataclasses.dataclass(eq=True, frozen=True)
421 class StaticOperand(Operand):
422 value: int = None
423
424 @_dataclasses.dataclass(eq=True, frozen=True)
425 class DynamicOperandIFormLI(DynamicOperand):
426 def disassemble(self, value, record):
427 return hex(int(_selectconcat(
428 value[record.fields["LI"]],
429 _SelectableInt(value=0b00, bits=2))))
430
431 class DynamicOperandBFormBD(DynamicOperand):
432 def disassemble(self, value, record):
433 return hex(int(_selectconcat(
434 value[record.fields["BD"]],
435 _SelectableInt(value=0b00, bits=2))))
436
437 @_dataclasses.dataclass(eq=True, frozen=True)
438 class DynamicOperandGPR(DynamicOperand):
439 def disassemble(self, value, record):
440 return f"r{super().disassemble(value=value, record=record)}"
441
442 @_dataclasses.dataclass(eq=True, frozen=True)
443 class DynamicOperandFPR(DynamicOperand):
444 def disassemble(self, value, record):
445 return f"f{super().disassemble(value=value, record=record)}"
446
447 def __init__(self, insn, iterable):
448 branches = {
449 "b": {"LI": self.__class__.DynamicOperandIFormLI},
450 "ba": {"LI": self.__class__.DynamicOperandIFormLI},
451 "bl": {"LI": self.__class__.DynamicOperandIFormLI},
452 "bla": {"LI": self.__class__.DynamicOperandIFormLI},
453 "bc": {"BD": self.__class__.DynamicOperandBFormBD},
454 "bca": {"BD": self.__class__.DynamicOperandBFormBD},
455 "bcl": {"BD": self.__class__.DynamicOperandBFormBD},
456 "bcla": {"BD": self.__class__.DynamicOperandBFormBD},
457 }
458
459 operands = []
460 for operand in iterable:
461 dynamic_cls = self.__class__.DynamicOperand
462 static_cls = self.__class__.StaticOperand
463
464 if "=" in operand:
465 (name, value) = operand.split("=")
466 operand = static_cls(name=name, value=int(value))
467 else:
468 if insn in branches and operand in branches[insn]:
469 dynamic_cls = branches[insn][operand]
470
471 if operand in _RegType.__members__:
472 regtype = _RegType[operand]
473 if regtype is _RegType.GPR:
474 dynamic_cls = self.__class__.DynamicOperandGPR
475 elif regtype is _RegType.FPR:
476 dynamic_cls = self.__class__.DynamicOperandFPR
477
478 operand = dynamic_cls(name=operand)
479
480 operands.append(operand)
481
482 self.__operands = operands
483
484 return super().__init__()
485
486 def __repr__(self):
487 return self.__operands.__repr__()
488
489 def __iter__(self):
490 yield from self.__operands
491
492 def __contains__(self, key):
493 return self.__getitem__(key) is not None
494
495 def __getitem__(self, key):
496 for operand in self.__operands:
497 if operand.name == key:
498 return operand
499
500 return None
501
502 @property
503 def dynamic(self):
504 for operand in self:
505 if isinstance(operand, self.__class__.DynamicOperand):
506 yield operand
507
508 @property
509 def static(self):
510 for operand in self:
511 if isinstance(operand, self.__class__.StaticOperand):
512 yield operand
513
514
515 @_functools.total_ordering
516 @_dataclasses.dataclass(eq=True, frozen=True)
517 class Record:
518 name: str
519 section: Section
520 ppc: PPCRecord
521 fields: Fields
522 operands: Operands
523 svp64: SVP64Record = None
524
525 __EXTRA = (
526 _SVExtra.Idx0,
527 _SVExtra.Idx1,
528 _SVExtra.Idx2,
529 _SVExtra.Idx3,
530 )
531
532 def __lt__(self, other):
533 if not isinstance(other, Record):
534 return NotImplemented
535 return (self.opcode < other.opcode)
536
537 @cached_property
538 def opcode(self):
539 fields = []
540 if self.section.opcode:
541 fields += [(self.section.opcode.value, BitSel((0, 5)))]
542 fields += [(self.ppc.opcode.value, self.section.bitsel)]
543 else:
544 fields += [(self.ppc.opcode.value, self.section.bitsel)]
545
546 for operand in self.operands.static:
547 fields += [(operand.value, self.fields[operand.name])]
548
549 return FieldsOpcode(fields)
550
551 @property
552 def function(self):
553 return self.ppc.function
554
555 @property
556 def in1(self):
557 return self.ppc.in1
558
559 @property
560 def in2(self):
561 return self.ppc.in2
562
563 @property
564 def in3(self):
565 return self.ppc.in3
566
567 @property
568 def out(self):
569 return self.ppc.out
570
571 @property
572 def out2(self):
573 if self.svp64 is None:
574 return _OutSel.NONE
575 return self.ppc.out
576
577 @property
578 def cr_in(self):
579 return self.ppc.cr_in
580
581 @property
582 def cr_out(self):
583 return self.ppc.cr_out
584
585 def sv_extra(self, key):
586 if key not in frozenset({
587 "in1", "in2", "in3", "cr_in",
588 "out", "out2", "cr_out",
589 }):
590 raise KeyError(key)
591
592 sel = getattr(self.svp64, key)
593 if sel is _CRInSel.BA_BB:
594 return _SVExtra.Idx_1_2
595 reg = _SVExtraReg(sel)
596 if reg is _SVExtraReg.NONE:
597 return _SVExtra.NONE
598
599 extra_map = {
600 _SVExtraRegType.SRC: {},
601 _SVExtraRegType.DST: {},
602 }
603 for index in range(0, 4):
604 for entry in self.svp64.extra[index]:
605 extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
606
607 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
608 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
609 if extra is not _SVExtra.NONE:
610 return extra
611
612 return _SVExtra.NONE
613
614 sv_in1 = property(_functools.partial(sv_extra, key="in1"))
615 sv_in2 = property(_functools.partial(sv_extra, key="in2"))
616 sv_in3 = property(_functools.partial(sv_extra, key="in3"))
617 sv_out = property(_functools.partial(sv_extra, key="out"))
618 sv_out2 = property(_functools.partial(sv_extra, key="out2"))
619 sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
620 sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
621
622 @property
623 def sv_ptype(self):
624 if self.svp64 is None:
625 return _SVPtype.NONE
626 return self.svp64.ptype
627
628 @property
629 def sv_etype(self):
630 if self.svp64 is None:
631 return _SVEtype.NONE
632 return self.svp64.etype
633
634
635 class Instruction(_Mapping):
636 @classmethod
637 def integer(cls, value=0, bits=None, byteorder="little"):
638 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
639 raise ValueError(bits)
640
641 if isinstance(value, bytes):
642 if ((len(value) * 8) != bits):
643 raise ValueError(f"bit length mismatch")
644 value = int.from_bytes(value, byteorder=byteorder)
645
646 if isinstance(value, int):
647 value = _SelectableInt(value=value, bits=bits)
648 elif isinstance(value, Instruction):
649 value = value.storage
650
651 if not isinstance(value, _SelectableInt):
652 raise ValueError(value)
653 if bits is None:
654 bits = len(cls)
655 if len(value) != bits:
656 raise ValueError(value)
657
658 value = _SelectableInt(value=value, bits=bits)
659
660 return cls(storage=value)
661
662 def __hash__(self):
663 return hash(int(self))
664
665 def disassemble(self, db, byteorder="little"):
666 raise NotImplementedError
667
668
669 class WordInstruction(Instruction):
670 _: _Field = range(0, 32)
671 po: _Field = range(0, 6)
672
673 @classmethod
674 def integer(cls, value, byteorder="little"):
675 return super().integer(bits=32, value=value, byteorder=byteorder)
676
677 def disassemble(self, db, byteorder="little"):
678 integer = int(self)
679 blob = integer.to_bytes(length=4, byteorder=byteorder)
680 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
681
682 record = db[self]
683 if record is None:
684 yield f"{blob} .long 0x{integer:08x}"
685 return
686
687 operands = []
688 for operand in record.operands.dynamic:
689 operand = operand.disassemble(self, record)
690 operands.append(operand)
691 if operands:
692 operands = ",".join(operands)
693 operands = f" {operands}"
694 else:
695 operands = ""
696
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 return
955
956 Rc = False
957 if record.operands["Rc"] is not None:
958 Rc = bool(self[record.fields["Rc"]])
959
960 subvl = self.prefix.rm.subvl
961 mode = self.prefix.rm.mode
962 sel = mode.sel
963
964 if record.svp64.mode is _SVMode.NORMAL:
965 mode = mode.normal
966 if sel == 0b00:
967 if mode[2] == 0b0:
968 mode = mode.simple
969 else:
970 if subvl == 0b00:
971 if mode[3] == 0b0:
972 mode = mode.smr
973 else:
974 mode = mode.pmr
975 else:
976 if mode[4] == 0b0:
977 mode = mode.svmr
978 else:
979 mode = mode.pu
980 elif sel == 0b01:
981 if Rc:
982 mode = mode.ffrc1
983 else:
984 mode = mode.ffrc0
985 elif sel == 0b10:
986 if subvl == 0b00:
987 mode = mode.sat
988 else:
989 if mode[4]:
990 mode = mode.satx
991 else:
992 mode = mode.satpu
993 elif sel == 0b11:
994 if Rc:
995 mode = mode.prrc1
996 else:
997 mode = mode.prrc0
998 elif record.svp64.mode is _SVMode.LDST_IMM:
999 mode = mode.ldst_imm
1000 if sel == 0b00:
1001 if mode[2] == 0b0:
1002 mode = mode.simple
1003 else:
1004 mode = mode.spu
1005 elif sel == 0b01:
1006 if Rc:
1007 mode = mode.ffrc1
1008 else:
1009 mode = mode.ffrc0
1010 elif sel == 0b10:
1011 mode = mode.sat
1012 elif sel == 0b11:
1013 if Rc:
1014 mode = mode.prrc1
1015 else:
1016 mode = mode.prrc0
1017 elif record.svp64.mode is _SVMode.LDST_IMM:
1018 mode = mode.ldst_idx
1019 if mode.sel == 0b00:
1020 mode = mode.simple
1021 elif mode.sel == 0b01:
1022 mode = mode.stride
1023 elif mode.sel == 0b10:
1024 mode = mode.sat
1025 elif mode.sel == 0b11:
1026 if Rc:
1027 mode = mode.prrc1
1028 else:
1029 mode = mode.prrc0
1030
1031 if type(mode) is Mode:
1032 raise NotImplementedError
1033
1034 yield f"{blob_prefix} sv.{record.name}"
1035 yield f"{blob_suffix}"
1036
1037
1038 def parse(stream, factory):
1039 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1040 entries = _csv.DictReader(lines)
1041 entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
1042 return tuple(map(factory, entries))
1043
1044
1045 class MarkdownDatabase:
1046 def __init__(self):
1047 db = {}
1048 for (name, desc) in _ISA():
1049 operands = []
1050 if desc.regs:
1051 (dynamic, *static) = desc.regs
1052 operands.extend(dynamic)
1053 operands.extend(static)
1054 db[name] = Operands(insn=name, iterable=operands)
1055 self.__db = db
1056 return super().__init__()
1057
1058 def __iter__(self):
1059 yield from self.__db.items()
1060
1061 def __getitem__(self, key):
1062 return self.__db.__getitem__(key)
1063
1064
1065 class FieldsDatabase:
1066 def __init__(self):
1067 db = {}
1068 df = _DecodeFields()
1069 df.create_specs()
1070 for (form, fields) in df.instrs.items():
1071 if form in {"DQE", "TX"}:
1072 continue
1073 if form == "all":
1074 form = "NONE"
1075 db[_Form[form]] = Fields(fields)
1076
1077 self.__db = db
1078
1079 return super().__init__()
1080
1081 def __getitem__(self, key):
1082 return self.__db.__getitem__(key)
1083
1084
1085 class PPCDatabase:
1086 def __init__(self, root, mdwndb, fieldsdb):
1087 # The code below groups the instructions by section:identifier.
1088 # We use the comment as an identifier, there's nothing better.
1089 # The point is to capture different opcodes for the same instruction.
1090 dd = _collections.defaultdict
1091 records = dd(lambda: dd(set))
1092 path = (root / "insndb.csv")
1093 with open(path, "r", encoding="UTF-8") as stream:
1094 for section in parse(stream, Section.CSV):
1095 path = (root / section.path)
1096 opcode_cls = {
1097 section.Mode.INTEGER: IntegerOpcode,
1098 section.Mode.PATTERN: PatternOpcode,
1099 }[section.mode]
1100 factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
1101 with open(path, "r", encoding="UTF-8") as stream:
1102 for insn in parse(stream, factory):
1103 records[section][insn.comment].add(insn)
1104
1105 # Once we collected all instructions with the same identifier,
1106 # it's time to merge the different opcodes into the single pattern.
1107 # At this point, we only consider masks; the algorithm as follows:
1108 # 1. If any of two masks ignores the bit, it's ignored entirely.
1109 # 2. If the bit is not equal between masks, it's ignored.
1110 # 3. Otherwise the bits are equal and considered.
1111 def merge(lhs, rhs):
1112 value = 0
1113 mask = 0
1114 lvalue = lhs.opcode.value
1115 rvalue = rhs.opcode.value
1116 lmask = lhs.opcode.mask
1117 rmask = rhs.opcode.mask
1118 bits = max(lmask.bit_length(), rmask.bit_length())
1119 for bit in range(bits):
1120 lvstate = ((lvalue & (1 << bit)) != 0)
1121 rvstate = ((rvalue & (1 << bit)) != 0)
1122 lmstate = ((lmask & (1 << bit)) != 0)
1123 rmstate = ((rmask & (1 << bit)) != 0)
1124 vstate = lvstate
1125 mstate = True
1126 if (not lmstate or not rmstate) or (lvstate != rvstate):
1127 vstate = 0
1128 mstate = 0
1129 value |= (vstate << bit)
1130 mask |= (mstate << bit)
1131 return _dataclasses.replace(lhs, opcode=Opcode(value=value, mask=mask))
1132
1133 db = dd(set)
1134 for (section, group) in records.items():
1135 for records in group.values():
1136 db[section].add(_functools.reduce(merge, records))
1137
1138 self.__db = db
1139 self.__mdwndb = mdwndb
1140 self.__fieldsdb = fieldsdb
1141
1142 return super().__init__()
1143
1144 def __getitem__(self, key):
1145 def exact_match(key, record):
1146 for name in record.names:
1147 if name == key:
1148 return True
1149
1150 return False
1151
1152 def Rc_match(key, record):
1153 if not key.endswith("."):
1154 return False
1155
1156 if not record.Rc is _RCOE.RC:
1157 return False
1158
1159 return exact_match(key[:-1], record)
1160
1161 def LK_match(key, record):
1162 if not key.endswith("l"):
1163 return False
1164
1165 if "lk" not in record.flags:
1166 return False
1167
1168 return exact_match(key[:-1], record)
1169
1170 def AA_match(key, record):
1171 if not key.endswith("a"):
1172 return False
1173
1174 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1175 return False
1176
1177 if self.__mdwndb[key]["AA"] is None:
1178 return False
1179
1180 return (exact_match(key[:-1], record) or
1181 LK_match(key[:-1], record))
1182
1183 for (section, records) in self.__db.items():
1184 for record in records:
1185 if (exact_match(key, record) or
1186 Rc_match(key, record) or
1187 LK_match(key, record) or
1188 AA_match(key, record)):
1189 return (section, record)
1190
1191 return (None, None)
1192
1193
1194 class SVP64Database:
1195 def __init__(self, root, ppcdb):
1196 db = set()
1197 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1198 for (prefix, _, names) in _os.walk(root):
1199 prefix = _pathlib.Path(prefix)
1200 for name in filter(lambda name: pattern.match(name), names):
1201 path = (prefix / _pathlib.Path(name))
1202 with open(path, "r", encoding="UTF-8") as stream:
1203 db.update(parse(stream, SVP64Record.CSV))
1204
1205 self.__db = {record.name:record for record in db}
1206 self.__ppcdb = ppcdb
1207
1208 return super().__init__()
1209
1210 def __getitem__(self, key):
1211 (_, record) = self.__ppcdb[key]
1212 if record is None:
1213 return None
1214
1215 for name in record.names:
1216 record = self.__db.get(name, None)
1217 if record is not None:
1218 return record
1219
1220 return None
1221
1222
1223 class Database:
1224 def __init__(self, root):
1225 root = _pathlib.Path(root)
1226
1227 mdwndb = MarkdownDatabase()
1228 fieldsdb = FieldsDatabase()
1229 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb, fieldsdb=fieldsdb)
1230 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1231
1232 db = set()
1233 for (name, operands) in mdwndb:
1234 (section, ppc) = ppcdb[name]
1235 if ppc is None:
1236 continue
1237 svp64 = svp64db[name]
1238 fields = fieldsdb[ppc.form]
1239 record = Record(name=name,
1240 section=section, ppc=ppc, svp64=svp64,
1241 operands=operands, fields=fields)
1242 db.add(record)
1243
1244 self.__db = tuple(sorted(db))
1245
1246 return super().__init__()
1247
1248 def __repr__(self):
1249 return repr(self.__db)
1250
1251 def __iter__(self):
1252 yield from self.__db
1253
1254 @_functools.lru_cache(maxsize=None)
1255 def __contains__(self, key):
1256 return self.__getitem__(key) is not None
1257
1258 @_functools.lru_cache(maxsize=None)
1259 def __getitem__(self, key):
1260 if isinstance(key, (int, Instruction)):
1261 key = int(key)
1262 for record in self:
1263 opcode = record.opcode
1264 if ((opcode.value & opcode.mask) ==
1265 (key & opcode.mask)):
1266 return record
1267 return None
1268 elif isinstance(key, Opcode):
1269 for record in self:
1270 if record.opcode == key:
1271 return record
1272 elif isinstance(key, str):
1273 for record in self:
1274 if record.name == key:
1275 return record
1276 return None