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