diff --git a/examples/dataflow_dma.py b/examples/dataflow_dma.py index 267176916..5e6649ada 100644 --- a/examples/dataflow_dma.py +++ b/examples/dataflow_dma.py @@ -1,10 +1,9 @@ -import sys import networkx as nx from migen.fhdl import verilog from migen.flow.ala import * from migen.flow.network import * -from migen.actorlib import dma_wishbone +from migen.actorlib import dma_wishbone, control L = [ ("x", BV(10), 8), @@ -15,6 +14,14 @@ L = [ ]) ] +adrgen = control.For(10) reader = dma_wishbone.Reader(L) -frag = reader.get_fragment() -print(verilog.convert(frag, ios=set(reader.bus.signals()))) + +g = nx.MultiDiGraph() +add_connection(g, adrgen, reader) +comp = CompositeActor(g) + +frag = comp.get_fragment() +ios = set(reader.bus.signals()) +ios.add(comp.busy) +print(verilog.convert(frag, ios=ios)) diff --git a/migen/actorlib/control.py b/migen/actorlib/control.py new file mode 100644 index 000000000..9819c5dfe --- /dev/null +++ b/migen/actorlib/control.py @@ -0,0 +1,94 @@ +from operator import mul +from functools import reduce + +from migen.fhdl.structure import * +from migen.corelogic.record import * +from migen.corelogic.fsm import * +from migen.flow.actor import * + +# Generates integers from start to maximum-1 +class For(Actor): + def __init__(self, *maxima, start=False, step=False): + self.dimensions = len(maxima) + self.start = start + self.step = step + params = ["end"] + if start: params.append("start") + if step: params.append("step") + self.d_bv = [BV(bits_for(dimension)) for dimension in maxima] + l_sink = [("d{0}".format(n), [(p, bv) for p in params]) + for n, bv in zip(range(len(self.d_bv)), self.d_bv)] + l_source = [("d{0}".format(n), bv) + for n, bv in zip(range(len(self.d_bv)), self.d_bv)] + Actor.__init__(self, SchedulingModel(SchedulingModel.DYNAMIC), + ("sink", Sink, l_sink), + ("source", Source, l_source)) + + def get_fragment(self): + load = Signal() + ce = Signal() + last = Signal() + + counters_v = [Signal(bv, variable=True) for bv in self.d_bv] + counters = [getattr(self.token("source"), "d{0}".format(n)) + for n in range(self.dimensions)] + + params = [getattr(self.token("sink"), "d{0}".format(n)) + for n in range(self.dimensions)] + if self.start: + starts = [p.start for p in params] + start_rs = [Signal(s.bv, variable=True) for s in starts] + else: + start_rs = [Constant(0, bv) for bv in self.d_bv] + if self.step: + steps = [p.step for p in params] + step_rs = [Signal(s.bv, variable=True) for s in steps] + else: + step_rs = [Constant(1, bv) for bv in self.d_bv] + ends = [p.end for p in params] + end_rs = [Signal(s.bv, variable=True) for s in ends] + + lasts = Signal(BV(self.dimensions)) + + on_ce = [ + If(lasts[n], + counter.eq(start) + ).Else( + counter.eq(counter + step) + ) + for n, counter, start, step + in zip(range(self.dimensions), counters_v, start_rs, step_rs) + ] + lasts_gen = [ + lasts[n].eq(counter + step >= end if self.step else counter + step == end) + for n, counter, step, end + in zip(range(self.dimensions), counters_v, step_rs, end_rs) + ] + sync = [ + If(load, + Cat(*start_rs).eq(Cat(*starts)) if self.start else None, + Cat(*step_rs).eq(Cat(*steps)) if self.step else None, + Cat(*end_rs).eq(Cat(*ends)), + Cat(*counters_v).eq(Cat(*start_rs)) + ), + If(ce, *on_ce) + ] + lasts_gen + [ + Cat(*counters).eq(Cat(*counters_v)) + ] + counters_fragment = Fragment(sync=sync) + + fsm = FSM("IDLE", "ACTIVE") + fsm.act(fsm.IDLE, + load.eq(1), + self.endpoints["sink"].ack.eq(1), + If(self.endpoints["sink"].stb, fsm.next_state(fsm.ACTIVE)) + ) + fsm.act(fsm.ACTIVE, + self.busy.eq(1), + self.endpoints["source"].stb.eq(1), + If(self.endpoints["source"].ack, + ce.eq(1), + If(last, fsm.next_state(fsm.IDLE)) + ) + ) + return counters_fragment + fsm.get_fragment()