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