pytholite/io: support Wishbone writes
This commit is contained in:
parent
f098c5c695
commit
0b24a2ff36
|
@ -1,8 +1,10 @@
|
||||||
import ast
|
import ast
|
||||||
|
from itertools import zip_longest
|
||||||
|
|
||||||
from migen.fhdl.structure import *
|
from migen.fhdl.structure import *
|
||||||
from migen.uio.ioo import UnifiedIOObject
|
from migen.uio.ioo import UnifiedIOObject
|
||||||
from migen.actorlib.sim import *
|
from migen.actorlib.sim import *
|
||||||
|
from migen.bus import wishbone
|
||||||
from migen.bus.transactions import *
|
from migen.bus.transactions import *
|
||||||
from migen.pytholite.fsm import *
|
from migen.pytholite.fsm import *
|
||||||
from migen.pytholite.expr import ExprCompiler
|
from migen.pytholite.expr import ExprCompiler
|
||||||
|
@ -32,14 +34,12 @@ class _TokenPullExprCompiler(ExprCompiler):
|
||||||
|
|
||||||
return signal
|
return signal
|
||||||
|
|
||||||
def gen_df_io(compiler, modelname, to_model, from_model):
|
def _gen_df_io(compiler, modelname, to_model, from_model):
|
||||||
if len(to_model) == 1 or len(to_model) == 2:
|
epname = ast.literal_eval(to_model["endpoint"])
|
||||||
epname = ast.literal_eval(to_model[0])
|
values = to_model["value"]
|
||||||
ep = compiler.ioo.endpoints[epname]
|
ep = compiler.ioo.endpoints[epname]
|
||||||
else:
|
|
||||||
raise TypeError("Token() takes 1 or 2 arguments")
|
|
||||||
|
|
||||||
if len(to_model) == 1:
|
if isinstance(values, ast.Name) and values.id == "None":
|
||||||
# token pull from sink
|
# token pull from sink
|
||||||
if not isinstance(ep, Sink):
|
if not isinstance(ep, Sink):
|
||||||
raise TypeError("Attempted to pull from source")
|
raise TypeError("Attempted to pull from source")
|
||||||
|
@ -59,11 +59,10 @@ def gen_df_io(compiler, modelname, to_model, from_model):
|
||||||
raise TypeError("Attempted to push to sink")
|
raise TypeError("Attempted to push to sink")
|
||||||
if from_model:
|
if from_model:
|
||||||
raise TypeError("Attempted to read from pushed token")
|
raise TypeError("Attempted to read from pushed token")
|
||||||
d = to_model[1]
|
if not isinstance(values, ast.Dict):
|
||||||
if not isinstance(d, ast.Dict):
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
state = []
|
state = []
|
||||||
for akey, value in zip(d.keys, d.values):
|
for akey, value in zip(values.keys, values.values):
|
||||||
key = ast.literal_eval(akey)
|
key = ast.literal_eval(akey)
|
||||||
signal = getattr(ep.token, key)
|
signal = getattr(ep.token, key)
|
||||||
state.append(signal.eq(compiler.ec.visit_expr(value)))
|
state.append(signal.eq(compiler.ec.visit_expr(value)))
|
||||||
|
@ -73,8 +72,79 @@ def gen_df_io(compiler, modelname, to_model, from_model):
|
||||||
]
|
]
|
||||||
return [state], [state]
|
return [state], [state]
|
||||||
|
|
||||||
def gen_io(compiler, modelname, model, to_model, from_model):
|
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"])),
|
||||||
|
]
|
||||||
|
|
||||||
|
if model == TWrite:
|
||||||
|
state.append(bus.we.eq(1))
|
||||||
|
if from_model:
|
||||||
|
raise TypeError("Attempted to read from write transaction")
|
||||||
|
else:
|
||||||
|
state.append(bus.we.eq(0))
|
||||||
|
# TODO
|
||||||
|
state.append(If(~bus.ack, AbstractNextState(state)))
|
||||||
|
return [state], [state]
|
||||||
|
|
||||||
|
def _gen_bus_io(compiler, modelname, model, to_model, from_model):
|
||||||
|
busname = ast.literal_eval(to_model["busname"])
|
||||||
|
if busname is None:
|
||||||
|
if len(compiler.ioo.buses) != 1:
|
||||||
|
raise TypeError("Bus name not specified")
|
||||||
|
bus = list(compiler.ioo.buses.values())[0]
|
||||||
|
else:
|
||||||
|
bus = compiler.ioo.buses[busname]
|
||||||
|
if isinstance(bus, wishbone.Interface):
|
||||||
|
return _gen_wishbone_io(compiler, modelname, model, to_model, from_model, bus)
|
||||||
|
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
|
||||||
|
|
||||||
|
# build the set of argument names at the same time
|
||||||
|
argnames.add(name)
|
||||||
|
|
||||||
|
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):
|
||||||
if model == Token:
|
if model == Token:
|
||||||
return gen_df_io(compiler, modelname, to_model, from_model)
|
desc = [
|
||||||
|
"endpoint",
|
||||||
|
("value", ast.Name("None", ast.Load())),
|
||||||
|
]
|
||||||
|
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)),
|
||||||
|
("sel", ast.Name("None", ast.Load())),
|
||||||
|
("busname", ast.Name("None", ast.Load()))
|
||||||
|
]
|
||||||
|
args = _decode_args(desc, to_model, to_model_kw)
|
||||||
|
return _gen_bus_io(compiler, modelname, model, args, from_model)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
Loading…
Reference in New Issue