856182f36de8e918c92418196d5a129a2869d5ef
[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 selectltu as _selectltu,
12 )
13
14
15 class RemapError(ValueError):
16 pass
17
18
19 class Descriptor:
20 def __init__(self, cls):
21 self.__cls = cls
22 return super().__init__()
23
24 def __get__(self, instance, owner):
25 if instance is None:
26 return self.__cls
27 return self.__cls(storage=instance.storage)
28
29 def __set__(self, instance, value):
30 if instance is None:
31 raise AttributeError("read-only attribute")
32 self.__cls(storage=instance.storage).assign(value)
33
34
35 @_functools.total_ordering
36 class Reference:
37 def __init__(self, storage, *args, **kwargs):
38 if not isinstance(storage, _SelectableInt):
39 raise ValueError(storage)
40
41 self.storage = storage
42
43 super().__init__()
44 self.__post_init__()
45
46 def __post_init__(self, *args, **kwargs):
47 _ = (args, kwargs)
48
49 def __binary_operator(self, op, other):
50 span = dict.fromkeys(self.__class__.span).keys()
51 lhs = _selectconcat(*(self.storage[bit] for bit in span))
52
53 if isinstance(other, Reference):
54 span = dict.fromkeys(other.__class__.span).keys()
55 rhs = _selectconcat(*(other.storage[bit] for bit in span))
56 elif isinstance(other, int):
57 bits = len(self.__class__)
58 if other.bit_length() > bits:
59 raise OverflowError(other)
60 rhs = _SelectableInt(value=other, bits=bits)
61 elif isinstance(other, _SelectableInt):
62 rhs = other
63 else:
64 raise ValueError(other)
65
66 return op(lhs, rhs)
67
68 def __lt__(self, other):
69 return self.__binary_operator(_selectltu, other)
70
71 def __eq__(self, other):
72 return self.__binary_operator(_operator.eq, other)
73
74 def __bool__(self):
75 return bool(int(self))
76
77 def __int__(self):
78 span = dict.fromkeys(self.__class__.span).keys()
79 return int(_selectconcat(*(self.storage[bit] for bit in span)))
80
81 def __index__(self):
82 return int(self).__index__()
83
84 @property
85 def storage(self):
86 return self.__storage
87
88 @storage.setter
89 def storage(self, storage):
90 if not isinstance(storage, _SelectableInt):
91 raise ValueError(storage)
92
93 self.__storage = storage
94
95 def assign(self, value, bits=None):
96 if bits is None:
97 bits = range(len(self.__class__))
98 elif isinstance(bits, int):
99 bits = (bits,)
100 elif isinstance(bits, slice):
101 assert bits.step is None or bits.step == 1
102 bits = range(bits.start, bits.stop)
103 bits = tuple(bits)
104
105 if isinstance(value, int):
106 if value.bit_length() > len(bits):
107 raise OverflowError(value)
108 value = _SelectableInt(value=value, bits=len(bits))
109 if not isinstance(value, _SelectableInt):
110 raise ValueError(value)
111 if value.bits != len(bits):
112 raise OverflowError(value)
113
114 span = tuple(self.__class__.span)
115 mapping = dict(enumerate(span))
116 for (src, bit) in enumerate(bits):
117 if src >= value.bits:
118 raise OverflowError(src)
119 dst = mapping.get(bit)
120 if dst is None:
121 raise OverflowError(bit)
122 self.storage[dst] = value[src]
123
124
125 class FieldMeta(type):
126 def __new__(metacls, clsname, bases, ns, items=()):
127 assert "__members__" not in ns
128
129 members = []
130 for item in items:
131 if not isinstance(item, int):
132 raise ValueError(item)
133 if item < 0:
134 raise ValueError(item)
135 members.append(item)
136
137 ns["__members__"] = tuple(members)
138
139 return super().__new__(metacls, clsname, bases, ns)
140
141 def __repr__(cls):
142 if not cls.__members__:
143 return cls.__name__
144 return f"{cls.__name__}{cls.__members__!r}"
145
146 def __iter__(cls):
147 yield from cls.__members__
148
149 def __len__(cls):
150 return len(cls.__members__)
151
152 def __getitem__(cls, selector):
153 if isinstance(selector, int):
154 selector = (selector,)
155
156 items = []
157 for idx in selector:
158 if not isinstance(idx, int):
159 raise ValueError(selector)
160 item = cls.__members__[idx]
161 items.append(item)
162
163 return cls.__class__(cls.__name__, (Field,), {}, items=items)
164
165 def remap(cls, scheme):
166 if isinstance(scheme, type) and issubclass(scheme, Mapping):
167 scheme = range(len(scheme))
168 scheme = cls.__class__(cls.__name__, (cls,), {}, items=scheme)
169
170 if len(cls) == 0:
171 return scheme
172 elif len(cls) > len(scheme):
173 llen = f"len(scheme)"
174 rlen = f"len({cls.__name__})"
175 raise RemapError(f"{llen} != {rlen}")
176
177 ns = {}
178 ns["__doc__"] = cls.__doc__
179 items = map(lambda item: scheme.__members__[item], cls)
180
181 return cls.__class__(cls.__name__, (cls,), ns, items=items)
182
183 @property
184 def span(cls):
185 return cls.__members__
186
187
188 class Field(Reference, metaclass=FieldMeta):
189 def __repr__(self):
190 return f"[{len(self.__class__)}]0x{int(self):x}"
191
192 def __iter__(self):
193 for bit in self.__class__:
194 yield self.storage[bit]
195
196 def __getitem__(self, key):
197 if isinstance(key, int):
198 bit = self.storage[self.__class__.__members__[key]]
199 return _SelectableInt(value=bit, bits=1)
200 if isinstance(key, slice):
201 assert key.step is None or key.step == 1
202 key = range(key.start, key.stop)
203
204 return _selectconcat(*(self[bit] for bit in key))
205
206 def __setitem__(self, key, value):
207 return self.assign(value=value, bits=key)
208
209 @classmethod
210 def traverse(cls, path):
211 yield (path, cls.__members__)
212
213
214 class MappingMeta(type):
215 def __new__(metacls, clsname, bases, ns):
216 members = {}
217
218 for cls in bases:
219 if isinstance(cls, metacls):
220 members.update(cls.__members__)
221
222 for (name, cls) in ns.get("__annotations__", {}).items():
223 if not (isinstance(cls, type) and
224 issubclass(cls, (Mapping, Field))):
225 raise ValueError(f"{clsname}.{name}: {cls!r}")
226
227 if name in ns:
228 try:
229 members[name] = cls.remap(ns[name])
230 except RemapError as error:
231 raise RemapError(f"{name}: {error}")
232 else:
233 if cls is Field:
234 raise ValueError(f"{clsname}.{name}: missing initializer")
235 members[name] = cls
236
237 ns["__members__"] = members
238 for (name, cls) in members.items():
239 ns[name] = Descriptor(cls)
240
241 return super().__new__(metacls, clsname, bases, ns)
242
243 def __repr__(cls):
244 return f"{cls.__name__}({cls.__members__!r})"
245
246 def __iter__(cls):
247 yield from cls.__members__.items()
248
249 def __len__(cls):
250 length = 0
251 for field in cls.__members__.values():
252 length = max(length, len(field))
253 return length
254
255 def __getitem__(cls, selector):
256 return cls.__members__["_"][selector]
257
258 def remap(cls, scheme):
259 ns = {}
260 annotations = {}
261
262 for (name, field) in cls:
263 annotations[name] = field.remap(scheme)
264 ns["__annotations__"] = annotations
265 ns["__doc__"] = cls.__doc__
266
267 return cls.__class__(cls.__name__, (cls,), ns)
268
269 @property
270 def span(cls):
271 for field in cls.__members__.values():
272 yield from field.span
273
274
275 class Mapping(Reference, metaclass=MappingMeta):
276 def __init__(self, storage, **kwargs):
277 members = {}
278 for (name, cls) in self.__class__:
279 members[name] = cls(storage)
280
281 self.__members = members
282
283 return super().__init__(storage, **kwargs)
284
285 def __repr__(self):
286 items = tuple(f"{name}={field!r}" for (name, field) in self)
287 return f"{{{', '.join(items)}}}"
288
289 def __iter__(self):
290 yield from self.__members.items()
291
292 def __getitem__(self, key):
293 if isinstance(key, (int, slice, list, tuple, range)):
294 return self["_"].__getitem__(key)
295
296 return self.__members.__getitem__(key)
297
298 def __setitem__(self, key, value):
299 if isinstance(key, (int, slice, list, tuple, range)):
300 return self["_"].assign(value=value, bits=key)
301
302 return self.assign(value=value, bits=key)
303
304 def __getattr__(self, key):
305 raise AttributeError(key)
306
307 @classmethod
308 def traverse(cls, path):
309 for (name, member) in cls.__members__.items():
310 if name == "_":
311 yield from member.traverse(path=path)
312 elif path == "":
313 yield from member.traverse(path=name)
314 else:
315 yield from member.traverse(path=f"{path}.{name}")
316
317
318 def decode_instructions(form):
319 res = {}
320 accum = []
321 for l in form:
322 if l.strip().startswith("Formats"):
323 l = l.strip().split(":")[-1]
324 l = l.replace(" ", "")
325 l = l.split(",")
326 for fmt in l:
327 if fmt not in res:
328 res[fmt] = [accum[0]]
329 else:
330 res[fmt].append(accum[0])
331 accum = []
332 else:
333 accum.append(l.strip())
334 return res
335
336
337 def decode_form_header(hdr):
338 res = {}
339 count = 0
340 hdr = hdr.strip()
341 for f in hdr.split("|"):
342 if not f:
343 continue
344 if f[0].isdigit():
345 idx = int(f.strip().split(' ')[0])
346 res[count] = idx
347 count += len(f) + 1
348 return res
349
350
351 def find_unique(d, key):
352 if key not in d:
353 return key
354 idx = 1
355 while "%s_%d" % (key, idx) in d:
356 idx += 1
357 return "%s_%d" % (key, idx)
358
359
360 def decode_line(header, line):
361 line = line.strip()
362 res = {}
363 count = 0
364 prev_fieldname = None
365 for f in line.split("|"):
366 if not f:
367 continue
368 end = count + len(f) + 1
369 fieldname = f.strip()
370 if not fieldname or fieldname.startswith('/'):
371 if prev_fieldname is not None:
372 res[prev_fieldname] = (res[prev_fieldname], header[count])
373 prev_fieldname = None
374 count = end
375 continue
376 bitstart = header[count]
377 if prev_fieldname is not None:
378 res[prev_fieldname] = (res[prev_fieldname], bitstart)
379 res[fieldname] = bitstart
380 count = end
381 prev_fieldname = fieldname
382 res[prev_fieldname] = (bitstart, 32)
383 return res
384
385
386 def decode_form(form):
387 header = decode_form_header(form[0])
388 res = []
389 for line in form[1:]:
390 dec = decode_line(header, line)
391 if dec:
392 res.append(dec)
393 fields = {}
394 falternate = {}
395 for l in res:
396 for k, (start, end) in l.items():
397 if k in fields:
398 if (start, end) == fields[k]:
399 continue # already in and matching for this Form
400 if k in falternate:
401 alternate = "%s_%d" % (k, falternate[k])
402 if (start, end) == fields[alternate]:
403 continue
404 falternate[k] = fidx = falternate.get(k, 0) + 1
405 fields["%s_%d" % (k, fidx)] = (start, end)
406 else:
407 fields[k] = (start, end)
408 return fields
409
410
411 class DecodeFields:
412
413 def __init__(self, bitkls=_BitRange, bitargs=(), fname=None,
414 name_on_wiki=None):
415 self.bitkls = bitkls
416 self.bitargs = bitargs
417 if fname is None:
418 assert name_on_wiki is None
419 fname = "fields.txt"
420 name_on_wiki = "fields.text"
421 self.fname = _find_wiki_file(name_on_wiki)
422
423 @property
424 def form_names(self):
425 return self.instrs.keys()
426
427 def create_specs(self):
428 self.forms, self.instrs = self.decode_fields()
429 forms = self.form_names
430 #print ("specs", self.forms, forms)
431 for form in forms:
432 fields = self.instrs[form]
433 fk = fields.keys()
434 Fields = namedtuple("Fields", fk)
435 instr = Fields(**fields)
436 setattr(self, "Form%s" % form, instr)
437 # now add in some commonly-used fields (should be done automatically)
438 # note that these should only be ones which are the same on all Forms
439 # note: these are from microwatt insn_helpers.vhdl
440 self.common_fields = {
441 "PO": self.Formall.PO,
442 "FRS": self.FormX.FRS,
443 "FRT": self.FormX.FRT,
444 "FRA": self.FormX.FRA,
445 "FRB": self.FormX.FRB,
446 "FRC": self.FormA.FRC,
447 "RS": self.FormX.RS,
448 "RT": self.FormX.RT,
449 "RA": self.FormX.RA,
450 "RB": self.FormX.RB,
451 "RC": self.FormVA.RC,
452 "SI": self.FormD.SI,
453 "UI": self.FormD.UI,
454 "L": self.FormD.L,
455 "SH32": self.FormM.SH,
456 "sh": self.FormMD.sh,
457 "MB32": self.FormM.MB,
458 "ME32": self.FormM.ME,
459 "LI": self.FormI.LI,
460 "LK": self.FormI.LK,
461 "AA": self.FormB.AA,
462 "Rc": self.FormX.Rc,
463 "OE": self.FormXO.OE,
464 "BD": self.FormB.BD,
465 "BF": self.FormX.BF,
466 "CR": self.FormXL.XO,
467 "BB": self.FormXL.BB,
468 "BA": self.FormXL.BA,
469 "BT": self.FormXL.BT,
470 "FXM": self.FormXFX.FXM,
471 "BO": self.FormXL.BO,
472 "BI": self.FormXL.BI,
473 "BH": self.FormXL.BH,
474 "D": self.FormD.D,
475 "DS": self.FormDS.DS,
476 "TO": self.FormX.TO,
477 "BC": self.FormA.BC,
478 "SH": self.FormX.SH,
479 "ME": self.FormM.ME,
480 "MB": self.FormM.MB,
481 "SPR": self.FormXFX.SPR}
482 for k, v in self.common_fields.items():
483 setattr(self, k, v)
484
485 def decode_fields(self):
486 with open(self.fname) as f:
487 txt = f.readlines()
488 #print ("decode", txt)
489 forms = {}
490 reading_data = False
491 for l in txt:
492 l = l.strip()
493 if len(l) == 0:
494 continue
495 if reading_data:
496 if l[0] == '#':
497 reading_data = False
498 else:
499 forms[heading].append(l)
500 if not reading_data:
501 assert l[0] == '#'
502 heading = l[1:].strip()
503 # if heading.startswith('1.6.28'): # skip instr fields for now
504 # break
505 heading = heading.split(' ')[-1]
506 reading_data = True
507 forms[heading] = []
508
509 res = {}
510 inst = {}
511
512 for hdr, form in forms.items():
513 if heading == 'Fields':
514 i = decode_instructions(form)
515 for form, field in i.items():
516 inst[form] = self.decode_instruction_fields(field)
517 # else:
518 # res[hdr] = decode_form(form)
519 return res, inst
520
521 def decode_instruction_fields(self, fields):
522 res = {}
523 for field in fields:
524 f, spec = field.strip().split(" ")
525 ss = spec[1:-1].split(",")
526 fs = f.split(",")
527 if len(fs) > 1:
528 individualfields = []
529 for f0, s0 in zip(fs, ss):
530 txt = "%s (%s)" % (f0, s0)
531 individualfields.append(txt)
532 if len(fs) > 1:
533 res.update(self.decode_instruction_fields(
534 individualfields))
535 d = self.bitkls(*self.bitargs)
536 idx = 0
537 for s in ss:
538 s = s.split(':')
539 if len(s) == 1:
540 d[idx] = int(s[0])
541 idx += 1
542 else:
543 start = int(s[0])
544 end = int(s[1])
545 while start <= end:
546 d[idx] = start
547 idx += 1
548 start += 1
549 f = f.replace(",", "_")
550 unique = find_unique(res, f)
551 res[unique] = d
552
553 return res
554
555
556 if __name__ == '__main__':
557 dec = DecodeFields()
558 dec.create_specs()
559 forms, instrs = dec.forms, dec.instrs
560 for form, fields in instrs.items():
561 print("Form", form)
562 for field, bits in fields.items():
563 print("\tfield", field, bits)