122 lines
2.9 KiB
Python
122 lines
2.9 KiB
Python
from migen.fhdl.structure import *
|
|
from migen.fhdl.tracer import get_obj_var_name
|
|
from migen.genlib.misc import optree
|
|
|
|
(DIR_NONE, DIR_S_TO_M, DIR_M_TO_S) = range(3)
|
|
|
|
# Possible layout elements:
|
|
# 1. (name, size)
|
|
# 2. (name, size, direction)
|
|
# 3. (name, sublayout)
|
|
# size can be an int, or a (int, bool) tuple for signed numbers
|
|
# sublayout must be a list
|
|
|
|
def layout_len(layout):
|
|
r = 0
|
|
for f in layout:
|
|
if isinstance(f[1], (int, tuple)): # cases 1/2
|
|
if(len(f) == 3):
|
|
fname, fsize, fdirection = f
|
|
else:
|
|
fname, fsize = f
|
|
elif isinstance(f[1], list): # case 3
|
|
fname, fsublayout = f
|
|
fsize = layout_len(fsublayout)
|
|
else:
|
|
raise TypeError
|
|
if isinstance(fsize, tuple):
|
|
r += fsize[0]
|
|
else:
|
|
r += fsize
|
|
return r
|
|
|
|
def layout_get(layout, name):
|
|
for f in layout:
|
|
if f[0] == name:
|
|
return f
|
|
raise KeyError(name)
|
|
|
|
def layout_partial(layout, *elements):
|
|
r = []
|
|
for path in elements:
|
|
path_s = path.split("/")
|
|
last = path_s.pop()
|
|
copy_ref = layout
|
|
insert_ref = r
|
|
for hop in path_s:
|
|
name, copy_ref = layout_get(copy_ref, hop)
|
|
try:
|
|
name, insert_ref = layout_get(insert_ref, hop)
|
|
except KeyError:
|
|
new_insert_ref = []
|
|
insert_ref.append((hop, new_insert_ref))
|
|
insert_ref = new_insert_ref
|
|
insert_ref.append(layout_get(copy_ref, last))
|
|
return r
|
|
|
|
class Record:
|
|
def __init__(self, layout, name=None):
|
|
self.name = get_obj_var_name(name, "")
|
|
self.layout = layout
|
|
|
|
if self.name:
|
|
prefix = self.name + "_"
|
|
else:
|
|
prefix = ""
|
|
for f in self.layout:
|
|
if isinstance(f[1], (int, tuple)): # cases 1/2
|
|
if(len(f) == 3):
|
|
fname, fsize, fdirection = f
|
|
else:
|
|
fname, fsize = f
|
|
finst = Signal(fsize, name=prefix + fname)
|
|
elif isinstance(f[1], list): # case 3
|
|
fname, fsublayout = f
|
|
finst = Record(fsublayout, prefix + fname)
|
|
else:
|
|
raise TypeError
|
|
setattr(self, fname, finst)
|
|
|
|
def eq(self, other):
|
|
return [getattr(self, f[0]).eq(getattr(other, f[0]))
|
|
for f in self.layout if hasattr(other, f[0])]
|
|
|
|
def flatten(self):
|
|
r = []
|
|
for f in self.layout:
|
|
e = getattr(self, f[0])
|
|
if isinstance(e, Signal):
|
|
r.append(e)
|
|
elif isinstance(e, Record):
|
|
r += e.flatten()
|
|
else:
|
|
raise TypeError
|
|
return r
|
|
|
|
def raw_bits(self):
|
|
return Cat(*self.flatten())
|
|
|
|
def connect(self, *slaves):
|
|
r = []
|
|
for f in self.layout:
|
|
field = f[0]
|
|
self_e = getattr(self, field)
|
|
if isinstance(self_e, Signal):
|
|
direction = f[2]
|
|
if direction == DIR_M_TO_S:
|
|
r += [getattr(slave, field).eq(self_e) for slave in slaves]
|
|
elif direction == DIR_S_TO_M:
|
|
r.append(self_e.eq(optree("|", [getattr(slave, field) for slave in slaves])))
|
|
else:
|
|
raise TypeError
|
|
else:
|
|
for slave in slaves:
|
|
r += self_e.connect(getattr(slave, field))
|
|
return r
|
|
|
|
def __len__(self):
|
|
return layout_len(self.layout)
|
|
|
|
def __repr__(self):
|
|
return "<Record " + ":".join(f[0] for f in self.layout) + " at " + hex(id(self)) + ">"
|