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

Многотактное процессорное ядро

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >

Выходы Rs1, Rs2 и выбранного CSR также записываются в регистр R4.

Выборка операндов из файл-регистров

Рис. 6.4. Выборка операндов из файл-регистров
wire [31:0] l3r4_Rs1_reg;
wire [31:0] l3r4_Rs2_reg;
wire [31:0] l3r4_CSR;

rv_reg_file reg_file(   // register's file
  .clk(clk),
  .rs1(r3l3_rs1),
  .rs2(r3l3_rs2),
  .rd(r6l6_rd),
  .Rs1_out(l3r4_Rs1_reg),
  .Rs2_out(l3r4_Rs2_reg),
  .Rd_input(Rd_reg),
  .we(r6l6_rd_wr),
  .en(en_level[6])
);
rv_csr csr(
  .csr_addr(r3l3_imm[11:0]),
  .csr_in(r6l6_Rez),
  .csr_out(l3r4_CSR),
  .csr_wr(r6l6_csr_wr),
  .en(en_level[3])
);
assign Data_out = l3r4_CSR; //CSR;
wire [31:0] r4l4_Rs1_reg;
wire [31:0] r4l4_Rs2_reg;
wire [6:0] r4l4_op;
wire [2:0] r4l4_fn3;
wire [6:0] r4l4_fn7;
wire [4:0] r4l4_rd;
wire r4l4_rd_wr;
wire r4l4_mem_wr;
wire r4l4_csr_wr;
wire [31:0] r4l4_imm;
wire [31:0] r4l4_PC;
wire [31:0] r4l4_PCplus;
wire [31:0] r4l4_CSR;
wire [255:0] r4_in;
wire [255:0] r4_out;
assign r4_in = {l3r4_Rs1_reg, l3r4_Rs2_reg, r3l3_op, r3l3_fn3, r3l3_fn7, r3l3_rd, r3l3_rd_wr,
    r3l3_mem_wr, r3l3_csr_wr, r3l3_imm,  r3l3_PC, r3l3_PCplus, l3r4_CSR, 39'h0};
wire [38:0] r4_null;
assign {r4l4_Rs1_reg, r4l4_Rs2_reg, r4l4_op, r4l4_fn3, r4l4_fn7, r4l4_rd, r4l4_rd_wr,
    r4l4_mem_wr, r4l4_csr_wr, r4l4_imm,  r4l4_PC, r4l4_PCplus, r4l4_CSR, r4_null} = r4_out;

rv_r_reg R4(
  .clk(clk),
  .rst_n(rst),
  .en(en_level[3]),
  .r_in(r4_in),
  .r_out(r4_out)
);

L4 - этап работы арифметико-логического устройства( АЛУ)

В рассматриваемой архитектуре АЛУ применяется для действий над операндами из файл-регистров, для вычисления адресов переходов, действий над считанными значениями регистров специального назначения. Из R4 на мультиплексор поступают возможные операнды, выбор двух операндов производится в зависимости от управляющих кодов (opcode, funct3, funct7).

Параллельно Rs1, Rs2 и опкоды подаются на блок разрешения переноса (по факту - компаратор с входами разрешения).

Все остальные сигналы плюс копия Rs2 транзитом подаются на вход регистра R5.

L5 - чтение/запись данных из оперативной памяти

На этом шаге производятся операции с памятью (памятью данных). Из регистра R5 выбираются результаты АЛУ, значение регистра Rs2, сигнал управления записью. Остальные сигналы транзитом подаются на вход регистра R6.

L6 - запись данных в файл-регистры.

Потенциальные результаты для записи в Rd подаются на вход мультиплексора, определяющего какое из значений будет записано в регистр Rd. Данные для записи также подаются на входы блока регистра специального назначения (CSR). Транзитом следует только новое значение программного счетчика и сигнал разрешения его модификации.

Подача операндов на АЛУ

Рис. 6.5. Подача операндов на АЛУ
wire [31:0] Op1;
wire [31:0] Op2;

rv_ops_mux ops_mux(
  .opcode(r4l4_op),
  .funct3(r4l4_fn3),
  .funct7(r4l4_fn7),
  .Rs1(r4l4_Rs1_reg),
  .Rs2(r4l4_Rs2_reg),
  .imm(r4l4_imm),
  .PC(r4l4_PC),
  .CSR(r4l4_CSR),
  .Op1(Op1),
  .Op2(Op2)
);
rv_cmp cmp(
  .opcode(r4l4_op),
  .funct3(r4l4_fn3),
  .Rs1(r4l4_Rs1_reg),
  .Rs2(r4l4_Rs2_reg),
  .pc_new(l4r5_PC_load)
);
rv_alu_v alu_v(
  .opcode(r4l4_op),
  .funct3(r4l4_fn3),
  .funct7(r4l4_fn7),
  .Op1(Op1),
  .Op2(Op2),
  .Rez(l4r5_Rez)
);
wire [31:0] l4r5_Rez;
wire l4r5_PC_load;
wire [31:0] r5l5_Rez;
wire [31:0] r5l5_Rs2_reg;
wire [6:0] r5l5_op;
wire [2:0] r5l5_fn3;
wire [6:0] r5l5_fn7;
wire [4:0] r5l5_rd;
wire r5l5_rd_wr;
wire r5l5_mem_wr; 
wire r5l5_csr_wr;
wire [31:0] r5l5_imm;
wire [31:0] r5l5_PC;
wire [31:0] r5l5_PCplus;
wire r5l5_PC_load;
//L5
wire [255:0] r5_in;
wire [255:0] r5_out;
assign r5_in = {l4r5_Rez, r4l4_Rs2_reg, r4l4_op, r4l4_fn3, r4l4_fn7, r4l4_rd, r4l4_rd_wr,
    r4l4_mem_wr, r4l4_csr_wr, r4l4_imm,  r4l4_PC, r4l4_PCplus, l4r5_PC_load, 70'h0};
wire [69:0] r5_null;
assign {r5l5_Rez, r5l5_Rs2_reg, r5l5_op, r5l5_fn3, r5l5_fn7, r5l5_rd, r5l5_rd_wr,
    r5l5_mem_wr, r5l5_csr_wr, r5l5_imm,  r5l5_PC, r5l5_PCplus, r5l5_PC_load, r5_null} = r5_out;
rv_r_reg R5(
  .clk(clk),
  .rst_n(rst),
  .en(en_level[4]),
  .r_in(r5_in),
  .r_out(r5_out)
);
Чтение/запись данных из оперативной памяти

Рис. 6.6. Чтение/запись данных из оперативной памяти
wire [31:0] l5r6_Mem_data;
wire [31:0] r6l6_Mem_data;
wire [31:0] r6l6_Rez;
wire [31:0] r6l6_Rs2_reg;
wire [6:0] r6l6_op;
wire [2:0] r6l6_fn3;
wire [6:0] r6l6_fn7;
wire [4:0] r6l6_rd;
wire r6l6_rd_wr;
wire r6l6_mem_wr;
wire r6l6_csr_wr; 
wire [31:0] r6l6_imm;
wire [31:0] r6l6_PC;
wire [31:0] r6l6_PCplus;
wire r6l6_PC_load;
wire [255:0] r6_in;
wire [255:0] r6_out;
assign r6_in = {l5r6_Mem_data, r5l5_Rez,  r5l5_op, r5l5_fn3, r5l5_fn7, r5l5_rd, r5l5_rd_wr,
    r5l5_mem_wr, r5l5_csr_wr, r5l5_imm,  r5l5_PC, r5l5_PCplus, r5l5_PC_load, 70'h0};
wire [69:0] r6_null;
assign {r6l6_Mem_data, r6l6_Rez, r6l6_op, r6l6_fn3, r6l6_fn7, r6l6_rd, r6l6_rd_wr,
    r6l6_mem_wr, r6l6_csr_wr, r6l6_imm,  r6l6_PC, r6l6_PCplus, r6l6_PC_load, r6_null} = r6_out;
rv_r_reg R6(
  .clk(clk),
  .rst_n(rst),
  .en(en_level[5]),
  .r_in(r6_in),
  .r_out(r6_out)
);
wire [31:0] Rd_reg;
rv_rez_mux rez_mux(
  .opcode(r6l6_op),
  .funct3(r6l6_fn3),
  .funct7(r6l6_fn7),
  .Rez(r6l6_Rez),
  .Pc_plus(r6l6_PCplus),
  .Mem_data(r6l6_Mem_data),
  .Imm(r6l6_imm),
  .Rd(Rd_reg)
);
Запись в файл-регистры

Рис. 6.7. Запись в файл-регистры
wire [31:0] Rd_reg;

rv_rez_mux rez_mux(
  .opcode(r6l6_op),
  .funct3(r6l6_fn3),
  .funct7(r6l6_fn7),
  .Rez(r6l6_Rez),
  .Pc_plus(r6l6_PCplus),
  .Mem_data(r6l6_Mem_data),
  .Imm(r6l6_imm),
  .Rd(Rd_reg)
);

Общая структура процессора представлена на рис.6.8.

Регистры R1-R6 являются достаточно "широкими" - их разрядность с запасом взята 256 бит (да, немного расточительно с точки зрения ресурсов кристалла/FPGA, но достаточно наглядно). Кольцевой счетчик, выдающий сигналы разрешения и "широкие" регистры хранения промежуточных результатов.

module rv_ring_reg
#(
parameter WIDTH=7
)
(
  input clk,
  input rst_n,
  output  [WIDTH-1:0] L_en
);
reg [WIDTH-1:0] ring;
always@(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      ring   <= 8'b00000001;
    else
      ring <= {ring[WIDTH-2:0],ring[WIDTH-1]};
    end
assign L_en = ring; 
endmodule
module rv_r_reg
#(
  parameter WIDTH=256
  )
(
  input clk,
  input rst_n,
  input en,
  input  [WIDTH - 1:0] r_in,
  output reg [WIDTH - 1:0] r_out
);

always@(posedge clk or negedge rst_n)
  begin
    if(!rst_n)
      r_out <= 0;
    else
      if(en) begin r_out <= r_in; end
    end
endmodule
Структура многотактного процессора

Рис. 6.8. Структура многотактного процессора
< Лекция 5 || Лекция 6: 1234 || Лекция 7 >