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