【RISC-V设计-10】- RISC-V处理器设计K0A之IDU
文章目录
- 【RISC-V设计-10】- RISC-V处理器设计K0A之IDU
- 1.简介
- 2.顶层设计
- 3.端口说明
- 4.代码设计
- 5.总结
1.简介
指令译码单元(Instruction Decoder Unit,简称IDU)是CPU中的一个关键组件,其主要作用是将从内存中获取的指令进行解读和翻译,使其能够被CPU的其它组件理解和执行。指令译码单元承接总线管理单元(BMU)发送过来的指令和数据以及核内中断控制器(CIC)发过来的中断请求,然后经过转换后发送给算术运算单元(ALU)、通用寄存器组(GPR)、控制与状态寄存器(CSR)以及和BMU、CIC的交互。,指令译码单元在 CPU 的整体运行中起着承上启下、转换协调的重要作用,确保了 CPU 各组件之间的高效协同工作。
2.顶层设计
指令译码单元与其他所有模块相互交流协作,不同模块之间直接或间接地通过指令译码单元实现耦合。
3.端口说明
序号 | 端口 | 位宽 | 方向 | 说明 |
---|---|---|---|---|
1 | bmu2idu_valid | 1 | input | 指令有效指示 |
2 | bmu2idu_instr | 32 | input | 需要执行的指令 |
3 | bmu2idu_pc_cur | 18 | input | 当前指令的PC |
4 | bmu2idu_pc_nxt | 18 | input | 下一条指令的PC |
5 | idu2bmu_pc_set | 1 | output | 程序计数器设置 |
6 | idu2bmu_pc_new | 18 | output | 新的程序计数器 |
7 | bmu2idu_pc_ack | 1 | input | 程序计数器应答 |
8 | idu2bmu_ls_req | 1 | output | 加载与存储请求 |
9 | idu2bmu_ls_cmd | 1 | output | 加载与存储命令,1写0读 |
10 | idu2bmu_ls_size | 2 | output | 加载与存储写数据字节数 |
11 | idu2bmu_ls_addr | 20 | output | 加载与存储的地址 |
12 | idu2bmu_ls_wdata | 32 | output | 加载与存储的写数据 |
13 | bmu2idu_ls_rdata | 32 | input | 加载与存储的读数据 |
14 | idu2gpr_we | 1 | output | 通用寄存器组写使能,高有效 |
15 | idu2gpr_waddr | 4 | output | 通用寄存器组写地址 |
16 | idu2gpr_wdata | 32 | output | 通用寄存器组写数据 |
17 | idu2gpr_raddr1 | 4 | output | 通用寄存器组读地址1 |
18 | idu2gpr_raddr2 | 4 | output | 通用寄存器组读地址2 |
19 | gpr2idu_rdata1 | 32 | input | 通用寄存器组读数据1 |
20 | gpr2idu_rdata2 | 32 | input | 通用寄存器组读数据2 |
21 | idu2csr_we | 1 | output | CSR读写总线,写使能 |
22 | idu2csr_addr | 12 | output | CSR读写总线,地址 |
23 | idu2csr_wdata | 32 | output | CSR读写总线,写数据 |
24 | csr2idu_rdata | 32 | input | CSR读写总线,读数据 |
25 | idu2alu_op | 4 | output | ALU的操作码 |
26 | idu2alu_rs1 | 32 | output | 运算的第一操作数 |
27 | idu2alu_rs2 | 32 | output | 运算的第二操作数 |
28 | alu2idu_res | 32 | input | 数值运算的结果 |
29 | alu2idu_cmp | 1 | input | 比较运算的结果 |
30 | idu2alu_addr1 | 20 | output | 地址运算的第一操作数 |
31 | idu2alu_addr2 | 20 | output | 地址运算的第二操作数 |
32 | alu2idu_addro | 20 | input | 地址运算的输出结果 |
33 | cic2idu_int_req | 1 | input | 中断请求 |
34 | idu2cic_int_ack | 1 | output | 中断应答 |
35 | idu2cic_int_mret | 1 | output | 中断返回 |
4.代码设计
// -------------------------------------------------------------------------------------------------
// Copyright 2024 Kearn Chen, kearn.chen@aliyun.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------
// Description :
// 1. Instruction Decoder Unit
// -------------------------------------------------------------------------------------------------
module k0a_core_idu (
input wire bmu2idu_valid ,
input wire [31:0] bmu2idu_instr ,
input wire [17:0] bmu2idu_pc_cur ,
input wire [17:0] bmu2idu_pc_nxt ,
output wire idu2bmu_pc_set ,
output wire [17:0] idu2bmu_pc_new ,
input wire bmu2idu_pc_ack ,
output wire idu2bmu_ls_req ,
output wire idu2bmu_ls_cmd ,
output wire [1:0] idu2bmu_ls_size ,
output wire [19:0] idu2bmu_ls_addr ,
output wire [31:0] idu2bmu_ls_wdata ,
input wire [31:0] bmu2idu_ls_rdata ,
output wire idu2gpr_we ,
output wire [3:0] idu2gpr_waddr ,
output wire [31:0] idu2gpr_wdata ,
output wire [3:0] idu2gpr_raddr1 ,
output wire [3:0] idu2gpr_raddr2 ,
input wire [31:0] gpr2idu_rdata1 ,
input wire [31:0] gpr2idu_rdata2 ,
output wire idu2csr_we ,
output wire [11:0] idu2csr_addr ,
output wire [31:0] idu2csr_wdata ,
input wire [31:0] csr2idu_rdata ,
input wire [17:0] csr2idu_mepc ,
input wire [17:0] csr2idu_mtvec ,
output wire idu2csr_mepc_set ,
output wire [17:0] idu2csr_mepc_nxt ,
output wire [3:0] idu2alu_op ,
output wire [31:0] idu2alu_rs1 ,
output wire [31:0] idu2alu_rs2 ,
input wire [31:0] alu2idu_res ,
input wire alu2idu_cmp ,
output wire [19:0] idu2alu_addr1 ,
output wire [19:0] idu2alu_addr2 ,
input wire [19:0] alu2idu_addro ,
input wire cic2idu_int_req ,
output wire idu2cic_int_ack ,
output wire idu2cic_int_mret
);
wire rvi_imm = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0010011;
wire rvi_reg = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0110011;
wire rvi_ldr = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0000011;
wire rvi_str = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0100011;
wire rvi_bra = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b1100011;
wire rvi_jal = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b1101111;
wire rvi_jar = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b1100111;
wire rvi_sys = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b1110011;
wire rvi_lui = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0110111;
wire rvi_aui = bmu2idu_valid & bmu2idu_instr[6:0] == 7'b0010111;
wire rvi_func3_000 = bmu2idu_instr[14:12] == 3'b000;
wire rvi_func3_001 = bmu2idu_instr[14:12] == 3'b001;
wire rvi_func3_010 = bmu2idu_instr[14:12] == 3'b010;
wire rvi_func3_011 = bmu2idu_instr[14:12] == 3'b011;
wire rvi_func3_100 = bmu2idu_instr[14:12] == 3'b100;
wire rvi_func3_101 = bmu2idu_instr[14:12] == 3'b101;
wire rvi_func3_110 = bmu2idu_instr[14:12] == 3'b110;
wire rvi_func3_111 = bmu2idu_instr[14:12] == 3'b111;
wire rvi_func7_zero = bmu2idu_instr[31:25] == 7'h00;
wire instr_lui = rvi_lui;
wire instr_auipc = rvi_aui;
wire instr_jal = rvi_jal;
wire instr_jalr = rvi_jar & rvi_func3_000;
wire instr_beq = rvi_bra & rvi_func3_000;
wire instr_bne = rvi_bra & rvi_func3_001;
wire instr_blt = rvi_bra & rvi_func3_100;
wire instr_bge = rvi_bra & rvi_func3_101;
wire instr_bltu = rvi_bra & rvi_func3_110;
wire instr_bgeu = rvi_bra & rvi_func3_111;
wire instr_lb = rvi_ldr & bmu2idu_instr[13:12] == 2'b00;
wire instr_lh = rvi_ldr & bmu2idu_instr[13:12] == 2'b01;
wire instr_lw = rvi_ldr & rvi_func3_010;
wire instr_lbu = rvi_ldr & bmu2idu_instr[14];
wire instr_lhu = rvi_ldr & bmu2idu_instr[14];
wire instr_sb = rvi_str & rvi_func3_000;
wire instr_sh = rvi_str & rvi_func3_001;
wire instr_sw = rvi_str & rvi_func3_010;
wire instr_addi = rvi_imm & rvi_func3_000;
wire instr_slti = rvi_imm & rvi_func3_010;
wire instr_sltiu = rvi_imm & rvi_func3_011;
wire instr_slt = rvi_reg & rvi_func3_010 & rvi_func7_zero;
wire instr_sltu = rvi_reg & rvi_func3_011 & rvi_func7_zero;
wire instr_csrrw = rvi_sys & rvi_func3_001;
wire instr_csrrs = rvi_sys & rvi_func3_010;
wire instr_csrrc = rvi_sys & rvi_func3_011;
wire instr_csrrwi = rvi_sys & rvi_func3_101;
wire instr_csrrsi = rvi_sys & rvi_func3_110;
wire instr_csrrci = rvi_sys & rvi_func3_111;
wire instr_mret = rvi_sys & bmu2idu_instr[31:7] == 25'h0604000;
wire branch_pc_set = instr_jal | instr_jalr | instr_mret | (instr_beq | instr_blt | instr_bltu) & alu2idu_cmp | (instr_bne | instr_bge | instr_bgeu) & ~alu2idu_cmp;
wire [17:0] branch_pc_new = instr_mret ? csr2idu_mepc : alu2idu_addro[19:2];
wire [31:0] gpr_wdata_lui = {32{instr_lui}} & {bmu2idu_instr[31:12], 12'd0};
wire [31:0] gpr_wdata_jal = {32{instr_jal | instr_jalr}} & {12'd0, bmu2idu_pc_nxt, 2'd0};
wire [31:0] gpr_wdata_alu = {32{rvi_aui | rvi_imm | rvi_reg}} & alu2idu_res;
wire [31:0] gpr_wdata_csr = {32{rvi_sys}} & csr2idu_rdata;
wire [31:0] gpr_wdata_lb0 = {32{instr_lb & ~idu2bmu_ls_addr[1] & ~idu2bmu_ls_addr[0]}} & {{24{bmu2idu_ls_rdata[7] & ~instr_lbu}}, bmu2idu_ls_rdata[7:0]};
wire [31:0] gpr_wdata_lb1 = {32{instr_lb & ~idu2bmu_ls_addr[1] & idu2bmu_ls_addr[0]}} & {{24{bmu2idu_ls_rdata[15] & ~instr_lbu}}, bmu2idu_ls_rdata[15:8]};
wire [31:0] gpr_wdata_lb2 = {32{instr_lb & idu2bmu_ls_addr[1] & ~idu2bmu_ls_addr[0]}} & {{24{bmu2idu_ls_rdata[23] & ~instr_lbu}}, bmu2idu_ls_rdata[23:16]};
wire [31:0] gpr_wdata_lb3 = {32{instr_lb & idu2bmu_ls_addr[1] & idu2bmu_ls_addr[0]}} & {{24{bmu2idu_ls_rdata[31] & ~instr_lbu}}, bmu2idu_ls_rdata[31:24]};
wire [31:0] gpr_wdata_lh0 = {32{instr_lh & ~idu2bmu_ls_addr[1]}} & {{16{bmu2idu_ls_rdata[15] & ~instr_lhu}}, bmu2idu_ls_rdata[15:0]};
wire [31:0] gpr_wdata_lh1 = {32{instr_lh & idu2bmu_ls_addr[1]}} & {{16{bmu2idu_ls_rdata[31] & ~instr_lhu}}, bmu2idu_ls_rdata[31:16]};
wire [31:0] gpr_wdata_lw = {32{instr_lw}} & bmu2idu_ls_rdata;
wire [31:0] csr_wdata_rw = {32{instr_csrrw}} & gpr2idu_rdata1;
wire [31:0] csr_wdata_rs = {32{instr_csrrs}} & (csr2idu_rdata | gpr2idu_rdata1);
wire [31:0] csr_wdata_rc = {32{instr_csrrc}} & (csr2idu_rdata & ~gpr2idu_rdata1);
wire [31:0] csr_wdata_rwi = {32{instr_csrrwi}} & {27'd0, bmu2idu_instr[19:15]};
wire [31:0] csr_wdata_rsi = {32{instr_csrrsi}} & (csr2idu_rdata | {27'd0, bmu2idu_instr[19:15]});
wire [31:0] csr_wdata_rci = {32{instr_csrrci}} & (csr2idu_rdata & ~{27'd0, bmu2idu_instr[19:15]});
wire [3:0] alu_op_beq = {4{instr_beq | instr_bne }} & 4'b1000;
wire [3:0] alu_op_blt = {4{instr_blt | instr_bge }} & 4'b1010;
wire [3:0] alu_op_bltu = {4{instr_bltu | instr_bgeu}} & 4'b1011;
wire [3:0] alu_op_calc = {4{rvi_imm | rvi_reg}} & {bmu2idu_instr[30] & ~instr_addi | instr_slti | instr_sltiu | instr_slt | instr_sltu, bmu2idu_instr[14:12]};
wire [31:0] alu_rs2_aui = {32{instr_auipc}} & {12'd0, bmu2idu_pc_cur, 2'd0};
wire [31:0] alu_rs2_imm = {32{rvi_imm}} & {{20{bmu2idu_instr[31]}}, bmu2idu_instr[31:20]};
wire [31:0] alu_rs2_reg = {32{rvi_reg | rvi_bra}} & gpr2idu_rdata2;
wire [19:0] alu_addr1_jal = {20{instr_jal}} & {bmu2idu_instr[19:12], bmu2idu_instr[20], bmu2idu_instr[30:21], 1'b0};
wire [19:0] alu_addr1_bra = {20{rvi_bra}} & {{8{bmu2idu_instr[31]}}, bmu2idu_instr[7], bmu2idu_instr[30:25], bmu2idu_instr[11:8], 1'b0};
wire [19:0] alu_addr1_reg = {20{rvi_ldr | rvi_str | instr_jalr}} & gpr2idu_rdata1[19:0];
wire [19:0] alu_addr2_ldr = {20{instr_jalr | rvi_ldr}} & {{8{bmu2idu_instr[31]}}, bmu2idu_instr[31:20]};
wire [19:0] alu_addr2_str = {20{rvi_str}} & {{8{bmu2idu_instr[31]}}, bmu2idu_instr[31:25], bmu2idu_instr[11:7]};
wire [19:0] alu_addr2_bra = {20{instr_jal | rvi_bra}} & {bmu2idu_pc_cur, 2'd0};
assign idu2gpr_we = rvi_imm | rvi_reg | rvi_ldr & bmu2idu_pc_ack | rvi_jal | rvi_jar | rvi_sys | rvi_lui | rvi_aui;
assign idu2gpr_waddr = bmu2idu_instr[10:7];
assign idu2gpr_raddr1 = bmu2idu_instr[18:15];
assign idu2gpr_raddr2 = bmu2idu_instr[23:20];
assign idu2gpr_wdata = gpr_wdata_lui | gpr_wdata_jal | gpr_wdata_alu | gpr_wdata_csr | gpr_wdata_lw |
gpr_wdata_lb0 | gpr_wdata_lb1 | gpr_wdata_lb2 | gpr_wdata_lb3 | gpr_wdata_lh0 | gpr_wdata_lh1;
assign idu2csr_we = rvi_sys;
assign idu2csr_addr = bmu2idu_instr[31:20];
assign idu2csr_wdata = csr_wdata_rw | csr_wdata_rs | csr_wdata_rc | csr_wdata_rwi | csr_wdata_rsi | csr_wdata_rci;
assign idu2cic_int_ack = bmu2idu_pc_ack;
assign idu2csr_mepc_set = cic2idu_int_req & idu2cic_int_ack;
assign idu2bmu_pc_set = branch_pc_set | idu2csr_mepc_set;
assign idu2bmu_pc_new = idu2csr_mepc_set ? csr2idu_mtvec : branch_pc_new;
assign idu2csr_mepc_nxt = branch_pc_set ? branch_pc_new : bmu2idu_pc_nxt;
assign idu2cic_int_mret = instr_mret;
assign idu2alu_op = alu_op_beq | alu_op_blt | alu_op_bltu | alu_op_calc;
assign idu2alu_rs1 = {32{~instr_auipc}} & gpr2idu_rdata1 | {32{instr_auipc}} & {bmu2idu_instr[31:12], 12'd0};
assign idu2alu_rs2 = alu_rs2_aui | alu_rs2_imm | alu_rs2_reg;
assign idu2bmu_ls_req = rvi_ldr | rvi_str;
assign idu2bmu_ls_cmd = rvi_str;
assign idu2bmu_ls_size = bmu2idu_instr[13:12];
assign idu2bmu_ls_addr = alu2idu_addro;
assign idu2bmu_ls_wdata = {32{instr_sb}} & {4{gpr2idu_rdata2[7:0]}} | {32{instr_sh}} & {2{gpr2idu_rdata2[15:0]}} | {32{instr_sw}} & gpr2idu_rdata2;
assign idu2alu_addr1 = alu_addr1_jal | alu_addr1_bra | alu_addr1_reg;
assign idu2alu_addr2 = alu_addr2_ldr | alu_addr2_str | alu_addr2_bra;
endmodule
5.总结
本篇文章详细介绍了指令译码单元的具体实现方式。其中,通过对相同类型指令集进行归并这一巧妙的操作,极大地优化了译码单元的电路结构。这种归并处理使得电路变得更加精简,减少了不必要的逻辑,同时也让整个电路更加整洁有序。在处理中断应答方面,存在着特定的规则。只有当当前正在执行指令的情况下,才能够产生中断应答。这是因为只有在执行指令的过程中,才能够准确地确定下一条指令的程序计数器(PC)的值。假设当前正在执行一条加法指令,只有在这条指令执行期间,系统才能判断是否满足产生中断应答的条件,并依据此来确定下一条指令的 PC 值,以保障指令执行的连贯性和准确性。对于指令译码单元的实现,相同类型指令集的归并以及在特定条件下处理中断应答的方式,都是为了确保指令译码单元能够高效、准确地工作。