// Copyright 2018 ETH Zurich and University of Bologna. // Copyright and related rights are licensed under the Solderpad Hardware // License, Version 0.51 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law // or agreed to in writing, software, hardware and materials distributed under // this 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. // // File: issue_read_operands.sv // Author: Florian Zaruba <zarubaf@ethz.ch> // Date: 8.4.2017 // // Copyright (C) 2017 ETH Zurich, University of Bologna // All rights reserved. // // Description: Issues instruction from the scoreboard and fetches the operands // This also includes all the forwarding logic // import ariane_pkg::*; module decoder ( input logic [63:0] pc_i, // PC from IF input logic is_compressed_i, // is a compressed instruction input logic [15:0] compressed_instr_i, // compressed form of instruction input logic is_illegal_i, // illegal compressed instruction input logic [31:0] instruction_i, // instruction from IF input branchpredict_sbe_t branch_predict_i, input exception_t ex_i, // if an exception occured in if // From CSR input riscv::priv_lvl_t priv_lvl_i, // current privilege level input logic debug_mode_i, // we are in debug mode input riscv::xs_t fs_i, // floating point extension status input logic [2:0] frm_i, // floating-point dynamic rounding mode input logic tvm_i, // trap virtual memory input logic tw_i, // timeout wait input logic tsr_i, // trap sret output scoreboard_entry_t instruction_o, // scoreboard entry to scoreboard output logic is_control_flow_instr_o // this instruction will change the control flow ); logic illegal_instr; // this instruction is an environment call (ecall), it is handled like an exception logic ecall; // this instruction is a software break-point logic ebreak; // this instruction needs floating-point rounding-mode verification logic check_fprm; riscv::instruction_t instr; assign instr = riscv::instruction_t'(instruction_i); // -------------------- // Immediate select // -------------------- enum logic[3:0] { NOIMM, IIMM, SIMM, SBIMM, UIMM, JIMM, RS3 } imm_select; logic [63:0] imm_i_type; logic [63:0] imm_s_type; logic [63:0] imm_sb_type; logic [63:0] imm_u_type; logic [63:0] imm_uj_type; logic [63:0] imm_bi_type; always_comb begin : decoder imm_select = NOIMM; is_control_flow_instr_o = 1'b0; illegal_instr = 1'b0; instruction_o.pc = pc_i; instruction_o.trans_id = 5'b0; instruction_o.fu = NONE; instruction_o.op = ADD; instruction_o.rs1 = '0; instruction_o.rs2 = '0; instruction_o.rd = '0; instruction_o.use_pc = 1'b0; instruction_o.trans_id = '0; instruction_o.is_compressed = is_compressed_i; instruction_o.use_zimm = 1'b0; instruction_o.bp = branch_predict_i; ecall = 1'b0; ebreak = 1'b0; check_fprm = 1'b0; if (~ex_i.valid) begin case (instr.rtype.opcode) riscv::OpcodeSystem: begin instruction_o.fu = CSR; instruction_o.rs1[4:0] = instr.itype.rs1; instruction_o.rd[4:0] = instr.itype.rd; unique case (instr.itype.funct3) 3'b000: begin // check if the RD and and RS1 fields are zero, this may be reset for the SENCE.VMA instruction if (instr.itype.rs1 != '0 || instr.itype.rd != '0) illegal_instr = 1'b1; // decode the immiediate field case (instr.itype.imm) // ECALL -> inject exception 12'b0: ecall = 1'b1; // EBREAK -> inject exception 12'b1: ebreak = 1'b1; // SRET 12'b1_0000_0010: begin instruction_o.op = SRET; // check privilege level, SRET can only be executed in S and M mode // we'll just decode an illegal instruction if we are in the wrong privilege level if (priv_lvl_i == riscv::PRIV_LVL_U) begin illegal_instr = 1'b1; // do not change privilege level if this is an illegal instruction instruction_o.op = ADD; end // if we are in S-Mode and Trap SRET (tsr) is set -> trap on illegal instruction if (priv_lvl_i == riscv::PRIV_LVL_S && tsr_i) begin illegal_instr = 1'b1; // do not change privilege level if this is an illegal instruction instruction_o.op = ADD; end end // MRET 12'b11_0000_0010: begin instruction_o.op = MRET; // check privilege level, MRET can only be executed in M mode // otherwise we decode an illegal instruction if (priv_lvl_i inside {riscv::PRIV_LVL_U, riscv::PRIV_LVL_S}) illegal_instr = 1'b1; end // DRET 12'b111_1011_0010: begin instruction_o.op = DRET; // check that we are in debug mode when executing this instruction illegal_instr = (!debug_mode_i) ? 1'b1 : 1'b0; end // WFI 12'b1_0000_0101: begin if (ENABLE_WFI) instruction_o.op = WFI; // if timeout wait is set, trap on an illegal instruction in S Mode // (after 0 cycles timeout) if (priv_lvl_i == riscv::PRIV_LVL_S && tw_i) begin illegal_instr = 1'b1; instruction_o.op = ADD; end // we don't support U mode interrupts so WFI is illegal in this context if (priv_lvl_i == riscv::PRIV_LVL_U) begin illegal_instr = 1'b1; instruction_o.op = ADD; end end // SFENCE.VMA default: begin if (instr.instr[31:25] == 7'b1001) begin // check privilege level, SFENCE.VMA can only be executed in M/S mode // otherwise decode an illegal instruction illegal_instr = (priv_lvl_i inside {riscv::PRIV_LVL_M, riscv::PRIV_LVL_S}) ? 1'b0 : 1'b1; instruction_o.op = SFENCE_VMA; // check TVM flag and intercept SFENCE.VMA call if necessary if (priv_lvl_i == riscv::PRIV_LVL_S && tvm_i) illegal_instr = 1'b1; end end endcase end // atomically swaps values in the CSR and integer register 3'b001: begin// CSRRW imm_select = IIMM; instruction_o.op = CSR_WRITE; end // atomically set values in the CSR and write back to rd 3'b010: begin// CSRRS imm_select = IIMM; // this is just a read if (instr.itype.rs1 == 5'b0) instruction_o.op = CSR_READ; else instruction_o.op = CSR_SET; end // atomically clear values in the CSR and write back to rd 3'b011: begin// CSRRC imm_select = IIMM; // this is just a read if (instr.itype.rs1 == 5'b0) instruction_o.op = CSR_READ; else instruction_o.op = CSR_CLEAR; end // use zimm and iimm 3'b101: begin// CSRRWI instruction_o.rs1[4:0] = instr.itype.rs1; imm_select = IIMM; instruction_o.use_zimm = 1'b1; instruction_o.op = CSR_WRITE; end 3'b110: begin// CSRRSI instruction_o.rs1[4:0] = instr.itype.rs1; imm_select = IIMM; instruction_o.use_zimm = 1'b1; // this is just a read if (instr.itype.rs1 == 5'b0) instruction_o.op = CSR_READ; else instruction_o.op = CSR_SET; end 3'b111: begin// CSRRCI instruction_o.rs1[4:0] = instr.itype.rs1; imm_select = IIMM; instruction_o.use_zimm = 1'b1; // this is just a read if (instr.itype.rs1 == 5'b0) instruction_o.op = CSR_READ; else instruction_o.op = CSR_CLEAR; end default: illegal_instr = 1'b1; endcase end // Memory ordering instructions riscv::OpcodeMiscMem: begin instruction_o.fu = CSR; instruction_o.rs1 = '0; instruction_o.rs2 = '0; instruction_o.rd = '0; case (instr.stype.funct3) // FENCE // Currently implemented as a whole DCache flush boldly ignoring other things 3'b000: instruction_o.op = FENCE; // FENCE.I 3'b001: begin if (instr.instr[31:20] != '0) illegal_instr = 1'b1; instruction_o.op = FENCE_I; end default: illegal_instr = 1'b1; endcase if (instr.stype.rs1 != '0 || instr.stype.imm0 != '0 || instr.instr[31:28] != '0) illegal_instr = 1'b1; end // -------------------------- // Reg-Reg Operations // -------------------------- riscv::OpcodeOp: begin // -------------------------------------------- // Vectorial Floating-Point Reg-Reg Operations // -------------------------------------------- if (instr.rvftype.funct2 == 2'b10) begin // Prefix 10 for all Xfvec ops // only generate decoder if FP extensions are enabled (static) if (FP_PRESENT && XFVEC && fs_i != riscv::Off) begin automatic logic allow_replication; // control honoring of replication flag instruction_o.fu = FPU_VEC; // Same unit, but sets 'vectorial' signal instruction_o.rs1[4:0] = instr.rvftype.rs1; instruction_o.rs2[4:0] = instr.rvftype.rs2; instruction_o.rd[4:0] = instr.rvftype.rd; check_fprm = 1'b1; allow_replication = 1'b1; // decode vectorial FP instruction unique case (instr.rvftype.vecfltop) 5'b00001 : begin instruction_o.op = FADD; // vfadd.vfmt - Vectorial FP Addition instruction_o.rs1 = '0; // Operand A is set to 0 instruction_o.rs2 = instr.rvftype.rs1; // Operand B is set to rs1 imm_select = IIMM; // Operand C is set to rs2 end 5'b00010 : begin instruction_o.op = FSUB; // vfsub.vfmt - Vectorial FP Subtraction instruction_o.rs1 = '0; // Operand A is set to 0 instruction_o.rs2 = instr.rvftype.rs1; // Operand B is set to rs1 imm_select = IIMM; // Operand C is set to rs2 end 5'b00011 : instruction_o.op = FMUL; // vfmul.vfmt - Vectorial FP Multiplication 5'b00100 : instruction_o.op = FDIV; // vfdiv.vfmt - Vectorial FP Division 5'b00101 : begin instruction_o.op = VFMIN; // vfmin.vfmt - Vectorial FP Minimum check_fprm = 1'b0; // rounding mode irrelevant end 5'b00110 : begin instruction_o.op = VFMAX; // vfmax.vfmt - Vectorial FP Maximum check_fprm = 1'b0; // rounding mode irrelevant end 5'b00111 : begin instruction_o.op = FSQRT; // vfsqrt.vfmt - Vectorial FP Square Root allow_replication = 1'b0; // only one operand if (instr.rvftype.rs2 != 5'b00000) illegal_instr = 1'b1; // rs2 must be 0 end 5'b01000 : begin instruction_o.op = FMADD; // vfmac.vfmt - Vectorial FP Multiply-Accumulate imm_select = SIMM; // rd into result field (upper bits don't matter) end 5'b01001 : begin instruction_o.op = FMSUB; // vfmre.vfmt - Vectorial FP Multiply-Reduce imm_select = SIMM; // rd into result field (upper bits don't matter) end 5'b01100 : begin unique case (instr.rvftype.rs2) inside // operation encoded in rs2, `inside` for matching ? 5'b00000 : begin instruction_o.rs2 = instr.rvftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit if (instr.rvftype.repl) instruction_o.op = FMV_F2X; // vfmv.x.vfmt - FPR to GPR Move else instruction_o.op = FMV_X2F; // vfmv.vfmt.x - GPR to FPR Move check_fprm = 1'b0; // no rounding for moves end 5'b00001 : begin instruction_o.op = FCLASS; // vfclass.vfmt - Vectorial FP Classify check_fprm = 1'b0; // no rounding for classification allow_replication = 1'b0; // R must not be set end 5'b00010 : instruction_o.op = FCVT_F2I; // vfcvt.x.vfmt - Vectorial FP to Int Conversion 5'b00011 : instruction_o.op = FCVT_I2F; // vfcvt.vfmt.x - Vectorial Int to FP Conversion 5'b001?? : begin instruction_o.op = FCVT_F2F; // vfcvt.vfmt.vfmt - Vectorial FP to FP Conversion instruction_o.rs2 = instr.rvftype.rd; // set rs2 = rd as target vector for conversion imm_select = IIMM; // rs2 holds part of the intruction // TODO CHECK R bit for valid fmt combinations // determine source format unique case (instr.rvftype.rs2[21:20]) // Only process instruction if corresponding extension is active (static) 2'b00: if (~RVFVEC) illegal_instr = 1'b1; 2'b01: if (~XF16ALTVEC) illegal_instr = 1'b1; 2'b10: if (~XF16VEC) illegal_instr = 1'b1; 2'b11: if (~XF8VEC) illegal_instr = 1'b1; default : illegal_instr = 1'b1; endcase end default : illegal_instr = 1'b1; endcase end 5'b01101 : begin check_fprm = 1'b0; // no rounding for sign-injection instruction_o.op = VFSGNJ; // vfsgnj.vfmt - Vectorial FP Sign Injection end 5'b01110 : begin check_fprm = 1'b0; // no rounding for sign-injection instruction_o.op = VFSGNJN; // vfsgnjn.vfmt - Vectorial FP Negated Sign Injection end 5'b01111 : begin check_fprm = 1'b0; // no rounding for sign-injection instruction_o.op = VFSGNJX; // vfsgnjx.vfmt - Vectorial FP XORed Sign Injection end 5'b10000 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFEQ; // vfeq.vfmt - Vectorial FP Equality end 5'b10001 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFNE; // vfne.vfmt - Vectorial FP Non-Equality end 5'b10010 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFLT; // vfle.vfmt - Vectorial FP Less Than end 5'b10011 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFGE; // vfge.vfmt - Vectorial FP Greater or Equal end 5'b10100 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFLE; // vfle.vfmt - Vectorial FP Less or Equal end 5'b10101 : begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = VFGT; // vfgt.vfmt - Vectorial FP Greater Than end 5'b11000 : begin instruction_o.op = VFCPKAB_S; // vfcpka/b.vfmt.s - Vectorial FP Cast-and-Pack from 2x FP32, lowest 4 entries imm_select = SIMM; // rd into result field (upper bits don't matter) if (~RVF) illegal_instr = 1'b1; // if we don't support RVF, we can't cast from FP32 // check destination format unique case (instr.rvftype.vfmt) // Only process instruction if corresponding extension is active and FLEN suffices (static) 2'b00: begin if (~RVFVEC) illegal_instr = 1'b1; // destination vector not supported if (instr.rvftype.repl) illegal_instr = 1'b1; // no entries 2/3 in vector of 2 fp32 end 2'b01: begin if (~XF16ALTVEC) illegal_instr = 1'b1; // destination vector not supported end 2'b10: begin if (~XF16VEC) illegal_instr = 1'b1; // destination vector not supported end 2'b11: begin if (~XF8VEC) illegal_instr = 1'b1; // destination vector not supported end default : illegal_instr = 1'b1; endcase end 5'b11001 : begin instruction_o.op = VFCPKCD_S; // vfcpkc/d.vfmt.s - Vectorial FP Cast-and-Pack from 2x FP32, second 4 entries imm_select = SIMM; // rd into result field (upper bits don't matter) if (~RVF) illegal_instr = 1'b1; // if we don't support RVF, we can't cast from FP32 // check destination format unique case (instr.rvftype.vfmt) // Only process instruction if corresponding extension is active and FLEN suffices (static) 2'b00: illegal_instr = 1'b1; // no entries 4-7 in vector of 2 FP32 2'b01: illegal_instr = 1'b1; // no entries 4-7 in vector of 4 FP16ALT 2'b10: illegal_instr = 1'b1; // no entries 4-7 in vector of 4 FP16 2'b11: begin if (~XF8VEC) illegal_instr = 1'b1; // destination vector not supported end default : illegal_instr = 1'b1; endcase end 5'b11010 : begin instruction_o.op = VFCPKAB_D; // vfcpka/b.vfmt.d - Vectorial FP Cast-and-Pack from 2x FP64, lowest 4 entries imm_select = SIMM; // rd into result field (upper bits don't matter) if (~RVD) illegal_instr = 1'b1; // if we don't support RVD, we can't cast from FP64 // check destination format unique case (instr.rvftype.vfmt) // Only process instruction if corresponding extension is active and FLEN suffices (static) 2'b00: begin if (~RVFVEC) illegal_instr = 1'b1; // destination vector not supported if (instr.rvftype.repl) illegal_instr = 1'b1; // no entries 2/3 in vector of 2 fp32 end 2'b01: begin if (~XF16ALTVEC) illegal_instr = 1'b1; // destination vector not supported end 2'b10: begin if (~XF16VEC) illegal_instr = 1'b1; // destination vector not supported end 2'b11: begin if (~XF8VEC) illegal_instr = 1'b1; // destination vector not supported end default : illegal_instr = 1'b1; endcase end 5'b11011 : begin instruction_o.op = VFCPKCD_D; // vfcpka/b.vfmt.d - Vectorial FP Cast-and-Pack from 2x FP64, second 4 entries imm_select = SIMM; // rd into result field (upper bits don't matter) if (~RVD) illegal_instr = 1'b1; // if we don't support RVD, we can't cast from FP64 // check destination format unique case (instr.rvftype.vfmt) // Only process instruction if corresponding extension is active and FLEN suffices (static) 2'b00: illegal_instr = 1'b1; // no entries 4-7 in vector of 2 FP32 2'b01: illegal_instr = 1'b1; // no entries 4-7 in vector of 4 FP16ALT 2'b10: illegal_instr = 1'b1; // no entries 4-7 in vector of 4 FP16 2'b11: begin if (~XF8VEC) illegal_instr = 1'b1; // destination vector not supported end default : illegal_instr = 1'b1; endcase end default : illegal_instr = 1'b1; endcase // check format unique case (instr.rvftype.vfmt) // Only process instruction if corresponding extension is active (static) 2'b00: if (~RVFVEC) illegal_instr = 1'b1; 2'b01: if (~XF16ALTVEC) illegal_instr = 1'b1; 2'b10: if (~XF16VEC) illegal_instr = 1'b1; 2'b11: if (~XF8VEC) illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase // check disallowed replication if (~allow_replication & instr.rvftype.repl) illegal_instr = 1'b1; // check rounding mode if (check_fprm) begin unique case (frm_i) inside // actual rounding mode from frm csr [3'b000:3'b100]: ; //legal rounding modes default : illegal_instr = 1'b1; endcase end end else begin // No vectorial FP enabled (static) illegal_instr = 1'b1; end // --------------------------- // Integer Reg-Reg Operations // --------------------------- end else begin instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU; instruction_o.rs1 = instr.rtype.rs1; instruction_o.rs2 = instr.rtype.rs2; instruction_o.rd = instr.rtype.rd; unique case ({instr.rtype.funct7, instr.rtype.funct3}) {7'b000_0000, 3'b000}: instruction_o.op = ADD; // Add {7'b010_0000, 3'b000}: instruction_o.op = SUB; // Sub {7'b000_0000, 3'b010}: instruction_o.op = SLTS; // Set Lower Than {7'b000_0000, 3'b011}: instruction_o.op = SLTU; // Set Lower Than Unsigned {7'b000_0000, 3'b100}: instruction_o.op = XORL; // Xor {7'b000_0000, 3'b110}: instruction_o.op = ORL; // Or {7'b000_0000, 3'b111}: instruction_o.op = ANDL; // And {7'b000_0000, 3'b001}: instruction_o.op = SLL; // Shift Left Logical {7'b000_0000, 3'b101}: instruction_o.op = SRL; // Shift Right Logical {7'b010_0000, 3'b101}: instruction_o.op = SRA; // Shift Right Arithmetic // Multiplications {7'b000_0001, 3'b000}: instruction_o.op = MUL; {7'b000_0001, 3'b001}: instruction_o.op = MULH; {7'b000_0001, 3'b010}: instruction_o.op = MULHSU; {7'b000_0001, 3'b011}: instruction_o.op = MULHU; {7'b000_0001, 3'b100}: instruction_o.op = DIV; {7'b000_0001, 3'b101}: instruction_o.op = DIVU; {7'b000_0001, 3'b110}: instruction_o.op = REM; {7'b000_0001, 3'b111}: instruction_o.op = REMU; default: begin illegal_instr = 1'b1; end endcase end end // -------------------------- // 32bit Reg-Reg Operations // -------------------------- riscv::OpcodeOp32: begin instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU; instruction_o.rs1[4:0] = instr.rtype.rs1; instruction_o.rs2[4:0] = instr.rtype.rs2; instruction_o.rd[4:0] = instr.rtype.rd; unique case ({instr.rtype.funct7, instr.rtype.funct3}) {7'b000_0000, 3'b000}: instruction_o.op = ADDW; // addw {7'b010_0000, 3'b000}: instruction_o.op = SUBW; // subw {7'b000_0000, 3'b001}: instruction_o.op = SLLW; // sllw {7'b000_0000, 3'b101}: instruction_o.op = SRLW; // srlw {7'b010_0000, 3'b101}: instruction_o.op = SRAW; // sraw // Multiplications {7'b000_0001, 3'b000}: instruction_o.op = MULW; {7'b000_0001, 3'b100}: instruction_o.op = DIVW; {7'b000_0001, 3'b101}: instruction_o.op = DIVUW; {7'b000_0001, 3'b110}: instruction_o.op = REMW; {7'b000_0001, 3'b111}: instruction_o.op = REMUW; default: illegal_instr = 1'b1; endcase end // -------------------------------- // Reg-Immediate Operations // -------------------------------- riscv::OpcodeOpImm: begin instruction_o.fu = ALU; imm_select = IIMM; instruction_o.rs1[4:0] = instr.itype.rs1; instruction_o.rd[4:0] = instr.itype.rd; unique case (instr.itype.funct3) 3'b000: instruction_o.op = ADD; // Add Immediate 3'b010: instruction_o.op = SLTS; // Set to one if Lower Than Immediate 3'b011: instruction_o.op = SLTU; // Set to one if Lower Than Immediate Unsigned 3'b100: instruction_o.op = XORL; // Exclusive Or with Immediate 3'b110: instruction_o.op = ORL; // Or with Immediate 3'b111: instruction_o.op = ANDL; // And with Immediate 3'b001: begin instruction_o.op = SLL; // Shift Left Logical by Immediate if (instr.instr[31:26] != 6'b0) illegal_instr = 1'b1; end 3'b101: begin if (instr.instr[31:26] == 6'b0) instruction_o.op = SRL; // Shift Right Logical by Immediate else if (instr.instr[31:26] == 6'b010_000) instruction_o.op = SRA; // Shift Right Arithmetically by Immediate else illegal_instr = 1'b1; end endcase end // -------------------------------- // 32 bit Reg-Immediate Operations // -------------------------------- riscv::OpcodeOpImm32: begin instruction_o.fu = ALU; imm_select = IIMM; instruction_o.rs1[4:0] = instr.itype.rs1; instruction_o.rd[4:0] = instr.itype.rd; unique case (instr.itype.funct3) 3'b000: instruction_o.op = ADDW; // Add Immediate 3'b001: begin instruction_o.op = SLLW; // Shift Left Logical by Immediate if (instr.instr[31:25] != 7'b0) illegal_instr = 1'b1; end 3'b101: begin if (instr.instr[31:25] == 7'b0) instruction_o.op = SRLW; // Shift Right Logical by Immediate else if (instr.instr[31:25] == 7'b010_0000) instruction_o.op = SRAW; // Shift Right Arithmetically by Immediate else illegal_instr = 1'b1; end default: illegal_instr = 1'b1; endcase end // -------------------------------- // LSU // -------------------------------- riscv::OpcodeStore: begin instruction_o.fu = STORE; imm_select = SIMM; instruction_o.rs1[4:0] = instr.stype.rs1; instruction_o.rs2[4:0] = instr.stype.rs2; // determine store size unique case (instr.stype.funct3) 3'b000: instruction_o.op = SB; 3'b001: instruction_o.op = SH; 3'b010: instruction_o.op = SW; 3'b011: instruction_o.op = SD; default: illegal_instr = 1'b1; endcase end riscv::OpcodeLoad: begin instruction_o.fu = LOAD; imm_select = IIMM; instruction_o.rs1[4:0] = instr.itype.rs1; instruction_o.rd[4:0] = instr.itype.rd; // determine load size and signed type unique case (instr.itype.funct3) 3'b000: instruction_o.op = LB; 3'b001: instruction_o.op = LH; 3'b010: instruction_o.op = LW; 3'b100: instruction_o.op = LBU; 3'b101: instruction_o.op = LHU; 3'b110: instruction_o.op = LWU; 3'b011: instruction_o.op = LD; default: illegal_instr = 1'b1; endcase end // -------------------------------- // Floating-Point Load/store // -------------------------------- riscv::OpcodeStoreFp: begin if (FP_PRESENT && fs_i != riscv::Off) begin // only generate decoder if FP extensions are enabled (static) instruction_o.fu = STORE; imm_select = SIMM; instruction_o.rs1 = instr.stype.rs1; instruction_o.rs2 = instr.stype.rs2; // determine store size unique case (instr.stype.funct3) // Only process instruction if corresponding extension is active (static) 3'b000: if (XF8) instruction_o.op = FSB; else illegal_instr = 1'b1; 3'b001: if (XF16 | XF16ALT) instruction_o.op = FSH; else illegal_instr = 1'b1; 3'b010: if (RVF) instruction_o.op = FSW; else illegal_instr = 1'b1; 3'b011: if (RVD) instruction_o.op = FSD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase end else illegal_instr = 1'b1; end riscv::OpcodeLoadFp: begin if (FP_PRESENT && fs_i != riscv::Off) begin // only generate decoder if FP extensions are enabled (static) instruction_o.fu = LOAD; imm_select = IIMM; instruction_o.rs1 = instr.itype.rs1; instruction_o.rd = instr.itype.rd; // determine load size unique case (instr.itype.funct3) // Only process instruction if corresponding extension is active (static) 3'b000: if (XF8) instruction_o.op = FLB; else illegal_instr = 1'b1; 3'b001: if (XF16 | XF16ALT) instruction_o.op = FLH; else illegal_instr = 1'b1; 3'b010: if (RVF) instruction_o.op = FLW; else illegal_instr = 1'b1; 3'b011: if (RVD) instruction_o.op = FLD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase end else illegal_instr = 1'b1; end // ---------------------------------- // Floating-Point Reg-Reg Operations // ---------------------------------- riscv::OpcodeMadd, riscv::OpcodeMsub, riscv::OpcodeNmsub, riscv::OpcodeNmadd: begin if (FP_PRESENT && fs_i != riscv::Off) begin // only generate decoder if FP extensions are enabled (static) instruction_o.fu = FPU; instruction_o.rs1 = instr.r4type.rs1; instruction_o.rs2 = instr.r4type.rs2; instruction_o.rd = instr.r4type.rd; imm_select = RS3; // rs3 into result field check_fprm = 1'b1; // select the correct fused operation unique case (instr.r4type.opcode) default: instruction_o.op = FMADD; // fmadd.fmt - FP Fused multiply-add riscv::OpcodeMsub: instruction_o.op = FMSUB; // fmsub.fmt - FP Fused multiply-subtract riscv::OpcodeNmsub: instruction_o.op = FNMSUB; // fnmsub.fmt - FP Negated fused multiply-subtract riscv::OpcodeNmadd: instruction_o.op = FNMADD; // fnmadd.fmt - FP Negated fused multiply-add endcase // determine fp format unique case (instr.r4type.funct2) // Only process instruction if corresponding extension is active (static) 2'b00: if (~RVF) illegal_instr = 1'b1; 2'b01: if (~RVD) illegal_instr = 1'b1; 2'b10: if (~XF16 & ~XF16ALT) illegal_instr = 1'b1; 2'b11: if (~XF8) illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase // check rounding mode if (check_fprm) begin unique case (instr.rftype.rm) inside [3'b000:3'b100]: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~XF16ALT || instr.rftype.fmt != 2'b10) illegal_instr = 1'b1; unique case (frm_i) inside // actual rounding mode from frm csr [3'b000:3'b100]: ; //legal rounding modes default : illegal_instr = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside [3'b000:3'b100]: ; //legal rounding modes default : illegal_instr = 1'b1; endcase end default : illegal_instr = 1'b1; endcase end end else begin illegal_instr = 1'b1; end end riscv::OpcodeOpFp: begin if (FP_PRESENT && fs_i != riscv::Off) begin // only generate decoder if FP extensions are enabled (static) instruction_o.fu = FPU; instruction_o.rs1 = instr.rftype.rs1; instruction_o.rs2 = instr.rftype.rs2; instruction_o.rd = instr.rftype.rd; check_fprm = 1'b1; // decode FP instruction unique case (instr.rftype.funct5) 5'b00000: begin instruction_o.op = FADD; // fadd.fmt - FP Addition instruction_o.rs1 = '0; // Operand A is set to 0 instruction_o.rs2 = instr.rftype.rs1; // Operand B is set to rs1 imm_select = IIMM; // Operand C is set to rs2 end 5'b00001: begin instruction_o.op = FSUB; // fsub.fmt - FP Subtraction instruction_o.rs1 = '0; // Operand A is set to 0 instruction_o.rs2 = instr.rftype.rs1; // Operand B is set to rs1 imm_select = IIMM; // Operand C is set to rs2 end 5'b00010: instruction_o.op = FMUL; // fmul.fmt - FP Multiplication 5'b00011: instruction_o.op = FDIV; // fdiv.fmt - FP Division 5'b01011: begin instruction_o.op = FSQRT; // fsqrt.fmt - FP Square Root // rs2 must be zero if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1; end 5'b00100: begin instruction_o.op = FSGNJ; // fsgn{j[n]/jx}.fmt - FP Sign Injection check_fprm = 1'b0; // instruction encoded in rm, do the check here if (XF16ALT) begin // FP16ALT instructions encoded in rm separately (static) if (!(instr.rftype.rm inside {[3'b000:3'b010], [3'b100:3'b110]})) illegal_instr = 1'b1; end else begin if (!(instr.rftype.rm inside {[3'b000:3'b010]})) illegal_instr = 1'b1; end end 5'b00101: begin instruction_o.op = FMIN_MAX; // fmin/fmax.fmt - FP Minimum / Maximum check_fprm = 1'b0; // instruction encoded in rm, do the check here if (XF16ALT) begin // FP16ALT instructions encoded in rm separately (static) if (!(instr.rftype.rm inside {[3'b000:3'b001], [3'b100:3'b101]})) illegal_instr = 1'b1; end else begin if (!(instr.rftype.rm inside {[3'b000:3'b001]})) illegal_instr = 1'b1; end end 5'b01000: begin instruction_o.op = FCVT_F2F; // fcvt.fmt.fmt - FP to FP Conversion instruction_o.rs2 = instr.rvftype.rs1; // tie rs2 to rs1 to be safe (vectors use rs2) imm_select = IIMM; // rs2 holds part of the intruction if (instr.rftype.rs2[24:23]) illegal_instr = 1'b1; // bits [22:20] used, other bits must be 0 // check source format unique case (instr.rftype.rs2[22:20]) // Only process instruction if corresponding extension is active (static) 3'b000: if (~RVF) illegal_instr = 1'b1; 3'b001: if (~RVD) illegal_instr = 1'b1; 3'b010: if (~XF16) illegal_instr = 1'b1; 3'b110: if (~XF16ALT) illegal_instr = 1'b1; 3'b011: if (~XF8) illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase end 5'b10100: begin instruction_o.op = FCMP; // feq/flt/fle.fmt - FP Comparisons check_fprm = 1'b0; // instruction encoded in rm, do the check here if (XF16ALT) begin // FP16ALT instructions encoded in rm separately (static) if (!(instr.rftype.rm inside {[3'b000:3'b010], [3'b100:3'b110]})) illegal_instr = 1'b1; end else begin if (!(instr.rftype.rm inside {[3'b000:3'b010]})) illegal_instr = 1'b1; end end 5'b11000: begin instruction_o.op = FCVT_F2I; // fcvt.ifmt.fmt - FP to Int Conversion imm_select = IIMM; // rs2 holds part of the instruction if (instr.rftype.rs2[24:22]) illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0 end 5'b11010: begin instruction_o.op = FCVT_I2F; // fcvt.fmt.ifmt - Int to FP Conversion imm_select = IIMM; // rs2 holds part of the instruction if (instr.rftype.rs2[24:22]) illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0 end 5'b11100: begin instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit check_fprm = 1'b0; // instruction encoded in rm, do the check here if (instr.rftype.rm == 3'b000 || (XF16ALT && instr.rftype.rm == 3'b100)) // FP16ALT has separate encoding instruction_o.op = FMV_F2X; // fmv.ifmt.fmt - FPR to GPR Move else if (instr.rftype.rm == 3'b001 || (XF16ALT && instr.rftype.rm == 3'b101)) // FP16ALT has separate encoding instruction_o.op = FCLASS; // fclass.fmt - FP Classify else illegal_instr = 1'b1; // rs2 must be zero if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1; end 5'b11110: begin instruction_o.op = FMV_X2F; // fmv.fmt.ifmt - GPR to FPR Move instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit check_fprm = 1'b0; // instruction encoded in rm, do the check here if (!(instr.rftype.rm == 3'b000 || (XF16ALT && instr.rftype.rm == 3'b100))) illegal_instr = 1'b1; // rs2 must be zero if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1; end default : illegal_instr = 1'b1; endcase // check format unique case (instr.rftype.fmt) // Only process instruction if corresponding extension is active (static) 2'b00: if (~RVF) illegal_instr = 1'b1; 2'b01: if (~RVD) illegal_instr = 1'b1; 2'b10: if (~XF16 & ~XF16ALT) illegal_instr = 1'b1; 2'b11: if (~XF8) illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase // check rounding mode if (check_fprm) begin unique case (instr.rftype.rm) inside [3'b000:3'b100]: ; //legal rounding modes 3'b101: begin // Alternative Half-Precsision encded as fmt=10 and rm=101 if (~XF16ALT || instr.rftype.fmt != 2'b10) illegal_instr = 1'b1; unique case (frm_i) inside // actual rounding mode from frm csr [3'b000:3'b100]: ; //legal rounding modes default : illegal_instr = 1'b1; endcase end 3'b111: begin // rounding mode from frm csr unique case (frm_i) inside [3'b000:3'b100]: ; //legal rounding modes default : illegal_instr = 1'b1; endcase end default : illegal_instr = 1'b1; endcase end end else begin illegal_instr = 1'b1; end end // ---------------------------------- // Atomic Operations // ---------------------------------- riscv::OpcodeAmo: begin // we are going to use the load unit for AMOs instruction_o.fu = STORE; instruction_o.rs1[4:0] = instr.atype.rs1; instruction_o.rs2[4:0] = instr.atype.rs2; instruction_o.rd[4:0] = instr.atype.rd; // TODO(zarubaf): Ordering // words if (RVA && instr.stype.funct3 == 3'h2) begin unique case (instr.instr[31:27]) 5'h0: instruction_o.op = AMO_ADDW; 5'h1: instruction_o.op = AMO_SWAPW; 5'h2: begin instruction_o.op = AMO_LRW; if (instr.atype.rs2 != 0) illegal_instr = 1'b1; end 5'h3: instruction_o.op = AMO_SCW; 5'h4: instruction_o.op = AMO_XORW; 5'h8: instruction_o.op = AMO_ORW; 5'hC: instruction_o.op = AMO_ANDW; 5'h10: instruction_o.op = AMO_MINW; 5'h14: instruction_o.op = AMO_MAXW; 5'h18: instruction_o.op = AMO_MINWU; 5'h1C: instruction_o.op = AMO_MAXWU; default: illegal_instr = 1'b1; endcase // double words end else if (RVA && instr.stype.funct3 == 3'h3) begin unique case (instr.instr[31:27]) 5'h0: instruction_o.op = AMO_ADDD; 5'h1: instruction_o.op = AMO_SWAPD; 5'h2: begin instruction_o.op = AMO_LRD; if (instr.atype.rs2 != 0) illegal_instr = 1'b1; end 5'h3: instruction_o.op = AMO_SCD; 5'h4: instruction_o.op = AMO_XORD; 5'h8: instruction_o.op = AMO_ORD; 5'hC: instruction_o.op = AMO_ANDD; 5'h10: instruction_o.op = AMO_MIND; 5'h14: instruction_o.op = AMO_MAXD; 5'h18: instruction_o.op = AMO_MINDU; 5'h1C: instruction_o.op = AMO_MAXDU; default: illegal_instr = 1'b1; endcase end else begin illegal_instr = 1'b1; end end // -------------------------------- // Control Flow Instructions // -------------------------------- riscv::OpcodeBranch: begin imm_select = SBIMM; instruction_o.fu = CTRL_FLOW; instruction_o.rs1[4:0] = instr.stype.rs1; instruction_o.rs2[4:0] = instr.stype.rs2; is_control_flow_instr_o = 1'b1; case (instr.stype.funct3) 3'b000: instruction_o.op = EQ; 3'b001: instruction_o.op = NE; 3'b100: instruction_o.op = LTS; 3'b101: instruction_o.op = GES; 3'b110: instruction_o.op = LTU; 3'b111: instruction_o.op = GEU; default: begin is_control_flow_instr_o = 1'b0; illegal_instr = 1'b1; end endcase end // Jump and link register riscv::OpcodeJalr: begin instruction_o.fu = CTRL_FLOW; instruction_o.op = JALR; instruction_o.rs1[4:0] = instr.itype.rs1; imm_select = IIMM; instruction_o.rd[4:0] = instr.itype.rd; is_control_flow_instr_o = 1'b1; // invalid jump and link register -> reserved for vector encoding if (instr.itype.funct3 != 3'b0) illegal_instr = 1'b1; end // Jump and link riscv::OpcodeJal: begin instruction_o.fu = CTRL_FLOW; imm_select = JIMM; instruction_o.rd[4:0] = instr.utype.rd; is_control_flow_instr_o = 1'b1; end riscv::OpcodeAuipc: begin instruction_o.fu = ALU; imm_select = UIMM; instruction_o.use_pc = 1'b1; instruction_o.rd[4:0] = instr.utype.rd; end riscv::OpcodeLui: begin imm_select = UIMM; instruction_o.fu = ALU; instruction_o.rd[4:0] = instr.utype.rd; end default: illegal_instr = 1'b1; endcase end end // -------------------------------- // Sign extend immediate // -------------------------------- always_comb begin : sign_extend imm_i_type = i_imm(instruction_i); imm_s_type = { {52 {instruction_i[31]}}, instruction_i[31:25], instruction_i[11:7] }; imm_sb_type = sb_imm(instruction_i); imm_u_type = { {32 {instruction_i[31]}}, instruction_i[31:12], 12'b0 }; // JAL, AUIPC, sign extended to 64 bit imm_uj_type = uj_imm(instruction_i); imm_bi_type = { {59{instruction_i[24]}}, instruction_i[24:20] }; // NOIMM, IIMM, SIMM, BIMM, UIMM, JIMM, RS3 // select immediate case (imm_select) IIMM: begin instruction_o.result = imm_i_type; instruction_o.use_imm = 1'b1; end SIMM: begin instruction_o.result = imm_s_type; instruction_o.use_imm = 1'b1; end SBIMM: begin instruction_o.result = imm_sb_type; instruction_o.use_imm = 1'b1; end UIMM: begin instruction_o.result = imm_u_type; instruction_o.use_imm = 1'b1; end JIMM: begin instruction_o.result = imm_uj_type; instruction_o.use_imm = 1'b1; end RS3: begin // result holds address of fp operand rs3 instruction_o.result = {59'b0, instr.r4type.rs3}; instruction_o.use_imm = 1'b0; end default: begin instruction_o.result = 64'b0; instruction_o.use_imm = 1'b0; end endcase end // --------------------- // Exception handling // --------------------- always_comb begin : exception_handling instruction_o.ex = ex_i; instruction_o.valid = ex_i.valid; // look if we didn't already get an exception in any previous // stage - we should not overwrite it as we retain order regarding the exception if (~ex_i.valid) begin // if we didn't already get an exception save the instruction here as we may need it // in the commit stage if we got a access exception to one of the CSR registers instruction_o.ex.tval = (is_compressed_i) ? {48'b0, compressed_instr_i} : {32'b0, instruction_i}; // instructions which will throw an exception are marked as valid // e.g.: they can be committed anytime and do not need to wait for any functional unit // check here if we decoded an invalid instruction or if the compressed decoder already decoded // a invalid instruction if (illegal_instr || is_illegal_i) begin instruction_o.valid = 1'b1; instruction_o.ex.valid = 1'b1; // we decoded an illegal exception here instruction_o.ex.cause = riscv::ILLEGAL_INSTR; // we got an ecall, set the correct cause depending on the current privilege level end else if (ecall) begin // this instruction has already executed instruction_o.valid = 1'b1; // this exception is valid instruction_o.ex.valid = 1'b1; // depending on the privilege mode, set the appropriate cause case (priv_lvl_i) riscv::PRIV_LVL_M: instruction_o.ex.cause = riscv::ENV_CALL_MMODE; riscv::PRIV_LVL_S: instruction_o.ex.cause = riscv::ENV_CALL_SMODE; riscv::PRIV_LVL_U: instruction_o.ex.cause = riscv::ENV_CALL_UMODE; default:; // this should not happen endcase end else if (ebreak) begin // this instruction has already executed instruction_o.valid = 1'b1; // this exception is valid instruction_o.ex.valid = 1'b1; // set breakpoint cause instruction_o.ex.cause = riscv::BREAKPOINT; end end end endmodule