Case support + register bank generator
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 5 Dec 2011 16:43:56 +0000 (17:43 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 5 Dec 2011 16:43:56 +0000 (17:43 +0100)
examples/divider_conv.py
examples/simple_gpio.py [new file with mode: 0644]
migen/bank/csrgen.py [new file with mode: 0644]
migen/bank/description.py [new file with mode: 0644]
migen/fhdl/convtools.py
migen/fhdl/structure.py
migen/fhdl/verilog.py

index 0531ad42ee1a8af20deacee39081265dc0fb1034..988e0b8a65d786c31874878fd0827001a59badf6 100644 (file)
@@ -46,5 +46,5 @@ class Divider:
 
 d = Divider(32)
 f = d.GetFragment()
-o = verilog.Convert(f, {d.start_i, d.dividend_i, d.divisor_i}, {d.ready_o, d.quotient_o, d.remainder_o})
+o = verilog.Convert(f, {d.ready_o, d.quotient_o, d.remainder_o}, {d.start_i, d.dividend_i, d.divisor_i})
 print(o)
\ No newline at end of file
diff --git a/examples/simple_gpio.py b/examples/simple_gpio.py
new file mode 100644 (file)
index 0000000..2215a81
--- /dev/null
@@ -0,0 +1,25 @@
+from migen.fhdl import structure as f
+from migen.fhdl import verilog
+from migen.bank import description, csrgen
+
+ninputs = 4
+noutputs = 4
+
+oreg = description.Register("o")
+ofield = description.Field(oreg, "val", noutputs)
+ireg = description.Register("i")
+ifield = description.Field(ireg, "val", ninputs, description.READ_ONLY, description.WRITE_ONLY)
+
+# input path
+gpio_in = f.Signal(f.BV(ninputs), name="gpio_in")
+gpio_in_s = f.Signal(f.BV(ninputs), name="gpio_in_s") # synchronizer
+incomb = [f.Assign(ifield.dev_we, 1)]
+insync = [f.Assign(gpio_in_s, gpio_in), f.Assign(ifield.dev_w, gpio_in_s)]
+inf = f.Fragment(incomb, insync)
+
+bank = csrgen.Bank([oreg, ireg])
+f = bank.GetFragment() + inf
+i = bank.interface
+ofield.dev_r.name = "gpio_out"
+v = verilog.Convert(f, {i.d_o, ofield.dev_r}, {i.a_i, i.we_i, i.d_i, gpio_in})
+print(v)
\ No newline at end of file
diff --git a/migen/bank/csrgen.py b/migen/bank/csrgen.py
new file mode 100644 (file)
index 0000000..e605415
--- /dev/null
@@ -0,0 +1,72 @@
+from ..fhdl import structure as f
+from ..bus.csr import *
+from .description import *
+from functools import partial
+
+class Bank:
+       def __init__(self, description, address=0):
+               self.description = description
+               self.address = address
+               self.interface = Slave()
+               d = partial(f.Declare, self)
+               d("_sel")
+       
+       def GetFragment(self):
+               a = f.Assign
+               comb = []
+               sync = []
+               
+               comb.append(a(self._sel, self.interface.a_i[12:] == f.Constant(self.address, f.BV(4))))
+               
+               nregs = len(self.description)
+               nbits = f.BitsFor(nregs-1)
+               
+               # Bus writes
+               bwcases = []
+               for i in range(nregs):
+                       reg = self.description[i]
+                       nfields = len(reg.fields)
+                       bwra = []
+                       for j in range(nfields):
+                               field = reg.fields[j]
+                               if field.access_bus == WRITE_ONLY or field.access_bus == READ_WRITE:
+                                       bwra.append(a(field.storage, self.interface.d_i[j]))
+                       if bwra:
+                               bwcases.append((f.Constant(i, f.BV(nbits)), bwra))
+               if bwcases:
+                       sync.append(f.If(self._sel & self.interface.we_i, [f.Case(self.interface.a_i[:nbits], bwcases)]))
+               
+               # Bus reads
+               brcases = []
+               for i in range(nregs):
+                       reg = self.description[i]
+                       nfields = len(reg.fields)
+                       brs = []
+                       reg_readable = False
+                       for j in range(nfields):
+                               field = reg.fields[j]
+                               if field.access_bus == READ_ONLY or field.access_bus == READ_WRITE:
+                                       brs.append(field.storage)
+                                       reg_readable = True
+                               else:
+                                       brs.append(f.Constant(0, f.bv(field.size)))
+                       if reg_readable:
+                               if len(brs) > 1:
+                                       brcases.append((f.Constant(i, f.BV(nbits)), [a(self.interface.d_o, f.Cat(*brs))]))
+                               else:
+                                       brcases.append((f.Constant(i, f.BV(nbits)), [a(self.interface.d_o, brs[0])]))
+               if brcases:
+                       sync.append(a(self.interface.d_o, f.Constant(0, f.BV(32))))
+                       sync.append(f.If(self._sel, [f.Case(self.interface.a_i[:nbits], brcases)]))
+               else:
+                       comb.append(a(self.interface.d_o, f.Constant(0, f.BV(32))))
+               
+               # Device access
+               for reg in self.description:
+                       for field in reg.fields:
+                               if field.access_dev == READ_ONLY or field.access_dev == READ_WRITE:
+                                       comb.append(a(field.dev_r, field.storage))
+                               if field.access_dev == WRITE_ONLY or field.access_dev == READ_WRITE:
+                                       sync.append(f.If(field.dev_we, [a(field.storage, field.dev_w)]))
+               
+               return f.Fragment(comb, sync)
\ No newline at end of file
diff --git a/migen/bank/description.py b/migen/bank/description.py
new file mode 100644 (file)
index 0000000..accb182
--- /dev/null
@@ -0,0 +1,28 @@
+from ..fhdl import structure as f
+
+class Register:
+       def __init__(self, name):
+               self.name = name
+               self.fields = []
+       
+       def AddField(self, f):
+               self.fields.append(f)
+
+(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
+
+class Field:
+       def __init__(self, parent, name, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0):
+               self.parent = parent
+               self.name = name
+               self.size = size
+               self.access_bus = access_bus
+               self.access_dev = access_dev
+               self.reset = reset
+               fullname = parent.name + "_" + name
+               self.storage = f.Signal(f.BV(self.size), fullname)
+               if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE:
+                       self.dev_r = f.Signal(f.BV(self.size), fullname + "_r")
+               if self.access_dev == WRITE_ONLY or self.access_dev == READ_WRITE:
+                       self.dev_w = f.Signal(f.BV(self.size), fullname + "_w")
+                       self.dev_we = f.Signal(name=fullname + "_we")
+               self.parent.AddField(self)
\ No newline at end of file
index df2855b7eaf76910cffe21e7d50ac86d1f4931ce..bb71ed4fcae793c7ac14dd5c5292591782587237 100644 (file)
@@ -44,6 +44,9 @@ def ListSignals(node):
                return set().union(*l)
        elif isinstance(node, If):
                return ListSignals(node.cond) | ListSignals(node.t) | ListSignals(node.f)
+       elif isinstance(node, Case):
+               l = list(map(lambda x: ListSignals(x[1]), node.cases))
+               return ListSignals(node.test).union(*l).union(ListSignals(node.default))
        elif isinstance(node, Fragment):
                return ListSignals(node.comb) | ListSignals(node.sync)
        else:
@@ -64,6 +67,9 @@ def ListTargets(node):
                return set().union(*l)
        elif isinstance(node, If):
                return ListTargets(node.t) | ListTargets(node.f)
+       elif isinstance(node, Case):
+               l = list(map(lambda x: ListTargets(x[1]), node.cases))
+               return ListTargets(node.default).union(*l)
        else:
                raise TypeError
 
@@ -73,4 +79,4 @@ def InsertReset(rst, sl):
        for t in targets:
                if not t.variable:
                        resetcode.append(Assign(t, t.reset))
-       return If(rst == 1, resetcode, sl)
\ No newline at end of file
+       return If(rst, resetcode, sl)
\ No newline at end of file
index db37eee7f819975fac246140a461a562326c9dca..8e924b4b2be54deca218bfb553efeb06506c8e09 100644 (file)
@@ -195,9 +195,10 @@ class If:
                return r
 
 class Case:
-       def __init__(self, test, cases=[]):
+       def __init__(self, test, cases=[], default=StatementList()):
                self.test = test
-               self.cases = cases
+               self.cases = [(c[0], _sl(c[1])) for c in cases]
+               self.default = _sl(default)
 
 #
 
@@ -207,4 +208,7 @@ class Fragment:
                self.sync = _sl(sync)
        
        def __str__(self):
-               return "Comb:\n" + _indent(str(self.comb)) + "\nSync:\n" + _indent(str(self.sync))
\ No newline at end of file
+               return "Comb:\n" + _indent(str(self.comb)) + "\nSync:\n" + _indent(str(self.sync))
+       
+       def __add__(self, other):
+               return Fragment(self.comb.l + other.comb.l, self.sync.l + other.sync.l)
\ No newline at end of file
index e5acfd1e2533730a52c987736a68189b86d41392..d3e291a4b9486c0570e4236bd43d236bfab34e70 100644 (file)
@@ -2,7 +2,7 @@ from .structure import *
 from .convtools import *
 from functools import partial
 
-def Convert(f, ins, outs, name="top", clkname="sys_clk", rstname="sys_rst"):
+def Convert(f, outs=set(), ins=set(), name="top", clkname="sys_clk", rstname="sys_rst"):
        ns = Namespace()
        
        clks = Signal(name=clkname)
@@ -50,13 +50,21 @@ def Convert(f, ins, outs, name="top", clkname="sys_clk", rstname="sys_rst"):
                elif isinstance(node, StatementList):
                        return "".join(list(map(partial(printnode, level), node.l)))
                elif isinstance(node, If):
-                       r = "\t"*level + "if " + printnode(level, node.cond) + " begin\n"
+                       r = "\t"*level + "if (" + printnode(level, node.cond) + ") begin\n"
                        r += printnode(level + 1, node.t)
                        if node.f.l:
                                r += "\t"*level + "end else begin\n"
                                r += printnode(level + 1, node.f)
                        r += "\t"*level + "end\n"
                        return r
+               elif isinstance(node, Case):
+                       r = "\t"*level + "case (" + printnode(level, node.test) + ")\n"
+                       for case in node.cases:
+                               r += "\t"*(level + 1) + printnode(level, case[0]) + ": begin\n"
+                               r += printnode(level + 2, case[1])
+                               r += "\t"*(level + 1) + "end\n"
+                       r += "\t"*level + "endcase\n"
+                       return r
                else:
                        raise TypeError