power_insn: remove the whitespaces properly
[openpower-isa.git] / src / openpower / decoder / power_fields.py
1 from collections import namedtuple
2
3 import operator as _operator
4 import functools as _functools
5
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,
9 BitRange as _BitRange,
10 selectconcat as _selectconcat,
11 )
12
13
14 class RemapError(ValueError):
15 pass
16
17
18 class Descriptor:
19 def __init__(self, cls):
20 self.__cls = cls
21 return super().__init__()
22
23 def __get__(self, instance, owner):
24 if instance is None:
25 return self.__cls
26 return self.__cls(storage=instance.storage)
27
28 def __set__(self, instance, value):
29 if instance is None:
30 raise AttributeError("read-only attribute")
31 self.__cls(storage=instance.storage).assign(value)
32
33
34 @_functools.total_ordering
35 class Reference:
36 def __init__(self, storage, *args, **kwargs):
37 if not isinstance(storage, _SelectableInt):
38 raise ValueError(storage)
39
40 self.storage = storage
41
42 super().__init__()
43 self.__post_init__()
44
45 def __post_init__(self, *args, **kwargs):
46 _ = (args, kwargs)
47
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))
51
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):
61 rhs = other
62 else:
63 raise ValueError(other)
64
65 return op(lhs, rhs)
66
67 def __lt__(self, other):
68 return self.__binary_operator(_operator.lt, other)
69
70 def __eq__(self, other):
71 return self.__binary_operator(_operator.eq, other)
72
73 def __int__(self):
74 span = dict.fromkeys(self.__class__.span).keys()
75 return int(_selectconcat(*(self.storage[bit] for bit in span)))
76
77 def __index__(self):
78 return int(self).__index__()
79
80 @property
81 def storage(self):
82 return self.__storage
83
84 @storage.setter
85 def storage(self, storage):
86 if not isinstance(storage, _SelectableInt):
87 raise ValueError(storage)
88
89 self.__storage = storage
90
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)
97
98 span = frozenset(self.__class__.span)
99 for (src_bit, dst_bit) in enumerate(span):
100 self.storage[dst_bit] = value[src_bit]
101
102
103 class FieldMeta(type):
104 def __new__(metacls, clsname, bases, ns, items=()):
105 assert "__members__" not in ns
106
107 members = []
108 for item in items:
109 if not isinstance(item, int):
110 raise ValueError(item)
111 if item < 0:
112 raise ValueError(item)
113 members.append(item)
114
115 ns["__members__"] = tuple(members)
116
117 return super().__new__(metacls, clsname, bases, ns)
118
119 def __repr__(cls):
120 if not cls.__members__:
121 return cls.__name__
122 return f"{cls.__name__}{cls.__members__!r}"
123
124 def __iter__(cls):
125 yield from cls.__members__
126
127 def __len__(cls):
128 return len(cls.__members__)
129
130 def __getitem__(cls, selector):
131 if isinstance(selector, int):
132 selector = (selector,)
133
134 items = []
135 for idx in selector:
136 if not isinstance(idx, int):
137 raise ValueError(selector)
138 item = cls.__members__[idx]
139 items.append(item)
140
141 return cls.__class__(cls.__name__, (Field,), {}, items=items)
142
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)
147
148 if len(cls) == 0:
149 return scheme
150 elif len(cls) > len(scheme):
151 llen = f"len(scheme)"
152 rlen = f"len({cls.__name__})"
153 raise RemapError(f"{llen} != {rlen}")
154
155 items = map(lambda item: scheme.__members__[item], cls)
156
157 return cls.__class__(cls.__name__, (cls,), {}, items=items)
158
159 @property
160 def span(cls):
161 return cls.__members__
162
163 def traverse(cls, path):
164 yield (path, cls.__members__)
165
166
167 class Field(Reference, metaclass=FieldMeta):
168 def __len__(self):
169 return self.__class__.__len__()
170
171 def __repr__(self):
172 return f"[{len(self.__class__)}]0x{int(self):x}"
173
174 def __iter__(self):
175 for bit in self.__class__:
176 yield self.storage[bit]
177
178
179 class ArrayMeta(type):
180 def __new__(metacls, clsname, bases, ns, items=()):
181 assert "__members__" not in ns
182
183 members = []
184 for item in items:
185 if not (isinstance(item, type) and issubclass(item, Field)):
186 item = FieldMeta("Field", (Field,), {}, items=item)
187 members.append(item)
188
189 ns["__members__"] = tuple(members)
190
191 return super().__new__(metacls, clsname, bases, ns)
192
193 def __repr__(cls):
194 if not cls.__members__:
195 return cls.__name__
196 return f"{cls.__name__}{cls.__members__!r}"
197
198 def __iter__(cls):
199 yield from enumerate(cls.__members__)
200
201 def __len__(cls):
202 length = 0
203 for field in cls.__members__:
204 length += len(field)
205 return length
206
207 def __getitem__(cls, size):
208 clsname = f"{cls.__name__}[{size}]"
209 items = ((Field,) * size)
210 return ArrayMeta(clsname, (Array,), {}, items=items)
211
212 def remap(cls, scheme):
213 scheme_md = []
214 scheme_sd = []
215
216 for item in scheme:
217 if not isinstance(item, int):
218 scheme_md.append(item)
219 else:
220 scheme_sd.append(item)
221
222 if scheme_md and scheme_sd:
223 raise ValueError(scheme)
224
225 def remap_md(scheme):
226 scheme = cls.__class__(cls.__name__, (cls,), {}, items=scheme)
227 if len(cls) == 0:
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}")
232 return scheme
233 elif len(scheme) != len(cls):
234 llen = f"len(scheme)"
235 rlen = f"len({cls.__name__})"
236 raise RemapError(f"{llen} != {rlen}")
237
238 items = []
239 for (idx, field) in enumerate(cls):
240 try:
241 item = field.remap(scheme.__members__[idx])
242 except RemapError as error:
243 raise RemapError(f"[{idx}]: {error}")
244 items.append(item)
245
246 return cls.__class__(cls.__name__, (cls,), {}, items=items)
247
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)
251
252 if scheme_md:
253 return remap_md(scheme_md)
254 else:
255 return remap_sd(scheme_sd)
256
257 @property
258 def span(cls):
259 for field in cls.__members__:
260 yield from field.span
261
262 def traverse(cls, path=""):
263 for (idx, field) in cls:
264 yield from field.traverse(path=f"{path}[{idx}]")
265
266
267 class Array(Reference, metaclass=ArrayMeta):
268 def __init__(self, storage):
269 members = []
270 for (idx, cls) in self.__class__:
271 members.append(cls(storage))
272
273 self.__members = tuple(members)
274
275 return super().__init__(storage)
276
277 def __repr__(self):
278 items = tuple(f"[{idx}]={field!r}" for (idx, field) in self)
279 return f"[{', '.join(items)}]"
280
281 def __iter__(self):
282 yield from enumerate(self.__members)
283
284 def __getitem__(self, key):
285 return self.__members[key]
286
287 def __setitem__(self, key, value):
288 self.__members[key].assign(value)
289
290
291 class MappingMeta(type):
292 def __new__(metacls, clsname, bases, ns):
293 members = {}
294
295 for cls in bases:
296 if isinstance(cls, metacls):
297 members.update(cls.__members__)
298
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}")
303
304 if name in ns:
305 try:
306 members[name] = cls.remap(ns[name])
307 except RemapError as error:
308 raise RemapError(f"{name}: {error}")
309 else:
310 if cls in (Array, Field):
311 raise ValueError(f"{clsname}.{name}: " + \
312 "base class without initializer")
313 members[name] = cls
314
315 ns["__members__"] = members
316 for (name, cls) in members.items():
317 ns[name] = Descriptor(cls)
318
319 return super().__new__(metacls, clsname, bases, ns)
320
321 def __repr__(cls):
322 return f"{cls.__name__}({cls.__members__!r})"
323
324 def __iter__(cls):
325 yield from cls.__members__.items()
326
327 def __len__(cls):
328 length = 0
329 for field in cls.__members__.values():
330 length = max(length, len(field))
331 return length
332
333 def __getitem__(cls, selector):
334 best_min = 0
335 best_max = 0
336 for field in cls.__members__.values():
337 length = len(field)
338 best_min = min(best_min, length)
339 best_max = max(best_max, length)
340
341 items = tuple(range(best_min, best_max))
342 field = FieldMeta(cls.__name__, (Field,), {}, items=items)
343
344 return field[selector]
345
346 def remap(cls, scheme):
347 ns = {}
348 annotations = {}
349
350 for (name, field) in cls:
351 annotations[name] = field.remap(scheme)
352 ns["__annotations__"] = annotations
353
354 return cls.__class__(cls.__name__, (cls,), ns)
355
356 @property
357 def span(cls):
358 for field in cls.__members__.values():
359 yield from field.span
360
361 def traverse(cls, path=""):
362 for (name, field) in cls:
363 if name == "_":
364 yield from field.traverse(path=path)
365 elif path == "":
366 yield from field.traverse(path=name)
367 else:
368 yield from field.traverse(path=f"{path}.{name}")
369
370
371 class Mapping(Reference, metaclass=MappingMeta):
372 def __init__(self, storage, **kwargs):
373 members = {}
374 for (name, cls) in self.__class__:
375 members[name] = cls(storage)
376
377 self.__members = members
378
379 return super().__init__(storage, **kwargs)
380
381 def __repr__(self):
382 items = tuple(f"{name}={field!r}" for (name, field) in self)
383 return f"{{{', '.join(items)}}}"
384
385 def __iter__(self):
386 yield from self.__members.items()
387
388 def __getitem__(self, key):
389 if isinstance(key, (int, slice, list, tuple, range)):
390 return self.storage[key]
391
392 return self.__members[key]
393
394
395 def decode_instructions(form):
396 res = {}
397 accum = []
398 for l in form:
399 if l.strip().startswith("Formats"):
400 l = l.strip().split(":")[-1]
401 l = l.replace(" ", "")
402 l = l.split(",")
403 for fmt in l:
404 if fmt not in res:
405 res[fmt] = [accum[0]]
406 else:
407 res[fmt].append(accum[0])
408 accum = []
409 else:
410 accum.append(l.strip())
411 return res
412
413
414 def decode_form_header(hdr):
415 res = {}
416 count = 0
417 hdr = hdr.strip()
418 for f in hdr.split("|"):
419 if not f:
420 continue
421 if f[0].isdigit():
422 idx = int(f.strip().split(' ')[0])
423 res[count] = idx
424 count += len(f) + 1
425 return res
426
427
428 def find_unique(d, key):
429 if key not in d:
430 return key
431 idx = 1
432 while "%s_%d" % (key, idx) in d:
433 idx += 1
434 return "%s_%d" % (key, idx)
435
436
437 def decode_line(header, line):
438 line = line.strip()
439 res = {}
440 count = 0
441 prev_fieldname = None
442 for f in line.split("|"):
443 if not f:
444 continue
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
451 count = end
452 continue
453 bitstart = header[count]
454 if prev_fieldname is not None:
455 res[prev_fieldname] = (res[prev_fieldname], bitstart)
456 res[fieldname] = bitstart
457 count = end
458 prev_fieldname = fieldname
459 res[prev_fieldname] = (bitstart, 32)
460 return res
461
462
463 def decode_form(form):
464 header = decode_form_header(form[0])
465 res = []
466 for line in form[1:]:
467 dec = decode_line(header, line)
468 if dec:
469 res.append(dec)
470 fields = {}
471 falternate = {}
472 for l in res:
473 for k, (start, end) in l.items():
474 if k in fields:
475 if (start, end) == fields[k]:
476 continue # already in and matching for this Form
477 if k in falternate:
478 alternate = "%s_%d" % (k, falternate[k])
479 if (start, end) == fields[alternate]:
480 continue
481 falternate[k] = fidx = falternate.get(k, 0) + 1
482 fields["%s_%d" % (k, fidx)] = (start, end)
483 else:
484 fields[k] = (start, end)
485 return fields
486
487
488 class DecodeFields:
489
490 def __init__(self, bitkls=_BitRange, bitargs=(), fname=None,
491 name_on_wiki=None):
492 self.bitkls = bitkls
493 self.bitargs = bitargs
494 if fname is None:
495 assert name_on_wiki is None
496 fname = "fields.txt"
497 name_on_wiki = "fields.text"
498 self.fname = _find_wiki_file(name_on_wiki)
499
500 @property
501 def form_names(self):
502 return self.instrs.keys()
503
504 def create_specs(self):
505 self.forms, self.instrs = self.decode_fields()
506 forms = self.form_names
507 #print ("specs", self.forms, forms)
508 for form in forms:
509 fields = self.instrs[form]
510 fk = fields.keys()
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,
524 "RS": self.FormX.RS,
525 "RT": self.FormX.RT,
526 "RA": self.FormX.RA,
527 "RB": self.FormX.RB,
528 "RC": self.FormVA.RC,
529 "SI": self.FormD.SI,
530 "UI": self.FormD.UI,
531 "L": self.FormD.L,
532 "SH32": self.FormM.SH,
533 "sh": self.FormMD.sh,
534 "MB32": self.FormM.MB,
535 "ME32": self.FormM.ME,
536 "LI": self.FormI.LI,
537 "LK": self.FormI.LK,
538 "AA": self.FormB.AA,
539 "Rc": self.FormX.Rc,
540 "OE": self.FormXO.OE,
541 "BD": self.FormB.BD,
542 "BF": self.FormX.BF,
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,
551 "D": self.FormD.D,
552 "DS": self.FormDS.DS,
553 "TO": self.FormX.TO,
554 "BC": self.FormA.BC,
555 "SH": self.FormX.SH,
556 "ME": self.FormM.ME,
557 "MB": self.FormM.MB,
558 "SPR": self.FormXFX.SPR}
559 for k, v in self.common_fields.items():
560 setattr(self, k, v)
561
562 def decode_fields(self):
563 with open(self.fname) as f:
564 txt = f.readlines()
565 #print ("decode", txt)
566 forms = {}
567 reading_data = False
568 for l in txt:
569 l = l.strip()
570 if len(l) == 0:
571 continue
572 if reading_data:
573 if l[0] == '#':
574 reading_data = False
575 else:
576 forms[heading].append(l)
577 if not reading_data:
578 assert l[0] == '#'
579 heading = l[1:].strip()
580 # if heading.startswith('1.6.28'): # skip instr fields for now
581 # break
582 heading = heading.split(' ')[-1]
583 reading_data = True
584 forms[heading] = []
585
586 res = {}
587 inst = {}
588
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)
594 # else:
595 # res[hdr] = decode_form(form)
596 return res, inst
597
598 def decode_instruction_fields(self, fields):
599 res = {}
600 for field in fields:
601 f, spec = field.strip().split(" ")
602 ss = spec[1:-1].split(",")
603 fs = f.split(",")
604 if len(fs) > 1:
605 individualfields = []
606 for f0, s0 in zip(fs, ss):
607 txt = "%s (%s)" % (f0, s0)
608 individualfields.append(txt)
609 if len(fs) > 1:
610 res.update(self.decode_instruction_fields(
611 individualfields))
612 d = self.bitkls(*self.bitargs)
613 idx = 0
614 for s in ss:
615 s = s.split(':')
616 if len(s) == 1:
617 d[idx] = int(s[0])
618 idx += 1
619 else:
620 start = int(s[0])
621 end = int(s[1])
622 while start <= end:
623 d[idx] = start
624 idx += 1
625 start += 1
626 f = f.replace(",", "_")
627 unique = find_unique(res, f)
628 res[unique] = d
629
630 return res
631
632
633 if __name__ == '__main__':
634 dec = DecodeFields()
635 dec.create_specs()
636 forms, instrs = dec.forms, dec.instrs
637 for form, fields in instrs.items():
638 print("Form", form)
639 for field, bits in fields.items():
640 print("\tfield", field, bits)