【RISC-V设计-10】- RISC-V处理器设计K0A之IDU

【RISC-V设计-10】- RISC-V处理器设计K0A之IDU

文章目录

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.代码设计

verilog 复制代码
// -------------------------------------------------------------------------------------------------
// 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 值,以保障指令执行的连贯性和准确性。对于指令译码单元的实现,相同类型指令集的归并以及在特定条件下处理中断应答的方式,都是为了确保指令译码单元能够高效、准确地工作。

相关推荐
BigDark的笔记15 天前
【鸿蒙】0x02-LiteOS-M基于Qemu RISC-V运行
华为·harmonyos·risc-v
早上真好18 天前
【项目推荐】CakeMu-RV:一个开放的 RISC-V 处理器模拟器学习项目
嵌入式硬件·mcu·学习·计算机外设·risc-v
sinovoip18 天前
Banana Pi BPI-RV2 RISC-V路由开发板采用矽昌通信SF2H8898芯片
risc-v
CV金科20 天前
freertos的基础(二)内存管理:堆和栈
stm32·开源·arm·freertos·risc-v
BroccoliKing21 天前
An FPGA-based SoC System——RISC-V On PYNQ项目复现
arm开发·单片机·mcu·fpga开发·dsp开发·risc-v
百里杨24 天前
X86(Local APIC+I/O APIC)与RISC-V(IMSIC+APLIC)对比
risc-v·x86·local apic·ioapic·imsic·aplic
嵌入式Linux,24 天前
一块钱的RISC-V 32位芯片
risc-v
世事如云有卷舒1 个月前
RISC-V学习笔记
笔记·学习·risc-v
oahrzvq1 个月前
【CPU】RISC-V 与 x86 操作数字段的区别
系统架构·risc-v
MounRiver_Studio1 个月前
基于VSCode软件框架的RISC-V IDE MRS2正式上线发布
ide·vscode·mcu·risc-v