1 import collections
as _collections
3 import dataclasses
as _dataclasses
5 import functools
as _functools
7 import operator
as _operator
8 import pathlib
as _pathlib
12 from functools
import cached_property
14 from cached_property
import cached_property
16 from openpower
.decoder
.power_enums
import (
17 Function
as _Function
,
24 CROutSel
as _CROutSel
,
26 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 (
47 def dataclass(cls
, record
, keymap
=None, typemap
=None):
51 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
53 def transform(key_value
):
54 (key
, value
) = key_value
55 key
= keymap
.get(key
, key
)
56 hook
= typemap
.get(key
, lambda value
: value
)
57 if hook
is bool and value
in ("", "0"):
63 record
= dict(map(transform
, record
.items()))
64 for key
in frozenset(record
.keys()):
71 @_functools.total_ordering
72 @_dataclasses.dataclass(eq
=True, frozen
=True)
76 if self
.bit_length() <= 32:
77 return f
"0x{self:08x}"
79 return f
"0x{self:016x}"
83 if self
.bit_length() <= 32:
84 return f
"0x{self:08x}"
86 return f
"0x{self:016x}"
91 def __lt__(self
, other
):
92 if not isinstance(other
, Opcode
):
94 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
96 def __post_init__(self
):
97 (value
, mask
) = (self
.value
, self
.mask
)
99 if isinstance(value
, Opcode
):
101 raise ValueError(mask
)
102 (value
, mask
) = (value
.value
, value
.mask
)
103 elif isinstance(value
, str):
105 raise ValueError(mask
)
106 value
= int(value
, 0)
108 if not isinstance(value
, int):
109 raise ValueError(value
)
112 if not isinstance(mask
, int):
113 raise ValueError(mask
)
115 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
116 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
119 class IntegerOpcode(Opcode
):
120 def __init__(self
, value
):
121 if isinstance(value
, str):
122 value
= int(value
, 0)
123 return super().__init
__(value
=value
, mask
=None)
126 class PatternOpcode(Opcode
):
127 def __init__(self
, value
):
128 (pattern
, value
, mask
) = (value
, 0, 0)
130 for symbol
in pattern
:
131 if symbol
not in {"0", "1", "-"}:
132 raise ValueError(pattern
)
133 value |
= (symbol
== "1")
134 mask |
= (symbol
!= "-")
140 return super().__init
__(value
=value
, mask
=mask
)
143 class FieldsOpcode(Opcode
):
144 def __init__(self
, fields
):
145 def field(opcode
, field
):
146 (value
, mask
) = opcode
147 (field
, bits
) = field
148 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
149 for (index
, shift
) in enumerate(shifts
):
150 bit
= ((field
& (1 << index
)) != 0)
151 value |
= (bit
<< shift
)
155 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
157 return super().__init
__(value
=value
, mask
=mask
)
160 @_dataclasses.dataclass(eq
=True, frozen
=True)
162 class FlagsMeta(type):
177 class Flags(frozenset, metaclass
=FlagsMeta
):
178 def __new__(cls
, flags
=frozenset()):
179 flags
= frozenset(flags
)
180 diff
= (flags
- frozenset(cls
))
182 raise ValueError(flags
)
183 return super().__new
__(cls
, flags
)
187 flags
: Flags
= Flags()
189 function
: _Function
= _Function
.NONE
190 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
191 in1
: _In1Sel
= _In1Sel
.RA
192 in2
: _In2Sel
= _In2Sel
.NONE
193 in3
: _In3Sel
= _In3Sel
.NONE
194 out
: _OutSel
= _OutSel
.NONE
195 cr_in
: _CRInSel
= _CRInSel
.NONE
196 cr_out
: _CROutSel
= _CROutSel
.NONE
197 cry_in
: _CryIn
= _CryIn
.ZERO
198 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
199 upd
: _LDSTMode
= _LDSTMode
.NONE
200 rc
: _RCOE
= _RCOE
.NONE
201 form
: _Form
= _Form
.NONE
203 unofficial
: bool = False
207 "internal op": "intop",
211 "ldst len": "ldst_len",
212 "CONDITIONS": "conditions",
216 def CSV(cls
, record
, opcode_cls
=Opcode
):
217 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
218 typemap
["opcode"] = opcode_cls
221 for flag
in frozenset(PPCRecord
.Flags
):
222 if bool(record
.pop(flag
, "")):
224 record
["flags"] = PPCRecord
.Flags(flags
)
226 return dataclass(cls
, record
, keymap
=PPCRecord
.__KEYMAP
, typemap
=typemap
)
229 def identifier(self
):
234 return frozenset(self
.comment
.split("=")[-1].split("/"))
237 @_dataclasses.dataclass(eq
=True, frozen
=True)
239 class ExtraMap(tuple):
241 @_dataclasses.dataclass(eq
=True, frozen
=True)
243 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
244 reg
: _SVExtraReg
= _SVExtraReg
.NONE
247 return f
"{self.regtype.value}:{self.reg.name}"
249 def __new__(cls
, value
="0"):
250 if isinstance(value
, str):
251 def transform(value
):
252 (regtype
, reg
) = value
.split(":")
253 regtype
= _SVExtraRegType(regtype
)
254 reg
= _SVExtraReg(reg
)
255 return cls
.Entry(regtype
=regtype
, reg
=reg
)
260 value
= map(transform
, value
.split(";"))
262 return super().__new
__(cls
, value
)
265 return repr(list(self
))
267 def __new__(cls
, value
=tuple()):
271 return super().__new
__(cls
, map(cls
.Extra
, value
))
274 return repr({index
:self
[index
] for index
in range(0, 4)})
277 ptype
: _SVPtype
= _SVPtype
.NONE
278 etype
: _SVEtype
= _SVEtype
.NONE
279 in1
: _In1Sel
= _In1Sel
.NONE
280 in2
: _In2Sel
= _In2Sel
.NONE
281 in3
: _In3Sel
= _In3Sel
.NONE
282 out
: _OutSel
= _OutSel
.NONE
283 out2
: _OutSel
= _OutSel
.NONE
284 cr_in
: _CRInSel
= _CRInSel
.NONE
285 cr_out
: _CROutSel
= _CROutSel
.NONE
286 extra
: ExtraMap
= ExtraMap()
289 mode
: _SVMode
= _SVMode
.NORMAL
292 "insn": "identifier",
293 "CONDITIONS": "conditions",
302 def CSV(cls
, record
):
303 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
308 record
["extra"] = cls
.ExtraMap(record
.pop(f
"{index}") for index
in range(0, 4))
310 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
314 def __init__(self
, value
=(0, 32)):
315 if isinstance(value
, str):
316 (start
, end
) = map(int, value
.split(":"))
319 if start
< 0 or end
< 0 or start
>= end
:
320 raise ValueError(value
)
325 return super().__init
__()
328 return f
"[{self.__start}:{self.__end}]"
331 yield from range(self
.start
, (self
.end
+ 1))
342 @_dataclasses.dataclass(eq
=True, frozen
=True)
344 class Mode(_enum
.Enum
):
345 INTEGER
= _enum
.auto()
346 PATTERN
= _enum
.auto()
349 def _missing_(cls
, value
):
350 if isinstance(value
, str):
351 return cls
[value
.upper()]
352 return super()._missing
_(value
)
355 def __new__(cls
, value
=None):
356 if isinstance(value
, str):
357 if value
.upper() == "NONE":
360 value
= int(value
, 0)
364 return super().__new
__(cls
, value
)
370 return (bin(self
) if self
else "None")
379 def CSV(cls
, record
):
380 return dataclass(cls
, record
)
384 def __init__(self
, items
):
385 if isinstance(items
, dict):
386 items
= items
.items()
389 (name
, bitrange
) = item
390 return (name
, tuple(bitrange
.values()))
392 self
.__mapping
= dict(map(transform
, items
))
394 return super().__init
__()
397 return repr(self
.__mapping
)
400 yield from self
.__mapping
.items()
402 def __contains__(self
, key
):
403 return self
.__mapping
.__contains
__(key
)
405 def __getitem__(self
, key
):
406 return self
.__mapping
.get(key
, None)
409 @_functools.total_ordering
410 @_dataclasses.dataclass(eq
=True, frozen
=True)
417 svp64
: SVP64Record
= None
426 def __lt__(self
, other
):
427 if not isinstance(other
, Record
):
428 return NotImplemented
429 return (self
.opcode
< other
.opcode
)
432 return f
"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
437 if self
.section
.opcode
:
438 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
439 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
441 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
443 # Some instructions are special regarding Rc handling.
444 # They are marked with Rc.ONE, but don't have Rc field.
445 # At least addic., andi., andis. belong to this list.
446 if self
.rc
and "Rc" in self
.fields
:
447 fields
+= [(1, self
.fields
["Rc"])]
449 return FieldsOpcode(fields
)
453 return self
.ppc
.function
473 if self
.svp64
is None:
479 return self
.ppc
.cr_in
483 return self
.ppc
.cr_out
485 def sv_extra(self
, key
):
486 if key
not in frozenset({
487 "in1", "in2", "in3", "cr_in",
488 "out", "out2", "cr_out",
492 sel
= getattr(self
.svp64
, key
)
493 if sel
is _CRInSel
.BA_BB
:
494 return _SVExtra
.Idx_1_2
495 reg
= _SVExtraReg(sel
)
496 if reg
is _SVExtraReg
.NONE
:
500 _SVExtraRegType
.SRC
: {},
501 _SVExtraRegType
.DST
: {},
503 for index
in range(0, 4):
504 for entry
in self
.svp64
.extra
[index
]:
505 extra_map
[entry
.regtype
][entry
.reg
] = Record
.__EXTRA
[index
]
507 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
508 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
509 if extra
is not _SVExtra
.NONE
:
514 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
515 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
516 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
517 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
518 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
519 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
520 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
524 if self
.svp64
is None:
526 return self
.svp64
.ptype
530 if self
.svp64
is None:
532 return self
.svp64
.etype
535 class Instruction(_Mapping
):
537 def integer(cls
, value
=0, bits
=None, byteorder
="little"):
538 if isinstance(value
, (int, bytes
)) and not isinstance(bits
, int):
539 raise ValueError(bits
)
541 if isinstance(value
, bytes
):
542 if ((len(value
) * 8) != bits
):
543 raise ValueError(f
"bit length mismatch")
544 value
= int.from_bytes(value
, byteorder
=byteorder
)
546 if isinstance(value
, int):
547 value
= _SelectableInt(value
=value
, bits
=bits
)
548 elif isinstance(value
, Instruction
):
549 value
= value
.storage
551 if not isinstance(value
, _SelectableInt
):
552 raise ValueError(value
)
555 if len(value
) != bits
:
556 raise ValueError(value
)
558 value
= _SelectableInt(value
=value
, bits
=bits
)
560 return cls(storage
=value
)
563 return hash(int(self
))
565 def disassemble(self
, db
):
566 raise NotImplementedError
569 class WordInstruction(Instruction
):
570 _
: _Field
= range(0, 32)
571 po
: _Field
= range(0, 6)
574 def integer(cls
, value
, byteorder
="little"):
575 return super().integer(bits
=32, value
=value
, byteorder
=byteorder
)
577 def disassemble(self
, db
):
580 yield f
".long 0x{int(self):08x}"
582 yield f
".long 0x{int(self):08x} # {record.name}"
585 class PrefixedInstruction(Instruction
):
586 class Prefix(WordInstruction
.remap(range(0, 32))):
589 class Suffix(WordInstruction
.remap(range(32, 64))):
592 _
: _Field
= range(64)
598 def integer(cls
, value
, byteorder
="little"):
599 return super().integer(bits
=64, value
=value
, byteorder
=byteorder
)
602 def pair(cls
, prefix
=0, suffix
=0, byteorder
="little"):
603 def transform(value
):
604 return WordInstruction
.integer(value
=value
,
605 byteorder
=byteorder
)[0:32]
607 (prefix
, suffix
) = map(transform
, (prefix
, suffix
))
608 value
= _selectconcat(prefix
, suffix
)
610 return super().integer(value
=value
)
612 def disassemble(self
, db
):
613 record
= db
[self
.suffix
]
615 yield f
".llong 0x{int(self):016x}"
617 yield f
".llong 0x{int(self):016x} # {record.name}"
620 class SVP64Instruction(PrefixedInstruction
):
621 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
622 class Prefix(PrefixedInstruction
.Prefix
):
624 _
: _Field
= range(24)
626 mask
: _Field
= range(1, 4)
627 elwidth
: _Field
= range(4, 6)
628 ewsrc
: _Field
= range(6, 8)
629 subvl
: _Field
= range(8, 10)
630 extra
: _Field
= range(10, 19)
631 mode
: _Field
= range(19, 24)
632 extra2
: _Field
[4] = (
638 smask
: _Field
= range(16, 19)
639 extra3
: _Field
[3] = (
646 rm
: RM
= ((6, 8) + tuple(range(10, 32)))
650 def disassemble(self
, db
):
651 record
= db
[self
.suffix
]
653 yield f
".llong 0x{int(self):016x}"
655 yield f
".llong 0x{int(self):016x} # sv.{record.name}"
659 def __init__(self
, root
):
660 root
= _pathlib
.Path(root
)
662 def parse(stream
, factory
):
663 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
664 entries
= _csv
.DictReader(lines
)
665 entries
= filter(lambda entry
: "TODO" not in frozenset(entry
.values()), entries
)
666 return tuple(map(factory
, entries
))
668 def database_ppc(root
):
669 db
= _collections
.defaultdict(set)
670 path
= (root
/ "insndb.csv")
671 with
open(path
, "r", encoding
="UTF-8") as stream
:
672 for section
in parse(stream
, Section
.CSV
):
673 path
= (root
/ section
.path
)
675 section
.Mode
.INTEGER
: IntegerOpcode
,
676 section
.Mode
.PATTERN
: PatternOpcode
,
678 factory
= _functools
.partial(PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
679 with
open(path
, "r", encoding
="UTF-8") as stream
:
680 db
[section
].update(parse(stream
, factory
))
681 for (section
, records
) in db
.items():
682 db
[section
] = {record
.identifier
:record
for record
in records
}
685 def database_svp64(root
):
687 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
688 for (prefix
, _
, names
) in _os
.walk(root
):
689 prefix
= _pathlib
.Path(prefix
)
690 for name
in filter(lambda name
: pattern
.match(name
), names
):
691 path
= (prefix
/ _pathlib
.Path(name
))
692 with
open(path
, "r", encoding
="UTF-8") as stream
:
693 db
.update(parse(stream
, SVP64Record
.CSV
))
694 db
= {record
.identifier
:record
for record
in db
}
697 def database_forms(root
):
698 # This is hack. The whole code there should be moved here.
699 # The fields.text parser should take care of the validation.
700 from openpower
.decoder
.power_fields
import DecodeFields
as _DecodeFields
704 for (form
, fields
) in df
.instrs
.items():
705 if form
in {"DQE", "TX"}:
709 db
[_Form
[form
]] = Fields(fields
)
712 def database(ppcdb
, svp64db
, formsdb
):
714 for section
in ppcdb
:
715 for (identifier
, ppc
) in ppcdb
[section
].items():
716 fields
= formsdb
[ppc
.form
]
717 svp64
= svp64db
.get(identifier
)
718 if ppc
.rc
is _RCOE
.ONE
:
719 variants
= {name
:True for name
in ppc
.names
}
720 elif ppc
.rc
in [_RCOE
.RC_OE
, _RCOE
.RC_ONLY
]:
721 variants
= {name
:False for name
in ppc
.names
}
722 variants
.update({f
"{name}.":True for name
in ppc
.names
})
724 variants
= {name
:False for name
in ppc
.names
}
725 for (name
, rc
) in variants
.items():
726 items
.add(Record(name
=name
, rc
=rc
,
727 section
=section
, ppc
=ppc
, fields
=fields
, svp64
=svp64
))
729 items
= tuple(sorted(items
, key
=_operator
.attrgetter("opcode")))
730 opcodes
= {item
.opcode
:item
for item
in items
}
731 names
= {item
.name
:item
for item
in sorted(items
, key
=_operator
.attrgetter("name"))}
733 return (items
, opcodes
, names
)
735 ppcdb
= database_ppc(root
)
736 svp64db
= database_svp64(root
)
737 formsdb
= database_forms(root
)
739 (items
, opcodes
, names
) = database(ppcdb
, svp64db
, formsdb
)
741 self
.__opcodes
= opcodes
744 return super().__init
__()
747 return repr(self
.__items
)
750 yield from self
.__items
752 @_functools.lru_cache(maxsize
=None)
753 def __contains__(self
, key
):
754 return self
.__getitem
__(key
) is not None
756 @_functools.lru_cache(maxsize
=None)
757 def __getitem__(self
, key
):
758 if isinstance(key
, (int, Instruction
)):
760 for (opcode
, insn
) in self
.__opcodes
.items():
761 if ((opcode
.value
& opcode
.mask
) ==
762 (key
& opcode
.mask
)):
765 elif isinstance(key
, Opcode
):
766 return self
.__opcodes
.get(key
, None)
767 elif isinstance(key
, str):
768 return self
.__names
.get(key
, None)