`timescale 1ns / 1ps `default_nettype none // ----------------------------------------------------------------------------- // ID 级组合译码器。 // // 与原始 Logisim 控制器一致:操作码取标准 RISC-V 的 IR[6:2] 五位字段, // 真值表中以十六进制形式存储该字段。 // 所有输出在无匹配时保持"无操作/不写回"的默认值。 // ----------------------------------------------------------------------------- module cpu21_riscv_decoder ( input wire [31:0] ir_i, output reg [ 4:0] rs1_idx_o, output reg [ 4:0] rs2_idx_o, output reg [ 4:0] rd_o, output reg [31:0] imm_o, output reg [ 3:0] alu_op_o, output reg [ 2:0] wb_sel_o, output reg [ 2:0] md_op_o, output wire [11:0] csr_addr_o, output reg uses_rs1_o, output reg uses_rs2_o, output reg reg_write_o, output reg mem_to_reg_o, output reg mem_write_o, output reg mem_byte_o, output reg alu_src_o, output reg branch_o, output reg beq_o, output reg bne_o, output reg blt_o, output reg bge_o, output reg bltu_o, output reg bgeu_o, output reg jal_o, output reg jalr_o, output reg ecall_o, output reg uret_o, output reg csr_set_o, output reg csr_clear_o, output reg csr_write_o ); // CPU21 自定义操作码(取自所提供的真值表)。 localparam OP_LOAD = 5'h00; localparam OP_R = 5'h0c; localparam OP_I = 5'h04; localparam OP_STORE = 5'h08; localparam OP_JALR = 5'h19; localparam OP_BRANCH = 5'h18; localparam OP_JAL = 5'h1b; localparam OP_SYS = 5'h1c; // LUI 为扩展指令(标准 RISC-V opcode 0x37 -> IR[6:2]=0x0d)。 localparam OP_LUI = 5'h0d; localparam ALU_SLL = 4'd0; localparam ALU_SRA = 4'd1; localparam ALU_SRL = 4'd2; localparam ALU_MUL = 4'd3; localparam ALU_DIVU = 4'd4; localparam ALU_ADD = 4'd5; localparam ALU_SUB = 4'd6; localparam ALU_AND = 4'd7; localparam ALU_OR = 4'd8; localparam ALU_XOR = 4'd9; localparam ALU_SLT = 4'd11; localparam ALU_SLTU = 4'd12; localparam ALU_MULH = 4'd13; localparam ALU_MULHSU = 4'd14; localparam ALU_PASSB = 4'd15; // LUI:直接输出 B 端(立即数) // 乘除法单元(cpu21_riscv_muldiv)的操作编码,MD_NONE 表示非乘除法指令。 localparam [2:0] MD_NONE = 3'd0; localparam [2:0] MD_MUL = 3'd1; localparam [2:0] MD_MULH = 3'd2; localparam [2:0] MD_MULHSU = 3'd3; localparam [2:0] MD_MULHU = 3'd4; localparam [2:0] MD_DIVU = 3'd5; localparam [2:0] MD_REMU = 3'd6; wire [4:0] opcode = ir_i[6:2]; wire [2:0] funct3 = ir_i[14:12]; wire [6:0] funct7 = ir_i[31:25]; // CSR 地址字段在译码时直接旁路输出(供 EX 级读取 CSR)。 assign csr_addr_o = ir_i[31:20]; // 默认控制信号:全部为"无操作/不写回",再由下面的 case 覆盖。 always @* begin rs1_idx_o = ir_i[19:15]; rs2_idx_o = ir_i[24:20]; rd_o = ir_i[11:7]; imm_o = {{20{ir_i[31]}}, ir_i[31:20]}; alu_op_o = ALU_ADD; wb_sel_o = 3'd0; md_op_o = MD_NONE; uses_rs1_o = 1'b0; uses_rs2_o = 1'b0; reg_write_o = 1'b0; mem_to_reg_o = 1'b0; mem_write_o = 1'b0; mem_byte_o = 1'b0; alu_src_o = 1'b0; branch_o = 1'b0; beq_o = 1'b0; bne_o = 1'b0; blt_o = 1'b0; bge_o = 1'b0; bltu_o = 1'b0; bgeu_o = 1'b0; jal_o = 1'b0; jalr_o = 1'b0; ecall_o = 1'b0; uret_o = 1'b0; csr_set_o = 1'b0; csr_clear_o = 1'b0; csr_write_o = 1'b0; case (opcode) // R 型运算:由 funct3/funct7 决定具体操作。 OP_R: begin uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; reg_write_o = 1'b1; // M 扩展(funct7=0000001):mul/mulh/mulhsu/mulhu,以及课程真值表里的 // divu(funct3=101,商)与 remu(funct3=111,余数)。它们都由多周期 // 乘除法单元完成,这里只给出操作类型 md_op_o;mulhu 与 remu 依旧用 // wb_sel=3 取 result2(高位乘积 / 余数)。 if (funct7 == 7'b0000001) begin case (funct3) 3'b000: begin // mul:低 32 位 alu_op_o = ALU_MUL; md_op_o = MD_MUL; end 3'b001: begin // mulh:有符号高 32 位 alu_op_o = ALU_MULH; md_op_o = MD_MULH; end 3'b010: begin // mulhsu:有符号 x 无符号高 32 位 alu_op_o = ALU_MULHSU; md_op_o = MD_MULHSU; end 3'b011: begin // mulhu:无符号高 32 位 alu_op_o = ALU_MUL; md_op_o = MD_MULHU; wb_sel_o = 3'd3; end 3'b101: begin // divu:无符号商 alu_op_o = ALU_DIVU; md_op_o = MD_DIVU; end 3'b111: begin // remu:无符号余数 alu_op_o = ALU_DIVU; md_op_o = MD_REMU; wb_sel_o = 3'd3; end default: reg_write_o = 1'b0; endcase end else begin // 标准 R 型 funct3 译码;add/sub 与 sra/srl 由 funct7[5] 区分。 case (funct3) 3'b000: alu_op_o = (funct7[5] ? ALU_SUB : ALU_ADD); 3'b001: alu_op_o = ALU_SLL; 3'b010: alu_op_o = ALU_SLT; 3'b011: alu_op_o = ALU_SLTU; 3'b100: alu_op_o = ALU_XOR; 3'b101: alu_op_o = (funct7[5] ? ALU_SRA : ALU_SRL); 3'b110: alu_op_o = ALU_OR; 3'b111: alu_op_o = ALU_AND; default: reg_write_o = 1'b0; endcase end end // I 型运算(addi/slli/slti/sltiu/xori/srai/srli/ori/andi)。 OP_I: begin uses_rs1_o = 1'b1; alu_src_o = 1'b1; reg_write_o = 1'b1; case (funct3) 3'b000: alu_op_o = ALU_ADD; // addi:立即数加 3'b001: alu_op_o = ALU_SLL; // slli:立即数逻辑左移 3'b010: alu_op_o = ALU_SLT; // slti:有符号小于置 1 3'b011: alu_op_o = ALU_SLTU; // sltiu:无符号小于置 1(立即数符号扩展) 3'b100: alu_op_o = ALU_XOR; // xori:立即数异或 3'b101: alu_op_o = (funct7[5] ? ALU_SRA : ALU_SRL); // srai/srli:立即数算术/逻辑右移 3'b110: alu_op_o = ALU_OR; // ori:立即数或 3'b111: alu_op_o = ALU_AND; // andi:立即数与 default: reg_write_o = 1'b0; endcase end // 加载高位立即数 lui:rd = imm[31:12] << 12。 // 不读寄存器;用 ALU_SRC 选立即数,ALU 直通 B 端输出。 OP_LUI: begin reg_write_o = 1'b1; alu_src_o = 1'b1; alu_op_o = ALU_PASSB; imm_o = {ir_i[31:12], 12'b0}; wb_sel_o = 3'd0; end // 加载指令,当前仅支持 lw(funct3=010)。 OP_LOAD: begin if (funct3 == 3'b010) begin uses_rs1_o = 1'b1; alu_src_o = 1'b1; alu_op_o = ALU_ADD; mem_to_reg_o = 1'b1; reg_write_o = 1'b1; wb_sel_o = 3'd1; end end // 存储指令:sw(funct3=010)与 sb(funct3=000)。 OP_STORE: begin if ((funct3 == 3'b010) || (funct3 == 3'b000)) begin uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; alu_src_o = 1'b1; alu_op_o = ALU_ADD; mem_write_o = 1'b1; mem_byte_o = (funct3 == 3'b000); // sb:字节存储 imm_o = {{20{ir_i[31]}}, ir_i[31:25], ir_i[11:7]}; end end // 条件分支:beq(000)/bne(001)/blt(100)/bge(101)/bltu(110)/bgeu(111)。 OP_BRANCH: begin if ((funct3 == 3'b000) || (funct3 == 3'b001) || (funct3 == 3'b100) || (funct3 == 3'b101) || (funct3 == 3'b110) || (funct3 == 3'b111)) begin uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; branch_o = 1'b1; beq_o = (funct3 == 3'b000); bne_o = (funct3 == 3'b001); blt_o = (funct3 == 3'b100); bge_o = (funct3 == 3'b101); bltu_o = (funct3 == 3'b110); bgeu_o = (funct3 == 3'b111); // 有符号比较用 ALU_SLT、无符号比较用 ALU_SLTU,相等/不等用减法; // 分支是否成立由 EX 级的分支裁决单元决定,这里只与真值表保持一致。 alu_op_o = (blt_o || bge_o) ? ALU_SLT : ((bltu_o || bgeu_o) ? ALU_SLTU : ALU_SUB); imm_o = {{19{ir_i[31]}}, ir_i[31], ir_i[7], ir_i[30:25], ir_i[11:8], 1'b0}; end end // 无条件跳转并链接:jal(写回 PC+4)。 OP_JAL: begin jal_o = 1'b1; reg_write_o = 1'b1; wb_sel_o = 3'd2; imm_o = {{11{ir_i[31]}}, ir_i[31], ir_i[19:12], ir_i[20], ir_i[30:21], 1'b0}; end // 寄存器间接跳转并链接:jalr。 OP_JALR: begin if (funct3 == 3'b000) begin jalr_o = 1'b1; uses_rs1_o = 1'b1; alu_src_o = 1'b1; alu_op_o = ALU_ADD; reg_write_o = 1'b1; wb_sel_o = 3'd2; end end // 系统指令:ecall / uret / CSR 读写。 OP_SYS: begin // 电路用 IR[21] 区分 URET 与 ecall。 if (funct3 == 3'b000) begin if (ir_i[21]) begin uret_o = 1'b1; end else begin ecall_o = 1'b1; // 按文档说明,ecall 读取 a7(rs17) 与 a0(rs10)。 uses_rs1_o = 1'b1; uses_rs2_o = 1'b1; rs1_idx_o = 5'd17; rs2_idx_o = 5'd10; end end else if (funct3 == 3'b001) begin csr_write_o = 1'b1; // CSRRW:写 CSR,并把旧值写回 rd uses_rs1_o = 1'b1; alu_src_o = 1'b1; imm_o = {27'b0, ir_i[19:15]}; reg_write_o = (rd_o != 5'd0); wb_sel_o = 3'd4; end else if (funct3 == 3'b110) begin csr_set_o = 1'b1; // CSRRSI:置位 CSR 中的指定位 imm_o = {27'b0, ir_i[19:15]}; reg_write_o = (rd_o != 5'd0); wb_sel_o = 3'd4; end else if (funct3 == 3'b111) begin csr_clear_o = 1'b1; // CSRRCI:清除 CSR 中的指定位 imm_o = {27'b0, ir_i[19:15]}; reg_write_o = (rd_o != 5'd0); wb_sel_o = 3'd4; end end default: begin end endcase end endmodule `default_nettype wire