1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
7 import pathlib
as _pathlib
11 from functools
import cached_property
13 from cached_property
import cached_property
15 from openpower
.decoder
.power_enums
import (
16 Function
as _Function
,
23 CROutSel
as _CROutSel
,
25 LDSTMode
as _LDSTMode
,
34 SVExtraRegType
as _SVExtraRegType
,
35 SVExtraReg
as _SVExtraReg
,
37 from openpower
.decoder
.selectable_int
import (
38 SelectableInt
as _SelectableInt
,
39 selectconcat
as _selectconcat
,
41 from openpower
.decoder
.power_fields
import (
44 DecodeFields
as _DecodeFields
,
46 from openpower
.decoder
.pseudo
.pagereader
import ISA
as _ISA
49 def dataclass(cls
, record
, keymap
=None, typemap
=None):
53 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
55 def transform(key_value
):
56 (key
, value
) = key_value
57 key
= keymap
.get(key
, key
)
58 hook
= typemap
.get(key
, lambda value
: value
)
59 if hook
is bool and value
in ("", "0"):
65 record
= dict(map(transform
, record
.items()))
66 for key
in frozenset(record
.keys()):
73 @_functools.total_ordering
74 @_dataclasses.dataclass(eq
=True, frozen
=True)
78 if self
.bit_length() <= 32:
79 return f
"0x{self:08x}"
81 return f
"0x{self:016x}"
85 if self
.bit_length() <= 32:
86 return f
"0x{self:08x}"
88 return f
"0x{self:016x}"
93 def __lt__(self
, other
):
94 if not isinstance(other
, Opcode
):
96 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
98 def __post_init__(self
):
99 (value
, mask
) = (self
.value
, self
.mask
)
101 if isinstance(value
, Opcode
):
103 raise ValueError(mask
)
104 (value
, mask
) = (value
.value
, value
.mask
)
105 elif isinstance(value
, str):
107 raise ValueError(mask
)
108 value
= int(value
, 0)
110 if not isinstance(value
, int):
111 raise ValueError(value
)
114 if not isinstance(mask
, int):
115 raise ValueError(mask
)
117 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
118 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
121 class IntegerOpcode(Opcode
):
122 def __init__(self
, value
):
123 if isinstance(value
, str):
124 value
= int(value
, 0)
125 return super().__init
__(value
=value
, mask
=None)
128 class PatternOpcode(Opcode
):
129 def __init__(self
, value
):
130 (pattern
, value
, mask
) = (value
, 0, 0)
132 for symbol
in pattern
:
133 if symbol
not in {"0", "1", "-"}:
134 raise ValueError(pattern
)
135 value |
= (symbol
== "1")
136 mask |
= (symbol
!= "-")
142 return super().__init
__(value
=value
, mask
=mask
)
145 class FieldsOpcode(Opcode
):
146 def __init__(self
, fields
):
147 def field(opcode
, field
):
148 (value
, mask
) = opcode
149 (field
, bits
) = field
150 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
151 for (index
, shift
) in enumerate(shifts
):
152 bit
= ((field
& (1 << index
)) != 0)
153 value |
= (bit
<< shift
)
157 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
159 return super().__init
__(value
=value
, mask
=mask
)
162 @_dataclasses.dataclass(eq
=True, frozen
=True)
164 class FlagsMeta(type):
179 class Flags(frozenset, metaclass
=FlagsMeta
):
180 def __new__(cls
, flags
=frozenset()):
181 flags
= frozenset(flags
)
182 diff
= (flags
- frozenset(cls
))
184 raise ValueError(flags
)
185 return super().__new
__(cls
, flags
)
189 flags
: Flags
= Flags()
191 function
: _Function
= _Function
.NONE
192 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
193 in1
: _In1Sel
= _In1Sel
.RA
194 in2
: _In2Sel
= _In2Sel
.NONE
195 in3
: _In3Sel
= _In3Sel
.NONE
196 out
: _OutSel
= _OutSel
.NONE
197 cr_in
: _CRInSel
= _CRInSel
.NONE
198 cr_out
: _CROutSel
= _CROutSel
.NONE
199 cry_in
: _CryIn
= _CryIn
.ZERO
200 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
201 upd
: _LDSTMode
= _LDSTMode
.NONE
202 rc
: _RCOE
= _RCOE
.NONE
203 form
: _Form
= _Form
.NONE
205 unofficial
: bool = False
209 "internal op": "intop",
213 "ldst len": "ldst_len",
214 "CONDITIONS": "conditions",
218 def CSV(cls
, record
, opcode_cls
=Opcode
):
219 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
220 typemap
["opcode"] = opcode_cls
223 for flag
in frozenset(PPCRecord
.Flags
):
224 if bool(record
.pop(flag
, "")):
226 record
["flags"] = PPCRecord
.Flags(flags
)
228 return dataclass(cls
, record
, keymap
=PPCRecord
.__KEYMAP
, typemap
=typemap
)
232 return frozenset(self
.comment
.split("=")[-1].split("/"))
235 @_dataclasses.dataclass(eq
=True, frozen
=True)
237 class ExtraMap(tuple):
239 @_dataclasses.dataclass(eq
=True, frozen
=True)
241 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
242 reg
: _SVExtraReg
= _SVExtraReg
.NONE
245 return f
"{self.regtype.value}:{self.reg.name}"
247 def __new__(cls
, value
="0"):
248 if isinstance(value
, str):
249 def transform(value
):
250 (regtype
, reg
) = value
.split(":")
251 regtype
= _SVExtraRegType(regtype
)
252 reg
= _SVExtraReg(reg
)
253 return cls
.Entry(regtype
=regtype
, reg
=reg
)
258 value
= map(transform
, value
.split(";"))
260 return super().__new
__(cls
, value
)
263 return repr(list(self
))
265 def __new__(cls
, value
=tuple()):
269 return super().__new
__(cls
, map(cls
.Extra
, value
))
272 return repr({index
:self
[index
] for index
in range(0, 4)})
275 ptype
: _SVPtype
= _SVPtype
.NONE
276 etype
: _SVEtype
= _SVEtype
.NONE
277 in1
: _In1Sel
= _In1Sel
.NONE
278 in2
: _In2Sel
= _In2Sel
.NONE
279 in3
: _In3Sel
= _In3Sel
.NONE
280 out
: _OutSel
= _OutSel
.NONE
281 out2
: _OutSel
= _OutSel
.NONE
282 cr_in
: _CRInSel
= _CRInSel
.NONE
283 cr_out
: _CROutSel
= _CROutSel
.NONE
284 extra
: ExtraMap
= ExtraMap()
287 mode
: _SVMode
= _SVMode
.NORMAL
291 "CONDITIONS": "conditions",
300 def CSV(cls
, record
):
301 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
306 record
["extra"] = cls
.ExtraMap(record
.pop(f
"{index}") for index
in range(0, 4))
308 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
312 def __init__(self
, value
=(0, 32)):
313 if isinstance(value
, str):
314 (start
, end
) = map(int, value
.split(":"))
317 if start
< 0 or end
< 0 or start
>= end
:
318 raise ValueError(value
)
323 return super().__init
__()
326 return f
"[{self.__start}:{self.__end}]"
329 yield from range(self
.start
, (self
.end
+ 1))
340 @_dataclasses.dataclass(eq
=True, frozen
=True)
342 class Mode(_enum
.Enum
):
343 INTEGER
= _enum
.auto()
344 PATTERN
= _enum
.auto()
347 def _missing_(cls
, value
):
348 if isinstance(value
, str):
349 return cls
[value
.upper()]
350 return super()._missing
_(value
)
353 def __new__(cls
, value
=None):
354 if isinstance(value
, str):
355 if value
.upper() == "NONE":
358 value
= int(value
, 0)
362 return super().__new
__(cls
, value
)
368 return (bin(self
) if self
else "None")
377 def CSV(cls
, record
):
378 return dataclass(cls
, record
)
382 def __init__(self
, items
):
383 if isinstance(items
, dict):
384 items
= items
.items()
387 (name
, bitrange
) = item
388 return (name
, tuple(bitrange
.values()))
390 self
.__mapping
= dict(map(transform
, items
))
392 return super().__init
__()
395 return repr(self
.__mapping
)
398 yield from self
.__mapping
.items()
400 def __contains__(self
, key
):
401 return self
.__mapping
.__contains
__(key
)
403 def __getitem__(self
, key
):
404 return self
.__mapping
.get(key
, None)
408 @_dataclasses.dataclass(eq
=True, frozen
=True)
412 def disassemble(self
, value
, record
):
413 raise NotImplementedError
415 @_dataclasses.dataclass(eq
=True, frozen
=True)
416 class DynamicOperand(Operand
):
417 def disassemble(self
, value
, record
):
418 return str(int(value
[record
.fields
[self
.name
]]))
420 @_dataclasses.dataclass(eq
=True, frozen
=True)
421 class StaticOperand(Operand
):
424 @_dataclasses.dataclass(eq
=True, frozen
=True)
425 class DynamicOperandIFormLI(DynamicOperand
):
426 def disassemble(self
, value
, record
):
427 return hex(int(_selectconcat(
428 value
[record
.fields
["LI"]],
429 _SelectableInt(value
=0b00, bits
=2))))
431 class DynamicOperandBFormBD(DynamicOperand
):
432 def disassemble(self
, value
, record
):
433 return hex(int(_selectconcat(
434 value
[record
.fields
["BD"]],
435 _SelectableInt(value
=0b00, bits
=2))))
437 @_dataclasses.dataclass(eq
=True, frozen
=True)
438 class DynamicOperandGPR(DynamicOperand
):
439 def disassemble(self
, value
, record
):
440 return f
"r{super().disassemble(value=value, record=record)}"
442 @_dataclasses.dataclass(eq
=True, frozen
=True)
443 class DynamicOperandFPR(DynamicOperand
):
444 def disassemble(self
, value
, record
):
445 return f
"f{super().disassemble(value=value, record=record)}"
447 def __init__(self
, insn
, iterable
):
449 "b": {"LI": self
.__class
__.DynamicOperandIFormLI
},
450 "ba": {"LI": self
.__class
__.DynamicOperandIFormLI
},
451 "bl": {"LI": self
.__class
__.DynamicOperandIFormLI
},
452 "bla": {"LI": self
.__class
__.DynamicOperandIFormLI
},
453 "bc": {"BD": self
.__class
__.DynamicOperandBFormBD
},
454 "bca": {"BD": self
.__class
__.DynamicOperandBFormBD
},
455 "bcl": {"BD": self
.__class
__.DynamicOperandBFormBD
},
456 "bcla": {"BD": self
.__class
__.DynamicOperandBFormBD
},
460 for operand
in iterable
:
461 dynamic_cls
= self
.__class
__.DynamicOperand
462 static_cls
= self
.__class
__.StaticOperand
465 (name
, value
) = operand
.split("=")
466 operand
= static_cls(name
=name
, value
=int(value
))
468 if insn
in branches
and operand
in branches
[insn
]:
469 dynamic_cls
= branches
[insn
][operand
]
471 if operand
in _RegType
.__members
__:
472 regtype
= _RegType
[operand
]
473 if regtype
is _RegType
.GPR
:
474 dynamic_cls
= self
.__class
__.DynamicOperandGPR
475 elif regtype
is _RegType
.FPR
:
476 dynamic_cls
= self
.__class
__.DynamicOperandFPR
478 operand
= dynamic_cls(name
=operand
)
480 operands
.append(operand
)
482 self
.__operands
= operands
484 return super().__init
__()
487 return self
.__operands
.__repr
__()
490 yield from self
.__operands
492 def __getitem__(self
, key
):
493 for operand
in self
.__operands
:
494 if operand
.name
== key
:
502 if isinstance(operand
, self
.__class
__.DynamicOperand
):
508 if isinstance(operand
, self
.__class
__.StaticOperand
):
512 @_functools.total_ordering
513 @_dataclasses.dataclass(eq
=True, frozen
=True)
520 svp64
: SVP64Record
= None
529 def __lt__(self
, other
):
530 if not isinstance(other
, Record
):
531 return NotImplemented
532 return (self
.opcode
< other
.opcode
)
535 return f
"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
540 if self
.section
.opcode
:
541 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
542 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
544 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
546 for operand
in self
.operands
.static
:
547 fields
+= [(operand
.value
, self
.fields
[operand
.name
])]
549 return FieldsOpcode(fields
)
553 return self
.ppc
.function
573 if self
.svp64
is None:
579 return self
.ppc
.cr_in
583 return self
.ppc
.cr_out
585 def sv_extra(self
, key
):
586 if key
not in frozenset({
587 "in1", "in2", "in3", "cr_in",
588 "out", "out2", "cr_out",
592 sel
= getattr(self
.svp64
, key
)
593 if sel
is _CRInSel
.BA_BB
:
594 return _SVExtra
.Idx_1_2
595 reg
= _SVExtraReg(sel
)
596 if reg
is _SVExtraReg
.NONE
:
600 _SVExtraRegType
.SRC
: {},
601 _SVExtraRegType
.DST
: {},
603 for index
in range(0, 4):
604 for entry
in self
.svp64
.extra
[index
]:
605 extra_map
[entry
.regtype
][entry
.reg
] = Record
.__EXTRA
[index
]
607 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
608 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
609 if extra
is not _SVExtra
.NONE
:
614 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
615 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
616 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
617 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
618 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
619 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
620 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
624 if self
.svp64
is None:
626 return self
.svp64
.ptype
630 if self
.svp64
is None:
632 return self
.svp64
.etype
635 class Instruction(_Mapping
):
637 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
638 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
639 raise ValueError(bits
)
641 if isinstance(value
, bytes
):
642 if ((len(value
) * 8) != bits
):
643 raise ValueError(f
"bit length mismatch")
644 value
= int.from_bytes(value
, byteorder
=byteorder
)
646 if isinstance(value
, int):
647 value
= _SelectableInt(value
=value
, bits
=bits
)
648 elif isinstance(value
, Instruction
):
649 value
= value
.storage
651 if not isinstance(value
, _SelectableInt
):
652 raise ValueError(value
)
655 if len(value
) != bits
:
656 raise ValueError(value
)
658 value
= _SelectableInt(value
=value
, bits
=bits
)
660 return cls(storage
=value
)
663 return hash(int(self
))
665 def disassemble(self
, db
, byteorder
="little"):
666 raise NotImplementedError
669 class WordInstruction(Instruction
):
670 _
: _Field
= range(0, 32)
671 po
: _Field
= range(0, 6)
674 def integer(cls
, value
, byteorder
="little"):
675 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
677 def disassemble(self
, db
, byteorder
="little"):
679 blob
= integer
.to_bytes(length
=4, byteorder
=byteorder
)
680 blob
= " ".join(map(lambda byte
: f
"{byte:02x}", blob
))
684 yield f
"{blob} .long 0x{integer:08x}"
687 for operand
in record
.operands
.dynamic
:
688 operand
= operand
.disassemble(self
, record
)
689 operands
.append(operand
)
691 operands
= ",".join(operands
)
692 operands
= f
" {operands}"
695 yield f
"{blob} {record.name}{operands}"
697 class PrefixedInstruction(Instruction
):
698 class Prefix(WordInstruction
.remap(range(0, 32))):
701 class Suffix(WordInstruction
.remap(range(32, 64))):
704 _
: _Field
= range(64)
710 def integer(cls
, value
, byteorder
="little"):
711 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
714 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
715 def transform(value
):
716 return WordInstruction
.integer(value
=value
,
717 byteorder
=byteorder
)[0:32]
719 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
720 value
= _selectconcat(prefix
, suffix
)
722 return super().integer(value
=value
)
725 class SVP64Instruction(PrefixedInstruction
):
726 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
727 class Prefix(PrefixedInstruction
.Prefix
):
729 _
: _Field
= range(24)
731 mask
: _Field
= range(1, 4)
732 elwidth
: _Field
= range(4, 6)
733 ewsrc
: _Field
= range(6, 8)
734 subvl
: _Field
= range(8, 10)
735 extra
: _Field
= range(10, 19)
736 mode
: _Field
= range(19, 24)
737 extra2
: _Field
[4] = (
743 smask
: _Field
= range(16, 19)
744 extra3
: _Field
[3] = (
751 rm
: RM
= ((6, 8) + tuple(range(10, 32)))
755 def disassemble(self
, db
, byteorder
="little"):
756 integer_prefix
= int(self
.prefix
)
757 blob_prefix
= integer_prefix
.to_bytes(length
=4, byteorder
=byteorder
)
758 blob_prefix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_prefix
))
760 integer_suffix
= int(self
.suffix
)
761 blob_suffix
= integer_suffix
.to_bytes(length
=4, byteorder
=byteorder
)
762 blob_suffix
= " ".join(map(lambda byte
: f
"{byte:02x}", blob_suffix
))
764 record
= db
[self
.suffix
]
765 if record
is None or record
.svp64
is None:
766 yield f
"{blob_prefix} .long 0x{int(self.prefix):08x}"
767 yield f
"{blob_suffix} .long 0x{int(self.suffix):08x}"
769 yield f
"{blob_prefix} sv.{record.name}"
770 yield f
"{blob_suffix}"
773 def parse(stream
, factory
):
774 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
775 entries
= _csv
.DictReader(lines
)
776 entries
= filter(lambda entry
: "TODO" not in frozenset(entry
.values()), entries
)
777 return tuple(map(factory
, entries
))
780 class MarkdownDatabase
:
783 for (name
, desc
) in _ISA():
786 (dynamic
, *static
) = desc
.regs
787 operands
.extend(dynamic
)
788 operands
.extend(static
)
789 db
[name
] = Operands(insn
=name
, iterable
=operands
)
791 return super().__init
__()
794 yield from self
.__db
.items()
796 def __getitem__(self
, key
):
797 return self
.__db
.__getitem
__(key
)
800 class FieldsDatabase
:
805 for (form
, fields
) in df
.instrs
.items():
806 if form
in {"DQE", "TX"}:
810 db
[_Form
[form
]] = Fields(fields
)
814 return super().__init
__()
816 def __getitem__(self
, key
):
817 return self
.__db
.__getitem
__(key
)
821 def __init__(self
, root
, mdwndb
, fieldsdb
):
822 db
= _collections
.defaultdict(set)
823 path
= (root
/ "insndb.csv")
824 with
open(path
, "r", encoding
="UTF-8") as stream
:
825 for section
in parse(stream
, Section
.CSV
):
826 path
= (root
/ section
.path
)
828 section
.Mode
.INTEGER
: IntegerOpcode
,
829 section
.Mode
.PATTERN
: PatternOpcode
,
831 factory
= _functools
.partial(PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
832 with
open(path
, "r", encoding
="UTF-8") as stream
:
833 db
[section
].update(parse(stream
, factory
))
836 self
.__mdwndb
= mdwndb
837 self
.__fieldsdb
= fieldsdb
839 return super().__init
__()
841 def __getitem__(self
, key
):
842 def exact_match(key
, record
):
843 for name
in record
.names
:
849 def Rc_match(key
, record
):
850 if not key
.endswith("."):
853 if not record
.rc
is _RCOE
.RC
:
856 return exact_match(key
[:-1], record
)
858 def LK_match(key
, record
):
859 if not key
.endswith("l"):
862 if "lk" not in record
.flags
:
865 return exact_match(key
[:-1], record
)
867 def AA_match(key
, record
):
868 if not key
.endswith("a"):
871 if record
.intop
not in {_MicrOp
.OP_B
, _MicrOp
.OP_BC
}:
874 if self
.__mdwndb
[key
]["AA"] is None:
877 return (exact_match(key
[:-1], record
) or
878 LK_match(key
[:-1], record
))
880 for (section
, records
) in self
.__db
.items():
881 for record
in records
:
882 if (exact_match(key
, record
) or
883 Rc_match(key
, record
) or
884 LK_match(key
, record
) or
885 AA_match(key
, record
)):
886 return (section
, record
)
892 def __init__(self
, root
, ppcdb
):
894 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
895 for (prefix
, _
, names
) in _os
.walk(root
):
896 prefix
= _pathlib
.Path(prefix
)
897 for name
in filter(lambda name
: pattern
.match(name
), names
):
898 path
= (prefix
/ _pathlib
.Path(name
))
899 with
open(path
, "r", encoding
="UTF-8") as stream
:
900 db
.update(parse(stream
, SVP64Record
.CSV
))
902 self
.__db
= {record
.name
:record
for record
in db
}
905 return super().__init
__()
907 def __getitem__(self
, key
):
908 (_
, record
) = self
.__ppcdb
[key
]
912 for name
in record
.names
:
913 record
= self
.__db
.get(name
, None)
914 if record
is not None:
921 def __init__(self
, root
):
922 root
= _pathlib
.Path(root
)
924 mdwndb
= MarkdownDatabase()
925 fieldsdb
= FieldsDatabase()
926 ppcdb
= PPCDatabase(root
=root
, mdwndb
=mdwndb
, fieldsdb
=fieldsdb
)
927 svp64db
= SVP64Database(root
=root
, ppcdb
=ppcdb
)
930 for (name
, operands
) in mdwndb
:
931 (section
, ppc
) = ppcdb
[name
]
934 svp64
= svp64db
[name
]
935 fields
= fieldsdb
[ppc
.form
]
936 record
= Record(name
=name
,
937 section
=section
, ppc
=ppc
, svp64
=svp64
,
938 operands
=operands
, fields
=fields
)
941 self
.__db
= tuple(sorted(db
))
943 return super().__init
__()
946 return repr(self
.__db
)
951 @_functools.lru_cache(maxsize
=None)
952 def __contains__(self
, key
):
953 return self
.__getitem
__(key
) is not None
955 @_functools.lru_cache(maxsize
=None)
956 def __getitem__(self
, key
):
957 if isinstance(key
, (int, Instruction
)):
960 opcode
= record
.opcode
961 if ((opcode
.value
& opcode
.mask
) ==
962 (key
& opcode
.mask
)):
965 elif isinstance(key
, Opcode
):
967 if record
.opcode
== key
:
969 elif isinstance(key
, str):
971 if record
.name
== key
: