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