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