power_insn: support non-zero operands
[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 TargetAddrOperand(RegisterOperand):
689 def disassemble(self, insn, record, field,
690 verbosity=Verbosity.NORMAL, indent=""):
691 span = self.span(record=record)
692 if isinstance(insn, SVP64Instruction):
693 span = tuple(map(lambda bit: (bit + 32), span))
694 value = insn[span]
695
696 if verbosity >= Verbosity.VERBOSE:
697 span = tuple(map(str, span))
698 yield f"{indent}{self.name}"
699 yield f"{indent}{indent}{int(value):0{value.bits}b}00"
700 yield f"{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
701 yield f"{indent}{indent}target_addr = EXTS({field} || 0b00))"
702 else:
703 yield hex(int(_selectconcat(value,
704 _SelectableInt(value=0b00, bits=2))))
705
706
707 class TargetAddrOperandLI(TargetAddrOperand):
708 def span(self, record):
709 return record.fields["LI"]
710
711 def disassemble(self, insn, record,
712 verbosity=Verbosity.NORMAL, indent=""):
713 return super().disassemble(field="LI",
714 insn=insn, record=record,
715 verbosity=verbosity, indent=indent)
716
717
718 class TargetAddrOperandBD(TargetAddrOperand):
719 def span(self, record):
720 return record.fields["BD"]
721
722 def disassemble(self, insn, record,
723 verbosity=Verbosity.NORMAL, indent=""):
724 return super().disassemble(field="BD",
725 insn=insn, record=record,
726 verbosity=verbosity, indent=indent)
727
728
729 class DOperandDX(DynamicOperand):
730 def span(self, record):
731 operands = map(DynamicOperand, ("d0", "d1", "d2"))
732 spans = map(lambda operand: operand.span(record=record), operands)
733 return sum(spans, tuple())
734
735 def disassemble(self, insn, record,
736 verbosity=Verbosity.NORMAL, indent=""):
737 span = self.span(record=record)
738 if isinstance(insn, SVP64Instruction):
739 span = tuple(map(lambda bit: (bit + 32), span))
740 value = insn[span]
741
742 if verbosity >= Verbosity.VERBOSE:
743 yield f"{indent}D"
744 mapping = {
745 "d0": "[0:9]",
746 "d1": "[10:15]",
747 "d2": "[16]",
748 }
749 for (subname, subspan) in mapping.items():
750 operand = DynamicOperand(name=subname)
751 span = operand.span(record=record)
752 if isinstance(insn, SVP64Instruction):
753 span = tuple(map(lambda bit: (bit + 32), span))
754 value = insn[span]
755 span = map(str, span)
756 yield f"{indent}{indent}{operand.name} = D{subspan}"
757 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
758 yield f"{indent}{indent}{indent}{', '.join(span)}"
759 else:
760 yield str(int(value))
761
762
763 class Operands(tuple):
764 def __new__(cls, insn, iterable):
765 custom_insns = {
766 "b": {"target_addr": TargetAddrOperandLI},
767 "ba": {"target_addr": TargetAddrOperandLI},
768 "bl": {"target_addr": TargetAddrOperandLI},
769 "bla": {"target_addr": TargetAddrOperandLI},
770 "bc": {"target_addr": TargetAddrOperandBD},
771 "bca": {"target_addr": TargetAddrOperandBD},
772 "bcl": {"target_addr": TargetAddrOperandBD},
773 "bcla": {"target_addr": TargetAddrOperandBD},
774 "addpcis": {"D": DOperandDX},
775 "fishmv": {"D": DOperandDX},
776 "fmvis": {"D": DOperandDX},
777 }
778 custom_fields = {
779 "SVi": NonZeroOperand,
780 "SVd": NonZeroOperand,
781 "SVxd": NonZeroOperand,
782 "SVyd": NonZeroOperand,
783 "SVzd": NonZeroOperand,
784 }
785
786 operands = []
787 for operand in iterable:
788 dynamic_cls = DynamicOperand
789 static_cls = StaticOperand
790
791 if "=" in operand:
792 (name, value) = operand.split("=")
793 operand = static_cls(name=name, value=int(value))
794 operands.append(operand)
795 else:
796 if operand.endswith(")"):
797 operand = operand.replace("(", " ").replace(")", "")
798 (immediate, _, operand) = operand.partition(" ")
799 else:
800 immediate = None
801
802 if immediate is not None:
803 operands.append(ImmediateOperand(name=immediate))
804
805 if insn in custom_insns and operand in custom_insns[insn]:
806 dynamic_cls = custom_insns[insn][operand]
807 if operand in custom_fields:
808 dynamic_cls = custom_fields[operand]
809
810 if operand in _RegType.__members__:
811 regtype = _RegType[operand]
812 if regtype is _RegType.GPR:
813 dynamic_cls = GPROperand
814 elif regtype is _RegType.FPR:
815 dynamic_cls = FPROperand
816
817 operand = dynamic_cls(name=operand)
818 operands.append(operand)
819
820 return super().__new__(cls, operands)
821
822 def __contains__(self, key):
823 return self.__getitem__(key) is not None
824
825 def __getitem__(self, key):
826 for operand in self:
827 if operand.name == key:
828 return operand
829
830 return None
831
832 @property
833 def dynamic(self):
834 for operand in self:
835 if isinstance(operand, DynamicOperand):
836 yield operand
837
838 @property
839 def static(self):
840 for operand in self:
841 if isinstance(operand, StaticOperand):
842 yield operand
843
844
845 @_functools.total_ordering
846 @_dataclasses.dataclass(eq=True, frozen=True)
847 class Record:
848 name: str
849 section: Section
850 ppc: PPCRecord
851 fields: Fields
852 operands: Operands
853 svp64: SVP64Record = None
854
855 def __lt__(self, other):
856 if not isinstance(other, Record):
857 return NotImplemented
858 return (self.opcode < other.opcode)
859
860 @cached_property
861 def opcode(self):
862 value = ([0] * 32)
863 mask = ([0] * 32)
864
865 if self.section.opcode:
866 for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
867 value[dst] = ((self.section.opcode.value & (1 << src)) != 0)
868 mask[dst] = ((self.section.opcode.mask & (1 << src)) != 0)
869
870 for (src, dst) in enumerate(reversed(self.section.bitsel)):
871 value[dst] = ((self.ppc.opcode.value & (1 << src)) != 0)
872 mask[dst] = ((self.ppc.opcode.mask & (1 << src)) != 0)
873
874 for operand in self.operands.static:
875 for (src, dst) in enumerate(reversed(operand.span(record=self))):
876 value[dst] = ((operand.value & (1 << src)) != 0)
877 mask[dst] = True
878
879 for operand in self.operands.dynamic:
880 for dst in operand.span(record=self):
881 value[dst] = False
882 mask[dst] = False
883
884 def onebit(bit):
885 return _SelectableInt(value=int(bit), bits=1)
886
887 value = _selectconcat(*map(onebit, value))
888 mask = _selectconcat(*map(onebit, mask))
889
890 value = int(value)
891 mask = int(mask)
892
893 return Opcode(value=value, mask=mask)
894
895 @property
896 def function(self):
897 return self.ppc.function
898
899 @property
900 def in1(self):
901 return self.ppc.in1
902
903 @property
904 def in2(self):
905 return self.ppc.in2
906
907 @property
908 def in3(self):
909 return self.ppc.in3
910
911 @property
912 def out(self):
913 return self.ppc.out
914
915 @property
916 def out2(self):
917 if self.svp64 is None:
918 return _OutSel.NONE
919 return self.ppc.out
920
921 @property
922 def cr_in(self):
923 return self.ppc.cr_in
924
925 @property
926 def cr_out(self):
927 return self.ppc.cr_out
928
929 ptype = property(lambda self: self.svp64.ptype)
930 etype = property(lambda self: self.svp64.etype)
931
932 def extra_idx(self, key):
933 return self.svp64.extra_idx(key)
934
935 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
936 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
937 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
938 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
939 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
940 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
941 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
942
943
944 class Instruction(_Mapping):
945 @classmethod
946 def integer(cls, value=0, bits=None, byteorder="little"):
947 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
948 raise ValueError(bits)
949
950 if isinstance(value, bytes):
951 if ((len(value) * 8) != bits):
952 raise ValueError(f"bit length mismatch")
953 value = int.from_bytes(value, byteorder=byteorder)
954
955 if isinstance(value, int):
956 value = _SelectableInt(value=value, bits=bits)
957 elif isinstance(value, Instruction):
958 value = value.storage
959
960 if not isinstance(value, _SelectableInt):
961 raise ValueError(value)
962 if bits is None:
963 bits = len(cls)
964 if len(value) != bits:
965 raise ValueError(value)
966
967 value = _SelectableInt(value=value, bits=bits)
968
969 return cls(storage=value)
970
971 def __hash__(self):
972 return hash(int(self))
973
974 def record(self, db):
975 record = db[self]
976 if record is None:
977 raise KeyError(self)
978 return record
979
980 def spec(self, db, prefix):
981 record = self.record(db=db)
982
983 dynamic_operands = tuple(map(_operator.itemgetter(0),
984 self.dynamic_operands(db=db)))
985
986 static_operands = []
987 for (name, value) in self.static_operands(db=db):
988 static_operands.append(f"{name}={value}")
989
990 operands = ""
991 if dynamic_operands:
992 operands += f" {','.join(dynamic_operands)}"
993 if static_operands:
994 operands += f" ({' '.join(static_operands)})"
995
996 return f"{prefix}{record.name}{operands}"
997
998 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
999 record = self.record(db=db)
1000
1001 imm = False
1002 imm_name = ""
1003 imm_value = ""
1004 for operand in record.operands.dynamic:
1005 name = operand.name
1006 dis = operand.disassemble(insn=self, record=record,
1007 verbosity=min(verbosity, Verbosity.NORMAL))
1008 value = " ".join(dis)
1009 if imm:
1010 name = f"{imm_name}({name})"
1011 value = f"{imm_value}({value})"
1012 imm = False
1013 if isinstance(operand, ImmediateOperand):
1014 imm_name = name
1015 imm_value = value
1016 imm = True
1017 if not imm:
1018 yield (name, value)
1019
1020 def static_operands(self, db):
1021 record = self.record(db=db)
1022 for operand in record.operands.static:
1023 yield (operand.name, operand.value)
1024
1025 def disassemble(self, db,
1026 byteorder="little",
1027 verbosity=Verbosity.NORMAL):
1028 raise NotImplementedError
1029
1030
1031 class WordInstruction(Instruction):
1032 _: _Field = range(0, 32)
1033 po: _Field = range(0, 6)
1034
1035 @classmethod
1036 def integer(cls, value, byteorder="little"):
1037 return super().integer(bits=32, value=value, byteorder=byteorder)
1038
1039 @property
1040 def binary(self):
1041 bits = []
1042 for idx in range(32):
1043 bit = int(self[idx])
1044 bits.append(bit)
1045 return "".join(map(str, bits))
1046
1047 def opcode(self, db):
1048 record = self.record(db=db)
1049 return f"0x{record.opcode.value:08x}"
1050
1051 def mask(self, db):
1052 record = self.record(db=db)
1053 return f"0x{record.opcode.mask:08x}"
1054
1055 def disassemble(self, db,
1056 byteorder="little",
1057 verbosity=Verbosity.NORMAL):
1058 integer = int(self)
1059 if verbosity <= Verbosity.SHORT:
1060 blob = ""
1061 else:
1062 blob = integer.to_bytes(length=4, byteorder=byteorder)
1063 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1064 blob += " "
1065
1066 record = db[self]
1067 if record is None:
1068 yield f"{blob}.long 0x{integer:08x}"
1069 return
1070
1071 operands = tuple(map(_operator.itemgetter(1),
1072 self.dynamic_operands(db=db, verbosity=verbosity)))
1073 if operands:
1074 yield f"{blob}{record.name} {','.join(operands)}"
1075 else:
1076 yield f"{blob}{record.name}"
1077
1078 if verbosity >= Verbosity.VERBOSE:
1079 indent = (" " * 4)
1080 binary = self.binary
1081 spec = self.spec(db=db, prefix="")
1082 opcode = self.opcode(db=db)
1083 mask = self.mask(db=db)
1084 yield f"{indent}spec"
1085 yield f"{indent}{indent}{spec}"
1086 yield f"{indent}binary"
1087 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1088 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1089 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1090 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1091 yield f"{indent}opcode"
1092 yield f"{indent}{indent}{opcode}"
1093 yield f"{indent}mask"
1094 yield f"{indent}{indent}{mask}"
1095 for operand in record.operands:
1096 yield from operand.disassemble(insn=self, record=record,
1097 verbosity=verbosity, indent=indent)
1098 yield ""
1099
1100
1101 class PrefixedInstruction(Instruction):
1102 class Prefix(WordInstruction.remap(range(0, 32))):
1103 pass
1104
1105 class Suffix(WordInstruction.remap(range(32, 64))):
1106 pass
1107
1108 _: _Field = range(64)
1109 prefix: Prefix
1110 suffix: Suffix
1111 po: Suffix.po
1112
1113 @classmethod
1114 def integer(cls, value, byteorder="little"):
1115 return super().integer(bits=64, value=value, byteorder=byteorder)
1116
1117 @classmethod
1118 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1119 def transform(value):
1120 return WordInstruction.integer(value=value,
1121 byteorder=byteorder)[0:32]
1122
1123 (prefix, suffix) = map(transform, (prefix, suffix))
1124 value = _selectconcat(prefix, suffix)
1125
1126 return super().integer(value=value)
1127
1128
1129 class Mode(_Mapping):
1130 _: _Field = range(0, 5)
1131 sel: _Field = range(0, 2)
1132
1133
1134 class NormalMode(Mode):
1135 class simple(Mode):
1136 """simple mode"""
1137 dz: Mode[3]
1138 sz: Mode[4]
1139
1140 class smr(Mode):
1141 """scalar reduce mode (mapreduce), SUBVL=1"""
1142 RG: Mode[4]
1143
1144 class pmr(Mode):
1145 """parallel reduce mode (mapreduce), SUBVL=1"""
1146 pass
1147
1148 class svmr(Mode):
1149 """subvector reduce mode, SUBVL>1"""
1150 SVM: Mode[3]
1151
1152 class pu(Mode):
1153 """Pack/Unpack mode, SUBVL>1"""
1154 SVM: Mode[3]
1155
1156 class ffrc1(Mode):
1157 """Rc=1: ffirst CR sel"""
1158 inv: Mode[2]
1159 CRbit: Mode[3, 4]
1160
1161 class ffrc0(Mode):
1162 """Rc=0: ffirst z/nonz"""
1163 inv: Mode[2]
1164 VLi: Mode[3]
1165 RC1: Mode[4]
1166
1167 class sat(Mode):
1168 """sat mode: N=0/1 u/s, SUBVL=1"""
1169 N: Mode[2]
1170 dz: Mode[3]
1171 sz: Mode[4]
1172
1173 class satx(Mode):
1174 """sat mode: N=0/1 u/s, SUBVL>1"""
1175 N: Mode[2]
1176 zz: Mode[3]
1177 dz: Mode[3]
1178 sz: Mode[3]
1179
1180 class satpu(Mode):
1181 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1182 N: Mode[2]
1183 zz: Mode[3]
1184 dz: Mode[3]
1185 sz: Mode[3]
1186
1187 class prrc1(Mode):
1188 """Rc=1: pred-result CR sel"""
1189 inv: Mode[2]
1190 CRbit: Mode[3, 4]
1191
1192 class prrc0(Mode):
1193 """Rc=0: pred-result z/nonz"""
1194 inv: Mode[2]
1195 zz: Mode[3]
1196 RC1: Mode[4]
1197 dz: Mode[3]
1198 sz: Mode[3]
1199
1200 simple: simple
1201 smr: smr
1202 pmr: pmr
1203 svmr: svmr
1204 pu: pu
1205 ffrc1: ffrc1
1206 ffrc0: ffrc0
1207 sat: sat
1208 satx: satx
1209 satpu: satpu
1210 prrc1: prrc1
1211 prrc0: prrc0
1212
1213
1214 class LDSTImmMode(Mode):
1215 class simple(Mode):
1216 """simple mode"""
1217 zz: Mode[3]
1218 els: Mode[4]
1219 dz: Mode[3]
1220 sz: Mode[3]
1221
1222 class spu(Mode):
1223 """Structured Pack/Unpack"""
1224 zz: Mode[3]
1225 els: Mode[4]
1226 dz: Mode[3]
1227 sz: Mode[3]
1228
1229 class ffrc1(Mode):
1230 """Rc=1: ffirst CR sel"""
1231 inv: Mode[2]
1232 CRbit: Mode[3, 4]
1233
1234 class ffrc0(Mode):
1235 """Rc=0: ffirst z/nonz"""
1236 inv: Mode[2]
1237 els: Mode[3]
1238 RC1: Mode[4]
1239
1240 class sat(Mode):
1241 """sat mode: N=0/1 u/s"""
1242 N: Mode[2]
1243 zz: Mode[3]
1244 els: Mode[4]
1245 dz: Mode[3]
1246 sz: Mode[3]
1247
1248 class prrc1(Mode):
1249 """Rc=1: pred-result CR sel"""
1250 inv: Mode[2]
1251 CRbit: Mode[3, 4]
1252
1253 class prrc0(Mode):
1254 """Rc=0: pred-result z/nonz"""
1255 inv: Mode[2]
1256 els: Mode[3]
1257 RC1: Mode[4]
1258
1259 simple: simple
1260 spu: spu
1261 ffrc1: ffrc1
1262 ffrc0: ffrc0
1263 sat: sat
1264 prrc1: prrc1
1265 prrc0: prrc0
1266
1267
1268 class LDSTIdxMode(Mode):
1269 class simple(Mode):
1270 """simple mode"""
1271 SEA: Mode[2]
1272 sz: Mode[3]
1273 dz: Mode[3]
1274
1275 class stride(Mode):
1276 """strided (scalar only source)"""
1277 SEA: Mode[2]
1278 dz: Mode[3]
1279 sz: Mode[4]
1280
1281 class sat(Mode):
1282 """sat mode: N=0/1 u/s"""
1283 N: Mode[2]
1284 dz: Mode[3]
1285 sz: Mode[4]
1286
1287 class prrc1(Mode):
1288 """Rc=1: pred-result CR sel"""
1289 inv: Mode[2]
1290 CRbit: Mode[3, 4]
1291
1292 class prrc0(Mode):
1293 """Rc=0: pred-result z/nonz"""
1294 inv: Mode[2]
1295 zz: Mode[3]
1296 RC1: Mode[4]
1297 dz: Mode[3]
1298 sz: Mode[3]
1299
1300 simple: simple
1301 stride: stride
1302 sat: sat
1303 prrc1: prrc1
1304 prrc0: prrc0
1305
1306
1307 class Extra(_Mapping):
1308 _: _Field = range(0, 9)
1309
1310
1311 class Extra2(Extra):
1312 idx0: _Field = range(0, 2)
1313 idx1: _Field = range(2, 4)
1314 idx2: _Field = range(4, 6)
1315 idx3: _Field = range(6, 8)
1316
1317 def __getitem__(self, key):
1318 return {
1319 0: self.idx0,
1320 1: self.idx1,
1321 2: self.idx2,
1322 3: self.idx3,
1323 _SVExtra.Idx0: self.idx0,
1324 _SVExtra.Idx1: self.idx1,
1325 _SVExtra.Idx2: self.idx2,
1326 _SVExtra.Idx3: self.idx3,
1327 }[key]
1328
1329 def __setitem__(self, key, value):
1330 self[key].assign(value)
1331
1332
1333 class Extra3(Extra):
1334 idx0: _Field = range(0, 3)
1335 idx1: _Field = range(3, 6)
1336 idx2: _Field = range(6, 9)
1337
1338 def __getitem__(self, key):
1339 return {
1340 0: self.idx0,
1341 1: self.idx1,
1342 2: self.idx2,
1343 _SVExtra.Idx0: self.idx0,
1344 _SVExtra.Idx1: self.idx1,
1345 _SVExtra.Idx2: self.idx2,
1346 }[key]
1347
1348 def __setitem__(self, key, value):
1349 self[key].assign(value)
1350
1351
1352 class RM(_Mapping):
1353 class Mode(Mode):
1354 normal: NormalMode
1355 ldst_imm: LDSTImmMode
1356 ldst_idx: LDSTIdxMode
1357
1358 _: _Field = range(24)
1359 mmode: _Field = (0,)
1360 mask: _Field = range(1, 4)
1361 elwidth: _Field = range(4, 6)
1362 ewsrc: _Field = range(6, 8)
1363 subvl: _Field = range(8, 10)
1364 mode: Mode.remap(range(19, 24))
1365 smask: _Field = range(16, 19)
1366
1367 extra: Extra.remap(range(10, 19))
1368 extra2: Extra2.remap(range(10, 19))
1369 extra3: Extra3.remap(range(10, 19))
1370
1371
1372 class SVP64Instruction(PrefixedInstruction):
1373 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1374 class Prefix(PrefixedInstruction.Prefix):
1375 id: _Field = (7, 9)
1376 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1377
1378 prefix: Prefix
1379
1380 @property
1381 def binary(self):
1382 bits = []
1383 for idx in range(64):
1384 bit = int(self[idx])
1385 bits.append(bit)
1386 return "".join(map(str, bits))
1387
1388 def opcode(self, db):
1389 return self.suffix.opcode(db=db)
1390
1391 def mask(self, db):
1392 return self.suffix.mask(db=db)
1393
1394 def mode(self, db):
1395 record = self.record(db=db)
1396
1397 Rc = False
1398 if record.operands["Rc"] is not None:
1399 Rc = bool(self[record.fields["Rc"]])
1400
1401 record = self.record(db=db)
1402 subvl = self.prefix.rm.subvl
1403 mode = self.prefix.rm.mode
1404 sel = mode.sel
1405
1406 if record.svp64.mode is _SVMode.NORMAL:
1407 mode = mode.normal
1408 if sel == 0b00:
1409 if mode[2] == 0b0:
1410 mode = mode.simple
1411 else:
1412 if subvl == 0b00:
1413 if mode[3] == 0b0:
1414 mode = mode.smr
1415 else:
1416 mode = mode.pmr
1417 else:
1418 if mode[4] == 0b0:
1419 mode = mode.svmr
1420 else:
1421 mode = mode.pu
1422 elif sel == 0b01:
1423 if Rc:
1424 mode = mode.ffrc1
1425 else:
1426 mode = mode.ffrc0
1427 elif sel == 0b10:
1428 if subvl == 0b00:
1429 mode = mode.sat
1430 else:
1431 if mode[4]:
1432 mode = mode.satx
1433 else:
1434 mode = mode.satpu
1435 elif sel == 0b11:
1436 if Rc:
1437 mode = mode.prrc1
1438 else:
1439 mode = mode.prrc0
1440 elif record.svp64.mode is _SVMode.LDST_IMM:
1441 mode = mode.ldst_imm
1442 if sel == 0b00:
1443 if mode[2] == 0b0:
1444 mode = mode.simple
1445 else:
1446 mode = mode.spu
1447 elif sel == 0b01:
1448 if Rc:
1449 mode = mode.ffrc1
1450 else:
1451 mode = mode.ffrc0
1452 elif sel == 0b10:
1453 mode = mode.sat
1454 elif sel == 0b11:
1455 if Rc:
1456 mode = mode.prrc1
1457 else:
1458 mode = mode.prrc0
1459 elif record.svp64.mode is _SVMode.LDST_IMM:
1460 mode = mode.ldst_idx
1461 if mode.sel == 0b00:
1462 mode = mode.simple
1463 elif mode.sel == 0b01:
1464 mode = mode.stride
1465 elif mode.sel == 0b10:
1466 mode = mode.sat
1467 elif mode.sel == 0b11:
1468 if Rc:
1469 mode = mode.prrc1
1470 else:
1471 mode = mode.prrc0
1472
1473 modes = {
1474 NormalMode.simple: "normal: simple",
1475 NormalMode.smr: "normal: smr",
1476 NormalMode.pmr: "normal: pmr",
1477 NormalMode.svmr: "normal: svmr",
1478 NormalMode.pu: "normal: pu",
1479 NormalMode.ffrc1: "normal: ffrc1",
1480 NormalMode.ffrc0: "normal: ffrc0",
1481 NormalMode.sat: "normal: sat",
1482 NormalMode.satx: "normal: satx",
1483 NormalMode.satpu: "normal: satpu",
1484 NormalMode.prrc1: "normal: prrc1",
1485 NormalMode.prrc0: "normal: prrc0",
1486 LDSTImmMode.simple: "ld/st imm: simple",
1487 LDSTImmMode.spu: "ld/st imm: spu",
1488 LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
1489 LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
1490 LDSTImmMode.sat: "ld/st imm: sat",
1491 LDSTImmMode.prrc1: "ld/st imm: prrc1",
1492 LDSTImmMode.prrc0: "ld/st imm: prrc0",
1493 LDSTIdxMode.simple: "ld/st idx simple",
1494 LDSTIdxMode.stride: "ld/st idx stride",
1495 LDSTIdxMode.sat: "ld/st idx sat",
1496 LDSTIdxMode.prrc1: "ld/st idx prrc1",
1497 LDSTIdxMode.prrc0: "ld/st idx prrc0",
1498 }
1499 for (cls, desc) in modes.items():
1500 if isinstance(mode, cls):
1501 return (mode, desc)
1502
1503 if record.svp64.mode is _SVMode.BRANCH:
1504 return (self.prefix.rm.mode, "branch")
1505
1506 raise ValueError(self)
1507
1508 def disassemble(self, db,
1509 byteorder="little",
1510 verbosity=Verbosity.NORMAL):
1511 def blob(integer):
1512 if verbosity <= Verbosity.SHORT:
1513 return ""
1514 else:
1515 blob = integer.to_bytes(length=4, byteorder=byteorder)
1516 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1517 return f"{blob} "
1518
1519 blob_prefix = blob(int(self.prefix))
1520 blob_suffix = blob(int(self.suffix))
1521 record = db[self]
1522 if record is None or record.svp64 is None:
1523 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
1524 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
1525 return
1526
1527 operands = tuple(map(_operator.itemgetter(1),
1528 self.dynamic_operands(db=db, verbosity=verbosity)))
1529 if operands:
1530 yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
1531 else:
1532 yield f"{blob_prefix}{record.name}"
1533 if blob_suffix:
1534 yield f"{blob_suffix}"
1535
1536 (mode, mode_desc) = self.mode(db=db)
1537
1538 if verbosity >= Verbosity.VERBOSE:
1539 indent = (" " * 4)
1540 binary = self.binary
1541 spec = self.spec(db=db, prefix="sv.")
1542 opcode = self.opcode(db=db)
1543 mask = self.mask(db=db)
1544 yield f"{indent}spec"
1545 yield f"{indent}{indent}{spec}"
1546 yield f"{indent}binary"
1547 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1548 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1549 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1550 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1551 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1552 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1553 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1554 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1555 yield f"{indent}opcode"
1556 yield f"{indent}{indent}{opcode}"
1557 yield f"{indent}mask"
1558 yield f"{indent}{indent}{mask}"
1559 for operand in record.operands:
1560 yield from operand.disassemble(insn=self, record=record,
1561 verbosity=verbosity, indent=indent)
1562
1563 yield f"{indent}mode"
1564 yield f"{indent}{indent}{mode_desc}"
1565 yield ""
1566
1567
1568 def parse(stream, factory):
1569 def match(entry):
1570 return ("TODO" not in frozenset(entry.values()))
1571
1572 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1573 entries = _csv.DictReader(lines)
1574 entries = filter(match, entries)
1575 return tuple(map(factory, entries))
1576
1577
1578 class MarkdownDatabase:
1579 def __init__(self):
1580 db = {}
1581 for (name, desc) in _ISA():
1582 operands = []
1583 if desc.regs:
1584 (dynamic, *static) = desc.regs
1585 operands.extend(dynamic)
1586 operands.extend(static)
1587 db[name] = Operands(insn=name, iterable=operands)
1588 self.__db = db
1589 return super().__init__()
1590
1591 def __iter__(self):
1592 yield from self.__db.items()
1593
1594 def __getitem__(self, key):
1595 return self.__db.__getitem__(key)
1596
1597
1598 class FieldsDatabase:
1599 def __init__(self):
1600 db = {}
1601 df = _DecodeFields()
1602 df.create_specs()
1603 for (form, fields) in df.instrs.items():
1604 if form in {"DQE", "TX"}:
1605 continue
1606 if form == "all":
1607 form = "NONE"
1608 db[_Form[form]] = Fields(fields)
1609
1610 self.__db = db
1611
1612 return super().__init__()
1613
1614 def __getitem__(self, key):
1615 return self.__db.__getitem__(key)
1616
1617
1618 class PPCDatabase:
1619 def __init__(self, root, mdwndb):
1620 # The code below groups the instructions by section:identifier.
1621 # We use the comment as an identifier, there's nothing better.
1622 # The point is to capture different opcodes for the same instruction.
1623 dd = _collections.defaultdict
1624 records = dd(lambda: dd(set))
1625 path = (root / "insndb.csv")
1626 with open(path, "r", encoding="UTF-8") as stream:
1627 for section in parse(stream, Section.CSV):
1628 path = (root / section.path)
1629 opcode_cls = {
1630 section.Mode.INTEGER: IntegerOpcode,
1631 section.Mode.PATTERN: PatternOpcode,
1632 }[section.mode]
1633 factory = _functools.partial(
1634 PPCRecord.CSV, opcode_cls=opcode_cls)
1635 with open(path, "r", encoding="UTF-8") as stream:
1636 for insn in parse(stream, factory):
1637 records[section][insn.comment].add(insn)
1638
1639 db = dd(set)
1640 for (section, group) in records.items():
1641 for records in group.values():
1642 db[section].add(PPCMultiRecord(records))
1643
1644 self.__db = db
1645 self.__mdwndb = mdwndb
1646
1647 return super().__init__()
1648
1649 def __getitem__(self, key):
1650 def exact_match(key, record):
1651 for name in record.names:
1652 if name == key:
1653 return True
1654
1655 return False
1656
1657 def Rc_match(key, record):
1658 if not key.endswith("."):
1659 return False
1660
1661 if not record.Rc is _RCOE.RC:
1662 return False
1663
1664 return exact_match(key[:-1], record)
1665
1666 def LK_match(key, record):
1667 if not key.endswith("l"):
1668 return False
1669
1670 if "lk" not in record.flags:
1671 return False
1672
1673 return exact_match(key[:-1], record)
1674
1675 def AA_match(key, record):
1676 if not key.endswith("a"):
1677 return False
1678
1679 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1680 return False
1681
1682 if self.__mdwndb[key]["AA"] is None:
1683 return False
1684
1685 return (exact_match(key[:-1], record) or
1686 LK_match(key[:-1], record))
1687
1688 for (section, records) in self.__db.items():
1689 for record in records:
1690 if exact_match(key, record):
1691 return (section, record)
1692
1693 for record in records:
1694 if (Rc_match(key, record) or
1695 LK_match(key, record) or
1696 AA_match(key, record)):
1697 return (section, record)
1698
1699 return (None, None)
1700
1701
1702 class SVP64Database:
1703 def __init__(self, root, ppcdb):
1704 db = set()
1705 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1706 for (prefix, _, names) in _os.walk(root):
1707 prefix = _pathlib.Path(prefix)
1708 for name in filter(lambda name: pattern.match(name), names):
1709 path = (prefix / _pathlib.Path(name))
1710 with open(path, "r", encoding="UTF-8") as stream:
1711 db.update(parse(stream, SVP64Record.CSV))
1712
1713 self.__db = {record.name:record for record in db}
1714 self.__ppcdb = ppcdb
1715
1716 return super().__init__()
1717
1718 def __getitem__(self, key):
1719 (_, record) = self.__ppcdb[key]
1720 if record is None:
1721 return None
1722
1723 for name in record.names:
1724 record = self.__db.get(name, None)
1725 if record is not None:
1726 return record
1727
1728 return None
1729
1730
1731 class Database:
1732 def __init__(self, root):
1733 root = _pathlib.Path(root)
1734
1735 mdwndb = MarkdownDatabase()
1736 fieldsdb = FieldsDatabase()
1737 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
1738 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1739
1740 db = set()
1741 for (name, operands) in mdwndb:
1742 (section, ppc) = ppcdb[name]
1743 if ppc is None:
1744 continue
1745 svp64 = svp64db[name]
1746 fields = fieldsdb[ppc.form]
1747 record = Record(name=name,
1748 section=section, ppc=ppc, svp64=svp64,
1749 operands=operands, fields=fields)
1750 db.add(record)
1751
1752 self.__db = tuple(sorted(db))
1753
1754 return super().__init__()
1755
1756 def __repr__(self):
1757 return repr(self.__db)
1758
1759 def __iter__(self):
1760 yield from self.__db
1761
1762 @_functools.lru_cache(maxsize=None)
1763 def __contains__(self, key):
1764 return self.__getitem__(key) is not None
1765
1766 @_functools.lru_cache(maxsize=None)
1767 def __getitem__(self, key):
1768 if isinstance(key, (int, Instruction)):
1769 key = int(key)
1770 matches = []
1771 for record in self:
1772 opcode = record.opcode
1773 if ((opcode.value & opcode.mask) ==
1774 (key & opcode.mask)):
1775 matches.append(record)
1776 if matches:
1777 return matches[-1]
1778 return None
1779 elif isinstance(key, Opcode):
1780 for record in self:
1781 if record.opcode == key:
1782 return record
1783 elif isinstance(key, str):
1784 for record in self:
1785 if record.name == key:
1786 return record
1787 return None