genlib/record: add eq
[litex.git] / migen / genlib / record.py
1 from migen.fhdl.structure import *
2 from migen.fhdl.tools import value_bits_sign
3
4 class Record:
5 def __init__(self, layout, name=""):
6 self.name = name
7 self.field_order = []
8 if self.name:
9 prefix = self.name + "_"
10 else:
11 prefix = ""
12 for f in layout:
13 if isinstance(f, tuple):
14 if isinstance(f[1], (int, tuple)):
15 setattr(self, f[0], Signal(f[1], prefix + f[0]))
16 elif isinstance(f[1], Signal) or isinstance(f[1], Record):
17 setattr(self, f[0], f[1])
18 elif isinstance(f[1], list):
19 setattr(self, f[0], Record(f[1], prefix + f[0]))
20 else:
21 raise TypeError
22 if len(f) == 3:
23 self.field_order.append((f[0], f[2]))
24 else:
25 self.field_order.append((f[0], 1))
26 else:
27 setattr(self, f, Signal(1, prefix + f))
28 self.field_order.append((f, 1))
29
30 def eq(self, other):
31 return [getattr(self, key).eq(getattr(other, key))
32 for key, a in self.field_order]
33
34 def layout(self):
35 l = []
36 for key, alignment in self.field_order:
37 e = self.__dict__[key]
38 if isinstance(e, Signal):
39 l.append((key, (e.nbits, e.signed), alignment))
40 elif isinstance(e, Record):
41 l.append((key, e.layout(), alignment))
42 return l
43
44 def copy(self, name=None):
45 return Record(self.layout(), name)
46
47 def get_alignment(self, name):
48 return list(filter(lambda x: x[0] == name, self.field_order))[0][1]
49
50 def subrecord(self, *descr):
51 fields = []
52 for item in descr:
53 path = item.split("/")
54 last = path.pop()
55 pos_self = self
56 pos_fields = fields
57 for hop in path:
58 pos_self = getattr(pos_self, hop)
59 lu = list(filter(lambda x: x[0] == hop, pos_fields))
60 try:
61 pos_fields = lu[0][1]
62 except IndexError:
63 n = []
64 pos_fields.append((hop, n))
65 pos_fields = n
66 if not isinstance(pos_fields, list):
67 raise ValueError
68 if len(list(filter(lambda x: x[0] == last, pos_fields))) > 0:
69 raise ValueError
70 pos_fields.append((last, getattr(pos_self, last), pos_self.get_alignment(last)))
71 return Record(fields, "subrecord")
72
73 def compatible(self, other):
74 tpl1 = self.flatten()
75 tpl2 = other.flatten()
76 return len(tpl1) == len(tpl2)
77
78 def flatten(self, align=False, offset=0, return_offset=False):
79 l = []
80 for key, alignment in self.field_order:
81 if align:
82 pad_size = alignment - (offset % alignment)
83 if pad_size < alignment:
84 l.append(Replicate(0, pad_size))
85 offset += pad_size
86
87 e = self.__dict__[key]
88 if isinstance(e, Signal):
89 added = [e]
90 elif isinstance(e, Record):
91 added = e.flatten(align, offset)
92 else:
93 raise TypeError
94 for x in added:
95 offset += value_bits_sign(x)[0]
96 l += added
97 if return_offset:
98 return (l, offset)
99 else:
100 return l
101
102 def to_signal(self, assignment_list, sig_out, align=False):
103 flattened, length = self.flatten(align, return_offset=True)
104 raw = Signal(length)
105 if sig_out:
106 assignment_list.append(raw.eq(Cat(*flattened)))
107 else:
108 assignment_list.append(Cat(*flattened).eq(raw))
109 return raw
110
111 def __repr__(self):
112 return "<Record " + repr(self.layout()) + ">"