ddf2564fa7ee5ed49251a4d640aa9e4ec7b9fa23
[openpower-isa.git] / src / openpower / insndb / core.py
1 import collections as _collections
2 import contextlib as _contextlib
3 import csv as _csv
4 import dataclasses as _dataclasses
5 import enum as _enum
6 import functools as _functools
7 import os as _os
8 import operator as _operator
9 import pathlib as _pathlib
10 import re as _re
11 import types as _types
12 import typing as _typing
13
14 try:
15 from functools import cached_property
16 except ImportError:
17 from cached_property import cached_property
18
19 from openpower.decoder.power_enums import (
20 Function as _Function,
21 MicrOp as _MicrOp,
22 In1Sel as _In1Sel,
23 In2Sel as _In2Sel,
24 In3Sel as _In3Sel,
25 OutSel as _OutSel,
26 CRInSel as _CRInSel,
27 CRIn2Sel as _CRIn2Sel,
28 CROutSel as _CROutSel,
29 LDSTLen as _LDSTLen,
30 LDSTMode as _LDSTMode,
31 RCOE as _RCOE,
32 CryIn as _CryIn,
33 Form as _Form,
34 SVEType as _SVEType,
35 SVMaskSrc as _SVMaskSrc,
36 SVMode as _SVMode,
37 SVPType as _SVPType,
38 SVExtra as _SVExtra,
39 Reg as _Reg,
40 RegType as _RegType,
41 SelType as _SelType,
42 SVP64SubVL as _SVP64SubVL,
43 SVP64Pred as _SVP64Pred,
44 SVP64PredMode as _SVP64PredMode,
45 SVP64Width as _SVP64Width,
46 )
47 from openpower.decoder.selectable_int import (
48 SelectableInt as _SelectableInt,
49 selectconcat as _selectconcat,
50 )
51 from openpower.decoder.power_fields import (
52 Field as _Field,
53 Mapping as _Mapping,
54 DecodeFields as _DecodeFields,
55 )
56 from openpower.decoder.pseudo.pagereader import ISA as _ISA
57
58
59 class Node:
60 def visit(self, handler, matcher, depth):
61 if matcher(node=self, depth=depth):
62 with handler(node=self, depth=depth):
63 pass
64
65
66 class Visitor:
67 def __init__(self, **parameters):
68 self.__parameters = _types.MappingProxyType(parameters)
69 return super().__init__()
70
71 def __contains__(self, key):
72 return self.__parameters.__contains__(key)
73
74 def __getitem__(self, key):
75 return self.__parameters.__getitem__(key)
76
77 def Node(self, node, depth):
78 raise NotImplementedError()
79
80 def __call__(self, node, depth):
81 method = node.__class__.__name__
82 method = getattr(self, method, self.Node)
83 return method(node=node, depth=depth)
84
85
86 class Matcher(Visitor):
87 def Node(self, node, depth):
88 return True
89
90
91 class Handler(Visitor):
92 @_contextlib.contextmanager
93 def Node(self, node, depth):
94 yield node
95
96
97 def visit(node, handler, matcher=Matcher()):
98 node.visit(handler=handler, matcher=matcher, depth=0)
99
100
101 @_functools.total_ordering
102 class Style(_enum.Enum):
103 LEGACY = _enum.auto()
104 SHORT = _enum.auto()
105 NORMAL = _enum.auto()
106 VERBOSE = _enum.auto()
107
108 def __lt__(self, other):
109 if not isinstance(other, self.__class__):
110 return NotImplemented
111 return (self.value < other.value)
112
113
114 @_functools.total_ordering
115 class Priority(_enum.Enum):
116 LOW = -1
117 NORMAL = 0
118 HIGH = +1
119
120 @classmethod
121 def _missing_(cls, value):
122 if isinstance(value, str):
123 value = value.upper()
124 try:
125 return cls[value]
126 except ValueError:
127 return super()._missing_(value)
128
129 def __lt__(self, other):
130 if not isinstance(other, self.__class__):
131 return NotImplemented
132
133 # NOTE: the order is inversed, LOW < NORMAL < HIGH
134 return (self.value > other.value)
135
136
137 def dataclass(cls, record, keymap=None, typemap=None):
138 if keymap is None:
139 keymap = {}
140 if typemap is None:
141 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
142
143 def transform(key_value):
144 (key, value) = key_value
145 key = keymap.get(key, key)
146 hook = typemap.get(key, lambda value: value)
147 if hook is bool and value in ("", "0"):
148 value = False
149 else:
150 value = hook(value)
151 return (key, value)
152
153 record = dict(map(transform, record.items()))
154 for key in frozenset(record.keys()):
155 if record[key] == "":
156 record.pop(key)
157
158 return cls(**record)
159
160
161 @_functools.total_ordering
162 @_dataclasses.dataclass(eq=True, frozen=True)
163 class Opcode:
164 class Integer(int):
165 def __new__(cls, value):
166 if isinstance(value, str):
167 value = int(value, 0)
168 if not isinstance(value, int):
169 raise ValueError(value)
170
171 if value.bit_length() > 64:
172 raise ValueError(value)
173
174 return super().__new__(cls, value)
175
176 def __str__(self):
177 return self.__repr__()
178
179 def __repr__(self):
180 return f"{self:0{self.bit_length()}b}"
181
182 def bit_length(self):
183 if super().bit_length() > 32:
184 return 64
185 return 32
186
187 class Value(Integer):
188 pass
189
190 class Mask(Integer):
191 pass
192
193 value: Value
194 mask: Mask
195
196 def __lt__(self, other):
197 if not isinstance(other, Opcode):
198 return NotImplemented
199 return ((self.value, self.mask) < (other.value, other.mask))
200
201 def __int__(self):
202 return (self.value & self.mask)
203
204 def __index__(self):
205 return int(self).__index__()
206
207 def __repr__(self):
208 def pattern(value, mask, bit_length):
209 for bit in range(bit_length):
210 if ((mask & (1 << (bit_length - bit - 1))) == 0):
211 yield "-"
212 elif (value & (1 << (bit_length - bit - 1))):
213 yield "1"
214 else:
215 yield "0"
216
217 return "".join(pattern(self.value, self.mask, self.value.bit_length()))
218
219 def match(self, key):
220 return ((self.value & self.mask) == (key & self.mask))
221
222
223 @_functools.total_ordering
224 @_dataclasses.dataclass(eq=True, frozen=True)
225 class IntegerOpcode(Opcode):
226 def __init__(self, value):
227 if value.startswith("0b"):
228 mask = int(("1" * len(value[2:])), 2)
229 else:
230 mask = 0b111111
231
232 value = Opcode.Value(value)
233 mask = Opcode.Mask(mask)
234
235 return super().__init__(value=value, mask=mask)
236
237
238 @_functools.total_ordering
239 @_dataclasses.dataclass(eq=True, frozen=True)
240 class PatternOpcode(Opcode):
241 def __init__(self, pattern):
242 if not isinstance(pattern, str):
243 raise ValueError(pattern)
244
245 (value, mask) = (0, 0)
246 for symbol in pattern:
247 if symbol not in {"0", "1", "-"}:
248 raise ValueError(pattern)
249 value |= (symbol == "1")
250 mask |= (symbol != "-")
251 value <<= 1
252 mask <<= 1
253 value >>= 1
254 mask >>= 1
255
256 value = Opcode.Value(value)
257 mask = Opcode.Mask(mask)
258
259 return super().__init__(value=value, mask=mask)
260
261
262 @_dataclasses.dataclass(eq=True, frozen=True)
263 class PPCRecord:
264 class FlagsMeta(type):
265 def __iter__(cls):
266 yield from (
267 "inv A",
268 "inv out",
269 "cry out",
270 "BR",
271 "sgn ext",
272 "rsrv",
273 "32b",
274 "sgn",
275 "lk",
276 "sgl pipe",
277 )
278
279 class Flags(tuple, metaclass=FlagsMeta):
280 def __new__(cls, flags=frozenset()):
281 flags = frozenset(flags)
282 diff = (flags - frozenset(cls))
283 if diff:
284 raise ValueError(flags)
285 return super().__new__(cls, sorted(flags))
286
287 opcode: Opcode
288 comment: str
289 flags: Flags = Flags()
290 comment2: str = ""
291 function: _Function = _Function.NONE
292 intop: _MicrOp = _MicrOp.OP_ILLEGAL
293 in1: _In1Sel = _In1Sel.NONE
294 in2: _In2Sel = _In2Sel.NONE
295 in3: _In3Sel = _In3Sel.NONE
296 out: _OutSel = _OutSel.NONE
297 cr_in: _CRInSel = _CRInSel.NONE
298 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
299 cr_out: _CROutSel = _CROutSel.NONE
300 cry_in: _CryIn = _CryIn.ZERO
301 ldst_len: _LDSTLen = _LDSTLen.NONE
302 upd: _LDSTMode = _LDSTMode.NONE
303 Rc: _RCOE = _RCOE.NONE
304 form: _Form = _Form.NONE
305 conditions: str = ""
306 unofficial: bool = False
307
308 __KEYMAP = {
309 "unit": "function",
310 "internal op": "intop",
311 "CR in": "cr_in",
312 "CR out": "cr_out",
313 "cry in": "cry_in",
314 "ldst len": "ldst_len",
315 "rc": "Rc",
316 "CONDITIONS": "conditions",
317 }
318
319 def __lt__(self, other):
320 if not isinstance(other, self.__class__):
321 return NotImplemented
322 lhs = (self.opcode, self.comment)
323 rhs = (other.opcode, other.comment)
324 return (lhs < rhs)
325
326 @classmethod
327 def CSV(cls, record, opcode_cls):
328 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
329 typemap["opcode"] = opcode_cls
330
331 if record["CR in"] == "BA_BB":
332 record["cr_in"] = "BA"
333 record["cr_in2"] = "BB"
334 del record["CR in"]
335
336 flags = set()
337 for flag in frozenset(PPCRecord.Flags):
338 if bool(record.pop(flag, "")):
339 flags.add(flag)
340 record["flags"] = PPCRecord.Flags(flags)
341
342 return dataclass(cls, record,
343 keymap=PPCRecord.__KEYMAP,
344 typemap=typemap)
345
346 @cached_property
347 def names(self):
348 return frozenset(self.comment.split("=")[-1].split("/"))
349
350
351 class PPCMultiRecord(tuple):
352 def __getattr__(self, attr):
353 if attr == "opcode":
354 if len(self) != 1:
355 raise AttributeError(attr)
356 return getattr(self[0], attr)
357
358
359 @_dataclasses.dataclass(eq=True, frozen=True)
360 class SVP64Record:
361 class ExtraMap(tuple):
362 class Extra(tuple):
363 @_dataclasses.dataclass(eq=True, frozen=True)
364 class Entry:
365 seltype: _SelType = _SelType.NONE
366 reg: _Reg = _Reg.NONE
367
368 def __repr__(self):
369 return f"{self.seltype.value}:{self.reg.name}"
370
371 def __new__(cls, value="0"):
372 if isinstance(value, str):
373 def transform(value):
374 (seltype, reg) = value.split(":")
375 seltype = _SelType(seltype)
376 reg = _Reg(reg)
377 return cls.Entry(seltype=seltype, reg=reg)
378
379 if value == "0":
380 value = tuple()
381 else:
382 value = map(transform, value.split(";"))
383
384 return super().__new__(cls, value)
385
386 def __repr__(self):
387 return repr(list(self))
388
389 def __new__(cls, value=tuple()):
390 value = tuple(value)
391 if len(value) == 0:
392 value = (("0",) * 4)
393 return super().__new__(cls, map(cls.Extra, value))
394
395 def __repr__(self):
396 return repr({index:self[index] for index in range(0, 4)})
397
398 name: str
399 ptype: _SVPType = _SVPType.NONE
400 etype: _SVEType = _SVEType.NONE
401 msrc: _SVMaskSrc = _SVMaskSrc.NO # MASK_SRC is active
402 in1: _In1Sel = _In1Sel.NONE
403 in2: _In2Sel = _In2Sel.NONE
404 in3: _In3Sel = _In3Sel.NONE
405 out: _OutSel = _OutSel.NONE
406 out2: _OutSel = _OutSel.NONE
407 cr_in: _CRInSel = _CRInSel.NONE
408 cr_in2: _CRIn2Sel = _CRIn2Sel.NONE
409 cr_out: _CROutSel = _CROutSel.NONE
410 extra: ExtraMap = ExtraMap()
411 conditions: str = ""
412 mode: _SVMode = _SVMode.NORMAL
413
414 __KEYMAP = {
415 "insn": "name",
416 "CONDITIONS": "conditions",
417 "Ptype": "ptype",
418 "Etype": "etype",
419 "SM": "msrc",
420 "CR in": "cr_in",
421 "CR out": "cr_out",
422 }
423
424 @classmethod
425 def CSV(cls, record):
426 record["insn"] = record["insn"].split("=")[-1]
427
428 for key in frozenset({
429 "in1", "in2", "in3", "CR in",
430 "out", "out2", "CR out",
431 }):
432 value = record[key]
433 if value == "0":
434 record[key] = "NONE"
435
436 if record["CR in"] == "BA_BB":
437 record["cr_in"] = "BA"
438 record["cr_in2"] = "BB"
439 del record["CR in"]
440
441 extra = []
442 for idx in range(0, 4):
443 extra.append(record.pop(f"{idx}"))
444
445 record["extra"] = cls.ExtraMap(extra)
446
447 return dataclass(cls, record, keymap=cls.__KEYMAP)
448
449 @cached_property
450 def extras(self):
451 keys = (
452 "in1", "in2", "in3", "cr_in", "cr_in2",
453 "out", "out2", "cr_out",
454 )
455
456 idxmap = (
457 _SVExtra.Idx0,
458 _SVExtra.Idx1,
459 _SVExtra.Idx2,
460 _SVExtra.Idx3,
461 )
462
463 def extra(reg):
464 extras = {
465 _SelType.DST: {},
466 _SelType.SRC: {},
467 }
468 for index in range(0, 4):
469 for entry in self.extra[index]:
470 extras[entry.seltype][entry.reg] = idxmap[index]
471
472 for (seltype, regs) in extras.items():
473 idx = regs.get(reg, _SVExtra.NONE)
474 if idx is not _SVExtra.NONE:
475 yield (reg, seltype, idx)
476
477 sels = {}
478 idxs = {}
479 regs = {}
480 seltypes = {}
481 for key in keys:
482 # has the word "in", it is a SelType.SRC "out" -> DST
483 # in1/2/3 and CR in are SRC, and must match only against "s:NN"
484 # out/out1 and CR out are DST, and must match only against "d:NN"
485 keytype = _SelType.SRC if ("in" in key) else _SelType.DST
486 sel = sels[key] = getattr(self, key)
487 reg = regs[key] = _Reg(sel)
488 seltypes[key] = _SelType.NONE
489 idxs[key] = _SVExtra.NONE
490 for (reg, seltype, idx) in extra(reg.alias):
491 if keytype != seltype: # only check SRC-to-SRC and DST-to-DST
492 continue
493 if idx != idxs[key] and idxs[key] is not _SVExtra.NONE:
494 raise ValueError(idx)
495 idxs[key] = idx
496 regs[key] = reg
497 seltypes[key] = seltype
498
499 if sels["cr_in"] is _CRInSel.BA_BB:
500 sels["cr_in"] = _CRIn2Sel.BA
501 sels["cr_in2"] = _CRIn2Sel.BB
502 idxs["cr_in2"] = idxs["cr_in"]
503 for key in ("cr_in", "cr_in2"):
504 regs[key] = _Reg(sels[key])
505 seltype[key] = _SelType.SRC
506
507 records = {}
508 for key in keys:
509 records[key] = {
510 "sel": sels[key],
511 "reg": regs[key],
512 "seltype": seltypes[key],
513 "idx": idxs[key],
514 }
515
516 return _types.MappingProxyType(records)
517
518 extra_idx_in1 = property(lambda self: self.extras["in1"]["idx"])
519 extra_idx_in2 = property(lambda self: self.extras["in2"]["idx"])
520 extra_idx_in3 = property(lambda self: self.extras["in3"]["idx"])
521 extra_idx_out = property(lambda self: self.extras["out"]["idx"])
522 extra_idx_out2 = property(lambda self: self.extras["out2"]["idx"])
523 extra_idx_cr_in = property(lambda self: self.extras["cr_in"]["idx"])
524 extra_idx_cr_in2 = property(lambda self: self.extras["cr_in2"]["idx"])
525 extra_idx_cr_out = property(lambda self: self.extras["cr_out"]["idx"])
526
527 @cached_property
528 def extra_CR(self):
529 extra = None
530 for idx in range(0, 4):
531 for entry in self.extra[idx]:
532 if entry.seltype is _SelType.DST:
533 if extra is not None:
534 raise ValueError(self.svp64)
535 extra = entry
536 break
537
538 if _RegType(extra.reg) not in (_RegType.CR_3BIT, _RegType.CR_5BIT):
539 raise ValueError(self.svp64)
540
541 return extra
542
543 @cached_property
544 def extra_CR_3bit(self):
545 return (_RegType(self.extra_CR.reg) is _RegType.CR_3BIT)
546
547
548 class BitSel:
549 def __init__(self, value=(0, 32)):
550 if isinstance(value, str):
551 (start, end) = map(int, value.split(":"))
552 else:
553 (start, end) = value
554 if start < 0 or end < 0 or start >= end:
555 raise ValueError(value)
556
557 self.__start = start
558 self.__end = end
559
560 return super().__init__()
561
562 def __len__(self):
563 return (self.__end - self.__start + 1)
564
565 def __repr__(self):
566 return f"[{self.__start}:{self.__end}]"
567
568 def __iter__(self):
569 yield from range(self.start, (self.end + 1))
570
571 def __reversed__(self):
572 return tuple(reversed(tuple(self)))
573
574 @property
575 def start(self):
576 return self.__start
577
578 @property
579 def end(self):
580 return self.__end
581
582
583 @_dataclasses.dataclass(eq=True, frozen=True)
584 class Section:
585 class Mode(_enum.Enum):
586 INTEGER = _enum.auto()
587 PATTERN = _enum.auto()
588
589 @classmethod
590 def _missing_(cls, value):
591 if isinstance(value, str):
592 return cls[value.upper()]
593 return super()._missing_(value)
594
595 class Suffix(int):
596 def __new__(cls, value=None):
597 if isinstance(value, str):
598 if value.upper() == "NONE":
599 value = None
600 else:
601 value = int(value, 0)
602 if value is None:
603 value = 0
604
605 return super().__new__(cls, value)
606
607 def __str__(self):
608 return repr(self)
609
610 def __repr__(self):
611 return (bin(self) if self else "None")
612
613 path: _pathlib.Path
614 bitsel: BitSel
615 suffix: Suffix
616 mode: Mode
617 opcode: IntegerOpcode = None
618 priority: Priority = Priority.NORMAL
619
620 def __lt__(self, other):
621 if not isinstance(other, self.__class__):
622 return NotImplemented
623 return (self.priority < other.priority)
624
625 @classmethod
626 def CSV(cls, record):
627 typemap = {field.name:field.type for field in _dataclasses.fields(cls)}
628 if record["opcode"] == "NONE":
629 typemap["opcode"] = lambda _: None
630
631 return dataclass(cls, record, typemap=typemap)
632
633
634 class Fields:
635 def __init__(self, items):
636 if isinstance(items, dict):
637 items = items.items()
638
639 def transform(item):
640 (name, bitrange) = item
641 return (name, tuple(bitrange.values()))
642
643 self.__mapping = dict(map(transform, items))
644
645 return super().__init__()
646
647 def __repr__(self):
648 return repr(self.__mapping)
649
650 def __iter__(self):
651 yield from self.__mapping.items()
652
653 def __contains__(self, key):
654 return self.__mapping.__contains__(key)
655
656 def __getitem__(self, key):
657 return self.__mapping.get(key, None)
658
659
660 class Operands:
661 __GPR_PAIRS = (
662 _Reg.RTp,
663 _Reg.RSp,
664 )
665 __FPR_PAIRS = (
666 _Reg.FRAp,
667 _Reg.FRBp,
668 _Reg.FRSp,
669 _Reg.FRTp,
670 )
671
672 def __init__(self, insn, operands):
673 custom_insns = {
674 "b": {"target_addr": TargetAddrOperandLI},
675 "ba": {"target_addr": TargetAddrOperandLI},
676 "bl": {"target_addr": TargetAddrOperandLI},
677 "bla": {"target_addr": TargetAddrOperandLI},
678 "bc": {"target_addr": TargetAddrOperandBD},
679 "bca": {"target_addr": TargetAddrOperandBD},
680 "bcl": {"target_addr": TargetAddrOperandBD},
681 "bcla": {"target_addr": TargetAddrOperandBD},
682 "addpcis": {"D": DOperandDX},
683 "fishmv": {"D": DOperandDX},
684 "fmvis": {"D": DOperandDX},
685 }
686 custom_fields = {
687 "SVi": NonZeroOperand,
688 "SVd": NonZeroOperand,
689 "SVxd": NonZeroOperand,
690 "SVyd": NonZeroOperand,
691 "SVzd": NonZeroOperand,
692 "BD": SignedOperand,
693 "D": SignedImmediateOperand,
694 "SI": SignedOperand,
695 "IB": SignedOperand,
696 "LI": SignedOperand,
697 "SIM": SignedOperand,
698 "SVD": SignedOperand,
699 "SVDS": SignedOperand,
700 "RSp": GPRPairOperand,
701 "RTp": GPRPairOperand,
702 "FRAp": FPRPairOperand,
703 "FRBp": FPRPairOperand,
704 "FRSp": FPRPairOperand,
705 "FRTp": FPRPairOperand,
706 }
707 custom_immediates = {
708 "DQ": EXTSOperandDQ,
709 "DS": EXTSOperandDS,
710 }
711
712 mapping = {}
713 for operand in operands:
714 cls = DynamicOperand
715
716 if "=" in operand:
717 (name, value) = operand.split("=")
718 mapping[name] = (StaticOperand, {
719 "name": name,
720 "value": int(value),
721 })
722 else:
723 name = operand
724 if name.endswith(")"):
725 name = name.replace("(", " ").replace(")", "")
726 (imm_name, _, name) = name.partition(" ")
727 else:
728 imm_name = None
729
730 if imm_name is not None:
731 imm_cls = custom_immediates.get(imm_name, ImmediateOperand)
732
733 if insn in custom_insns and name in custom_insns[insn]:
734 cls = custom_insns[insn][name]
735 elif name in custom_fields:
736 cls = custom_fields[name]
737 elif name in _Reg.__members__:
738 reg = _Reg[name]
739 if reg in self.__class__.__GPR_PAIRS:
740 cls = GPRPairOperand
741 elif reg in self.__class__.__FPR_PAIRS:
742 cls = FPRPairOperand
743 else:
744 regtype = _RegType[name]
745 if regtype is _RegType.GPR:
746 cls = GPROperand
747 elif regtype is _RegType.FPR:
748 cls = FPROperand
749 elif regtype is _RegType.CR_3BIT:
750 cls = CR3Operand
751 elif regtype is _RegType.CR_5BIT:
752 cls = CR5Operand
753
754 if imm_name is not None:
755 mapping[imm_name] = (imm_cls, {"name": imm_name})
756 mapping[name] = (cls, {"name": name})
757
758 static = []
759 dynamic = []
760 for (name, (cls, kwargs)) in mapping.items():
761 kwargs = dict(kwargs)
762 kwargs["name"] = name
763 if issubclass(cls, StaticOperand):
764 static.append((cls, kwargs))
765 elif issubclass(cls, DynamicOperand):
766 dynamic.append((cls, kwargs))
767 else:
768 raise ValueError(name)
769
770 self.__mapping = mapping
771 self.__static = tuple(static)
772 self.__dynamic = tuple(dynamic)
773
774 return super().__init__()
775
776 def __iter__(self):
777 for (_, items) in self.__mapping.items():
778 (cls, kwargs) = items
779 yield (cls, kwargs)
780
781 def __repr__(self):
782 return self.__mapping.__repr__()
783
784 def __contains__(self, key):
785 return self.__mapping.__contains__(key)
786
787 def __getitem__(self, key):
788 return self.__mapping.__getitem__(key)
789
790 @property
791 def static(self):
792 return self.__static
793
794 @property
795 def dynamic(self):
796 return self.__dynamic
797
798
799 class Arguments(tuple):
800 def __new__(cls, record, arguments, operands):
801 operands = iter(tuple(operands))
802 arguments = iter(tuple(arguments))
803
804 items = []
805 while True:
806 try:
807 operand = next(operands)
808 except StopIteration:
809 break
810
811 try:
812 argument = next(arguments)
813 except StopIteration:
814 raise ValueError("operands count mismatch")
815
816 if isinstance(operand, ImmediateOperand):
817 argument = argument.replace("(", " ").replace(")", "")
818 (imm_argument, _, argument) = argument.partition(" ")
819 try:
820 (imm_operand, operand) = (operand, next(operands))
821 except StopIteration:
822 raise ValueError("operands count mismatch")
823 items.append((imm_argument, imm_operand))
824 items.append((argument, operand))
825
826 try:
827 next(arguments)
828 except StopIteration:
829 pass
830 else:
831 raise ValueError("operands count mismatch")
832
833 return super().__new__(cls, items)
834
835
836 class PCode:
837 def __init__(self, iterable):
838 self.__pcode = tuple(iterable)
839 return super().__init__()
840
841 def __iter__(self):
842 yield from self.__pcode
843
844 def __repr__(self):
845 return self.__pcode.__repr__()
846
847
848 @_dataclasses.dataclass(eq=True, frozen=True)
849 class MarkdownRecord:
850 pcode: PCode
851 operands: Operands
852
853
854 @_dataclasses.dataclass(eq=True, frozen=True)
855 class Extra(Node):
856 name: str
857 sel: _typing.Union[
858 _In1Sel, _In2Sel, _In3Sel, _CRInSel, _CRIn2Sel,
859 _OutSel, _CROutSel,
860 ]
861 reg: _Reg
862 seltype: _SelType
863 idx: _SVExtra
864
865
866 @_functools.total_ordering
867 @_dataclasses.dataclass(eq=True, frozen=True)
868 class Record(Node):
869 name: str
870 section: Section
871 ppc: PPCRecord
872 fields: Fields
873 mdwn: MarkdownRecord
874 svp64: SVP64Record = None
875
876 def visit(self, handler, matcher, depth):
877 if matcher(node=self, depth=depth):
878 with handler(node=self, depth=depth):
879 for (name, fields) in self.extras.items():
880 extra = Extra(name=name, **fields)
881 extra.visit(depth=(depth + 1),
882 handler=handler, matcher=matcher)
883
884 @property
885 def extras(self):
886 if self.svp64 is not None:
887 return self.svp64.extras
888 else:
889 return _types.MappingProxyType({})
890
891 @property
892 def pcode(self):
893 return self.mdwn.pcode
894
895 def __lt__(self, other):
896 if not isinstance(other, Record):
897 return NotImplemented
898 lhs = (min(self.opcodes), self.name)
899 rhs = (min(other.opcodes), other.name)
900 return (lhs < rhs)
901
902 @cached_property
903 def operands(self):
904 return (self.static_operands + self.dynamic_operands)
905
906 @cached_property
907 def static_operands(self):
908 operands = []
909 operands.append(POStaticOperand(record=self, value=self.PO))
910 for ppc in self.ppc:
911 operands.append(XOStaticOperand(
912 record=self,
913 value=ppc.opcode.value,
914 span=self.section.bitsel,
915 ))
916 for (cls, kwargs) in self.mdwn.operands.static:
917 operands.append(cls(record=self, **kwargs))
918 return tuple(operands)
919
920 @cached_property
921 def dynamic_operands(self):
922 operands = []
923 for (cls, kwargs) in self.mdwn.operands.dynamic:
924 operands.append(cls(record=self, **kwargs))
925 return tuple(operands)
926
927 @cached_property
928 def opcodes(self):
929 def binary(mapping):
930 return int("".join(str(int(mapping[bit])) \
931 for bit in sorted(mapping)), 2)
932
933 def PO_XO(value, mask, opcode, bits):
934 value = dict(value)
935 mask = dict(mask)
936 for (src, dst) in enumerate(reversed(bits)):
937 value[dst] = ((opcode.value & (1 << src)) != 0)
938 mask[dst] = ((opcode.mask & (1 << src)) != 0)
939 return (value, mask)
940
941 def PO(value, mask, opcode, bits):
942 return PO_XO(value=value, mask=mask, opcode=opcode, bits=bits)
943
944 def XO(value, mask, opcode, bits):
945 (value, mask) = PO_XO(value=value, mask=mask,
946 opcode=opcode, bits=bits)
947 for (op_cls, op_kwargs) in self.mdwn.operands.static:
948 operand = op_cls(record=self, **op_kwargs)
949 for (src, dst) in enumerate(reversed(operand.span)):
950 value[dst] = ((operand.value & (1 << src)) != 0)
951 mask[dst] = True
952 return (value, mask)
953
954 pairs = []
955 value = {bit:False for bit in range(32)}
956 mask = {bit:False for bit in range(32)}
957 if self.section.opcode is not None:
958 (value, mask) = PO(value=value, mask=mask,
959 opcode=self.section.opcode, bits=range(0, 6))
960 for ppc in self.ppc:
961 pairs.append(XO(value=value, mask=mask,
962 opcode=ppc.opcode, bits=self.section.bitsel))
963
964 result = []
965 for (value, mask) in pairs:
966 value = Opcode.Value(binary(value))
967 mask = Opcode.Mask(binary(mask))
968 result.append(Opcode(value=value, mask=mask))
969
970 return tuple(result)
971
972 @cached_property
973 def PO(self):
974 opcode = self.section.opcode
975 if opcode is None:
976 opcode = self.ppc[0].opcode
977 if isinstance(opcode, PatternOpcode):
978 value = int(opcode.value)
979 bits = opcode.value.bit_length()
980 return int(_SelectableInt(value=value, bits=bits)[0:6])
981
982 return int(opcode.value)
983
984 @cached_property
985 def XO(self):
986 return tuple(ppc.opcode for ppc in self.ppc)
987
988 def match(self, key):
989 for opcode in self.opcodes:
990 if opcode.match(key):
991 return True
992
993 return False
994
995 @property
996 def mode(self):
997 return self.svp64.mode
998
999 @property
1000 def in1(self):
1001 return self.ppc.in1
1002
1003 @property
1004 def in2(self):
1005 return self.ppc.in2
1006
1007 @property
1008 def in3(self):
1009 return self.ppc.in3
1010
1011 @property
1012 def out(self):
1013 return self.ppc.out
1014
1015 @property
1016 def out2(self):
1017 if self.svp64 is None:
1018 return _OutSel.NONE
1019 return self.ppc.out
1020
1021 @property
1022 def cr_in(self):
1023 return self.ppc.cr_in
1024
1025 @property
1026 def cr_in2(self):
1027 return self.ppc.cr_in2
1028
1029 @property
1030 def cr_out(self):
1031 return self.ppc.cr_out
1032
1033 ptype = property(lambda self: self.svp64.ptype)
1034 etype = property(lambda self: self.svp64.etype)
1035
1036 extra_idx_in1 = property(lambda self: self.svp64.extra_idx_in1)
1037 extra_idx_in2 = property(lambda self: self.svp64.extra_idx_in2)
1038 extra_idx_in3 = property(lambda self: self.svp64.extra_idx_in3)
1039 extra_idx_out = property(lambda self: self.svp64.extra_idx_out)
1040 extra_idx_out2 = property(lambda self: self.svp64.extra_idx_out2)
1041 extra_idx_cr_in = property(lambda self: self.svp64.extra_idx_cr_in)
1042 extra_idx_cr_in2 = property(lambda self: self.svp64.extra_idx_cr_in2)
1043 extra_idx_cr_out = property(lambda self: self.svp64.extra_idx_cr_out)
1044
1045 def __contains__(self, key):
1046 return self.mdwn.operands.__contains__(key)
1047
1048 def __getitem__(self, key):
1049 (cls, kwargs) = self.mdwn.operands.__getitem__(key)
1050 return cls(record=self, **kwargs)
1051
1052 @cached_property
1053 def Rc(self):
1054 if "Rc" not in self:
1055 return False
1056 return self["Rc"].value
1057
1058
1059 class Operand:
1060 def __init__(self, record, name):
1061 self.__record = record
1062 self.__name = name
1063
1064 def __iter__(self):
1065 yield ("record", self.record)
1066 yield ("name", self.__name)
1067
1068 def __repr__(self):
1069 return f"{self.__class__.__name__}({self.name})"
1070
1071 @property
1072 def name(self):
1073 return self.__name
1074
1075 @property
1076 def record(self):
1077 return self.__record
1078
1079 @cached_property
1080 def span(self):
1081 return self.record.fields[self.name]
1082
1083 def assemble(self, insn):
1084 raise NotImplementedError()
1085
1086 def disassemble(self, insn,
1087 style=Style.NORMAL, indent=""):
1088 raise NotImplementedError()
1089
1090
1091 class DynamicOperand(Operand):
1092 def assemble(self, insn, value):
1093 span = self.span
1094 if isinstance(value, str):
1095 value = int(value, 0)
1096 if value < 0:
1097 raise ValueError("signed operands not allowed")
1098 insn[span] = value
1099
1100 def disassemble(self, insn,
1101 style=Style.NORMAL, indent=""):
1102 span = self.span
1103 value = insn[span]
1104
1105 if style >= Style.VERBOSE:
1106 span = map(str, span)
1107 yield f"{indent}{self.name}"
1108 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1109 yield f"{indent}{indent}{', '.join(span)}"
1110 else:
1111 yield str(int(value))
1112
1113
1114 class SignedOperand(DynamicOperand):
1115 def assemble(self, insn, value):
1116 if isinstance(value, str):
1117 value = int(value, 0)
1118 return super().assemble(value=value, insn=insn)
1119
1120 def assemble(self, insn, value):
1121 span = self.span
1122 if isinstance(value, str):
1123 value = int(value, 0)
1124 insn[span] = value
1125
1126 def disassemble(self, insn,
1127 style=Style.NORMAL, indent=""):
1128 span = self.span
1129 value = insn[span].to_signed_int()
1130 sign = "-" if (value < 0) else ""
1131 value = abs(value)
1132
1133 if style >= Style.VERBOSE:
1134 span = map(str, span)
1135 yield f"{indent}{self.name}"
1136 yield f"{indent}{indent}{sign}{value}"
1137 yield f"{indent}{indent}{', '.join(span)}"
1138 else:
1139 yield f"{sign}{value}"
1140
1141
1142 class StaticOperand(Operand):
1143 def __init__(self, record, name, value):
1144 self.__value = value
1145 return super().__init__(record=record, name=name)
1146
1147 def __iter__(self):
1148 yield ("value", self.__value)
1149 yield from super().__iter__()
1150
1151 def __repr__(self):
1152 return f"{self.__class__.__name__}({self.name}, value={self.value})"
1153
1154 @property
1155 def value(self):
1156 return self.__value
1157
1158 def assemble(self, insn):
1159 insn[self.span] = self.value
1160
1161 def disassemble(self, insn,
1162 style=Style.NORMAL, indent=""):
1163 span = self.span
1164 value = insn[span]
1165
1166 if style >= Style.VERBOSE:
1167 span = map(str, span)
1168 yield f"{indent}{self.name}"
1169 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1170 yield f"{indent}{indent}{', '.join(span)}"
1171 else:
1172 yield str(int(value))
1173
1174
1175 class SpanStaticOperand(StaticOperand):
1176 def __init__(self, record, name, value, span):
1177 self.__span = tuple(span)
1178 return super().__init__(record=record, name=name, value=value)
1179
1180 def __iter__(self):
1181 yield ("span", self.__span)
1182 yield from super().__iter__()
1183
1184 @property
1185 def span(self):
1186 return self.__span
1187
1188
1189 class POStaticOperand(SpanStaticOperand):
1190 def __init__(self, record, value):
1191 return super().__init__(record=record, name="PO",
1192 value=value, span=range(0, 6))
1193
1194 def __iter__(self):
1195 for (key, value) in super().__iter__():
1196 if key not in {"name", "span"}:
1197 yield (key, value)
1198
1199
1200 class XOStaticOperand(SpanStaticOperand):
1201 def __init__(self, record, value, span):
1202 bits = record.section.bitsel
1203 value = _SelectableInt(value=value, bits=len(bits))
1204 span = dict(zip(bits, range(len(bits))))
1205 span_rev = {value:key for (key, value) in span.items()}
1206
1207 # This part is tricky: we cannot use record.operands,
1208 # as this code is called by record.static_operands method.
1209 for (cls, kwargs) in record.mdwn.operands:
1210 operand = cls(record=record, **kwargs)
1211 for idx in operand.span:
1212 rev = span.pop(idx, None)
1213 if rev is not None:
1214 span_rev.pop(rev, None)
1215
1216 value = int(_selectconcat(*(value[bit] for bit in span.values())))
1217 span = tuple(span.keys())
1218
1219 return super().__init__(record=record, name="XO",
1220 value=value, span=span)
1221
1222 def __iter__(self):
1223 for (key, value) in super().__iter__():
1224 if key not in {"name"}:
1225 yield (key, value)
1226
1227
1228 class ImmediateOperand(DynamicOperand):
1229 pass
1230
1231
1232 class SignedImmediateOperand(SignedOperand, ImmediateOperand):
1233 pass
1234
1235
1236 class NonZeroOperand(DynamicOperand):
1237 def assemble(self, insn, value):
1238 if isinstance(value, str):
1239 value = int(value, 0)
1240 if not isinstance(value, int):
1241 raise ValueError("non-integer operand")
1242 if value == 0:
1243 raise ValueError("non-zero operand")
1244 value -= 1
1245 return super().assemble(value=value, insn=insn)
1246
1247 def disassemble(self, insn,
1248 style=Style.NORMAL, indent=""):
1249 span = self.span
1250 value = insn[span]
1251
1252 if style >= Style.VERBOSE:
1253 span = map(str, span)
1254 yield f"{indent}{self.name}"
1255 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1256 yield f"{indent}{indent}{', '.join(span)}"
1257 else:
1258 yield str(int(value) + 1)
1259
1260
1261 class ExtendableOperand(DynamicOperand):
1262 def sv_spec_enter(self, value, span):
1263 return (value, span)
1264
1265 def sv_spec(self, insn):
1266 vector = False
1267 span = self.span
1268 value = insn[span]
1269 span = tuple(map(str, span))
1270
1271 if isinstance(insn, SVP64Instruction):
1272 (origin_value, origin_span) = (value, span)
1273 (value, span) = self.sv_spec_enter(value=value, span=span)
1274
1275 for extra_idx in self.extra_idx:
1276 if self.record.etype is _SVEType.EXTRA3:
1277 spec = insn.prefix.rm.extra3[extra_idx]
1278 elif self.record.etype is _SVEType.EXTRA2:
1279 spec = insn.prefix.rm.extra2[extra_idx]
1280 else:
1281 raise ValueError(self.record.etype)
1282
1283 if spec != 0:
1284 vector = bool(spec[0])
1285 spec_span = spec.__class__
1286 if self.record.etype is _SVEType.EXTRA3:
1287 spec_span = tuple(map(str, spec_span[1, 2]))
1288 spec = spec[1, 2]
1289 elif self.record.etype is _SVEType.EXTRA2:
1290 spec_span = tuple(map(str, spec_span[1,]))
1291 spec = _SelectableInt(value=spec[1].value, bits=2)
1292 if vector:
1293 spec <<= 1
1294 spec_span = (spec_span + ("{0}",))
1295 else:
1296 spec_span = (("{0}",) + spec_span)
1297 else:
1298 raise ValueError(self.record.etype)
1299
1300 vector_shift = (2 + (5 - value.bits))
1301 scalar_shift = value.bits
1302 spec_shift = (5 - value.bits)
1303
1304 bits = (len(span) + len(spec_span))
1305 value = _SelectableInt(value=value.value, bits=bits)
1306 spec = _SelectableInt(value=spec.value, bits=bits)
1307 if vector:
1308 value = ((value << vector_shift) | (spec << spec_shift))
1309 span = (span + spec_span + ((spec_shift * ("{0}",))))
1310 else:
1311 value = ((spec << scalar_shift) | value)
1312 span = ((spec_shift * ("{0}",)) + spec_span + span)
1313
1314 (value, span) = self.sv_spec_leave(value=value, span=span,
1315 origin_value=origin_value, origin_span=origin_span)
1316
1317 return (vector, value, span)
1318
1319 def sv_spec_leave(self, value, span, origin_value, origin_span):
1320 return (value, span)
1321
1322 @property
1323 def extra_idx(self):
1324 for (key, record) in self.record.svp64.extras.items():
1325 if record["reg"].alias is self.extra_reg.alias:
1326 yield record["idx"]
1327
1328 @cached_property
1329 def extra_reg(self):
1330 return _Reg(self.name)
1331
1332 def remap(self, value, vector):
1333 raise NotImplementedError()
1334
1335 def assemble(self, value, insn, prefix):
1336 vector = False
1337
1338 if isinstance(value, str):
1339 value = value.lower()
1340 if value.startswith("%"):
1341 value = value[1:]
1342 if value.startswith("*"):
1343 if not isinstance(insn, SVP64Instruction):
1344 raise ValueError(value)
1345 value = value[1:]
1346 vector = True
1347 if value.startswith(prefix):
1348 if (self.extra_reg.or_zero and (value == f"{prefix}0")):
1349 raise ValueError(value)
1350 value = value[len(prefix):]
1351 value = int(value, 0)
1352
1353 if isinstance(insn, SVP64Instruction):
1354 (value, extra) = self.remap(value=value, vector=vector)
1355
1356 for extra_idx in self.extra_idx:
1357 if self.record.etype is _SVEType.EXTRA3:
1358 insn.prefix.rm.extra3[extra_idx] = extra
1359 elif self.record.etype is _SVEType.EXTRA2:
1360 insn.prefix.rm.extra2[extra_idx] = extra
1361 else:
1362 raise ValueError(self.record.etype)
1363
1364 return super().assemble(value=value, insn=insn)
1365
1366 def disassemble(self, insn,
1367 style=Style.NORMAL, prefix="", indent=""):
1368 (vector, value, span) = self.sv_spec(insn=insn)
1369
1370 if (self.extra_reg.or_zero and (value == 0)):
1371 prefix = ""
1372
1373 if style >= Style.VERBOSE:
1374 mode = "vector" if vector else "scalar"
1375 yield f"{indent}{self.name} ({mode})"
1376 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1377 yield f"{indent}{indent}{', '.join(span)}"
1378 if isinstance(insn, SVP64Instruction):
1379 for extra_idx in frozenset(self.extra_idx):
1380 if self.record.etype is _SVEType.NONE:
1381 yield f"{indent}{indent}extra[none]"
1382 else:
1383 etype = repr(self.record.etype).lower()
1384 yield f"{indent}{indent}{etype}{extra_idx!r}"
1385 else:
1386 vector = "*" if vector else ""
1387 yield f"{vector}{prefix}{int(value)}"
1388
1389
1390 class SimpleRegisterOperand(ExtendableOperand):
1391 def remap(self, value, vector):
1392 if vector:
1393 extra = (value & 0b11)
1394 value = (value >> 2)
1395 else:
1396 extra = (value >> 5)
1397 value = (value & 0b11111)
1398
1399 # now sanity-check. EXTRA3 is ok, EXTRA2 has limits
1400 # (and shrink to a single bit if ok)
1401 if self.record.etype is _SVEType.EXTRA2:
1402 if vector:
1403 # range is r0-r127 in increments of 2 (r0 r2 ... r126)
1404 assert (extra & 0b01) == 0, \
1405 ("vector field %s cannot fit into EXTRA2" % value)
1406 extra = (0b10 | (extra >> 1))
1407 else:
1408 # range is r0-r63 in increments of 1
1409 assert (extra >> 1) == 0, \
1410 ("scalar GPR %d cannot fit into EXTRA2" % value)
1411 extra &= 0b01
1412 elif self.record.etype is _SVEType.EXTRA3:
1413 if vector:
1414 # EXTRA3 vector bit needs marking
1415 extra |= 0b100
1416 else:
1417 raise ValueError(self.record.etype)
1418
1419 return (value, extra)
1420
1421
1422 class GPROperand(SimpleRegisterOperand):
1423 def assemble(self, insn, value):
1424 return super().assemble(value=value, insn=insn, prefix="r")
1425
1426 def disassemble(self, insn,
1427 style=Style.NORMAL, indent=""):
1428 prefix = "" if (style <= Style.SHORT) else "r"
1429 yield from super().disassemble(prefix=prefix, insn=insn,
1430 style=style, indent=indent)
1431
1432
1433 class GPRPairOperand(GPROperand):
1434 pass
1435
1436
1437 class FPROperand(SimpleRegisterOperand):
1438 def assemble(self, insn, value):
1439 return super().assemble(value=value, insn=insn, prefix="f")
1440
1441 def disassemble(self, insn,
1442 style=Style.NORMAL, indent=""):
1443 prefix = "" if (style <= Style.SHORT) else "f"
1444 yield from super().disassemble(prefix=prefix, insn=insn,
1445 style=style, indent=indent)
1446
1447
1448 class FPRPairOperand(FPROperand):
1449 pass
1450
1451
1452 class ConditionRegisterFieldOperand(ExtendableOperand):
1453 def pattern(name_pattern):
1454 (name, pattern) = name_pattern
1455 return (name, _re.compile(f"^{pattern}$", _re.S))
1456
1457 CONDS = {
1458 "lt": 0,
1459 "gt": 1,
1460 "eq": 2,
1461 "so": 3,
1462 "un": 3,
1463 }
1464 CR = r"(?:CR|cr)([0-9]+)"
1465 N = r"([0-9]+)"
1466 BIT = rf"({'|'.join(CONDS.keys())})"
1467 LBIT = fr"{BIT}\s*\+\s*" # BIT+
1468 RBIT = fr"\s*\+\s*{BIT}" # +BIT
1469 CRN = fr"{CR}\s*\*\s*{N}" # CR*N
1470 NCR = fr"{N}\s*\*\s*{CR}" # N*CR
1471 XCR = fr"{CR}\.{BIT}"
1472 PATTERNS = tuple(map(pattern, (
1473 ("CR", CR),
1474 ("XCR", XCR),
1475 ("CR*N", CRN),
1476 ("N*CR", NCR),
1477 ("BIT+CR", (LBIT + CR)),
1478 ("CR+BIT", (CR + RBIT)),
1479 ("BIT+CR*N", (LBIT + CRN)),
1480 ("CR*N+BIT", (CRN + RBIT)),
1481 ("BIT+N*CR", (LBIT + NCR)),
1482 ("N*CR+BIT", (NCR + RBIT)),
1483 )))
1484
1485 def remap(self, value, vector, regtype):
1486 if regtype is _RegType.CR_5BIT:
1487 subvalue = (value & 0b11)
1488 value >>= 2
1489
1490 if vector:
1491 extra = (value & 0b1111)
1492 value >>= 4
1493 else:
1494 extra = (value >> 3)
1495 value &= 0b111
1496
1497 if self.record.etype is _SVEType.EXTRA2:
1498 if vector:
1499 assert (extra & 0b111) == 0, \
1500 "vector CR cannot fit into EXTRA2"
1501 extra = (0b10 | (extra >> 3))
1502 else:
1503 assert (extra >> 1) == 0, \
1504 "scalar CR cannot fit into EXTRA2"
1505 extra &= 0b01
1506 elif self.record.etype is _SVEType.EXTRA3:
1507 if vector:
1508 assert (extra & 0b11) == 0, \
1509 "vector CR cannot fit into EXTRA3"
1510 extra = (0b100 | (extra >> 2))
1511 else:
1512 assert (extra >> 2) == 0, \
1513 "scalar CR cannot fit into EXTRA3"
1514 extra &= 0b11
1515
1516 if regtype is _RegType.CR_5BIT:
1517 value = ((value << 2) | subvalue)
1518
1519 return (value, extra)
1520
1521 def assemble(self, insn, value):
1522 if isinstance(value, str):
1523 vector = False
1524
1525 if value.startswith("*"):
1526 if not isinstance(insn, SVP64Instruction):
1527 raise ValueError(value)
1528 value = value[1:]
1529 vector = True
1530
1531 for (name, pattern) in reversed(self.__class__.PATTERNS):
1532 match = pattern.match(value)
1533 if match is not None:
1534 keys = name.replace("+", "_").replace("*", "_").split("_")
1535 values = match.groups()
1536 match = dict(zip(keys, values))
1537 CR = int(match["CR"])
1538 if name == "XCR":
1539 N = 4
1540 else:
1541 N = int(match.get("N", "1"))
1542 BIT = self.__class__.CONDS[match.get("BIT", "lt")]
1543 value = ((CR * N) + BIT)
1544 break
1545
1546 value = str(value)
1547 if vector:
1548 value = f"*{value}"
1549
1550 return super().assemble(value=value, insn=insn, prefix="cr")
1551
1552 def disassemble(self, insn,
1553 style=Style.NORMAL, prefix="", indent=""):
1554 (vector, value, span) = self.sv_spec(insn=insn)
1555
1556 if style >= Style.VERBOSE:
1557 mode = "vector" if vector else "scalar"
1558 yield f"{indent}{self.name} ({mode})"
1559 yield f"{indent}{indent}{int(value):0{value.bits}b}"
1560 yield f"{indent}{indent}{', '.join(span)}"
1561 if isinstance(insn, SVP64Instruction):
1562 for extra_idx in frozenset(self.extra_idx):
1563 if self.record.etype is _SVEType.NONE:
1564 yield f"{indent}{indent}extra[none]"
1565 else:
1566 etype = repr(self.record.etype).lower()
1567 yield f"{indent}{indent}{etype}{extra_idx!r}"
1568 else:
1569 vector = "*" if vector else ""
1570 CR = int(value >> 2)
1571 CC = int(value & 3)
1572 cond = ("lt", "gt", "eq", "so")[CC]
1573 if style >= Style.NORMAL:
1574 if CR != 0:
1575 if isinstance(insn, SVP64Instruction):
1576 yield f"{vector}cr{CR}.{cond}"
1577 else:
1578 yield f"4*cr{CR}+{cond}"
1579 else:
1580 yield cond
1581 else:
1582 yield f"{vector}{prefix}{int(value)}"
1583
1584
1585 class CR3Operand(ConditionRegisterFieldOperand):
1586 def remap(self, value, vector):
1587 return super().remap(value=value, vector=vector,
1588 regtype=_RegType.CR_3BIT)
1589
1590
1591 class CR5Operand(ConditionRegisterFieldOperand):
1592 def remap(self, value, vector):
1593 return super().remap(value=value, vector=vector,
1594 regtype=_RegType.CR_5BIT)
1595
1596 def sv_spec_enter(self, value, span):
1597 value = _SelectableInt(value=(value.value >> 2), bits=3)
1598 return (value, span)
1599
1600 def sv_spec_leave(self, value, span, origin_value, origin_span):
1601 value = _selectconcat(value, origin_value[3:5])
1602 span += origin_span
1603 return (value, span)
1604
1605
1606 class EXTSOperand(SignedOperand):
1607 field: str # real name to report
1608 nz: int = 0 # number of zeros
1609 fmt: str = "d" # integer formatter
1610
1611 def __init__(self, record, name, field, nz=0, fmt="d"):
1612 self.__field = field
1613 self.__nz = nz
1614 self.__fmt = fmt
1615 return super().__init__(record=record, name=name)
1616
1617 @property
1618 def field(self):
1619 return self.__field
1620
1621 @property
1622 def nz(self):
1623 return self.__nz
1624
1625 @property
1626 def fmt(self):
1627 return self.__fmt
1628
1629 @cached_property
1630 def span(self):
1631 return self.record.fields[self.field]
1632
1633 def assemble(self, insn, value):
1634 span = self.span
1635 if isinstance(value, str):
1636 value = int(value, 0)
1637 insn[span] = (value >> self.nz)
1638
1639 def disassemble(self, insn,
1640 style=Style.NORMAL, indent=""):
1641 span = self.span
1642 value = insn[span].to_signed_int()
1643 sign = "-" if (value < 0) else ""
1644 value = (abs(value) << self.nz)
1645
1646 if style >= Style.VERBOSE:
1647 span = (tuple(map(str, span)) + (("{0}",) * self.nz))
1648 zeros = ("0" * self.nz)
1649 hint = f"{self.name} = EXTS({self.field} || {zeros})"
1650 yield f"{indent * 1}{hint}"
1651 yield f"{indent * 2}{self.field}"
1652 yield f"{indent * 3}{sign}{value:{self.fmt}}"
1653 yield f"{indent * 3}{', '.join(span)}"
1654 else:
1655 yield f"{sign}{value:{self.fmt}}"
1656
1657
1658 class TargetAddrOperand(EXTSOperand):
1659 def __init__(self, record, name, field):
1660 return super().__init__(record=record, name=name, field=field,
1661 nz=2, fmt="#x")
1662
1663
1664 class TargetAddrOperandLI(TargetAddrOperand):
1665 def __init__(self, record, name):
1666 return super().__init__(record=record, name=name, field="LI")
1667
1668
1669 class TargetAddrOperandBD(TargetAddrOperand):
1670 def __init__(self, record, name):
1671 return super().__init__(record=record, name=name, field="BD")
1672
1673
1674 class EXTSOperandDS(EXTSOperand, ImmediateOperand):
1675 def __init__(self, record, name):
1676 return super().__init__(record=record, name=name, field="DS", nz=2)
1677
1678
1679 class EXTSOperandDQ(EXTSOperand, ImmediateOperand):
1680 def __init__(self, record, name):
1681 return super().__init__(record=record, name=name, field="DQ", nz=4)
1682
1683
1684 class DOperandDX(SignedOperand):
1685 @cached_property
1686 def span(self):
1687 cls = lambda name: DynamicOperand(record=self.record, name=name)
1688 operands = map(cls, ("d0", "d1", "d2"))
1689 spans = map(lambda operand: operand.span, operands)
1690 return sum(spans, tuple())
1691
1692 def disassemble(self, insn,
1693 style=Style.NORMAL, indent=""):
1694 span = self.span
1695 value = insn[span].to_signed_int()
1696 sign = "-" if (value < 0) else ""
1697 value = abs(value)
1698
1699 if style >= Style.VERBOSE:
1700 yield f"{indent}D"
1701 mapping = {
1702 "d0": "[0:9]",
1703 "d1": "[10:15]",
1704 "d2": "[16]",
1705 }
1706 for (subname, subspan) in mapping.items():
1707 operand = DynamicOperand(name=subname)
1708 span = operand.span
1709 span = map(str, span)
1710 yield f"{indent}{indent}{operand.name} = D{subspan}"
1711 yield f"{indent}{indent}{indent}{sign}{value}"
1712 yield f"{indent}{indent}{indent}{', '.join(span)}"
1713 else:
1714 yield f"{sign}{value}"
1715
1716
1717 class Instruction(_Mapping):
1718 @classmethod
1719 def integer(cls, value=0, bits=None, byteorder="little"):
1720 if isinstance(value, (int, bytes)) and not isinstance(bits, int):
1721 raise ValueError(bits)
1722
1723 if isinstance(value, bytes):
1724 if ((len(value) * 8) != bits):
1725 raise ValueError(f"bit length mismatch")
1726 value = int.from_bytes(value, byteorder=byteorder)
1727
1728 if isinstance(value, int):
1729 value = _SelectableInt(value=value, bits=bits)
1730 elif isinstance(value, Instruction):
1731 value = value.storage
1732
1733 if not isinstance(value, _SelectableInt):
1734 raise ValueError(value)
1735 if bits is None:
1736 bits = len(cls)
1737 if len(value) != bits:
1738 raise ValueError(value)
1739
1740 value = _SelectableInt(value=value, bits=bits)
1741
1742 return cls(storage=value)
1743
1744 def __hash__(self):
1745 return hash(int(self))
1746
1747 def __getitem__(self, key):
1748 return self.storage.__getitem__(key)
1749
1750 def __setitem__(self, key, value):
1751 return self.storage.__setitem__(key, value)
1752
1753 def bytes(self, byteorder="little"):
1754 nr_bytes = (len(self.__class__) // 8)
1755 return int(self).to_bytes(nr_bytes, byteorder=byteorder)
1756
1757 @classmethod
1758 def record(cls, db, entry):
1759 record = db[entry]
1760 if record is None:
1761 raise KeyError(entry)
1762 return record
1763
1764 @classmethod
1765 def operands(cls, record):
1766 yield from record.operands
1767
1768 @classmethod
1769 def static_operands(cls, record):
1770 return filter(lambda operand: isinstance(operand, StaticOperand),
1771 cls.operands(record=record))
1772
1773 @classmethod
1774 def dynamic_operands(cls, record):
1775 return filter(lambda operand: isinstance(operand, DynamicOperand),
1776 cls.operands(record=record))
1777
1778 def spec(self, record, prefix):
1779 dynamic_operands = tuple(map(_operator.itemgetter(0),
1780 self.spec_dynamic_operands(record=record)))
1781
1782 static_operands = []
1783 for (name, value) in self.spec_static_operands(record=record):
1784 static_operands.append(f"{name}={value}")
1785
1786 operands = ""
1787 if dynamic_operands:
1788 operands += " "
1789 operands += ",".join(dynamic_operands)
1790 if static_operands:
1791 operands += " "
1792 operands += " ".join(static_operands)
1793
1794 return f"{prefix}{record.name}{operands}"
1795
1796 def spec_static_operands(self, record):
1797 for operand in self.static_operands(record=record):
1798 if not isinstance(operand, (POStaticOperand, XOStaticOperand)):
1799 yield (operand.name, operand.value)
1800
1801 def spec_dynamic_operands(self, record, style=Style.NORMAL):
1802 imm = False
1803 imm_name = ""
1804 imm_value = ""
1805 for operand in self.dynamic_operands(record=record):
1806 name = operand.name
1807 value = " ".join(operand.disassemble(insn=self,
1808 style=min(style, Style.NORMAL)))
1809 if imm:
1810 name = f"{imm_name}({name})"
1811 value = f"{imm_value}({value})"
1812 imm = False
1813 if isinstance(operand, ImmediateOperand):
1814 imm_name = name
1815 imm_value = value
1816 imm = True
1817 if not imm:
1818 yield (name, value)
1819
1820 @classmethod
1821 def assemble(cls, record, arguments=None):
1822 if arguments is None:
1823 arguments = ()
1824
1825 insn = cls.integer(value=0)
1826
1827 for operand in cls.static_operands(record=record):
1828 operand.assemble(insn=insn)
1829
1830 arguments = Arguments(record=record,
1831 arguments=arguments, operands=cls.dynamic_operands(record=record))
1832 for (value, operand) in arguments:
1833 operand.assemble(insn=insn, value=value)
1834
1835 return insn
1836
1837 def disassemble(self, record,
1838 byteorder="little",
1839 style=Style.NORMAL):
1840 raise NotImplementedError()
1841
1842
1843 class WordInstruction(Instruction):
1844 _: _Field = range(0, 32)
1845 PO: _Field = range(0, 6)
1846
1847 @classmethod
1848 def integer(cls, value, byteorder="little"):
1849 return super().integer(bits=32, value=value, byteorder=byteorder)
1850
1851 @property
1852 def binary(self):
1853 bits = []
1854 for idx in range(32):
1855 bit = int(self[idx])
1856 bits.append(bit)
1857 return "".join(map(str, bits))
1858
1859 def disassemble(self, record,
1860 byteorder="little",
1861 style=Style.NORMAL):
1862 if style <= Style.SHORT:
1863 blob = ""
1864 else:
1865 blob = self.bytes(byteorder=byteorder)
1866 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
1867 blob += " "
1868
1869 if record is None:
1870 yield f"{blob}.long 0x{int(self):08x}"
1871 return
1872
1873 # awful temporary hack: workaround for ld-update
1874 # https://bugs.libre-soc.org/show_bug.cgi?id=1056#c2
1875 # XXX TODO must check that *EXTENDED* RA != extended-RT
1876 if (record.svp64 is not None and
1877 record.mode == _SVMode.LDST_IMM and
1878 'u' in record.name):
1879 yield f"{blob}.long 0x{int(self):08x}"
1880 return
1881
1882 paired = False
1883 if style is Style.LEGACY:
1884 paired = False
1885 for operand in self.dynamic_operands(record=record):
1886 if isinstance(operand, (GPRPairOperand, FPRPairOperand)):
1887 paired = True
1888
1889 if style is Style.LEGACY and (paired or record.ppc.unofficial):
1890 yield f"{blob}.long 0x{int(self):08x}"
1891 else:
1892 operands = tuple(map(_operator.itemgetter(1),
1893 self.spec_dynamic_operands(record=record, style=style)))
1894 if operands:
1895 operands = ",".join(operands)
1896 yield f"{blob}{record.name} {operands}"
1897 else:
1898 yield f"{blob}{record.name}"
1899
1900 if style >= Style.VERBOSE:
1901 indent = (" " * 4)
1902 binary = self.binary
1903 spec = self.spec(record=record, prefix="")
1904 yield f"{indent}spec"
1905 yield f"{indent}{indent}{spec}"
1906 yield f"{indent}pcode"
1907 for stmt in record.mdwn.pcode:
1908 yield f"{indent}{indent}{stmt}"
1909 yield f"{indent}binary"
1910 yield f"{indent}{indent}[0:8] {binary[0:8]}"
1911 yield f"{indent}{indent}[8:16] {binary[8:16]}"
1912 yield f"{indent}{indent}[16:24] {binary[16:24]}"
1913 yield f"{indent}{indent}[24:32] {binary[24:32]}"
1914 yield f"{indent}opcodes"
1915 for opcode in record.opcodes:
1916 yield f"{indent}{indent}{opcode!r}"
1917 for operand in self.operands(record=record):
1918 yield from operand.disassemble(insn=self,
1919 style=style, indent=indent)
1920 yield ""
1921
1922
1923 class PrefixedInstruction(Instruction):
1924 class Prefix(WordInstruction.remap(range(0, 32))):
1925 pass
1926
1927 class Suffix(WordInstruction.remap(range(32, 64))):
1928 pass
1929
1930 _: _Field = range(64)
1931 prefix: Prefix
1932 suffix: Suffix
1933 PO: Suffix.PO
1934
1935 @classmethod
1936 def integer(cls, value, byteorder="little"):
1937 return super().integer(bits=64, value=value, byteorder=byteorder)
1938
1939 @classmethod
1940 def pair(cls, prefix=0, suffix=0, byteorder="little"):
1941 def transform(value):
1942 return WordInstruction.integer(value=value,
1943 byteorder=byteorder)[0:32]
1944
1945 (prefix, suffix) = map(transform, (prefix, suffix))
1946 value = _selectconcat(prefix, suffix)
1947
1948 return super().integer(bits=64, value=value)
1949
1950
1951 class Mode(_Mapping):
1952 _: _Field = range(0, 5)
1953 sel: _Field = (0, 1)
1954
1955
1956 class ExtraRM(_Mapping):
1957 _: _Field = range(0, 9)
1958
1959
1960 class Extra2RM(ExtraRM):
1961 idx0: _Field = range(0, 2)
1962 idx1: _Field = range(2, 4)
1963 idx2: _Field = range(4, 6)
1964 idx3: _Field = range(6, 8)
1965
1966 def __getitem__(self, key):
1967 return {
1968 0: self.idx0,
1969 1: self.idx1,
1970 2: self.idx2,
1971 3: self.idx3,
1972 _SVExtra.Idx0: self.idx0,
1973 _SVExtra.Idx1: self.idx1,
1974 _SVExtra.Idx2: self.idx2,
1975 _SVExtra.Idx3: self.idx3,
1976 }[key]
1977
1978 def __setitem__(self, key, value):
1979 self[key].assign(value)
1980
1981
1982 class Extra3RM(ExtraRM):
1983 idx0: _Field = range(0, 3)
1984 idx1: _Field = range(3, 6)
1985 idx2: _Field = range(6, 9)
1986
1987 def __getitem__(self, key):
1988 return {
1989 0: self.idx0,
1990 1: self.idx1,
1991 2: self.idx2,
1992 _SVExtra.Idx0: self.idx0,
1993 _SVExtra.Idx1: self.idx1,
1994 _SVExtra.Idx2: self.idx2,
1995 }[key]
1996
1997 def __setitem__(self, key, value):
1998 self[key].assign(value)
1999
2000
2001 class BaseRM(_Mapping):
2002 _: _Field = range(24)
2003 mmode: _Field = (0,)
2004 mask: _Field = range(1, 4)
2005 elwidth: _Field = range(4, 6)
2006 ewsrc: _Field = range(6, 8)
2007 subvl: _Field = range(8, 10)
2008 mode: Mode.remap(range(19, 24))
2009 smask_extra322: _Field = (6,7,18,) # LDST_IDX is EXTRA332
2010 smask: _Field = range(16, 19) # everything else use this
2011 extra: ExtraRM.remap(range(10, 19))
2012 extra2: Extra2RM.remap(range(10, 19))
2013 extra3: Extra3RM.remap(range(10, 19))
2014 # XXX extra332 = (extra3[0], extra3[1], extra2[3])
2015
2016 def specifiers(self, record):
2017 subvl = int(self.subvl)
2018 if subvl > 0:
2019 yield {
2020 1: "vec2",
2021 2: "vec3",
2022 3: "vec4",
2023 }[subvl]
2024
2025 def disassemble(self, style=Style.NORMAL):
2026 if style >= Style.VERBOSE:
2027 indent = (" " * 4)
2028 for (name, span) in self.traverse(path="RM"):
2029 value = self.storage[span]
2030 yield f"{name}"
2031 yield f"{indent}{int(value):0{value.bits}b}"
2032 yield f"{indent}{', '.join(map(str, span))}"
2033
2034
2035 class FFRc1BaseRM(BaseRM):
2036 def specifiers(self, record, mode):
2037 inv = _SelectableInt(value=int(self.inv), bits=1)
2038 CR = _SelectableInt(value=int(self.CR), bits=2)
2039 mask = int(_selectconcat(CR, inv))
2040 predicate = PredicateBaseRM.predicate(True, mask)
2041 yield f"{mode}={predicate}"
2042
2043 yield from super().specifiers(record=record)
2044
2045
2046 class FFRc0BaseRM(BaseRM):
2047 def specifiers(self, record, mode):
2048 if self.RC1:
2049 inv = "~" if self.inv else ""
2050 yield f"{mode}={inv}RC1"
2051
2052 yield from super().specifiers(record=record)
2053
2054
2055 class SatBaseRM(BaseRM):
2056 def specifiers(self, record):
2057 if self.N:
2058 yield "sats"
2059 else:
2060 yield "satu"
2061
2062 yield from super().specifiers(record=record)
2063
2064
2065 class ZZBaseRM(BaseRM):
2066 def specifiers(self, record):
2067 if self.zz:
2068 yield "zz"
2069
2070 yield from super().specifiers(record=record)
2071
2072
2073 class ZZCombinedBaseRM(BaseRM):
2074 def specifiers(self, record):
2075 if self.sz and self.dz:
2076 yield "zz"
2077 elif self.sz:
2078 yield "sz"
2079 elif self.dz:
2080 yield "dz"
2081
2082 yield from super().specifiers(record=record)
2083
2084
2085 class DZBaseRM(BaseRM):
2086 def specifiers(self, record):
2087 if self.dz:
2088 yield "dz"
2089
2090 yield from super().specifiers(record=record)
2091
2092
2093 class SZBaseRM(BaseRM):
2094 def specifiers(self, record):
2095 if self.sz:
2096 yield "sz"
2097
2098 yield from super().specifiers(record=record)
2099
2100
2101 class MRBaseRM(BaseRM):
2102 def specifiers(self, record):
2103 if self.RG:
2104 yield "mrr"
2105 else:
2106 yield "mr"
2107
2108 yield from super().specifiers(record=record)
2109
2110
2111 class ElsBaseRM(BaseRM):
2112 def specifiers(self, record):
2113 if self.els:
2114 yield "els"
2115
2116 yield from super().specifiers(record=record)
2117
2118
2119 class WidthBaseRM(BaseRM):
2120 @staticmethod
2121 def width(FP, width):
2122 width = {
2123 0b11: "8",
2124 0b10: "16",
2125 0b01: "32",
2126 }.get(width)
2127 if width is None:
2128 return None
2129 if FP:
2130 width = ("fp" + width)
2131 return width
2132
2133 def specifiers(self, record):
2134 # elwidths: use "w=" if same otherwise dw/sw
2135 # FIXME this should consider FP instructions
2136 FP = False
2137 dw = WidthBaseRM.width(FP, int(self.elwidth))
2138 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2139 if record.svp64.mode is _SVMode.CROP:
2140 if dw:
2141 yield ("dw=" + dw)
2142 else:
2143 sw = WidthBaseRM.width(FP, int(self.ewsrc))
2144 if dw == sw and dw:
2145 yield ("w=" + dw)
2146 else:
2147 if dw:
2148 yield ("dw=" + dw)
2149 if sw:
2150 yield ("sw=" + sw)
2151
2152 yield from super().specifiers(record=record)
2153
2154
2155 class PredicateBaseRM(BaseRM):
2156 @staticmethod
2157 def predicate(CR, mask):
2158 return {
2159 # integer
2160 (False, 0b001): "1<<r3",
2161 (False, 0b010): "r3",
2162 (False, 0b011): "~r3",
2163 (False, 0b100): "r10",
2164 (False, 0b101): "~r10",
2165 (False, 0b110): "r30",
2166 (False, 0b111): "~r30",
2167 # CRs
2168 (True, 0b000): "lt",
2169 (True, 0b001): "ge",
2170 (True, 0b010): "gt",
2171 (True, 0b011): "le",
2172 (True, 0b100): "eq",
2173 (True, 0b101): "ne",
2174 (True, 0b110): "so",
2175 (True, 0b111): "ns",
2176 }.get((CR, mask))
2177
2178 def specifiers(self, record):
2179 # predication - single and twin
2180 # use "m=" if same otherwise sm/dm
2181 CR = (int(self.mmode) == 1)
2182 mask = int(self.mask)
2183 sm = dm = PredicateBaseRM.predicate(CR, mask)
2184 if record.svp64.ptype is _SVPType.P2:
2185 # LDST_IDX smask moving to extra322 but not straight away (False)
2186 if False and record.svp64.mode is _SVMode.LDST_IDX:
2187 smask = int(self.smask_extra332)
2188 else:
2189 smask = int(self.smask)
2190 sm = PredicateBaseRM.predicate(CR, smask)
2191 if sm == dm and dm:
2192 yield ("m=" + dm)
2193 else:
2194 if sm:
2195 yield ("sm=" + sm)
2196 if dm:
2197 yield ("dm=" + dm)
2198
2199 yield from super().specifiers(record=record)
2200
2201
2202 class PredicateWidthBaseRM(WidthBaseRM, PredicateBaseRM):
2203 pass
2204
2205
2206 class SEABaseRM(BaseRM):
2207 def specifiers(self, record):
2208 if self.SEA:
2209 yield "sea"
2210
2211 yield from super().specifiers(record=record)
2212
2213
2214 class VLiBaseRM(BaseRM):
2215 def specifiers(self, record):
2216 if self.VLi:
2217 yield "vli"
2218
2219 yield from super().specifiers(record=record)
2220
2221
2222 class NormalBaseRM(PredicateWidthBaseRM):
2223 """
2224 Normal mode
2225 https://libre-soc.org/openpower/sv/normal/
2226 """
2227 pass
2228
2229
2230 class NormalSimpleRM(ZZCombinedBaseRM, NormalBaseRM):
2231 """normal: simple mode"""
2232 dz: BaseRM.mode[3]
2233 sz: BaseRM.mode[4]
2234
2235 def specifiers(self, record):
2236 yield from super().specifiers(record=record)
2237
2238
2239 class NormalMRRM(MRBaseRM, NormalBaseRM):
2240 """normal: scalar reduce mode (mapreduce), SUBVL=1"""
2241 RG: BaseRM.mode[4]
2242
2243
2244 class NormalFFRc1RM(FFRc1BaseRM, VLiBaseRM, NormalBaseRM):
2245 """normal: Rc=1: ffirst CR sel"""
2246 VLi: BaseRM.mode[0]
2247 inv: BaseRM.mode[2]
2248 CR: BaseRM.mode[3, 4]
2249
2250 def specifiers(self, record):
2251 yield from super().specifiers(record=record, mode="ff")
2252
2253
2254 class NormalFFRc0RM(FFRc0BaseRM, VLiBaseRM, NormalBaseRM):
2255 """normal: Rc=0: ffirst z/nonz"""
2256 VLi: BaseRM.mode[0]
2257 inv: BaseRM.mode[2]
2258 RC1: BaseRM.mode[4]
2259
2260 def specifiers(self, record):
2261 yield from super().specifiers(record=record, mode="ff")
2262
2263
2264 class NormalSatRM(SatBaseRM, ZZCombinedBaseRM, NormalBaseRM):
2265 """normal: sat mode: N=0/1 u/s, SUBVL=1"""
2266 N: BaseRM.mode[2]
2267 dz: BaseRM.mode[3]
2268 sz: BaseRM.mode[4]
2269
2270
2271 class NormalRM(NormalBaseRM):
2272 simple: NormalSimpleRM
2273 mr: NormalMRRM
2274 ffrc1: NormalFFRc1RM
2275 ffrc0: NormalFFRc0RM
2276 sat: NormalSatRM
2277
2278
2279 class LDSTImmBaseRM(PredicateWidthBaseRM):
2280 """
2281 LD/ST Immediate mode
2282 https://libre-soc.org/openpower/sv/ldst/
2283 """
2284 pass
2285
2286
2287 class LDSTImmSimpleRM(ElsBaseRM, ZZBaseRM, LDSTImmBaseRM):
2288 """ld/st immediate: simple mode"""
2289 pi: BaseRM.mode[2] # Post-Increment Mode
2290 lf: BaseRM.mode[4] # Fault-First Mode (not *Data-Dependent* Fail-First)
2291 zz: BaseRM.mode[3]
2292 els: BaseRM.mode[0]
2293 dz: BaseRM.mode[3]
2294 sz: BaseRM.mode[3]
2295
2296 def specifiers(self, record):
2297 if self.pi:
2298 yield "pi"
2299 if self.lf:
2300 yield "lf"
2301
2302 yield from super().specifiers(record=record)
2303
2304
2305 class LDSTFFRc1RM(FFRc1BaseRM, VLiBaseRM, LDSTImmBaseRM):
2306 """ld/st immediate&indexed: Rc=1: ffirst CR sel"""
2307 VLi: BaseRM.mode[0]
2308 inv: BaseRM.mode[2]
2309 CR: BaseRM.mode[3, 4]
2310
2311 def specifiers(self, record):
2312 yield from super().specifiers(record=record, mode="ff")
2313
2314
2315 class LDSTFFRc0RM(FFRc0BaseRM, VLiBaseRM, LDSTImmBaseRM):
2316 """ld/st immediate&indexed: Rc=0: ffirst z/nonz"""
2317 VLi: BaseRM.mode[0]
2318 inv: BaseRM.mode[2]
2319 RC1: BaseRM.mode[4]
2320
2321 def specifiers(self, record):
2322 yield from super().specifiers(record=record, mode="ff")
2323
2324
2325 class LDSTImmRM(LDSTImmBaseRM):
2326 simple: LDSTImmSimpleRM
2327 ffrc1: LDSTFFRc1RM
2328 ffrc0: LDSTFFRc0RM
2329
2330
2331 class LDSTIdxBaseRM(PredicateWidthBaseRM):
2332 """
2333 LD/ST Indexed mode
2334 https://libre-soc.org/openpower/sv/ldst/
2335 """
2336 pass
2337
2338
2339 class LDSTIdxSimpleRM(SEABaseRM, ZZBaseRM, LDSTIdxBaseRM):
2340 """ld/st index: simple mode (includes element-strided and Signed-EA)"""
2341 pi: BaseRM.mode[2] # Post-Increment Mode
2342 els: BaseRM.mode[0]
2343 SEA: BaseRM.mode[4]
2344 zz: BaseRM.mode[3]
2345 dz: BaseRM.mode[3]
2346 sz: BaseRM.mode[3]
2347
2348 def specifiers(self, record):
2349 if self.els:
2350 yield "els"
2351 if self.pi:
2352 yield "pi"
2353
2354 yield from super().specifiers(record=record)
2355
2356
2357 class LDSTIdxRM(LDSTIdxBaseRM):
2358 simple: LDSTIdxSimpleRM
2359 ffrc1: LDSTFFRc1RM
2360 ffrc0: LDSTFFRc0RM
2361
2362
2363
2364 class CROpBaseRM(BaseRM):
2365 """
2366 CR ops mode
2367 https://libre-soc.org/openpower/sv/cr_ops/
2368 """
2369 SNZ: BaseRM[7]
2370
2371
2372 class CROpSimpleRM(PredicateBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2373 """crop: simple mode"""
2374 RG: BaseRM[21]
2375 dz: BaseRM[22]
2376 sz: BaseRM[23]
2377
2378 def specifiers(self, record):
2379 if self.RG:
2380 yield "rg" # simple CR Mode reports /rg
2381
2382 yield from super().specifiers(record=record)
2383
2384
2385 class CROpMRRM(MRBaseRM, ZZCombinedBaseRM, CROpBaseRM):
2386 """crop: scalar reduce mode (mapreduce)"""
2387 RG: BaseRM[21]
2388 dz: BaseRM[22]
2389 sz: BaseRM[23]
2390
2391
2392 class CROpFF5RM(FFRc0BaseRM, PredicateBaseRM, VLiBaseRM, DZBaseRM,
2393 SZBaseRM, CROpBaseRM):
2394 """crop: ffirst 5-bit mode"""
2395 VLi: BaseRM[19]
2396 RC1 = 1
2397 inv: BaseRM[21]
2398 dz: BaseRM[22]
2399 sz: BaseRM[23]
2400
2401 def specifiers(self, record):
2402 yield from super().specifiers(record=record, mode="ff")
2403
2404
2405 # FIXME: almost everything in this class contradicts the specs (it doesn't)
2406 # The modes however are swapped: 5-bit is 3-bit, 3-bit is 5-bit
2407 class CROpFF3RM(FFRc1BaseRM, PredicateBaseRM, VLiBaseRM, ZZBaseRM, CROpBaseRM):
2408 """cr_op: ffirst 3-bit mode"""
2409 VLi: BaseRM[19]
2410 inv: BaseRM[21]
2411 CR: BaseRM[22, 23]
2412 zz: BaseRM[6]
2413
2414 def specifiers(self, record):
2415 yield from super().specifiers(record=record, mode="ff")
2416
2417
2418 class CROpRM(CROpBaseRM):
2419 simple: CROpSimpleRM
2420 mr: CROpMRRM
2421 ff3: CROpFF3RM
2422 ff5: CROpFF5RM
2423
2424
2425 # ********************
2426 # Branches mode
2427 # https://libre-soc.org/openpower/sv/branches/
2428 class BranchBaseRM(BaseRM):
2429 ALL: BaseRM[4]
2430 SNZ: BaseRM[5]
2431 SL: BaseRM[17]
2432 SLu: BaseRM[18]
2433 LRu: BaseRM[22]
2434 sz: BaseRM[23]
2435 CTR: BaseRM[19]
2436 VLS: BaseRM[20]
2437
2438 def specifiers(self, record):
2439 if self.ALL:
2440 yield "all"
2441
2442 # /sz
2443 # branch.sz=1
2444 # branch.snz=0
2445 # /snz
2446 # branch.sz=1
2447 # branch.snz=1
2448 if self.SNZ:
2449 if not self.sz:
2450 raise ValueError(self.sz)
2451 yield "snz"
2452 elif self.sz:
2453 yield "sz"
2454
2455 if self.SL:
2456 yield "sl"
2457 if self.SLu:
2458 yield "slu"
2459 if self.LRu:
2460 yield "lru"
2461
2462 # Branch modes lack source mask.
2463 # Therefore a custom code is needed.
2464 CR = (int(self.mmode) == 1)
2465 mask = int(self.mask)
2466 m = PredicateBaseRM.predicate(CR, mask)
2467 if m is not None:
2468 yield ("m=" + m)
2469
2470 yield from super().specifiers(record=record)
2471
2472
2473 class BranchSimpleRM(BranchBaseRM):
2474 """branch: simple mode"""
2475 pass
2476
2477
2478 class BranchVLSRM(BranchBaseRM):
2479 """branch: VLSET mode"""
2480 VSb: BaseRM[7]
2481 VLi: BaseRM[21]
2482
2483 def specifiers(self, record):
2484 yield {
2485 (0b0, 0b0): "vs",
2486 (0b0, 0b1): "vsi",
2487 (0b1, 0b0): "vsb",
2488 (0b1, 0b1): "vsbi",
2489 }[int(self.VSb), int(self.VLi)]
2490
2491 yield from super().specifiers(record=record)
2492
2493
2494 class BranchCTRRM(BranchBaseRM):
2495 """branch: CTR-test mode"""
2496 CTi: BaseRM[6]
2497
2498 def specifiers(self, record):
2499 if self.CTi:
2500 yield "cti"
2501 else:
2502 yield "ctr"
2503
2504 yield from super().specifiers(record=record)
2505
2506
2507 class BranchCTRVLSRM(BranchVLSRM, BranchCTRRM):
2508 """branch: CTR-test+VLSET mode"""
2509 pass
2510
2511
2512 class BranchRM(BranchBaseRM):
2513 simple: BranchSimpleRM
2514 vls: BranchVLSRM
2515 ctr: BranchCTRRM
2516 ctrvls: BranchCTRVLSRM
2517
2518
2519 class RM(BaseRM):
2520 normal: NormalRM
2521 ldst_imm: LDSTImmRM
2522 ldst_idx: LDSTIdxRM
2523 crop: CROpRM
2524 branch: BranchRM
2525
2526
2527 @_dataclasses.dataclass(eq=True, frozen=True)
2528 class Specifier:
2529 record: Record
2530
2531 @classmethod
2532 def match(cls, desc, record):
2533 raise NotImplementedError()
2534
2535 def validate(self, others):
2536 pass
2537
2538 def assemble(self, insn):
2539 raise NotImplementedError()
2540
2541
2542 @_dataclasses.dataclass(eq=True, frozen=True)
2543 class SpecifierWidth(Specifier):
2544 width: _SVP64Width
2545
2546 @classmethod
2547 def match(cls, desc, record, etalon):
2548 (mode, _, value) = desc.partition("=")
2549 mode = mode.strip()
2550 value = value.strip()
2551 if mode != etalon:
2552 return None
2553 width = _SVP64Width(value)
2554
2555 return cls(record=record, width=width)
2556
2557
2558 @_dataclasses.dataclass(eq=True, frozen=True)
2559 class SpecifierW(SpecifierWidth):
2560 @classmethod
2561 def match(cls, desc, record):
2562 return super().match(desc=desc, record=record, etalon="w")
2563
2564 def assemble(self, insn):
2565 selector = insn.select(record=self.record)
2566 if self.record.svp64.mode is not _SVMode.CROP:
2567 selector.ewsrc = self.width.value
2568 selector.elwidth = self.width.value
2569
2570
2571 @_dataclasses.dataclass(eq=True, frozen=True)
2572 class SpecifierSW(SpecifierWidth):
2573 @classmethod
2574 def match(cls, desc, record):
2575 if record.svp64.mode is _SVMode.CROP:
2576 return None
2577 return super().match(desc=desc, record=record, etalon="sw")
2578
2579 def assemble(self, insn):
2580 selector = insn.select(record=self.record)
2581 selector.ewsrc = self.width.value
2582
2583
2584 @_dataclasses.dataclass(eq=True, frozen=True)
2585 class SpecifierDW(SpecifierWidth):
2586 @classmethod
2587 def match(cls, desc, record):
2588 return super().match(desc=desc, record=record, etalon="dw")
2589
2590 def assemble(self, insn):
2591 selector = insn.select(record=self.record)
2592 selector.elwidth = self.width.value
2593
2594
2595 @_dataclasses.dataclass(eq=True, frozen=True)
2596 class SpecifierSubVL(Specifier):
2597 value: _SVP64SubVL
2598
2599 @classmethod
2600 def match(cls, desc, record):
2601 try:
2602 value = _SVP64SubVL(desc)
2603 except ValueError:
2604 return None
2605
2606 return cls(record=record, value=value)
2607
2608 def assemble(self, insn):
2609 selector = insn.select(record=self.record)
2610 selector.subvl = int(self.value.value)
2611
2612
2613 @_dataclasses.dataclass(eq=True, frozen=True)
2614 class SpecifierPredicate(Specifier):
2615 mode: str
2616 pred: _SVP64Pred
2617
2618 @classmethod
2619 def match(cls, desc, record, mode_match, pred_match):
2620 (mode, _, pred) = desc.partition("=")
2621
2622 mode = mode.strip()
2623 if not mode_match(mode):
2624 return None
2625
2626 pred = _SVP64Pred(pred.strip())
2627 if not pred_match(pred):
2628 raise ValueError(pred)
2629
2630 return cls(record=record, mode=mode, pred=pred)
2631
2632
2633 @_dataclasses.dataclass(eq=True, frozen=True)
2634 class SpecifierFF(SpecifierPredicate):
2635 @classmethod
2636 def match(cls, desc, record):
2637 return super().match(desc=desc, record=record,
2638 mode_match=lambda mode_arg: mode_arg == "ff",
2639 pred_match=lambda pred_arg: pred_arg.mode in (
2640 _SVP64PredMode.CR,
2641 _SVP64PredMode.RC1,
2642 ))
2643
2644 def assemble(self, insn):
2645 selector = insn.select(record=self.record)
2646 if selector.mode.sel != 0:
2647 raise ValueError("cannot override mode")
2648 if self.record.svp64.mode is _SVMode.CROP:
2649 selector.mode.sel = 0b01
2650 # HACK: please finally provide correct logic for CRs.
2651 if self.pred in (_SVP64Pred.RC1, _SVP64Pred.RC1_N):
2652 selector.mode[2] = (self.pred is _SVP64Pred.RC1_N)
2653 else:
2654 selector.mode[2] = self.pred.inv
2655 selector.mode[3, 4] = self.pred.state
2656 else:
2657 selector.mode.sel = 0b01 if self.mode == "ff" else 0b11
2658 selector.inv = self.pred.inv
2659 if self.record.Rc:
2660 selector.CR = self.pred.state
2661 else:
2662 selector.RC1 = self.pred.state
2663
2664
2665 @_dataclasses.dataclass(eq=True, frozen=True)
2666 class SpecifierMask(SpecifierPredicate):
2667 @classmethod
2668 def match(cls, desc, record, mode):
2669 return super().match(desc=desc, record=record,
2670 mode_match=lambda mode_arg: mode_arg == mode,
2671 pred_match=lambda pred_arg: pred_arg.mode in (
2672 _SVP64PredMode.INT,
2673 _SVP64PredMode.CR,
2674 ))
2675
2676 def assemble(self, insn):
2677 raise NotImplementedError()
2678
2679
2680 @_dataclasses.dataclass(eq=True, frozen=True)
2681 class SpecifierM(SpecifierMask):
2682 @classmethod
2683 def match(cls, desc, record):
2684 return super().match(desc=desc, record=record, mode="m")
2685
2686 def validate(self, others):
2687 for spec in others:
2688 if isinstance(spec, SpecifierSM):
2689 raise ValueError("source-mask and predicate mask conflict")
2690 elif isinstance(spec, SpecifierDM):
2691 raise ValueError("dest-mask and predicate mask conflict")
2692
2693 def assemble(self, insn):
2694 selector = insn.select(record=self.record)
2695 selector.mask = int(self.pred)
2696 if ((self.record.ptype is _SVPType.P2) and
2697 (self.record.svp64.mode is not _SVMode.BRANCH)):
2698 selector.smask = int(self.pred)
2699 # LDST_IDX smask moving to extra322 but not straight away (False)
2700 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2701 selector.smask_extra332 = int(self.pred)
2702 else:
2703 selector.smask = int(self.pred)
2704
2705 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2706
2707
2708 @_dataclasses.dataclass(eq=True, frozen=True)
2709 class SpecifierSM(SpecifierMask):
2710 @classmethod
2711 def match(cls, desc, record):
2712 return super().match(desc=desc, record=record, mode="sm")
2713
2714 def validate(self, others):
2715 if self.record.svp64.ptype is _SVPType.P1:
2716 raise ValueError("source-mask on non-twin predicate")
2717
2718 if self.pred.mode is _SVP64PredMode.CR:
2719 twin = None
2720 for spec in others:
2721 if isinstance(spec, SpecifierDM):
2722 twin = spec
2723
2724 if twin is None:
2725 raise ValueError("missing dest-mask in CR twin predication")
2726 if self.pred.mode != twin.pred.mode:
2727 raise ValueError(f"predicate masks mismatch: "
2728 f"{self.pred!r} vs {twin.pred!r}")
2729
2730 def assemble(self, insn):
2731 selector = insn.select(record=self.record)
2732 # LDST_IDX smask moving to extra322 but not straight away (False)
2733 if False and self.record.svp64.mode is _SVMode.LDST_IDX:
2734 selector.smask_extra332 = int(self.pred)
2735 else:
2736 selector.smask = int(self.pred)
2737 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2738
2739
2740 @_dataclasses.dataclass(eq=True, frozen=True)
2741 class SpecifierDM(SpecifierMask):
2742 @classmethod
2743 def match(cls, desc, record):
2744 return super().match(desc=desc, record=record, mode="dm")
2745
2746 def validate(self, others):
2747 if self.record.svp64.ptype is _SVPType.P1:
2748 raise ValueError("dest-mask on non-twin predicate")
2749
2750 if self.pred.mode is _SVP64PredMode.CR:
2751 twin = None
2752 for spec in others:
2753 if isinstance(spec, SpecifierSM):
2754 twin = spec
2755
2756 if twin is None:
2757 raise ValueError("missing source-mask in CR twin predication")
2758 if self.pred.mode != twin.pred.mode:
2759 raise ValueError(f"predicate masks mismatch: "
2760 f"{self.pred!r} vs {twin.pred!r}")
2761
2762 def assemble(self, insn):
2763 selector = insn.select(record=self.record)
2764 selector.mask = int(self.pred)
2765 selector.mmode = (self.pred.mode is _SVP64PredMode.CR)
2766
2767
2768 @_dataclasses.dataclass(eq=True, frozen=True)
2769 class SpecifierZZ(Specifier):
2770 @classmethod
2771 def match(cls, desc, record):
2772 if desc != "zz":
2773 return None
2774
2775 return cls(record=record)
2776
2777 def validate(self, others):
2778 for spec in others:
2779 # Since zz takes precedence (overrides) sz and dz,
2780 # treat them as mutually exclusive.
2781 if isinstance(spec, (SpecifierSZ, SpecifierDZ)):
2782 raise ValueError("mutually exclusive predicate masks")
2783
2784 def assemble(self, insn):
2785 selector = insn.select(record=self.record)
2786 if hasattr(selector, "zz"): # this should be done in a different way
2787 selector.zz = 1
2788 else:
2789 selector.sz = 1
2790 selector.dz = 1
2791
2792
2793 @_dataclasses.dataclass(eq=True, frozen=True)
2794 class SpecifierXZ(Specifier):
2795 desc: str
2796 hint: str = _dataclasses.field(repr=False)
2797
2798 @classmethod
2799 def match(cls, desc, record, etalon, hint):
2800 if desc != etalon:
2801 return None
2802
2803 return cls(desc=desc, record=record, hint=hint)
2804
2805 def validate(self, others):
2806 if self.record.svp64.ptype is _SVPType.P1:
2807 raise ValueError(f"{self.hint} on non-twin predicate")
2808
2809 if self.pred.mode is _SVP64PredMode.CR:
2810 twin = None
2811 for spec in others:
2812 if isinstance(spec, SpecifierXZ):
2813 twin = spec
2814
2815 if twin is None:
2816 raise ValueError(f"missing {self.hint} in CR twin predication")
2817 if self.pred != twin.pred:
2818 raise ValueError(f"predicate masks mismatch: "
2819 f"{self.pred!r} vs {twin.pred!r}")
2820
2821 def assemble(self, insn):
2822 selector = insn.select(record=self.record)
2823 setattr(selector, self.desc, 1)
2824
2825
2826 @_dataclasses.dataclass(eq=True, frozen=True)
2827 class SpecifierSZ(SpecifierXZ):
2828 @classmethod
2829 def match(cls, desc, record):
2830 return super().match(desc=desc, record=record,
2831 etalon="sz", hint="source-mask")
2832
2833 def validate(self, others):
2834 for spec in others:
2835 if self.record.svp64.mode is not _SVMode.CROP:
2836 if isinstance(spec, SpecifierFF):
2837 raise ValueError("source-zero not allowed in ff mode")
2838
2839
2840 @_dataclasses.dataclass(eq=True, frozen=True)
2841 class SpecifierDZ(SpecifierXZ):
2842 @classmethod
2843 def match(cls, desc, record):
2844 return super().match(desc=desc, record=record,
2845 etalon="dz", hint="dest-mask")
2846
2847 def validate(self, others):
2848 for spec in others:
2849 if ((self.record.svp64.mode is not _SVMode.CROP) and
2850 isinstance(spec, SpecifierFF) and
2851 (spec.pred.mode is _SVP64PredMode.RC1)):
2852 raise ValueError(f"dest-zero not allowed in ff mode BO")
2853
2854
2855 @_dataclasses.dataclass(eq=True, frozen=True)
2856 class SpecifierEls(Specifier):
2857 @classmethod
2858 def match(cls, desc, record):
2859 if desc != "els":
2860 return None
2861
2862 if record.svp64.mode not in (_SVMode.LDST_IMM, _SVMode.LDST_IDX):
2863 raise ValueError("els is only valid in ld/st modes, not "
2864 "%s" % str(self.record.svp64.mode))
2865
2866 return cls(record=record)
2867
2868 def assemble(self, insn):
2869 if self.record.svp64.mode is _SVMode.LDST_IDX: # stride mode
2870 insn.prefix.rm.mode[1] = 0
2871
2872 selector = insn.select(record=self.record)
2873 selector.els = 1
2874
2875
2876
2877 @_dataclasses.dataclass(eq=True, frozen=True)
2878 class SpecifierSEA(Specifier):
2879 @classmethod
2880 def match(cls, desc, record):
2881 if desc != "sea":
2882 return None
2883
2884 return cls(record=record)
2885
2886 def validate(self, others):
2887 if self.record.svp64.mode is not _SVMode.LDST_IDX:
2888 raise ValueError("sea is only valid in ld/st modes, not "
2889 "%s" % str(self.record.svp64.mode))
2890
2891 for spec in others:
2892 if isinstance(spec, SpecifierFF):
2893 raise ValueError(f"sea cannot be used in ff mode")
2894
2895 def assemble(self, insn):
2896 selector = insn.select(record=self.record)
2897 if selector.mode.sel not in (0b10, 0b00):
2898 raise ValueError("sea is only valid for normal and els modes, "
2899 "not %d" % int(selector.mode.sel))
2900 selector.SEA = 1
2901
2902
2903 @_dataclasses.dataclass(eq=True, frozen=True)
2904 class SpecifierSat(Specifier):
2905 desc: str
2906 sign: bool
2907
2908 @classmethod
2909 def match(cls, desc, record, etalon, sign):
2910 if desc != etalon:
2911 return None
2912
2913 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.LDST_IMM,
2914 _SVMode.LDST_IDX):
2915 raise ValueError("only normal, ld/st imm and "
2916 "ld/st idx modes supported")
2917
2918 return cls(record=record, desc=desc, sign=sign)
2919
2920 def assemble(self, insn):
2921 selector = insn.select(record=self.record)
2922 selector.mode[0] = 0b1
2923 selector.mode[1] = 0b0
2924 selector.N = int(self.sign)
2925
2926
2927 @_dataclasses.dataclass(eq=True, frozen=True)
2928 class SpecifierSatS(SpecifierSat):
2929 @classmethod
2930 def match(cls, desc, record):
2931 return super().match(desc=desc, record=record,
2932 etalon="sats", sign=True)
2933
2934
2935 @_dataclasses.dataclass(eq=True, frozen=True)
2936 class SpecifierSatU(SpecifierSat):
2937 @classmethod
2938 def match(cls, desc, record):
2939 return super().match(desc=desc, record=record,
2940 etalon="satu", sign=False)
2941
2942
2943 @_dataclasses.dataclass(eq=True, frozen=True)
2944 class SpecifierMapReduce(Specifier):
2945 RG: bool
2946
2947 @classmethod
2948 def match(cls, record, RG):
2949 if record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2950 raise ValueError("only normal and crop modes supported")
2951
2952 return cls(record=record, RG=RG)
2953
2954 def assemble(self, insn):
2955 selector = insn.select(record=self.record)
2956 if self.record.svp64.mode not in (_SVMode.NORMAL, _SVMode.CROP):
2957 raise ValueError("only normal and crop modes supported")
2958 selector.mode[0] = 0
2959 selector.mode[1] = 0
2960 selector.mode[2] = 1
2961 selector.RG = self.RG
2962
2963
2964 @_dataclasses.dataclass(eq=True, frozen=True)
2965 class SpecifierMR(SpecifierMapReduce):
2966 @classmethod
2967 def match(cls, desc, record):
2968 if desc != "mr":
2969 return None
2970
2971 return super().match(record=record, RG=False)
2972
2973
2974 @_dataclasses.dataclass(eq=True, frozen=True)
2975 class SpecifierMRR(SpecifierMapReduce):
2976 @classmethod
2977 def match(cls, desc, record):
2978 if desc != "mrr":
2979 return None
2980
2981 return super().match(record=record, RG=True)
2982
2983
2984 @_dataclasses.dataclass(eq=True, frozen=True)
2985 class SpecifierBranch(Specifier):
2986 @classmethod
2987 def match(cls, desc, record, etalon):
2988 if desc != etalon:
2989 return None
2990
2991 if record.svp64.mode is not _SVMode.BRANCH:
2992 raise ValueError("only branch modes supported")
2993
2994 return cls(record=record)
2995
2996
2997 @_dataclasses.dataclass(eq=True, frozen=True)
2998 class SpecifierAll(SpecifierBranch):
2999 @classmethod
3000 def match(cls, desc, record):
3001 return super().match(desc=desc, record=record, etalon="all")
3002
3003 def assemble(self, insn):
3004 selector = insn.select(record=self.record)
3005 selector.ALL = 1
3006
3007
3008 @_dataclasses.dataclass(eq=True, frozen=True)
3009 class SpecifierSNZ(Specifier):
3010 @classmethod
3011 def match(cls, desc, record):
3012 if desc != "snz":
3013 return None
3014
3015 if record.svp64.mode not in (_SVMode.BRANCH, _SVMode.CROP):
3016 raise ValueError("only branch and crop modes supported")
3017
3018 return cls(record=record)
3019
3020 def assemble(self, insn):
3021 selector = insn.select(record=self.record)
3022 if self.record.svp64.mode in (_SVMode.CROP, _SVMode.BRANCH):
3023 selector.SNZ = 1
3024 if self.record.svp64.mode is _SVMode.BRANCH:
3025 selector.sz = 1
3026 else:
3027 raise ValueError("only branch and crop modes supported")
3028
3029
3030 @_dataclasses.dataclass(eq=True, frozen=True)
3031 class SpecifierSL(SpecifierBranch):
3032 @classmethod
3033 def match(cls, desc, record):
3034 return super().match(desc=desc, record=record, etalon="sl")
3035
3036 def assemble(self, insn):
3037 selector = insn.select(record=self.record)
3038 selector.SL = 1
3039
3040
3041 @_dataclasses.dataclass(eq=True, frozen=True)
3042 class SpecifierSLu(SpecifierBranch):
3043 @classmethod
3044 def match(cls, desc, record):
3045 return super().match(desc=desc, record=record, etalon="slu")
3046
3047 def assemble(self, insn):
3048 selector = insn.select(record=self.record)
3049 selector.SLu = 1
3050
3051
3052 @_dataclasses.dataclass(eq=True, frozen=True)
3053 class SpecifierLRu(SpecifierBranch):
3054 @classmethod
3055 def match(cls, desc, record):
3056 return super().match(desc=desc, record=record, etalon="lru")
3057
3058 def assemble(self, insn):
3059 selector = insn.select(record=self.record)
3060 selector.LRu = 1
3061
3062
3063 @_dataclasses.dataclass(eq=True, frozen=True)
3064 class SpecifierVSXX(SpecifierBranch):
3065 VSb: bool
3066 VLi: bool
3067
3068 @classmethod
3069 def match(cls, desc, record, etalon, VSb, VLi):
3070 if desc != etalon:
3071 return None
3072
3073 if record.svp64.mode is not _SVMode.BRANCH:
3074 raise ValueError("only branch modes supported")
3075
3076 return cls(record=record, VSb=VSb, VLi=VLi)
3077
3078 def assemble(self, insn):
3079 selector = insn.select(record=self.record)
3080 selector.VLS = 1
3081 selector.VSb = int(self.VSb)
3082 selector.VLi = int(self.VLi)
3083
3084
3085 @_dataclasses.dataclass(eq=True, frozen=True)
3086 class SpecifierVS(SpecifierVSXX):
3087 @classmethod
3088 def match(cls, desc, record):
3089 return super().match(desc=desc, record=record,
3090 etalon="vs", VSb=False, VLi=False)
3091
3092
3093 @_dataclasses.dataclass(eq=True, frozen=True)
3094 class SpecifierVSi(SpecifierVSXX):
3095 @classmethod
3096 def match(cls, desc, record):
3097 return super().match(desc=desc, record=record,
3098 etalon="vsi", VSb=False, VLi=True)
3099
3100
3101 @_dataclasses.dataclass(eq=True, frozen=True)
3102 class SpecifierVSb(SpecifierVSXX):
3103 @classmethod
3104 def match(cls, desc, record):
3105 return super().match(desc=desc, record=record,
3106 etalon="vsb", VSb=True, VLi=False)
3107
3108
3109 @_dataclasses.dataclass(eq=True, frozen=True)
3110 class SpecifierVSbi(SpecifierVSXX):
3111 @classmethod
3112 def match(cls, desc, record):
3113 return super().match(desc=desc, record=record,
3114 etalon="vsbi", VSb=True, VLi=True)
3115
3116
3117 @_dataclasses.dataclass(eq=True, frozen=True)
3118 class SpecifierCTX(Specifier):
3119 CTi: bool
3120
3121 @classmethod
3122 def match(cls, desc, record, etalon, CTi):
3123 if desc != etalon:
3124 return None
3125
3126 if record.svp64.mode is not _SVMode.BRANCH:
3127 raise ValueError("only branch modes supported")
3128
3129 return cls(record=record, CTi=CTi)
3130
3131 def assemble(self, insn):
3132 selector = insn.select(record=self.record)
3133 selector.CTR = 1
3134 selector.CTi = int(self.CTi)
3135
3136
3137 @_dataclasses.dataclass(eq=True, frozen=True)
3138 class SpecifierCTR(SpecifierCTX):
3139 @classmethod
3140 def match(cls, desc, record):
3141 return super().match(desc=desc, record=record,
3142 etalon="ctr", CTi=False)
3143
3144
3145 @_dataclasses.dataclass(eq=True, frozen=True)
3146 class SpecifierCTi(SpecifierCTX):
3147 @classmethod
3148 def match(cls, desc, record):
3149 return super().match(desc=desc, record=record,
3150 etalon="cti", CTi=True)
3151
3152
3153 @_dataclasses.dataclass(eq=True, frozen=True)
3154 class SpecifierPI(Specifier):
3155 @classmethod
3156 def match(cls, desc, record):
3157 if desc != "pi":
3158 return None
3159
3160 if record.svp64.mode not in [_SVMode.LDST_IMM, _SVMode.LDST_IDX]:
3161 raise ValueError("only ld/st imm/idx mode supported")
3162
3163 return cls(record=record)
3164
3165 def assemble(self, insn):
3166 selector = insn.select(record=self.record)
3167 selector.mode[2] = 0b1
3168 selector.pi = 0b1
3169
3170
3171 @_dataclasses.dataclass(eq=True, frozen=True)
3172 class SpecifierLF(Specifier):
3173 @classmethod
3174 def match(cls, desc, record):
3175 if desc != "lf":
3176 return None
3177
3178 if record.svp64.mode is not _SVMode.LDST_IMM:
3179 raise ValueError("only ld/st imm mode supported")
3180
3181 return cls(record=record)
3182
3183 def assemble(self, insn):
3184 selector = insn.select(record=self.record)
3185 selector.mode[1] = 0
3186 selector.lf = 0b1
3187
3188
3189 @_dataclasses.dataclass(eq=True, frozen=True)
3190 class SpecifierVLi(Specifier):
3191 @classmethod
3192 def match(cls, desc, record):
3193 if desc != "vli":
3194 return None
3195
3196 return cls(record=record)
3197
3198 def validate(self, others):
3199 for spec in others:
3200 if isinstance(spec, SpecifierFF):
3201 return
3202
3203 raise ValueError("VLi only allowed in failfirst")
3204
3205 def assemble(self, insn):
3206 selector = insn.select(record=self.record)
3207 selector.mode[1] = 1
3208 selector.VLi = 1
3209
3210
3211 class Specifiers(tuple):
3212 SPECS = (
3213 SpecifierW,
3214 SpecifierSW,
3215 SpecifierDW,
3216 SpecifierSubVL,
3217 SpecifierFF,
3218 SpecifierM,
3219 SpecifierSM,
3220 SpecifierDM,
3221 SpecifierZZ,
3222 SpecifierSZ,
3223 SpecifierDZ,
3224 SpecifierEls,
3225 SpecifierSEA,
3226 SpecifierSatS,
3227 SpecifierSatU,
3228 SpecifierMR,
3229 SpecifierMRR,
3230 SpecifierAll,
3231 SpecifierSNZ,
3232 SpecifierSL,
3233 SpecifierSLu,
3234 SpecifierLRu,
3235 SpecifierVS,
3236 SpecifierVSi,
3237 SpecifierVSb,
3238 SpecifierVSbi,
3239 SpecifierVLi,
3240 SpecifierCTR,
3241 SpecifierCTi,
3242 SpecifierPI,
3243 SpecifierLF,
3244 )
3245
3246 def __new__(cls, items, record):
3247 def transform(item):
3248 for spec_cls in cls.SPECS:
3249 spec = spec_cls.match(item, record=record)
3250 if spec is not None:
3251 return spec
3252 raise ValueError(item)
3253
3254 # TODO: remove this hack
3255 items = dict.fromkeys(items)
3256 if "vli" in items:
3257 del items["vli"]
3258 items["vli"] = None
3259 items = tuple(items)
3260
3261 specs = tuple(map(transform, items))
3262 for (index, spec) in enumerate(specs):
3263 head = specs[:index]
3264 tail = specs[index + 1:]
3265 spec.validate(others=(head + tail))
3266
3267 return super().__new__(cls, specs)
3268
3269
3270 class SVP64OperandMeta(type):
3271 class SVP64NonZeroOperand(NonZeroOperand):
3272 def assemble(self, insn, value):
3273 if isinstance(value, str):
3274 value = int(value, 0)
3275 if not isinstance(value, int):
3276 raise ValueError("non-integer operand")
3277
3278 # FIXME: this is really weird
3279 if self.record.name in ("svstep", "svstep."):
3280 value += 1 # compensation
3281
3282 return super().assemble(value=value, insn=insn)
3283
3284 class SVP64XOStaticOperand(SpanStaticOperand):
3285 def __init__(self, record, value, span):
3286 return super().__init__(record=record, name="XO",
3287 value=value, span=span)
3288
3289 __TRANSFORM = {
3290 NonZeroOperand: SVP64NonZeroOperand,
3291 XOStaticOperand: SVP64XOStaticOperand,
3292 }
3293
3294 def __new__(metacls, name, bases, ns):
3295 bases = list(bases)
3296 for (index, base_cls) in enumerate(bases):
3297 bases[index] = metacls.__TRANSFORM.get(base_cls, base_cls)
3298
3299 bases = tuple(bases)
3300
3301 return super().__new__(metacls, name, bases, ns)
3302
3303
3304 class SVP64Operand(Operand, metaclass=SVP64OperandMeta):
3305 @property
3306 def span(self):
3307 return tuple(map(lambda bit: (bit + 32), super().span))
3308
3309
3310 class RMSelector:
3311 def __init__(self, insn, record):
3312 self.__insn = insn
3313 self.__record = record
3314 return super().__init__()
3315
3316 def __str__(self):
3317 return self.rm.__doc__
3318
3319 def __repr__(self):
3320 return repr(self.rm)
3321
3322 @property
3323 def insn(self):
3324 return self.__insn
3325
3326 @property
3327 def record(self):
3328 return self.__record
3329
3330 @property
3331 def rm(self):
3332 rm = getattr(self.insn.prefix.rm, self.record.svp64.mode.name.lower())
3333
3334 # The idea behind these tables is that they are now literally
3335 # in identical format to insndb.csv and minor_xx.csv and can
3336 # be done precisely as that. The only thing to watch out for
3337 # is the insertion of Rc=1 as a "mask/value" bit and likewise
3338 # regtype detection (3-bit BF/BFA, 5-bit BA/BB/BT) also inserted
3339 # as the LSB.
3340 table = None
3341 if self.record.svp64.mode is _SVMode.NORMAL:
3342 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3343 # mode Rc mask Rc member
3344 table = (
3345 (0b000000, 0b111000, "simple"), # simple (no Rc)
3346 (0b001000, 0b111100, "mr"), # mapreduce (no Rc)
3347 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3348 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3349 (0b100000, 0b110000, "sat"), # saturation (no Rc)
3350 (0b001100, 0b111100, "rsvd"), # reserved
3351 )
3352 mode = int(self.insn.prefix.rm.normal.mode)
3353 search = ((mode << 1) | self.record.Rc)
3354
3355 elif self.record.svp64.mode is _SVMode.LDST_IMM:
3356 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3357 # mode Rc mask Rc member
3358 # ironically/coincidentally this table is identical to NORMAL
3359 # mode except reserved in place of mr
3360 table = (
3361 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3362 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3363 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3364 )
3365 search = ((int(self.insn.prefix.rm.ldst_imm.mode) << 1) |
3366 self.record.Rc)
3367
3368 elif self.record.svp64.mode is _SVMode.LDST_IDX:
3369 # concatenate mode 5-bit with Rc (LSB) then do a mask/map search
3370 # mode Rc mask Rc member
3371 table = (
3372 (0b000000, 0b010000, "simple"), # simple (no Rc involved)
3373 (0b010001, 0b010001, "ffrc1"), # ffirst, Rc=1
3374 (0b010000, 0b010001, "ffrc0"), # ffirst, Rc=0
3375 )
3376 search = ((int(self.insn.prefix.rm.ldst_idx.mode) << 1) |
3377 self.record.Rc)
3378
3379 elif self.record.svp64.mode is _SVMode.CROP:
3380 # concatenate mode 5-bit with regtype (LSB) then do mask/map search
3381 # mode 3b mask 3b member
3382 table = (
3383 (0b000000, 0b111000, "simple"), # simple
3384 (0b001000, 0b111000, "mr"), # mapreduce
3385 (0b010001, 0b010001, "ff3"), # ffirst, 3-bit CR
3386 (0b010000, 0b010000, "ff5"), # ffirst, 5-bit CR
3387 )
3388 search = ((int(self.insn.prefix.rm.crop.mode) << 1) |
3389 int(self.record.svp64.extra_CR_3bit))
3390
3391 elif self.record.svp64.mode is _SVMode.BRANCH:
3392 # just mode 2-bit
3393 # mode mask member
3394 table = (
3395 (0b00, 0b11, "simple"), # simple
3396 (0b01, 0b11, "vls"), # VLset
3397 (0b10, 0b11, "ctr"), # CTR mode
3398 (0b11, 0b11, "ctrvls"), # CTR+VLset mode
3399 )
3400 # slightly weird: doesn't have a 5-bit "mode" field like others
3401 search = int(self.insn.prefix.rm.branch.mode.sel)
3402
3403 # look up in table
3404 if table is not None:
3405 for (value, mask, field) in table:
3406 if field.startswith("rsvd"):
3407 continue
3408 if ((value & mask) == (search & mask)):
3409 return getattr(rm, field)
3410
3411 return rm
3412
3413 def __getattr__(self, key):
3414 if key.startswith(f"_{self.__class__.__name__}__"):
3415 return super().__getattribute__(key)
3416
3417 return getattr(self.rm, key)
3418
3419 def __setattr__(self, key, value):
3420 if key.startswith(f"_{self.__class__.__name__}__"):
3421 return super().__setattr__(key, value)
3422
3423 rm = self.rm
3424 if not hasattr(rm, key):
3425 raise AttributeError(key)
3426
3427 return setattr(rm, key, value)
3428
3429
3430 class SVP64Instruction(PrefixedInstruction):
3431 """SVP64 instruction: https://libre-soc.org/openpower/sv/svp64/"""
3432 class Prefix(PrefixedInstruction.Prefix):
3433 id: _Field = (7, 9)
3434 rm: RM.remap((6, 8) + tuple(range(10, 32)))
3435
3436 prefix: Prefix
3437
3438 def select(self, record):
3439 return RMSelector(insn=self, record=record)
3440
3441 @property
3442 def binary(self):
3443 bits = []
3444 for idx in range(64):
3445 bit = int(self[idx])
3446 bits.append(bit)
3447 return "".join(map(str, bits))
3448
3449 @classmethod
3450 def assemble(cls, record, arguments=None, specifiers=None):
3451 insn = super().assemble(record=record, arguments=arguments)
3452
3453 specifiers = Specifiers(items=specifiers, record=record)
3454 for specifier in specifiers:
3455 specifier.assemble(insn=insn)
3456
3457 insn.prefix.PO = 0x1
3458 insn.prefix.id = 0x3
3459
3460 return insn
3461
3462 def disassemble(self, record,
3463 byteorder="little",
3464 style=Style.NORMAL):
3465 def blob(insn):
3466 if style <= Style.SHORT:
3467 return ""
3468 else:
3469 blob = insn.bytes(byteorder=byteorder)
3470 blob = " ".join(map(lambda byte: f"{byte:02x}", blob))
3471 return f"{blob} "
3472
3473 blob_prefix = blob(self.prefix)
3474 blob_suffix = blob(self.suffix)
3475 if record is None:
3476 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3477 yield f"{blob_suffix}.long 0x{int(self.suffix):08x}"
3478 return
3479
3480 assert record.svp64 is not None
3481
3482 name = f"sv.{record.name}"
3483
3484 rm = self.select(record=record)
3485
3486 # convert specifiers to /x/y/z (sorted lexicographically)
3487 specifiers = sorted(rm.specifiers(record=record))
3488 if specifiers: # if any add one extra to get the extra "/"
3489 specifiers = ([""] + specifiers)
3490 specifiers = "/".join(specifiers)
3491
3492 # convert operands to " ,x,y,z"
3493 operands = tuple(map(_operator.itemgetter(1),
3494 self.spec_dynamic_operands(record=record, style=style)))
3495 operands = ",".join(operands)
3496 if len(operands) > 0: # if any separate with a space
3497 operands = (" " + operands)
3498
3499 if style <= Style.LEGACY:
3500 yield f"{blob_prefix}.long 0x{int(self.prefix):08x}"
3501 suffix = WordInstruction.integer(value=int(self.suffix))
3502 yield from suffix.disassemble(record=record,
3503 byteorder=byteorder, style=style)
3504 else:
3505 yield f"{blob_prefix}{name}{specifiers}{operands}"
3506 if blob_suffix:
3507 yield f"{blob_suffix}"
3508
3509 if style >= Style.VERBOSE:
3510 indent = (" " * 4)
3511 binary = self.binary
3512 spec = self.spec(record=record, prefix="sv.")
3513
3514 yield f"{indent}spec"
3515 yield f"{indent}{indent}{spec}"
3516 yield f"{indent}pcode"
3517 for stmt in record.mdwn.pcode:
3518 yield f"{indent}{indent}{stmt}"
3519 yield f"{indent}binary"
3520 yield f"{indent}{indent}[0:8] {binary[0:8]}"
3521 yield f"{indent}{indent}[8:16] {binary[8:16]}"
3522 yield f"{indent}{indent}[16:24] {binary[16:24]}"
3523 yield f"{indent}{indent}[24:32] {binary[24:32]}"
3524 yield f"{indent}{indent}[32:40] {binary[32:40]}"
3525 yield f"{indent}{indent}[40:48] {binary[40:48]}"
3526 yield f"{indent}{indent}[48:56] {binary[48:56]}"
3527 yield f"{indent}{indent}[56:64] {binary[56:64]}"
3528 yield f"{indent}opcodes"
3529 for opcode in record.opcodes:
3530 yield f"{indent}{indent}{opcode!r}"
3531 for operand in self.operands(record=record):
3532 yield from operand.disassemble(insn=self,
3533 style=style, indent=indent)
3534 yield f"{indent}RM"
3535 yield f"{indent}{indent}{str(rm)}"
3536 for line in rm.disassemble(style=style):
3537 yield f"{indent}{indent}{line}"
3538 yield ""
3539
3540 @classmethod
3541 def operands(cls, record):
3542 for operand in super().operands(record=record):
3543 parent = operand.__class__
3544 name = f"SVP64{parent.__name__}"
3545 bases = (SVP64Operand, parent)
3546 child = type(name, bases, {})
3547 yield child(**dict(operand))
3548
3549
3550 def parse(stream, factory):
3551 def match(entry):
3552 return ("TODO" not in frozenset(entry.values()))
3553
3554 lines = filter(lambda line: not line.strip().startswith("#"), stream)
3555 entries = _csv.DictReader(lines)
3556 entries = filter(match, entries)
3557 return tuple(map(factory, entries))
3558
3559
3560 class MarkdownDatabase:
3561 def __init__(self):
3562 db = {}
3563 for (name, desc) in _ISA():
3564 operands = []
3565 if desc.regs:
3566 (dynamic, *static) = desc.regs
3567 operands.extend(dynamic)
3568 operands.extend(static)
3569 pcode = PCode(iterable=filter(str.strip, desc.pcode))
3570 operands = Operands(insn=name, operands=operands)
3571 db[name] = MarkdownRecord(pcode=pcode, operands=operands)
3572
3573 self.__db = dict(sorted(db.items()))
3574
3575 return super().__init__()
3576
3577 def __iter__(self):
3578 yield from self.__db.items()
3579
3580 def __contains__(self, key):
3581 return self.__db.__contains__(key)
3582
3583 def __getitem__(self, key):
3584 return self.__db.__getitem__(key)
3585
3586
3587 class FieldsDatabase:
3588 def __init__(self):
3589 db = {}
3590 df = _DecodeFields()
3591 df.create_specs()
3592 for (form, fields) in df.instrs.items():
3593 if form in {"DQE", "TX"}:
3594 continue
3595 if form == "all":
3596 form = "NONE"
3597 db[_Form[form]] = Fields(fields)
3598
3599 self.__db = db
3600
3601 return super().__init__()
3602
3603 def __getitem__(self, key):
3604 return self.__db.__getitem__(key)
3605
3606
3607 class PPCDatabase:
3608 def __init__(self, root, mdwndb):
3609 # The code below groups the instructions by name:section.
3610 # There can be multiple names for the same instruction.
3611 # The point is to capture different opcodes for the same instruction.
3612 sections = {}
3613 records = _collections.defaultdict(set)
3614 path = (root / "insndb.csv")
3615 with open(path, "r", encoding="UTF-8") as stream:
3616 for section in sorted(parse(stream, Section.CSV)):
3617 path = (root / section.path)
3618 opcode_cls = {
3619 section.Mode.INTEGER: IntegerOpcode,
3620 section.Mode.PATTERN: PatternOpcode,
3621 }[section.mode]
3622 factory = _functools.partial(
3623 PPCRecord.CSV, opcode_cls=opcode_cls)
3624 with open(path, "r", encoding="UTF-8") as stream:
3625 for insn in parse(stream, factory):
3626 for name in insn.names:
3627 records[name].add(insn)
3628 sections[name] = section
3629
3630 items = sorted(records.items())
3631 records = {}
3632 for (name, multirecord) in items:
3633 records[name] = PPCMultiRecord(sorted(multirecord))
3634
3635 def exact_match(name):
3636 record = records.get(name)
3637 if record is None:
3638 return None
3639 return name
3640
3641 def LK_match(name):
3642 if not name.endswith("l"):
3643 return None
3644 alias = exact_match(name[:-1])
3645 if alias is None:
3646 return None
3647 record = records[alias]
3648 if "lk" not in record.flags:
3649 raise ValueError(record)
3650 return alias
3651
3652 def AA_match(name):
3653 if not name.endswith("a"):
3654 return None
3655 alias = LK_match(name[:-1])
3656 if alias is None:
3657 alias = name[:-1]
3658 record = records[alias]
3659 if record.intop not in {_MicrOp.OP_B, _MicrOp.OP_BC}:
3660 raise ValueError(record)
3661 if "AA" not in mdwndb[name].operands:
3662 raise ValueError(record)
3663 return alias
3664
3665 def Rc_match(name):
3666 if not name.endswith("."):
3667 return None
3668 alias = exact_match(name[:-1])
3669 if alias is None:
3670 return None
3671 record = records[alias]
3672 if record.Rc is _RCOE.NONE:
3673 raise ValueError(record)
3674 return alias
3675
3676 db = {}
3677 matches = (exact_match, LK_match, AA_match, Rc_match)
3678 for (name, _) in mdwndb:
3679 if name.startswith("sv."):
3680 continue
3681 alias = None
3682 for match in matches:
3683 alias = match(name)
3684 if alias is not None:
3685 break
3686 if alias is None:
3687 continue
3688 section = sections[alias]
3689 record = records[alias]
3690 db[name] = (section, record)
3691
3692 self.__db = dict(sorted(db.items()))
3693
3694 return super().__init__()
3695
3696 @_functools.lru_cache(maxsize=512, typed=False)
3697 def __getitem__(self, key):
3698 return self.__db.get(key, (None, None))
3699
3700
3701 class SVP64Database:
3702 def __init__(self, root, ppcdb):
3703 db = set()
3704 pattern = _re.compile(r"^(?:LDST)?RM-(1P|2P)-.*?\.csv$")
3705 for (prefix, _, names) in _os.walk(root):
3706 prefix = _pathlib.Path(prefix)
3707 for name in filter(lambda name: pattern.match(name), names):
3708 path = (prefix / _pathlib.Path(name))
3709 with open(path, "r", encoding="UTF-8") as stream:
3710 db.update(parse(stream, SVP64Record.CSV))
3711 db = {record.name:record for record in db}
3712
3713 self.__db = dict(sorted(db.items()))
3714 self.__ppcdb = ppcdb
3715
3716 return super().__init__()
3717
3718 def __getitem__(self, key):
3719 (_, record) = self.__ppcdb[key]
3720 if record is None:
3721 return None
3722
3723 for name in record.names:
3724 record = self.__db.get(name, None)
3725 if record is not None:
3726 return record
3727
3728 return None
3729
3730
3731 class Database(Node):
3732 def __init__(self, root):
3733 root = _pathlib.Path(root)
3734 mdwndb = MarkdownDatabase()
3735 fieldsdb = FieldsDatabase()
3736 ppcdb = PPCDatabase(root=root, mdwndb=mdwndb)
3737 svp64db = SVP64Database(root=root, ppcdb=ppcdb)
3738
3739 db = set()
3740 names = {}
3741 opcodes = _collections.defaultdict(
3742 lambda: _collections.defaultdict(set))
3743
3744 for (name, mdwn) in mdwndb:
3745 if name.startswith("sv."):
3746 continue
3747 (section, ppc) = ppcdb[name]
3748 if ppc is None:
3749 continue
3750 svp64 = svp64db[name]
3751 fields = fieldsdb[ppc.form]
3752 record = Record(name=name,
3753 section=section, ppc=ppc, svp64=svp64,
3754 mdwn=mdwn, fields=fields)
3755 db.add(record)
3756 names[record.name] = record
3757 opcodes[section][record.PO].add(record)
3758
3759 self.__db = sorted(db)
3760 self.__names = dict(sorted(names.items()))
3761 self.__opcodes = dict(sorted(opcodes.items()))
3762
3763 return super().__init__()
3764
3765 def visit(self, handler, matcher, depth):
3766 if matcher(node=self, depth=depth):
3767 with handler(node=self, depth=depth):
3768 for record in self:
3769 record.visit(depth=(depth + 1),
3770 handler=handler, matcher=matcher)
3771
3772 @property
3773 def subnodes(self):
3774 for record in self.__db:
3775 yield record
3776
3777 def __repr__(self):
3778 return repr(self.__db)
3779
3780 def __iter__(self):
3781 yield from self.__db
3782
3783 @_functools.lru_cache(maxsize=None)
3784 def __contains__(self, key):
3785 return self.__getitem__(key) is not None
3786
3787 @_functools.lru_cache(maxsize=None)
3788 def __getitem__(self, key):
3789 if isinstance(key, SVP64Instruction):
3790 key = key.suffix
3791
3792 if isinstance(key, Instruction):
3793 PO = int(key.PO)
3794 key = int(key)
3795 sections = sorted(self.__opcodes)
3796 for section in sections:
3797 group = self.__opcodes[section]
3798 for record in group[PO]:
3799 if record.match(key=key):
3800 return record
3801
3802 return None
3803
3804 elif isinstance(key, str):
3805 return self.__names.get(key)
3806
3807 raise ValueError("instruction or name expected")