bank: support registers larger than the bus word width
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 6 Feb 2012 15:15:27 +0000 (16:15 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 6 Feb 2012 15:15:27 +0000 (16:15 +0100)
examples/simple_gpio.py
migen/bank/csrgen.py
migen/bank/description.py

index 426df02ccc966dbac2bcec43827e15e1e92bd13c..b53a323a70db64d6902a65b5605938fc3af3f1ba 100644 (file)
@@ -3,7 +3,7 @@ from migen.fhdl import verilog
 from migen.bank import description, csrgen
 
 ninputs = 4
-noutputs = 4
+noutputs = 31
 
 oreg = description.RegisterField("o", noutputs)
 ireg = description.RegisterRaw("i", ninputs)
index 894579350de5459bbaba57ffc39c93cbfdf7972e..6007ab50701e7b8e84af42acc29053f5ce5cfcf6 100644 (file)
@@ -15,11 +15,12 @@ class Bank:
                sel = Signal()
                comb.append(sel.eq(self.interface.a_i[9:] == Constant(self.address, BV(5))))
                
-               nbits = bits_for(len(self.description)-1)
+               desc_exp = expand_description(self.description, 8)
+               nbits = bits_for(len(desc_exp)-1)
                
                # Bus writes
                bwcases = []
-               for i, reg in enumerate(self.description):
+               for i, reg in enumerate(desc_exp):
                        if isinstance(reg, RegisterRaw):
                                comb.append(reg.r.eq(self.interface.d_i[:reg.size]))
                                comb.append(reg.re.eq(sel & \
@@ -27,9 +28,11 @@ class Bank:
                                        (self.interface.a_i[:nbits] == Constant(i, BV(nbits)))))
                        elif isinstance(reg, RegisterFields):
                                bwra = [Constant(i, BV(nbits))]
-                               for j, field in enumerate(reg.fields):
+                               offset = 0
+                               for field in reg.fields:
                                        if field.access_bus == WRITE_ONLY or field.access_bus == READ_WRITE:
-                                               bwra.append(field.storage.eq(self.interface.d_i[j]))
+                                               bwra.append(field.storage.eq(self.interface.d_i[offset:offset+field.size]))
+                                       offset += field.size
                                if len(bwra) > 1:
                                        bwcases.append(bwra)
                        else:
@@ -39,13 +42,13 @@ class Bank:
                
                # Bus reads
                brcases = []
-               for i, reg in enumerate(self.description):
+               for i, reg in enumerate(desc_exp):
                        if isinstance(reg, RegisterRaw):
                                brcases.append([Constant(i, BV(nbits)), self.interface.d_o.eq(reg.w)])
                        elif isinstance(reg, RegisterFields):
                                brs = []
                                reg_readable = False
-                               for j, field in enumerate(reg.fields):
+                               for field in reg.fields:
                                        if field.access_bus == READ_ONLY or field.access_bus == READ_WRITE:
                                                brs.append(field.storage)
                                                reg_readable = True
@@ -53,7 +56,7 @@ class Bank:
                                                brs.append(Constant(0, BV(field.size)))
                                if reg_readable:
                                        if len(brs) > 1:
-                                               brcases.append([Constant(i, BV(nbits)), self.interface.d_o.eq(f.Cat(*brs))])
+                                               brcases.append([Constant(i, BV(nbits)), self.interface.d_o.eq(Cat(*brs))])
                                        else:
                                                brcases.append([Constant(i, BV(nbits)), self.interface.d_o.eq(brs[0])])
                        else:
index 14d2d136d050fefa51fe6db22096e3979100e9cf..325738f71a750cfc393a0cb63cc247c5b9de860d 100644 (file)
@@ -32,3 +32,43 @@ class RegisterField(RegisterFields):
        def __init__(self, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
                self.field = Field(name, size, access_bus, access_dev, reset)
                RegisterFields.__init__(self, name, [self.field])
+
+class FieldAlias:
+       def __init__(self, f, start, end):
+               self.size = end - start
+               self.access_bus = f.access_bus
+               self.access_dev = f.access_dev
+               self.storage = f.storage[start:end]
+               # device access is through the original field
+
+def expand_description(description, busword):
+       d = []
+       for reg in description:
+               if isinstance(reg, RegisterRaw):
+                       if reg.size > busword:
+                               raise ValueError("Raw register larger than a bus word")
+                       d.append(reg)
+               elif isinstance(reg, RegisterFields):
+                       f = []
+                       size = 0
+                       for field in reg.fields:
+                               size += field.size
+                               if size > busword:
+                                       top = field.size
+                                       while size > busword:
+                                               slice1 = busword - size + top
+                                               slice2 = min(size - busword, busword)
+                                               if slice1:
+                                                       f.append(FieldAlias(field, top - slice1, top))
+                                                       top -= slice1
+                                               d.append(RegisterFields(reg.name, f))
+                                               f = [FieldAlias(field, top - slice2, top)]
+                                               top -= slice2
+                                               size -= busword
+                               else:
+                                       f.append(field)
+                       if f:
+                               d.append(RegisterFields(reg.name, f))
+               else:
+                       raise TypeError
+       return d