[libre-riscv-dev] buffered pipeline

Jacob Lifshay programmerjake at gmail.com
Tue Mar 12 15:11:28 GMT 2019

the strategy I'm planning on using for the simple barrel processor is just
to have the pipeline never stop, if we encounter a reason an instruction
can't proceed in the current cycle, it is shunted into a delay pipeline to
be retried the next time around.

For stallable pipelines, I think we should name the pipeline control
signals pred_sending, succ_sending, pred_accepting and succ_accepting.

pred_sending is 1 when the input from the predecessor stage will have valid
data at the next clock edge, including when pred_accepting is 0. It is
connected to the current stage from the predecessor stage.

succ_sending is 1 when the output to the successor stage will have valid
data at the next clock edge, including when succ_accepting is 0. It is
connected from the current stage to the successor stage.

pred_accepting is 1 when the current stage can accept data from the
predecessor stage at the next clock edge, including when pred_sending is 0.
It is connected from the current stage to the predecessor stage.

succ_accepting is 1 when the successor stage can accept data from the
current stage at the next clock edge, including when succ_sending is 0. It
is connected from the successor stage to the current stage.

A simple example stage:

module stage(clk, rst, pred_sending, pred_accepting, pred_data,
succ_sending, succ_accepting, succ_data);
    input clk;
    input rst;
    input pred_sending;
    output pred_accepting;
    input [63:0] pred_data;
    output succ_sending;
    input succ_accepting;
    output [63:0] succ_data;

    reg data_valid;
    reg [63:0] data;
    wire next_data_valid;

    assign succ_sending = data_valid;
    assign pred_accepting = ~data_valid | succ_accepting;
    assign next_data_valid = pred_sending | (~succ_accepting & data_valid);

    assign succ_data = data + 1; // stage operation

    initial data_valid = 0;
    initial data = 0;

    always @(posedge clk or posedge rst) begin
        if(rst) begin
            data_valid <= 0;
            data <= 0;
        else begin
            data_valid <= next_data_valid;
            data <= pred_data;


On Tue, Mar 12, 2019, 06:33 Luke Kenneth Casson Leighton <lkcl at lkcl.net>

> https://zipcpu.com/blog/2017/08/14/strategies-for-pipelining.html
> i experimentally-implemented the above buffered pipeline, here:
> https://git.libre-riscv.org/?p=ieee754fpu.git;a=blob;f=src/add/example_buf_pipe.py;h=b72e1c43904451ba0ef7f9fa78d5417da8de0a8d;hb=0e70fec7c3df1ee97020aa5be6f358c85898a5fb
> it is... very confusing.  the names stb/busy, there are pairs: input
> and output, however the connection for previous and next is crossed.
> in the john dawson code, the stb / ack signals act effectively as a
> clock.  you *must* raise and then lower the "ack" signal each and
> every time that data is ready, and the sender will *not* initiate a
> new data send until it has seen that raise *and* lower.
> this means that the john dawson code's data receive and transmit rate
> is *half* that of the clock.
> by contrast, dan gisselquist's code is designed to keep on receiving
> (or transmitting) data on every clock, for as long as stb is true and
> busy is false.  it also seems to cope with all the situations such as
> when input is ready and output is not (this activates "store incoming
> data in buffer") and allows the stage to tell the input to stop
> sending any more data (without losing the *current* data).
> there may however be a bug in what dan has published:
> if (!o_stb)
>    o_data <= i_data;
> i believe this should be "r_data <= i_data" according to the comments,
> given that it says "store incoming data in temporary".
> insights and comments appreciated.
> l.
> _______________________________________________
> libre-riscv-dev mailing list
> libre-riscv-dev at lists.libre-riscv.org
> http://lists.libre-riscv.org/mailman/listinfo/libre-riscv-dev

More information about the libre-riscv-dev mailing list