Опубликован: 19.04.2025 | Доступ: свободный | Студентов: 1 / 0 | Длительность: 07:05:00
Лекция 7:

Конвейеризированное процессорное ядро

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >
Тестовая программа в симуляторе RARS

Рис. 7.10. Тестовая программа в симуляторе RARS
Временные диаграммы

Рис. 7.11. Временные диаграммы
Тестовая программа в симуляторе RARS

Рис. 7.12. Тестовая программа в симуляторе RARS
Временные диаграммы тестирования работы варианта конвейера

Рис. 7.13. Временные диаграммы тестирования работы варианта конвейера

Из всего этого следует, что необходимо как-то разрешать данную ситуацию. Варианты могут быть следующие.

  1. Немного модифицируем логику выборки команд так, чтобы при обнаружении команд перехода (любого) запрещается дальнейшая загрузка команд в конвейер (это можно сделать даже на первом этапе. Но это приведет к тому, что данные команды в любом случае будут выполняться несколько тактов, вне зависимости от того, выполняется условие перехода или нет.
  2. Можно добавить опцию сброса конвейера при обнаружении перехода - например все этапы заменяем на выполнение операции "nop" - ее роль в архитектуре RISC-V исполняет команда " addi x0,x0,0" (как один из вариантов).

Попытаемся пойти вторым путём, так как первый действительно порождает много циклов простоя.

Немного модифицируется дешифратор команд - вводим дополнительный входной сигнал "сброса конвейера", по которому дешифратор при любом входном слове выдает комбинацию сигналов, соответствующих "nop" (в наборе команд RV32I nop соответствует, например, команда сложения add x0,x0,x0):

module rv_desh
( input [31:0] inst,
  output reg [6:0] opcode,
  output reg [4:0] rs1,
  output reg rs1_en,
  output reg [4:0] rs2,
  output reg rs2_en,
  output reg [4:0] rd,
  output reg rd_wr,
  output reg [2:0] funct3,
  output reg f3_en,
  output reg [6:0] funct7,
  output reg f7_en,
  output reg mem_en,
  output reg mem_wr,
  output reg csr_en,
  output reg csr_wr,
  input pipe_rst,
  output reg pc_load
);

always @ *
begin
    if (pipe_rst) begin
        opcode[6:0] <= 7'b0010011;
        rs1 <= 5'h0;
        rs2 <= 5'h0;
        rd <= 5'h0;
        funct3 <= 3'b0;
        funct7 <= 3'b0;
        end
    else begin
        opcode[6:0] <= inst[6:0];
        rs1 <= inst[19:15];
        rs2 <= inst[24:20];
        rd <= inst[11:7];
        funct3 <= inst[14:12];
        funct7 <= inst[31:25];
    end
end

always @ *
begin
  case (opcode)
    //I-type
    7'b00000_11 : begin // load data from mem
        $display("LOAD");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b1;
        f3_en <= 1'b1;
        f7_en <= 1'b0;
        mem_en <= 1'b1;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    7'b00011_11 : begin // fence
        $display("fence");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b1;
        f3_en <= 1'b1;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    7'b00100_11 : begin // reg with immediate operations
        $display("OP-IMM");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b1;
        f3_en <= 1'b1;
        f7_en <= 1'b1;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    7'b00100_11 : begin // reg with reg operations
        $display("OP-reg");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b1;
        f3_en <= 1'b1;
        f7_en <= 1'b1;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    7'b11100_11 : begin // mret - system return
        $display("RET_SYST");
        rs1_en <= 1'b0;
        rs2_en <= 1'b0;
        rd_wr <= 1'b0;
        f3_en <= 1'b1;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        if (funct3 == 3'b000) begin
            csr_en <= 1'b0;
            csr_wr <= 1'b0; 
        end 
        else begin  // operations with CSR 
            csr_en <= 1'b1;
            csr_wr <= 1'b1; 
        end 
        pc_load <= 1'b0;        
        end
    7'b11001_11 : begin // Relative (rs1) jump and link in register
        $display("JALR");
        rs1_en <= 1'b1;
        rs2_en <= 1'b0;
        rd_wr <= 1'b1;
        f3_en <= 1'b0;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b1;
        end
    //J-type
    7'b11011_11 : begin // pc relative jump and link in register
        $display("JAL");
        rs1_en <= 1'b0;
        rs2_en <= 1'b0;
        rd_wr <= 1'b1;
        f3_en <= 1'b0;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b1;
        end
    //S-type
    7'b01000_11 : begin // store register value in memory
        $display("Store");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b0;
        f3_en <= 1'b1;
        f7_en <= 1'b0;
        mem_en <= 1'b1;
        mem_wr <= 1'b1;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    //U-type
    7'b01101_11 : begin // load upper immediate
        $display("LUI");
        rs1_en <= 1'b0;
        rs2_en <= 1'b0;
        rd_wr <= 1'b1;
        f3_en <= 1'b0;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    7'b00101_11 : begin // add upper immediate to PC
        $display("AUIPC");
        rs1_en <= 1'b0;
        rs2_en <= 1'b0;
        rd_wr <= 1'b1;
        f3_en <= 1'b0;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
    //B-type
    7'b11000_11 : begin // conditional PC relative branch - PC+imm
        $display("BRANCH");
        rs1_en <= 1'b1;
        rs2_en <= 1'b1;
        rd_wr <= 1'b0;
        f3_en <= 1'b1;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b1; // must be 'AND' with compatator output signal
        end
    default: begin
        $display ("default");
        rs1_en <= 1'b0;
        rs2_en <= 1'b0;
        rd_wr <= 1'b0;
        f3_en <= 1'b0;
        f7_en <= 1'b0;
        mem_en <= 1'b0;
        mem_wr <= 1'b0;
        csr_en <= 1'b0;
        csr_wr <= 1'b0;
        pc_load <= 1'b0;
        end
  endcase
end
endmodule

Вводим биты сброса конвейера в сам конвейер.

Этап L0:

wire [255:0] r1_in;
assign r1_in = {l3r4_PC_load, l0r1_PC, l0r1_PCplus, 191'h0}; 
wire [255:0] r1_out;
wire [190:0] r1_null;
assign {r1l1_pipe_rst, r1l1_PC, r1l1_PCplus, r1_null} = r1_out; 

rv_r_reg R1(
  .clk(clk),
  .rst_n(rst),
  .en(1'b1),
  .r_in(r1_in),
  .r_out(r1_out)
);

Этап L1:

wire [31:0]r2l2_iw;
wire [31:0]r2l2_PC;
wire [31:0]r2l2_PCplus;
wire [255:0] r2_in;
wire [255:0] r2_out;
assign r2_in = {r1l1_pipe_rst, l1r2_iw, r1l1_PC, r1l1_PCplus, 159'h0};
wire [158:0] r2_null;
assign {r2l2_pipe_rst, r2l2_iw, r2l2_PC, r2l2_PCplus, r2_null} = r2_out;

rv_r_reg R2(
  .clk(clk),
  .rst_n(rst),
  .en(1'b1),
  .r_in(r2_in),
  .r_out(r2_out)
);
wire [4:0] l2r3_rs1;
wire [4:0] l2r3_rs2;
wire [6:0] l2r3_op;
wire [2:0] l2r3_fn3;
wire [6:0] l2r3_fn7;
wire [4:0] l2r3_rd;
wire l2r3_rd_wr;
wire l2r3_mem_wr;
wire l2r3_csr_wr;
wire [31:0] l2r3_imm;
wire [31:0] l2r3_PC;
wire [31:0] l2r3_PCplus;
< Лекция 6 || Лекция 7: 12345 || Лекция 8 >