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

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

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >

L4 - запись нового значения в программный счётчик.

Возможно, данный этап можно было совместить с предыдущим, но пока для наглядности оставим его. Вычисленный результат нового адреса перехода и сигнал записи в программный счетчик из регистра R4 подаются на соответствующие входы программного счётчика.

Запись нового значения в программный счётчик

Рис. 7.9. Запись нового значения в программный счётчик
wire r4l4_PC_load;
wire [31:0] r4l4_Rez;

wire [255:0] r4_in;
wire [255:0] r4_out;
assign r7_in = {Rez, l3r4_PC_load, 223'h0};
wire [222:0] r4_null;
assign {r4l4_Rez, r4l4_PC_load, r4_null} = r4_out;

rv_r_reg R4(
  .clk(clk),
  .rst_n(rst),
  //.en(en_level[6]),
  .en(1'b1),
  .r_in(r4_in),
  .r_out(r4_out)
);

Общий код процессора:

`include "rv_pc.v"
`include "rv_mem.v"
`include "rv_desh.v"
`include "rv_imm.v"
`include "rv_reg_file_tst.v"
`include "rv_ops_mux.v"
`include "rv_cmp.v"
`include "rv_alu_v.v"
`include "rv_rez_mux.v"
`include "rv_csr.v"
`include "rv_r_reg.v"
`include "rv_ring_reg.v"

module rv_cpu_top
#(
  parameter DATA_WIDTH=32,
  parameter ADDR_WIDTH=32
  )
( input clk,
  input rst,
//  input [(ADDR_WIDTH-1):0] Data_In,
  output[(DATA_WIDTH-1):0] Data_out
);

// CPU modules 
///*
wire [6:0] en_level;

rv_ring_reg ring_reg(
  .clk(clk),
  .rst_n(rst),
  .L_en(en_level)
);
//*/
// L0_R1
wire [31:0]l0r1_PC;
wire [31:0]l0r1_PCplus;
wire [31:0]r1l1_PC;
wire [31:0]r1l1_PCplus;

rv_pc pc( // programm counter
  .clk(clk),
  .rst_n(rst),
  //.en(en_level[6]),
  .en(1'b1),
  .pc_load(r4l4_PC_load),
  .pc_next(r4l4_Rez),
  .pc(l0r1_PC),
  .pc_plus(l0r1_PCplus)
);
wire [255:0] r1_in;
assign r1_in = {l0r1_PC, l0r1_PCplus, 192'h0}; 
wire [255:0] r1_out;
wire [191:0] r1_null;
assign {r1l1_PC, r1l1_PCplus, r1_null} = r1_out; 

rv_r_reg R1(
  .clk(clk),
  .rst_n(rst),
  //.en(en_level[0]),
  .en(1'b1),
  .r_in(r1_in),
  .r_out(r1_out)
);
// R1_L1
wire [31:0] l1r2_iw;
wire [31:0] l1r2_PC;
wire [31:0] l1r2_PCplus;

rv_mem mem( // system memory
  .clk(clk),
  //.i_addr(32'h0), //(r1l1_PC),
  .i_addr(r1l1_PC>>2),
  .code_out(l1r2_iw),
  .d_addr(Rez>>2),
  .d_out(Mem_data),
  .d_in(Rs2_reg),
  .we(r3l3_mem_wr),
  .en(1'b1)
);
// L1_R2
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 = {l1r2_iw, r1l1_PC, r1l1_PCplus, 160'h0};
wire [159:0] r2_null;
assign {r2l2_iw, r2l2_PC, r2l2_PCplus, r2_null} = r2_out;
rv_r_reg R2(
  .clk(clk),
  .rst_n(rst),
  //.en(en_level[1]),
  .en(1'b1),
  .r_in(r2_in),
  .r_out(r2_out)
);
// L2_R3
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;
rv_desh desh( // instruction decoder
  .inst(r2l2_iw),
  .opcode(l2r3_op),
  .rs1(l2r3_rs1),
  .rs1_en(),
  .rs2(l2r3_rs2),
  .rs2_en(),
  .rd(l2r3_rd),
  .rd_wr(l2r3_rd_wr),
  .funct3(l2r3_fn3),
  .f3_en(),
  .funct7(l2r3_fn7),
  .f7_en(),
  .mem_en(),
  .mem_wr(l2r3_mem_wr),
  .csr_en(),
  .csr_wr(l2r3_csr_wr),
  .pc_load()
);
rv_imm immed(  // immediate decoder
  .inst(r2l2_iw),
  .imm(l2r3_imm)
);
wire [4:0] r3l3_rs1;
wire [4:0] r3l3_rs2;
wire [6:0] r3l3_op;
wire [2:0] r3l3_fn3;
wire [6:0] r3l3_fn7;
wire [4:0] r3l3_rd;
wire r3l3_rd_wr;
wire r3l3_mem_wr;
wire r3l3_csr_wr;
wire [31:0] r3l3_imm;
wire [31:0] r3l3_PC;
wire [31:0] r3l3_PCplus;

wire [255:0] r3_in;
wire [255:0] r3_out;
assign r3_in = {l2r3_rs1, l2r3_rs2, l2r3_op, l2r3_fn3, l2r3_fn7, l2r3_rd, l2r3_rd_wr,
    l2r3_mem_wr, l2r3_csr_wr, l2r3_imm,  r2l2_PC, r2l2_PCplus, 125'h0};
wire [124:0] r3_null;
assign {r3l3_rs1, r3l3_rs2, r3l3_op, r3l3_fn3, r3l3_fn7, r3l3_rd, r3l3_rd_wr,
    r3l3_mem_wr, r3l3_csr_wr, r3l3_imm,  r3l3_PC, r3l3_PCplus, r3_null} = r3_out;
rv_r_reg R3(
  .clk(clk),
  .rst_n(rst),
  //.en(en_level[2]),
  .en(1'b1),
  .r_in(r3_in),
  .r_out(r3_out)
);
//L3_R4
wire [31:0] Rs1_reg;
wire [31:0] Rs2_reg;
wire [31:0] CSR_mux;

rv_reg_file reg_file(   // register's file
  .clk(clk),
  .rs1(r3l3_rs1),
  .rs2(r3l3_rs2),
  .rd(r3l3_rd),
  .Rs1_out(Rs1_reg),
  .Rs2_out(Rs2_reg),
  .Rd_input(Rd_reg),
  .we(r3l3_rd_wr),
  .en(1'b1)
);
rv_csr csr(
  .clk(clk),
  .csr_addr(r3l3_imm[11:0]),
  .csr_in(Rez),
  .csr_out(CSR_mux),
  .csr_wr(r3l3_csr_wr),
  .en(1'b1)
);
wire [31:0] Op1;
wire [31:0] Op2;
rv_ops_mux ops_mux(
  .opcode(r3l3_op),
  .funct3(r3l3_fn3),
  .funct7(r3l3_fn7),
  .Rs1(Rs1_reg),
  .Rs2(Rs2_reg),
  .imm(r3l3_imm),
  .PC(r3l3_PC),
  .CSR(CSR_mux),
  .Op1(Op1),
  .Op2(Op2)
);
rv_cmp cmp(
  .opcode(r3l3_op),
  .funct3(r3l3_fn3),
  .Rs1(Rs1_reg),
  .Rs2(Rs2_reg),
  .pc_new(l3r4_PC_load)
);
wire [31:0] Rez;
wire [31:0] Rd_reg;
wire [31:0] Mem_data;
rv_alu_v alu_v(
  .opcode(r3l3_op),
  .funct3(r3l3_fn3),
  .funct7(r3l3_fn7),
  .Op1(Op1),
  .Op2(Op2),
  .Rez(Rez)
);

rv_rez_mux rez_mux(
  .opcode(r3l3_op),
  .funct3(r3l3_fn3),
  .funct7(r3l3_fn7),
  .Rez(Rez),
  .Pc_plus(r3l3_PCplus),
  .Mem_data(Mem_data),
  .Imm(r3l3_imm),
  .Rd(Rd_reg)
);

wire r4l4_PC_load;
wire [31:0] r4l4_Rez;

wire [255:0] r4_in;
wire [255:0] r4_out;
assign r4_in = {Rez, l3r4_PC_load, 223'h0};
wire [222:0] r4_null;
assign {r4l4_Rez, r4l4_PC_load, r4_null} = r4_out;

rv_r_reg R4(
  .clk(clk),
  .rst_n(rst),
  .en(1'b1),
  .r_in(r4_in),
  .r_out(r4_out)
);

Endmodule

При выполнении всё той же тестовой программы, где фиксировалась неточность (ошибочность функционирования) видно, что ситуация с регистрами выправилась. И до определенного момента выполнение кода адекватно, а именно - до инструкций переходов/ветвления.

Перенос операции записи нового адреса перехода в программный счетчик лишь немного решает проблему - да, переход совершается, но происходит выполнение команд, уже попавших в конвейер (рис.7.12 -7.13), что, конечно же, недопустимо.

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >