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