1 from collections
import namedtuple
3 import operator
as _operator
4 import functools
as _functools
6 from openpower
.decoder
.power_enums
import find_wiki_file
as _find_wiki_file
7 from openpower
.decoder
.selectable_int
import (
8 SelectableInt
as _SelectableInt
,
10 selectconcat
as _selectconcat
,
14 class RemapError(ValueError):
19 def __init__(self
, cls
):
21 return super().__init
__()
23 def __get__(self
, instance
, owner
):
26 return self
.__cls
(storage
=instance
.storage
)
28 def __set__(self
, instance
, value
):
30 raise AttributeError("read-only attribute")
31 self
.__cls
(storage
=instance
.storage
).assign(value
)
34 @_functools.total_ordering
36 def __init__(self
, storage
, *args
, **kwargs
):
37 if not isinstance(storage
, _SelectableInt
):
38 raise ValueError(storage
)
40 self
.storage
= storage
45 def __post_init__(self
, *args
, **kwargs
):
48 def __binary_operator(self
, op
, other
):
49 span
= dict.fromkeys(self
.__class
__.span
).keys()
50 lhs
= _selectconcat(*(self
.storage
[bit
] for bit
in span
))
52 if isinstance(other
, Reference
):
53 span
= dict.fromkeys(other
.__class
__.span
).keys()
54 rhs
= _selectconcat(*(other
.storage
[bit
] for bit
in span
))
55 elif isinstance(other
, int):
56 bits
= len(self
.__class
__)
57 if other
.bit_length() > bits
:
58 raise OverflowError(other
)
59 rhs
= _SelectableInt(value
=other
, bits
=bits
)
60 elif isinstance(other
, _SelectableInt
):
63 raise ValueError(other
)
67 def __lt__(self
, other
):
68 return self
.__binary
_operator
(_operator
.lt
, other
)
70 def __eq__(self
, other
):
71 return self
.__binary
_operator
(_operator
.eq
, other
)
74 span
= dict.fromkeys(self
.__class
__.span
).keys()
75 return int(_selectconcat(*(self
.storage
[bit
] for bit
in span
)))
78 return int(self
).__index
__()
85 def storage(self
, storage
):
86 if not isinstance(storage
, _SelectableInt
):
87 raise ValueError(storage
)
89 self
.__storage
= storage
91 def assign(self
, value
):
92 if isinstance(value
, int):
93 bits
= len(self
.__class
__)
94 value
= _SelectableInt(value
=value
, bits
=bits
)
95 if not isinstance(value
, _SelectableInt
):
96 raise ValueError(value
)
98 span
= frozenset(self
.__class
__.span
)
99 for (src_bit
, dst_bit
) in enumerate(span
):
100 self
.storage
[dst_bit
] = value
[src_bit
]
103 class FieldMeta(type):
104 def __new__(metacls
, clsname
, bases
, ns
, items
=()):
105 assert "__members__" not in ns
109 if not isinstance(item
, int):
110 raise ValueError(item
)
112 raise ValueError(item
)
115 ns
["__members__"] = tuple(members
)
117 return super().__new
__(metacls
, clsname
, bases
, ns
)
120 if not cls
.__members
__:
122 return f
"{cls.__name__}{cls.__members__!r}"
125 yield from cls
.__members
__
128 return len(cls
.__members
__)
130 def __getitem__(cls
, selector
):
131 if isinstance(selector
, int):
132 selector
= (selector
,)
136 if not isinstance(idx
, int):
137 raise ValueError(selector
)
138 item
= cls
.__members
__[idx
]
141 return cls
.__class
__(cls
.__name
__, (Field
,), {}, items
=items
)
143 def remap(cls
, scheme
):
144 if isinstance(scheme
, type) and issubclass(scheme
, Mapping
):
145 scheme
= range(len(scheme
))
146 scheme
= cls
.__class
__(cls
.__name
__, (cls
,), {}, items
=scheme
)
150 elif len(cls
) > len(scheme
):
151 llen
= f
"len(scheme)"
152 rlen
= f
"len({cls.__name__})"
153 raise RemapError(f
"{llen} != {rlen}")
155 items
= map(lambda item
: scheme
.__members
__[item
], cls
)
157 return cls
.__class
__(cls
.__name
__, (cls
,), {}, items
=items
)
161 return cls
.__members
__
163 def traverse(cls
, path
):
164 yield (path
, cls
.__members
__)
167 class Field(Reference
, metaclass
=FieldMeta
):
169 return self
.__class
__.__len
__()
172 return f
"[{len(self.__class__)}]0x{int(self):x}"
175 for bit
in self
.__class
__:
176 yield self
.storage
[bit
]
179 class ArrayMeta(type):
180 def __new__(metacls
, clsname
, bases
, ns
, items
=()):
181 assert "__members__" not in ns
185 if not (isinstance(item
, type) and issubclass(item
, Field
)):
186 item
= FieldMeta("Field", (Field
,), {}, items
=item
)
189 ns
["__members__"] = tuple(members
)
191 return super().__new
__(metacls
, clsname
, bases
, ns
)
194 if not cls
.__members
__:
196 return f
"{cls.__name__}{cls.__members__!r}"
199 yield from enumerate(cls
.__members
__)
203 for field
in cls
.__members
__:
207 def __getitem__(cls
, size
):
208 clsname
= f
"{cls.__name__}[{size}]"
209 items
= ((Field
,) * size
)
210 return ArrayMeta(clsname
, (Array
,), {}, items
=items
)
212 def remap(cls
, scheme
):
217 if not isinstance(item
, int):
218 scheme_md
.append(item
)
220 scheme_sd
.append(item
)
222 if scheme_md
and scheme_sd
:
223 raise ValueError(scheme
)
225 def remap_md(scheme
):
226 scheme
= cls
.__class
__(cls
.__name
__, (cls
,), {}, items
=scheme
)
228 if len(cls
.__members
__) != len(scheme
.__members
__):
229 llen
= f
"len(scheme.__members__)"
230 rlen
= f
"len({cls.__name__}.__members__)"
231 raise RemapError(f
"{llen} != {rlen}")
233 elif len(scheme
) != len(cls
):
234 llen
= f
"len(scheme)"
235 rlen
= f
"len({cls.__name__})"
236 raise RemapError(f
"{llen} != {rlen}")
239 for (idx
, field
) in enumerate(cls
):
241 item
= field
.remap(scheme
.__members
__[idx
])
242 except RemapError
as error
:
243 raise RemapError(f
"[{idx}]: {error}")
246 return cls
.__class
__(cls
.__name
__, (cls
,), {}, items
=items
)
248 def remap_sd(scheme
):
249 items
= tuple(item
.remap(scheme
) for item
in cls
.__members
__)
250 return cls
.__class
__(cls
.__name
__, (cls
,), {}, items
=items
)
253 return remap_md(scheme_md
)
255 return remap_sd(scheme_sd
)
259 for field
in cls
.__members
__:
260 yield from field
.span
262 def traverse(cls
, path
=""):
263 for (idx
, field
) in cls
:
264 yield from field
.traverse(path
=f
"{path}[{idx}]")
267 class Array(Reference
, metaclass
=ArrayMeta
):
268 def __init__(self
, storage
):
270 for (idx
, cls
) in self
.__class
__:
271 members
.append(cls(storage
))
273 self
.__members
= tuple(members
)
275 return super().__init
__(storage
)
278 items
= tuple(f
"[{idx}]={field!r}" for (idx
, field
) in self
)
279 return f
"[{', '.join(items)}]"
282 yield from enumerate(self
.__members
)
284 def __getitem__(self
, key
):
285 return self
.__members
[key
]
287 def __setitem__(self
, key
, value
):
288 self
.__members
[key
].assign(value
)
291 class MappingMeta(type):
292 def __new__(metacls
, clsname
, bases
, ns
):
296 if isinstance(cls
, metacls
):
297 members
.update(cls
.__members
__)
299 for (name
, cls
) in ns
.get("__annotations__", {}).items():
300 if not (isinstance(cls
, type) and
301 issubclass(cls
, (Mapping
, Array
, Field
))):
302 raise ValueError(f
"{clsname}.{name}: {cls!r}")
306 members
[name
] = cls
.remap(ns
[name
])
307 except RemapError
as error
:
308 raise RemapError(f
"{name}: {error}")
310 if cls
in (Array
, Field
):
311 raise ValueError(f
"{clsname}.{name}: " + \
312 "base class without initializer")
315 ns
["__members__"] = members
316 for (name
, cls
) in members
.items():
317 ns
[name
] = Descriptor(cls
)
319 return super().__new
__(metacls
, clsname
, bases
, ns
)
322 return f
"{cls.__name__}({cls.__members__!r})"
325 yield from cls
.__members
__.items()
329 for field
in cls
.__members
__.values():
330 length
= max(length
, len(field
))
333 def __getitem__(cls
, selector
):
336 for field
in cls
.__members
__.values():
338 best_min
= min(best_min
, length
)
339 best_max
= max(best_max
, length
)
341 items
= tuple(range(best_min
, best_max
))
342 field
= FieldMeta(cls
.__name
__, (Field
,), {}, items
=items
)
344 return field
[selector
]
346 def remap(cls
, scheme
):
350 for (name
, field
) in cls
:
351 annotations
[name
] = field
.remap(scheme
)
352 ns
["__annotations__"] = annotations
354 return cls
.__class
__(cls
.__name
__, (cls
,), ns
)
358 for field
in cls
.__members
__.values():
359 yield from field
.span
361 def traverse(cls
, path
=""):
362 for (name
, field
) in cls
:
364 yield from field
.traverse(path
=path
)
366 yield from field
.traverse(path
=name
)
368 yield from field
.traverse(path
=f
"{path}.{name}")
371 class Mapping(Reference
, metaclass
=MappingMeta
):
372 def __init__(self
, storage
, **kwargs
):
374 for (name
, cls
) in self
.__class
__:
375 members
[name
] = cls(storage
)
377 self
.__members
= members
379 return super().__init
__(storage
, **kwargs
)
382 items
= tuple(f
"{name}={field!r}" for (name
, field
) in self
)
383 return f
"{{{', '.join(items)}}}"
386 yield from self
.__members
.items()
388 def __getitem__(self
, key
):
389 if isinstance(key
, (int, slice, list, tuple, range)):
390 return self
.storage
[key
]
392 return self
.__members
[key
]
395 def decode_instructions(form
):
399 if l
.strip().startswith("Formats"):
400 l
= l
.strip().split(":")[-1]
401 l
= l
.replace(" ", "")
405 res
[fmt
] = [accum
[0]]
407 res
[fmt
].append(accum
[0])
410 accum
.append(l
.strip())
414 def decode_form_header(hdr
):
418 for f
in hdr
.split("|"):
422 idx
= int(f
.strip().split(' ')[0])
428 def find_unique(d
, key
):
432 while "%s_%d" % (key
, idx
) in d
:
434 return "%s_%d" % (key
, idx
)
437 def decode_line(header
, line
):
441 prev_fieldname
= None
442 for f
in line
.split("|"):
445 end
= count
+ len(f
) + 1
446 fieldname
= f
.strip()
447 if not fieldname
or fieldname
.startswith('/'):
448 if prev_fieldname
is not None:
449 res
[prev_fieldname
] = (res
[prev_fieldname
], header
[count
])
450 prev_fieldname
= None
453 bitstart
= header
[count
]
454 if prev_fieldname
is not None:
455 res
[prev_fieldname
] = (res
[prev_fieldname
], bitstart
)
456 res
[fieldname
] = bitstart
458 prev_fieldname
= fieldname
459 res
[prev_fieldname
] = (bitstart
, 32)
463 def decode_form(form
):
464 header
= decode_form_header(form
[0])
466 for line
in form
[1:]:
467 dec
= decode_line(header
, line
)
473 for k
, (start
, end
) in l
.items():
475 if (start
, end
) == fields
[k
]:
476 continue # already in and matching for this Form
478 alternate
= "%s_%d" % (k
, falternate
[k
])
479 if (start
, end
) == fields
[alternate
]:
481 falternate
[k
] = fidx
= falternate
.get(k
, 0) + 1
482 fields
["%s_%d" % (k
, fidx
)] = (start
, end
)
484 fields
[k
] = (start
, end
)
490 def __init__(self
, bitkls
=_BitRange
, bitargs
=(), fname
=None,
493 self
.bitargs
= bitargs
495 assert name_on_wiki
is None
497 name_on_wiki
= "fields.text"
498 self
.fname
= _find_wiki_file(name_on_wiki
)
501 def form_names(self
):
502 return self
.instrs
.keys()
504 def create_specs(self
):
505 self
.forms
, self
.instrs
= self
.decode_fields()
506 forms
= self
.form_names
507 #print ("specs", self.forms, forms)
509 fields
= self
.instrs
[form
]
511 Fields
= namedtuple("Fields", fk
)
512 instr
= Fields(**fields
)
513 setattr(self
, "Form%s" % form
, instr
)
514 # now add in some commonly-used fields (should be done automatically)
515 # note that these should only be ones which are the same on all Forms
516 # note: these are from microwatt insn_helpers.vhdl
517 self
.common_fields
= {
518 "PO": self
.Formall
.PO
,
519 "FRS": self
.FormX
.FRS
,
520 "FRT": self
.FormX
.FRT
,
521 "FRA": self
.FormX
.FRA
,
522 "FRB": self
.FormX
.FRB
,
523 "FRC": self
.FormA
.FRC
,
528 "RC": self
.FormVA
.RC
,
532 "SH32": self
.FormM
.SH
,
533 "sh": self
.FormMD
.sh
,
534 "MB32": self
.FormM
.MB
,
535 "ME32": self
.FormM
.ME
,
540 "OE": self
.FormXO
.OE
,
543 "CR": self
.FormXL
.XO
,
544 "BB": self
.FormXL
.BB
,
545 "BA": self
.FormXL
.BA
,
546 "BT": self
.FormXL
.BT
,
547 "FXM": self
.FormXFX
.FXM
,
548 "BO": self
.FormXL
.BO
,
549 "BI": self
.FormXL
.BI
,
550 "BH": self
.FormXL
.BH
,
552 "DS": self
.FormDS
.DS
,
558 "SPR": self
.FormXFX
.SPR
}
559 for k
, v
in self
.common_fields
.items():
562 def decode_fields(self
):
563 with
open(self
.fname
) as f
:
565 #print ("decode", txt)
576 forms
[heading
].append(l
)
579 heading
= l
[1:].strip()
580 # if heading.startswith('1.6.28'): # skip instr fields for now
582 heading
= heading
.split(' ')[-1]
589 for hdr
, form
in forms
.items():
590 if heading
== 'Fields':
591 i
= decode_instructions(form
)
592 for form
, field
in i
.items():
593 inst
[form
] = self
.decode_instruction_fields(field
)
595 # res[hdr] = decode_form(form)
598 def decode_instruction_fields(self
, fields
):
601 f
, spec
= field
.strip().split(" ")
602 ss
= spec
[1:-1].split(",")
605 individualfields
= []
606 for f0
, s0
in zip(fs
, ss
):
607 txt
= "%s (%s)" % (f0
, s0
)
608 individualfields
.append(txt
)
610 res
.update(self
.decode_instruction_fields(
612 d
= self
.bitkls(*self
.bitargs
)
626 f
= f
.replace(",", "_")
627 unique
= find_unique(res
, f
)
633 if __name__
== '__main__':
636 forms
, instrs
= dec
.forms
, dec
.instrs
637 for form
, fields
in instrs
.items():
639 for field
, bits
in fields
.items():
640 print("\tfield", field
, bits
)