Change FSM to pipeline
Published: 2024-06-14 11:43:00

Hi guys, I'm a newbie in learning Verilog, I have written a simple FSM below, and now I wanna change it using pipeline to increase the performance, but I'm so confused because I haven't learnt pipeline since I finished this FSM, can anyone help me to rewrite it using pipeline and tell me the difference between them, thanks in advance:

```
module processor (
    input wire clk,
    input wire rst
);
    localparam FETCH = 3'b000, LOAD_INS = 3'b001, LOAD_MEM = 3'b010, STORE_RF = 3'b011, EXECUTE = 3'b100, STORE_RF_ALU = 3'b101, STORE_MEM = 3'b110;

    wire [1:0] rf_readaddr1, rf_readaddr2, rf_write_addr;
    wire [7:0] rf_write_data, rf_read_data1, rf_read_data2;
    wire rf_we;
    register_file RF (
        .clk(clk),
        .we(rf_we),
        .read_addr1(rf_readaddr1),
        .read_addr2(rf_readaddr2),
        .write_addr(rf_write_addr),
        .write_data(rf_write_data),
        .read_data1(rf_read_data1),
        .read_data2(rf_read_data2)
    );

    wire [7:0] alu_x, alu_y, alu_out;
    wire alu_sl;
    alu alu (
        .clk(clk),
        .x(alu_x),
        .y(alu_y),
        .alu_sl(alu_sl),
        .alu_out(alu_out)
    );

    wire dm_we;
    wire [1:0] dm_addr;
    wire [7:0] dm_write_data, dm_read_data;
    data_memory DM (
        .clk(clk),
        .we(dm_we),
        .addr(dm_addr),
        .write_data(dm_write_data),
        .read_data(dm_read_data)
    );

    wire [3:0] pm_addr;
    wire [7:0] pm_instr;
    program_memory PM (
        .clk(clk),
        .addr(pm_addr),
        .instr(pm_instr)
    );
 
 
    // State change
    reg [2:0] state, next;
    always @(*) begin
        next = 2'bx;
        case (state)
            FETCH: begin
                next = LOAD_INS;
            end
            LOAD_INS: begin
                if (pm_instr[7:6] == 2'b10) 
                    next = LOAD_MEM;
                else if (pm_instr[7:6] == 2'b11) 
                    next = STORE_MEM;
                else next = EXECUTE;
            end
            LOAD_MEM: begin
                next = STORE_RF;
            end
            STORE_RF: begin
                next = FETCH;
            end
            EXECUTE: begin
                next = STORE_RF_ALU;
            end
            STORE_RF_ALU: begin
                next = FETCH;
            end
            STORE_MEM: begin
                next = FETCH;
            end
        endcase
    end

    always @(posedge clk) begin
        if (rst) begin
            state <= FETCH;
        end else begin
            state <= next;
        end
    end

    // fetch instruction
    reg [3:0] pc;
    reg [7:0] temp_ins;

    always @(posedge clk) begin
        if (rst) begin
            pc <= 0;
        end else begin
            if (state == FETCH) pc <= pc + 1;
        end
    end

    assign pm_addr = pc;
   
    // load instruction
    always @(posedge clk) begin
        if (state == LOAD_INS) temp_ins <= pm_instr;
    end

    // state EXE
    reg op;

    always @(*) begin
        op = 1'bx;
        if (state == EXECUTE) begin
            case(temp_ins[7:6])
                2'b00: begin // ADD
                    op = 1'b0; 
                end
                2'b01: begin // SUB
                    op = 1'b1; 
                end
            endcase
        end
    end

    assign alu_sl = op;
    assign rf_readaddr1 = temp_ins[5:4];
    assign rf_readaddr2 = temp_ins[3:2];
    assign alu_x = rf_read_data1;
    assign alu_y = rf_read_data2;

    // memory signal assign
    assign dm_we = (state == STORE_MEM);
    assign dm_write_data = (state == STORE_MEM) ? rf_read_data1:0;
    assign dm_addr = (state == LOAD_MEM || state == STORE_MEM) ? temp_ins[3:2]:2'b0;

    // register file store
    reg [7:0] write_data_rf; 
    
    always @(*) begin
        write_data_rf = 8'bx;
        case(state)
            STORE_RF: begin
                write_data_rf = dm_read_data;
            end
            STORE_RF_ALU: begin
                write_data_rf = alu_out;
            end
        endcase
    end

    assign rf_write_data = write_data_rf;
    assign rf_write_addr = (state == STORE_RF || state == STORE_RF_ALU) ? temp_ins[1:0]:2'b0;
    assign rf_we = (state == STORE_RF || state == EXECUTE || state == STORE_RF_ALU);
endmodule
//Change it into pipeline by the simplest way (just add some blocks and register)
```