2012-01-06 05:20:44 -05:00
|
|
|
from migen.fhdl.structure import *
|
2012-11-29 15:22:38 -05:00
|
|
|
from migen.fhdl.tools import value_bits_sign
|
2012-01-06 05:20:44 -05:00
|
|
|
|
|
|
|
class Record:
|
2012-01-16 13:38:14 -05:00
|
|
|
def __init__(self, layout, name=""):
|
|
|
|
self.name = name
|
2012-01-09 09:14:42 -05:00
|
|
|
self.field_order = []
|
2012-01-16 13:38:14 -05:00
|
|
|
if self.name:
|
|
|
|
prefix = self.name + "_"
|
|
|
|
else:
|
|
|
|
prefix = ""
|
2012-01-09 09:14:42 -05:00
|
|
|
for f in layout:
|
2012-01-06 05:20:44 -05:00
|
|
|
if isinstance(f, tuple):
|
2012-11-29 15:22:38 -05:00
|
|
|
if isinstance(f[1], (int, tuple)):
|
2012-01-16 13:38:14 -05:00
|
|
|
setattr(self, f[0], Signal(f[1], prefix + f[0]))
|
2012-01-06 05:20:44 -05:00
|
|
|
elif isinstance(f[1], Signal) or isinstance(f[1], Record):
|
|
|
|
setattr(self, f[0], f[1])
|
|
|
|
elif isinstance(f[1], list):
|
2012-01-16 13:38:14 -05:00
|
|
|
setattr(self, f[0], Record(f[1], prefix + f[0]))
|
2012-01-06 05:20:44 -05:00
|
|
|
else:
|
|
|
|
raise TypeError
|
2012-01-09 13:16:11 -05:00
|
|
|
if len(f) == 3:
|
|
|
|
self.field_order.append((f[0], f[2]))
|
|
|
|
else:
|
|
|
|
self.field_order.append((f[0], 1))
|
2012-01-06 05:20:44 -05:00
|
|
|
else:
|
2012-11-29 15:22:38 -05:00
|
|
|
setattr(self, f, Signal(1, prefix + f))
|
2012-01-09 13:16:11 -05:00
|
|
|
self.field_order.append((f, 1))
|
2012-01-06 05:20:44 -05:00
|
|
|
|
2013-03-23 19:50:33 -04:00
|
|
|
def eq(self, other):
|
|
|
|
return [getattr(self, key).eq(getattr(other, key))
|
|
|
|
for key, a in self.field_order]
|
|
|
|
|
2012-01-09 09:14:42 -05:00
|
|
|
def layout(self):
|
2012-01-06 05:20:44 -05:00
|
|
|
l = []
|
2012-01-09 13:16:11 -05:00
|
|
|
for key, alignment in self.field_order:
|
2013-03-23 19:51:01 -04:00
|
|
|
e = getattr(self, key)
|
2012-01-06 05:20:44 -05:00
|
|
|
if isinstance(e, Signal):
|
2012-11-29 15:22:38 -05:00
|
|
|
l.append((key, (e.nbits, e.signed), alignment))
|
2012-01-06 05:20:44 -05:00
|
|
|
elif isinstance(e, Record):
|
2012-01-09 13:16:11 -05:00
|
|
|
l.append((key, e.layout(), alignment))
|
2012-01-06 05:20:44 -05:00
|
|
|
return l
|
|
|
|
|
|
|
|
def copy(self, name=None):
|
2012-01-16 12:09:52 -05:00
|
|
|
return Record(self.layout(), name)
|
2012-01-06 05:20:44 -05:00
|
|
|
|
2012-01-09 13:16:11 -05:00
|
|
|
def get_alignment(self, name):
|
|
|
|
return list(filter(lambda x: x[0] == name, self.field_order))[0][1]
|
|
|
|
|
2012-01-06 05:20:44 -05:00
|
|
|
def subrecord(self, *descr):
|
2012-01-09 09:14:42 -05:00
|
|
|
fields = []
|
2012-01-06 05:20:44 -05:00
|
|
|
for item in descr:
|
2012-02-14 07:12:43 -05:00
|
|
|
path = item.split("/")
|
2012-01-06 05:20:44 -05:00
|
|
|
last = path.pop()
|
|
|
|
pos_self = self
|
|
|
|
pos_fields = fields
|
|
|
|
for hop in path:
|
|
|
|
pos_self = getattr(pos_self, hop)
|
2012-01-09 09:17:24 -05:00
|
|
|
lu = list(filter(lambda x: x[0] == hop, pos_fields))
|
2012-01-06 05:20:44 -05:00
|
|
|
try:
|
2012-01-09 09:14:42 -05:00
|
|
|
pos_fields = lu[0][1]
|
|
|
|
except IndexError:
|
|
|
|
n = []
|
|
|
|
pos_fields.append((hop, n))
|
|
|
|
pos_fields = n
|
|
|
|
if not isinstance(pos_fields, list):
|
2012-01-06 05:20:44 -05:00
|
|
|
raise ValueError
|
2012-01-09 09:14:42 -05:00
|
|
|
if len(list(filter(lambda x: x[0] == last, pos_fields))) > 0:
|
2012-01-06 05:20:44 -05:00
|
|
|
raise ValueError
|
2012-01-09 13:16:11 -05:00
|
|
|
pos_fields.append((last, getattr(pos_self, last), pos_self.get_alignment(last)))
|
2012-01-09 09:14:42 -05:00
|
|
|
return Record(fields, "subrecord")
|
2012-01-06 05:20:44 -05:00
|
|
|
|
2012-01-06 17:00:23 -05:00
|
|
|
def compatible(self, other):
|
2012-01-08 07:56:11 -05:00
|
|
|
tpl1 = self.flatten()
|
|
|
|
tpl2 = other.flatten()
|
|
|
|
return len(tpl1) == len(tpl2)
|
2012-01-06 17:00:23 -05:00
|
|
|
|
2012-01-10 11:10:03 -05:00
|
|
|
def flatten(self, align=False, offset=0, return_offset=False):
|
2012-01-06 05:20:44 -05:00
|
|
|
l = []
|
2012-01-09 13:16:11 -05:00
|
|
|
for key, alignment in self.field_order:
|
|
|
|
if align:
|
|
|
|
pad_size = alignment - (offset % alignment)
|
|
|
|
if pad_size < alignment:
|
2012-11-28 17:18:43 -05:00
|
|
|
l.append(Replicate(0, pad_size))
|
2012-01-09 13:16:11 -05:00
|
|
|
offset += pad_size
|
|
|
|
|
2013-03-23 19:51:01 -04:00
|
|
|
e = getattr(self, key)
|
2012-01-06 05:20:44 -05:00
|
|
|
if isinstance(e, Signal):
|
2012-01-09 13:16:11 -05:00
|
|
|
added = [e]
|
2012-01-06 05:20:44 -05:00
|
|
|
elif isinstance(e, Record):
|
2012-01-09 13:16:11 -05:00
|
|
|
added = e.flatten(align, offset)
|
|
|
|
else:
|
|
|
|
raise TypeError
|
|
|
|
for x in added:
|
2012-11-29 15:22:38 -05:00
|
|
|
offset += value_bits_sign(x)[0]
|
2012-01-09 13:16:11 -05:00
|
|
|
l += added
|
2012-01-10 11:10:03 -05:00
|
|
|
if return_offset:
|
|
|
|
return (l, offset)
|
|
|
|
else:
|
|
|
|
return l
|
2012-01-06 18:33:28 -05:00
|
|
|
|
2012-02-11 14:55:23 -05:00
|
|
|
def to_signal(self, assignment_list, sig_out, align=False):
|
|
|
|
flattened, length = self.flatten(align, return_offset=True)
|
2012-11-29 15:22:38 -05:00
|
|
|
raw = Signal(length)
|
2012-02-11 14:55:23 -05:00
|
|
|
if sig_out:
|
|
|
|
assignment_list.append(raw.eq(Cat(*flattened)))
|
|
|
|
else:
|
|
|
|
assignment_list.append(Cat(*flattened).eq(raw))
|
|
|
|
return raw
|
|
|
|
|
2012-01-06 18:33:28 -05:00
|
|
|
def __repr__(self):
|
2012-06-08 11:49:31 -04:00
|
|
|
return "<Record " + repr(self.layout()) + ">"
|