From c53520bf002b48858b3837b603893445404ac5a1 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Sun, 31 Mar 2019 15:27:42 +0100 Subject: [PATCH] bug where combinatorial assignments from stage are bleeding through --- src/add/pipeline.py | 101 ++++++++++++++++++++++++++++-------- src/add/pipeline_example.py | 43 ++++++--------- 2 files changed, 95 insertions(+), 49 deletions(-) diff --git a/src/add/pipeline.py b/src/add/pipeline.py index 4cfe1259..0608cbe9 100644 --- a/src/add/pipeline.py +++ b/src/add/pipeline.py @@ -1,12 +1,15 @@ """ Example 5: Making use of PyRTL and Introspection. """ +from collections.abc import Sequence + from nmigen import Signal from nmigen.hdl.rec import Record from nmigen import tracer from nmigen.compat.fhdl.bitcontainer import value_bits_sign from contextlib import contextmanager -from singlepipe import eq +from singlepipe import eq, StageCls, ControlBase, BufferedPipeline +from singlepipe import UnbufferedPipeline # The following example shows how pyrtl can be used to make some interesting @@ -16,6 +19,14 @@ from singlepipe import eq # stages, and new members with names not starting with "_" are to be registered # for the next stage. +def like(value, rname, pipe): + if isinstance(value, ObjectProxy): + return ObjectProxy.like(pipe, value, name=rname, reset_less=True) + else: + return Signal(value_bits_sign(value), name=rname, + reset_less=True) + return Signal.like(value, name=rname, reset_less=True) + class ObjectProxy: def __init__(self, pipe, name=None): @@ -60,12 +71,7 @@ class ObjectProxy: return #rname = "%s_%s" % (self.name, name) rname = name - if isinstance(value, ObjectProxy): - new_pipereg = ObjectProxy.like(self._pipe, value, - name=rname, reset_less=True) - else: - new_pipereg = Signal.like(value, name=rname, reset_less=True) - + new_pipereg = like(value, rname, self._pipe) object.__setattr__(self, name, new_pipereg) self._pipe.sync += eq(new_pipereg, value) @@ -74,27 +80,35 @@ class PipelineStage: """ Pipeline builder stage with auto generation of pipeline registers. """ - def __init__(self, name, m, prev=None): + def __init__(self, name, m, prev=None, pipemode=False): self._m = m self._stagename = name self._preg_map = {} self._prev_stage = prev if prev: - print ("prev", prev._preg_map) + print ("prev", prev._stagename, prev._preg_map) if prev._stagename in prev._preg_map: m = prev._preg_map[prev._stagename] self._preg_map[prev._stagename] = m + for k, v in m.items(): + m[k] = like(v, k, self._m) if '__nextstage__' in prev._preg_map: m = prev._preg_map['__nextstage__'] self._preg_map[self._stagename] = m - print ("make current", m) + for k, v in m.items(): + m[k] = like(v, k, self._m) + print ("make current", self._stagename, m) + self._pipemode = pipemode + self._eqs = [] def __getattr__(self, name): try: - return self._preg_map[self._stagename][name] + v = self._preg_map[self._stagename][name] + return v + #return like(v, name, self._m) except KeyError: raise AttributeError( - 'error, no pipeline register "%s" defined for stage %d' + 'error, no pipeline register "%s" defined for stage %s' % (name, self._stagename)) def __setattr__(self, name, value): @@ -104,31 +118,74 @@ class PipelineStage: return pipereg_id = self._stagename rname = 'pipereg_' + pipereg_id + '_' + name - #new_pipereg = Signal(value_bits_sign(value), name=rname, - # reset_less=True) - if isinstance(value, ObjectProxy): - new_pipereg = ObjectProxy.like(self._pipe, value, - name=rname, reset_less = True) - else: - new_pipereg = Signal.like(value, name=rname, reset_less = True) + new_pipereg = like(value, rname, self._m) next_stage = '__nextstage__' if next_stage not in self._preg_map: self._preg_map[next_stage] = {} self._preg_map[next_stage][name] = new_pipereg - self._m.d.sync += eq(new_pipereg, value) + if self._pipemode: + self._eqs.append(value) + print ("!pipemode: append", new_pipereg, value) + #self._m.d.comb += assign + else: + print ("!pipemode: assign", new_pipereg, value) + assign = eq(new_pipereg, value) + self._m.d.sync += assign + + +class AutoStage(StageCls): + def __init__(self, inspecs, outspecs, eqs): + self.inspecs, self.outspecs, self.eqs = inspecs, outspecs, eqs + def ispec(self): return self.inspecs + def ospec(self): return self.outspecs + def process(self, i): + return self.eqs + #def setup(self, m, i): #m.d.comb += self.eqs class PipeManager: - def __init__(self, m): + def __init__(self, m, pipemode=False): self.m = m + self.pipemode = pipemode @contextmanager def Stage(self, name, prev=None): - stage = PipelineStage(name, self.m, prev) + stage = PipelineStage(name, self.m, prev, self.pipemode) try: yield stage, stage._m finally: pass + if self.pipemode: + inspecs = self.get_specs(stage, name) + outspecs = self.get_specs(stage, '__nextstage__', liked=True) + s = AutoStage(inspecs, outspecs, stage._eqs) + self.stages.append(s) + + def get_specs(self, stage, name, liked=False): + if name in stage._preg_map: + res = [] + for k, v in stage._preg_map[name].items(): + #v = like(v, k, stage._m) + res.append(v) + return res + return [] + + def __enter__(self): + self.stages = [] + return self + + def __exit__(self, *args): + print (args) + pipes = [] + cb = ControlBase() + for s in self.stages: + print (s, s.inspecs, s.outspecs) + p = UnbufferedPipeline(s) + pipes.append(p) + self.m.submodules += p + + #self.m.d.comb += cb.connect(pipes) + class SimplePipeline: """ Pipeline builder with auto generation of pipeline registers. diff --git a/src/add/pipeline_example.py b/src/add/pipeline_example.py index e612bb0c..5e350e5b 100644 --- a/src/add/pipeline_example.py +++ b/src/add/pipeline_example.py @@ -83,42 +83,31 @@ class PipeModule: return self.m -class PipelineStageExample(PipeManager): +class PipelineStageExample: def __init__(self): - self.m = Module() self._loopback = Signal(4) - PipeManager.__init__(self, self.m) - def stage0(self): - self.n = ~self._loopback - - def stage1(self): - self.n = self.n + 2 - - def stage2(self): - localv = Signal(4) - self._pipe.comb += localv.eq(2) - self.n = self.n << localv + def get_fragment(self, platform=None): - def stage3(self): - self.n = ~self.n + m = Module() - def stage4(self): - self._pipe.sync += self._loopback.eq(self.n + 3) + with PipeManager(m, pipemode=True) as pipe: - def get_fragment(self, platform=None): + with pipe.Stage("first") as (p, m): + p.n = ~self._loopback + with pipe.Stage("second", p) as (p, m): + #p.n = ~self._loopback + 2 + p.n = p.n + 2 + with pipe.Stage("third", p) as (p, m): + #p.n = ~self._loopback + 5 + localv = Signal(4) + m.d.comb += localv.eq(2) + p.n = p.n << localv - with self.Stage("first") as (p, m): - p.n = ~self._loopback - with self.Stage("second", p) as (p, m): - p.n = p.n + 2 - with self.Stage("third", p) as (p, m): - localv = Signal(4) - m.d.comb += localv.eq(2) - p.n = p.n << localv + print (pipe.stages) - return self.m + return m -- 2.30.2