power_insn: disable disassembly for prefixed instructions
[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 pathlib as _pathlib
8 import re as _re
9
10 try:
11 from functools import cached_property
12 except ImportError:
13 from cached_property import cached_property
14
15 from openpower.decoder.power_enums import (
16 Function as _Function,
17 MicrOp as _MicrOp,
18 In1Sel as _In1Sel,
19 In2Sel as _In2Sel,
20 In3Sel as _In3Sel,
21 OutSel as _OutSel,
22 CRInSel as _CRInSel,
23 CROutSel as _CROutSel,
24 LDSTLen as _LDSTLen,
25 LDSTMode as _LDSTMode,
26 RCOE as _RCOE,
27 CryIn as _CryIn,
28 Form as _Form,
29 SVEtype as _SVEtype,
30 SVMode as _SVMode,
31 SVPtype as _SVPtype,
32 SVExtra as _SVExtra,
33 RegType as _RegType,
34 SVExtraRegType as _SVExtraRegType,
35 SVExtraReg as _SVExtraReg,
36 )
37 from openpower.decoder.selectable_int import (
38 SelectableInt as _SelectableInt,
39 selectconcat as _selectconcat,
40 )
41 from openpower.decoder.power_fields import (
42 Field as _Field,
43 Mapping as _Mapping,
44 DecodeFields as _DecodeFields,
45 )
46 from openpower.decoder.pseudo.pagereader import ISA as _ISA
47
48
49 def dataclass(cls, record, keymap=None, typemap=None):
50 if keymap is None:
51 keymap = {}
52 if typemap is None:
53 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
54
55 def transform(key_value):
56 (key, value) = key_value
57 key = keymap.get(key, key)
58 hook = typemap.get(key, lambda value: value)
59 if hook is bool and value in ("", "0"):
60 value = False
61 else:
62 value = hook(value)
63 return (key, value)
64
65 record = dict(map(transform, record.items()))
66 for key in frozenset(record.keys()):
67 if record[key] == "":
68 record.pop(key)
69
70 return cls(**record)
71
72
73 @_functools.total_ordering
74 @_dataclasses.dataclass(eq=True, frozen=True)
75 class Opcode:
76 class Value(int):
77 def __repr__(self):
78 if self.bit_length() <= 32:
79 return f"0x{self:08x}"
80 else:
81 return f"0x{self:016x}"
82
83 class Mask(int):
84 def __repr__(self):
85 if self.bit_length() <= 32:
86 return f"0x{self:08x}"
87 else:
88 return f"0x{self:016x}"
89
90 value: Value
91 mask: Mask = None
92
93 def __lt__(self, other):
94 if not isinstance(other, Opcode):
95 return NotImplemented
96 return ((self.value, self.mask) < (other.value, other.mask))
97
98 def __post_init__(self):
99 (value, mask) = (self.value, self.mask)
100
101 if isinstance(value, Opcode):
102 if mask is not None:
103 raise ValueError(mask)
104 (value, mask) = (value.value, value.mask)
105 elif isinstance(value, str):
106 if mask is not None:
107 raise ValueError(mask)
108 value = int(value, 0)
109
110 if not isinstance(value, int):
111 raise ValueError(value)
112 if mask is None:
113 mask = value
114 if not isinstance(mask, int):
115 raise ValueError(mask)
116
117 object.__setattr__(self, "value", self.__class__.Value(value))
118 object.__setattr__(self, "mask", self.__class__.Mask(mask))
119
120
121 class IntegerOpcode(Opcode):
122 def __init__(self, value):
123 if isinstance(value, str):
124 value = int(value, 0)
125 return super().__init__(value=value, mask=None)
126
127
128 class PatternOpcode(Opcode):
129 def __init__(self, value):
130 (pattern, value, mask) = (value, 0, 0)
131
132 for symbol in pattern:
133 if symbol not in {"0", "1", "-"}:
134 raise ValueError(pattern)
135 value |= (symbol == "1")
136 mask |= (symbol != "-")
137 value <<= 1
138 mask <<= 1
139 value >>= 1
140 mask >>= 1
141
142 return super().__init__(value=value, mask=mask)
143
144
145 class FieldsOpcode(Opcode):
146 def __init__(self, fields):
147 def field(opcode, field):
148 (value, mask) = opcode
149 (field, bits) = field
150 shifts = map(lambda bit: (31 - bit), reversed(tuple(bits)))
151 for (index, shift) in enumerate(shifts):
152 bit = ((field & (1 << index)) != 0)
153 value |= (bit << shift)
154 mask |= (1 << shift)
155 return (value, mask)
156
157 (value, mask) = _functools.reduce(field, fields, (0, 0))
158
159 return super().__init__(value=value, mask=mask)
160
161
162 @_dataclasses.dataclass(eq=True, frozen=True)
163 class PPCRecord:
164 class FlagsMeta(type):
165 def __iter__(cls):
166 yield from (
167 "inv A",
168 "inv out",
169 "cry out",
170 "BR",
171 "sgn ext",
172 "rsrv",
173 "32b",
174 "sgn",
175 "lk",
176 "sgl pipe",
177 )
178
179 class Flags(frozenset, metaclass=FlagsMeta):
180 def __new__(cls, flags=frozenset()):
181 flags = frozenset(flags)
182 diff = (flags - frozenset(cls))
183 if diff:
184 raise ValueError(flags)
185 return super().__new__(cls, flags)
186
187 opcode: Opcode
188 comment: str
189 flags: Flags = Flags()
190 comment2: str = ""
191 function: _Function = _Function.NONE
192 intop: _MicrOp = _MicrOp.OP_ILLEGAL
193 in1: _In1Sel = _In1Sel.RA
194 in2: _In2Sel = _In2Sel.NONE
195 in3: _In3Sel = _In3Sel.NONE
196 out: _OutSel = _OutSel.NONE
197 cr_in: _CRInSel = _CRInSel.NONE
198 cr_out: _CROutSel = _CROutSel.NONE
199 cry_in: _CryIn = _CryIn.ZERO
200 ldst_len: _LDSTLen = _LDSTLen.NONE
201 upd: _LDSTMode = _LDSTMode.NONE
202 rc: _RCOE = _RCOE.NONE
203 form: _Form = _Form.NONE
204 conditions: str = ""
205 unofficial: bool = False
206
207 __KEYMAP = {
208 "unit": "function",
209 "internal op": "intop",
210 "CR in": "cr_in",
211 "CR out": "cr_out",
212 "cry in": "cry_in",
213 "ldst len": "ldst_len",
214 "CONDITIONS": "conditions",
215 }
216
217 @classmethod
218 def CSV(cls, record, opcode_cls=Opcode):
219 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
220 typemap["opcode"] = opcode_cls
221
222 flags = set()
223 for flag in frozenset(PPCRecord.Flags):
224 if bool(record.pop(flag, "")):
225 flags.add(flag)
226 record["flags"] = PPCRecord.Flags(flags)
227
228 return dataclass(cls, record, keymap=PPCRecord.__KEYMAP, typemap=typemap)
229
230 @cached_property
231 def names(self):
232 return frozenset(self.comment.split("=")[-1].split("/"))
233
234
235 @_dataclasses.dataclass(eq=True, frozen=True)
236 class SVP64Record:
237 class ExtraMap(tuple):
238 class Extra(tuple):
239 @_dataclasses.dataclass(eq=True, frozen=True)
240 class Entry:
241 regtype: _SVExtraRegType = _SVExtraRegType.NONE
242 reg: _SVExtraReg = _SVExtraReg.NONE
243
244 def __repr__(self):
245 return f"{self.regtype.value}:{self.reg.name}"
246
247 def __new__(cls, value="0"):
248 if isinstance(value, str):
249 def transform(value):
250 (regtype, reg) = value.split(":")
251 regtype = _SVExtraRegType(regtype)
252 reg = _SVExtraReg(reg)
253 return cls.Entry(regtype=regtype, reg=reg)
254
255 if value == "0":
256 value = tuple()
257 else:
258 value = map(transform, value.split(";"))
259
260 return super().__new__(cls, value)
261
262 def __repr__(self):
263 return repr(list(self))
264
265 def __new__(cls, value=tuple()):
266 value = tuple(value)
267 if len(value) == 0:
268 value = (("0",) * 4)
269 return super().__new__(cls, map(cls.Extra, value))
270
271 def __repr__(self):
272 return repr({index:self[index] for index in range(0, 4)})
273
274 name: str
275 ptype: _SVPtype = _SVPtype.NONE
276 etype: _SVEtype = _SVEtype.NONE
277 in1: _In1Sel = _In1Sel.NONE
278 in2: _In2Sel = _In2Sel.NONE
279 in3: _In3Sel = _In3Sel.NONE
280 out: _OutSel = _OutSel.NONE
281 out2: _OutSel = _OutSel.NONE
282 cr_in: _CRInSel = _CRInSel.NONE
283 cr_out: _CROutSel = _CROutSel.NONE
284 extra: ExtraMap = ExtraMap()
285 pu: bool = False
286 conditions: str = ""
287 mode: _SVMode = _SVMode.NORMAL
288
289 __KEYMAP = {
290 "insn": "name",
291 "CONDITIONS": "conditions",
292 "Ptype": "ptype",
293 "Etype": "etype",
294 "CR in": "cr_in",
295 "CR out": "cr_out",
296 "PU": "pu",
297 }
298
299 @classmethod
300 def CSV(cls, record):
301 for key in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
302 value = record[key]
303 if value == "0":
304 record[key] = "NONE"
305
306 record["extra"] = cls.ExtraMap(record.pop(f"{index}") for index in range(0, 4))
307
308 return dataclass(cls, record, keymap=cls.__KEYMAP)
309
310
311 class BitSel:
312 def __init__(self, value=(0, 32)):
313 if isinstance(value, str):
314 (start, end) = map(int, value.split(":"))
315 else:
316 (start, end) = value
317 if start < 0 or end < 0 or start >= end:
318 raise ValueError(value)
319
320 self.__start = start
321 self.__end = end
322
323 return super().__init__()
324
325 def __repr__(self):
326 return f"[{self.__start}:{self.__end}]"
327
328 def __iter__(self):
329 yield from range(self.start, (self.end + 1))
330
331 @property
332 def start(self):
333 return self.__start
334
335 @property
336 def end(self):
337 return self.__end
338
339
340 @_dataclasses.dataclass(eq=True, frozen=True)
341 class Section:
342 class Mode(_enum.Enum):
343 INTEGER = _enum.auto()
344 PATTERN = _enum.auto()
345
346 @classmethod
347 def _missing_(cls, value):
348 if isinstance(value, str):
349 return cls[value.upper()]
350 return super()._missing_(value)
351
352 class Suffix(int):
353 def __new__(cls, value=None):
354 if isinstance(value, str):
355 if value.upper() == "NONE":
356 value = None
357 else:
358 value = int(value, 0)
359 if value is None:
360 value = 0
361
362 return super().__new__(cls, value)
363
364 def __str__(self):
365 return repr(self)
366
367 def __repr__(self):
368 return (bin(self) if self else "None")
369
370 path: _pathlib.Path
371 opcode: Opcode
372 bitsel: BitSel
373 suffix: Suffix
374 mode: Mode
375
376 @classmethod
377 def CSV(cls, record):
378 return dataclass(cls, record)
379
380
381 class Fields:
382 def __init__(self, items):
383 if isinstance(items, dict):
384 items = items.items()
385
386 def transform(item):
387 (name, bitrange) = item
388 return (name, tuple(bitrange.values()))
389
390 self.__mapping = dict(map(transform, items))
391
392 return super().__init__()
393
394 def __repr__(self):
395 return repr(self.__mapping)
396
397 def __iter__(self):
398 yield from self.__mapping.items()
399
400 def __contains__(self, key):
401 return self.__mapping.__contains__(key)
402
403 def __getitem__(self, key):
404 return self.__mapping.get(key, None)
405
406
407 @_dataclasses.dataclass(eq=True, frozen=True)
408 class Operand:
409 pass
410
411
412 class Operands(tuple):
413 @_dataclasses.dataclass(eq=True, frozen=True)
414 class DynamicOperand(Operand):
415 name: str
416
417 def disassemble(self, value, record):
418 return str(int(value[record.fields[self.name]]))
419
420 @_dataclasses.dataclass(eq=True, frozen=True)
421 class StaticOperand(Operand):
422 name: str
423 value: int = None
424
425 @_dataclasses.dataclass(eq=True, frozen=True)
426 class DynamicOperandIFormLI(DynamicOperand):
427 def disassemble(self, value, record):
428 return hex(int(_selectconcat(
429 value[record.fields["LI"]],
430 _SelectableInt(value=0b00, bits=2))))
431
432 class DynamicOperandBFormBD(DynamicOperand):
433 def disassemble(self, value, record):
434 return hex(int(_selectconcat(
435 value[record.fields["BD"]],
436 _SelectableInt(value=0b00, bits=2))))
437
438 @_dataclasses.dataclass(eq=True, frozen=True)
439 class DynamicOperandGPR(DynamicOperand):
440 def disassemble(self, value, record):
441 return f"r{super().disassemble(value=value, record=record)}"
442
443 @_dataclasses.dataclass(eq=True, frozen=True)
444 class DynamicOperandFPR(DynamicOperand):
445 def disassemble(self, value, record):
446 return f"f{super().disassemble(value=value, record=record)}"
447
448 def __new__(cls, insn, iterable):
449 branches = {
450 "b": {"LI": cls.DynamicOperandIFormLI},
451 "ba": {"LI": cls.DynamicOperandIFormLI},
452 "bl": {"LI": cls.DynamicOperandIFormLI},
453 "bla": {"LI": cls.DynamicOperandIFormLI},
454 "bc": {"BD": cls.DynamicOperandBFormBD},
455 "bca": {"BD": cls.DynamicOperandBFormBD},
456 "bcl": {"BD": cls.DynamicOperandBFormBD},
457 "bcla": {"BD": cls.DynamicOperandBFormBD},
458 }
459
460 operands = []
461 for operand in iterable:
462 dynamic_cls = cls.DynamicOperand
463 static_cls = cls.StaticOperand
464
465 if "=" in operand:
466 (name, value) = operand.split("=")
467 operand = static_cls(name=name, value=int(value))
468 else:
469 if insn in branches and operand in branches[insn]:
470 dynamic_cls = branches[insn][operand]
471
472 if operand in _RegType.__members__:
473 regtype = _RegType[operand]
474 if regtype is _RegType.GPR:
475 dynamic_cls = cls.DynamicOperandGPR
476 elif regtype is _RegType.FPR:
477 dynamic_cls = cls.DynamicOperandFPR
478
479 operand = dynamic_cls(name=operand)
480
481 operands.append(operand)
482
483 return super().__new__(cls, operands)
484
485
486 @_functools.total_ordering
487 @_dataclasses.dataclass(eq=True, frozen=True)
488 class Record:
489 name: str
490 section: Section
491 ppc: PPCRecord
492 fields: Fields
493 operands: Operands
494 svp64: SVP64Record = None
495
496 __EXTRA = (
497 _SVExtra.Idx0,
498 _SVExtra.Idx1,
499 _SVExtra.Idx2,
500 _SVExtra.Idx3,
501 )
502
503 def __lt__(self, other):
504 if not isinstance(other, Record):
505 return NotImplemented
506 return (self.opcode < other.opcode)
507
508 def __repr__(self):
509 return f"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
510
511 @cached_property
512 def opcode(self):
513 fields = []
514 if self.section.opcode:
515 fields += [(self.section.opcode.value, BitSel((0, 5)))]
516 fields += [(self.ppc.opcode.value, self.section.bitsel)]
517 else:
518 fields += [(self.ppc.opcode.value, self.section.bitsel)]
519
520 for operand in self.static_operands:
521 fields += [(operand.value, self.fields[operand.name])]
522
523 return FieldsOpcode(fields)
524
525 @property
526 def function(self):
527 return self.ppc.function
528
529 @property
530 def in1(self):
531 return self.ppc.in1
532
533 @property
534 def in2(self):
535 return self.ppc.in2
536
537 @property
538 def in3(self):
539 return self.ppc.in3
540
541 @property
542 def out(self):
543 return self.ppc.out
544
545 @property
546 def out2(self):
547 if self.svp64 is None:
548 return _OutSel.NONE
549 return self.ppc.out
550
551 @property
552 def cr_in(self):
553 return self.ppc.cr_in
554
555 @property
556 def cr_out(self):
557 return self.ppc.cr_out
558
559 def sv_extra(self, key):
560 if key not in frozenset({
561 "in1", "in2", "in3", "cr_in",
562 "out", "out2", "cr_out",
563 }):
564 raise KeyError(key)
565
566 sel = getattr(self.svp64, key)
567 if sel is _CRInSel.BA_BB:
568 return _SVExtra.Idx_1_2
569 reg = _SVExtraReg(sel)
570 if reg is _SVExtraReg.NONE:
571 return _SVExtra.NONE
572
573 extra_map = {
574 _SVExtraRegType.SRC: {},
575 _SVExtraRegType.DST: {},
576 }
577 for index in range(0, 4):
578 for entry in self.svp64.extra[index]:
579 extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
580
581 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
582 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
583 if extra is not _SVExtra.NONE:
584 return extra
585
586 return _SVExtra.NONE
587
588 sv_in1 = property(_functools.partial(sv_extra, key="in1"))
589 sv_in2 = property(_functools.partial(sv_extra, key="in2"))
590 sv_in3 = property(_functools.partial(sv_extra, key="in3"))
591 sv_out = property(_functools.partial(sv_extra, key="out"))
592 sv_out2 = property(_functools.partial(sv_extra, key="out2"))
593 sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
594 sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
595
596 @property
597 def sv_ptype(self):
598 if self.svp64 is None:
599 return _SVPtype.NONE
600 return self.svp64.ptype
601
602 @property
603 def sv_etype(self):
604 if self.svp64 is None:
605 return _SVEtype.NONE
606 return self.svp64.etype
607
608 @property
609 def dynamic_operands(self):
610 for operand in self.operands:
611 if isinstance(operand, Operands.DynamicOperand):
612 yield operand
613
614 @property
615 def static_operands(self):
616 for operand in self.operands:
617 if isinstance(operand, Operands.StaticOperand):
618 yield operand
619
620
621 class Instruction(_Mapping):
622 @classmethod
623 def integer(cls, value=0, bits=None, byteorder="little"):
624 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
625 raise ValueError(bits)
626
627 if isinstance(value, bytes):
628 if ((len(value) * 8) != bits):
629 raise ValueError(f"bit length mismatch")
630 value = int.from_bytes(value, byteorder=byteorder)
631
632 if isinstance(value, int):
633 value = _SelectableInt(value=value, bits=bits)
634 elif isinstance(value, Instruction):
635 value = value.storage
636
637 if not isinstance(value, _SelectableInt):
638 raise ValueError(value)
639 if bits is None:
640 bits = len(cls)
641 if len(value) != bits:
642 raise ValueError(value)
643
644 value = _SelectableInt(value=value, bits=bits)
645
646 return cls(storage=value)
647
648 def __hash__(self):
649 return hash(int(self))
650
651 def disassemble(self, db):
652 raise NotImplementedError
653
654
655 class WordInstruction(Instruction):
656 _: _Field = range(0, 32)
657 po: _Field = range(0, 6)
658
659 @classmethod
660 def integer(cls, value, byteorder="little"):
661 return super().integer(bits=32, value=value, byteorder=byteorder)
662
663 def disassemble(self, db):
664 record = db[self]
665 if record is None:
666 yield f".long 0x{int(self):08x}"
667 else:
668 operands = []
669 for operand in record.dynamic_operands:
670 operand = operand.disassemble(self, record)
671 operands.append(operand)
672 if operands:
673 operands = ",".join(operands)
674 operands = f" {operands}"
675 else:
676 operands = ""
677
678 yield f"{record.name}{operands}"
679
680 class PrefixedInstruction(Instruction):
681 class Prefix(WordInstruction.remap(range(0, 32))):
682 pass
683
684 class Suffix(WordInstruction.remap(range(32, 64))):
685 pass
686
687 _: _Field = range(64)
688 prefix: Prefix
689 suffix: Suffix
690 po: Suffix.po
691
692 @classmethod
693 def integer(cls, value, byteorder="little"):
694 return super().integer(bits=64, value=value, byteorder=byteorder)
695
696 @classmethod
697 def pair(cls, prefix=0, suffix=0, byteorder="little"):
698 def transform(value):
699 return WordInstruction.integer(value=value,
700 byteorder=byteorder)[0:32]
701
702 (prefix, suffix) = map(transform, (prefix, suffix))
703 value = _selectconcat(prefix, suffix)
704
705 return super().integer(value=value)
706
707
708 class SVP64Instruction(PrefixedInstruction):
709 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
710 class Prefix(PrefixedInstruction.Prefix):
711 class RM(_Mapping):
712 _: _Field = range(24)
713 mmode: _Field = (0,)
714 mask: _Field = range(1, 4)
715 elwidth: _Field = range(4, 6)
716 ewsrc: _Field = range(6, 8)
717 subvl: _Field = range(8, 10)
718 extra: _Field = range(10, 19)
719 mode: _Field = range(19, 24)
720 extra2: _Field[4] = (
721 range(10, 12),
722 range(12, 14),
723 range(14, 16),
724 range(16, 18),
725 )
726 smask: _Field = range(16, 19)
727 extra3: _Field[3] = (
728 range(10, 13),
729 range(13, 16),
730 range(16, 19),
731 )
732
733 id: _Field = (7, 9)
734 rm: RM = ((6, 8) + tuple(range(10, 32)))
735
736 prefix: Prefix
737
738 def disassemble(self, db):
739 record = db[self.suffix]
740 if record is None:
741 yield f".llong 0x{int(self):016x}"
742 else:
743 yield f".llong 0x{int(self):016x} # sv.{record.name}"
744
745
746 def parse(stream, factory):
747 lines = filter(lambda line: not line.strip().startswith("#"), stream)
748 entries = _csv.DictReader(lines)
749 entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
750 return tuple(map(factory, entries))
751
752
753 class PPCDatabase:
754 def __init__(self, root):
755 db = _collections.defaultdict(set)
756 path = (root / "insndb.csv")
757 with open(path, "r", encoding="UTF-8") as stream:
758 for section in parse(stream, Section.CSV):
759 path = (root / section.path)
760 opcode_cls = {
761 section.Mode.INTEGER: IntegerOpcode,
762 section.Mode.PATTERN: PatternOpcode,
763 }[section.mode]
764 factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
765 with open(path, "r", encoding="UTF-8") as stream:
766 db[section].update(parse(stream, factory))
767 self.__db = db
768 return super().__init__()
769
770 def __getitem__(self, key):
771 for (section, records) in self.__db.items():
772 for record in records:
773 for name in record.names:
774 if ((key == name) or
775 ((record.rc is _RC.RC) and
776 key.endswith(".") and
777 name == key[:-1])):
778 return (section, record)
779 return (None, None)
780
781
782 class SVP64Database:
783 def __init__(self, root):
784 db = set()
785 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
786 for (prefix, _, names) in _os.walk(root):
787 prefix = _pathlib.Path(prefix)
788 for name in filter(lambda name: pattern.match(name), names):
789 path = (prefix / _pathlib.Path(name))
790 with open(path, "r", encoding="UTF-8") as stream:
791 db.update(parse(stream, SVP64Record.CSV))
792 self.__db = {record.name:record for record in db}
793 return super().__init__()
794
795 def __getitem__(self, key):
796 for name in key:
797 record = self.__db.get(name, None)
798 if record is not None:
799 return record
800 return None
801
802
803 class FieldsDatabase:
804 def __init__(self):
805 db = {}
806 df = _DecodeFields()
807 df.create_specs()
808 for (form, fields) in df.instrs.items():
809 if form in {"DQE", "TX"}:
810 continue
811 if form == "all":
812 form = "NONE"
813 db[_Form[form]] = Fields(fields)
814 self.__db = db
815 return super().__init__()
816
817 def __getitem__(self, key):
818 return self.__db.__getitem__(key)
819
820
821 class MarkdownDatabase:
822 def __init__(self):
823 db = {}
824 for (name, desc) in _ISA():
825 operands = []
826 if desc.regs:
827 (dynamic, *static) = desc.regs
828 operands.extend(dynamic)
829 operands.extend(static)
830 db[name] = Operands(insn=name, iterable=operands)
831 self.__db = db
832 return super().__init__()
833
834 def __iter__(self):
835 yield from self.__db.items()
836
837 def __getitem__(self, key):
838 return self.__db.__getitem__(key)
839
840
841 class Database:
842 def __init__(self, root):
843 root = _pathlib.Path(root)
844
845 mdwndb = MarkdownDatabase()
846 fieldsdb = FieldsDatabase()
847 svp64db = SVP64Database(root)
848 ppcdb = PPCDatabase(root)
849
850 db = set()
851 for (name, operands) in mdwndb:
852 (section, ppc) = ppcdb[name]
853 if ppc is None:
854 continue
855 svp64 = svp64db[ppc.names]
856 fields = fieldsdb[ppc.form]
857 record = Record(name=name,
858 section=section, ppc=ppc, svp64=svp64,
859 operands=operands, fields=fields)
860 db.add(record)
861
862 self.__db = tuple(sorted(db))
863
864 return super().__init__()
865
866 def __repr__(self):
867 return repr(self.__db)
868
869 def __iter__(self):
870 yield from self.__db
871
872 @_functools.lru_cache(maxsize=None)
873 def __contains__(self, key):
874 return self.__getitem__(key) is not None
875
876 @_functools.lru_cache(maxsize=None)
877 def __getitem__(self, key):
878 if isinstance(key, (int, Instruction)):
879 key = int(key)
880 for record in self:
881 opcode = record.opcode
882 if ((opcode.value & opcode.mask) ==
883 (key & opcode.mask)):
884 return record
885 return None
886 elif isinstance(key, Opcode):
887 for record in self:
888 if record.opcode == key:
889 return record
890 elif isinstance(key, str):
891 for record in self:
892 if record.name == key:
893 return record
894 return None