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