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