[libre-riscv-dev] buffered pipeline

Luke Kenneth Casson Leighton lkcl at lkcl.net
Wed Mar 27 11:55:02 GMT 2019

this is what RegStage can be replaced with:

class PassThroughStage(StageCls):
    def __init__(self, iospec): self.iospecfn = iospecfn
    def ispec(self): return self.iospecfn()
    def ospec(self): return self.iospecfn()
    def process(self, i): return i

class RegisterPipeline(UnbufferedPipeline):
    def __init__(self, iospecfn):
        UnbufferedPipeline.__init__(self, PassThroughStage(iospecfn))

initially i wrote this (based directly on RegStage - one-for-one

    def elaborate(self, platform):
        m = Module()

        # some temporaries
        p_i_valid = Signal(reset_less=True)
        pv = Signal(reset_less=True)
        m.d.comb += [p_i_valid.eq(self.p.i_valid_logic()),
                     pv.eq(p_i_valid & self.p.o_ready)]

        # set prev/next ready/valid
        m.d.comb += self.p.o_ready.eq(~self.n.o_valid | self.n.i_ready)
        m.d.sync += self.n.o_valid.eq(p_i_valid
                                           | (~self.n.i_ready & self.n.o_valid))
        # output data if input is valid and output is ready
        with m.If(pv):
            m.d.sync += eq(self.n.o_data, self.p.i_data)

        return m

however i realised that, actually, that's near-identical to
UnbufferedPipeline, except that the sync of the data is put into a
temporary named "register" first, and that the call to stage.process()
is missed out.

that allowed me to think, "hmmm, if you have a stage which just passes
through its data, and has the exact same input-spec as output-spec,
that's the job done".

the temporary named pv *is* data_valid (aka inverted buffer_full).

so there's direct one-to-one equivalence between the code that you've
written, and the preliminary Stage/Pipeline API, with the exception
that StageChain, BufferedPipeline and the ability to support an
arbitrary recursive mixture of objects, Records and Signals are


More information about the libre-riscv-dev mailing list