2012-11-10 16:59:14 -05:00
|
|
|
import ast
|
2012-11-23 06:41:50 -05:00
|
|
|
from itertools import zip_longest
|
2012-11-10 16:59:14 -05:00
|
|
|
|
2013-05-22 11:11:09 -04:00
|
|
|
from migen.fhdl.std import *
|
2012-12-14 09:55:38 -05:00
|
|
|
from migen.flow.actor import Source, Sink
|
|
|
|
from migen.flow.transactions import *
|
2012-11-23 06:41:50 -05:00
|
|
|
from migen.bus import wishbone
|
2012-11-17 13:54:50 -05:00
|
|
|
from migen.bus.transactions import *
|
2013-06-28 13:03:55 -04:00
|
|
|
from migen.pytholite.util import *
|
2012-11-16 17:48:41 -05:00
|
|
|
from migen.pytholite.expr import ExprCompiler
|
2012-11-10 15:51:19 -05:00
|
|
|
|
2012-11-16 17:48:41 -05:00
|
|
|
class _TokenPullExprCompiler(ExprCompiler):
|
|
|
|
def __init__(self, symdict, modelname, ep):
|
2012-12-18 08:54:33 -05:00
|
|
|
ExprCompiler.__init__(self, symdict)
|
2012-11-16 17:48:41 -05:00
|
|
|
self.modelname = modelname
|
|
|
|
self.ep = ep
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-16 17:48:41 -05:00
|
|
|
def visit_expr_subscript(self, node):
|
|
|
|
# check that we are subscripting <modelname>.value
|
|
|
|
if not isinstance(node.value, ast.Attribute) \
|
|
|
|
or node.value.attr != "value" \
|
|
|
|
or not isinstance(node.value.value, ast.Name) \
|
|
|
|
or node.value.value.id != self.modelname:
|
|
|
|
raise NotImplementedError
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-16 17:48:41 -05:00
|
|
|
if not isinstance(node.slice, ast.Index):
|
|
|
|
raise NotImplementedError
|
2013-06-28 13:03:55 -04:00
|
|
|
field = eval_ast(node.slice.value, self.symdict)
|
2013-04-10 13:12:42 -04:00
|
|
|
signal = getattr(self.ep.payload, field)
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-16 17:48:41 -05:00
|
|
|
return signal
|
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
def _gen_df_io(compiler, modelname, to_model, from_model):
|
2013-06-28 13:03:55 -04:00
|
|
|
epname = eval_ast(to_model["endpoint"], compiler.symdict)
|
2012-11-23 06:41:50 -05:00
|
|
|
values = to_model["value"]
|
2013-06-28 13:03:55 -04:00
|
|
|
idle_wait = eval_ast(to_model["idle_wait"], compiler.symdict)
|
2013-04-10 13:12:42 -04:00
|
|
|
ep = getattr(compiler.ioo, epname)
|
2012-12-14 13:16:22 -05:00
|
|
|
if idle_wait:
|
|
|
|
state = [compiler.ioo.busy.eq(0)]
|
|
|
|
else:
|
|
|
|
state = []
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
if isinstance(values, ast.Name) and values.id == "None":
|
2012-11-16 13:24:45 -05:00
|
|
|
# token pull from sink
|
2012-11-16 17:48:41 -05:00
|
|
|
if not isinstance(ep, Sink):
|
|
|
|
raise TypeError("Attempted to pull from source")
|
|
|
|
ec = _TokenPullExprCompiler(compiler.symdict, modelname, ep)
|
|
|
|
for target_regs, expr in from_model:
|
|
|
|
cexpr = ec.visit_expr(expr)
|
|
|
|
state += [reg.load(cexpr) for reg in target_regs]
|
|
|
|
state += [
|
|
|
|
ep.ack.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
If(~ep.stb, id_next_state(state))
|
2012-11-16 17:48:41 -05:00
|
|
|
]
|
|
|
|
return [state], [state]
|
2012-11-16 13:24:45 -05:00
|
|
|
else:
|
|
|
|
# token push to source
|
2012-11-16 17:48:41 -05:00
|
|
|
if not isinstance(ep, Source):
|
|
|
|
raise TypeError("Attempted to push to sink")
|
2012-11-16 13:24:45 -05:00
|
|
|
if from_model:
|
|
|
|
raise TypeError("Attempted to read from pushed token")
|
2012-11-23 06:41:50 -05:00
|
|
|
if not isinstance(values, ast.Dict):
|
2012-11-16 13:24:45 -05:00
|
|
|
raise NotImplementedError
|
2012-11-23 06:41:50 -05:00
|
|
|
for akey, value in zip(values.keys, values.values):
|
2013-06-28 13:03:55 -04:00
|
|
|
key = eval_ast(akey, compiler.symdict)
|
2013-04-10 13:12:42 -04:00
|
|
|
signal = getattr(ep.payload, key)
|
2012-11-16 13:24:45 -05:00
|
|
|
state.append(signal.eq(compiler.ec.visit_expr(value)))
|
|
|
|
state += [
|
|
|
|
ep.stb.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
If(~ep.ack, id_next_state(state))
|
2012-11-16 13:24:45 -05:00
|
|
|
]
|
|
|
|
return [state], [state]
|
2012-11-10 16:59:14 -05:00
|
|
|
|
2012-11-23 07:09:55 -05:00
|
|
|
class _BusReadExprCompiler(ExprCompiler):
|
|
|
|
def __init__(self, symdict, modelname, data_signal):
|
2012-12-18 08:54:33 -05:00
|
|
|
ExprCompiler.__init__(self, symdict)
|
2012-11-23 07:09:55 -05:00
|
|
|
self.modelname = modelname
|
|
|
|
self.data_signal = data_signal
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-23 07:09:55 -05:00
|
|
|
def visit_expr_attribute(self, node):
|
|
|
|
# recognize <modelname>.data as the bus read signal, raise exception otherwise
|
|
|
|
if not isinstance(node.value, ast.Name) \
|
|
|
|
or node.value.id != self.modelname \
|
|
|
|
or node.attr != "data":
|
|
|
|
raise NotImplementedError
|
|
|
|
return self.data_signal
|
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
def _gen_wishbone_io(compiler, modelname, model, to_model, from_model, bus):
|
|
|
|
state = [
|
|
|
|
bus.cyc.eq(1),
|
|
|
|
bus.stb.eq(1),
|
|
|
|
bus.adr.eq(compiler.ec.visit_expr(to_model["address"])),
|
|
|
|
]
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
if model == TWrite:
|
|
|
|
if from_model:
|
|
|
|
raise TypeError("Attempted to read from write transaction")
|
2012-11-23 07:40:46 -05:00
|
|
|
state += [
|
|
|
|
bus.we.eq(1),
|
|
|
|
bus.dat_w.eq(compiler.ec.visit_expr(to_model["data"]))
|
|
|
|
]
|
|
|
|
sel = to_model["sel"]
|
|
|
|
if isinstance(sel, ast.Name) and sel.id == "None":
|
2013-07-27 09:38:48 -04:00
|
|
|
nbytes = (flen(bus.dat_w) + 7)//8
|
2012-11-23 07:40:46 -05:00
|
|
|
state.append(bus.sel.eq(2**nbytes-1))
|
|
|
|
else:
|
|
|
|
state.append(bus.sel.eq(compiler.ec.visit_expr(sel)))
|
2012-11-23 06:41:50 -05:00
|
|
|
else:
|
2012-11-23 07:09:55 -05:00
|
|
|
ec = _BusReadExprCompiler(compiler.symdict, modelname, bus.dat_r)
|
|
|
|
for target_regs, expr in from_model:
|
|
|
|
cexpr = ec.visit_expr(expr)
|
|
|
|
state += [reg.load(cexpr) for reg in target_regs]
|
2013-06-25 16:17:39 -04:00
|
|
|
state.append(If(~bus.ack, id_next_state(state)))
|
2012-11-23 06:41:50 -05:00
|
|
|
return [state], [state]
|
|
|
|
|
2012-11-23 14:36:09 -05:00
|
|
|
def _gen_memory_io(compiler, modelname, model, to_model, from_model, port):
|
|
|
|
s1 = [port.adr.eq(compiler.ec.visit_expr(to_model["address"]))]
|
|
|
|
if model == TWrite:
|
|
|
|
if from_model:
|
|
|
|
raise TypeError("Attempted to read from write transaction")
|
|
|
|
s1.append(port.dat_w.eq(compiler.ec.visit_expr(to_model["data"])))
|
|
|
|
sel = to_model["sel"]
|
|
|
|
if isinstance(sel, ast.Name) and sel.id == "None":
|
2013-07-27 09:38:48 -04:00
|
|
|
nbytes = (flen(port.dat_w) + 7)//8
|
2012-11-23 14:36:09 -05:00
|
|
|
s1.append(port.we.eq(2**nbytes-1))
|
|
|
|
else:
|
|
|
|
s1.append(port.we.eq(compiler.ec.visit_expr(sel)))
|
|
|
|
return [s1], [s1]
|
|
|
|
else:
|
|
|
|
s2 = []
|
2013-06-25 16:17:39 -04:00
|
|
|
s1.append(id_next_state(s2))
|
2012-11-23 14:36:09 -05:00
|
|
|
ec = _BusReadExprCompiler(compiler.symdict, modelname, port.dat_r)
|
|
|
|
for target_regs, expr in from_model:
|
|
|
|
cexpr = ec.visit_expr(expr)
|
|
|
|
s2 += [reg.load(cexpr) for reg in target_regs]
|
|
|
|
return [s1, s2], [s2]
|
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
def _gen_bus_io(compiler, modelname, model, to_model, from_model):
|
2013-06-28 13:03:55 -04:00
|
|
|
busname = eval_ast(to_model["busname"], compiler.symdict)
|
2012-11-23 06:41:50 -05:00
|
|
|
if busname is None:
|
2013-04-10 17:42:46 -04:00
|
|
|
buses = compiler.ioo.get_buses()
|
|
|
|
if len(buses) != 1:
|
2012-11-23 06:41:50 -05:00
|
|
|
raise TypeError("Bus name not specified")
|
2013-04-10 17:42:46 -04:00
|
|
|
bus = list(buses.values())[0]
|
2012-11-23 06:41:50 -05:00
|
|
|
else:
|
2013-04-10 17:42:46 -04:00
|
|
|
bus = getattr(compiler.ioo, busname)
|
2012-11-23 06:41:50 -05:00
|
|
|
if isinstance(bus, wishbone.Interface):
|
|
|
|
return _gen_wishbone_io(compiler, modelname, model, to_model, from_model, bus)
|
2012-11-23 14:36:09 -05:00
|
|
|
elif isinstance(bus, Memory):
|
|
|
|
port = compiler.ioo.memory_ports[bus]
|
|
|
|
return _gen_memory_io(compiler, modelname, model, to_model, from_model, port)
|
2012-11-23 06:41:50 -05:00
|
|
|
else:
|
|
|
|
raise NotImplementedError("Unsupported bus")
|
|
|
|
|
|
|
|
def _decode_args(desc, args, args_kw):
|
|
|
|
d = {}
|
|
|
|
argnames = set()
|
|
|
|
for param, value in zip_longest(desc, args):
|
|
|
|
if param is None:
|
|
|
|
raise TypeError("Too many arguments")
|
|
|
|
if isinstance(param, tuple):
|
|
|
|
name, default = param
|
|
|
|
else:
|
|
|
|
name, default = param, None
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
# build the set of argument names at the same time
|
|
|
|
argnames.add(name)
|
2014-10-17 05:08:37 -04:00
|
|
|
|
2012-11-23 06:41:50 -05:00
|
|
|
if value is None:
|
|
|
|
if default is None:
|
|
|
|
raise TypeError("No default value for parameter " + name)
|
|
|
|
else:
|
|
|
|
d[name] = default
|
|
|
|
else:
|
|
|
|
d[name] = value
|
|
|
|
for akw in args_kw:
|
|
|
|
if akw.arg not in argnames:
|
|
|
|
raise TypeError("Parameter " + akw.arg + " does not exist")
|
|
|
|
d[akw.arg] = akw.value
|
|
|
|
return d
|
|
|
|
|
|
|
|
def gen_io(compiler, modelname, model, to_model, to_model_kw, from_model):
|
2012-11-16 13:24:45 -05:00
|
|
|
if model == Token:
|
2012-11-23 06:41:50 -05:00
|
|
|
desc = [
|
|
|
|
"endpoint",
|
2013-06-28 13:03:55 -04:00
|
|
|
("value", ast.Name("None", ast.Load(), lineno=0, col_offset=0)),
|
|
|
|
("idle_wait", ast.Name("False", ast.Load(), lineno=0, col_offset=0))
|
2012-11-23 06:41:50 -05:00
|
|
|
]
|
|
|
|
args = _decode_args(desc, to_model, to_model_kw)
|
|
|
|
return _gen_df_io(compiler, modelname, args, from_model)
|
|
|
|
elif model == TRead or model == TWrite:
|
|
|
|
desc = [
|
|
|
|
"address",
|
|
|
|
("data", ast.Num(0)),
|
2013-06-28 13:03:55 -04:00
|
|
|
("sel", ast.Name("None", ast.Load(), lineno=0, col_offset=0)),
|
|
|
|
("busname", ast.Name("None", ast.Load(), lineno=0, col_offset=0))
|
2012-11-23 06:41:50 -05:00
|
|
|
]
|
|
|
|
args = _decode_args(desc, to_model, to_model_kw)
|
|
|
|
return _gen_bus_io(compiler, modelname, model, args, from_model)
|
2012-11-16 13:24:45 -05:00
|
|
|
else:
|
|
|
|
raise NotImplementedError
|