From f901ac1438edde930b17868f2755d2484f70d689 Mon Sep 17 00:00:00 2001 From: Kia <kia@special-circumstanc.es> Date: Sat, 13 Mar 2021 18:46:34 -0700 Subject: [PATCH] generic pipeline stage register, with registered and non-registered ready --- PipeStage.py | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 PipeStage.py diff --git a/PipeStage.py b/PipeStage.py new file mode 100644 index 0000000..96f212e --- /dev/null +++ b/PipeStage.py @@ -0,0 +1,163 @@ +from nmigen import * +from nmigen.cli import main + + + + + + +class PipeStage(Elaboratable): + def __init__(self, width, *, registered_ready): + self.width = width + self.registered_ready = registered_ready + + self.upstream_valid_in = Signal(1) + self.upstream_ready_out = Signal(1) + self.upstream_data_in = Signal(self.width) + + self.downstream_valid_out = Signal(1) + self.downstream_ready_in = Signal(1) + self.downstream_data_out = Signal(self.width) + + def elaborate(self, platform): + m = Module() + + if (self.registered_ready == False): + m.d.comb += self.upstream_ready_out.eq(self.downstream_ready | (~self.downstream_valid)) + + with m.If(self.upstream_ready_out == 1): + m.d.sync += self.downstream_data_out.eq(self.upstream_data_in) + m.d.sync += self.downstream_valid_out.eq(self.upstream_valid_in) + + else: + pipe_reg = Signal(self.width) + skid_reg = Signal(self.width) + + pipe_reg_valid = Signal(1) + skid_reg_valid = Signal(1) + + m.d.comb += self.downstream_valid_out.eq( skid_reg_valid | pipe_reg_valid) + m.d.comb += self.upstream_ready_out.eq(~skid_reg_valid) + + with m.If(skid_reg_valid == 1): + m.d.comb += self.downstream_data_out.eq(skid_reg) + with m.Else(): + m.d.comb += self.downstream_data_out.eq(pipe_reg) + + with m.If(self.downstream_ready_in == 1): + m.d.sync += skid_reg_valid.eq(0) + + with m.If(self.upstream_ready_out == 1): + m.d.sync += pipe_reg.eq(self.upstream_data_in) + m.d.sync += pipe_reg_valid.eq(self.upstream_valid_in) + + with m.If(self.downstream_ready_in == 0): + m.d.sync += skid_reg.eq(pipe_reg) + m.d.sync += skid_reg_valid.eq(pipe_reg_valid) + + return m + + + + +class RegisteredPipeStage(Elaboratable): # registered + def __init__(self, width): + self.width = width + + self.upstream_valid_in = Signal(1) + self.upstream_ready_out = Signal(1) + self.upstream_data_in = Signal(self.width) + + self.downstream_valid_out = Signal(1) + self.downstream_ready_in = Signal(1) + self.downstream_data_out = Signal(self.width) + + def elaborate(self, platform): + m = Module() + + skid_buffer = Signal(self.width) + skid_buffer_frozen = Signal(1) + + # we signal ready to upstream if and only if the skid buffer is empty + m.d.comb += self.upstream_ready_out.eq(~skid_buffer_frozen) + + + # should we capture a value in the skid buffer? + # we should if upstream has data for us *and* downstream cannot accept + + # If we want to fill our skid buffer, we need: + # 1. valid input data (upstream_valid_in == 1) + # 2. a buffer that is empty (skid_buffer_frozen == 0) + # 3. stalled downstream (downstream_ready_in == 0) & (downstream_valid_out == 1) + + with m.If(self.upstream_valid_in & (~skid_buffer_frozen) & (~self.downstream_ready_in) & (self.downstream_valid_out)): + m.d.sync += skid_buffer_frozen.eq(1) + + # if downstream is accepting data again, we will flush our skid buffer + with m.If(self.downstream_ready_in == 1): + m.d.sync += skid_buffer_frozen.eq(0) + + + # Stalled == (downstream_ready_in == 0 & downstream_valid_out == 1) + # so not stalled = !(downstream_ready_in == 0 & downstream_valid_out == 1) + # = downstream_ready_in == 1 | downstream_valid_out == 0 + # by de Morgan + + with m.If((self.downstream_ready_in) | (~self.downstream_valid_out)): + m.d.sync += self.downstream_valid_out.eq(self.upstream_valid_in | skid_buffer_frozen) + + # data path + + # always clock data into the skid buffer as long as the buffer isn't filled + + with m.If(skid_buffer_frozen == 0): + m.d.sync += skid_buffer.eq(self.upstream_data_in) + + # not stalled condition + with m.If((self.downstream_ready_in) | (~self.downstream_valid_out)): + with m.If(skid_buffer_frozen == 1): + m.d.sync += self.downstream_data_out.eq(skid_buffer) + with m.Elif(self.upstream_valid_in == 1): + m.d.sync += self.downstream_data_out.eq(self.upstream_data_in) + + return m + + + + +class DummyPlug(Elaboratable): + def elaborate(self, platform): + m = Module() + egg = RegisteredSkidBuffer(8) + m.submodules += egg + + cntr = Signal(8) + intctr = Signal(8) + data_in = Signal(8) + m.d.sync += intctr.eq(intctr +1) + m.d.comb += egg.upstream_data_in.eq(data_in) + + upstream_valid = Signal(1) + m.d.comb += egg.upstream_valid_in.eq(upstream_valid) + m.d.comb += upstream_valid.eq(1) + + downstream_ready = Signal(1) + m.d.comb += egg.downstream_ready_in.eq(downstream_ready) + m.d.comb += downstream_ready.eq(1) + m.d.comb += data_in.eq(cntr) + with m.If((intctr == 4) | (intctr == 5) | (intctr == 6)): + m.d.comb += downstream_ready.eq(0) +# with m.If((intctr == 4) | (intctr == 5)): +# m.d.comb += upstream_valid.eq(0) +# m.d.comb += data_in.eq(0) + + with m.If(egg.upstream_ready_out == 1): + m.d.sync += cntr.eq(cntr+1) + + + return m + + +if __name__ == '__main__': + baka =DummyPlug() + main(baka) \ No newline at end of file -- GitLab