add CR5Operand and CR3Operand to power_insns.py
[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 if vector:
705 value = ((value << vshift) | (spec<<spshft))
706 span = (span[0:3] + spec_span + ('{0}', '{0}') + span[3:5])
707 else:
708 value = ((spec << sshift) | value)
709 span = (('{0}', '{0}') + spec_span + span)
710
711 # add the 2 LSBs back in
712 #print ("after", bin(value.value), value.bits)
713 return (value, span)
714
715 return super().spec(insn=insn, record=record, merge=merge)
716
717
718 # exactly the same as CR3Operand, should be exactly the same base class
719 # which should also be exactly the same base class as GPR and FPR operand
720 # which sohuld be taking a constructor with prefix "r" and "f" as options
721 # as well as vshift, sshift and spsft as parameters, and whether
722 # to skip 2 LSBs and put them back on afterwards.
723 # it's all the exact same scheme, so why on earth duplicate code?
724 class CR5Operand(RegisterOperand):
725 def spec(self, insn, record):
726 def merge(vector, value, span, spec, spec_span):
727 # record the 2 lsbs first
728 lsbs = _SelectableInt(value=value.value&3, bits=2)
729 bits = (len(span) + len(spec_span))
730 #print ("value", bin(value.value), value.bits)
731 value = _SelectableInt(value=value.value>>2, bits=bits)
732 spec = _SelectableInt(value=spec.value, bits=bits)
733 #print ("spec", bin(spec.value), spec.bits)
734 #print ("value", bin(value.value), value.bits)
735 #print ("lsbs", bin(lsbs.value), lsbs.bits)
736 # this is silly these should be in a general base class,
737 # settable by constructor
738 vshift = 4
739 sshift = 3
740 spshft = 2
741 if vector:
742 value = ((value << vshift) | (spec<<spshft))
743 span = (span[0:3] + spec_span + ('{0}', '{0}') + span[3:5])
744 else:
745 value = ((spec << sshift) | value)
746 span = (('{0}', '{0}') + spec_span + span)
747
748 # add the 2 LSBs back in
749 res = _SelectableInt(value=(value.value<<2)+lsbs.value, bits=bits+2)
750 #print ("after", bin(value.value), value.bits)
751 #print ("res", bin(res.value), res.bits)
752 return (res, span)
753
754 return super().spec(insn=insn, record=record, merge=merge)
755
756
757 # this is silly, all of these should be the same base class
758 class DynamicOperandCR(RegisterOperand):
759 def spec(self, insn, record):
760 def merge(vector, value, span, spec, spec_span):
761 bits = (len(span) + len(spec_span))
762 value = _SelectableInt(value=value.value, bits=bits)
763 spec = _SelectableInt(value=spec.value, bits=bits)
764 if vector:
765 dst_value = []
766 dst_span = []
767 table = (
768 (value, span, (0, 1, 2)),
769 (spec, spec_span, (0, 1)),
770 (value, span, (3, 4)),
771 )
772 else:
773 dst_value = [
774 _SelectableInt(value=0, bits=1),
775 _SelectableInt(value=0, bits=1),
776 ]
777 dst_span = ["{0}", "{0}"]
778 table = (
779 (spec, spec_span, (0, 1)),
780 (value, span, (0, 1, 2, 3, 4)),
781 )
782
783 for (src_value, src_span, sel) in table:
784 for idx in sel:
785 dst_value.append(src_value[idx])
786 dst_span.append(src_span[idx])
787
788 value = _selectconcat(dst_value)
789 span = tuple(dst_span)
790
791 return (value, span)
792
793 return super().spec(insn=insn, record=record, merge=merge)
794
795 def disassemble(self, insn, record, verbose=False, indent=""):
796 yield from super().disassemble(prefix="cr",
797 insn=insn, record=record, verbose=verbose, indent=indent)
798
799
800 class TargetAddrOperand(RegisterOperand):
801 def disassemble(self, insn, record, field,
802 verbosity=Verbosity.NORMAL, indent=""):
803 span = self.span(record=record)
804 if isinstance(insn, SVP64Instruction):
805 span = tuple(map(lambda bit: (bit + 32), span))
806 value = insn[span]
807
808 if verbosity >= Verbosity.VERBOSE:
809 span = tuple(map(str, span))
810 yield f"{indent}{self.name} = EXTS({field} || 0b00))"
811 yield f"{indent}{indent}{field}"
812 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}00"
813 yield f"{indent}{indent}{indent}{', '.join(span + ('{0}', '{0}'))}"
814 else:
815 yield hex(int(_selectconcat(value,
816 _SelectableInt(value=0b00, bits=2))))
817
818
819 class TargetAddrOperandLI(TargetAddrOperand):
820 def span(self, record):
821 return record.fields["LI"]
822
823 def disassemble(self, insn, record,
824 verbosity=Verbosity.NORMAL, indent=""):
825 return super().disassemble(field="LI",
826 insn=insn, record=record,
827 verbosity=verbosity, indent=indent)
828
829
830 class TargetAddrOperandBD(TargetAddrOperand):
831 def span(self, record):
832 return record.fields["BD"]
833
834 def disassemble(self, insn, record,
835 verbosity=Verbosity.NORMAL, indent=""):
836 return super().disassemble(field="BD",
837 insn=insn, record=record,
838 verbosity=verbosity, indent=indent)
839
840
841 class DOperandDX(DynamicOperand):
842 def span(self, record):
843 operands = map(DynamicOperand, ("d0", "d1", "d2"))
844 spans = map(lambda operand: operand.span(record=record), operands)
845 return sum(spans, tuple())
846
847 def disassemble(self, insn, record,
848 verbosity=Verbosity.NORMAL, indent=""):
849 span = self.span(record=record)
850 if isinstance(insn, SVP64Instruction):
851 span = tuple(map(lambda bit: (bit + 32), span))
852 value = insn[span]
853
854 if verbosity >= Verbosity.VERBOSE:
855 yield f"{indent}D"
856 mapping = {
857 "d0": "[0:9]",
858 "d1": "[10:15]",
859 "d2": "[16]",
860 }
861 for (subname, subspan) in mapping.items():
862 operand = DynamicOperand(name=subname)
863 span = operand.span(record=record)
864 if isinstance(insn, SVP64Instruction):
865 span = tuple(map(lambda bit: (bit + 32), span))
866 value = insn[span]
867 span = map(str, span)
868 yield f"{indent}{indent}{operand.name} = D{subspan}"
869 yield f"{indent}{indent}{indent}{int(value):0{value.bits}b}"
870 yield f"{indent}{indent}{indent}{', '.join(span)}"
871 else:
872 yield str(int(value))
873
874
875 class Operands(tuple):
876 def __new__(cls, insn, iterable):
877 custom_insns = {
878 "b": {"target_addr": TargetAddrOperandLI},
879 "ba": {"target_addr": TargetAddrOperandLI},
880 "bl": {"target_addr": TargetAddrOperandLI},
881 "bla": {"target_addr": TargetAddrOperandLI},
882 "bc": {"target_addr": TargetAddrOperandBD},
883 "bca": {"target_addr": TargetAddrOperandBD},
884 "bcl": {"target_addr": TargetAddrOperandBD},
885 "bcla": {"target_addr": TargetAddrOperandBD},
886 "addpcis": {"D": DOperandDX},
887 "fishmv": {"D": DOperandDX},
888 "fmvis": {"D": DOperandDX},
889 }
890 custom_fields = {
891 "SVi": NonZeroOperand,
892 "SVd": NonZeroOperand,
893 "SVxd": NonZeroOperand,
894 "SVyd": NonZeroOperand,
895 "SVzd": NonZeroOperand,
896 }
897
898 operands = []
899 for operand in iterable:
900 dynamic_cls = DynamicOperand
901 static_cls = StaticOperand
902
903 if "=" in operand:
904 (name, value) = operand.split("=")
905 operand = static_cls(name=name, value=int(value))
906 operands.append(operand)
907 else:
908 if operand.endswith(")"):
909 operand = operand.replace("(", " ").replace(")", "")
910 (immediate, _, operand) = operand.partition(" ")
911 else:
912 immediate = None
913
914 if immediate is not None:
915 operands.append(ImmediateOperand(name=immediate))
916
917 if insn in custom_insns and operand in custom_insns[insn]:
918 dynamic_cls = custom_insns[insn][operand]
919 if operand in custom_fields:
920 dynamic_cls = custom_fields[operand]
921
922 if operand in _RegType.__members__:
923 regtype = _RegType[operand]
924 if regtype is _RegType.GPR:
925 dynamic_cls = GPROperand
926 elif regtype is _RegType.FPR:
927 dynamic_cls = FPROperand
928 if regtype is _RegType.CR_BIT: # 5-bit
929 dynamic_cls = CR5Operand
930 if regtype is _RegType.CR_REG: # actually CR Field, 3-bit
931 dynamic_cls = CR3Operand
932
933 operand = dynamic_cls(name=operand)
934 operands.append(operand)
935
936 return super().__new__(cls, operands)
937
938 def __contains__(self, key):
939 return self.__getitem__(key) is not None
940
941 def __getitem__(self, key):
942 for operand in self:
943 if operand.name == key:
944 return operand
945
946 return None
947
948 @property
949 def dynamic(self):
950 for operand in self:
951 if isinstance(operand, DynamicOperand):
952 yield operand
953
954 @property
955 def static(self):
956 for operand in self:
957 if isinstance(operand, StaticOperand):
958 yield operand
959
960
961 class PCode:
962 def __init__(self, iterable):
963 self.__pcode = tuple(iterable)
964 return super().__init__()
965
966 def __iter__(self):
967 yield from self.__pcode
968
969 def __repr__(self):
970 return self.__pcode.__repr__()
971
972
973 @_dataclasses.dataclass(eq=True, frozen=True)
974 class MarkdownRecord:
975 pcode: PCode
976 operands: Operands
977
978
979 @_functools.total_ordering
980 @_dataclasses.dataclass(eq=True, frozen=True)
981 class Record:
982 name: str
983 section: Section
984 ppc: PPCRecord
985 fields: Fields
986 mdwn: MarkdownRecord
987 svp64: SVP64Record = None
988
989 def __lt__(self, other):
990 if not isinstance(other, Record):
991 return NotImplemented
992 return (min(self.opcodes) < min(other.opcodes))
993
994 @property
995 def opcodes(self):
996 def opcode(ppc):
997 value = ([0] * 32)
998 mask = ([0] * 32)
999
1000 PO = self.section.opcode
1001 if PO is not None:
1002 for (src, dst) in enumerate(reversed(BitSel((0, 5)))):
1003 value[dst] = int((PO.value & (1 << src)) != 0)
1004 mask[dst] = int((PO.mask & (1 << src)) != 0)
1005
1006 XO = ppc.opcode
1007 for (src, dst) in enumerate(reversed(self.section.bitsel)):
1008 value[dst] = int((XO.value & (1 << src)) != 0)
1009 mask[dst] = int((XO.mask & (1 << src)) != 0)
1010
1011 for operand in self.mdwn.operands.static:
1012 for (src, dst) in enumerate(reversed(operand.span(record=self))):
1013 value[dst] = int((operand.value & (1 << src)) != 0)
1014 mask[dst] = 1
1015
1016 value = Opcode.Value(int(("".join(map(str, value))), 2))
1017 mask = Opcode.Mask(int(("".join(map(str, mask))), 2))
1018
1019 return Opcode(value=value, mask=mask)
1020
1021 return tuple(sorted(map(opcode, self.ppc)))
1022
1023 def match(self, key):
1024 for opcode in self.opcodes:
1025 if ((opcode.value & opcode.mask) ==
1026 (key & opcode.mask)):
1027 return True
1028 return False
1029
1030 @property
1031 def function(self):
1032 return self.ppc.function
1033
1034 @property
1035 def in1(self):
1036 return self.ppc.in1
1037
1038 @property
1039 def in2(self):
1040 return self.ppc.in2
1041
1042 @property
1043 def in3(self):
1044 return self.ppc.in3
1045
1046 @property
1047 def out(self):
1048 return self.ppc.out
1049
1050 @property
1051 def out2(self):
1052 if self.svp64 is None:
1053 return _OutSel.NONE
1054 return self.ppc.out
1055
1056 @property
1057 def cr_in(self):
1058 return self.ppc.cr_in
1059
1060 @property
1061 def cr_out(self):
1062 return self.ppc.cr_out
1063
1064 ptype = property(lambda self: self.svp64.ptype)
1065 etype = property(lambda self: self.svp64.etype)
1066
1067 def extra_idx(self, key):
1068 return self.svp64.extra_idx(key)
1069
1070 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
1071 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
1072 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
1073 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
1074 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
1075 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
1076 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
1077
1078
1079 class Instruction(_Mapping):
1080 @classmethod
1081 def integer(cls, value=0, bits=None, byteorder="little"):
1082 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1083 raise ValueError(bits)
1084
1085 if isinstance(value, bytes):
1086 if ((len(value) * 8) != bits):
1087 raise ValueError(f"bit length mismatch")
1088 value = int.from_bytes(value, byteorder=byteorder)
1089
1090 if isinstance(value, int):
1091 value = _SelectableInt(value=value, bits=bits)
1092 elif isinstance(value, Instruction):
1093 value = value.storage
1094
1095 if not isinstance(value, _SelectableInt):
1096 raise ValueError(value)
1097 if bits is None:
1098 bits = len(cls)
1099 if len(value) != bits:
1100 raise ValueError(value)
1101
1102 value = _SelectableInt(value=value, bits=bits)
1103
1104 return cls(storage=value)
1105
1106 def __hash__(self):
1107 return hash(int(self))
1108
1109 def record(self, db):
1110 record = db[self]
1111 if record is None:
1112 raise KeyError(self)
1113 return record
1114
1115 def spec(self, db, prefix):
1116 record = self.record(db=db)
1117
1118 dynamic_operands = tuple(map(_operator.itemgetter(0),
1119 self.dynamic_operands(db=db)))
1120
1121 static_operands = []
1122 for (name, value) in self.static_operands(db=db):
1123 static_operands.append(f"{name}={value}")
1124
1125 operands = ""
1126 if dynamic_operands:
1127 operands += f" {','.join(dynamic_operands)}"
1128 if static_operands:
1129 operands += f" ({' '.join(static_operands)})"
1130
1131 return f"{prefix}{record.name}{operands}"
1132
1133 def dynamic_operands(self, db, verbosity=Verbosity.NORMAL):
1134 record = self.record(db=db)
1135
1136 imm = False
1137 imm_name = ""
1138 imm_value = ""
1139 for operand in record.mdwn.operands.dynamic:
1140 name = operand.name
1141 dis = operand.disassemble(insn=self, record=record,
1142 verbosity=min(verbosity, Verbosity.NORMAL))
1143 value = " ".join(dis)
1144 if imm:
1145 name = f"{imm_name}({name})"
1146 value = f"{imm_value}({value})"
1147 imm = False
1148 if isinstance(operand, ImmediateOperand):
1149 imm_name = name
1150 imm_value = value
1151 imm = True
1152 if not imm:
1153 yield (name, value)
1154
1155 def static_operands(self, db):
1156 record = self.record(db=db)
1157 for operand in record.mdwn.operands.static:
1158 yield (operand.name, operand.value)
1159
1160 def disassemble(self, db,
1161 byteorder="little",
1162 verbosity=Verbosity.NORMAL):
1163 raise NotImplementedError
1164
1165
1166 class WordInstruction(Instruction):
1167 _: _Field = range(0, 32)
1168 po: _Field = range(0, 6)
1169
1170 @classmethod
1171 def integer(cls, value, byteorder="little"):
1172 return super().integer(bits=32, value=value, byteorder=byteorder)
1173
1174 @property
1175 def binary(self):
1176 bits = []
1177 for idx in range(32):
1178 bit = int(self[idx])
1179 bits.append(bit)
1180 return "".join(map(str, bits))
1181
1182 def disassemble(self, db,
1183 byteorder="little",
1184 verbosity=Verbosity.NORMAL):
1185 integer = int(self)
1186 if verbosity <= Verbosity.SHORT:
1187 blob = ""
1188 else:
1189 blob = integer.to_bytes(length=4, byteorder=byteorder)
1190 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1191 blob += " "
1192
1193 record = db[self]
1194 if record is None:
1195 yield f"{blob}.long 0x{integer:08x}"
1196 return
1197
1198 operands = tuple(map(_operator.itemgetter(1),
1199 self.dynamic_operands(db=db, verbosity=verbosity)))
1200 if operands:
1201 yield f"{blob}{record.name} {','.join(operands)}"
1202 else:
1203 yield f"{blob}{record.name}"
1204
1205 if verbosity >= Verbosity.VERBOSE:
1206 indent = (" " * 4)
1207 binary = self.binary
1208 spec = self.spec(db=db, prefix="")
1209 yield f"{indent}spec"
1210 yield f"{indent}{indent}{spec}"
1211 yield f"{indent}pcode"
1212 for stmt in record.mdwn.pcode:
1213 yield f"{indent}{indent}{stmt}"
1214 yield f"{indent}binary"
1215 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1216 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1217 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1218 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1219 yield f"{indent}opcodes"
1220 for opcode in record.opcodes:
1221 yield f"{indent}{indent}{opcode!r}"
1222 for operand in record.mdwn.operands:
1223 yield from operand.disassemble(insn=self, record=record,
1224 verbosity=verbosity, indent=indent)
1225 yield ""
1226
1227
1228 class PrefixedInstruction(Instruction):
1229 class Prefix(WordInstruction.remap(range(0, 32))):
1230 pass
1231
1232 class Suffix(WordInstruction.remap(range(32, 64))):
1233 pass
1234
1235 _: _Field = range(64)
1236 prefix: Prefix
1237 suffix: Suffix
1238 po: Suffix.po
1239
1240 @classmethod
1241 def integer(cls, value, byteorder="little"):
1242 return super().integer(bits=64, value=value, byteorder=byteorder)
1243
1244 @classmethod
1245 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1246 def transform(value):
1247 return WordInstruction.integer(value=value,
1248 byteorder=byteorder)[0:32]
1249
1250 (prefix, suffix) = map(transform, (prefix, suffix))
1251 value = _selectconcat(prefix, suffix)
1252
1253 return super().integer(value=value)
1254
1255
1256 class Mode(_Mapping):
1257 _: _Field = range(0, 5)
1258 sel: _Field = range(0, 2)
1259
1260
1261 class NormalMode(Mode):
1262 class simple(Mode):
1263 """simple mode"""
1264 dz: Mode[3]
1265 sz: Mode[4]
1266
1267 class smr(Mode):
1268 """scalar reduce mode (mapreduce), SUBVL=1"""
1269 RG: Mode[4]
1270
1271 class pmr(Mode):
1272 """parallel reduce mode (mapreduce), SUBVL=1"""
1273 pass
1274
1275 class svmr(Mode):
1276 """subvector reduce mode, SUBVL>1"""
1277 SVM: Mode[3]
1278
1279 class pu(Mode):
1280 """Pack/Unpack mode, SUBVL>1"""
1281 SVM: Mode[3]
1282
1283 class ffrc1(Mode):
1284 """Rc=1: ffirst CR sel"""
1285 inv: Mode[2]
1286 CRbit: Mode[3, 4]
1287
1288 class ffrc0(Mode):
1289 """Rc=0: ffirst z/nonz"""
1290 inv: Mode[2]
1291 VLi: Mode[3]
1292 RC1: Mode[4]
1293
1294 class sat(Mode):
1295 """sat mode: N=0/1 u/s, SUBVL=1"""
1296 N: Mode[2]
1297 dz: Mode[3]
1298 sz: Mode[4]
1299
1300 class satx(Mode):
1301 """sat mode: N=0/1 u/s, SUBVL>1"""
1302 N: Mode[2]
1303 zz: Mode[3]
1304 dz: Mode[3]
1305 sz: Mode[3]
1306
1307 class satpu(Mode):
1308 """Pack/Unpack sat mode: N=0/1 u/s, SUBVL>1"""
1309 N: Mode[2]
1310 zz: Mode[3]
1311 dz: Mode[3]
1312 sz: Mode[3]
1313
1314 class prrc1(Mode):
1315 """Rc=1: pred-result CR sel"""
1316 inv: Mode[2]
1317 CRbit: Mode[3, 4]
1318
1319 class prrc0(Mode):
1320 """Rc=0: pred-result z/nonz"""
1321 inv: Mode[2]
1322 zz: Mode[3]
1323 RC1: Mode[4]
1324 dz: Mode[3]
1325 sz: Mode[3]
1326
1327 simple: simple
1328 smr: smr
1329 pmr: pmr
1330 svmr: svmr
1331 pu: pu
1332 ffrc1: ffrc1
1333 ffrc0: ffrc0
1334 sat: sat
1335 satx: satx
1336 satpu: satpu
1337 prrc1: prrc1
1338 prrc0: prrc0
1339
1340
1341 class LDSTImmMode(Mode):
1342 class simple(Mode):
1343 """simple mode"""
1344 zz: Mode[3]
1345 els: Mode[4]
1346 dz: Mode[3]
1347 sz: Mode[3]
1348
1349 class spu(Mode):
1350 """Structured Pack/Unpack"""
1351 zz: Mode[3]
1352 els: Mode[4]
1353 dz: Mode[3]
1354 sz: Mode[3]
1355
1356 class ffrc1(Mode):
1357 """Rc=1: ffirst CR sel"""
1358 inv: Mode[2]
1359 CRbit: Mode[3, 4]
1360
1361 class ffrc0(Mode):
1362 """Rc=0: ffirst z/nonz"""
1363 inv: Mode[2]
1364 els: Mode[3]
1365 RC1: Mode[4]
1366
1367 class sat(Mode):
1368 """sat mode: N=0/1 u/s"""
1369 N: Mode[2]
1370 zz: Mode[3]
1371 els: Mode[4]
1372 dz: Mode[3]
1373 sz: Mode[3]
1374
1375 class prrc1(Mode):
1376 """Rc=1: pred-result CR sel"""
1377 inv: Mode[2]
1378 CRbit: Mode[3, 4]
1379
1380 class prrc0(Mode):
1381 """Rc=0: pred-result z/nonz"""
1382 inv: Mode[2]
1383 els: Mode[3]
1384 RC1: Mode[4]
1385
1386 simple: simple
1387 spu: spu
1388 ffrc1: ffrc1
1389 ffrc0: ffrc0
1390 sat: sat
1391 prrc1: prrc1
1392 prrc0: prrc0
1393
1394
1395 class LDSTIdxMode(Mode):
1396 class simple(Mode):
1397 """simple mode"""
1398 SEA: Mode[2]
1399 sz: Mode[3]
1400 dz: Mode[3]
1401
1402 class stride(Mode):
1403 """strided (scalar only source)"""
1404 SEA: Mode[2]
1405 dz: Mode[3]
1406 sz: Mode[4]
1407
1408 class sat(Mode):
1409 """sat mode: N=0/1 u/s"""
1410 N: Mode[2]
1411 dz: Mode[3]
1412 sz: Mode[4]
1413
1414 class prrc1(Mode):
1415 """Rc=1: pred-result CR sel"""
1416 inv: Mode[2]
1417 CRbit: Mode[3, 4]
1418
1419 class prrc0(Mode):
1420 """Rc=0: pred-result z/nonz"""
1421 inv: Mode[2]
1422 zz: Mode[3]
1423 RC1: Mode[4]
1424 dz: Mode[3]
1425 sz: Mode[3]
1426
1427 simple: simple
1428 stride: stride
1429 sat: sat
1430 prrc1: prrc1
1431 prrc0: prrc0
1432
1433
1434 class Extra(_Mapping):
1435 _: _Field = range(0, 9)
1436
1437
1438 class Extra2(Extra):
1439 idx0: _Field = range(0, 2)
1440 idx1: _Field = range(2, 4)
1441 idx2: _Field = range(4, 6)
1442 idx3: _Field = range(6, 8)
1443
1444 def __getitem__(self, key):
1445 return {
1446 0: self.idx0,
1447 1: self.idx1,
1448 2: self.idx2,
1449 3: self.idx3,
1450 _SVExtra.Idx0: self.idx0,
1451 _SVExtra.Idx1: self.idx1,
1452 _SVExtra.Idx2: self.idx2,
1453 _SVExtra.Idx3: self.idx3,
1454 }[key]
1455
1456 def __setitem__(self, key, value):
1457 self[key].assign(value)
1458
1459
1460 class Extra3(Extra):
1461 idx0: _Field = range(0, 3)
1462 idx1: _Field = range(3, 6)
1463 idx2: _Field = range(6, 9)
1464
1465 def __getitem__(self, key):
1466 return {
1467 0: self.idx0,
1468 1: self.idx1,
1469 2: self.idx2,
1470 _SVExtra.Idx0: self.idx0,
1471 _SVExtra.Idx1: self.idx1,
1472 _SVExtra.Idx2: self.idx2,
1473 }[key]
1474
1475 def __setitem__(self, key, value):
1476 self[key].assign(value)
1477
1478
1479 class RM(_Mapping):
1480 class Mode(Mode):
1481 normal: NormalMode
1482 ldst_imm: LDSTImmMode
1483 ldst_idx: LDSTIdxMode
1484
1485 _: _Field = range(24)
1486 mmode: _Field = (0,)
1487 mask: _Field = range(1, 4)
1488 elwidth: _Field = range(4, 6)
1489 ewsrc: _Field = range(6, 8)
1490 subvl: _Field = range(8, 10)
1491 mode: Mode.remap(range(19, 24))
1492 smask: _Field = range(16, 19)
1493
1494 extra: Extra.remap(range(10, 19))
1495 extra2: Extra2.remap(range(10, 19))
1496 extra3: Extra3.remap(range(10, 19))
1497
1498
1499 class SVP64Instruction(PrefixedInstruction):
1500 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
1501 class Prefix(PrefixedInstruction.Prefix):
1502 id: _Field = (7, 9)
1503 rm: RM.remap((6, 8) + tuple(range(10, 32)))
1504
1505 prefix: Prefix
1506
1507 def record(self, db):
1508 record = db[self.suffix]
1509 if record is None:
1510 raise KeyError(self)
1511 return record
1512
1513 @property
1514 def binary(self):
1515 bits = []
1516 for idx in range(64):
1517 bit = int(self[idx])
1518 bits.append(bit)
1519 return "".join(map(str, bits))
1520
1521 def mode(self, db):
1522 record = self.record(db=db)
1523
1524 Rc = False
1525 if record.mdwn.operands["Rc"] is not None:
1526 Rc = bool(self[record.fields["Rc"]])
1527
1528 record = self.record(db=db)
1529 subvl = self.prefix.rm.subvl
1530 mode = self.prefix.rm.mode
1531 sel = mode.sel
1532
1533 if record.svp64.mode is _SVMode.NORMAL:
1534 mode = mode.normal
1535 if sel == 0b00:
1536 if mode[2] == 0b0:
1537 mode = mode.simple
1538 else:
1539 if subvl == 0b00:
1540 if mode[3] == 0b0:
1541 mode = mode.smr
1542 else:
1543 mode = mode.pmr
1544 else:
1545 if mode[4] == 0b0:
1546 mode = mode.svmr
1547 else:
1548 mode = mode.pu
1549 elif sel == 0b01:
1550 if Rc:
1551 mode = mode.ffrc1
1552 else:
1553 mode = mode.ffrc0
1554 elif sel == 0b10:
1555 if subvl == 0b00:
1556 mode = mode.sat
1557 else:
1558 if mode[4]:
1559 mode = mode.satx
1560 else:
1561 mode = mode.satpu
1562 elif sel == 0b11:
1563 if Rc:
1564 mode = mode.prrc1
1565 else:
1566 mode = mode.prrc0
1567 elif record.svp64.mode is _SVMode.LDST_IMM:
1568 mode = mode.ldst_imm
1569 if sel == 0b00:
1570 if mode[2] == 0b0:
1571 mode = mode.simple
1572 else:
1573 mode = mode.spu
1574 elif sel == 0b01:
1575 if Rc:
1576 mode = mode.ffrc1
1577 else:
1578 mode = mode.ffrc0
1579 elif sel == 0b10:
1580 mode = mode.sat
1581 elif sel == 0b11:
1582 if Rc:
1583 mode = mode.prrc1
1584 else:
1585 mode = mode.prrc0
1586 elif record.svp64.mode is _SVMode.LDST_IMM:
1587 mode = mode.ldst_idx
1588 if mode.sel == 0b00:
1589 mode = mode.simple
1590 elif mode.sel == 0b01:
1591 mode = mode.stride
1592 elif mode.sel == 0b10:
1593 mode = mode.sat
1594 elif mode.sel == 0b11:
1595 if Rc:
1596 mode = mode.prrc1
1597 else:
1598 mode = mode.prrc0
1599
1600 modes = {
1601 NormalMode.simple: "normal: simple",
1602 NormalMode.smr: "normal: smr",
1603 NormalMode.pmr: "normal: pmr",
1604 NormalMode.svmr: "normal: svmr",
1605 NormalMode.pu: "normal: pu",
1606 NormalMode.ffrc1: "normal: ffrc1",
1607 NormalMode.ffrc0: "normal: ffrc0",
1608 NormalMode.sat: "normal: sat",
1609 NormalMode.satx: "normal: satx",
1610 NormalMode.satpu: "normal: satpu",
1611 NormalMode.prrc1: "normal: prrc1",
1612 NormalMode.prrc0: "normal: prrc0",
1613 LDSTImmMode.simple: "ld/st imm: simple",
1614 LDSTImmMode.spu: "ld/st imm: spu",
1615 LDSTImmMode.ffrc1: "ld/st imm: ffrc1",
1616 LDSTImmMode.ffrc0: "ld/st imm: ffrc0",
1617 LDSTImmMode.sat: "ld/st imm: sat",
1618 LDSTImmMode.prrc1: "ld/st imm: prrc1",
1619 LDSTImmMode.prrc0: "ld/st imm: prrc0",
1620 LDSTIdxMode.simple: "ld/st idx simple",
1621 LDSTIdxMode.stride: "ld/st idx stride",
1622 LDSTIdxMode.sat: "ld/st idx sat",
1623 LDSTIdxMode.prrc1: "ld/st idx prrc1",
1624 LDSTIdxMode.prrc0: "ld/st idx prrc0",
1625 }
1626 for (cls, desc) in modes.items():
1627 if isinstance(mode, cls):
1628 return (mode, desc)
1629
1630 if record.svp64.mode is _SVMode.BRANCH:
1631 return (self.prefix.rm.mode, "branch")
1632
1633 raise ValueError(self)
1634
1635 def disassemble(self, db,
1636 byteorder="little",
1637 verbosity=Verbosity.NORMAL):
1638 def blob(integer):
1639 if verbosity <= Verbosity.SHORT:
1640 return ""
1641 else:
1642 blob = integer.to_bytes(length=4, byteorder=byteorder)
1643 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1644 return f"{blob} "
1645
1646 blob_prefix = blob(int(self.prefix))
1647 blob_suffix = blob(int(self.suffix))
1648 record = db[self]
1649 if record is None or record.svp64 is None:
1650 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
1651 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
1652 return
1653
1654 operands = tuple(map(_operator.itemgetter(1),
1655 self.dynamic_operands(db=db, verbosity=verbosity)))
1656 if operands:
1657 yield f"{blob_prefix}sv.{record.name} {','.join(operands)}"
1658 else:
1659 yield f"{blob_prefix}{record.name}"
1660 if blob_suffix:
1661 yield f"{blob_suffix}"
1662
1663 (mode, mode_desc) = self.mode(db=db)
1664
1665 if verbosity >= Verbosity.VERBOSE:
1666 indent = (" " * 4)
1667 binary = self.binary
1668 spec = self.spec(db=db, prefix="sv.")
1669 yield f"{indent}spec"
1670 yield f"{indent}{indent}{spec}"
1671 yield f"{indent}pcode"
1672 for stmt in record.mdwn.pcode:
1673 yield f"{indent}{indent}{stmt}"
1674 yield f"{indent}binary"
1675 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1676 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1677 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1678 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1679 yield f"{indent}{indent}[32:40] {binary[32:40]}"
1680 yield f"{indent}{indent}[40:48] {binary[40:48]}"
1681 yield f"{indent}{indent}[48:56] {binary[48:56]}"
1682 yield f"{indent}{indent}[56:64] {binary[56:64]}"
1683 yield f"{indent}opcodes"
1684 for opcode in record.opcodes:
1685 yield f"{indent}{indent}{opcode!r}"
1686 for operand in record.mdwn.operands:
1687 yield from operand.disassemble(insn=self, record=record,
1688 verbosity=verbosity, indent=indent)
1689
1690 yield f"{indent}mode"
1691 yield f"{indent}{indent}{mode_desc}"
1692 yield ""
1693
1694
1695 def parse(stream, factory):
1696 def match(entry):
1697 return ("TODO" not in frozenset(entry.values()))
1698
1699 lines = filter(lambda line: not line.strip().startswith("#"), stream)
1700 entries = _csv.DictReader(lines)
1701 entries = filter(match, entries)
1702 return tuple(map(factory, entries))
1703
1704
1705 class MarkdownDatabase:
1706 def __init__(self):
1707 db = {}
1708 for (name, desc) in _ISA():
1709 operands = []
1710 if desc.regs:
1711 (dynamic, *static) = desc.regs
1712 operands.extend(dynamic)
1713 operands.extend(static)
1714 pcode = PCode(iterable=desc.pcode)
1715 operands = Operands(insn=name, iterable=operands)
1716 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
1717
1718 self.__db = db
1719
1720 return super().__init__()
1721
1722 def __iter__(self):
1723 yield from self.__db.items()
1724
1725 def __getitem__(self, key):
1726 return self.__db.__getitem__(key)
1727
1728
1729 class FieldsDatabase:
1730 def __init__(self):
1731 db = {}
1732 df = _DecodeFields()
1733 df.create_specs()
1734 for (form, fields) in df.instrs.items():
1735 if form in {"DQE", "TX"}:
1736 continue
1737 if form == "all":
1738 form = "NONE"
1739 db[_Form[form]] = Fields(fields)
1740
1741 self.__db = db
1742
1743 return super().__init__()
1744
1745 def __getitem__(self, key):
1746 return self.__db.__getitem__(key)
1747
1748
1749 class PPCDatabase:
1750 def __init__(self, root, mdwndb):
1751 # The code below groups the instructions by section:identifier.
1752 # We use the comment as an identifier, there's nothing better.
1753 # The point is to capture different opcodes for the same instruction.
1754 dd = _collections.defaultdict
1755 records = dd(lambda: dd(set))
1756 path = (root / "insndb.csv")
1757 with open(path, "r", encoding="UTF-8") as stream:
1758 for section in parse(stream, Section.CSV):
1759 path = (root / section.path)
1760 opcode_cls = {
1761 section.Mode.INTEGER: IntegerOpcode,
1762 section.Mode.PATTERN: PatternOpcode,
1763 }[section.mode]
1764 factory = _functools.partial(
1765 PPCRecord.CSV, opcode_cls=opcode_cls)
1766 with open(path, "r", encoding="UTF-8") as stream:
1767 for insn in parse(stream, factory):
1768 records[section][insn.comment].add(insn)
1769
1770 db = dd(set)
1771 for (section, group) in records.items():
1772 for records in group.values():
1773 db[section].add(PPCMultiRecord(records))
1774
1775 self.__db = db
1776 self.__mdwndb = mdwndb
1777
1778 return super().__init__()
1779
1780 def __getitem__(self, key):
1781 def exact_match(key, record):
1782 for name in record.names:
1783 if name == key:
1784 return True
1785
1786 return False
1787
1788 def Rc_match(key, record):
1789 if not key.endswith("."):
1790 return False
1791
1792 if not record.Rc is _RCOE.RC:
1793 return False
1794
1795 return exact_match(key[:-1], record)
1796
1797 def LK_match(key, record):
1798 if not key.endswith("l"):
1799 return False
1800
1801 if "lk" not in record.flags:
1802 return False
1803
1804 return exact_match(key[:-1], record)
1805
1806 def AA_match(key, record):
1807 if not key.endswith("a"):
1808 return False
1809
1810 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
1811 return False
1812
1813 if self.__mdwndb[key].operands["AA"] is None:
1814 return False
1815
1816 return (exact_match(key[:-1], record) or
1817 LK_match(key[:-1], record))
1818
1819 for (section, records) in self.__db.items():
1820 for record in records:
1821 if exact_match(key, record):
1822 return (section, record)
1823
1824 for record in records:
1825 if (Rc_match(key, record) or
1826 LK_match(key, record) or
1827 AA_match(key, record)):
1828 return (section, record)
1829
1830 return (None, None)
1831
1832
1833 class SVP64Database:
1834 def __init__(self, root, ppcdb):
1835 db = set()
1836 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
1837 for (prefix, _, names) in _os.walk(root):
1838 prefix = _pathlib.Path(prefix)
1839 for name in filter(lambda name: pattern.match(name), names):
1840 path = (prefix / _pathlib.Path(name))
1841 with open(path, "r", encoding="UTF-8") as stream:
1842 db.update(parse(stream, SVP64Record.CSV))
1843
1844 self.__db = {record.name:record for record in db}
1845 self.__ppcdb = ppcdb
1846
1847 return super().__init__()
1848
1849 def __getitem__(self, key):
1850 (_, record) = self.__ppcdb[key]
1851 if record is None:
1852 return None
1853
1854 for name in record.names:
1855 record = self.__db.get(name, None)
1856 if record is not None:
1857 return record
1858
1859 return None
1860
1861
1862 class Database:
1863 def __init__(self, root):
1864 root = _pathlib.Path(root)
1865
1866 mdwndb = MarkdownDatabase()
1867 fieldsdb = FieldsDatabase()
1868 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
1869 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
1870
1871 db = set()
1872 for (name, mdwn) in mdwndb:
1873 (section, ppc) = ppcdb[name]
1874 if ppc is None:
1875 continue
1876 svp64 = svp64db[name]
1877 fields = fieldsdb[ppc.form]
1878 record = Record(name=name,
1879 section=section, ppc=ppc, svp64=svp64,
1880 mdwn=mdwn, fields=fields)
1881 db.add(record)
1882
1883 self.__db = tuple(sorted(db))
1884
1885 return super().__init__()
1886
1887 def __repr__(self):
1888 return repr(self.__db)
1889
1890 def __iter__(self):
1891 yield from self.__db
1892
1893 @_functools.lru_cache(maxsize=None)
1894 def __contains__(self, key):
1895 return self.__getitem__(key) is not None
1896
1897 @_functools.lru_cache(maxsize=None)
1898 def __getitem__(self, key):
1899 if isinstance(key, (int, Instruction)):
1900 key = int(key)
1901 for record in self:
1902 if record.match(key=key):
1903 return record
1904
1905 elif isinstance(key, Opcode):
1906 for record in self:
1907 if record.opcode == key:
1908 return record
1909
1910 elif isinstance(key, str):
1911 for record in self:
1912 if record.name == key:
1913 return record
1914
1915 return None