Case support + register bank generator
This commit is contained in:
parent
458cfc8623
commit
ec51f09c98
|
@ -46,5 +46,5 @@ class Divider:
|
||||||
|
|
||||||
d = Divider(32)
|
d = Divider(32)
|
||||||
f = d.GetFragment()
|
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)
|
print(o)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -44,6 +44,9 @@ def ListSignals(node):
|
||||||
return set().union(*l)
|
return set().union(*l)
|
||||||
elif isinstance(node, If):
|
elif isinstance(node, If):
|
||||||
return ListSignals(node.cond) | ListSignals(node.t) | ListSignals(node.f)
|
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):
|
elif isinstance(node, Fragment):
|
||||||
return ListSignals(node.comb) | ListSignals(node.sync)
|
return ListSignals(node.comb) | ListSignals(node.sync)
|
||||||
else:
|
else:
|
||||||
|
@ -64,6 +67,9 @@ def ListTargets(node):
|
||||||
return set().union(*l)
|
return set().union(*l)
|
||||||
elif isinstance(node, If):
|
elif isinstance(node, If):
|
||||||
return ListTargets(node.t) | ListTargets(node.f)
|
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:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
|
@ -73,4 +79,4 @@ def InsertReset(rst, sl):
|
||||||
for t in targets:
|
for t in targets:
|
||||||
if not t.variable:
|
if not t.variable:
|
||||||
resetcode.append(Assign(t, t.reset))
|
resetcode.append(Assign(t, t.reset))
|
||||||
return If(rst == 1, resetcode, sl)
|
return If(rst, resetcode, sl)
|
|
@ -195,9 +195,10 @@ class If:
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class Case:
|
class Case:
|
||||||
def __init__(self, test, cases=[]):
|
def __init__(self, test, cases=[], default=StatementList()):
|
||||||
self.test = test
|
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):
|
def __str__(self):
|
||||||
return "Comb:\n" + _indent(str(self.comb)) + "\nSync:\n" + _indent(str(self.sync))
|
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)
|
|
@ -2,7 +2,7 @@ from .structure import *
|
||||||
from .convtools import *
|
from .convtools import *
|
||||||
from functools import partial
|
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()
|
ns = Namespace()
|
||||||
|
|
||||||
clks = Signal(name=clkname)
|
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):
|
elif isinstance(node, StatementList):
|
||||||
return "".join(list(map(partial(printnode, level), node.l)))
|
return "".join(list(map(partial(printnode, level), node.l)))
|
||||||
elif isinstance(node, If):
|
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)
|
r += printnode(level + 1, node.t)
|
||||||
if node.f.l:
|
if node.f.l:
|
||||||
r += "\t"*level + "end else begin\n"
|
r += "\t"*level + "end else begin\n"
|
||||||
r += printnode(level + 1, node.f)
|
r += printnode(level + 1, node.f)
|
||||||
r += "\t"*level + "end\n"
|
r += "\t"*level + "end\n"
|
||||||
return r
|
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:
|
else:
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue