diff --git a/examples/divider_conv.py b/examples/divider_conv.py index 0531ad42e..988e0b8a6 100644 --- a/examples/divider_conv.py +++ b/examples/divider_conv.py @@ -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 index 000000000..2215a8164 --- /dev/null +++ b/examples/simple_gpio.py @@ -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 index 000000000..e605415b1 --- /dev/null +++ b/migen/bank/csrgen.py @@ -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 index 000000000..accb18232 --- /dev/null +++ b/migen/bank/description.py @@ -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 diff --git a/migen/fhdl/convtools.py b/migen/fhdl/convtools.py index df2855b7e..bb71ed4fc 100644 --- a/migen/fhdl/convtools.py +++ b/migen/fhdl/convtools.py @@ -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 diff --git a/migen/fhdl/structure.py b/migen/fhdl/structure.py index db37eee7f..8e924b4b2 100644 --- a/migen/fhdl/structure.py +++ b/migen/fhdl/structure.py @@ -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 diff --git a/migen/fhdl/verilog.py b/migen/fhdl/verilog.py index e5acfd1e2..d3e291a4b 100644 --- a/migen/fhdl/verilog.py +++ b/migen/fhdl/verilog.py @@ -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