- o_p_busyn = Signal(reset_less=True)
- i_p_stb_o_p_busyn = Signal(reset_less=True)
- m.d.comb += o_p_busyn.eq(~self.o_p_busy)
- m.d.comb += i_p_stb_o_p_busyn.eq(self.i_p_stb & o_p_busyn)
-
- result = Signal(32)
- m.d.comb += result.eq(self.process(self.i_data))
- with m.If(o_p_busyn): # not stalled
- m.d.sync += self.r_data.eq(result)
-
- #with m.If(self.i_p_rst): # reset
- # m.d.sync += self.o_n_stb.eq(0)
- # m.d.sync += self.o_p_busy.eq(0)
- with m.If(~self.i_n_busy): # previous stage is not busy
- with m.If(o_p_busyn): # not stalled
- # nothing in buffer: send input direct to output
- m.d.sync += self.o_n_stb.eq(self.i_p_stb)
- m.d.sync += self.o_data.eq(result)
- with m.Else(): # o_p_busy is true, and something is in our buffer.
- # Flush the buffer to the output port.
- m.d.sync += self.o_n_stb.eq(1)
- m.d.sync += self.o_data.eq(self.r_data)
- # ignore input, since o_p_busy is also true.
- # also clear stall condition, declare register to be empty.
- m.d.sync += self.o_p_busy.eq(0)
-
- # (i_n_busy) is true here: previous stage is busy
- with m.Elif(~self.o_n_stb): # next stage being told "not busy"
- m.d.sync += self.o_n_stb.eq(self.i_p_stb)
- m.d.sync += self.o_p_busy.eq(0) # Keep the buffer empty
- # Apply the logic to the input data, and set the output data
- m.d.sync += self.o_data.eq(result)
-
- # (i_n_busy) and (o_n_stb) both true:
- with m.Elif(i_p_stb_o_p_busyn):
- # If next stage *is* busy, and not stalled yet, accept input
- m.d.sync += self.o_p_busy.eq(self.i_p_stb & self.o_n_stb)
-
- with m.If(o_p_busyn): # not stalled
- # turns out that from all of the above conditions, just
- # always put result into buffer if not busy
- m.d.sync += self.r_data.eq(result)
+ # establish some combinatorial temporaries
+ o_n_validn = Signal(reset_less=True)
+ i_p_valid_o_p_ready = Signal(reset_less=True)
+ m.d.comb += [o_n_validn.eq(~self.o.n_valid),
+ i_p_valid_o_p_ready.eq(self.i.p_valid & self.o.p_ready),
+ ]
+
+ # store result of processing in combinatorial temporary
+ with m.If(self.i.p_valid): # input is valid: process it
+ m.d.comb += eq(self.result, self.stage.process(self.i.data))
+ # if not in stall condition, update the temporary register
+ with m.If(self.o.p_ready): # not stalled
+ m.d.sync += self.update_buffer()
+
+ #with m.If(self.i.p_rst): # reset
+ # m.d.sync += self.o.n_valid.eq(0)
+ # m.d.sync += self.o.p_ready.eq(0)
+ with m.If(self.i.n_ready): # next stage is ready
+ with m.If(self.o.p_ready): # not stalled
+ # nothing in buffer: send (processed) input direct to output
+ m.d.sync += [self.o.n_valid.eq(self.i.p_valid),
+ self.update_output(),
+ ]
+ with m.Else(): # o.p_ready is false, and something is in buffer.
+ # Flush the [already processed] buffer to the output port.
+ m.d.sync += [self.o.n_valid.eq(1),
+ self.flush_buffer(),
+ # clear stall condition, declare register empty.
+ self.o.p_ready.eq(1),
+ ]
+ # ignore input, since o.p_ready is also false.
+
+ # (i.n_ready) is false here: next stage is ready
+ with m.Elif(o_n_validn): # next stage being told "ready"
+ m.d.sync += [self.o.n_valid.eq(self.i.p_valid),
+ self.o.p_ready.eq(1), # Keep the buffer empty
+ # set the output data (from comb result)
+ self.update_output(),
+ ]
+ # (i.n_ready) false and (o.n_valid) true:
+ with m.Elif(i_p_valid_o_p_ready):
+ # If next stage *is* ready, and not stalled yet, accept input
+ m.d.sync += self.o.p_ready.eq(~(self.i.p_valid & self.o.n_valid))