Case support + register bank generator

This commit is contained in:
Sebastien Bourdeauducq 2011-12-05 17:43:56 +01:00
parent 458cfc8623
commit ec51f09c98
7 changed files with 150 additions and 7 deletions

View 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)

25
examples/simple_gpio.py Normal file
View File

@ -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)

72
migen/bank/csrgen.py Normal file
View File

@ -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)

28
migen/bank/description.py Normal file
View File

@ -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)

View 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)
return If(rst, resetcode, sl)

View 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)
#
@ -208,3 +209,6 @@ class Fragment:
def __str__(self):
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)

View 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