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