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