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