From 8f1bf508ca01506cedeec983a099d4fa42d1d18d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jan 2012 15:35:17 +0100 Subject: [PATCH] actor: simplified automatic control --- migen/flow/actor.py | 92 +++++++++++++++++++++------------------------ migen/flow/ala.py | 6 +-- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/migen/flow/actor.py b/migen/flow/actor.py index 5742bd9e0..f1b783a67 100644 --- a/migen/flow/actor.py +++ b/migen/flow/actor.py @@ -1,5 +1,4 @@ from migen.fhdl.structure import * -from migen.corelogic.misc import optree class SchedulingModel: COMBINATORIAL, SEQUENTIAL, PIPELINE, DYNAMIC = range(4) @@ -8,7 +7,7 @@ class SchedulingModel: self.model = model self.latency = latency - def __str__(self): + def __repr__(self): if self.model == SchedulingModel.COMBINATORIAL: return "" elif self.model == SchedulingModel.SEQUENTIAL: @@ -20,27 +19,17 @@ class SchedulingModel: else: raise AttributeError -class Sink: +class Endpoint: def __init__(self, actor, token): self.actor = actor self.token = token - self.stb_i = Signal() - self.ack_o = Signal() + self.stb = Signal() + self.ack = Signal() -class Source: - def __init__(self, actor, token): - self.actor = actor - self.token = token - self.stb_o = Signal() - self.ack_i = Signal() +def _control_fragment_comb(stb_i, ack_o, stb_o, ack_i): + return Fragment([stb_o.eq(stb_i), ack_o.eq(ack_i)]) -def _control_fragment_comb(l_stb_i, l_ack_o, l_stb_o, l_ack_i): - en = Signal() - comb = [en.eq(optree('&', l_stb_i + l_ack_i))] - comb += [o.eq(en) for o in l_ack_o + l_stb_o] - return Fragment(comb) - -def _control_fragment_seq(latency, l_stb_i, l_ack_o, l_stb_o, l_ack_i, trigger): +def _control_fragment_seq(latency, stb_i, ack_o, stb_o, ack_i, trigger): ready = Signal() timer = Signal(BV(bits_for(latency))) comb = [ready.eq(timer == 0)] @@ -52,61 +41,64 @@ def _control_fragment_seq(latency, l_stb_i, l_ack_o, l_stb_o, l_ack_i, trigger): ) ] - nsources = len(l_stb_o) - mask = Signal(BV(nsources)) - sync.append(If(trigger, mask.eq(0)).Else(mask.eq(mask | Cat(*l_ack_i)))) - - comb.append(Cat(*l_stb_o).eq(Replicate(ready, len(l_stb_o)) & ~mask)) - comb.append(Cat(*l_ack_o).eq(Replicate(trigger, len(l_ack_o)))) - - stb_all = Signal() - comb.append(stb_all.eq(optree('&', l_stb_i))) - comb.append(trigger.eq(ready & stb_all & ((mask | Cat(*l_ack_i)) == Replicate(1, nsources)))) + mask = Signal() + comb += [ + stb_o.eq(ready & mask), + trigger.eq(stb_i & (ack_i | ~mask) & ready), + ack_o.eq(trigger), + ] + sync += [ + If(trigger, mask.eq(1)), + If(stb_o & ack_i, mask.eq(0)) + ] return Fragment(comb, sync) -def _control_fragment_pipe(latency, l_stb_i, l_ack_o, l_stb_o, l_ack_i, pipe_ce): - stb_all = Signal() - comb = [stb_all.eq(optree('&', l_stb_i))] +def _control_fragment_pipe(latency, stb_i, ack_o, stb_o, ack_i, pipe_ce): valid = Signal(BV(latency)) if latency > 1: - sync = [If(pipe_ce, valid.eq(Cat(stb_all, valid[:latency-1])))] + sync = [If(pipe_ce, valid.eq(Cat(stb_i, valid[:latency-1])))] else: - sync = [If(pipe_ce, valid.eq(stb_all))] + sync = [If(pipe_ce, valid.eq(stb_i))] last_valid = valid[latency-1] - nsources = len(l_stb_o) - mask = Signal(BV(nsources)) - sync.append(If(pipe_ce, mask.eq(0)).Else(mask.eq(mask | Cat(*l_ack_i)))) - - comb.append(Cat(*l_stb_o).eq(Replicate(last_valid, len(l_stb_o)) & ~mask)) - comb.append(Cat(*l_ack_o).eq(Replicate(pipe_ce, len(l_ack_o)))) - - comb.append(pipe_ce.eq(~last_valid | ((mask | Cat(*l_ack_i)) == Replicate(1, nsources)))) + comb = [ + pipe_ce.eq(ack_i | ~last_valid), + ack_o.eq(pipe_ce), + stb_o.eq(last_valid) + ] return Fragment(comb, sync) class Actor: def __init__(self, scheduling_model, sinks, sources): self.scheduling_model = scheduling_model - self.sinks = sinks - self.sources = sources + if isinstance(sinks, list): + self.sinks = [Endpoint(self, sink) for sink in sinks] + else: + self.sinks = [Endpoint(self, sinks)] + if isinstance(sources, list): + self.sources = [Endpoint(self, source) for source in sources] + else: + self.sources = [Endpoint(self, sources)] if self.scheduling_model.model == SchedulingModel.SEQUENTIAL: self.trigger = Signal() elif self.scheduling_model.model == SchedulingModel.PIPELINE: self.pipe_ce = Signal() def get_control_fragment(self): - l_stb_i = [e.stb_i for e in self.sinks] - l_ack_o = [e.ack_o for e in self.sinks] - l_stb_o = [e.stb_o for e in self.sources] - l_ack_i = [e.ack_i for e in self.sources] + if len(self.sinks) != 1 or len(self.sources) != 1: + raise ValueError("Actors with automatic control fragment must have one sink and one source. Consider using plumbing actors.") + stb_i = self.sinks[0].stb + ack_o = self.sinks[0].ack + stb_o = self.sources[0].stb + ack_i = self.sources[0].ack if self.scheduling_model.model == SchedulingModel.COMBINATORIAL: - return _control_fragment_comb(l_stb_i, l_ack_o, l_stb_o, l_ack_i) + return _control_fragment_comb(stb_i, ack_o, stb_o, ack_i) elif self.scheduling_model.model == SchedulingModel.SEQUENTIAL: - return _control_fragment_seq(self.scheduling_model.latency, l_stb_i, l_ack_o, l_stb_o, l_ack_i, self.trigger) + return _control_fragment_seq(self.scheduling_model.latency, stb_i, ack_o, stb_o, ack_i, self.trigger) elif self.scheduling_model.model == SchedulingModel.PIPELINE: - return _control_fragment_pipe(self.scheduling_model.latency, l_stb_i, l_ack_o, l_stb_o, l_ack_i, self.pipe_ce) + return _control_fragment_pipe(self.scheduling_model.latency, stb_i, ack_o, stb_o, ack_i, self.pipe_ce) elif self.scheduling_model.model == SchedulingModel.DYNAMIC: raise NotImplementedError("Actor classes with dynamic scheduling must overload get_control_fragment") diff --git a/migen/flow/ala.py b/migen/flow/ala.py index d8693115f..b3456eb51 100644 --- a/migen/flow/ala.py +++ b/migen/flow/ala.py @@ -9,8 +9,7 @@ class Adder(Actor): self.result = Record(['sum', BV(width+1)]) Actor.__init__(self, SchedulingModel(SchedulingModel.COMBINATORIAL), - [Sink(self, self.operands)], - [Source(self, self.result)]) + self.operands, self.result) def get_process_fragment(self): return Fragment([self.result.sum.eq(self.operands.a + self.operands.b)]) @@ -22,8 +21,7 @@ class Divider(Actor): self.result = Record([('quotient', self.div.quotient_o), ('remainder', self.div.remainder_o)]) Actor.__init__(self, SchedulingModel(SchedulingModel.SEQUENTIAL, width), - [Sink(self, [self.operands])], - [Source(self, [self.result])]) + self.operands, self.result) def get_process_fragment(self): return self.div.get_fragment() + Fragment([self.div.start_i.eq(self.trigger)])