• 【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.端口说明

    序号端口位宽方向说明
    1bmu2idu_valid1input指令有效指示
    2bmu2idu_instr32input需要执行的指令
    3bmu2idu_pc_cur18input当前指令的PC
    4bmu2idu_pc_nxt18input下一条指令的PC
    5idu2bmu_pc_set1output程序计数器设置
    6idu2bmu_pc_new18output新的程序计数器
    7bmu2idu_pc_ack1input程序计数器应答
    8idu2bmu_ls_req1output加载与存储请求
    9idu2bmu_ls_cmd1output加载与存储命令,1写0读
    10idu2bmu_ls_size2output加载与存储写数据字节数
    11idu2bmu_ls_addr20output加载与存储的地址
    12idu2bmu_ls_wdata32output加载与存储的写数据
    13bmu2idu_ls_rdata32input加载与存储的读数据
    14idu2gpr_we1output通用寄存器组写使能,高有效
    15idu2gpr_waddr4output通用寄存器组写地址
    16idu2gpr_wdata32output通用寄存器组写数据
    17idu2gpr_raddr14output通用寄存器组读地址1
    18idu2gpr_raddr24output通用寄存器组读地址2
    19gpr2idu_rdata132input通用寄存器组读数据1
    20gpr2idu_rdata232input通用寄存器组读数据2
    21idu2csr_we1outputCSR读写总线,写使能
    22idu2csr_addr12outputCSR读写总线,地址
    23idu2csr_wdata32outputCSR读写总线,写数据
    24csr2idu_rdata32inputCSR读写总线,读数据
    25idu2alu_op4outputALU的操作码
    26idu2alu_rs132output运算的第一操作数
    27idu2alu_rs232output运算的第二操作数
    28alu2idu_res32input数值运算的结果
    29alu2idu_cmp1input比较运算的结果
    30idu2alu_addr120output地址运算的第一操作数
    31idu2alu_addr220output地址运算的第二操作数
    32alu2idu_addro20input地址运算的输出结果
    33cic2idu_int_req1input中断请求
    34idu2cic_int_ack1output中断应答
    35idu2cic_int_mret1output中断返回

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

  • 相关阅读:
    使用branch and bound分支定界算法选择UTXO
    Matlab 多项式插值(曲线拟合)
    【Spring进阶系列丨最终篇】一文详解Spring中的事务控制
    oracle10g 监听异常处理
    Docker搭建RabbitMQ集群
    移动Web实训DAY-1
    C++面试八股文:如何避免死锁?
    noip十连测day5-狗
    Nginx优化与防盗链
    Visual Studio 2022下载安装及使用教程
  • 原文地址:https://blog.csdn.net/kearnchen/article/details/141071297