1 import collections
as _collections
4 import dataclasses
as _dataclasses
6 import functools
as _functools
8 import operator
as _operator
9 import pathlib
as _pathlib
13 from functools
import cached_property
15 from cached_property
import cached_property
17 from openpower
.decoder
.power_enums
import (
18 Function
as _Function
,
25 CROutSel
as _CROutSel
,
27 LDSTMode
as _LDSTMode
,
35 SVExtraRegType
as _SVExtraRegType
,
36 SVExtraReg
as _SVExtraReg
,
38 from openpower
.decoder
.selectable_int
import (
39 SelectableInt
as _SelectableInt
,
42 # TODO: these should be present in the decoder module.
43 from openpower
.decoder
.isa
.caller
import (
44 SVP64PrefixFields
as _SVP64PrefixFields
,
45 SVP64RMFields
as _SVP64RMFields
,
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 unit
: _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
203 form
: _Form
= _Form
.NONE
205 unofficial
: bool = False
208 "internal op": "intop",
212 "ldst len": "ldst_len",
213 "CONDITIONS": "conditions",
217 def CSV(cls
, record
, opcode_cls
=Opcode
):
218 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
219 typemap
["opcode"] = opcode_cls
222 for flag
in frozenset(PPCRecord
.Flags
):
223 if bool(record
.pop(flag
, "")):
225 record
["flags"] = PPCRecord
.Flags(flags
)
227 return dataclass(cls
, record
, keymap
=PPCRecord
.__KEYMAP
, typemap
=typemap
)
230 def identifier(self
):
235 return frozenset(self
.comment
.split("=")[-1].split("/"))
238 @_dataclasses.dataclass(eq
=True, frozen
=True)
240 class ExtraMap(tuple):
242 @_dataclasses.dataclass(eq
=True, frozen
=True)
244 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
245 reg
: _SVExtraReg
= _SVExtraReg
.NONE
248 return f
"{self.regtype.value}:{self.reg.name}"
250 def __new__(cls
, value
="0"):
251 if isinstance(value
, str):
252 def transform(value
):
253 (regtype
, reg
) = value
.split(":")
254 regtype
= _SVExtraRegType(regtype
)
255 reg
= _SVExtraReg(reg
)
256 return cls
.Entry(regtype
=regtype
, reg
=reg
)
261 value
= map(transform
, value
.split(";"))
263 return super().__new
__(cls
, value
)
266 return repr(list(self
))
268 def __new__(cls
, value
=tuple()):
272 return super().__new
__(cls
, map(cls
.Extra
, value
))
275 return repr({index
:self
[index
] for index
in range(0, 4)})
278 ptype
: _SVPtype
= _SVPtype
.NONE
279 etype
: _SVEtype
= _SVEtype
.NONE
280 in1
: _In1Sel
= _In1Sel
.NONE
281 in2
: _In2Sel
= _In2Sel
.NONE
282 in3
: _In3Sel
= _In3Sel
.NONE
283 out
: _OutSel
= _OutSel
.NONE
284 out2
: _OutSel
= _OutSel
.NONE
285 cr_in
: _CRInSel
= _CRInSel
.NONE
286 cr_out
: _CROutSel
= _CROutSel
.NONE
287 extra
: ExtraMap
= ExtraMap()
290 mode
: _SVMode
= _SVMode
.NORMAL
293 "insn": "identifier",
294 "CONDITIONS": "conditions",
303 def CSV(cls
, record
):
304 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
309 record
["extra"] = cls
.ExtraMap(record
.pop(f
"{index}") for index
in range(0, 4))
311 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
315 def __init__(self
, value
=(0, 32)):
316 if isinstance(value
, str):
317 (start
, end
) = map(int, value
.split(":"))
320 if start
< 0 or end
< 0 or start
>= end
:
321 raise ValueError(value
)
326 return super().__init
__()
329 return f
"[{self.__start}:{self.__end}]"
332 yield from range(self
.start
, (self
.end
+ 1))
343 @_dataclasses.dataclass(eq
=True, frozen
=True)
345 class Mode(_enum
.Enum
):
346 INTEGER
= _enum
.auto()
347 PATTERN
= _enum
.auto()
350 def _missing_(cls
, value
):
351 if isinstance(value
, str):
352 return cls
[value
.upper()]
353 return super()._missing
_(value
)
356 def __new__(cls
, value
=None):
357 if isinstance(value
, str):
358 if value
.upper() == "NONE":
361 value
= int(value
, 0)
365 return super().__new
__(cls
, value
)
371 return (bin(self
) if self
else "None")
380 def CSV(cls
, record
):
381 return dataclass(cls
, record
)
385 def __init__(self
, items
):
386 if isinstance(items
, dict):
387 items
= items
.items()
390 (name
, bitrange
) = item
391 return (name
, tuple(bitrange
.values()))
393 self
.__mapping
= dict(map(transform
, items
))
395 return super().__init
__()
398 return repr(self
.__mapping
)
400 def __contains__(self
, key
):
401 return self
.__mapping
.__contains
__(key
)
403 def __getitem__(self
, key
):
404 return self
.__mapping
.__getitem
__(key
)
406 def get(self
, key
, default
):
407 return self
.__mapping
.get(key
, default
)
410 @_functools.total_ordering
411 @_dataclasses.dataclass(eq
=True, frozen
=True)
418 svp64
: SVP64Record
= None
427 def __lt__(self
, other
):
428 if not isinstance(other
, Record
):
429 return NotImplemented
430 return (self
.opcode
< other
.opcode
)
433 return f
"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
438 if self
.section
.opcode
:
439 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
440 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
442 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
444 # Some instructions are special regarding Rc handling.
445 # They are marked with Rc.ONE, but don't have Rc field.
446 # At least addic., andi., andis. belong to this list.
447 if self
.rc
and "Rc" in self
.fields
:
448 fields
+= [(1, self
.fields
["Rc"])]
450 return FieldsOpcode(fields
)
474 if self
.svp64
is None:
480 return self
.ppc
.cr_in
484 return self
.ppc
.cr_out
486 def sv_extra(self
, key
):
487 if key
not in frozenset({
488 "in1", "in2", "in3", "cr_in",
489 "out", "out2", "cr_out",
493 sel
= getattr(self
.svp64
, key
)
494 if sel
is _CRInSel
.BA_BB
:
495 return _SVExtra
.Idx_1_2
496 reg
= _SVExtraReg(sel
)
497 if reg
is _SVExtraReg
.NONE
:
501 _SVExtraRegType
.SRC
: {},
502 _SVExtraRegType
.DST
: {},
504 for index
in range(0, 4):
505 for entry
in self
.svp64
.extra
[index
]:
506 extra_map
[entry
.regtype
][entry
.reg
] = Record
.__EXTRA
[index
]
508 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
509 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
510 if extra
is not _SVExtra
.NONE
:
515 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
516 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
517 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
518 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
519 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
520 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
521 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
525 if self
.svp64
is None:
527 return self
.svp64
.ptype
531 if self
.svp64
is None:
533 return self
.svp64
.etype
536 class Instruction(_SelectableInt
):
537 def __init__(self
, value
, bits
=None, byteorder
="little", db
=None):
538 if isinstance(value
, _SelectableInt
):
540 raise ValueError(bits
)
546 if isinstance(value
, bytes
):
547 value
= int.from_bytes(value
, byteorder
=str(byteorder
))
548 if not isinstance(bits
, int):
549 raise ValueError(bits
)
551 if not isinstance(value
, int):
552 raise ValueError(value
)
554 if db
is not None and not isinstance(db
, Database
):
559 return super().__init
__(value
=value
, bits
=bits
)
562 return f
"{self.__class__.__name__}({self.value:08x})"
564 def disassemble(self
):
565 if self
.dbrecord
is None:
566 yield f
".long 0x{self.value:08x}"
568 yield f
".long 0x{self.value:08x} # {self.dbrecord.name}"
576 if self
.__db
is None:
579 return self
.__db
[int(self
)]
584 class PrefixedInstruction(Instruction
):
585 def __init__(self
, prefix
, suffix
, byteorder
="little", db
=None):
586 insn
= _functools
.partial(Instruction
, byteorder
=byteorder
, db
=db
)
587 (prefix
, suffix
) = map(insn
, (prefix
, suffix
))
588 value
= ((prefix
.value
<< 32) | suffix
.value
)
590 return super().__init
__(value
=value
, bits
=64,
591 byteorder
=byteorder
, db
=db
)
594 return f
"{self.__class__.__name__}({self.value:016x})"
596 def disassemble(self
):
597 if self
.dbrecord
is None:
598 yield f
".llong 0x{self.value:08x}"
600 yield f
".llong 0x{self.value:08x} # {self.dbrecord.name}"
604 return Instruction(self
[0:32])
608 return Instruction(self
[32:64])
612 return self
.suffix
.major
616 return self
.suffix
.dbrecord
619 class SVP64Instruction(PrefixedInstruction
):
620 class PrefixError(ValueError):
623 class Prefix(Instruction
, _SVP64PrefixFields
):
624 class RM(_SVP64RMFields
):
627 return (self
.mode
& 0b11)
631 return self
.__class
__.RM(super().rm
)
633 class Suffix(Instruction
):
636 def __init__(self
, prefix
, suffix
, byteorder
="little", db
=None):
637 insn
= _functools
.partial(Instruction
, byteorder
=byteorder
, db
=db
)
638 (prefix
, suffix
) = map(insn
, (prefix
, suffix
))
640 prefix
= SVP64Instruction
.Prefix(value
=prefix
)
641 if prefix
.pid
!= 0b11:
642 raise SVP64Instruction
.PrefixError(prefix
)
644 return super().__init
__(prefix
=prefix
, suffix
=suffix
,
645 byteorder
=byteorder
, db
=db
)
647 def disassemble(self
):
648 if self
.dbrecord
is None:
649 yield f
".llong 0x{self.value:08x}"
651 yield f
".llong 0x{self.value:08x} # sv.{self.dbrecord.name}"
655 return self
.__class
__.Prefix(super().prefix
)
659 return self
.__class
__.Suffix(super().suffix
)
663 def __init__(self
, root
):
664 root
= _pathlib
.Path(root
)
666 def parse(stream
, factory
):
667 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
668 entries
= _csv
.DictReader(lines
)
669 entries
= filter(lambda entry
: "TODO" not in frozenset(entry
.values()), entries
)
670 return tuple(map(factory
, entries
))
672 def database_ppc(root
):
673 db
= _collections
.defaultdict(set)
674 path
= (root
/ "insndb.csv")
675 with
open(path
, "r", encoding
="UTF-8") as stream
:
676 for section
in parse(stream
, Section
.CSV
):
677 path
= (root
/ section
.path
)
679 section
.Mode
.INTEGER
: IntegerOpcode
,
680 section
.Mode
.PATTERN
: PatternOpcode
,
682 factory
= _functools
.partial(PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
683 with
open(path
, "r", encoding
="UTF-8") as stream
:
684 db
[section
].update(parse(stream
, factory
))
685 for (section
, records
) in db
.items():
686 db
[section
] = {record
.identifier
:record
for record
in records
}
689 def database_svp64(root
):
691 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
692 for (prefix
, _
, names
) in _os
.walk(root
):
693 prefix
= _pathlib
.Path(prefix
)
694 for name
in filter(lambda name
: pattern
.match(name
), names
):
695 path
= (prefix
/ _pathlib
.Path(name
))
696 with
open(path
, "r", encoding
="UTF-8") as stream
:
697 db
.update(parse(stream
, SVP64Record
.CSV
))
698 db
= {record
.identifier
:record
for record
in db
}
701 def database_forms(root
):
702 # This is hack. The whole code there should be moved here.
703 # The fields.text parser should take care of the validation.
704 from openpower
.decoder
.power_fields
import DecodeFields
as _DecodeFields
708 for (form
, fields
) in df
.instrs
.items():
709 if form
in {"DQE", "TX"}:
713 db
[_Form
[form
]] = Fields(fields
)
716 def database(ppcdb
, svp64db
, formsdb
):
718 for section
in ppcdb
:
719 for (identifier
, ppc
) in ppcdb
[section
].items():
720 fields
= formsdb
[ppc
.form
]
721 svp64
= svp64db
.get(identifier
)
722 if ppc
.rc
is _RC
.ONE
:
723 variants
= {name
:True for name
in ppc
.names
}
724 elif ppc
.rc
is _RC
.RC
:
725 variants
= {name
:False for name
in ppc
.names
}
726 variants
.update({f
"{name}.":True for name
in ppc
.names
})
728 variants
= {name
:False for name
in ppc
.names
}
729 for (name
, rc
) in variants
.items():
730 items
.add(Record(name
=name
, rc
=rc
,
731 section
=section
, ppc
=ppc
, fields
=fields
, svp64
=svp64
))
733 items
= tuple(sorted(items
, key
=_operator
.attrgetter("opcode")))
734 opcodes
= {item
.opcode
:item
for item
in items
}
735 names
= {item
.name
:item
for item
in sorted(items
, key
=_operator
.attrgetter("name"))}
737 return (items
, opcodes
, names
)
739 ppcdb
= database_ppc(root
)
740 svp64db
= database_svp64(root
)
741 formsdb
= database_forms(root
)
743 (items
, opcodes
, names
) = database(ppcdb
, svp64db
, formsdb
)
745 self
.__opcodes
= opcodes
748 return super().__init
__()
751 return repr(self
.__items
)
754 yield from self
.__items
756 @_functools.lru_cache(maxsize
=None)
757 def __contains__(self
, key
):
758 if isinstance(key
, int):
759 return self
.__opcodes
.__contains
__(key
)
760 elif isinstance(key
, int):
761 for (opcode
, insn
) in self
.__opcodes
.items():
762 if ((opcode
.value
& opcode
.mask
) ==
763 (key
& opcode
.mask
)):
766 elif isinstance(key
, str):
767 return self
.__names
.__contains
__(key
)
771 @_functools.lru_cache(maxsize
=None)
772 def __getitem__(self
, key
):
773 if isinstance(key
, Opcode
):
774 return self
.__opcodes
.__getitem
__(key
)
775 elif isinstance(key
, int):
776 for (opcode
, insn
) in self
.__opcodes
.items():
777 if ((opcode
.value
& opcode
.mask
) ==
778 (key
& opcode
.mask
)):
781 elif isinstance(key
, str):
782 return self
.__names
.__getitem
__(key
)