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
,
40 def dataclass(cls
, record
, keymap
=None, typemap
=None):
44 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
46 def transform(key_value
):
47 (key
, value
) = key_value
48 key
= keymap
.get(key
, key
)
49 hook
= typemap
.get(key
, lambda value
: value
)
50 if hook
is bool and value
in ("", "0"):
56 record
= dict(map(transform
, record
.items()))
57 for key
in frozenset(record
.keys()):
64 @_functools.total_ordering
65 @_dataclasses.dataclass(eq
=True, frozen
=True)
69 if self
.bit_length() <= 32:
70 return f
"0x{self:08x}"
72 return f
"0x{self:016x}"
76 if self
.bit_length() <= 32:
77 return f
"0x{self:08x}"
79 return f
"0x{self:016x}"
84 def __lt__(self
, other
):
85 if not isinstance(other
, Opcode
):
87 return ((self
.value
, self
.mask
) < (other
.value
, other
.mask
))
89 def __post_init__(self
):
90 (value
, mask
) = (self
.value
, self
.mask
)
92 if isinstance(value
, Opcode
):
94 raise ValueError(mask
)
95 (value
, mask
) = (value
.value
, value
.mask
)
96 elif isinstance(value
, str):
98 raise ValueError(mask
)
101 if not isinstance(value
, int):
102 raise ValueError(value
)
105 if not isinstance(mask
, int):
106 raise ValueError(mask
)
108 object.__setattr
__(self
, "value", self
.__class
__.Value(value
))
109 object.__setattr
__(self
, "mask", self
.__class
__.Mask(mask
))
112 class IntegerOpcode(Opcode
):
113 def __init__(self
, value
):
114 if isinstance(value
, str):
115 value
= int(value
, 0)
116 return super().__init
__(value
=value
, mask
=None)
119 class PatternOpcode(Opcode
):
120 def __init__(self
, value
):
121 (pattern
, value
, mask
) = (value
, 0, 0)
123 for symbol
in pattern
:
124 if symbol
not in {"0", "1", "-"}:
125 raise ValueError(pattern
)
126 value |
= (symbol
== "1")
127 mask |
= (symbol
!= "-")
133 return super().__init
__(value
=value
, mask
=mask
)
136 class FieldsOpcode(Opcode
):
137 def __init__(self
, fields
):
138 def field(opcode
, field
):
139 (value
, mask
) = opcode
140 (field
, bits
) = field
141 shifts
= map(lambda bit
: (31 - bit
), reversed(tuple(bits
)))
142 for (index
, shift
) in enumerate(shifts
):
143 bit
= ((field
& (1 << index
)) != 0)
144 value |
= (bit
<< shift
)
148 (value
, mask
) = _functools
.reduce(field
, fields
, (0, 0))
150 return super().__init
__(value
=value
, mask
=mask
)
153 @_dataclasses.dataclass(eq
=True, frozen
=True)
155 class FlagsMeta(type):
170 class Flags(frozenset, metaclass
=FlagsMeta
):
171 def __new__(cls
, flags
=frozenset()):
172 flags
= frozenset(flags
)
173 diff
= (flags
- frozenset(cls
))
175 raise ValueError(flags
)
176 return super().__new
__(cls
, flags
)
180 flags
: Flags
= Flags()
182 unit
: _Function
= _Function
.NONE
183 intop
: _MicrOp
= _MicrOp
.OP_ILLEGAL
184 in1
: _In1Sel
= _In1Sel
.RA
185 in2
: _In2Sel
= _In2Sel
.NONE
186 in3
: _In3Sel
= _In3Sel
.NONE
187 out
: _OutSel
= _OutSel
.NONE
188 cr_in
: _CRInSel
= _CRInSel
.NONE
189 cr_out
: _CROutSel
= _CROutSel
.NONE
190 cry_in
: _CryIn
= _CryIn
.ZERO
191 ldst_len
: _LDSTLen
= _LDSTLen
.NONE
192 upd
: _LDSTMode
= _LDSTMode
.NONE
194 form
: _Form
= _Form
.NONE
196 unofficial
: bool = False
199 "internal op": "intop",
203 "ldst len": "ldst_len",
204 "CONDITIONS": "conditions",
208 def CSV(cls
, record
, opcode_cls
=Opcode
):
209 typemap
= {field
.name
:field
.type for field
in _dataclasses
.fields(cls
)}
210 typemap
["opcode"] = opcode_cls
213 for flag
in frozenset(PPCRecord
.Flags
):
214 if bool(record
.pop(flag
, "")):
216 record
["flags"] = PPCRecord
.Flags(flags
)
218 return dataclass(cls
, record
, keymap
=PPCRecord
.__KEYMAP
, typemap
=typemap
)
221 def identifier(self
):
226 return frozenset(self
.comment
.split("=")[-1].split("/"))
229 @_dataclasses.dataclass(eq
=True, frozen
=True)
231 class ExtraMap(tuple):
233 @_dataclasses.dataclass(eq
=True, frozen
=True)
235 regtype
: _SVExtraRegType
= _SVExtraRegType
.NONE
236 reg
: _SVExtraReg
= _SVExtraReg
.NONE
239 return f
"{self.regtype.value}:{self.reg.name}"
241 def __new__(cls
, value
="0"):
242 if isinstance(value
, str):
243 def transform(value
):
244 (regtype
, reg
) = value
.split(":")
245 regtype
= _SVExtraRegType(regtype
)
246 reg
= _SVExtraReg(reg
)
247 return cls
.Entry(regtype
=regtype
, reg
=reg
)
252 value
= map(transform
, value
.split(";"))
254 return super().__new
__(cls
, value
)
257 return repr(list(self
))
259 def __new__(cls
, value
=tuple()):
263 return super().__new
__(cls
, map(cls
.Extra
, value
))
266 return repr({index
:self
[index
] for index
in range(0, 4)})
269 ptype
: _SVPtype
= _SVPtype
.NONE
270 etype
: _SVEtype
= _SVEtype
.NONE
271 in1
: _In1Sel
= _In1Sel
.NONE
272 in2
: _In2Sel
= _In2Sel
.NONE
273 in3
: _In3Sel
= _In3Sel
.NONE
274 out
: _OutSel
= _OutSel
.NONE
275 out2
: _OutSel
= _OutSel
.NONE
276 cr_in
: _CRInSel
= _CRInSel
.NONE
277 cr_out
: _CROutSel
= _CROutSel
.NONE
278 extra
: ExtraMap
= ExtraMap()
281 mode
: _SVMode
= _SVMode
.NORMAL
284 "insn": "identifier",
285 "CONDITIONS": "conditions",
294 def CSV(cls
, record
):
295 for key
in ("in1", "in2", "in3", "out", "out2", "CR in", "CR out"):
300 record
["extra"] = cls
.ExtraMap(record
.pop(f
"{index}") for index
in range(0, 4))
302 return dataclass(cls
, record
, keymap
=cls
.__KEYMAP
)
306 def __init__(self
, value
=(0, 32)):
307 if isinstance(value
, str):
308 (start
, end
) = map(int, value
.split(":"))
311 if start
< 0 or end
< 0 or start
>= end
:
312 raise ValueError(value
)
317 return super().__init
__()
320 return f
"[{self.__start}:{self.__end}]"
323 yield from range(self
.start
, (self
.end
+ 1))
334 @_dataclasses.dataclass(eq
=True, frozen
=True)
336 class Mode(_enum
.Enum
):
337 INTEGER
= _enum
.auto()
338 PATTERN
= _enum
.auto()
341 def _missing_(cls
, value
):
342 if isinstance(value
, str):
343 return cls
[value
.upper()]
344 return super()._missing
_(value
)
347 def __new__(cls
, value
=None):
348 if isinstance(value
, str):
349 if value
.upper() == "NONE":
352 value
= int(value
, 0)
356 return super().__new
__(cls
, value
)
362 return (bin(self
) if self
else "None")
371 def CSV(cls
, record
):
372 return dataclass(cls
, record
)
376 def __init__(self
, items
):
377 if isinstance(items
, dict):
378 items
= items
.items()
381 (name
, bitrange
) = item
382 return (name
, tuple(bitrange
.values()))
384 self
.__mapping
= dict(map(transform
, items
))
386 return super().__init
__()
389 return repr(self
.__mapping
)
391 def __contains__(self
, key
):
392 return self
.__mapping
.__contains
__(key
)
394 def __getitem__(self
, key
):
395 return self
.__mapping
.__getitem
__(key
)
397 def get(self
, key
, default
):
398 return self
.__mapping
.get(key
, default
)
401 @_functools.total_ordering
402 @_dataclasses.dataclass(eq
=True, frozen
=True)
409 svp64
: SVP64Record
= None
418 def __lt__(self
, other
):
419 if not isinstance(other
, Instruction
):
420 return NotImplemented
421 return (self
.opcode
< other
.opcode
)
424 return f
"{self.__class__.__name__}(name={self.name!r}, opcode={self.opcode})"
429 if self
.section
.opcode
:
430 fields
+= [(self
.section
.opcode
.value
, BitSel((0, 5)))]
431 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
433 fields
+= [(self
.ppc
.opcode
.value
, self
.section
.bitsel
)]
435 # Some instructions are special regarding Rc handling.
436 # They are marked with Rc.ONE, but don't have Rc field.
437 # At least addic., andi., andis. belong to this list.
438 if self
.rc
and "Rc" in self
.fields
:
439 fields
+= [(1, self
.fields
["Rc"])]
441 return FieldsOpcode(fields
)
465 if self
.svp64
is None:
471 return self
.ppc
.cr_in
475 return self
.ppc
.cr_out
477 def sv_extra(self
, key
):
478 if key
not in frozenset({
479 "in1", "in2", "in3", "cr_in",
480 "out", "out2", "cr_out",
484 sel
= getattr(self
.svp64
, key
)
485 if sel
is _CRInSel
.BA_BB
:
486 return _SVExtra
.Idx_1_2
487 reg
= _SVExtraReg(sel
)
488 if reg
is _SVExtraReg
.NONE
:
492 _SVExtraRegType
.SRC
: {},
493 _SVExtraRegType
.DST
: {},
495 for index
in range(0, 4):
496 for entry
in self
.svp64
.extra
[index
]:
497 extra_map
[entry
.regtype
][entry
.reg
] = Instruction
.__EXTRA
[index
]
499 for regtype
in (_SVExtraRegType
.SRC
, _SVExtraRegType
.DST
):
500 extra
= extra_map
[regtype
].get(reg
, _SVExtra
.NONE
)
501 if extra
is not _SVExtra
.NONE
:
506 sv_in1
= property(_functools
.partial(sv_extra
, key
="in1"))
507 sv_in2
= property(_functools
.partial(sv_extra
, key
="in2"))
508 sv_in3
= property(_functools
.partial(sv_extra
, key
="in3"))
509 sv_out
= property(_functools
.partial(sv_extra
, key
="out"))
510 sv_out2
= property(_functools
.partial(sv_extra
, key
="out2"))
511 sv_cr_in
= property(_functools
.partial(sv_extra
, key
="cr_in"))
512 sv_cr_out
= property(_functools
.partial(sv_extra
, key
="cr_out"))
516 if self
.svp64
is None:
518 return self
.svp64
.ptype
522 if self
.svp64
is None:
524 return self
.svp64
.etype
528 def __init__(self
, root
):
529 root
= _pathlib
.Path(root
)
531 def parse(stream
, factory
):
532 lines
= filter(lambda line
: not line
.strip().startswith("#"), stream
)
533 entries
= _csv
.DictReader(lines
)
534 entries
= filter(lambda entry
: "TODO" not in frozenset(entry
.values()), entries
)
535 return tuple(map(factory
, entries
))
537 def database_ppc(root
):
538 db
= _collections
.defaultdict(set)
539 path
= (root
/ "insndb.csv")
540 with
open(path
, "r", encoding
="UTF-8") as stream
:
541 for section
in parse(stream
, Section
.CSV
):
542 path
= (root
/ section
.path
)
544 section
.Mode
.INTEGER
: IntegerOpcode
,
545 section
.Mode
.PATTERN
: PatternOpcode
,
547 factory
= _functools
.partial(PPCRecord
.CSV
, opcode_cls
=opcode_cls
)
548 with
open(path
, "r", encoding
="UTF-8") as stream
:
549 db
[section
].update(parse(stream
, factory
))
550 for (section
, records
) in db
.items():
551 db
[section
] = {record
.identifier
:record
for record
in records
}
554 def database_svp64(root
):
556 pattern
= _re
.compile(r
"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
557 for (prefix
, _
, names
) in _os
.walk(root
):
558 prefix
= _pathlib
.Path(prefix
)
559 for name
in filter(lambda name
: pattern
.match(name
), names
):
560 path
= (prefix
/ _pathlib
.Path(name
))
561 with
open(path
, "r", encoding
="UTF-8") as stream
:
562 db
.update(parse(stream
, SVP64Record
.CSV
))
563 db
= {record
.identifier
:record
for record
in db
}
566 def database_forms(root
):
567 # This is hack. The whole code there should be moved here.
568 # The fields.text parser should take care of the validation.
569 from openpower
.decoder
.power_fields
import DecodeFields
as _DecodeFields
573 for (form
, fields
) in df
.instrs
.items():
574 if form
in {"DQE", "TX"}:
578 db
[_Form
[form
]] = Fields(fields
)
581 def database(ppcdb
, svp64db
, formsdb
):
583 for section
in ppcdb
:
584 for (identifier
, ppc
) in ppcdb
[section
].items():
585 fields
= formsdb
[ppc
.form
]
586 svp64
= svp64db
.get(identifier
)
587 if ppc
.rc
is _RC
.ONE
:
588 variants
= {name
:True for name
in ppc
.names
}
589 elif ppc
.rc
is _RC
.RC
:
590 variants
= {name
:False for name
in ppc
.names
}
591 variants
.update({f
"{name}.":True for name
in ppc
.names
})
593 variants
= {name
:False for name
in ppc
.names
}
594 for (name
, rc
) in variants
.items():
595 items
.add(Instruction(name
=name
, rc
=rc
,
596 section
=section
, ppc
=ppc
, fields
=fields
, svp64
=svp64
))
598 items
= tuple(sorted(items
, key
=_operator
.attrgetter("opcode")))
599 opcodes
= {item
.opcode
:item
for item
in items
}
600 names
= {item
.name
:item
for item
in sorted(items
, key
=_operator
.attrgetter("name"))}
602 return (items
, opcodes
, names
)
604 ppcdb
= database_ppc(root
)
605 svp64db
= database_svp64(root
)
606 formsdb
= database_forms(root
)
608 (items
, opcodes
, names
) = database(ppcdb
, svp64db
, formsdb
)
610 self
.__opcodes
= opcodes
613 return super().__init
__()
616 return repr(self
.__items
)
619 yield from self
.__items
621 def __contains__(self
, key
):
622 if isinstance(key
, int):
623 return self
.__opcodes
.__contains
__(key
)
624 elif isinstance(key
, str):
625 return self
.__names
.__contains
__(key
)
629 def __getitem__(self
, key
):
630 if isinstance(key
, int):
631 return self
.__opcodes
.__getitem
__(key
)
632 elif isinstance(key
, str):
633 return self
.__names
.__getitem
__(key
)