power_insn: refactor 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 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 class Operands:
408 @_dataclasses.dataclass(eq=True, frozen=True)
409 class Operand:
410 name: str
411
412 def disassemble(self, value, record):
413 raise NotImplementedError
414
415 @_dataclasses.dataclass(eq=True, frozen=True)
416 class DynamicOperand(Operand):
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 value: int = None
423
424 @_dataclasses.dataclass(eq=True, frozen=True)
425 class DynamicOperandIFormLI(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 DynamicOperandBFormBD(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 @_dataclasses.dataclass(eq=True, frozen=True)
438 class DynamicOperandGPR(DynamicOperand):
439 def disassemble(self, value, record):
440 return f"r{super().disassemble(value=value, record=record)}"
441
442 @_dataclasses.dataclass(eq=True, frozen=True)
443 class DynamicOperandFPR(DynamicOperand):
444 def disassemble(self, value, record):
445 return f"f{super().disassemble(value=value, record=record)}"
446
447 def __init__(self, insn, iterable):
448 branches = {
449 "b": {"LI": self.__class__.DynamicOperandIFormLI},
450 "ba": {"LI": self.__class__.DynamicOperandIFormLI},
451 "bl": {"LI": self.__class__.DynamicOperandIFormLI},
452 "bla": {"LI": self.__class__.DynamicOperandIFormLI},
453 "bc": {"BD": self.__class__.DynamicOperandBFormBD},
454 "bca": {"BD": self.__class__.DynamicOperandBFormBD},
455 "bcl": {"BD": self.__class__.DynamicOperandBFormBD},
456 "bcla": {"BD": self.__class__.DynamicOperandBFormBD},
457 }
458
459 operands = []
460 for operand in iterable:
461 dynamic_cls = self.__class__.DynamicOperand
462 static_cls = self.__class__.StaticOperand
463
464 if "=" in operand:
465 (name, value) = operand.split("=")
466 operand = static_cls(name=name, value=int(value))
467 else:
468 if insn in branches and operand in branches[insn]:
469 dynamic_cls = branches[insn][operand]
470
471 if operand in _RegType.__members__:
472 regtype = _RegType[operand]
473 if regtype is _RegType.GPR:
474 dynamic_cls = self.__class__.DynamicOperandGPR
475 elif regtype is _RegType.FPR:
476 dynamic_cls = self.__class__.DynamicOperandFPR
477
478 operand = dynamic_cls(name=operand)
479
480 operands.append(operand)
481
482 self.__operands = operands
483
484 return super().__init__()
485
486 def __repr__(self):
487 return self.__operands.__repr__()
488
489 def __iter__(self):
490 yield from self.__operands
491
492 def __getitem__(self, key):
493 for operand in self.__operands:
494 if operand.name == key:
495 return operand
496
497 return None
498
499 @property
500 def dynamic(self):
501 for operand in self:
502 if isinstance(operand, self.__class__.DynamicOperand):
503 yield operand
504
505 @property
506 def static(self):
507 for operand in self:
508 if isinstance(operand, self.__class__.StaticOperand):
509 yield operand
510
511
512 @_functools.total_ordering
513 @_dataclasses.dataclass(eq=True, frozen=True)
514 class Record:
515 name: str
516 section: Section
517 ppc: PPCRecord
518 fields: Fields
519 operands: Operands
520 svp64: SVP64Record = None
521
522 __EXTRA = (
523 _SVExtra.Idx0,
524 _SVExtra.Idx1,
525 _SVExtra.Idx2,
526 _SVExtra.Idx3,
527 )
528
529 def __lt__(self, other):
530 if not isinstance(other, Record):
531 return NotImplemented
532 return (self.opcode < other.opcode)
533
534 def __repr__(self):
535 return f"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
536
537 @cached_property
538 def opcode(self):
539 fields = []
540 if self.section.opcode:
541 fields += [(self.section.opcode.value, BitSel((0, 5)))]
542 fields += [(self.ppc.opcode.value, self.section.bitsel)]
543 else:
544 fields += [(self.ppc.opcode.value, self.section.bitsel)]
545
546 for operand in self.operands.static:
547 fields += [(operand.value, self.fields[operand.name])]
548
549 return FieldsOpcode(fields)
550
551 @property
552 def function(self):
553 return self.ppc.function
554
555 @property
556 def in1(self):
557 return self.ppc.in1
558
559 @property
560 def in2(self):
561 return self.ppc.in2
562
563 @property
564 def in3(self):
565 return self.ppc.in3
566
567 @property
568 def out(self):
569 return self.ppc.out
570
571 @property
572 def out2(self):
573 if self.svp64 is None:
574 return _OutSel.NONE
575 return self.ppc.out
576
577 @property
578 def cr_in(self):
579 return self.ppc.cr_in
580
581 @property
582 def cr_out(self):
583 return self.ppc.cr_out
584
585 def sv_extra(self, key):
586 if key not in frozenset({
587 "in1", "in2", "in3", "cr_in",
588 "out", "out2", "cr_out",
589 }):
590 raise KeyError(key)
591
592 sel = getattr(self.svp64, key)
593 if sel is _CRInSel.BA_BB:
594 return _SVExtra.Idx_1_2
595 reg = _SVExtraReg(sel)
596 if reg is _SVExtraReg.NONE:
597 return _SVExtra.NONE
598
599 extra_map = {
600 _SVExtraRegType.SRC: {},
601 _SVExtraRegType.DST: {},
602 }
603 for index in range(0, 4):
604 for entry in self.svp64.extra[index]:
605 extra_map[entry.regtype][entry.reg] = Record.__EXTRA[index]
606
607 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
608 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
609 if extra is not _SVExtra.NONE:
610 return extra
611
612 return _SVExtra.NONE
613
614 sv_in1 = property(_functools.partial(sv_extra, key="in1"))
615 sv_in2 = property(_functools.partial(sv_extra, key="in2"))
616 sv_in3 = property(_functools.partial(sv_extra, key="in3"))
617 sv_out = property(_functools.partial(sv_extra, key="out"))
618 sv_out2 = property(_functools.partial(sv_extra, key="out2"))
619 sv_cr_in = property(_functools.partial(sv_extra, key="cr_in"))
620 sv_cr_out = property(_functools.partial(sv_extra, key="cr_out"))
621
622 @property
623 def sv_ptype(self):
624 if self.svp64 is None:
625 return _SVPtype.NONE
626 return self.svp64.ptype
627
628 @property
629 def sv_etype(self):
630 if self.svp64 is None:
631 return _SVEtype.NONE
632 return self.svp64.etype
633
634
635 class Instruction(_Mapping):
636 @classmethod
637 def integer(cls, value=0, bits=None, byteorder="little"):
638 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
639 raise ValueError(bits)
640
641 if isinstance(value, bytes):
642 if ((len(value) * 8) != bits):
643 raise ValueError(f"bit length mismatch")
644 value = int.from_bytes(value, byteorder=byteorder)
645
646 if isinstance(value, int):
647 value = _SelectableInt(value=value, bits=bits)
648 elif isinstance(value, Instruction):
649 value = value.storage
650
651 if not isinstance(value, _SelectableInt):
652 raise ValueError(value)
653 if bits is None:
654 bits = len(cls)
655 if len(value) != bits:
656 raise ValueError(value)
657
658 value = _SelectableInt(value=value, bits=bits)
659
660 return cls(storage=value)
661
662 def __hash__(self):
663 return hash(int(self))
664
665 def disassemble(self, db, byteorder="little"):
666 raise NotImplementedError
667
668
669 class WordInstruction(Instruction):
670 _: _Field = range(0, 32)
671 po: _Field = range(0, 6)
672
673 @classmethod
674 def integer(cls, value, byteorder="little"):
675 return super().integer(bits=32, value=value, byteorder=byteorder)
676
677 def disassemble(self, db, byteorder="little"):
678 integer = int(self)
679 blob = integer.to_bytes(length=4, byteorder=byteorder)
680 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
681
682 record = db[self]
683 if record is None:
684 yield f"{blob} .long 0x{integer:08x}"
685 else:
686 operands = []
687 for operand in record.operands.dynamic:
688 operand = operand.disassemble(self, record)
689 operands.append(operand)
690 if operands:
691 operands = ",".join(operands)
692 operands = f" {operands}"
693 else:
694 operands = ""
695 yield f"{blob} {record.name}{operands}"
696
697 class PrefixedInstruction(Instruction):
698 class Prefix(WordInstruction.remap(range(0, 32))):
699 pass
700
701 class Suffix(WordInstruction.remap(range(32, 64))):
702 pass
703
704 _: _Field = range(64)
705 prefix: Prefix
706 suffix: Suffix
707 po: Suffix.po
708
709 @classmethod
710 def integer(cls, value, byteorder="little"):
711 return super().integer(bits=64, value=value, byteorder=byteorder)
712
713 @classmethod
714 def pair(cls, prefix=0, suffix=0, byteorder="little"):
715 def transform(value):
716 return WordInstruction.integer(value=value,
717 byteorder=byteorder)[0:32]
718
719 (prefix, suffix) = map(transform, (prefix, suffix))
720 value = _selectconcat(prefix, suffix)
721
722 return super().integer(value=value)
723
724
725 class SVP64Instruction(PrefixedInstruction):
726 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
727 class Prefix(PrefixedInstruction.Prefix):
728 class RM(_Mapping):
729 _: _Field = range(24)
730 mmode: _Field = (0,)
731 mask: _Field = range(1, 4)
732 elwidth: _Field = range(4, 6)
733 ewsrc: _Field = range(6, 8)
734 subvl: _Field = range(8, 10)
735 extra: _Field = range(10, 19)
736 mode: _Field = range(19, 24)
737 extra2: _Field[4] = (
738 range(10, 12),
739 range(12, 14),
740 range(14, 16),
741 range(16, 18),
742 )
743 smask: _Field = range(16, 19)
744 extra3: _Field[3] = (
745 range(10, 13),
746 range(13, 16),
747 range(16, 19),
748 )
749
750 id: _Field = (7, 9)
751 rm: RM = ((6, 8) + tuple(range(10, 32)))
752
753 prefix: Prefix
754
755 def disassemble(self, db, byteorder="little"):
756 integer_prefix = int(self.prefix)
757 blob_prefix = integer_prefix.to_bytes(length=4, byteorder=byteorder)
758 blob_prefix = " ".join(map(lambda byte: f"{byte:02x}", blob_prefix))
759
760 integer_suffix = int(self.suffix)
761 blob_suffix = integer_suffix.to_bytes(length=4, byteorder=byteorder)
762 blob_suffix = " ".join(map(lambda byte: f"{byte:02x}", blob_suffix))
763
764 record = db[self.suffix]
765 if record is None or record.svp64 is None:
766 yield f"{blob_prefix} .long 0x{int(self.prefix):08x}"
767 yield f"{blob_suffix} .long 0x{int(self.suffix):08x}"
768 else:
769 yield f"{blob_prefix} sv.{record.name}"
770 yield f"{blob_suffix}"
771
772
773 def parse(stream, factory):
774 lines = filter(lambda line: not line.strip().startswith("#"), stream)
775 entries = _csv.DictReader(lines)
776 entries = filter(lambda entry: "TODO" not in frozenset(entry.values()), entries)
777 return tuple(map(factory, entries))
778
779
780 class PPCDatabase:
781 def __init__(self, root):
782 db = _collections.defaultdict(set)
783 path = (root / "insndb.csv")
784 with open(path, "r", encoding="UTF-8") as stream:
785 for section in parse(stream, Section.CSV):
786 path = (root / section.path)
787 opcode_cls = {
788 section.Mode.INTEGER: IntegerOpcode,
789 section.Mode.PATTERN: PatternOpcode,
790 }[section.mode]
791 factory = _functools.partial(PPCRecord.CSV, opcode_cls=opcode_cls)
792 with open(path, "r", encoding="UTF-8") as stream:
793 db[section].update(parse(stream, factory))
794 self.__db = db
795 return super().__init__()
796
797 def __getitem__(self, key):
798 for (section, records) in self.__db.items():
799 for record in records:
800 for name in record.names:
801 if ((key == name) or
802 ((record.rc is _RC.RC) and
803 key.endswith(".") and
804 name == key[:-1])):
805 return (section, record)
806 return (None, None)
807
808
809 class SVP64Database:
810 def __init__(self, root):
811 db = set()
812 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
813 for (prefix, _, names) in _os.walk(root):
814 prefix = _pathlib.Path(prefix)
815 for name in filter(lambda name: pattern.match(name), names):
816 path = (prefix / _pathlib.Path(name))
817 with open(path, "r", encoding="UTF-8") as stream:
818 db.update(parse(stream, SVP64Record.CSV))
819 self.__db = {record.name:record for record in db}
820 return super().__init__()
821
822 def __getitem__(self, key):
823 for name in key:
824 record = self.__db.get(name, None)
825 if record is not None:
826 return record
827 return None
828
829
830 class FieldsDatabase:
831 def __init__(self):
832 db = {}
833 df = _DecodeFields()
834 df.create_specs()
835 for (form, fields) in df.instrs.items():
836 if form in {"DQE", "TX"}:
837 continue
838 if form == "all":
839 form = "NONE"
840 db[_Form[form]] = Fields(fields)
841 self.__db = db
842 return super().__init__()
843
844 def __getitem__(self, key):
845 return self.__db.__getitem__(key)
846
847
848 class MarkdownDatabase:
849 def __init__(self):
850 db = {}
851 for (name, desc) in _ISA():
852 operands = []
853 if desc.regs:
854 (dynamic, *static) = desc.regs
855 operands.extend(dynamic)
856 operands.extend(static)
857 db[name] = Operands(insn=name, iterable=operands)
858 self.__db = db
859 return super().__init__()
860
861 def __iter__(self):
862 yield from self.__db.items()
863
864 def __getitem__(self, key):
865 return self.__db.__getitem__(key)
866
867
868 class Database:
869 def __init__(self, root):
870 root = _pathlib.Path(root)
871
872 mdwndb = MarkdownDatabase()
873 fieldsdb = FieldsDatabase()
874 svp64db = SVP64Database(root)
875 ppcdb = PPCDatabase(root)
876
877 db = set()
878 for (name, operands) in mdwndb:
879 (section, ppc) = ppcdb[name]
880 if ppc is None:
881 continue
882 svp64 = svp64db[ppc.names]
883 fields = fieldsdb[ppc.form]
884 record = Record(name=name,
885 section=section, ppc=ppc, svp64=svp64,
886 operands=operands, fields=fields)
887 db.add(record)
888
889 self.__db = tuple(sorted(db))
890
891 return super().__init__()
892
893 def __repr__(self):
894 return repr(self.__db)
895
896 def __iter__(self):
897 yield from self.__db
898
899 @_functools.lru_cache(maxsize=None)
900 def __contains__(self, key):
901 return self.__getitem__(key) is not None
902
903 @_functools.lru_cache(maxsize=None)
904 def __getitem__(self, key):
905 if isinstance(key, (int, Instruction)):
906 key = int(key)
907 for record in self:
908 opcode = record.opcode
909 if ((opcode.value & opcode.mask) ==
910 (key & opcode.mask)):
911 return record
912 return None
913 elif isinstance(key, Opcode):
914 for record in self:
915 if record.opcode == key:
916 return record
917 elif isinstance(key, str):
918 for record in self:
919 if record.name == key:
920 return record
921 return None