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