New bidirectional-capable Record API
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 1 Apr 2013 19:53:33 +0000 (21:53 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 1 Apr 2013 19:53:33 +0000 (21:53 +0200)
examples/basic/record.py [new file with mode: 0644]
examples/basic/using_record.py [deleted file]
migen/genlib/record.py

diff --git a/examples/basic/record.py b/examples/basic/record.py
new file mode 100644 (file)
index 0000000..dd7a905
--- /dev/null
@@ -0,0 +1,24 @@
+from migen.fhdl.structure import *
+from migen.fhdl.module import Module
+from migen.fhdl import verilog
+from migen.genlib.record import *
+
+L = [
+       ("position", [
+                       ("x", 10, DIR_M_TO_S),
+                       ("y", 10, DIR_M_TO_S),
+       ]),
+       ("color", 32, DIR_M_TO_S),
+       ("stb", 1, DIR_M_TO_S),
+       ("ack", 1, DIR_S_TO_M)
+]
+
+class Test(Module):
+       def __init__(self):
+               master = Record(L)
+               slave = Record(L)
+               self.comb += master.connect(slave)
+
+print(verilog.convert(Test()))
+print(layout_len(L))
+print(layout_partial(L, "position/x", "color"))
diff --git a/examples/basic/using_record.py b/examples/basic/using_record.py
deleted file mode 100644 (file)
index 15988e8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-from migen.fhdl.structure import *
-from migen.genlib.record import *
-
-L = [
-       ("x", 10, 8),
-       ("y", 10, 8),
-       ("level2", [
-               ("a", 5, 32),
-               ("b", 5, 16)
-       ])
-]
-
-myrec = Record(L)
-print(myrec.flatten())
-print(myrec.flatten(True))
-s = myrec.subrecord("level2/a", "x")
-print(s.flatten())
-print(s.level2.layout())
-myrec2 = myrec.copy()
-print(myrec2.flatten())
index adf9440b1871ed8137153c7f0175803dc2b3eb59..f1a22c7061791e0be1d93ba766de1726fbc688c1 100644 (file)
 from migen.fhdl.structure import *
-from migen.fhdl.tools import value_bits_sign
+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
+
+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=""):
-               self.name = name
-               self.field_order = []
+       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 layout:
-                       if isinstance(f, tuple):
-                               if isinstance(f[1], (int, tuple)):
-                                       setattr(self, f[0], Signal(f[1], prefix + f[0]))
-                               elif isinstance(f[1], Signal) or isinstance(f[1], Record):
-                                       setattr(self, f[0], f[1])
-                               elif isinstance(f[1], list):
-                                       setattr(self, f[0], Record(f[1], prefix + f[0]))
-                               else:
-                                       raise TypeError
-                               if len(f) == 3:
-                                       self.field_order.append((f[0], f[2]))
+               for f in self.layout:
+                       if isinstance(f[1], (int, tuple)): # cases 1/2
+                               if(len(f) == 3):
+                                       fname, fsize, fdirection = f
                                else:
-                                       self.field_order.append((f[0], 1))
+                                       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:
-                               setattr(self, f, Signal(1, prefix + f))
-                               self.field_order.append((f, 1))
+                               raise TypeError
+                       setattr(self, fname, finst)
 
        def eq(self, other):
-               return [getattr(self, key).eq(getattr(other, key))
-                 for key, a in self.field_order]
-
-       def layout(self):
-               l = []
-               for key, alignment in self.field_order:
-                       e = getattr(self, key)
-                       if isinstance(e, Signal):
-                               l.append((key, (e.nbits, e.signed), alignment))
-                       elif isinstance(e, Record):
-                               l.append((key, e.layout(), alignment))
-               return l
-       
-       def copy(self, name=None):
-               return Record(self.layout(), name)
-       
-       def get_alignment(self, name):
-               return list(filter(lambda x: x[0] == name, self.field_order))[0][1]
-       
-       def subrecord(self, *descr):
-               fields = []
-               for item in descr:
-                       path = item.split("/")
-                       last = path.pop()
-                       pos_self = self
-                       pos_fields = fields
-                       for hop in path:
-                               pos_self = getattr(pos_self, hop)
-                               lu = list(filter(lambda x: x[0] == hop, pos_fields))
-                               try:
-                                       pos_fields = lu[0][1]
-                               except IndexError:
-                                       n = []
-                                       pos_fields.append((hop, n))
-                                       pos_fields = n
-                               if not isinstance(pos_fields, list):
-                                       raise ValueError
-                       if len(list(filter(lambda x: x[0] == last, pos_fields))) > 0:
-                               raise ValueError
-                       pos_fields.append((last, getattr(pos_self, last), pos_self.get_alignment(last)))
-               return Record(fields, "subrecord")
+               return [getattr(self, f[0]).eq(getattr(other, f[0]))
+                 for f in self.layout if hasattr(other, f[0])]
        
-       def compatible(self, other):
-               tpl1 = self.flatten()
-               tpl2 = other.flatten()
-               return len(tpl1) == len(tpl2)
-       
-       def flatten(self, align=False, offset=0, return_offset=False):
-               l = []
-               for key, alignment in self.field_order:
-                       if align:
-                               pad_size = alignment - (offset % alignment)
-                               if pad_size < alignment:
-                                       l.append(Replicate(0, pad_size))
-                                       offset += pad_size
-                       
-                       e = getattr(self, key)
+       def flatten(self):
+               r = []
+               for f in self.layout:                   
+                       e = getattr(self, f[0])
                        if isinstance(e, Signal):
-                               added = [e]
+                               r.append(e)
                        elif isinstance(e, Record):
-                               added = e.flatten(align, offset)
+                               r += e.flatten()
                        else:
                                raise TypeError
-                       for x in added:
-                               offset += value_bits_sign(x)[0]
-                       l += added
-               if return_offset:
-                       return (l, offset)
-               else:
-                       return l
-       
-       def to_signal(self, assignment_list, sig_out, align=False):
-               flattened, length = self.flatten(align, return_offset=True)
-               raw = Signal(length)
-               if sig_out:
-                       assignment_list.append(raw.eq(Cat(*flattened)))
-               else:
-                       assignment_list.append(Cat(*flattened).eq(raw))
-               return raw
+               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 " + repr(self.layout()) + ">"
+               return "<Record " + ":".join(f[0] for f in self.layout) + " at " + hex(id(self)) + ">"