diff --git a/migen/pytholite/compiler.py b/migen/pytholite/compiler.py index ec5c41d1f..269706a46 100644 --- a/migen/pytholite/compiler.py +++ b/migen/pytholite/compiler.py @@ -154,7 +154,7 @@ class _Compiler: raise NotImplementedError from_model.append((tregs, fstatement.value)) - states, exit_states = gen_io(self, model, args, from_model) + states, exit_states = gen_io(self, modelname, model, args, from_model) sa.assemble(states, exit_states) return fstatement @@ -222,7 +222,7 @@ class _Compiler: if not isinstance(yvalue, ast.Call) or not isinstance(yvalue.func, ast.Name): raise NotImplementedError("Unrecognized I/O pattern") callee = self.symdict[yvalue.func.id] - states, exit_states = gen_io(self, callee, yvalue.args, []) + states, exit_states = gen_io(self, None, callee, yvalue.args, []) sa.assemble(states, exit_states) else: raise NotImplementedError diff --git a/migen/pytholite/expr.py b/migen/pytholite/expr.py index 8c1c35511..bd82781d8 100644 --- a/migen/pytholite/expr.py +++ b/migen/pytholite/expr.py @@ -19,6 +19,10 @@ class ExprCompiler: return self.visit_expr_name(node) elif isinstance(node, ast.Num): return self.visit_expr_num(node) + elif isinstance(node, ast.Attribute): + return self.visit_expr_attribute(node) + elif isinstance(node, ast.Subscript): + return self.visit_expr_subscript(node) else: raise NotImplementedError @@ -102,3 +106,10 @@ class ExprCompiler: def visit_expr_num(self, node): return Constant(node.n) + + def visit_expr_attribute(self, node): + raise NotImplementedError + + def visit_expr_subscript(self, node): + raise NotImplementedError + diff --git a/migen/pytholite/io.py b/migen/pytholite/io.py index f0be3ca31..51820a69c 100644 --- a/migen/pytholite/io.py +++ b/migen/pytholite/io.py @@ -4,6 +4,7 @@ from migen.fhdl.structure import * from migen.flow.actor import * from migen.actorlib.sim import * from migen.pytholite.fsm import * +from migen.pytholite.expr import ExprCompiler class Pytholite: def get_fragment(self): @@ -18,7 +19,28 @@ def make_io_object(dataflow=None): else: return DFPytholite(*dataflow) -def gen_df_io(compiler, to_model, from_model): +class _TokenPullExprCompiler(ExprCompiler): + def __init__(self, symdict, modelname, ep): + super().__init__(symdict) + self.modelname = modelname + self.ep = ep + + def visit_expr_subscript(self, node): + # check that we are subscripting .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 + + if not isinstance(node.slice, ast.Index): + raise NotImplementedError + field = ast.literal_eval(node.slice.value) + signal = getattr(self.ep.token, field) + + return signal + +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[0]) ep = compiler.ioo.endpoints[epname] @@ -27,9 +49,22 @@ def gen_df_io(compiler, to_model, from_model): if len(to_model) == 1: # token pull from sink - raise NotImplementedError # TODO + if not isinstance(ep, Sink): + raise TypeError("Attempted to pull from source") + ec = _TokenPullExprCompiler(compiler.symdict, modelname, ep) + state = [] + 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), + If(~ep.stb, AbstractNextState(state)) + ] + return [state], [state] else: # token push to source + if not isinstance(ep, Source): + raise TypeError("Attempted to push to sink") if from_model: raise TypeError("Attempted to read from pushed token") d = to_model[1] @@ -46,8 +81,8 @@ def gen_df_io(compiler, to_model, from_model): ] return [state], [state] -def gen_io(compiler, model, to_model, from_model): +def gen_io(compiler, modelname, model, to_model, from_model): if model == Token: - return gen_df_io(compiler, to_model, from_model) + return gen_df_io(compiler, modelname, to_model, from_model) else: raise NotImplementedError