Опубликован: 19.04.2025 | Доступ: свободный | Студентов: 1 / 0 | Длительность: 07:05:00
Лекция 7:
Конвейеризированное процессорное ядро
Из всего этого следует, что необходимо как-то разрешать данную ситуацию. Варианты могут быть следующие.
- Немного модифицируем логику выборки команд так, чтобы при обнаружении команд перехода (любого) запрещается дальнейшая загрузка команд в конвейер (это можно сделать даже на первом этапе. Но это приведет к тому, что данные команды в любом случае будут выполняться несколько тактов, вне зависимости от того, выполняется условие перехода или нет.
- Можно добавить опцию сброса конвейера при обнаружении перехода - например все этапы заменяем на выполнение операции "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;



