power_insn: support instruction bytes conversion
[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 itertools as _itertools
7 import os as _os
8 import operator as _operator
9 import pathlib as _pathlib
10 import re as _re
11
12 try:
13 from functools import cached_property
14 except ImportError:
15 from cached_property import cached_property
16
17 from openpower.decoder.power_enums import (
18 Function as _Function,
19 MicrOp as _MicrOp,
20 In1Sel as _In1Sel,
21 In2Sel as _In2Sel,
22 In3Sel as _In3Sel,
23 OutSel as _OutSel,
24 CRInSel as _CRInSel,
25 CRIn2Sel as _CRIn2Sel,
26 CROutSel as _CROutSel,
27 LDSTLen as _LDSTLen,
28 LDSTMode as _LDSTMode,
29 RCOE as _RCOE,
30 CryIn as _CryIn,
31 Form as _Form,
32 SVEtype as _SVEtype,
33 SVMode as _SVMode,
34 SVPtype as _SVPtype,
35 SVExtra as _SVExtra,
36 RegType as _RegType,
37 SVExtraRegType as _SVExtraRegType,
38 SVExtraReg as _SVExtraReg,
39 )
40 from openpower.decoder.selectable_int import (
41 SelectableInt as _SelectableInt,
42 selectconcat as _selectconcat,
43 )
44 from openpower.decoder.power_fields import (
45 Field as _Field,
46 Mapping as _Mapping,
47 DecodeFields as _DecodeFields,
48 )
49 from openpower.decoder.pseudo.pagereader import ISA as _ISA
50
51
52 @_functools.total_ordering
53 class Verbosity(_enum.Enum):
54 SHORT = _enum.auto()
55 NORMAL = _enum.auto()
56 VERBOSE = _enum.auto()
57
58 def __lt__(self, other):
59 if not isinstance(other, self.__class__):
60 return NotImplemented
61 return (self.value < other.value)
62
63
64 def dataclass(cls, record, keymap=None, typemap=None):
65 if keymap is None:
66 keymap = {}
67 if typemap is None:
68 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
69
70 def transform(key_value):
71 (key, value) = key_value
72 key = keymap.get(key, key)
73 hook = typemap.get(key, lambda value: value)
74 if hook is bool and value in ("", "0"):
75 value = False
76 else:
77 value = hook(value)
78 return (key, value)
79
80 record = dict(map(transform, record.items()))
81 for key in frozenset(record.keys()):
82 if record[key] == "":
83 record.pop(key)
84
85 return cls(**record)
86
87
88 @_functools.total_ordering
89 @_dataclasses.dataclass(eq=True, frozen=True)
90 class Opcode:
91 class Integer(int):
92 def __new__(cls, value):
93 if isinstance(value, str):
94 value = int(value, 0)
95 if not isinstance(value, int):
96 raise ValueError(value)
97
98 if value.bit_length() > 64:
99 raise ValueError(value)
100
101 return super().__new__(cls, value)
102
103 def __str__(self):
104 return super().__repr__()
105
106 def __repr__(self):
107 return f"{self:0{self.bit_length()}b}"
108
109 def bit_length(self):
110 if super().bit_length() > 32:
111 return 64
112 return 32
113
114 class Value(Integer):
115 pass
116
117 class Mask(Integer):
118 pass
119
120 value: Value
121 mask: Mask
122
123 def __lt__(self, other):
124 if not isinstance(other, Opcode):
125 return NotImplemented
126 return ((self.value, self.mask) < (other.value, other.mask))
127
128 def __post_init__(self):
129 if self.value.bit_length() != self.mask.bit_length():
130 raise ValueError("bit length mismatch")
131
132 def __repr__(self):
133 def pattern(value, mask, bit_length):
134 for bit in range(bit_length):
135 if ((mask & (1 << (bit_length - bit - 1))) == 0):
136 yield "-"
137 elif (value & (1 << (bit_length - bit - 1))):
138 yield "1"
139 else:
140 yield "0"
141
142 return "".join(pattern(self.value, self.mask, self.value.bit_length()))
143
144
145 class IntegerOpcode(Opcode):
146 def __init__(self, value):
147 if value.startswith("0b"):
148 mask = int(("1" * len(value[2:])), 2)
149 else:
150 mask = 0b111111
151
152 value = Opcode.Value(value)
153 mask = Opcode.Mask(mask)
154
155 return super().__init__(value=value, mask=mask)
156
157
158 class PatternOpcode(Opcode):
159 def __init__(self, pattern):
160 if not isinstance(pattern, str):
161 raise ValueError(pattern)
162
163 (value, mask) = (0, 0)
164 for symbol in pattern:
165 if symbol not in {"0", "1", "-"}:
166 raise ValueError(pattern)
167 value |= (symbol == "1")
168 mask |= (symbol != "-")
169 value <<= 1
170 mask <<= 1
171 value >>= 1
172 mask >>= 1
173
174 value = Opcode.Value(value)
175 mask = Opcode.Mask(mask)
176
177 return super().__init__(value=value, mask=mask)
178
179
180 @_dataclasses.dataclass(eq=True, frozen=True)
181 class PPCRecord:
182 class FlagsMeta(type):
183 def __iter__(cls):
184 yield from (
185 "inv A",
186 "inv out",
187 "cry out",
188 "BR",
189 "sgn ext",
190 "rsrv",
191 "32b",
192 "sgn",
193 "lk",
194 "sgl pipe",
195 )
196
197 class Flags(frozenset, metaclass=FlagsMeta):
198 def __new__(cls, flags=frozenset()):
199 flags = frozenset(flags)
200 diff = (flags - frozenset(cls))
201 if diff:
202 raise ValueError(flags)
203 return super().__new__(cls, flags)
204
205 opcode: Opcode
206 comment: str
207 flags: Flags = Flags()
208 comment2: str = ""
209 function: _Function = _Function.NONE
210 intop: _MicrOp = _MicrOp.OP_ILLEGAL
211 in1: _In1Sel = _In1Sel.RA
212 in2: _In2Sel = _In2Sel.NONE
213 in3: _In3Sel = _In3Sel.NONE
214 out: _OutSel = _OutSel.NONE
215 cr_in: _CRInSel = _CRInSel.NONE
216 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
217 cr_out: _CROutSel = _CROutSel.NONE
218 cry_in: _CryIn = _CryIn.ZERO
219 ldst_len: _LDSTLen = _LDSTLen.NONE
220 upd: _LDSTMode = _LDSTMode.NONE
221 Rc: _RCOE = _RCOE.NONE
222 form: _Form = _Form.NONE
223 conditions: str = ""
224 unofficial: bool = False
225
226 __KEYMAP = {
227 "unit": "function",
228 "internal op": "intop",
229 "CR in": "cr_in",
230 "CR out": "cr_out",
231 "cry in": "cry_in",
232 "ldst len": "ldst_len",
233 "rc": "Rc",
234 "CONDITIONS": "conditions",
235 }
236
237 @classmethod
238 def CSV(cls, record, opcode_cls):
239 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
240 typemap["opcode"] = opcode_cls
241
242 if record["CR in"] == "BA_BB":
243 record["cr_in"] = "BA"
244 record["cr_in2"] = "BB"
245 del record["CR in"]
246
247 flags = set()
248 for flag in frozenset(PPCRecord.Flags):
249 if bool(record.pop(flag, "")):
250 flags.add(flag)
251 record["flags"] = PPCRecord.Flags(flags)
252
253 return dataclass(cls, record,
254 keymap=PPCRecord.__KEYMAP,
255 typemap=typemap)
256
257 @cached_property
258 def names(self):
259 return frozenset(self.comment.split("=")[-1].split("/"))
260
261
262 class PPCMultiRecord(tuple):
263 def __getattr__(self, attr):
264 if attr == "opcode":
265 raise AttributeError(attr)
266 return getattr(self[0], attr)
267
268
269 @_dataclasses.dataclass(eq=True, frozen=True)
270 class SVP64Record:
271 class ExtraMap(tuple):
272 class Extra(tuple):
273 @_dataclasses.dataclass(eq=True, frozen=True)
274 class Entry:
275 regtype: _SVExtraRegType = _SVExtraRegType.NONE
276 reg: _SVExtraReg = _SVExtraReg.NONE
277
278 def __repr__(self):
279 return f"{self.regtype.value}:{self.reg.name}"
280
281 def __new__(cls, value="0"):
282 if isinstance(value, str):
283 def transform(value):
284 (regtype, reg) = value.split(":")
285 regtype = _SVExtraRegType(regtype)
286 reg = _SVExtraReg(reg)
287 return cls.Entry(regtype=regtype, reg=reg)
288
289 if value == "0":
290 value = tuple()
291 else:
292 value = map(transform, value.split(";"))
293
294 return super().__new__(cls, value)
295
296 def __repr__(self):
297 return repr(list(self))
298
299 def __new__(cls, value=tuple()):
300 value = tuple(value)
301 if len(value) == 0:
302 value = (("0",) * 4)
303 return super().__new__(cls, map(cls.Extra, value))
304
305 def __repr__(self):
306 return repr({index:self[index] for index in range(0, 4)})
307
308 name: str
309 ptype: _SVPtype = _SVPtype.NONE
310 etype: _SVEtype = _SVEtype.NONE
311 in1: _In1Sel = _In1Sel.NONE
312 in2: _In2Sel = _In2Sel.NONE
313 in3: _In3Sel = _In3Sel.NONE
314 out: _OutSel = _OutSel.NONE
315 out2: _OutSel = _OutSel.NONE
316 cr_in: _CRInSel = _CRInSel.NONE
317 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
318 cr_out: _CROutSel = _CROutSel.NONE
319 extra: ExtraMap = ExtraMap()
320 conditions: str = ""
321 mode: _SVMode = _SVMode.NORMAL
322
323 __KEYMAP = {
324 "insn": "name",
325 "CONDITIONS": "conditions",
326 "Ptype": "ptype",
327 "Etype": "etype",
328 "CR in": "cr_in",
329 "CR out": "cr_out",
330 }
331
332 @classmethod
333 def CSV(cls, record):
334 for key in frozenset({
335 "in1", "in2", "in3", "CR in",
336 "out", "out2", "CR out",
337 }):
338 value = record[key]
339 if value == "0":
340 record[key] = "NONE"
341
342 if record["CR in"] == "BA_BB":
343 record["cr_in"] = "BA"
344 record["cr_in2"] = "BB"
345 del record["CR in"]
346
347 extra = []
348 for idx in range(0, 4):
349 extra.append(record.pop(f"{idx}"))
350
351 record["extra"] = cls.ExtraMap(extra)
352
353 return dataclass(cls, record, keymap=cls.__KEYMAP)
354
355 @_functools.lru_cache(maxsize=None)
356 def extra_idx(self, key):
357 extra_idx = (
358 _SVExtra.Idx0,
359 _SVExtra.Idx1,
360 _SVExtra.Idx2,
361 _SVExtra.Idx3,
362 )
363
364 if key not in frozenset({
365 "in1", "in2", "in3", "cr_in", "cr_in2",
366 "out", "out2", "cr_out",
367 }):
368 raise KeyError(key)
369
370 sel = getattr(self, key)
371 if sel is _CRInSel.BA_BB:
372 return _SVExtra.Idx_1_2
373 reg = _SVExtraReg(sel)
374 if reg is _SVExtraReg.NONE:
375 return _SVExtra.NONE
376
377 extra_map = {
378 _SVExtraRegType.SRC: {},
379 _SVExtraRegType.DST: {},
380 }
381 for index in range(0, 4):
382 for entry in self.extra[index]:
383 extra_map[entry.regtype][entry.reg] = extra_idx[index]
384
385 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
386 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
387 if extra is not _SVExtra.NONE:
388 return extra
389
390 return _SVExtra.NONE
391
392 extra_idx_in1 = property(_functools.partial(extra_idx, key="in1"))
393 extra_idx_in2 = property(_functools.partial(extra_idx, key="in2"))
394 extra_idx_in3 = property(_functools.partial(extra_idx, key="in3"))
395 extra_idx_out = property(_functools.partial(extra_idx, key="out"))
396 extra_idx_out2 = property(_functools.partial(extra_idx, key="out2"))
397 extra_idx_cr_in = property(_functools.partial(extra_idx, key="cr_in"))
398 extra_idx_cr_out = property(_functools.partial(extra_idx, key="cr_out"))
399
400 @_functools.lru_cache(maxsize=None)
401 def extra_reg(self, key):
402 return _SVExtraReg(getattr(self, key))
403
404 extra_reg_in1 = property(_functools.partial(extra_reg, key="in1"))
405 extra_reg_in2 = property(_functools.partial(extra_reg, key="in2"))
406 extra_reg_in3 = property(_functools.partial(extra_reg, key="in3"))
407 extra_reg_out = property(_functools.partial(extra_reg, key="out"))
408 extra_reg_out2 = property(_functools.partial(extra_reg, key="out2"))
409 extra_reg_cr_in = property(_functools.partial(extra_reg, key="cr_in"))
410 extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
411
412
413 class BitSel:
414 def __init__(self, value=(0, 32)):
415 if isinstance(value, str):
416 (start, end) = map(int, value.split(":"))
417 else:
418 (start, end) = value
419 if start < 0 or end < 0 or start >= end:
420 raise ValueError(value)
421
422 self.__start = start
423 self.__end = end
424
425 return super().__init__()
426
427 def __repr__(self):
428 return f"[{self.__start}:{self.__end}]"
429
430 def __iter__(self):
431 yield from range(self.start, (self.end + 1))
432
433 def __reversed__(self):
434 return tuple(reversed(tuple(self)))
435
436 @property
437 def start(self):
438 return self.__start
439
440 @property
441 def end(self):
442 return self.__end
443
444
445 @_dataclasses.dataclass(eq=True, frozen=True)
446 class Section:
447 class Mode(_enum.Enum):
448 INTEGER = _enum.auto()
449 PATTERN = _enum.auto()
450
451 @classmethod
452 def _missing_(cls, value):
453 if isinstance(value, str):
454 return cls[value.upper()]
455 return super()._missing_(value)
456
457 class Suffix(int):
458 def __new__(cls, value=None):
459 if isinstance(value, str):
460 if value.upper() == "NONE":
461 value = None
462 else:
463 value = int(value, 0)
464 if value is None:
465 value = 0
466
467 return super().__new__(cls, value)
468
469 def __str__(self):
470 return repr(self)
471
472 def __repr__(self):
473 return (bin(self) if self else "None")
474
475 path: _pathlib.Path
476 bitsel: BitSel
477 suffix: Suffix
478 mode: Mode
479 opcode: IntegerOpcode = None
480
481 @classmethod
482 def CSV(cls, record):
483 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
484 if record["opcode"] == "NONE":
485 typemap["opcode"] = lambda _: None
486
487 return dataclass(cls, record, typemap=typemap)
488
489
490 class Fields:
491 def __init__(self, items):
492 if isinstance(items, dict):
493 items = items.items()
494
495 def transform(item):
496 (name, bitrange) = item
497 return (name, tuple(bitrange.values()))
498
499 self.__mapping = dict(map(transform, items))
500
501 return super().__init__()
502
503 def __repr__(self):
504 return repr(self.__mapping)
505
506 def __iter__(self):
507 yield from self.__mapping.items()
508
509 def __contains__(self, key):
510 return self.__mapping.__contains__(key)
511
512 def __getitem__(self, key):
513 return self.__mapping.get(key, None)
514
515
516 @_dataclasses.dataclass(eq=True, frozen=True)
517 class Operand:
518 name: str
519
520 def span(self, record):
521 return record.fields[self.name]
522
523 def disassemble(self, insn, record,
524 verbosity=Verbosity.NORMAL, indent=""):
525 raise NotImplementedError
526
527
528 class DynamicOperand(Operand):
529 def disassemble(self, insn, record,
530 verbosity=Verbosity.NORMAL, indent=""):
531 span = self.span(record=record)
532 if isinstance(insn, SVP64Instruction):
533 span = tuple(map(lambda bit: (bit + 32), span))
534 value = insn[span]
535
536 if verbosity >= Verbosity.VERBOSE:
537 span = map(str, span)
538 yield f"{indent}{self.name}"
539 yield f"{indent}{indent}{int(value):0{value.bits}b}"
540 yield f"{indent}{indent}{', '.join(span)}"
541 else:
542 yield str(int(value))
543
544
545 class SignedOperand(DynamicOperand):
546 def disassemble(self, insn, record,
547 verbosity=Verbosity.NORMAL, indent=""):
548 span = self.span(record=record)
549 if isinstance(insn, SVP64Instruction):
550 span = tuple(map(lambda bit: (bit + 32), span))
551 value = insn[span]
552
553 if verbosity >= Verbosity.VERBOSE:
554 span = map(str, span)
555 yield f"{indent}{self.name}"
556 yield f"{indent}{indent}{int(value):0{value.bits}b}"
557 yield f"{indent}{indent}{', '.join(span)}"
558 else:
559 yield str(value.to_signed_int())
560
561
562 @_dataclasses.dataclass(eq=True, frozen=True)
563 class StaticOperand(Operand):
564 value: int
565
566 def disassemble(self, insn, record,
567 verbosity=Verbosity.NORMAL, indent=""):
568 span = self.span(record=record)
569 if isinstance(insn, SVP64Instruction):
570 span = tuple(map(lambda bit: (bit + 32), span))
571 value = insn[span]
572
573 if verbosity >= Verbosity.VERBOSE:
574 span = map(str, span)
575 yield f"{indent}{self.name}"
576 yield f"{indent}{indent}{int(value):0{value.bits}b}"
577 yield f"{indent}{indent}{', '.join(span)}"
578 else:
579 yield str(int(value))
580
581
582 class ImmediateOperand(DynamicOperand):
583 pass
584
585
586 class NonZeroOperand(DynamicOperand):
587 def disassemble(self, insn, record,
588 verbosity=Verbosity.NORMAL, indent=""):
589 span = self.span(record=record)
590 if isinstance(insn, SVP64Instruction):
591 span = tuple(map(lambda bit: (bit + 32), span))
592 value = insn[span]
593
594 if verbosity >= Verbosity.VERBOSE:
595 span = map(str, span)
596 yield f"{indent}{self.name}"
597 yield f"{indent}{indent}{int(value):0{value.bits}b}"
598 yield f"{indent}{indent}{', '.join(span)}"
599 else:
600 yield str(int(value) + 1)
601
602
603 class RegisterOperand(DynamicOperand):
604 def sv_spec_enter(self, value, span):
605 return (value, span)
606
607 def sv_spec_leave(self, value, span, origin_value, origin_span):
608 return (value, span)
609
610 def spec(self, insn, record):
611 vector = False
612 span = self.span(record=record)
613 if isinstance(insn, SVP64Instruction):
614 span = tuple(map(lambda bit: (bit + 32), span))
615 value = insn[span]
616 span = tuple(map(str, span))
617
618 if isinstance(insn, SVP64Instruction):
619 (origin_value, origin_span) = (value, span)
620 (value, span) = self.sv_spec_enter(value=value, span=span)
621
622 extra_idx = self.extra_idx(record=record)
623 if extra_idx is _SVExtra.NONE:
624 return (vector, value, span)
625
626 if record.etype is _SVEtype.EXTRA3:
627 spec = insn.prefix.rm.extra3[extra_idx]
628 elif record.etype is _SVEtype.EXTRA2:
629 spec = insn.prefix.rm.extra2[extra_idx]
630 else:
631 raise ValueError(record.etype)
632
633 if spec != 0:
634 vector = bool(spec[0])
635 spec_span = spec.__class__
636 if record.etype is _SVEtype.EXTRA3:
637 spec_span = tuple(map(str, spec_span[1, 2]))
638 spec = spec[1, 2]
639 elif record.etype is _SVEtype.EXTRA2:
640 spec_span = tuple(map(str, spec_span[1,]))
641 spec = _SelectableInt(value=spec[1].value, bits=2)
642 if vector:
643 spec <<= 1
644 spec_span = (spec_span + ("{0}",))
645 else:
646 spec_span = (("{0}",) + spec_span)
647 else:
648 raise ValueError(record.etype)
649
650 vector_shift = (2 + (5 - value.bits))
651 scalar_shift = value.bits
652 spec_shift = (5 - value.bits)
653
654 bits = (len(span) + len(spec_span))
655 value = _SelectableInt(value=value.value, bits=bits)
656 spec = _SelectableInt(value=spec.value, bits=bits)
657 if vector:
658 value = ((value << vector_shift) | (spec << spec_shift))
659 span = (span + spec_span + ((spec_shift * ('{0}',))))
660 else:
661 value = ((spec << scalar_shift) | value)
662 span = ((spec_shift * ('{0}',)) + spec_span + span)
663
664 (value, span) = self.sv_spec_leave(value=value, span=span,
665 origin_value=origin_value, origin_span=origin_span)
666
667 return (vector, value, span)
668
669 @property
670 def extra_reg(self):
671 return _SVExtraReg(self.name)
672
673 def extra_idx(self, record):
674 for key in frozenset({
675 "in1", "in2", "in3", "cr_in", "cr_in2",
676 "out", "out2", "cr_out",
677 }):
678 extra_reg = record.svp64.extra_reg(key=key)
679 if extra_reg is self.extra_reg:
680 return record.extra_idx(key=key)
681
682 return _SVExtra.NONE
683
684 def disassemble(self, insn, record,
685 verbosity=Verbosity.NORMAL, prefix="", indent=""):
686 (vector, value, span) = self.spec(insn=insn, record=record)
687
688 if verbosity >= Verbosity.VERBOSE:
689 mode = "vector" if vector else "scalar"
690 yield f"{indent}{self.name} ({mode})"
691 yield f"{indent}{indent}{int(value):0{value.bits}b}"
692 yield f"{indent}{indent}{', '.join(span)}"
693 if isinstance(insn, SVP64Instruction):
694 extra_idx = self.extra_idx(record)
695 if record.etype is _SVEtype.NONE:
696 yield f"{indent}{indent}extra[none]"
697 else:
698 etype = repr(record.etype).lower()
699 yield f"{indent}{indent}{etype}{extra_idx!r}"
700 else:
701 vector = "*" if vector else ""
702 yield f"{vector}{prefix}{int(value)}"
703
704
705 class GPROperand(RegisterOperand):
706 def disassemble(self, insn, record,
707 verbosity=Verbosity.NORMAL, indent=""):
708 prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
709 yield from super().disassemble(prefix=prefix,
710 insn=insn, record=record,
711 verbosity=verbosity, indent=indent)
712
713
714 class FPROperand(RegisterOperand):
715 def disassemble(self, insn, record,
716 verbosity=Verbosity.NORMAL, indent=""):
717 prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
718 yield from super().disassemble(prefix=prefix,
719 insn=insn, record=record,
720 verbosity=verbosity, indent=indent)
721
722
723 class CR3Operand(RegisterOperand):
724 pass
725
726
727 class CR5Operand(RegisterOperand):
728 def sv_spec_enter(self, value, span):
729 value = _SelectableInt(value=(value.value >> 2), bits=3)
730 return (value, span)
731
732 def sv_spec_leave(self, value, span, origin_value, origin_span):
733 value = _selectconcat(value, origin_value[3:5])
734 span += origin_span
735 return (value, span)
736
737
738 class TargetAddrOperand(RegisterOperand):
739 def disassemble(self, insn, record, field,
740 verbosity=Verbosity.NORMAL, indent=""):
741 span = self.span(record=record)
742 if isinstance(insn, SVP64Instruction):
743 span = tuple(map(lambda bit: (bit + 32), span))
744 value = insn[span]
745
746 if verbosity >= Verbosity.VERBOSE:
747 span = tuple(map(str, span))
748 yield f"{indent}{self.name} = EXTS({field} || 0b00))"
749 yield f"{indent}{indent}{field}"
750 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
751 yield f"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
752 else:
753 yield hex(_selectconcat(value,
754 _SelectableInt(value=0b00, bits=2)).to_signed_int())
755
756
757 class TargetAddrOperandLI(TargetAddrOperand):
758 def span(self, record):
759 return record.fields["LI"]
760
761 def disassemble(self, insn, record,
762 verbosity=Verbosity.NORMAL, indent=""):
763 return super().disassemble(field="LI",
764 insn=insn, record=record,
765 verbosity=verbosity, indent=indent)
766
767
768 class TargetAddrOperandBD(TargetAddrOperand):
769 def span(self, record):
770 return record.fields["BD"]
771
772 def disassemble(self, insn, record,
773 verbosity=Verbosity.NORMAL, indent=""):
774 return super().disassemble(field="BD",
775 insn=insn, record=record,
776 verbosity=verbosity, indent=indent)
777
778
779 class DOperandDX(DynamicOperand):
780 def span(self, record):
781 operands = map(DynamicOperand, ("d0", "d1", "d2"))
782 spans = map(lambda operand: operand.span(record=record), operands)
783 return sum(spans, tuple())
784
785 def disassemble(self, insn, record,
786 verbosity=Verbosity.NORMAL, indent=""):
787 span = self.span(record=record)
788 if isinstance(insn, SVP64Instruction):
789 span = tuple(map(lambda bit: (bit + 32), span))
790 value = insn[span]
791
792 if verbosity >= Verbosity.VERBOSE:
793 yield f"{indent}D"
794 mapping = {
795 "d0": "[0:9]",
796 "d1": "[10:15]",
797 "d2": "[16]",
798 }
799 for (subname, subspan) in mapping.items():
800 operand = DynamicOperand(name=subname)
801 span = operand.span(record=record)
802 if isinstance(insn, SVP64Instruction):
803 span = tuple(map(lambda bit: (bit + 32), span))
804 value = insn[span]
805 span = map(str, span)
806 yield f"{indent}{indent}{operand.name} = D{subspan}"
807 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
808 yield f"{indent}{indent}{indent}{', '.join(span)}"
809 else:
810 yield str(value.to_signed_int())
811
812
813 class Operands(tuple):
814 def __new__(cls, insn, iterable):
815 custom_insns = {
816 "b": {"target_addr": TargetAddrOperandLI},
817 "ba": {"target_addr": TargetAddrOperandLI},
818 "bl": {"target_addr": TargetAddrOperandLI},
819 "bla": {"target_addr": TargetAddrOperandLI},
820 "bc": {"target_addr": TargetAddrOperandBD},
821 "bca": {"target_addr": TargetAddrOperandBD},
822 "bcl": {"target_addr": TargetAddrOperandBD},
823 "bcla": {"target_addr": TargetAddrOperandBD},
824 "addpcis": {"D": DOperandDX},
825 "fishmv": {"D": DOperandDX},
826 "fmvis": {"D": DOperandDX},
827 }
828 custom_fields = {
829 "SVi": NonZeroOperand,
830 "SVd": NonZeroOperand,
831 "SVxd": NonZeroOperand,
832 "SVyd": NonZeroOperand,
833 "SVzd": NonZeroOperand,
834 "BD": SignedOperand,
835 "D": SignedOperand,
836 "DQ": SignedOperand,
837 "DS": SignedOperand,
838 "SI": SignedOperand,
839 "IB": SignedOperand,
840 "LI": SignedOperand,
841 "SIM": SignedOperand,
842 "SVD": SignedOperand,
843 "SVDS": SignedOperand,
844 }
845
846 operands = []
847 for operand in iterable:
848 dynamic_cls = DynamicOperand
849 static_cls = StaticOperand
850
851 if "=" in operand:
852 (name, value) = operand.split("=")
853 operand = static_cls(name=name, value=int(value))
854 operands.append(operand)
855 else:
856 if operand.endswith(")"):
857 operand = operand.replace("(", " ").replace(")", "")
858 (immediate, _, operand) = operand.partition(" ")
859 else:
860 immediate = None
861
862 if immediate is not None:
863 operands.append(ImmediateOperand(name=immediate))
864
865 if insn in custom_insns and operand in custom_insns[insn]:
866 dynamic_cls = custom_insns[insn][operand]
867 if operand in custom_fields:
868 dynamic_cls = custom_fields[operand]
869
870 if operand in _RegType.__members__:
871 regtype = _RegType[operand]
872 if regtype is _RegType.GPR:
873 dynamic_cls = GPROperand
874 elif regtype is _RegType.FPR:
875 dynamic_cls = FPROperand
876 if regtype is _RegType.CR_BIT: # 5-bit
877 dynamic_cls = CR5Operand
878 if regtype is _RegType.CR_REG: # actually CR Field, 3-bit
879 dynamic_cls = CR3Operand
880
881 operand = dynamic_cls(name=operand)
882 operands.append(operand)
883
884 return super().__new__(cls, operands)
885
886 def __contains__(self, key):
887 return self.__getitem__(key) is not None
888
889 def __getitem__(self, key):
890 for operand in self:
891 if operand.name == key:
892 return operand
893
894 return None
895
896 @property
897 def dynamic(self):
898 for operand in self:
899 if isinstance(operand, DynamicOperand):
900 yield operand
901
902 @property
903 def static(self):
904 for operand in self:
905 if isinstance(operand, StaticOperand):
906 yield operand
907
908
909 class PCode:
910 def __init__(self, iterable):
911 self.__pcode = tuple(iterable)
912 return super().__init__()
913
914 def __iter__(self):
915 yield from self.__pcode
916
917 def __repr__(self):
918 return self.__pcode.__repr__()
919
920
921 @_dataclasses.dataclass(eq=True, frozen=True)
922 class MarkdownRecord:
923 pcode: PCode
924 operands: Operands
925
926
927 @_functools.total_ordering
928 @_dataclasses.dataclass(eq=True, frozen=True)
929 class Record:
930 name: str
931 section: Section
932 ppc: PPCRecord
933 fields: Fields
934 mdwn: MarkdownRecord
935 svp64: SVP64Record = None
936
937 def __lt__(self, other):
938 if not isinstance(other, Record):
939 return NotImplemented
940 return (min(self.opcodes) < min(other.opcodes))
941
942 @property
943 def opcodes(self):
944 def opcode(ppc):
945 value = ([0] * 32)
946 mask = ([0] * 32)
947
948 PO = self.section.opcode
949 if PO is not None:
950 for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
951 value[dst] = int((PO.value & (1 << src)) != 0)
952 mask[dst] = int((PO.mask & (1 << src)) != 0)
953
954 XO = ppc.opcode
955 for (src, dst) in enumerate(reversed(self.section.bitsel)):
956 value[dst] = int((XO.value & (1 << src)) != 0)
957 mask[dst] = int((XO.mask & (1 << src)) != 0)
958
959 for operand in self.mdwn.operands.static:
960 for (src, dst) in enumerate(reversed(operand.span(record=self))):
961 value[dst] = int((operand.value & (1 << src)) != 0)
962 mask[dst] = 1
963
964 value = Opcode.Value(int(("".join(map(str, value))), 2))
965 mask = Opcode.Mask(int(("".join(map(str, mask))), 2))
966
967 return Opcode(value=value, mask=mask)
968
969 return tuple(sorted(map(opcode, self.ppc)))
970
971 def match(self, key):
972 for opcode in self.opcodes:
973 if ((opcode.value & opcode.mask) ==
974 (key & opcode.mask)):
975 return True
976 return False
977
978 @property
979 def function(self):
980 return self.ppc.function
981
982 @property
983 def in1(self):
984 return self.ppc.in1
985
986 @property
987 def in2(self):
988 return self.ppc.in2
989
990 @property
991 def in3(self):
992 return self.ppc.in3
993
994 @property
995 def out(self):
996 return self.ppc.out
997
998 @property
999 def out2(self):
1000 if self.svp64 is None:
1001 return _OutSel.NONE
1002 return self.ppc.out
1003
1004 @property
1005 def cr_in(self):
1006 return self.ppc.cr_in
1007
1008 @property
1009 def cr_in2(self):
1010 return self.ppc.cr_in2
1011
1012 @property
1013 def cr_out(self):
1014 return self.ppc.cr_out
1015
1016 ptype = property(lambda self: self.svp64.ptype)
1017 etype = property(lambda self: self.svp64.etype)
1018
1019 def extra_idx(self, key):
1020 return self.svp64.extra_idx(key)
1021
1022 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
1023 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
1024 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
1025 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
1026 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
1027 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
1028 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
1029
1030
1031 class Instruction(_Mapping):
1032 @classmethod
1033 def integer(cls, value=0, bits=None, byteorder="little"):
1034 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1035 raise ValueError(bits)
1036
1037 if isinstance(value, bytes):
1038 if ((len(value) * 8) != bits):
1039 raise ValueError(f"bit length mismatch")
1040 value = int.from_bytes(value, byteorder=byteorder)
1041
1042 if isinstance(value, int):
1043 value = _SelectableInt(value=value, bits=bits)
1044 elif isinstance(value, Instruction):
1045 value = value.storage
1046
1047 if not isinstance(value, _SelectableInt):
1048 raise ValueError(value)
1049 if bits is None:
1050 bits = len(cls)
1051 if len(value) != bits:
1052 raise ValueError(value)
1053
1054 value = _SelectableInt(value=value, bits=bits)
1055
1056 return cls(storage=value)
1057
1058 def __hash__(self):
1059 return hash(int(self))
1060
1061 def __getitem__(self, key):
1062 return self.storage.__getitem__(key)
1063
1064 def __setitem__(self, key, value):
1065 return self.storage.__setitem__(key, value)
1066
1067 def bytes(self, byteorder="little"):
1068 nr_bytes = (self.storage.bits // 8)
1069 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1070
1071 def record(self, db):
1072 record = db[self]
1073 if record is None:
1074 raise KeyError(self)
1075 return record
1076
1077 def spec(self, db, prefix):
1078 record = self.record(db=db)
1079
1080 dynamic_operands = tuple(map(_operator.itemgetter(0),
1081 self.dynamic_operands(db=db)))
1082
1083 static_operands = []
1084 for (name, value) in self.static_operands(db=db):
1085 static_operands.append(f"{name}={value}")
1086
1087 operands = ""
1088 if dynamic_operands:
1089 operands += f" {','.join(dynamic_operands)}"
1090 if static_operands:
1091 operands += f" ({' '.join(static_operands)})"
1092
1093 return f"{prefix}{record.name}{operands}"
1094
1095 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
1096 record = self.record(db=db)
1097
1098 imm = False
1099 imm_name = ""
1100 imm_value = ""
1101 for operand in record.mdwn.operands.dynamic:
1102 name = operand.name
1103 dis = operand.disassemble(insn=self, record=record,
1104 verbosity=min(verbosity, Verbosity.NORMAL))
1105 value = " ".join(dis)
1106 if imm:
1107 name = f"{imm_name}({name})"
1108 value = f"{imm_value}({value})"
1109 imm = False
1110 if isinstance(operand, ImmediateOperand):
1111 imm_name = name
1112 imm_value = value
1113 imm = True
1114 if not imm:
1115 yield (name, value)
1116
1117 def static_operands(self, db):
1118 record = self.record(db=db)
1119 for operand in record.mdwn.operands.static:
1120 yield (operand.name, operand.value)
1121
1122 def disassemble(self, db,
1123 byteorder="little",
1124 verbosity=Verbosity.NORMAL):
1125 raise NotImplementedError
1126
1127
1128 class WordInstruction(Instruction):
1129 _: _Field = range(0, 32)
1130 po: _Field = range(0, 6)
1131
1132 @classmethod
1133 def integer(cls, value, byteorder="little"):
1134 return super().integer(bits=32, value=value, byteorder=byteorder)
1135
1136 @property
1137 def binary(self):
1138 bits = []
1139 for idx in range(32):
1140 bit = int(self[idx])
1141 bits.append(bit)
1142 return "".join(map(str, bits))
1143
1144 def disassemble(self, db,
1145 byteorder="little",
1146 verbosity=Verbosity.NORMAL):
1147 integer = int(self)
1148 if verbosity <= Verbosity.SHORT:
1149 blob = ""
1150 else:
1151 blob = integer.to_bytes(length=4, byteorder=byteorder)
1152 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1153 blob += " "
1154
1155 record = db[self]
1156 if record is None:
1157 yield f"{blob}.long 0x{integer:08x}"
1158 return
1159
1160 operands = tuple(map(_operator.itemgetter(1),
1161 self.dynamic_operands(db=db, verbosity=verbosity)))
1162 if operands:
1163 yield f"{blob}{record.name} {','.join(operands)}"
1164 else:
1165 yield f"{blob}{record.name}"
1166
1167 if verbosity >= Verbosity.VERBOSE:
1168 indent = (" " * 4)
1169 binary = self.binary
1170 spec = self.spec(db=db, prefix="")
1171 yield f"{indent}spec"
1172 yield f"{indent}{indent}{spec}"
1173 yield f"{indent}pcode"
1174 for stmt in record.mdwn.pcode:
1175 yield f"{indent}{indent}{stmt}"
1176 yield f"{indent}binary"
1177 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1178 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1179 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1180 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1181 yield f"{indent}opcodes"
1182 for opcode in record.opcodes:
1183 yield f"{indent}{indent}{opcode!r}"
1184 for operand in record.mdwn.operands:
1185 yield from operand.disassemble(insn=self, record=record,
1186 verbosity=verbosity, indent=indent)
1187 yield ""
1188
1189
1190 class PrefixedInstruction(Instruction):
1191 class Prefix(WordInstruction.remap(range(0, 32))):
1192 pass
1193
1194 class Suffix(WordInstruction.remap(range(32, 64))):
1195 pass
1196
1197 _: _Field = range(64)
1198 prefix: Prefix
1199 suffix: Suffix
1200 po: Suffix.po
1201
1202 @classmethod
1203 def integer(cls, value, byteorder="little"):
1204 return super().integer(bits=64, value=value, byteorder=byteorder)
1205
1206 @classmethod
1207 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1208 def transform(value):
1209 return WordInstruction.integer(value=value,
1210 byteorder=byteorder)[0:32]
1211
1212 (prefix, suffix) = map(transform, (prefix, suffix))
1213 value = _selectconcat(prefix, suffix)
1214
1215 return super().integer(value=value)
1216
1217
1218 class Mode(_Mapping):
1219 _: _Field = range(0, 5)
1220
1221
1222 class Extra(_Mapping):
1223 _: _Field = range(0, 9)
1224
1225
1226 class Extra2(Extra):
1227 idx0: _Field = range(0, 2)
1228 idx1: _Field = range(2, 4)
1229 idx2: _Field = range(4, 6)
1230 idx3: _Field = range(6, 8)
1231
1232 def __getitem__(self, key):
1233 return {
1234 0: self.idx0,
1235 1: self.idx1,
1236 2: self.idx2,
1237 3: self.idx3,
1238 _SVExtra.Idx0: self.idx0,
1239 _SVExtra.Idx1: self.idx1,
1240 _SVExtra.Idx2: self.idx2,
1241 _SVExtra.Idx3: self.idx3,
1242 }[key]
1243
1244 def __setitem__(self, key, value):
1245 self[key].assign(value)
1246
1247
1248 class Extra3(Extra):
1249 idx0: _Field = range(0, 3)
1250 idx1: _Field = range(3, 6)
1251 idx2: _Field = range(6, 9)
1252
1253 def __getitem__(self, key):
1254 return {
1255 0: self.idx0,
1256 1: self.idx1,
1257 2: self.idx2,
1258 _SVExtra.Idx0: self.idx0,
1259 _SVExtra.Idx1: self.idx1,
1260 _SVExtra.Idx2: self.idx2,
1261 }[key]
1262
1263 def __setitem__(self, key, value):
1264 self[key].assign(value)
1265
1266
1267 class BaseRM(_Mapping):
1268 _: _Field = range(24)
1269 mmode: _Field = (0,)
1270 mask: _Field = range(1, 4)
1271 elwidth: _Field = range(4, 6)
1272 ewsrc: _Field = range(6, 8)
1273 subvl: _Field = range(8, 10)
1274 mode: Mode.remap(range(19, 24))
1275 smask: _Field = range(16, 19)
1276
1277 extra: Extra.remap(range(10, 19))
1278 extra2: Extra2.remap(range(10, 19))
1279 extra3: Extra3.remap(range(10, 19))
1280
1281
1282 class NormalRM(BaseRM):
1283 class simple(BaseRM):
1284 """simple mode"""
1285 dz: BaseRM.mode[3]
1286 sz: BaseRM.mode[4]
1287
1288 class smr(Mode):
1289 """scalar reduce mode (mapreduce), SUBVL=1"""
1290 RG: BaseRM.mode[4]
1291
1292 class pmr(Mode):
1293 """parallel reduce mode (mapreduce), SUBVL=1"""
1294 pass
1295
1296 class svmr(Mode):
1297 """subvector reduce mode, SUBVL>1"""
1298 SVM: BaseRM.mode[3]
1299
1300 class pu(Mode):
1301 """Pack/Unpack mode, SUBVL>1"""
1302 SVM: BaseRM.mode[3]
1303
1304 class ffrc1(Mode):
1305 """Rc=1: ffirst CR sel"""
1306 inv: BaseRM.mode[2]
1307 CR: BaseRM.mode[3, 4]
1308
1309 class ffrc0(Mode):
1310 """Rc=0: ffirst z/nonz"""
1311 inv: BaseRM.mode[2]
1312 VLi: BaseRM.mode[3]
1313 RC1: BaseRM.mode[4]
1314
1315 class sat(Mode):
1316 """sat mode: N=0/1 u/s, SUBVL=1"""
1317 N: BaseRM.mode[2]
1318 dz: BaseRM.mode[3]
1319 sz: BaseRM.mode[4]
1320
1321 class satx(Mode):
1322 """sat mode: N=0/1 u/s, SUBVL>1"""
1323 N: BaseRM.mode[2]
1324 zz: BaseRM.mode[3]
1325 dz: BaseRM.mode[3]
1326 sz: BaseRM.mode[3]
1327
1328 class satpu(Mode):
1329 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1330 N: BaseRM.mode[2]
1331 zz: BaseRM.mode[3]
1332 dz: BaseRM.mode[3]
1333 sz: BaseRM.mode[3]
1334
1335 class prrc1(Mode):
1336 """Rc=1: pred-result CR sel"""
1337 inv: BaseRM.mode[2]
1338 CR: BaseRM.mode[3, 4]
1339
1340 class prrc0(Mode):
1341 """Rc=0: pred-result z/nonz"""
1342 inv: BaseRM.mode[2]
1343 zz: BaseRM.mode[3]
1344 RC1: BaseRM.mode[4]
1345 dz: BaseRM.mode[3]
1346 sz: BaseRM.mode[3]
1347
1348 simple: simple
1349 smr: smr
1350 pmr: pmr
1351 svmr: svmr
1352 pu: pu
1353 ffrc1: ffrc1
1354 ffrc0: ffrc0
1355 sat: sat
1356 satx: satx
1357 satpu: satpu
1358 prrc1: prrc1
1359 prrc0: prrc0
1360
1361
1362 class LDSTImmRM(BaseRM):
1363 class simple(Mode):
1364 """simple mode"""
1365 zz: BaseRM.mode[3]
1366 els: BaseRM.mode[4]
1367 dz: BaseRM.mode[3]
1368 sz: BaseRM.mode[3]
1369
1370 class spu(Mode):
1371 """Structured Pack/Unpack"""
1372 zz: BaseRM.mode[3]
1373 els: BaseRM.mode[4]
1374 dz: BaseRM.mode[3]
1375 sz: BaseRM.mode[3]
1376
1377 class ffrc1(Mode):
1378 """Rc=1: ffirst CR sel"""
1379 inv: BaseRM.mode[2]
1380 CR: BaseRM.mode[3, 4]
1381
1382 class ffrc0(Mode):
1383 """Rc=0: ffirst z/nonz"""
1384 inv: BaseRM.mode[2]
1385 els: BaseRM.mode[3]
1386 RC1: BaseRM.mode[4]
1387
1388 class sat(Mode):
1389 """sat mode: N=0/1 u/s"""
1390 N: BaseRM.mode[2]
1391 zz: BaseRM.mode[3]
1392 els: BaseRM.mode[4]
1393 dz: BaseRM.mode[3]
1394 sz: BaseRM.mode[3]
1395
1396 class prrc1(Mode):
1397 """Rc=1: pred-result CR sel"""
1398 inv: BaseRM.mode[2]
1399 CR: BaseRM.mode[3, 4]
1400
1401 class prrc0(Mode):
1402 """Rc=0: pred-result z/nonz"""
1403 inv: BaseRM.mode[2]
1404 els: BaseRM.mode[3]
1405 RC1: BaseRM.mode[4]
1406
1407 simple: simple
1408 spu: spu
1409 ffrc1: ffrc1
1410 ffrc0: ffrc0
1411 sat: sat
1412 prrc1: prrc1
1413 prrc0: prrc0
1414
1415
1416 class LDSTIdxRM(BaseRM):
1417 class simple(Mode):
1418 """simple mode"""
1419 SEA: BaseRM.mode[2]
1420 sz: BaseRM.mode[3]
1421 dz: BaseRM.mode[3]
1422
1423 class stride(Mode):
1424 """strided (scalar only source)"""
1425 SEA: BaseRM.mode[2]
1426 dz: BaseRM.mode[3]
1427 sz: BaseRM.mode[4]
1428
1429 class sat(Mode):
1430 """sat mode: N=0/1 u/s"""
1431 N: BaseRM.mode[2]
1432 dz: BaseRM.mode[3]
1433 sz: BaseRM.mode[4]
1434
1435 class prrc1(Mode):
1436 """Rc=1: pred-result CR sel"""
1437 inv: BaseRM.mode[2]
1438 CR: BaseRM.mode[3, 4]
1439
1440 class prrc0(Mode):
1441 """Rc=0: pred-result z/nonz"""
1442 inv: BaseRM.mode[2]
1443 zz: BaseRM.mode[3]
1444 RC1: BaseRM.mode[4]
1445 dz: BaseRM.mode[3]
1446 sz: BaseRM.mode[3]
1447
1448 simple: simple
1449 stride: stride
1450 sat: sat
1451 prrc1: prrc1
1452 prrc0: prrc0
1453
1454
1455 class CROpRM(BaseRM):
1456 class simple(BaseRM):
1457 """simple mode"""
1458 sz: BaseRM[6]
1459 SNZ: BaseRM[7]
1460 RG: BaseRM[20]
1461 dz: BaseRM[22]
1462
1463 class smr(BaseRM):
1464 """scalar reduce mode (mapreduce), SUBVL=1"""
1465 sz: BaseRM[6]
1466 SNZ: BaseRM[7]
1467 RG: BaseRM[20]
1468
1469 class svmr(BaseRM):
1470 """subvector reduce mode, SUBVL>1"""
1471 zz: BaseRM[6]
1472 SNZ: BaseRM[7]
1473 RG: BaseRM[20]
1474 SVM: BaseRM[22]
1475 dz: BaseRM[6]
1476 sz: BaseRM[6]
1477
1478 class reserved(BaseRM):
1479 """reserved"""
1480 zz: BaseRM[6]
1481 SNZ: BaseRM[7]
1482 RG: BaseRM[20]
1483 dz: BaseRM[6]
1484 sz: BaseRM[6]
1485
1486 class ff3(BaseRM):
1487 """ffirst 3-bit mode"""
1488 zz: BaseRM[6]
1489 SNZ: BaseRM[7]
1490 VLI: BaseRM[20]
1491 inv: BaseRM[21]
1492 CR: BaseRM[22, 23]
1493 dz: BaseRM[6]
1494 sz: BaseRM[6]
1495
1496 class ff5(BaseRM):
1497 """ffirst 5-bit mode"""
1498 zz: BaseRM[6]
1499 SNZ: BaseRM[7]
1500 VLI: BaseRM[20]
1501 inv: BaseRM[21]
1502 dz: BaseRM[22]
1503 dz: BaseRM[6]
1504 sz: BaseRM[6]
1505
1506 simple: simple
1507 smr: smr
1508 svmr: svmr
1509 reserved: reserved
1510 ff3: ff3
1511 ff5: ff5
1512
1513
1514 class BranchBaseRM(BaseRM):
1515 ALL: BaseRM[4]
1516 SNZ: BaseRM[5]
1517 SL: BaseRM[17]
1518 SLu: BaseRM[18]
1519 LRu: BaseRM[22]
1520 sz: BaseRM[23]
1521
1522
1523 class BranchRM(BranchBaseRM):
1524 class simple(BranchBaseRM):
1525 """simple mode"""
1526 pass
1527
1528 class vls(BranchBaseRM):
1529 """VLSET mode"""
1530 VSb: BaseRM[7]
1531 VLI: BaseRM[21]
1532
1533 class ctr(BranchBaseRM):
1534 """CTR-test mode"""
1535 CTi: BaseRM[6]
1536
1537 class ctrvls(vls, ctr):
1538 """CTR-test+VLSET mode"""
1539 pass
1540
1541
1542 class RM(BaseRM):
1543 normal: NormalRM
1544 ldst_imm: LDSTImmRM
1545 ldst_idx: LDSTIdxRM
1546 cr_op: CROpRM
1547
1548
1549 class SVP64Instruction(PrefixedInstruction):
1550 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1551 class Prefix(PrefixedInstruction.Prefix):
1552 id: _Field = (7, 9)
1553 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1554
1555 prefix: Prefix
1556
1557 def record(self, db):
1558 record = db[self.suffix]
1559 if record is None:
1560 raise KeyError(self)
1561 return record
1562
1563 @property
1564 def binary(self):
1565 bits = []
1566 for idx in range(64):
1567 bit = int(self[idx])
1568 bits.append(bit)
1569 return "".join(map(str, bits))
1570
1571 def rm(self, db):
1572 record = self.record(db=db)
1573
1574 Rc = False
1575 if record.mdwn.operands["Rc"] is not None:
1576 Rc = bool(self[record.fields["Rc"]])
1577
1578 record = self.record(db=db)
1579 subvl = self.prefix.rm.subvl
1580 rm = self.prefix.rm
1581
1582 if record.svp64.mode is _SVMode.NORMAL:
1583 rm = rm.normal
1584 if rm.mode[0:2] == 0b00:
1585 if rm.mode[2] == 0b0:
1586 rm = rm.simple
1587 else:
1588 if subvl == 0b00:
1589 if rm.mode[3] == 0b0:
1590 rm = rm.smr
1591 else:
1592 rm = rm.pmr
1593 else:
1594 if rm.mode[4] == 0b0:
1595 rm = rm.svmr
1596 else:
1597 rm = rm.pu
1598 elif rm.mode[0:2] == 0b01:
1599 if Rc:
1600 rm = rm.ffrc1
1601 else:
1602 rm = rm.ffrc0
1603 elif rm.mode[0:2] == 0b10:
1604 if subvl == 0b00:
1605 rm = rm.sat
1606 else:
1607 if rm.mode[4]:
1608 rm = rm.satx
1609 else:
1610 rm = rm.satpu
1611 elif rm.mode[0:2] == 0b11:
1612 if Rc:
1613 rm = rm.prrc1
1614 else:
1615 rm = rm.prrc0
1616
1617 elif record.svp64.mode is _SVMode.LDST_IMM:
1618 rm = rm.ldst_imm
1619 if rm.mode[0:2] == 0b00:
1620 if rm.mode[2] == 0b0:
1621 rm = rm.simple
1622 else:
1623 rm = rm.spu
1624 elif rm.mode[0:2] == 0b01:
1625 if Rc:
1626 rm = rm.ffrc1
1627 else:
1628 rm = rm.ffrc0
1629 elif rm.mode[0:2] == 0b10:
1630 rm = rm.sat
1631 elif rm.mode[0:2] == 0b11:
1632 if Rc:
1633 rm = rm.prrc1
1634 else:
1635 rm = rm.prrc0
1636
1637 elif record.svp64.mode is _SVMode.LDST_IMM:
1638 rm = rm.ldst_idx
1639 if rm.mode[0:2] == 0b00:
1640 rm = rm.simple
1641 elif rm.mode[0:2] == 0b01:
1642 rm = rm.stride
1643 elif rm.mode[0:2] == 0b10:
1644 rm = rm.sat
1645 elif rm.mode[0:2] == 0b11:
1646 if Rc:
1647 rm = rm.prrc1
1648 else:
1649 rm = rm.prrc0
1650
1651 elif record.svp64.mode is _SVMode.CROP:
1652 rm = rm.cr_op
1653 if rm[19] == 0b0:
1654 if rm[21] == 0b0:
1655 rm = rm.simple
1656 else:
1657 if subvl == 0:
1658 rm = rm.smr
1659 else:
1660 if rm[23] == 0b0:
1661 rm = rm.svmr
1662 else:
1663 rm = rm.reserved
1664 else:
1665 regtype = None
1666 for idx in range(0, 4):
1667 for entry in record.svp64.extra[idx]:
1668 if entry.regtype is _SVExtraRegType.DST:
1669 if regtype is not None:
1670 raise ValueError(record.svp64)
1671 regtype = _RegType(entry.reg)
1672 if regtype is _RegType.CR_REG:
1673 rm = rm.ff5
1674 elif regtype is _RegType.CR_BIT:
1675 rm = rm.ff3
1676 else:
1677 raise ValueError(record.svp64)
1678
1679 elif record.svp64.mode is _SVMode.BRANCH:
1680 if rm[19] == 0b0:
1681 if rm[20] == 0b0:
1682 rm = rm.simple
1683 else:
1684 rm = rm.vls
1685 else:
1686 if rm[20] == 0b0:
1687 rm = rm.ctr
1688 else:
1689 rm = rm.ctrvls
1690
1691 else:
1692 raise ValueError(self)
1693
1694 table = {
1695 NormalRM.simple: "normal: simple",
1696 NormalRM.smr: "normal: smr",
1697 NormalRM.pmr: "normal: pmr",
1698 NormalRM.svmr: "normal: svmr",
1699 NormalRM.pu: "normal: pu",
1700 NormalRM.ffrc1: "normal: ffrc1",
1701 NormalRM.ffrc0: "normal: ffrc0",
1702 NormalRM.sat: "normal: sat",
1703 NormalRM.satx: "normal: satx",
1704 NormalRM.satpu: "normal: satpu",
1705 NormalRM.prrc1: "normal: prrc1",
1706 NormalRM.prrc0: "normal: prrc0",
1707 LDSTImmRM.simple: "ld/st imm: simple",
1708 LDSTImmRM.spu: "ld/st imm: spu",
1709 LDSTImmRM.ffrc1: "ld/st imm: ffrc1",
1710 LDSTImmRM.ffrc0: "ld/st imm: ffrc0",
1711 LDSTImmRM.sat: "ld/st imm: sat",
1712 LDSTImmRM.prrc1: "ld/st imm: prrc1",
1713 LDSTImmRM.prrc0: "ld/st imm: prrc0",
1714 LDSTIdxRM.simple: "ld/st idx: simple",
1715 LDSTIdxRM.stride: "ld/st idx: stride",
1716 LDSTIdxRM.sat: "ld/st idx: sat",
1717 LDSTIdxRM.prrc1: "ld/st idx: prrc1",
1718 LDSTIdxRM.prrc0: "ld/st idx: prrc0",
1719 CROpRM.simple: "simple mode",
1720 CROpRM.smr: "scalar reduce mode (mapreduce), SUBVL=1",
1721 CROpRM.svmr: "subvector reduce mode, SUBVL>1",
1722 CROpRM.reserved: "reserved",
1723 CROpRM.ff3: "ffirst 3-bit mode",
1724 CROpRM.ff5: "ffirst 5-bit mode",
1725 BranchRM.simple: "simple mode",
1726 BranchRM.vls: "VLSET mode",
1727 BranchRM.ctr: "CTR-test mode",
1728 BranchRM.ctrvls: "CTR-test+VLSET mode",
1729 }
1730 for (cls, desc) in table.items():
1731 if isinstance(rm, cls):
1732 return (rm, desc)
1733
1734 raise ValueError(self)
1735
1736 def disassemble(self, db,
1737 byteorder="little",
1738 verbosity=Verbosity.NORMAL):
1739 def blob(integer):
1740 if verbosity <= Verbosity.SHORT:
1741 return ""
1742 else:
1743 blob = integer.to_bytes(length=4, byteorder=byteorder)
1744 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1745 return f"{blob} "
1746
1747 blob_prefix = blob(int(self.prefix))
1748 blob_suffix = blob(int(self.suffix))
1749 record = db[self]
1750 if record is None or record.svp64 is None:
1751 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
1752 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
1753 return
1754
1755 operands = tuple(map(_operator.itemgetter(1),
1756 self.dynamic_operands(db=db, verbosity=verbosity)))
1757 if operands:
1758 yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
1759 else:
1760 yield f"{blob_prefix}{record.name}"
1761 if blob_suffix:
1762 yield f"{blob_suffix}"
1763
1764 (rm, rm_desc) = self.rm(db=db)
1765
1766 if verbosity >= Verbosity.VERBOSE:
1767 indent = (" " * 4)
1768 binary = self.binary
1769 spec = self.spec(db=db, prefix="sv.")
1770 yield f"{indent}spec"
1771 yield f"{indent}{indent}{spec}"
1772 yield f"{indent}pcode"
1773 for stmt in record.mdwn.pcode:
1774 yield f"{indent}{indent}{stmt}"
1775 yield f"{indent}binary"
1776 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1777 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1778 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1779 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1780 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1781 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1782 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1783 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1784 yield f"{indent}opcodes"
1785 for opcode in record.opcodes:
1786 yield f"{indent}{indent}{opcode!r}"
1787 for operand in record.mdwn.operands:
1788 yield from operand.disassemble(insn=self, record=record,
1789 verbosity=verbosity, indent=indent)
1790
1791 yield f"{indent}RM"
1792 yield f"{indent}{indent}{rm_desc}"
1793 yield ""
1794
1795
1796 def parse(stream, factory):
1797 def match(entry):
1798 return ("TODO" not in frozenset(entry.values()))
1799
1800 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1801 entries = _csv.DictReader(lines)
1802 entries = filter(match, entries)
1803 return tuple(map(factory, entries))
1804
1805
1806 class MarkdownDatabase:
1807 def __init__(self):
1808 db = {}
1809 for (name, desc) in _ISA():
1810 operands = []
1811 if desc.regs:
1812 (dynamic, *static) = desc.regs
1813 operands.extend(dynamic)
1814 operands.extend(static)
1815 pcode = PCode(iterable=desc.pcode)
1816 operands = Operands(insn=name, iterable=operands)
1817 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
1818
1819 self.__db = db
1820
1821 return super().__init__()
1822
1823 def __iter__(self):
1824 yield from self.__db.items()
1825
1826 def __getitem__(self, key):
1827 return self.__db.__getitem__(key)
1828
1829
1830 class FieldsDatabase:
1831 def __init__(self):
1832 db = {}
1833 df = _DecodeFields()
1834 df.create_specs()
1835 for (form, fields) in df.instrs.items():
1836 if form in {"DQE", "TX"}:
1837 continue
1838 if form == "all":
1839 form = "NONE"
1840 db[_Form[form]] = Fields(fields)
1841
1842 self.__db = db
1843
1844 return super().__init__()
1845
1846 def __getitem__(self, key):
1847 return self.__db.__getitem__(key)
1848
1849
1850 class PPCDatabase:
1851 def __init__(self, root, mdwndb):
1852 # The code below groups the instructions by section:identifier.
1853 # We use the comment as an identifier, there's nothing better.
1854 # The point is to capture different opcodes for the same instruction.
1855 dd = _collections.defaultdict
1856 records = dd(lambda: dd(set))
1857 path = (root / "insndb.csv")
1858 with open(path, "r", encoding="UTF-8") as stream:
1859 for section in parse(stream, Section.CSV):
1860 path = (root / section.path)
1861 opcode_cls = {
1862 section.Mode.INTEGER: IntegerOpcode,
1863 section.Mode.PATTERN: PatternOpcode,
1864 }[section.mode]
1865 factory = _functools.partial(
1866 PPCRecord.CSV, opcode_cls=opcode_cls)
1867 with open(path, "r", encoding="UTF-8") as stream:
1868 for insn in parse(stream, factory):
1869 records[section][insn.comment].add(insn)
1870
1871 db = dd(set)
1872 for (section, group) in records.items():
1873 for records in group.values():
1874 db[section].add(PPCMultiRecord(records))
1875
1876 self.__db = db
1877 self.__mdwndb = mdwndb
1878
1879 return super().__init__()
1880
1881 def __getitem__(self, key):
1882 def exact_match(key, record):
1883 return (key in record.names)
1884
1885 def Rc_match(key, record):
1886 if not key.endswith("."):
1887 return False
1888
1889 if record.Rc is _RCOE.NONE:
1890 return False
1891
1892 return exact_match(key[:-1], record)
1893
1894 def LK_match(key, record):
1895 if not key.endswith("l"):
1896 return False
1897
1898 if "lk" not in record.flags:
1899 return False
1900
1901 return exact_match(key[:-1], record)
1902
1903 def AA_match(key, record):
1904 if not key.endswith("a"):
1905 return False
1906
1907 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1908 return False
1909
1910 if self.__mdwndb[key].operands["AA"] is None:
1911 return False
1912
1913 return (exact_match(key[:-1], record) or
1914 LK_match(key[:-1], record))
1915
1916 for (section, records) in self.__db.items():
1917 for record in records:
1918 if exact_match(key, record):
1919 return (section, record)
1920
1921 for record in records:
1922 if (Rc_match(key, record) or
1923 LK_match(key, record) or
1924 AA_match(key, record)):
1925 return (section, record)
1926
1927 return (None, None)
1928
1929
1930 class SVP64Database:
1931 def __init__(self, root, ppcdb):
1932 db = set()
1933 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1934 for (prefix, _, names) in _os.walk(root):
1935 prefix = _pathlib.Path(prefix)
1936 for name in filter(lambda name: pattern.match(name), names):
1937 path = (prefix / _pathlib.Path(name))
1938 with open(path, "r", encoding="UTF-8") as stream:
1939 db.update(parse(stream, SVP64Record.CSV))
1940
1941 self.__db = {record.name:record for record in db}
1942 self.__ppcdb = ppcdb
1943
1944 return super().__init__()
1945
1946 def __getitem__(self, key):
1947 (_, record) = self.__ppcdb[key]
1948 if record is None:
1949 return None
1950
1951 for name in record.names:
1952 record = self.__db.get(name, None)
1953 if record is not None:
1954 return record
1955
1956 return None
1957
1958
1959 class Database:
1960 def __init__(self, root):
1961 root = _pathlib.Path(root)
1962 mdwndb = MarkdownDatabase()
1963 fieldsdb = FieldsDatabase()
1964 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
1965 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1966
1967 db = set()
1968 names = {}
1969 opcodes = _collections.defaultdict(set)
1970
1971 for (name, mdwn) in mdwndb:
1972 (section, ppc) = ppcdb[name]
1973 if ppc is None:
1974 continue
1975 svp64 = svp64db[name]
1976 fields = fieldsdb[ppc.form]
1977 record = Record(name=name,
1978 section=section, ppc=ppc, svp64=svp64,
1979 mdwn=mdwn, fields=fields)
1980 db.add(record)
1981 names[record.name] = record
1982 PO = section.opcode
1983 if PO is None:
1984 PO = ppc[0].opcode
1985 opcodes[PO.value].add(record)
1986
1987 self.__db = db
1988 self.__names = names
1989 self.__opcodes = opcodes
1990
1991 return super().__init__()
1992
1993 def __repr__(self):
1994 return repr(self.__db)
1995
1996 def __iter__(self):
1997 yield from self.__db
1998
1999 @_functools.lru_cache(maxsize=None)
2000 def __contains__(self, key):
2001 return self.__getitem__(key) is not None
2002
2003 @_functools.lru_cache(maxsize=None)
2004 def __getitem__(self, key):
2005 if isinstance(key, (int, Instruction)):
2006 key = int(key)
2007 XO = int(_SelectableInt(value=int(key), bits=32)[0:6])
2008 for record in self.__opcodes[XO]:
2009 if record.match(key=key):
2010 return record
2011
2012 elif isinstance(key, str):
2013 return self.__names[key]
2014
2015 return None