75879f86b126db3298809cab051b070ad9895134
[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 itertools as _itertools
7 import os as _os
8 import operator as _operator
9 import pathlib as _pathlib
10 import re as _re
11
12 try:
13 from functools import cached_property
14 except ImportError:
15 from cached_property import cached_property
16
17 from openpower.decoder.power_enums import (
18 Function as _Function,
19 MicrOp as _MicrOp,
20 In1Sel as _In1Sel,
21 In2Sel as _In2Sel,
22 In3Sel as _In3Sel,
23 OutSel as _OutSel,
24 CRInSel as _CRInSel,
25 CRIn2Sel as _CRIn2Sel,
26 CROutSel as _CROutSel,
27 LDSTLen as _LDSTLen,
28 LDSTMode as _LDSTMode,
29 RCOE as _RCOE,
30 CryIn as _CryIn,
31 Form as _Form,
32 SVEtype as _SVEtype,
33 SVmask_src as _SVmask_src,
34 SVMode as _SVMode,
35 SVPtype as _SVPtype,
36 SVExtra as _SVExtra,
37 RegType as _RegType,
38 SVExtraRegType as _SVExtraRegType,
39 SVExtraReg as _SVExtraReg,
40 )
41 from openpower.decoder.selectable_int import (
42 SelectableInt as _SelectableInt,
43 selectconcat as _selectconcat,
44 )
45 from openpower.decoder.power_fields import (
46 Field as _Field,
47 Mapping as _Mapping,
48 DecodeFields as _DecodeFields,
49 )
50 from openpower.decoder.pseudo.pagereader import ISA as _ISA
51
52
53 @_functools.total_ordering
54 class Verbosity(_enum.Enum):
55 SHORT = _enum.auto()
56 NORMAL = _enum.auto()
57 VERBOSE = _enum.auto()
58
59 def __lt__(self, other):
60 if not isinstance(other, self.__class__):
61 return NotImplemented
62 return (self.value < other.value)
63
64
65 def dataclass(cls, record, keymap=None, typemap=None):
66 if keymap is None:
67 keymap = {}
68 if typemap is None:
69 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
70
71 def transform(key_value):
72 (key, value) = key_value
73 key = keymap.get(key, key)
74 hook = typemap.get(key, lambda value: value)
75 if hook is bool and value in ("", "0"):
76 value = False
77 else:
78 value = hook(value)
79 return (key, value)
80
81 record = dict(map(transform, record.items()))
82 for key in frozenset(record.keys()):
83 if record[key] == "":
84 record.pop(key)
85
86 return cls(**record)
87
88
89 @_functools.total_ordering
90 @_dataclasses.dataclass(eq=True, frozen=True)
91 class Opcode:
92 class Integer(int):
93 def __new__(cls, value):
94 if isinstance(value, str):
95 value = int(value, 0)
96 if not isinstance(value, int):
97 raise ValueError(value)
98
99 if value.bit_length() > 64:
100 raise ValueError(value)
101
102 return super().__new__(cls, value)
103
104 def __str__(self):
105 return super().__repr__()
106
107 def __repr__(self):
108 return f"{self:0{self.bit_length()}b}"
109
110 def bit_length(self):
111 if super().bit_length() > 32:
112 return 64
113 return 32
114
115 class Value(Integer):
116 pass
117
118 class Mask(Integer):
119 pass
120
121 value: Value
122 mask: Mask
123
124 def __lt__(self, other):
125 if not isinstance(other, Opcode):
126 return NotImplemented
127 return ((self.value, self.mask) < (other.value, other.mask))
128
129 def __post_init__(self):
130 if self.value.bit_length() != self.mask.bit_length():
131 raise ValueError("bit length mismatch")
132
133 def __repr__(self):
134 def pattern(value, mask, bit_length):
135 for bit in range(bit_length):
136 if ((mask & (1 << (bit_length - bit - 1))) == 0):
137 yield "-"
138 elif (value & (1 << (bit_length - bit - 1))):
139 yield "1"
140 else:
141 yield "0"
142
143 return "".join(pattern(self.value, self.mask, self.value.bit_length()))
144
145
146 class IntegerOpcode(Opcode):
147 def __init__(self, value):
148 if value.startswith("0b"):
149 mask = int(("1" * len(value[2:])), 2)
150 else:
151 mask = 0b111111
152
153 value = Opcode.Value(value)
154 mask = Opcode.Mask(mask)
155
156 return super().__init__(value=value, mask=mask)
157
158
159 class PatternOpcode(Opcode):
160 def __init__(self, pattern):
161 if not isinstance(pattern, str):
162 raise ValueError(pattern)
163
164 (value, mask) = (0, 0)
165 for symbol in pattern:
166 if symbol not in {"0", "1", "-"}:
167 raise ValueError(pattern)
168 value |= (symbol == "1")
169 mask |= (symbol != "-")
170 value <<= 1
171 mask <<= 1
172 value >>= 1
173 mask >>= 1
174
175 value = Opcode.Value(value)
176 mask = Opcode.Mask(mask)
177
178 return super().__init__(value=value, mask=mask)
179
180
181 @_dataclasses.dataclass(eq=True, frozen=True)
182 class PPCRecord:
183 class FlagsMeta(type):
184 def __iter__(cls):
185 yield from (
186 "inv A",
187 "inv out",
188 "cry out",
189 "BR",
190 "sgn ext",
191 "rsrv",
192 "32b",
193 "sgn",
194 "lk",
195 "sgl pipe",
196 )
197
198 class Flags(frozenset, metaclass=FlagsMeta):
199 def __new__(cls, flags=frozenset()):
200 flags = frozenset(flags)
201 diff = (flags - frozenset(cls))
202 if diff:
203 raise ValueError(flags)
204 return super().__new__(cls, flags)
205
206 opcode: Opcode
207 comment: str
208 flags: Flags = Flags()
209 comment2: str = ""
210 function: _Function = _Function.NONE
211 intop: _MicrOp = _MicrOp.OP_ILLEGAL
212 in1: _In1Sel = _In1Sel.RA
213 in2: _In2Sel = _In2Sel.NONE
214 in3: _In3Sel = _In3Sel.NONE
215 out: _OutSel = _OutSel.NONE
216 cr_in: _CRInSel = _CRInSel.NONE
217 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
218 cr_out: _CROutSel = _CROutSel.NONE
219 cry_in: _CryIn = _CryIn.ZERO
220 ldst_len: _LDSTLen = _LDSTLen.NONE
221 upd: _LDSTMode = _LDSTMode.NONE
222 Rc: _RCOE = _RCOE.NONE
223 form: _Form = _Form.NONE
224 conditions: str = ""
225 unofficial: bool = False
226
227 __KEYMAP = {
228 "unit": "function",
229 "internal op": "intop",
230 "CR in": "cr_in",
231 "CR out": "cr_out",
232 "cry in": "cry_in",
233 "ldst len": "ldst_len",
234 "rc": "Rc",
235 "CONDITIONS": "conditions",
236 }
237
238 @classmethod
239 def CSV(cls, record, opcode_cls):
240 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
241 typemap["opcode"] = opcode_cls
242
243 if record["CR in"] == "BA_BB":
244 record["cr_in"] = "BA"
245 record["cr_in2"] = "BB"
246 del record["CR in"]
247
248 flags = set()
249 for flag in frozenset(PPCRecord.Flags):
250 if bool(record.pop(flag, "")):
251 flags.add(flag)
252 record["flags"] = PPCRecord.Flags(flags)
253
254 return dataclass(cls, record,
255 keymap=PPCRecord.__KEYMAP,
256 typemap=typemap)
257
258 @cached_property
259 def names(self):
260 return frozenset(self.comment.split("=")[-1].split("/"))
261
262
263 class PPCMultiRecord(tuple):
264 def __getattr__(self, attr):
265 if attr == "opcode":
266 raise AttributeError(attr)
267 return getattr(self[0], attr)
268
269
270 @_dataclasses.dataclass(eq=True, frozen=True)
271 class SVP64Record:
272 class ExtraMap(tuple):
273 class Extra(tuple):
274 @_dataclasses.dataclass(eq=True, frozen=True)
275 class Entry:
276 regtype: _SVExtraRegType = _SVExtraRegType.NONE
277 reg: _SVExtraReg = _SVExtraReg.NONE
278
279 def __repr__(self):
280 return f"{self.regtype.value}:{self.reg.name}"
281
282 def __new__(cls, value="0"):
283 if isinstance(value, str):
284 def transform(value):
285 (regtype, reg) = value.split(":")
286 regtype = _SVExtraRegType(regtype)
287 reg = _SVExtraReg(reg)
288 return cls.Entry(regtype=regtype, reg=reg)
289
290 if value == "0":
291 value = tuple()
292 else:
293 value = map(transform, value.split(";"))
294
295 return super().__new__(cls, value)
296
297 def __repr__(self):
298 return repr(list(self))
299
300 def __new__(cls, value=tuple()):
301 value = tuple(value)
302 if len(value) == 0:
303 value = (("0",) * 4)
304 return super().__new__(cls, map(cls.Extra, value))
305
306 def __repr__(self):
307 return repr({index:self[index] for index in range(0, 4)})
308
309 name: str
310 ptype: _SVPtype = _SVPtype.NONE
311 etype: _SVEtype = _SVEtype.NONE
312 msrc: _SVmask_src = _SVmask_src.NO # MASK_SRC is active
313 in1: _In1Sel = _In1Sel.NONE
314 in2: _In2Sel = _In2Sel.NONE
315 in3: _In3Sel = _In3Sel.NONE
316 out: _OutSel = _OutSel.NONE
317 out2: _OutSel = _OutSel.NONE
318 cr_in: _CRInSel = _CRInSel.NONE
319 cr_in2: _CRIn2Sel = _CRIn2Sel.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 "SM": "msrc",
331 "CR in": "cr_in",
332 "CR out": "cr_out",
333 }
334
335 @classmethod
336 def CSV(cls, record):
337 for key in frozenset({
338 "in1", "in2", "in3", "CR in",
339 "out", "out2", "CR out",
340 }):
341 value = record[key]
342 if value == "0":
343 record[key] = "NONE"
344
345 if record["CR in"] == "BA_BB":
346 record["cr_in"] = "BA"
347 record["cr_in2"] = "BB"
348 del record["CR in"]
349
350 extra = []
351 for idx in range(0, 4):
352 extra.append(record.pop(f"{idx}"))
353
354 record["extra"] = cls.ExtraMap(extra)
355
356 return dataclass(cls, record, keymap=cls.__KEYMAP)
357
358 @_functools.lru_cache(maxsize=None)
359 def extra_idx(self, key):
360 extra_idx = (
361 _SVExtra.Idx0,
362 _SVExtra.Idx1,
363 _SVExtra.Idx2,
364 _SVExtra.Idx3,
365 )
366
367 if key not in frozenset({
368 "in1", "in2", "in3", "cr_in", "cr_in2",
369 "out", "out2", "cr_out",
370 }):
371 raise KeyError(key)
372
373 sel = getattr(self, key)
374 if sel is _CRInSel.BA_BB:
375 return _SVExtra.Idx_1_2
376 reg = _SVExtraReg(sel)
377 if reg is _SVExtraReg.NONE:
378 return _SVExtra.NONE
379
380 extra_map = {
381 _SVExtraRegType.SRC: {},
382 _SVExtraRegType.DST: {},
383 }
384 for index in range(0, 4):
385 for entry in self.extra[index]:
386 extra_map[entry.regtype][entry.reg] = extra_idx[index]
387
388 for regtype in (_SVExtraRegType.SRC, _SVExtraRegType.DST):
389 extra = extra_map[regtype].get(reg, _SVExtra.NONE)
390 if extra is not _SVExtra.NONE:
391 return extra
392
393 return _SVExtra.NONE
394
395 extra_idx_in1 = property(_functools.partial(extra_idx, key="in1"))
396 extra_idx_in2 = property(_functools.partial(extra_idx, key="in2"))
397 extra_idx_in3 = property(_functools.partial(extra_idx, key="in3"))
398 extra_idx_out = property(_functools.partial(extra_idx, key="out"))
399 extra_idx_out2 = property(_functools.partial(extra_idx, key="out2"))
400 extra_idx_cr_in = property(_functools.partial(extra_idx, key="cr_in"))
401 extra_idx_cr_out = property(_functools.partial(extra_idx, key="cr_out"))
402
403 @_functools.lru_cache(maxsize=None)
404 def extra_reg(self, key):
405 return _SVExtraReg(getattr(self, key))
406
407 extra_reg_in1 = property(_functools.partial(extra_reg, key="in1"))
408 extra_reg_in2 = property(_functools.partial(extra_reg, key="in2"))
409 extra_reg_in3 = property(_functools.partial(extra_reg, key="in3"))
410 extra_reg_out = property(_functools.partial(extra_reg, key="out"))
411 extra_reg_out2 = property(_functools.partial(extra_reg, key="out2"))
412 extra_reg_cr_in = property(_functools.partial(extra_reg, key="cr_in"))
413 extra_reg_cr_out = property(_functools.partial(extra_reg, key="cr_out"))
414
415
416 class BitSel:
417 def __init__(self, value=(0, 32)):
418 if isinstance(value, str):
419 (start, end) = map(int, value.split(":"))
420 else:
421 (start, end) = value
422 if start < 0 or end < 0 or start >= end:
423 raise ValueError(value)
424
425 self.__start = start
426 self.__end = end
427
428 return super().__init__()
429
430 def __repr__(self):
431 return f"[{self.__start}:{self.__end}]"
432
433 def __iter__(self):
434 yield from range(self.start, (self.end + 1))
435
436 def __reversed__(self):
437 return tuple(reversed(tuple(self)))
438
439 @property
440 def start(self):
441 return self.__start
442
443 @property
444 def end(self):
445 return self.__end
446
447
448 @_dataclasses.dataclass(eq=True, frozen=True)
449 class Section:
450 class Mode(_enum.Enum):
451 INTEGER = _enum.auto()
452 PATTERN = _enum.auto()
453
454 @classmethod
455 def _missing_(cls, value):
456 if isinstance(value, str):
457 return cls[value.upper()]
458 return super()._missing_(value)
459
460 class Suffix(int):
461 def __new__(cls, value=None):
462 if isinstance(value, str):
463 if value.upper() == "NONE":
464 value = None
465 else:
466 value = int(value, 0)
467 if value is None:
468 value = 0
469
470 return super().__new__(cls, value)
471
472 def __str__(self):
473 return repr(self)
474
475 def __repr__(self):
476 return (bin(self) if self else "None")
477
478 path: _pathlib.Path
479 bitsel: BitSel
480 suffix: Suffix
481 mode: Mode
482 opcode: IntegerOpcode = None
483
484 @classmethod
485 def CSV(cls, record):
486 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
487 if record["opcode"] == "NONE":
488 typemap["opcode"] = lambda _: None
489
490 return dataclass(cls, record, typemap=typemap)
491
492
493 class Fields:
494 def __init__(self, items):
495 if isinstance(items, dict):
496 items = items.items()
497
498 def transform(item):
499 (name, bitrange) = item
500 return (name, tuple(bitrange.values()))
501
502 self.__mapping = dict(map(transform, items))
503
504 return super().__init__()
505
506 def __repr__(self):
507 return repr(self.__mapping)
508
509 def __iter__(self):
510 yield from self.__mapping.items()
511
512 def __contains__(self, key):
513 return self.__mapping.__contains__(key)
514
515 def __getitem__(self, key):
516 return self.__mapping.get(key, None)
517
518
519 @_dataclasses.dataclass(eq=True, frozen=True)
520 class Operand:
521 name: str
522
523 def span(self, record):
524 return record.fields[self.name]
525
526 def disassemble(self, insn, record,
527 verbosity=Verbosity.NORMAL, indent=""):
528 raise NotImplementedError
529
530
531 class DynamicOperand(Operand):
532 def disassemble(self, insn, record,
533 verbosity=Verbosity.NORMAL, indent=""):
534 span = self.span(record=record)
535 if isinstance(insn, SVP64Instruction):
536 span = tuple(map(lambda bit: (bit + 32), span))
537 value = insn[span]
538
539 if verbosity >= Verbosity.VERBOSE:
540 span = map(str, span)
541 yield f"{indent}{self.name}"
542 yield f"{indent}{indent}{int(value):0{value.bits}b}"
543 yield f"{indent}{indent}{', '.join(span)}"
544 else:
545 yield str(int(value))
546
547
548 class SignedOperand(DynamicOperand):
549 def disassemble(self, insn, record,
550 verbosity=Verbosity.NORMAL, indent=""):
551 span = self.span(record=record)
552 if isinstance(insn, SVP64Instruction):
553 span = tuple(map(lambda bit: (bit + 32), span))
554 value = insn[span]
555
556 if verbosity >= Verbosity.VERBOSE:
557 span = map(str, span)
558 yield f"{indent}{self.name}"
559 yield f"{indent}{indent}{int(value):0{value.bits}b}"
560 yield f"{indent}{indent}{', '.join(span)}"
561 else:
562 yield str(value.to_signed_int())
563
564
565 @_dataclasses.dataclass(eq=True, frozen=True)
566 class StaticOperand(Operand):
567 value: int
568
569 def disassemble(self, insn, record,
570 verbosity=Verbosity.NORMAL, indent=""):
571 span = self.span(record=record)
572 if isinstance(insn, SVP64Instruction):
573 span = tuple(map(lambda bit: (bit + 32), span))
574 value = insn[span]
575
576 if verbosity >= Verbosity.VERBOSE:
577 span = map(str, span)
578 yield f"{indent}{self.name}"
579 yield f"{indent}{indent}{int(value):0{value.bits}b}"
580 yield f"{indent}{indent}{', '.join(span)}"
581 else:
582 yield str(int(value))
583
584
585 class ImmediateOperand(DynamicOperand):
586 pass
587
588
589 class NonZeroOperand(DynamicOperand):
590 def disassemble(self, insn, record,
591 verbosity=Verbosity.NORMAL, indent=""):
592 span = self.span(record=record)
593 if isinstance(insn, SVP64Instruction):
594 span = tuple(map(lambda bit: (bit + 32), span))
595 value = insn[span]
596
597 if verbosity >= Verbosity.VERBOSE:
598 span = map(str, span)
599 yield f"{indent}{self.name}"
600 yield f"{indent}{indent}{int(value):0{value.bits}b}"
601 yield f"{indent}{indent}{', '.join(span)}"
602 else:
603 yield str(int(value) + 1)
604
605
606 class RegisterOperand(DynamicOperand):
607 def sv_spec_enter(self, value, span):
608 return (value, span)
609
610 def sv_spec_leave(self, value, span, origin_value, origin_span):
611 return (value, span)
612
613 def spec(self, insn, record):
614 vector = False
615 span = self.span(record=record)
616 if isinstance(insn, SVP64Instruction):
617 span = tuple(map(lambda bit: (bit + 32), span))
618 value = insn[span]
619 span = tuple(map(str, span))
620
621 if isinstance(insn, SVP64Instruction):
622 (origin_value, origin_span) = (value, span)
623 (value, span) = self.sv_spec_enter(value=value, span=span)
624
625 extra_idx = self.extra_idx(record=record)
626 if extra_idx is _SVExtra.NONE:
627 return (vector, value, span)
628
629 if record.etype is _SVEtype.EXTRA3:
630 spec = insn.prefix.rm.extra3[extra_idx]
631 elif record.etype is _SVEtype.EXTRA2:
632 spec = insn.prefix.rm.extra2[extra_idx]
633 else:
634 raise ValueError(record.etype)
635
636 if spec != 0:
637 vector = bool(spec[0])
638 spec_span = spec.__class__
639 if record.etype is _SVEtype.EXTRA3:
640 spec_span = tuple(map(str, spec_span[1, 2]))
641 spec = spec[1, 2]
642 elif record.etype is _SVEtype.EXTRA2:
643 spec_span = tuple(map(str, spec_span[1,]))
644 spec = _SelectableInt(value=spec[1].value, bits=2)
645 if vector:
646 spec <<= 1
647 spec_span = (spec_span + ("{0}",))
648 else:
649 spec_span = (("{0}",) + spec_span)
650 else:
651 raise ValueError(record.etype)
652
653 vector_shift = (2 + (5 - value.bits))
654 scalar_shift = value.bits
655 spec_shift = (5 - value.bits)
656
657 bits = (len(span) + len(spec_span))
658 value = _SelectableInt(value=value.value, bits=bits)
659 spec = _SelectableInt(value=spec.value, bits=bits)
660 if vector:
661 value = ((value << vector_shift) | (spec << spec_shift))
662 span = (span + spec_span + ((spec_shift * ("{0}",))))
663 else:
664 value = ((spec << scalar_shift) | value)
665 span = ((spec_shift * ("{0}",)) + spec_span + span)
666
667 (value, span) = self.sv_spec_leave(value=value, span=span,
668 origin_value=origin_value, origin_span=origin_span)
669
670 return (vector, value, span)
671
672 @property
673 def extra_reg(self):
674 return _SVExtraReg(self.name)
675
676 def extra_idx(self, record):
677 for key in frozenset({
678 "in1", "in2", "in3", "cr_in", "cr_in2",
679 "out", "out2", "cr_out",
680 }):
681 extra_reg = record.svp64.extra_reg(key=key)
682 if extra_reg is self.extra_reg:
683 return record.extra_idx(key=key)
684
685 return _SVExtra.NONE
686
687 def disassemble(self, insn, record,
688 verbosity=Verbosity.NORMAL, prefix="", indent=""):
689 (vector, value, span) = self.spec(insn=insn, record=record)
690
691 if verbosity >= Verbosity.VERBOSE:
692 mode = "vector" if vector else "scalar"
693 yield f"{indent}{self.name} ({mode})"
694 yield f"{indent}{indent}{int(value):0{value.bits}b}"
695 yield f"{indent}{indent}{', '.join(span)}"
696 if isinstance(insn, SVP64Instruction):
697 extra_idx = self.extra_idx(record)
698 if record.etype is _SVEtype.NONE:
699 yield f"{indent}{indent}extra[none]"
700 else:
701 etype = repr(record.etype).lower()
702 yield f"{indent}{indent}{etype}{extra_idx!r}"
703 else:
704 vector = "*" if vector else ""
705 yield f"{vector}{prefix}{int(value)}"
706
707
708 class GPROperand(RegisterOperand):
709 def disassemble(self, insn, record,
710 verbosity=Verbosity.NORMAL, indent=""):
711 prefix = "" if (verbosity <= Verbosity.SHORT) else "r"
712 yield from super().disassemble(prefix=prefix,
713 insn=insn, record=record,
714 verbosity=verbosity, indent=indent)
715
716
717 class FPROperand(RegisterOperand):
718 def disassemble(self, insn, record,
719 verbosity=Verbosity.NORMAL, indent=""):
720 prefix = "" if (verbosity <= Verbosity.SHORT) else "f"
721 yield from super().disassemble(prefix=prefix,
722 insn=insn, record=record,
723 verbosity=verbosity, indent=indent)
724
725
726 class CR3Operand(RegisterOperand):
727 pass
728
729
730 class CR5Operand(RegisterOperand):
731 def sv_spec_enter(self, value, span):
732 value = _SelectableInt(value=(value.value >> 2), bits=3)
733 return (value, span)
734
735 def sv_spec_leave(self, value, span, origin_value, origin_span):
736 value = _selectconcat(value, origin_value[3:5])
737 span += origin_span
738 return (value, span)
739
740
741 class TargetAddrOperand(RegisterOperand):
742 def disassemble(self, insn, record, field,
743 verbosity=Verbosity.NORMAL, indent=""):
744 span = self.span(record=record)
745 if isinstance(insn, SVP64Instruction):
746 span = tuple(map(lambda bit: (bit + 32), span))
747 value = insn[span]
748
749 if verbosity >= Verbosity.VERBOSE:
750 span = (tuple(map(str, span)) + ("{0}", "{0}"))
751 yield f"{indent}{self.name} = EXTS({field} || 0b00))"
752 yield f"{indent}{indent}{field}"
753 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
754 yield f"{indent}{indent}{indent}{', '.join(span)}"
755 else:
756 yield hex(_selectconcat(value,
757 _SelectableInt(value=0b00, bits=2)).to_signed_int())
758
759
760 class TargetAddrOperandLI(TargetAddrOperand):
761 def span(self, record):
762 return record.fields["LI"]
763
764 def disassemble(self, insn, record,
765 verbosity=Verbosity.NORMAL, indent=""):
766 return super().disassemble(field="LI",
767 insn=insn, record=record,
768 verbosity=verbosity, indent=indent)
769
770
771 class TargetAddrOperandBD(TargetAddrOperand):
772 def span(self, record):
773 return record.fields["BD"]
774
775 def disassemble(self, insn, record,
776 verbosity=Verbosity.NORMAL, indent=""):
777 return super().disassemble(field="BD",
778 insn=insn, record=record,
779 verbosity=verbosity, indent=indent)
780
781
782 class DOperandDX(SignedOperand):
783 def span(self, record):
784 operands = map(DynamicOperand, ("d0", "d1", "d2"))
785 spans = map(lambda operand: operand.span(record=record), operands)
786 return sum(spans, tuple())
787
788 def disassemble(self, insn, record,
789 verbosity=Verbosity.NORMAL, indent=""):
790 span = self.span(record=record)
791 if isinstance(insn, SVP64Instruction):
792 span = tuple(map(lambda bit: (bit + 32), span))
793 value = insn[span]
794
795 if verbosity >= Verbosity.VERBOSE:
796 yield f"{indent}D"
797 mapping = {
798 "d0": "[0:9]",
799 "d1": "[10:15]",
800 "d2": "[16]",
801 }
802 for (subname, subspan) in mapping.items():
803 operand = DynamicOperand(name=subname)
804 span = operand.span(record=record)
805 if isinstance(insn, SVP64Instruction):
806 span = tuple(map(lambda bit: (bit + 32), span))
807 value = insn[span]
808 span = map(str, span)
809 yield f"{indent}{indent}{operand.name} = D{subspan}"
810 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
811 yield f"{indent}{indent}{indent}{', '.join(span)}"
812 else:
813 yield str(value.to_signed_int())
814
815
816 class Operands(tuple):
817 def __new__(cls, insn, iterable):
818 custom_insns = {
819 "b": {"target_addr": TargetAddrOperandLI},
820 "ba": {"target_addr": TargetAddrOperandLI},
821 "bl": {"target_addr": TargetAddrOperandLI},
822 "bla": {"target_addr": TargetAddrOperandLI},
823 "bc": {"target_addr": TargetAddrOperandBD},
824 "bca": {"target_addr": TargetAddrOperandBD},
825 "bcl": {"target_addr": TargetAddrOperandBD},
826 "bcla": {"target_addr": TargetAddrOperandBD},
827 "addpcis": {"D": DOperandDX},
828 "fishmv": {"D": DOperandDX},
829 "fmvis": {"D": DOperandDX},
830 }
831 custom_fields = {
832 "SVi": NonZeroOperand,
833 "SVd": NonZeroOperand,
834 "SVxd": NonZeroOperand,
835 "SVyd": NonZeroOperand,
836 "SVzd": NonZeroOperand,
837 "BD": SignedOperand,
838 "D": SignedOperand,
839 "DQ": SignedOperand,
840 "DS": SignedOperand,
841 "SI": SignedOperand,
842 "IB": SignedOperand,
843 "LI": SignedOperand,
844 "SIM": SignedOperand,
845 "SVD": SignedOperand,
846 "SVDS": SignedOperand,
847 }
848
849 operands = []
850 for operand in iterable:
851 dynamic_cls = DynamicOperand
852 static_cls = StaticOperand
853
854 if "=" in operand:
855 (name, value) = operand.split("=")
856 operand = static_cls(name=name, value=int(value))
857 operands.append(operand)
858 else:
859 if operand.endswith(")"):
860 operand = operand.replace("(", " ").replace(")", "")
861 (immediate, _, operand) = operand.partition(" ")
862 else:
863 immediate = None
864
865 if immediate is not None:
866 operands.append(ImmediateOperand(name=immediate))
867
868 if operand in custom_fields:
869 dynamic_cls = custom_fields[operand]
870 if insn in custom_insns and operand in custom_insns[insn]:
871 dynamic_cls = custom_insns[insn][operand]
872
873 if operand in _RegType.__members__:
874 regtype = _RegType[operand]
875 if regtype is _RegType.GPR:
876 dynamic_cls = GPROperand
877 elif regtype is _RegType.FPR:
878 dynamic_cls = FPROperand
879 if regtype is _RegType.CR_BIT: # 5-bit
880 dynamic_cls = CR5Operand
881 if regtype is _RegType.CR_REG: # actually CR Field, 3-bit
882 dynamic_cls = CR3Operand
883
884 operand = dynamic_cls(name=operand)
885 operands.append(operand)
886
887 return super().__new__(cls, operands)
888
889 def __contains__(self, key):
890 return self.__getitem__(key) is not None
891
892 def __getitem__(self, key):
893 for operand in self:
894 if operand.name == key:
895 return operand
896
897 return None
898
899 @property
900 def dynamic(self):
901 for operand in self:
902 if isinstance(operand, DynamicOperand):
903 yield operand
904
905 @property
906 def static(self):
907 for operand in self:
908 if isinstance(operand, StaticOperand):
909 yield operand
910
911
912 class PCode:
913 def __init__(self, iterable):
914 self.__pcode = tuple(iterable)
915 return super().__init__()
916
917 def __iter__(self):
918 yield from self.__pcode
919
920 def __repr__(self):
921 return self.__pcode.__repr__()
922
923
924 @_dataclasses.dataclass(eq=True, frozen=True)
925 class MarkdownRecord:
926 pcode: PCode
927 operands: Operands
928
929
930 @_functools.total_ordering
931 @_dataclasses.dataclass(eq=True, frozen=True)
932 class Record:
933 name: str
934 section: Section
935 ppc: PPCRecord
936 fields: Fields
937 mdwn: MarkdownRecord
938 svp64: SVP64Record = None
939
940 def __lt__(self, other):
941 if not isinstance(other, Record):
942 return NotImplemented
943 return (min(self.opcodes) < min(other.opcodes))
944
945 @property
946 def opcodes(self):
947 def opcode(ppc):
948 value = ([0] * 32)
949 mask = ([0] * 32)
950
951 PO = self.section.opcode
952 if PO is not None:
953 for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
954 value[dst] = int((PO.value & (1 << src)) != 0)
955 mask[dst] = int((PO.mask & (1 << src)) != 0)
956
957 XO = ppc.opcode
958 for (src, dst) in enumerate(reversed(self.section.bitsel)):
959 value[dst] = int((XO.value & (1 << src)) != 0)
960 mask[dst] = int((XO.mask & (1 << src)) != 0)
961
962 for operand in self.mdwn.operands.static:
963 for (src, dst) in enumerate(reversed(operand.span(record=self))):
964 value[dst] = int((operand.value & (1 << src)) != 0)
965 mask[dst] = 1
966
967 value = Opcode.Value(int(("".join(map(str, value))), 2))
968 mask = Opcode.Mask(int(("".join(map(str, mask))), 2))
969
970 return Opcode(value=value, mask=mask)
971
972 return tuple(sorted(map(opcode, self.ppc)))
973
974 def match(self, key):
975 for opcode in self.opcodes:
976 if ((opcode.value & opcode.mask) ==
977 (key & opcode.mask)):
978 return True
979 return False
980
981 @property
982 def function(self):
983 return self.ppc.function
984
985 @property
986 def in1(self):
987 return self.ppc.in1
988
989 @property
990 def in2(self):
991 return self.ppc.in2
992
993 @property
994 def in3(self):
995 return self.ppc.in3
996
997 @property
998 def out(self):
999 return self.ppc.out
1000
1001 @property
1002 def out2(self):
1003 if self.svp64 is None:
1004 return _OutSel.NONE
1005 return self.ppc.out
1006
1007 @property
1008 def cr_in(self):
1009 return self.ppc.cr_in
1010
1011 @property
1012 def cr_in2(self):
1013 return self.ppc.cr_in2
1014
1015 @property
1016 def cr_out(self):
1017 return self.ppc.cr_out
1018
1019 ptype = property(lambda self: self.svp64.ptype)
1020 etype = property(lambda self: self.svp64.etype)
1021
1022 def extra_idx(self, key):
1023 return self.svp64.extra_idx(key)
1024
1025 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
1026 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
1027 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
1028 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
1029 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
1030 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
1031 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
1032
1033
1034 class Instruction(_Mapping):
1035 @classmethod
1036 def integer(cls, value=0, bits=None, byteorder="little"):
1037 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1038 raise ValueError(bits)
1039
1040 if isinstance(value, bytes):
1041 if ((len(value) * 8) != bits):
1042 raise ValueError(f"bit length mismatch")
1043 value = int.from_bytes(value, byteorder=byteorder)
1044
1045 if isinstance(value, int):
1046 value = _SelectableInt(value=value, bits=bits)
1047 elif isinstance(value, Instruction):
1048 value = value.storage
1049
1050 if not isinstance(value, _SelectableInt):
1051 raise ValueError(value)
1052 if bits is None:
1053 bits = len(cls)
1054 if len(value) != bits:
1055 raise ValueError(value)
1056
1057 value = _SelectableInt(value=value, bits=bits)
1058
1059 return cls(storage=value)
1060
1061 def __hash__(self):
1062 return hash(int(self))
1063
1064 def __getitem__(self, key):
1065 return self.storage.__getitem__(key)
1066
1067 def __setitem__(self, key, value):
1068 return self.storage.__setitem__(key, value)
1069
1070 def bytes(self, byteorder="little"):
1071 nr_bytes = (self.storage.bits // 8)
1072 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1073
1074 def record(self, db):
1075 record = db[self]
1076 if record is None:
1077 raise KeyError(self)
1078 return record
1079
1080 def spec(self, db, prefix):
1081 record = self.record(db=db)
1082
1083 dynamic_operands = tuple(map(_operator.itemgetter(0),
1084 self.dynamic_operands(db=db)))
1085
1086 static_operands = []
1087 for (name, value) in self.static_operands(db=db):
1088 static_operands.append(f"{name}={value}")
1089
1090 operands = ""
1091 if dynamic_operands:
1092 operands += " "
1093 operands += ",".join(dynamic_operands)
1094 if static_operands:
1095 operands += " "
1096 operands += " ".join(static_operands)
1097
1098 return f"{prefix}{record.name}{operands}"
1099
1100 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
1101 record = self.record(db=db)
1102
1103 imm = False
1104 imm_name = ""
1105 imm_value = ""
1106 for operand in record.mdwn.operands.dynamic:
1107 name = operand.name
1108 dis = operand.disassemble(insn=self, record=record,
1109 verbosity=min(verbosity, Verbosity.NORMAL))
1110 value = " ".join(dis)
1111 if imm:
1112 name = f"{imm_name}({name})"
1113 value = f"{imm_value}({value})"
1114 imm = False
1115 if isinstance(operand, ImmediateOperand):
1116 imm_name = name
1117 imm_value = value
1118 imm = True
1119 if not imm:
1120 yield (name, value)
1121
1122 def static_operands(self, db):
1123 record = self.record(db=db)
1124 for operand in record.mdwn.operands.static:
1125 yield (operand.name, operand.value)
1126
1127 def disassemble(self, db,
1128 byteorder="little",
1129 verbosity=Verbosity.NORMAL):
1130 raise NotImplementedError
1131
1132
1133 class WordInstruction(Instruction):
1134 _: _Field = range(0, 32)
1135 po: _Field = range(0, 6)
1136
1137 @classmethod
1138 def integer(cls, value, byteorder="little"):
1139 return super().integer(bits=32, value=value, byteorder=byteorder)
1140
1141 @property
1142 def binary(self):
1143 bits = []
1144 for idx in range(32):
1145 bit = int(self[idx])
1146 bits.append(bit)
1147 return "".join(map(str, bits))
1148
1149 def disassemble(self, db,
1150 byteorder="little",
1151 verbosity=Verbosity.NORMAL):
1152 integer = int(self)
1153 if verbosity <= Verbosity.SHORT:
1154 blob = ""
1155 else:
1156 blob = integer.to_bytes(length=4, byteorder=byteorder)
1157 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1158 blob += " "
1159
1160 record = db[self]
1161 if record is None:
1162 yield f"{blob}.long 0x{integer:08x}"
1163 return
1164
1165 operands = tuple(map(_operator.itemgetter(1),
1166 self.dynamic_operands(db=db, verbosity=verbosity)))
1167 if operands:
1168 operands = ",".join(operands)
1169 yield f"{blob}{record.name} {operands}"
1170 else:
1171 yield f"{blob}{record.name}"
1172
1173 if verbosity >= Verbosity.VERBOSE:
1174 indent = (" " * 4)
1175 binary = self.binary
1176 spec = self.spec(db=db, prefix="")
1177 yield f"{indent}spec"
1178 yield f"{indent}{indent}{spec}"
1179 yield f"{indent}pcode"
1180 for stmt in record.mdwn.pcode:
1181 yield f"{indent}{indent}{stmt}"
1182 yield f"{indent}binary"
1183 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1184 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1185 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1186 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1187 yield f"{indent}opcodes"
1188 for opcode in record.opcodes:
1189 yield f"{indent}{indent}{opcode!r}"
1190 for operand in record.mdwn.operands:
1191 yield from operand.disassemble(insn=self, record=record,
1192 verbosity=verbosity, indent=indent)
1193 yield ""
1194
1195
1196 class PrefixedInstruction(Instruction):
1197 class Prefix(WordInstruction.remap(range(0, 32))):
1198 pass
1199
1200 class Suffix(WordInstruction.remap(range(32, 64))):
1201 pass
1202
1203 _: _Field = range(64)
1204 prefix: Prefix
1205 suffix: Suffix
1206 po: Suffix.po
1207
1208 @classmethod
1209 def integer(cls, value, byteorder="little"):
1210 return super().integer(bits=64, value=value, byteorder=byteorder)
1211
1212 @classmethod
1213 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1214 def transform(value):
1215 return WordInstruction.integer(value=value,
1216 byteorder=byteorder)[0:32]
1217
1218 (prefix, suffix) = map(transform, (prefix, suffix))
1219 value = _selectconcat(prefix, suffix)
1220
1221 return super().integer(bits=64, value=value)
1222
1223
1224 class Mode(_Mapping):
1225 _: _Field = range(0, 5)
1226
1227
1228 class Extra(_Mapping):
1229 _: _Field = range(0, 9)
1230
1231
1232 class Extra2(Extra):
1233 idx0: _Field = range(0, 2)
1234 idx1: _Field = range(2, 4)
1235 idx2: _Field = range(4, 6)
1236 idx3: _Field = range(6, 8)
1237
1238 def __getitem__(self, key):
1239 return {
1240 0: self.idx0,
1241 1: self.idx1,
1242 2: self.idx2,
1243 3: self.idx3,
1244 _SVExtra.Idx0: self.idx0,
1245 _SVExtra.Idx1: self.idx1,
1246 _SVExtra.Idx2: self.idx2,
1247 _SVExtra.Idx3: self.idx3,
1248 }[key]
1249
1250 def __setitem__(self, key, value):
1251 self[key].assign(value)
1252
1253
1254 class Extra3(Extra):
1255 idx0: _Field = range(0, 3)
1256 idx1: _Field = range(3, 6)
1257 idx2: _Field = range(6, 9)
1258
1259 def __getitem__(self, key):
1260 return {
1261 0: self.idx0,
1262 1: self.idx1,
1263 2: self.idx2,
1264 _SVExtra.Idx0: self.idx0,
1265 _SVExtra.Idx1: self.idx1,
1266 _SVExtra.Idx2: self.idx2,
1267 }[key]
1268
1269 def __setitem__(self, key, value):
1270 self[key].assign(value)
1271
1272
1273 class BaseRM(_Mapping):
1274 _: _Field = range(24)
1275 mmode: _Field = (0,)
1276 mask: _Field = range(1, 4)
1277 elwidth: _Field = range(4, 6)
1278 ewsrc: _Field = range(6, 8)
1279 subvl: _Field = range(8, 10)
1280 mode: Mode.remap(range(19, 24))
1281 smask: _Field = range(16, 19)
1282 extra: Extra.remap(range(10, 19))
1283 extra2: Extra2.remap(range(10, 19))
1284 extra3: Extra3.remap(range(10, 19))
1285
1286 def specifiers(self, record):
1287 subvl = int(self.subvl)
1288 if subvl > 0:
1289 yield {
1290 1: "vec2",
1291 2: "vec3",
1292 3: "vec4",
1293 }[subvl]
1294
1295 def disassemble(self, verbosity=Verbosity.NORMAL):
1296 if verbosity >= Verbosity.VERBOSE:
1297 indent = (" " * 4)
1298 for (name, value, members) in self.traverse(path="RM"):
1299 yield f"{name}"
1300 yield f"{indent}{int(value):0{value.bits}b}"
1301 yield f"{indent}{', '.join(map(str, members))}"
1302
1303
1304 class FFPRRc1BaseRM(BaseRM):
1305 def specifiers(self, record, mode):
1306 inv = _SelectableInt(value=int(self.inv), bits=1)
1307 CR = _SelectableInt(value=int(self.CR), bits=2)
1308 mask = int(_selectconcat(CR, inv))
1309 predicate = PredicateBaseRM.predicate(True, mask)
1310 yield f"{mode}={predicate}"
1311
1312 yield from super().specifiers(record=record)
1313
1314
1315 class FFPRRc0BaseRM(BaseRM):
1316 def specifiers(self, record, mode):
1317 if self.RC1:
1318 inv = "~" if self.inv else ""
1319 yield f"{mode}={inv}RC1"
1320
1321 yield from super().specifiers(record=record)
1322
1323
1324 class SatBaseRM(BaseRM):
1325 def specifiers(self, record):
1326 if self.N:
1327 yield "sats"
1328 else:
1329 yield "satu"
1330
1331 yield from super().specifiers(record=record)
1332
1333
1334 class ZZBaseRM(BaseRM):
1335 def specifiers(self, record):
1336 if self.zz:
1337 yield "zz"
1338
1339 yield from super().specifiers(record=record)
1340
1341
1342 class DZBaseRM(BaseRM):
1343 def specifiers(self, record):
1344 if self.dz:
1345 yield "dz"
1346
1347 yield from super().specifiers(record=record)
1348
1349
1350 class SZBaseRM(BaseRM):
1351 def specifiers(self, record):
1352 if self.sz:
1353 yield "sz"
1354
1355 yield from super().specifiers(record=record)
1356
1357
1358 class MRBaseRM(BaseRM):
1359 def specifiers(self, record):
1360 if self.RG:
1361 yield "mrr"
1362 else:
1363 yield "mr"
1364
1365 yield from super().specifiers(record=record)
1366
1367
1368 class ElsBaseRM(BaseRM):
1369 def specifiers(self, record):
1370 if self.els:
1371 yield "els"
1372
1373 yield from super().specifiers(record=record)
1374
1375
1376 class WidthBaseRM(BaseRM):
1377 @staticmethod
1378 def width(FP, width):
1379 width = {
1380 0b11: "8",
1381 0b10: "16",
1382 0b01: "32",
1383 }.get(width)
1384 if width is None:
1385 return None
1386 if FP:
1387 width = ("fp" + width)
1388 return width
1389
1390 def specifiers(self, record):
1391 # elwidths: use "w=" if same otherwise dw/sw
1392 # FIXME this should consider FP instructions
1393 FP = False
1394 dw = WidthBaseRM.width(FP, int(self.elwidth))
1395 sw = WidthBaseRM.width(FP, int(self.ewsrc))
1396 if dw == sw and dw:
1397 yield ("w=" + dw)
1398 else:
1399 if dw:
1400 yield ("dw=" + dw)
1401 if sw:
1402 yield ("sw=" + sw)
1403
1404 yield from super().specifiers(record=record)
1405
1406
1407 class PredicateBaseRM(BaseRM):
1408 @staticmethod
1409 def predicate(CR, mask):
1410 return {
1411 # integer
1412 (False, 0b001): "1<<r3",
1413 (False, 0b010): "r3",
1414 (False, 0b011): "~r3",
1415 (False, 0b100): "r10",
1416 (False, 0b101): "~r10",
1417 (False, 0b110): "r30",
1418 (False, 0b111): "~r30",
1419 # CRs
1420 (True, 0b000): "lt",
1421 (True, 0b001): "ge",
1422 (True, 0b010): "gt",
1423 (True, 0b011): "le",
1424 (True, 0b100): "eq",
1425 (True, 0b101): "ne",
1426 (True, 0b110): "so",
1427 (True, 0b111): "ns",
1428 }.get((CR, mask))
1429
1430 def specifiers(self, record):
1431 # predication - single and twin
1432 # use "m=" if same otherwise sm/dm
1433 CR = (int(self.mmode) == 1)
1434 mask = int(self.mask)
1435 sm = dm = PredicateBaseRM.predicate(CR, mask)
1436 if record.svp64.ptype is _SVPtype.P2:
1437 smask = int(self.smask)
1438 sm = PredicateBaseRM.predicate(CR, smask)
1439 if sm == dm and dm:
1440 yield ("m=" + dm)
1441 else:
1442 if sm:
1443 yield ("sm=" + sm)
1444 if dm:
1445 yield ("dm=" + dm)
1446
1447 yield from super().specifiers(record=record)
1448
1449
1450 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
1451 pass
1452
1453
1454 class NormalBaseRM(PredicateWidthBaseRM):
1455 """
1456 Normal mode
1457 https://libre-soc.org/openpower/sv/normal/
1458 """
1459 pass
1460
1461
1462 class NormalSimpleRM(DZBaseRM, SZBaseRM, NormalBaseRM):
1463 """normal: simple mode"""
1464 dz: BaseRM.mode[3]
1465 sz: BaseRM.mode[4]
1466
1467 def specifiers(self, record):
1468 yield from super().specifiers(record=record)
1469
1470
1471 class NormalSMRRM(MRBaseRM, NormalBaseRM):
1472 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
1473 RG: BaseRM.mode[4]
1474
1475
1476 class NormalReservedRM(NormalBaseRM):
1477 """normal: reserved"""
1478 pass
1479
1480
1481 class NormalFFRc1RM(FFPRRc1BaseRM, NormalBaseRM):
1482 """normal: Rc=1: ffirst CR sel"""
1483 inv: BaseRM.mode[2]
1484 CR: BaseRM.mode[3, 4]
1485
1486 def specifiers(self, record):
1487 yield from super().specifiers(record=record, mode="ff")
1488
1489
1490 class NormalFFRc0RM(FFPRRc0BaseRM, NormalBaseRM):
1491 """normal: Rc=0: ffirst z/nonz"""
1492 inv: BaseRM.mode[2]
1493 VLi: BaseRM.mode[3]
1494 RC1: BaseRM.mode[4]
1495
1496 def specifiers(self, record):
1497 if self.VLi:
1498 yield "vli"
1499
1500 yield from super().specifiers(record=record, mode="ff")
1501
1502
1503 class NormalSatRM(SatBaseRM, DZBaseRM, SZBaseRM, NormalBaseRM):
1504 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
1505 N: BaseRM.mode[2]
1506 dz: BaseRM.mode[3]
1507 sz: BaseRM.mode[4]
1508
1509
1510 class NormalPRRc1RM(FFPRRc1BaseRM, NormalBaseRM):
1511 """normal: Rc=1: pred-result CR sel"""
1512 inv: BaseRM.mode[2]
1513 CR: BaseRM.mode[3, 4]
1514
1515 def specifiers(self, record):
1516 yield from super().specifiers(record=record, mode="pr")
1517
1518
1519 class NormalPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, NormalBaseRM):
1520 """normal: Rc=0: pred-result z/nonz"""
1521 inv: BaseRM.mode[2]
1522 zz: BaseRM.mode[3]
1523 RC1: BaseRM.mode[4]
1524 dz: BaseRM.mode[3]
1525 sz: BaseRM.mode[3]
1526
1527 def specifiers(self, record):
1528 yield from super().specifiers(record=record, mode="pr")
1529
1530
1531 class NormalRM(NormalBaseRM):
1532 simple: NormalSimpleRM
1533 smr: NormalSMRRM
1534 reserved: NormalReservedRM
1535 ffrc1: NormalFFRc1RM
1536 ffrc0: NormalFFRc0RM
1537 sat: NormalSatRM
1538 prrc1: NormalPRRc1RM
1539 prrc0: NormalPRRc0RM
1540
1541
1542 class LDSTImmBaseRM(PredicateWidthBaseRM):
1543 """
1544 LD/ST Immediate mode
1545 https://libre-soc.org/openpower/sv/ldst/
1546 """
1547 pass
1548
1549
1550 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
1551 """ld/st immediate: simple mode"""
1552 zz: BaseRM.mode[3]
1553 els: BaseRM.mode[4]
1554 dz: BaseRM.mode[3]
1555 sz: BaseRM.mode[3]
1556
1557
1558 class LDSTImmReservedRM(LDSTImmBaseRM):
1559 """ld/st immediate: reserved"""
1560 pass
1561
1562
1563 class LDSTImmFFRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
1564 """ld/st immediate: Rc=1: ffirst CR sel"""
1565 inv: BaseRM.mode[2]
1566 CR: BaseRM.mode[3, 4]
1567
1568 def specifiers(self, record):
1569 yield from super().specifiers(record=record, mode="ff")
1570
1571
1572 class LDSTImmFFRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
1573 """ld/st immediate: Rc=0: ffirst z/nonz"""
1574 inv: BaseRM.mode[2]
1575 els: BaseRM.mode[3]
1576 RC1: BaseRM.mode[4]
1577
1578 def specifiers(self, record):
1579 yield from super().specifiers(record=record, mode="ff")
1580
1581
1582 class LDSTImmSatRM(ElsBaseRM, SatBaseRM, ZZBaseRM, LDSTImmBaseRM):
1583 """ld/st immediate: sat mode: N=0/1 u/s"""
1584 N: BaseRM.mode[2]
1585 zz: BaseRM.mode[3]
1586 els: BaseRM.mode[4]
1587 dz: BaseRM.mode[3]
1588 sz: BaseRM.mode[3]
1589
1590
1591 class LDSTImmPRRc1RM(FFPRRc1BaseRM, LDSTImmBaseRM):
1592 """ld/st immediate: Rc=1: pred-result CR sel"""
1593 inv: BaseRM.mode[2]
1594 CR: BaseRM.mode[3, 4]
1595
1596 def specifiers(self, record):
1597 yield from super().specifiers(record=record, mode="pr")
1598
1599
1600 class LDSTImmPRRc0RM(FFPRRc0BaseRM, ElsBaseRM, LDSTImmBaseRM):
1601 """ld/st immediate: Rc=0: pred-result z/nonz"""
1602 inv: BaseRM.mode[2]
1603 els: BaseRM.mode[3]
1604 RC1: BaseRM.mode[4]
1605
1606 def specifiers(self, record):
1607 yield from super().specifiers(record=record, mode="pr")
1608
1609
1610 class LDSTImmRM(LDSTImmBaseRM):
1611 simple: LDSTImmSimpleRM
1612 reserved: LDSTImmReservedRM
1613 ffrc1: LDSTImmFFRc1RM
1614 ffrc0: LDSTImmFFRc0RM
1615 sat: LDSTImmSatRM
1616 prrc1: LDSTImmPRRc1RM
1617 prrc0: LDSTImmPRRc0RM
1618
1619
1620 class LDSTIdxBaseRM(PredicateWidthBaseRM):
1621 """
1622 LD/ST Indexed mode
1623 https://libre-soc.org/openpower/sv/ldst/
1624 """
1625 pass
1626
1627
1628 class LDSTIdxSimpleRM(DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
1629 """ld/st index: simple mode"""
1630 SEA: BaseRM.mode[2]
1631 dz: BaseRM.mode[3]
1632 sz: BaseRM.mode[4]
1633
1634
1635 class LDSTIdxStrideRM(DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
1636 """ld/st index: strided (scalar only source)"""
1637 SEA: BaseRM.mode[2]
1638 dz: BaseRM.mode[3]
1639 sz: BaseRM.mode[4]
1640
1641
1642 class LDSTIdxSatRM(SatBaseRM, DZBaseRM, SZBaseRM, LDSTIdxBaseRM):
1643 """ld/st index: sat mode: N=0/1 u/s"""
1644 N: BaseRM.mode[2]
1645 dz: BaseRM.mode[3]
1646 sz: BaseRM.mode[4]
1647
1648
1649 class LDSTIdxPRRc1RM(LDSTIdxBaseRM):
1650 """ld/st index: Rc=1: pred-result CR sel"""
1651 inv: BaseRM.mode[2]
1652 CR: BaseRM.mode[3, 4]
1653
1654 def specifiers(self, record):
1655 yield from super().specifiers(record=record, mode="pr")
1656
1657
1658 class LDSTIdxPRRc0RM(FFPRRc0BaseRM, ZZBaseRM, LDSTIdxBaseRM):
1659 """ld/st index: Rc=0: pred-result z/nonz"""
1660 inv: BaseRM.mode[2]
1661 zz: BaseRM.mode[3]
1662 RC1: BaseRM.mode[4]
1663 dz: BaseRM.mode[3]
1664 sz: BaseRM.mode[3]
1665
1666 def specifiers(self, record):
1667 yield from super().specifiers(record=record, mode="pr")
1668
1669
1670 class LDSTIdxRM(LDSTIdxBaseRM):
1671 simple: LDSTIdxSimpleRM
1672 stride: LDSTIdxStrideRM
1673 sat: LDSTIdxSatRM
1674 prrc1: LDSTIdxPRRc1RM
1675 prrc0: LDSTIdxPRRc0RM
1676
1677
1678
1679 class CROpBaseRM(BaseRM):
1680 """
1681 CR ops mode
1682 https://libre-soc.org/openpower/sv/cr_ops/
1683 """
1684 SNZ: BaseRM[7]
1685
1686
1687 class CROpSimpleRM(DZBaseRM, SZBaseRM, CROpBaseRM):
1688 """cr_op: simple mode"""
1689 RG: BaseRM[20]
1690 dz: BaseRM[22]
1691 sz: BaseRM[23]
1692
1693 def specifiers(self, record):
1694 if self.RG:
1695 yield "rg" # simple CR Mode reports /rg
1696
1697 yield from super().specifiers(record=record)
1698
1699 class CROpSMRRM(MRBaseRM, DZBaseRM, SZBaseRM, CROpBaseRM):
1700 """cr_op: scalar reduce mode (mapreduce), SUBVL=1"""
1701 RG: BaseRM[20]
1702 dz: BaseRM[22]
1703 sz: BaseRM[23]
1704
1705
1706 class CROpFF3RM(ZZBaseRM, CROpBaseRM):
1707 """cr_op: ffirst 3-bit mode"""
1708 VLI: BaseRM[20]
1709 inv: BaseRM[21]
1710 CR: BaseRM[22, 23]
1711 zz: BaseRM[6]
1712 sz: BaseRM[6]
1713 dz: BaseRM[6]
1714
1715 def specifiers(self, record):
1716 yield from super().specifiers(record=record, mode="ff")
1717
1718
1719 class CROpFF5RM(DZBaseRM, SZBaseRM, CROpBaseRM):
1720 """cr_op: ffirst 5-bit mode"""
1721 VLI: BaseRM[20]
1722 inv: BaseRM[21]
1723 dz: BaseRM[22]
1724 sz: BaseRM[23]
1725
1726 def specifiers(self, record):
1727 yield from super().specifiers(record=record)
1728
1729
1730 class CROpRM(CROpBaseRM):
1731 simple: CROpSimpleRM
1732 smr: CROpSMRRM
1733 ff3: CROpFF3RM
1734 ff5: CROpFF5RM
1735
1736
1737 # ********************
1738 # Branches mode
1739 # https://libre-soc.org/openpower/sv/branches/
1740 class BranchBaseRM(BaseRM):
1741 ALL: BaseRM[4]
1742 SNZ: BaseRM[5]
1743 SL: BaseRM[17]
1744 SLu: BaseRM[18]
1745 LRu: BaseRM[22]
1746 sz: BaseRM[23]
1747 CTR: BaseRM[19]
1748 VLS: BaseRM[20]
1749
1750 def specifiers(self, record):
1751 if self.ALL:
1752 yield "all"
1753
1754 # /sz
1755 # branch.sz=1
1756 # branch.snz=0
1757 # /snz
1758 # branch.sz=1
1759 # branch.snz=1
1760 if self.SNZ:
1761 if not self.sz:
1762 raise ValueError(self.sz)
1763 yield "snz"
1764 elif self.sz:
1765 yield "sz"
1766
1767 if self.SL:
1768 yield "sl"
1769 if self.SLu:
1770 yield "slu"
1771 if self.LRu:
1772 yield "lru"
1773
1774 # Branch modes lack source mask.
1775 # Therefore a custom code is needed.
1776 CR = (int(self.mmode) == 1)
1777 mask = int(self.mask)
1778 m = PredicateBaseRM.predicate(CR, mask)
1779 if m is not None:
1780 yield ("m=" + m)
1781
1782 yield from super().specifiers(record=record)
1783
1784
1785 class BranchSimpleRM(BranchBaseRM):
1786 """branch: simple mode"""
1787 pass
1788
1789
1790 class BranchVLSRM(BranchBaseRM):
1791 """branch: VLSET mode"""
1792 VSb: BaseRM[7]
1793 VLI: BaseRM[21]
1794
1795 def specifiers(self, record):
1796 yield {
1797 (0b0, 0b0): "vs",
1798 (0b0, 0b1): "vsi",
1799 (0b1, 0b0): "vsb",
1800 (0b1, 0b1): "vsbi",
1801 }[int(self.VSb), int(self.VLI)]
1802
1803 yield from super().specifiers(record=record)
1804
1805
1806 class BranchCTRRM(BranchBaseRM):
1807 """branch: CTR-test mode"""
1808 CTi: BaseRM[6]
1809
1810 def specifiers(self, record):
1811 if self.CTi:
1812 yield "cti"
1813 else:
1814 yield "ctr"
1815
1816 yield from super().specifiers(record=record)
1817
1818
1819 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
1820 """branch: CTR-test+VLSET mode"""
1821 pass
1822
1823
1824 class BranchRM(BranchBaseRM):
1825 simple: BranchSimpleRM
1826 vls: BranchVLSRM
1827 ctr: BranchCTRRM
1828 ctrvls: BranchCTRVLSRM
1829
1830
1831 class RM(BaseRM):
1832 normal: NormalRM
1833 ldst_imm: LDSTImmRM
1834 ldst_idx: LDSTIdxRM
1835 cr_op: CROpRM
1836 branch: BranchRM
1837
1838 def select(self, record, Rc):
1839 rm = self
1840
1841 # the idea behind these tables is that they are now literally
1842 # in identical format to insndb.csv and minor_xx.csv and can
1843 # be done precisely as that. the only thing to watch out for
1844 # is the insertion of Rc=1 as a "mask/value" bit and likewise
1845 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
1846 # as the LSB.
1847 table = None
1848 if record.svp64.mode is _SVMode.NORMAL:
1849 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1850 # mode Rc mask Rc member
1851 table = (
1852 (0b000000, 0b111000, "simple"), # simple (no Rc)
1853 (0b001000, 0b111000, "smr"), # mapreduce (no Rc)
1854 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1855 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1856 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1857 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1858 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1859 )
1860 rm = rm.normal
1861 search = ((int(rm.mode) << 1) | Rc)
1862
1863 elif record.svp64.mode is _SVMode.LDST_IMM:
1864 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1865 # mode Rc mask Rc member
1866 # ironically/coincidentally this table is identical to NORMAL
1867 # mode except reserved in place of smr
1868 table = (
1869 (0b000000, 0b111000, "simple"), # simple (no Rc)
1870 (0b001000, 0b111000, "reserved"), # rsvd (no Rc)
1871 (0b010000, 0b110001, "ffrc0"), # ffirst, Rc=0
1872 (0b010001, 0b110001, "ffrc1"), # ffirst, Rc=1
1873 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1874 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1875 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1876 )
1877 rm = rm.ldst_imm
1878 search = ((int(rm.mode) << 1) | Rc)
1879
1880 elif record.svp64.mode is _SVMode.LDST_IDX:
1881 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
1882 # mode Rc mask Rc member
1883 table = (
1884 (0b000000, 0b111000, "simple"), # simple (no Rc)
1885 (0b010000, 0b110000, "stride"), # strided, (no Rc)
1886 (0b100000, 0b110000, "sat"), # saturation (no Rc)
1887 (0b110000, 0b110001, "prrc0"), # predicate, Rc=0
1888 (0b110001, 0b110001, "prrc1"), # predicate, Rc=1
1889 )
1890 rm = rm.ldst_idx
1891 search = ((int(rm.mode) << 1) | Rc)
1892
1893 elif record.svp64.mode is _SVMode.CROP:
1894 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
1895 # mode 3b mask 3b member
1896 table = (
1897 (0b000000, 0b111000, "simple"), # simple
1898 (0b001000, 0b111000, "smr"), # mapreduce
1899 (0b100000, 0b100000, "ff5"), # failfirst, 5-bit CR
1900 (0b100001, 0b100001, "ff3"), # failfirst, 3-bit CR
1901 )
1902 # determine CR type, 5-bit (BA/BB/BT) or 3-bit Field (BF/BFA)
1903 regtype = None
1904 for idx in range(0, 4):
1905 for entry in record.svp64.extra[idx]:
1906 if entry.regtype is _SVExtraRegType.DST:
1907 if regtype is not None:
1908 raise ValueError(record.svp64)
1909 regtype = _RegType(entry.reg)
1910 if regtype is _RegType.CR_REG:
1911 regtype = 0 # 5-bit
1912 elif regtype is _RegType.CR_BIT:
1913 regtype = 1 # 3-bit
1914 else:
1915 raise ValueError(record.svp64)
1916 # finally provide info for search
1917 rm = rm.cr_op
1918 search = ((int(rm.mode) << 1) | (regtype or 0))
1919
1920 elif record.svp64.mode is _SVMode.BRANCH:
1921 # just mode 2-bit
1922 # mode mask member
1923 table = (
1924 (0b00, 0b11, "simple"), # simple
1925 (0b01, 0b11, "vls"), # VLset
1926 (0b10, 0b11, "ctr"), # CTR mode
1927 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
1928 )
1929 # slightly weird: doesn't have a 5-bit "mode" field like others
1930 rm = rm.branch
1931 search = int(rm.mode[0, 1])
1932
1933 # look up in table
1934 if table is not None:
1935 for (value, mask, member) in table:
1936 if ((value & search) == (mask & search)):
1937 rm = getattr(rm, member)
1938 break
1939
1940 if rm.__class__ is self.__class__:
1941 raise ValueError(self)
1942
1943 return rm
1944
1945
1946 class SVP64Instruction(PrefixedInstruction):
1947 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1948 class Prefix(PrefixedInstruction.Prefix):
1949 id: _Field = (7, 9)
1950 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1951
1952 prefix: Prefix
1953
1954 def record(self, db):
1955 record = db[self.suffix]
1956 if record is None:
1957 raise KeyError(self)
1958 return record
1959
1960 @property
1961 def binary(self):
1962 bits = []
1963 for idx in range(64):
1964 bit = int(self[idx])
1965 bits.append(bit)
1966 return "".join(map(str, bits))
1967
1968 def disassemble(self, db,
1969 byteorder="little",
1970 verbosity=Verbosity.NORMAL):
1971 def blob(integer):
1972 if verbosity <= Verbosity.SHORT:
1973 return ""
1974 else:
1975 blob = integer.to_bytes(length=4, byteorder=byteorder)
1976 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1977 return f"{blob} "
1978
1979 record = self.record(db=db)
1980 blob_prefix = blob(int(self.prefix))
1981 blob_suffix = blob(int(self.suffix))
1982 if record is None or record.svp64 is None:
1983 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
1984 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
1985 return
1986
1987 name = f"sv.{record.name}"
1988
1989 Rc = False
1990 if record.mdwn.operands["Rc"] is not None:
1991 Rc = bool(record.mdwn.operands["Rc"].value)
1992 rm = self.prefix.rm.select(record=record, Rc=Rc)
1993
1994 # convert specifiers to /x/y/z (sorted lexicographically)
1995 specifiers = sorted(rm.specifiers(record=record))
1996 if specifiers: # if any add one extra to get the extra "/"
1997 specifiers = ([""] + specifiers)
1998 specifiers = "/".join(specifiers)
1999
2000 # convert operands to " ,x,y,z"
2001 operands = tuple(map(_operator.itemgetter(1),
2002 self.dynamic_operands(db=db, verbosity=verbosity)))
2003 operands = ",".join(operands)
2004 if len(operands) > 0: # if any separate with a space
2005 operands = (" " + operands)
2006
2007 yield f"{blob_prefix}{name}{specifiers}{operands}"
2008 if blob_suffix:
2009 yield f"{blob_suffix}"
2010
2011 if verbosity >= Verbosity.VERBOSE:
2012 indent = (" " * 4)
2013 binary = self.binary
2014 spec = self.spec(db=db, prefix="sv.")
2015
2016 yield f"{indent}spec"
2017 yield f"{indent}{indent}{spec}"
2018 yield f"{indent}pcode"
2019 for stmt in record.mdwn.pcode:
2020 yield f"{indent}{indent}{stmt}"
2021 yield f"{indent}binary"
2022 yield f"{indent}{indent}[0:8] {binary[0:8]}"
2023 yield f"{indent}{indent}[8:16] {binary[8:16]}"
2024 yield f"{indent}{indent}[16:24] {binary[16:24]}"
2025 yield f"{indent}{indent}[24:32] {binary[24:32]}"
2026 yield f"{indent}{indent}[32:40] {binary[32:40]}"
2027 yield f"{indent}{indent}[40:48] {binary[40:48]}"
2028 yield f"{indent}{indent}[48:56] {binary[48:56]}"
2029 yield f"{indent}{indent}[56:64] {binary[56:64]}"
2030 yield f"{indent}opcodes"
2031 for opcode in record.opcodes:
2032 yield f"{indent}{indent}{opcode!r}"
2033 for operand in record.mdwn.operands:
2034 yield from operand.disassemble(insn=self, record=record,
2035 verbosity=verbosity, indent=indent)
2036 yield f"{indent}RM"
2037 yield f"{indent}{indent}{rm.__doc__}"
2038 for line in rm.disassemble(verbosity=verbosity):
2039 yield f"{indent}{indent}{line}"
2040 yield ""
2041
2042
2043 def parse(stream, factory):
2044 def match(entry):
2045 return ("TODO" not in frozenset(entry.values()))
2046
2047 lines = filter(lambda line: not line.strip().startswith("#"), stream)
2048 entries = _csv.DictReader(lines)
2049 entries = filter(match, entries)
2050 return tuple(map(factory, entries))
2051
2052
2053 class MarkdownDatabase:
2054 def __init__(self):
2055 db = {}
2056 for (name, desc) in _ISA():
2057 operands = []
2058 if desc.regs:
2059 (dynamic, *static) = desc.regs
2060 operands.extend(dynamic)
2061 operands.extend(static)
2062 pcode = PCode(iterable=desc.pcode)
2063 operands = Operands(insn=name, iterable=operands)
2064 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
2065
2066 self.__db = db
2067
2068 return super().__init__()
2069
2070 def __iter__(self):
2071 yield from self.__db.items()
2072
2073 def __contains__(self, key):
2074 return self.__db.__contains__(key)
2075
2076 def __getitem__(self, key):
2077 return self.__db.__getitem__(key)
2078
2079
2080 class FieldsDatabase:
2081 def __init__(self):
2082 db = {}
2083 df = _DecodeFields()
2084 df.create_specs()
2085 for (form, fields) in df.instrs.items():
2086 if form in {"DQE", "TX"}:
2087 continue
2088 if form == "all":
2089 form = "NONE"
2090 db[_Form[form]] = Fields(fields)
2091
2092 self.__db = db
2093
2094 return super().__init__()
2095
2096 def __getitem__(self, key):
2097 return self.__db.__getitem__(key)
2098
2099
2100 class PPCDatabase:
2101 def __init__(self, root, mdwndb):
2102 # The code below groups the instructions by section:identifier.
2103 # We use the comment as an identifier, there's nothing better.
2104 # The point is to capture different opcodes for the same instruction.
2105 dd = _collections.defaultdict
2106 records = dd(lambda: dd(set))
2107 path = (root / "insndb.csv")
2108 with open(path, "r", encoding="UTF-8") as stream:
2109 for section in parse(stream, Section.CSV):
2110 path = (root / section.path)
2111 opcode_cls = {
2112 section.Mode.INTEGER: IntegerOpcode,
2113 section.Mode.PATTERN: PatternOpcode,
2114 }[section.mode]
2115 factory = _functools.partial(
2116 PPCRecord.CSV, opcode_cls=opcode_cls)
2117 with open(path, "r", encoding="UTF-8") as stream:
2118 for insn in parse(stream, factory):
2119 records[section][insn.comment].add(insn)
2120
2121 sections = dd(set)
2122 for (section, group) in records.items():
2123 for records in group.values():
2124 sections[section].add(PPCMultiRecord(records))
2125
2126 db = {}
2127 for (section, records) in sections.items():
2128 for record in records:
2129 def exact_match(names):
2130 for name in names:
2131 if name in mdwndb:
2132 yield name
2133
2134 def Rc_match(names):
2135 for name in names:
2136 if f"{name}." in mdwndb:
2137 yield f"{name}."
2138 yield name
2139
2140 def LK_match(names):
2141 if "lk" not in record.flags:
2142 yield from names
2143 return
2144
2145 for name in names:
2146 if f"{name}l" in mdwndb:
2147 yield f"{name}l"
2148 yield name
2149
2150 def AA_match(names):
2151 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
2152 yield from names
2153 return
2154
2155 for name in names:
2156 operands = mdwndb[name].operands["AA"]
2157 if ((operands is not None) and
2158 (f"{name}a" in mdwndb)):
2159 yield f"{name}a"
2160 yield name
2161
2162 def reductor(names, match):
2163 return match(names)
2164
2165 matches = (exact_match, Rc_match, LK_match, AA_match)
2166
2167 names = _functools.reduce(reductor, matches, record.names)
2168 for name in names:
2169 db[name] = (section, record)
2170
2171 self.__db = db
2172 self.__mdwndb = mdwndb
2173
2174 return super().__init__()
2175
2176 @_functools.lru_cache(maxsize=512, typed=False)
2177 def __getitem__(self, key):
2178 return self.__db.get(key, (None, None))
2179
2180
2181 class SVP64Database:
2182 def __init__(self, root, ppcdb):
2183 db = set()
2184 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
2185 for (prefix, _, names) in _os.walk(root):
2186 prefix = _pathlib.Path(prefix)
2187 for name in filter(lambda name: pattern.match(name), names):
2188 path = (prefix / _pathlib.Path(name))
2189 with open(path, "r", encoding="UTF-8") as stream:
2190 db.update(parse(stream, SVP64Record.CSV))
2191
2192 self.__db = {record.name:record for record in db}
2193 self.__ppcdb = ppcdb
2194
2195 return super().__init__()
2196
2197 def __getitem__(self, key):
2198 (_, record) = self.__ppcdb[key]
2199 if record is None:
2200 return None
2201
2202 for name in record.names:
2203 record = self.__db.get(name, None)
2204 if record is not None:
2205 return record
2206
2207 return None
2208
2209
2210 class Database:
2211 def __init__(self, root):
2212 root = _pathlib.Path(root)
2213 mdwndb = MarkdownDatabase()
2214 fieldsdb = FieldsDatabase()
2215 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
2216 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
2217
2218 db = set()
2219 names = {}
2220 opcodes = _collections.defaultdict(set)
2221
2222 for (name, mdwn) in mdwndb:
2223 (section, ppc) = ppcdb[name]
2224 if ppc is None:
2225 continue
2226 svp64 = svp64db[name]
2227 fields = fieldsdb[ppc.form]
2228 record = Record(name=name,
2229 section=section, ppc=ppc, svp64=svp64,
2230 mdwn=mdwn, fields=fields)
2231 db.add(record)
2232 names[record.name] = record
2233 PO = section.opcode
2234 if PO is None:
2235 PO = ppc[0].opcode
2236 opcodes[PO.value].add(record)
2237
2238 self.__db = db
2239 self.__names = names
2240 self.__opcodes = opcodes
2241
2242 return super().__init__()
2243
2244 def __repr__(self):
2245 return repr(self.__db)
2246
2247 def __iter__(self):
2248 yield from self.__db
2249
2250 @_functools.lru_cache(maxsize=None)
2251 def __contains__(self, key):
2252 return self.__getitem__(key) is not None
2253
2254 @_functools.lru_cache(maxsize=None)
2255 def __getitem__(self, key):
2256 if isinstance(key, (int, Instruction)):
2257 key = int(key)
2258 XO = int(_SelectableInt(value=int(key), bits=32)[0:6])
2259 for record in self.__opcodes[XO]:
2260 if record.match(key=key):
2261 return record
2262
2263 elif isinstance(key, str):
2264 return self.__names[key]
2265
2266 return None