Многотактное процессорное ядро
Выходы Rs1, Rs2 и выбранного CSR также записываются в регистр R4.
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). Транзитом следует только новое значение программного счетчика и сигнал разрешения его модификации.
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)
);
|
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)
);
|
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
|




