0

I learned two ways of writing pipeline(unblocking and blocking), I wonder which is better?

My personal opinion is that the second one is tedious and I don't understand why so many wire are needed.

Also, is there any standard style(template) of writing pipeline like FSM in verilog? Thanks in advance.

module simplePipeline
#(
    parameter WIDTH = 100
)
(
    input clk,
    input [WIDTH - 1 : 0] datain,
    output [WIDTH - 1: 0] dataout
);

    reg [WIDTH - 1 : 0] piprData1;
    reg [WIDTH - 1 : 0] piprData2;
    reg [WIDTH - 1 : 0] piprData3;

    always @(posedge clk) begin
        piprData1 <= datain;
    end

    always @(posedge clk) begin
        piprData2 <= piprData1;
    end

    always @(posedge clk) begin
        piprData3 <= piprData2;
    end

    assign dataout = piprData3;

endmodule

module blockingPipeline#2
(
    parameter WIDTH = 100
)
(
    input                   clk,
    input                   rst,
    input                   validIn,
    input [WIDTH - 1 : 0]   dataIn,
    input                   outAllow,
    output wire                 validOut,
    output wire [WIDTH - 1 : 0]   dataOut
);

    reg                 pipe1Valid;
    reg [WIDTH - 1 : 0] pipe1Data;
    reg                 pipe2Valid;
    reg [WIDTH - 1 : 0] pipe2Data;
    reg                 pipe3Valid;
    reg [WIDTH - 1 : 0] pipe3Data;


    /*------------------------PIPE1 LOGIC------------------------*/
    wire                pipe1AllowIn;
    wire                pipe1ReadyGo;
    wire                pipe1ToPipe2Valid;

    assign pipe1ReadyGo = 1'b1

    assign pipe1AllowIn = ! pipe1Valid || pipe1ReadyGo && pipe2AllowIn;

    assign pipe1ToPipe2Valid = pipe1Valid && pipe1ReadyGo

    always @(posedge clk)begin

        if( rst ) begin
            pipe1Vali <= 1'b0;
        end

        else if(pipe1AllowIn)begin
            pipe1Valid <= validIn;
        end

        ifvalidIn && pipe1AllowIn)begin
           pipe1Data <= dataIn;
        end

    end

    /*------------------------PIPE2 LOGIC------------------------*/
    wire                pipe2AllowIn;
    wire                pipe2ReadyGo;
    wire                pipe2ToPipe3Valid;

    assign pipe2ReadyGo = 1'b1;
    assign pipe2AllowIn = ! pipe2Valid || pipe2ReadyGo && pipe3AllowIn;
    assign pipe2ToPipe3Valid = pipe2Valid && pipe3ReadyGo;

    always @(posedge clk)begin
        if( rst ) begin
            pipe2Valid <= 1'b0;
        end
        else if(pipe2AllowIn)begin
            pipe2Valid <= pipe1ToPipe2Valid;
        end
        if(pipe1ToPipe2Valid && pipe2AllowIn)begin
            pipe2Data <= pipe1Data;
        end
    end


    /*------------------------PIPE3 LOGIC------------------------*/
    wire                pipe3AllowIn;
    wire                pipe3ReadyGo;

    assign pipe3ReadyGo = 1'b1;
    assign pipe3AllowIn = ! pipe3Valid || pipe3ReadyGo && outAllow;

    always @(posedge clk)begin
        if( rst ) begin
            pipe3Valid <= 1'b0;
        end
        else if(pipe3AllowIn)begin
            pipe3Valid <= pipe2ToPipe3Valid;
        end
        if(pipe2ToPipe3Valid && pipe3AllowIn)begin
            pipe3Data <= pipe2Data;
        end
    end

    assign validOut = pipe3Valid && pipe3ReadyGo;
    assign dataOut = pipe3Data;

endmodule
kenny_k
  • 3,831
  • 5
  • 30
  • 41
ChufanSuki
  • 83
  • 1
  • 6
  • 2
    What do you mean by "better" ? More or less wire ? More or less circuit surface ? More or less control possibilities ? Code more readable ? More simple ? The only differences I see is that the blocking one can be controlled so it's more flexible but require more wires as you said. – Welgriv May 14 '20 at 07:52
  • Actually I am trying to write an adder and I want to stall and flash pipeline at some stage. I use the first method and add a `logic [2:0 ]stall` signal and says that `if (stall != `STALLFIRST)` then run the fist stage et cetera. (In addition, if it matters, I moved all unblocking assignment in one `always` block.) What I mean better is that less digital resources with right answer. (like a good practice) – ChufanSuki May 14 '20 at 08:29

2 Answers2

1

The problem with the first version is that there seems to be no clock gate at all. Unless your clock is well gated on a higher level or the pipeline is used every cycle you will waste a lot of power by (unnecessarily) toggling each stage of the pipeline every cycle.

Moberg
  • 5,253
  • 4
  • 38
  • 54
0

As good practice, the second one seems "better" in the sense that when you design a hardware circuit part you might want offer great control possibilities. Generally speaking, since your code will be implemented in the silicon forever (or in your FPGA with painful reconfiguration) that would be a real problem to not have enough controls capacities, because you can't really add some afterward.

As an example you already mentioned in the comments that you'll have to stall the pipeline, so of course you need more wires to do it. You will also need to reset the pipeline sometimes, this is the purpose of the rst signal.

However, more signals means more silicon surface (or more FPGA resources using) which generally come with a greater price. One can argue that only one or two wires will not makes such great difference for a chip, which is true, but if you re-use your pipeline thousand times on the circuit it will be much more significant.

For me the first implementation can be relevant only with really strong optimization requirements at circuit level like for an ASIC, where you exactly know the overall wanted behavior.

Welgriv
  • 714
  • 9
  • 24