// 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 // 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 // module decoder import ariane_pkg::*; #( parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, parameter type branchpredict_sbe_t = logic, parameter type exception_t = logic, parameter type irq_ctrl_t = logic, parameter type scoreboard_entry_t = logic, parameter type interrupts_t = logic, parameter interrupts_t INTERRUPTS = '0 ) ( // Debug (async) request - SUBSYSTEM input logic debug_req_i, // PC from fetch stage - FRONTEND input logic [CVA6Cfg.VLEN-1:0] pc_i, // Is a compressed instruction - compressed_decoder input logic is_compressed_i, // Compressed form of instruction - FRONTEND input logic [15:0] compressed_instr_i, // Illegal compressed instruction - compressed_decoder input logic is_illegal_i, // Instruction from fetch stage - FRONTEND input logic [31:0] instruction_i, // Is a macro instruction - macro_decoder input logic is_macro_instr_i, // Is a last macro instruction - macro_decoder input logic is_last_macro_instr_i, // Is mvsa01/mva01s macro instruction - macro_decoder input logic is_double_rd_macro_instr_i, // Is a branch predict instruction - FRONTEND input branchpredict_sbe_t branch_predict_i, // If an exception occured in fetch stage - FRONTEND input exception_t ex_i, // Level sensitive (async) interrupts - SUBSYSTEM input logic [1:0] irq_i, // Interrupt control status - CSR_REGFILE input irq_ctrl_t irq_ctrl_i, // Current privilege level - CSR_REGFILE input riscv::priv_lvl_t priv_lvl_i, // Current virtualization mode - CSR_REGFILE input logic v_i, // Is debug mode - CSR_REGFILE input logic debug_mode_i, // Floating point extension status - CSR_REGFILE input riscv::xs_t fs_i, // Virtual floating point extension status - CSR_REGFILE input riscv::xs_t vfs_i, // Floating-point dynamic rounding mode - CSR_REGFILE input logic [2:0] frm_i, // Vector extension status - CSR_REGFILE input riscv::xs_t vs_i, // Trap virtual memory - CSR_REGFILE input logic tvm_i, // Timeout wait - CSR_REGFILE input logic tw_i, // Virtual timeout wait - CSR_REGFILE input logic vtw_i, // Trap sret - CSR_REGFILE input logic tsr_i, // Hypervisor user mode - CSR_REGFILE input logic hu_i, // Instruction to be added to scoreboard entry - ISSUE_STAGE output scoreboard_entry_t instruction_o, // Instruction - ISSUE_STAGE output logic [31:0] orig_instr_o, // Is a control flow instruction - ISSUE_STAGE output logic is_control_flow_instr_o ); logic illegal_instr; logic illegal_instr_bm; logic illegal_instr_zic; logic illegal_instr_non_bm; logic virtual_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); // transformed instruction logic [31:0] tinst; // -------------------- // Immediate select // -------------------- enum logic [3:0] { NOIMM, IIMM, SIMM, SBIMM, UIMM, JIMM, RS3, MUX_RD_RS3 } imm_select; logic [CVA6Cfg.XLEN-1:0] imm_i_type; logic [CVA6Cfg.XLEN-1:0] imm_s_type; logic [CVA6Cfg.XLEN-1:0] imm_sb_type; logic [CVA6Cfg.XLEN-1:0] imm_u_type; logic [CVA6Cfg.XLEN-1:0] imm_uj_type; // --------------------------------------- // Accelerator instructions' first-pass decoder // --------------------------------------- logic is_accel; scoreboard_entry_t acc_instruction; logic acc_illegal_instr; logic acc_is_control_flow_instr; if (CVA6Cfg.EnableAccelerator) begin : gen_accel_decoder // This module is responsible for a light-weight decoding of accelerator instructions, // identifying them, but also whether they read/write scalar registers. // Accelerators are supposed to define this module. cva6_accel_first_pass_decoder #( .CVA6Cfg(CVA6Cfg), .scoreboard_entry_t(scoreboard_entry_t) ) i_accel_decoder ( .instruction_i(instruction_i), .fs_i(fs_i), .vs_i(vs_i), .is_accel_o(is_accel), .instruction_o(acc_instruction), .illegal_instr_o(acc_illegal_instr), .is_control_flow_instr_o(acc_is_control_flow_instr) ); end : gen_accel_decoder else begin assign is_accel = 1'b0; assign acc_instruction = '0; assign acc_illegal_instr = 1'b1; // this should never propagate assign acc_is_control_flow_instr = 1'b0; end always_comb begin : decoder imm_select = NOIMM; is_control_flow_instr_o = 1'b0; illegal_instr = 1'b0; illegal_instr_non_bm = 1'b0; illegal_instr_bm = 1'b0; illegal_instr_zic = 1'b0; virtual_illegal_instr = 1'b0; instruction_o.pc = pc_i; instruction_o.trans_id = '0; instruction_o.fu = NONE; instruction_o.op = ariane_pkg::ADD; instruction_o.rs1 = '0; instruction_o.rs2 = '0; instruction_o.rd = '0; instruction_o.use_pc = 1'b0; instruction_o.is_compressed = is_compressed_i; instruction_o.is_macro_instr = is_macro_instr_i; instruction_o.is_last_macro_instr = is_last_macro_instr_i; instruction_o.is_double_rd_macro_instr = is_double_rd_macro_instr_i; instruction_o.use_zimm = 1'b0; instruction_o.bp = branch_predict_i; instruction_o.vfp = 1'b0; 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 = instr.itype.rs1; instruction_o.rs2 = instr.rtype.rs2; //TODO: needs to be checked if better way is available instruction_o.rd = 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) begin if (CVA6Cfg.RVH && v_i) begin virtual_illegal_instr = 1'b1; end else begin illegal_instr = 1'b1; end end // 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 if (CVA6Cfg.RVS) begin instruction_o.op = ariane_pkg::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 (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U) begin if (CVA6Cfg.RVH && v_i) begin virtual_illegal_instr = 1'b1; end else begin illegal_instr = 1'b1; end // do not change privilege level if this is an illegal instruction instruction_o.op = ariane_pkg::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 if (CVA6Cfg.RVH && v_i) begin virtual_illegal_instr = 1'b1; end else begin illegal_instr = 1'b1; end // do not change privilege level if this is an illegal instruction instruction_o.op = ariane_pkg::ADD; end end else begin illegal_instr = 1'b1; instruction_o.op = ariane_pkg::ADD; end end // MRET 12'b11_0000_0010: begin instruction_o.op = ariane_pkg::MRET; // check privilege level, MRET can only be executed in M mode // otherwise we decode an illegal instruction if ((CVA6Cfg.RVS && priv_lvl_i == riscv::PRIV_LVL_S) || (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U)) illegal_instr = 1'b1; end // DRET 12'b111_1011_0010: begin instruction_o.op = ariane_pkg::DRET; if (CVA6Cfg.DebugEn) begin // check that we are in debug mode when executing this instruction illegal_instr = (!debug_mode_i) ? 1'b1 : illegal_instr; end else begin illegal_instr = 1'b1; end end // WFI 12'b1_0000_0101: begin instruction_o.op = ariane_pkg::WFI; // if timeout wait is set, trap on an illegal instruction in S Mode // (after 0 cycles timeout) if (CVA6Cfg.RVS && priv_lvl_i == riscv::PRIV_LVL_S && tw_i) begin illegal_instr = 1'b1; instruction_o.op = ariane_pkg::ADD; end if (CVA6Cfg.RVH && priv_lvl_i == riscv::PRIV_LVL_S && v_i && vtw_i && !tw_i) begin virtual_illegal_instr = 1'b1; instruction_o.op = ariane_pkg::ADD; end // we don't support U mode interrupts so WFI is illegal in this context if (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U) begin if (CVA6Cfg.RVH && v_i) virtual_illegal_instr = 1'b1; else illegal_instr = 1'b1; instruction_o.op = ariane_pkg::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 // only if S mode is supported // otherwise decode an illegal instruction if (CVA6Cfg.RVH && v_i) begin virtual_illegal_instr = (priv_lvl_i == riscv::PRIV_LVL_S) ? 1'b0 : 1'b1; end else begin illegal_instr = (CVA6Cfg.RVS && (priv_lvl_i inside {riscv::PRIV_LVL_M, riscv::PRIV_LVL_S}) && instr.itype.rd == '0) ? 1'b0 : 1'b1; end instruction_o.op = ariane_pkg::SFENCE_VMA; // check TVM flag and intercept SFENCE.VMA call if necessary if (CVA6Cfg.RVS && priv_lvl_i == riscv::PRIV_LVL_S && tvm_i) begin if (CVA6Cfg.RVH && v_i) virtual_illegal_instr = 1'b1; else illegal_instr = 1'b1; end end else if (CVA6Cfg.RVH) begin if (instr.instr[31:25] == 7'b10001) begin // check privilege level, HFENCE.VVMA can only be executed in M/S mode // otherwise decode an illegal instruction or virtual illegal instruction if (v_i) begin virtual_illegal_instr = 1'b1; end else begin illegal_instr = (priv_lvl_i inside {riscv::PRIV_LVL_M, riscv::PRIV_LVL_S}) ? 1'b0 : 1'b1; end instruction_o.op = ariane_pkg::HFENCE_VVMA; end else if (instr.instr[31:25] == 7'b110001) begin // check privilege level, HFENCE.GVMA can only be executed in M/S mode // otherwise decode an illegal instruction or virtual illegal instruction if (v_i) begin virtual_illegal_instr = 1'b1; end else begin illegal_instr = (priv_lvl_i inside {riscv::PRIV_LVL_M, riscv::PRIV_LVL_S}) ? 1'b0 : 1'b1; end instruction_o.op = ariane_pkg::HFENCE_GVMA; // check TVM flag and intercept HFENCE.GVMA call if necessary if (priv_lvl_i == riscv::PRIV_LVL_S && !v_i && tvm_i) illegal_instr = 1'b1; end else begin illegal_instr = 1'b1; end end else begin illegal_instr = 1'b1; end end endcase end 3'b100: begin // Hypervisor load/store instructions if (CVA6Cfg.RVH) begin if (instr.instr[25] != 1'b0) begin instruction_o.fu = STORE; imm_select = NOIMM; instruction_o.rs1 = instr.stype.rs1; instruction_o.rs2 = instr.stype.rs2; end else begin instruction_o.fu = LOAD; imm_select = NOIMM; instruction_o.rs1 = instr.itype.rs1; instruction_o.rd = instr.itype.rd; end // Hypervisor load/store instructions when V=1 cause virtual instruction if (v_i) virtual_illegal_instr = 1'b1; // Hypervisor load/store instructions in U-mode when hstatus.HU=0 cause an illegal instruction trap. else if (!hu_i && priv_lvl_i == riscv::PRIV_LVL_U) illegal_instr = 1'b1; unique case (instr.rtype.funct7) 7'b011_0000: begin if (instr.rtype.rs2 == 5'b0) begin instruction_o.op = ariane_pkg::HLV_B; end if (instr.rtype.rs2 == 5'b1) begin instruction_o.op = ariane_pkg::HLV_BU; end end 7'b011_0010: begin if (instr.rtype.rs2 == 5'b0) begin instruction_o.op = ariane_pkg::HLV_H; end if (instr.rtype.rs2 == 5'b1) begin instruction_o.op = ariane_pkg::HLV_HU; end if (instr.rtype.rs2 == 5'b11) begin instruction_o.op = ariane_pkg::HLVX_HU; end end 7'b011_0100: begin if (instr.rtype.rs2 == 5'b0) begin instruction_o.op = ariane_pkg::HLV_W; end if (instr.rtype.rs2 == 5'b1) begin instruction_o.op = ariane_pkg::HLV_WU; end if (instr.rtype.rs2 == 5'b11) begin instruction_o.op = ariane_pkg::HLVX_WU; end end 7'b011_0001: instruction_o.op = ariane_pkg::HSV_B; 7'b011_0011: instruction_o.op = ariane_pkg::HSV_H; 7'b011_0101: instruction_o.op = ariane_pkg::HSV_W; 7'b011_0110: instruction_o.op = ariane_pkg::HLV_D; 7'b011_0111: instruction_o.op = ariane_pkg::HSV_D; default: illegal_instr = 1'b1; endcase tinst = { instr.rtype.funct7, instr.rtype.rs2, 5'b0, instr.rtype.funct3, instr.rtype.rd, instr.rtype.opcode }; end else begin illegal_instr = 1'b1; end end // atomically swaps values in the CSR and integer register 3'b001: begin // CSRRW imm_select = IIMM; instruction_o.op = ariane_pkg::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 == '0) instruction_o.op = ariane_pkg::CSR_READ; else instruction_o.op = ariane_pkg::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 == '0) instruction_o.op = ariane_pkg::CSR_READ; else instruction_o.op = ariane_pkg::CSR_CLEAR; end // use zimm and iimm 3'b101: begin // CSRRWI instruction_o.rs1 = instr.itype.rs1; imm_select = IIMM; instruction_o.use_zimm = 1'b1; instruction_o.op = ariane_pkg::CSR_WRITE; end 3'b110: begin // CSRRSI instruction_o.rs1 = 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 = ariane_pkg::CSR_READ; else instruction_o.op = ariane_pkg::CSR_SET; end 3'b111: begin // CSRRCI instruction_o.rs1 = instr.itype.rs1; imm_select = IIMM; instruction_o.use_zimm = 1'b1; // this is just a read if (instr.itype.rs1 == '0) instruction_o.op = ariane_pkg::CSR_READ; else instruction_o.op = ariane_pkg::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 = ariane_pkg::FENCE; // FENCE.I 3'b001: instruction_o.op = ariane_pkg::FENCE_I; default: illegal_instr = 1'b1; endcase 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 (CVA6Cfg.FpPresent && CVA6Cfg.XFVec && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) begin automatic logic allow_replication; // control honoring of replication flag instruction_o.fu = FPU_VEC; // Same unit, but sets 'vectorial' signal instruction_o.rs1 = instr.rvftype.rs1; instruction_o.rs2 = instr.rvftype.rs2; instruction_o.rd = 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 = ariane_pkg::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 = ariane_pkg::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 = ariane_pkg::FMUL; // vfmul.vfmt - Vectorial FP Multiplication 5'b00100: instruction_o.op = ariane_pkg::FDIV; // vfdiv.vfmt - Vectorial FP Division 5'b00101: begin instruction_o.op = ariane_pkg::VFMIN; // vfmin.vfmt - Vectorial FP Minimum check_fprm = 1'b0; // rounding mode irrelevant end 5'b00110: begin instruction_o.op = ariane_pkg::VFMAX; // vfmax.vfmt - Vectorial FP Maximum check_fprm = 1'b0; // rounding mode irrelevant end 5'b00111: begin instruction_o.op = ariane_pkg::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 = ariane_pkg::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 = ariane_pkg::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 = ariane_pkg::FMV_X2F; // vfmv.vfmt.x - GPR to FPR Move else instruction_o.op = ariane_pkg::FMV_F2X; // vfmv.x.vfmt - FPR to GPR Move check_fprm = 1'b0; // no rounding for moves end 5'b00001: begin instruction_o.op = ariane_pkg::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 = ariane_pkg::FCVT_F2I; // vfcvt.x.vfmt - Vectorial FP to Int Conversion 5'b00011: instruction_o.op = ariane_pkg::FCVT_I2F; // vfcvt.vfmt.x - Vectorial Int to FP Conversion 5'b001??: begin instruction_o.op = ariane_pkg::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 (~CVA6Cfg.RVFVec) illegal_instr = 1'b1; 2'b01: if (~CVA6Cfg.XF16ALTVec) illegal_instr = 1'b1; 2'b10: if (~CVA6Cfg.XF16Vec) illegal_instr = 1'b1; 2'b11: if (~CVA6Cfg.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 = ariane_pkg::VFSGNJ; // vfsgnj.vfmt - Vectorial FP Sign Injection end 5'b01110: begin check_fprm = 1'b0; // no rounding for sign-injection instruction_o.op = ariane_pkg::VFSGNJN; // vfsgnjn.vfmt - Vectorial FP Negated Sign Injection end 5'b01111: begin check_fprm = 1'b0; // no rounding for sign-injection instruction_o.op = ariane_pkg::VFSGNJX; // vfsgnjx.vfmt - Vectorial FP XORed Sign Injection end 5'b10000: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFEQ; // vfeq.vfmt - Vectorial FP Equality end 5'b10001: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFNE; // vfne.vfmt - Vectorial FP Non-Equality end 5'b10010: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFLT; // vfle.vfmt - Vectorial FP Less Than end 5'b10011: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFGE; // vfge.vfmt - Vectorial FP Greater or Equal end 5'b10100: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFLE; // vfle.vfmt - Vectorial FP Less or Equal end 5'b10101: begin check_fprm = 1'b0; // no rounding for comparisons instruction_o.op = ariane_pkg::VFGT; // vfgt.vfmt - Vectorial FP Greater Than end 5'b11000: begin instruction_o.op = ariane_pkg::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 (~CVA6Cfg.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 (~CVA6Cfg.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 (~CVA6Cfg.XF16ALTVec) illegal_instr = 1'b1; // destination vector not supported end 2'b10: begin if (~CVA6Cfg.XF16Vec) illegal_instr = 1'b1; // destination vector not supported end 2'b11: begin if (~CVA6Cfg.XF8Vec) illegal_instr = 1'b1; // destination vector not supported end default: illegal_instr = 1'b1; endcase end 5'b11001: begin instruction_o.op = ariane_pkg::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 (~CVA6Cfg.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 (~CVA6Cfg.XF8Vec) illegal_instr = 1'b1; // destination vector not supported end default: illegal_instr = 1'b1; endcase end 5'b11010: begin instruction_o.op = ariane_pkg::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 (~CVA6Cfg.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 (~CVA6Cfg.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 (~CVA6Cfg.XF16ALTVec) illegal_instr = 1'b1; // destination vector not supported end 2'b10: begin if (~CVA6Cfg.XF16Vec) illegal_instr = 1'b1; // destination vector not supported end 2'b11: begin if (~CVA6Cfg.XF8Vec) illegal_instr = 1'b1; // destination vector not supported end default: illegal_instr = 1'b1; endcase end 5'b11011: begin instruction_o.op = ariane_pkg::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 (~CVA6Cfg.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 (~CVA6Cfg.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 (~CVA6Cfg.RVFVec) illegal_instr = 1'b1; 2'b01: if (~CVA6Cfg.XF16ALTVec) illegal_instr = 1'b1; 2'b10: if (~CVA6Cfg.XF16Vec) illegal_instr = 1'b1; 2'b11: if (~CVA6Cfg.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 if (CVA6Cfg.RVB) begin instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001 || ((instr.rtype.funct7 == 7'b000_0101) && !(instr.rtype.funct3[14]))) ? MULT : ALU; end else begin instruction_o.fu = (instr.rtype.funct7 == 7'b000_0001) ? MULT : ALU; end 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 = ariane_pkg::ADD; // Add {7'b010_0000, 3'b000} : instruction_o.op = ariane_pkg::SUB; // Sub {7'b000_0000, 3'b010} : instruction_o.op = ariane_pkg::SLTS; // Set Lower Than { 7'b000_0000, 3'b011 } : instruction_o.op = ariane_pkg::SLTU; // Set Lower Than Unsigned {7'b000_0000, 3'b100} : instruction_o.op = ariane_pkg::XORL; // Xor {7'b000_0000, 3'b110} : instruction_o.op = ariane_pkg::ORL; // Or {7'b000_0000, 3'b111} : instruction_o.op = ariane_pkg::ANDL; // And {7'b000_0000, 3'b001} : instruction_o.op = ariane_pkg::SLL; // Shift Left Logical {7'b000_0000, 3'b101} : instruction_o.op = ariane_pkg::SRL; // Shift Right Logical {7'b010_0000, 3'b101} : instruction_o.op = ariane_pkg::SRA; // Shift Right Arithmetic // Multiplications {7'b000_0001, 3'b000} : instruction_o.op = ariane_pkg::MUL; {7'b000_0001, 3'b001} : instruction_o.op = ariane_pkg::MULH; {7'b000_0001, 3'b010} : instruction_o.op = ariane_pkg::MULHSU; {7'b000_0001, 3'b011} : instruction_o.op = ariane_pkg::MULHU; {7'b000_0001, 3'b100} : instruction_o.op = ariane_pkg::DIV; {7'b000_0001, 3'b101} : instruction_o.op = ariane_pkg::DIVU; {7'b000_0001, 3'b110} : instruction_o.op = ariane_pkg::REM; {7'b000_0001, 3'b111} : instruction_o.op = ariane_pkg::REMU; default: begin illegal_instr_non_bm = 1'b1; end endcase if (CVA6Cfg.RVB) begin unique case ({ instr.rtype.funct7, instr.rtype.funct3 }) //Logical with Negate {7'b010_0000, 3'b111} : instruction_o.op = ariane_pkg::ANDN; // Andn {7'b010_0000, 3'b110} : instruction_o.op = ariane_pkg::ORN; // Orn {7'b010_0000, 3'b100} : instruction_o.op = ariane_pkg::XNOR; // Xnor //Shift and Add (Bitmanip) {7'b001_0000, 3'b010} : instruction_o.op = ariane_pkg::SH1ADD; // Sh1add {7'b001_0000, 3'b100} : instruction_o.op = ariane_pkg::SH2ADD; // Sh2add {7'b001_0000, 3'b110} : instruction_o.op = ariane_pkg::SH3ADD; // Sh3add // Integer maximum/minimum {7'b000_0101, 3'b110} : instruction_o.op = ariane_pkg::MAX; // max {7'b000_0101, 3'b111} : instruction_o.op = ariane_pkg::MAXU; // maxu {7'b000_0101, 3'b100} : instruction_o.op = ariane_pkg::MIN; // min {7'b000_0101, 3'b101} : instruction_o.op = ariane_pkg::MINU; // minu // Single bit instructions {7'b010_0100, 3'b001} : instruction_o.op = ariane_pkg::BCLR; // bclr {7'b010_0100, 3'b101} : instruction_o.op = ariane_pkg::BEXT; // bext {7'b011_0100, 3'b001} : instruction_o.op = ariane_pkg::BINV; // binv {7'b001_0100, 3'b001} : instruction_o.op = ariane_pkg::BSET; // bset // Carry-Less-Multiplication (clmul, clmulh, clmulr) {7'b000_0101, 3'b001} : instruction_o.op = ariane_pkg::CLMUL; // clmul {7'b000_0101, 3'b011} : instruction_o.op = ariane_pkg::CLMULH; // clmulh {7'b000_0101, 3'b010} : instruction_o.op = ariane_pkg::CLMULR; // clmulr // Bitwise Shifting {7'b011_0000, 3'b001} : instruction_o.op = ariane_pkg::ROL; // rol {7'b011_0000, 3'b101} : instruction_o.op = ariane_pkg::ROR; // ror // Zero Extend Op RV32 encoding { 7'b000_0100, 3'b100 } : begin if (!CVA6Cfg.IS_XLEN64 && instr.instr[24:20] == 5'b00000) instruction_o.op = ariane_pkg::ZEXTH; else illegal_instr_bm = 1'b1; end default: begin illegal_instr_bm = 1'b1; end endcase end if (CVA6Cfg.RVZiCond) begin unique case ({ instr.rtype.funct7, instr.rtype.funct3 }) //Conditional move {7'b000_0111, 3'b101} : instruction_o.op = ariane_pkg::CZERO_EQZ; // czero.eqz {7'b000_0111, 3'b111} : instruction_o.op = ariane_pkg::CZERO_NEZ; // czero.nez default: begin illegal_instr_zic = 1'b1; end endcase end //VCS coverage on unique case ({ CVA6Cfg.RVB, CVA6Cfg.RVZiCond }) 2'b00: illegal_instr = illegal_instr_non_bm; 2'b01: illegal_instr = illegal_instr_non_bm & illegal_instr_zic; 2'b10: illegal_instr = illegal_instr_non_bm & illegal_instr_bm; 2'b11: illegal_instr = illegal_instr_non_bm & illegal_instr_bm & illegal_instr_zic; endcase end end // -------------------------- // 32bit Reg-Reg Operations // -------------------------- riscv::OpcodeOp32: 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; if (CVA6Cfg.IS_XLEN64) begin unique case ({ instr.rtype.funct7, instr.rtype.funct3 }) {7'b000_0000, 3'b000} : instruction_o.op = ariane_pkg::ADDW; // addw {7'b010_0000, 3'b000} : instruction_o.op = ariane_pkg::SUBW; // subw {7'b000_0000, 3'b001} : instruction_o.op = ariane_pkg::SLLW; // sllw {7'b000_0000, 3'b101} : instruction_o.op = ariane_pkg::SRLW; // srlw {7'b010_0000, 3'b101} : instruction_o.op = ariane_pkg::SRAW; // sraw // Multiplications {7'b000_0001, 3'b000} : instruction_o.op = ariane_pkg::MULW; {7'b000_0001, 3'b100} : instruction_o.op = ariane_pkg::DIVW; {7'b000_0001, 3'b101} : instruction_o.op = ariane_pkg::DIVUW; {7'b000_0001, 3'b110} : instruction_o.op = ariane_pkg::REMW; {7'b000_0001, 3'b111} : instruction_o.op = ariane_pkg::REMUW; default: illegal_instr_non_bm = 1'b1; endcase if (CVA6Cfg.RVB) begin unique case ({ instr.rtype.funct7, instr.rtype.funct3 }) // Shift with Add (Unsigned Word) {7'b001_0000, 3'b010}: instruction_o.op = ariane_pkg::SH1ADDUW; // sh1add.uw {7'b001_0000, 3'b100}: instruction_o.op = ariane_pkg::SH2ADDUW; // sh2add.uw {7'b001_0000, 3'b110}: instruction_o.op = ariane_pkg::SH3ADDUW; // sh3add.uw // Unsigned word Op's {7'b000_0100, 3'b000}: instruction_o.op = ariane_pkg::ADDUW; // add.uw // Bitwise Shifting {7'b011_0000, 3'b001}: instruction_o.op = ariane_pkg::ROLW; // rolw {7'b011_0000, 3'b101}: instruction_o.op = ariane_pkg::RORW; // rorw // Zero Extend Op RV64 encoding {7'b000_0100, 3'b100}: begin if (instr.instr[24:20] == 5'b00000) instruction_o.op = ariane_pkg::ZEXTH; else illegal_instr_bm = 1'b1; end default: illegal_instr_bm = 1'b1; endcase illegal_instr = illegal_instr_non_bm & illegal_instr_bm; end else begin illegal_instr = illegal_instr_non_bm; end end else illegal_instr = 1'b1; end // -------------------------------- // Reg-Immediate Operations // -------------------------------- riscv::OpcodeOpImm: begin instruction_o.fu = ALU; imm_select = IIMM; instruction_o.rs1 = instr.itype.rs1; instruction_o.rd = instr.itype.rd; unique case (instr.itype.funct3) 3'b000: instruction_o.op = ariane_pkg::ADD; // Add Immediate 3'b010: instruction_o.op = ariane_pkg::SLTS; // Set to one if Lower Than Immediate 3'b011: instruction_o.op = ariane_pkg::SLTU; // Set to one if Lower Than Immediate Unsigned 3'b100: instruction_o.op = ariane_pkg::XORL; // Exclusive Or with Immediate 3'b110: instruction_o.op = ariane_pkg::ORL; // Or with Immediate 3'b111: instruction_o.op = ariane_pkg::ANDL; // And with Immediate 3'b001: begin instruction_o.op = ariane_pkg::SLL; // Shift Left Logical by Immediate if (instr.instr[31:26] != 6'b0) illegal_instr_non_bm = 1'b1; if (instr.instr[25] != 1'b0 && CVA6Cfg.XLEN == 32) illegal_instr_non_bm = 1'b1; end 3'b101: begin if (instr.instr[31:26] == 6'b0) instruction_o.op = ariane_pkg::SRL; // Shift Right Logical by Immediate else if (instr.instr[31:26] == 6'b010_000) instruction_o.op = ariane_pkg::SRA; // Shift Right Arithmetically by Immediate else illegal_instr_non_bm = 1'b1; if (instr.instr[25] != 1'b0 && CVA6Cfg.XLEN == 32) illegal_instr_non_bm = 1'b1; end endcase if (CVA6Cfg.RVB) begin unique case (instr.itype.funct3) 3'b001: begin if (instr.instr[31:25] == 7'b0110000) begin if (instr.instr[24:20] == 5'b00100) instruction_o.op = ariane_pkg::SEXTB; else if (instr.instr[24:20] == 5'b00101) instruction_o.op = ariane_pkg::SEXTH; else if (instr.instr[24:20] == 5'b00010) instruction_o.op = ariane_pkg::CPOP; else if (instr.instr[24:20] == 5'b00000) instruction_o.op = ariane_pkg::CLZ; else if (instr.instr[24:20] == 5'b00001) instruction_o.op = ariane_pkg::CTZ; else illegal_instr_bm = 1'b1; end else if (instr.instr[31:26] == 6'b010010) instruction_o.op = ariane_pkg::BCLRI; else if (instr.instr[31:26] == 6'b011010) instruction_o.op = ariane_pkg::BINVI; else if (instr.instr[31:26] == 6'b001010) instruction_o.op = ariane_pkg::BSETI; else illegal_instr_bm = 1'b1; end 3'b101: begin if (instr.instr[31:20] == 12'b001010000111) instruction_o.op = ariane_pkg::ORCB; else if (CVA6Cfg.IS_XLEN64 && instr.instr[31:20] == 12'b011010111000) instruction_o.op = ariane_pkg::REV8; else if (instr.instr[31:20] == 12'b011010011000) instruction_o.op = ariane_pkg::REV8; else if (instr.instr[31:26] == 6'b010_010) instruction_o.op = ariane_pkg::BEXTI; else if (instr.instr[31:26] == 6'b011_000) instruction_o.op = ariane_pkg::RORI; else illegal_instr_bm = 1'b1; end default: illegal_instr_bm = 1'b1; endcase illegal_instr = illegal_instr_non_bm & illegal_instr_bm; end else begin illegal_instr = illegal_instr_non_bm; end end // -------------------------------- // 32 bit Reg-Immediate Operations // -------------------------------- riscv::OpcodeOpImm32: begin instruction_o.fu = ALU; imm_select = IIMM; instruction_o.rs1 = instr.itype.rs1; instruction_o.rd = instr.itype.rd; if (CVA6Cfg.IS_XLEN64) begin unique case (instr.itype.funct3) 3'b000: instruction_o.op = ariane_pkg::ADDW; // Add Immediate 3'b001: begin instruction_o.op = ariane_pkg::SLLW; // Shift Left Logical by Immediate if (instr.instr[31:25] != 7'b0) illegal_instr_non_bm = 1'b1; end 3'b101: begin if (instr.instr[31:25] == 7'b0) instruction_o.op = ariane_pkg::SRLW; // Shift Right Logical by Immediate else if (instr.instr[31:25] == 7'b010_0000) instruction_o.op = ariane_pkg::SRAW; // Shift Right Arithmetically by Immediate else illegal_instr_non_bm = 1'b1; end default: illegal_instr_non_bm = 1'b1; endcase if (CVA6Cfg.RVB) begin unique case (instr.itype.funct3) 3'b001: begin if (instr.instr[31:25] == 7'b0110000) begin if (instr.instr[21:20] == 2'b10) instruction_o.op = ariane_pkg::CPOPW; else if (instr.instr[21:20] == 2'b00) instruction_o.op = ariane_pkg::CLZW; else if (instr.instr[21:20] == 2'b01) instruction_o.op = ariane_pkg::CTZW; else illegal_instr_bm = 1'b1; end else if (instr.instr[31:26] == 6'b000010) begin instruction_o.op = ariane_pkg::SLLIUW; // Shift Left Logic by Immediate (Unsigned Word) end else illegal_instr_bm = 1'b1; end 3'b101: begin if (instr.instr[31:25] == 7'b011_0000) instruction_o.op = ariane_pkg::RORIW; else illegal_instr_bm = 1'b1; end default: illegal_instr_bm = 1'b1; endcase illegal_instr = illegal_instr_non_bm & illegal_instr_bm; end else begin illegal_instr = illegal_instr_non_bm; end end else illegal_instr = 1'b1; end // -------------------------------- // LSU // -------------------------------- riscv::OpcodeStore: begin 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) 3'b000: instruction_o.op = ariane_pkg::SB; 3'b001: instruction_o.op = ariane_pkg::SH; 3'b010: instruction_o.op = ariane_pkg::SW; 3'b011: if (CVA6Cfg.XLEN == 64) instruction_o.op = ariane_pkg::SD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase if (CVA6Cfg.RVH) begin tinst = {7'b0, instr.stype.rs2, 5'b0, instr.stype.funct3, 5'b0, instr.stype.opcode}; tinst[1] = is_compressed_i ? 1'b0 : 'b1; end end riscv::OpcodeLoad: begin instruction_o.fu = LOAD; imm_select = IIMM; instruction_o.rs1 = instr.itype.rs1; instruction_o.rd = instr.itype.rd; // determine load size and signed type unique case (instr.itype.funct3) 3'b000: instruction_o.op = ariane_pkg::LB; 3'b001: instruction_o.op = ariane_pkg::LH; 3'b010: instruction_o.op = ariane_pkg::LW; 3'b100: instruction_o.op = ariane_pkg::LBU; 3'b101: instruction_o.op = ariane_pkg::LHU; 3'b110: if (CVA6Cfg.XLEN == 64) instruction_o.op = ariane_pkg::LWU; else illegal_instr = 1'b1; 3'b011: if (CVA6Cfg.XLEN == 64) instruction_o.op = ariane_pkg::LD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase if (CVA6Cfg.RVH) begin tinst = {17'b0, instr.itype.funct3, instr.itype.rd, instr.itype.opcode}; tinst[1] = is_compressed_i ? 1'b0 : 'b1; end end // -------------------------------- // Floating-Point Load/store // -------------------------------- riscv::OpcodeStoreFp: begin if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) 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 (CVA6Cfg.XF8) instruction_o.op = ariane_pkg::FSB; else illegal_instr = 1'b1; 3'b001: if (CVA6Cfg.XF16 | CVA6Cfg.XF16ALT) instruction_o.op = ariane_pkg::FSH; else illegal_instr = 1'b1; 3'b010: if (CVA6Cfg.RVF) instruction_o.op = ariane_pkg::FSW; else illegal_instr = 1'b1; 3'b011: if (CVA6Cfg.RVD) instruction_o.op = ariane_pkg::FSD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase if (CVA6Cfg.RVH) begin tinst = {7'b0, instr.stype.rs2, 5'b0, instr.stype.funct3, 5'b0, instr.stype.opcode}; tinst[1] = is_compressed_i ? 1'b0 : 'b1; end end else illegal_instr = 1'b1; end riscv::OpcodeLoadFp: begin if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) 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 (CVA6Cfg.XF8) instruction_o.op = ariane_pkg::FLB; else illegal_instr = 1'b1; 3'b001: if (CVA6Cfg.XF16 | CVA6Cfg.XF16ALT) instruction_o.op = ariane_pkg::FLH; else illegal_instr = 1'b1; 3'b010: if (CVA6Cfg.RVF) instruction_o.op = ariane_pkg::FLW; else illegal_instr = 1'b1; 3'b011: if (CVA6Cfg.RVD) instruction_o.op = ariane_pkg::FLD; else illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase if (CVA6Cfg.RVH) begin tinst = {17'b0, instr.itype.funct3, instr.itype.rd, instr.itype.opcode}; tinst[1] = is_compressed_i ? 1'b0 : 'b1; end end else illegal_instr = 1'b1; end // ---------------------------------- // Floating-Point Reg-Reg Operations // ---------------------------------- riscv::OpcodeMadd, riscv::OpcodeMsub, riscv::OpcodeNmsub, riscv::OpcodeNmadd: begin if (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) 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 = ariane_pkg::FMADD; // fmadd.fmt - FP Fused multiply-add riscv::OpcodeMsub: instruction_o.op = ariane_pkg::FMSUB; // fmsub.fmt - FP Fused multiply-subtract riscv::OpcodeNmsub: instruction_o.op = ariane_pkg::FNMSUB; // fnmsub.fmt - FP Negated fused multiply-subtract riscv::OpcodeNmadd: instruction_o.op = ariane_pkg::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 (~CVA6Cfg.RVF) illegal_instr = 1'b1; 2'b01: if (~CVA6Cfg.RVD) illegal_instr = 1'b1; 2'b10: if (~CVA6Cfg.XF16 & ~CVA6Cfg.XF16ALT) illegal_instr = 1'b1; 2'b11: if (~CVA6Cfg.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 (~CVA6Cfg.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 (CVA6Cfg.FpPresent && fs_i != riscv::Off && ((CVA6Cfg.RVH && (!v_i || vfs_i != riscv::Off)) || !CVA6Cfg.RVH)) 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 = ariane_pkg::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 = ariane_pkg::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 = ariane_pkg::FMUL; // fmul.fmt - FP Multiplication 5'b00011: instruction_o.op = ariane_pkg::FDIV; // fdiv.fmt - FP Division 5'b01011: begin instruction_o.op = ariane_pkg::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 = ariane_pkg::FSGNJ; // fsgn{j[n]/jx}.fmt - FP Sign Injection check_fprm = 1'b0; // instruction encoded in rm, do the check here if (CVA6Cfg.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 = ariane_pkg::FMIN_MAX; // fmin/fmax.fmt - FP Minimum / Maximum check_fprm = 1'b0; // instruction encoded in rm, do the check here if (CVA6Cfg.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 = ariane_pkg::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 (~CVA6Cfg.RVF) illegal_instr = 1'b1; 3'b001: if (~CVA6Cfg.RVD) illegal_instr = 1'b1; 3'b010: if (~CVA6Cfg.XF16) illegal_instr = 1'b1; 3'b110: if (~CVA6Cfg.XF16ALT) illegal_instr = 1'b1; 3'b011: if (~CVA6Cfg.XF8) illegal_instr = 1'b1; default: illegal_instr = 1'b1; endcase end 5'b10100: begin instruction_o.op = ariane_pkg::FCMP; // feq/flt/fle.fmt - FP Comparisons check_fprm = 1'b0; // instruction encoded in rm, do the check here if (CVA6Cfg.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 = ariane_pkg::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 = ariane_pkg::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 || (CVA6Cfg.XF16ALT && instr.rftype.rm == 3'b100)) // FP16ALT has separate encoding instruction_o.op = ariane_pkg::FMV_F2X; // fmv.ifmt.fmt - FPR to GPR Move else if (instr.rftype.rm == 3'b001 || (CVA6Cfg.XF16ALT && instr.rftype.rm == 3'b101)) // FP16ALT has separate encoding instruction_o.op = ariane_pkg::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 = ariane_pkg::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 || (CVA6Cfg.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 (~CVA6Cfg.RVF) illegal_instr = 1'b1; 2'b01: if (~CVA6Cfg.RVD) illegal_instr = 1'b1; 2'b10: if (~CVA6Cfg.XF16 & ~CVA6Cfg.XF16ALT) illegal_instr = 1'b1; 2'b11: if (~CVA6Cfg.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 (~CVA6Cfg.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 = instr.atype.rs1; instruction_o.rs2 = instr.atype.rs2; instruction_o.rd = instr.atype.rd; // TODO(zarubaf): Ordering // words if (CVA6Cfg.RVA && instr.stype.funct3 == 3'h2) begin unique case (instr.instr[31:27]) 5'h0: instruction_o.op = ariane_pkg::AMO_ADDW; 5'h1: instruction_o.op = ariane_pkg::AMO_SWAPW; 5'h2: begin instruction_o.op = ariane_pkg::AMO_LRW; if (instr.atype.rs2 != 0) illegal_instr = 1'b1; end 5'h3: instruction_o.op = ariane_pkg::AMO_SCW; 5'h4: instruction_o.op = ariane_pkg::AMO_XORW; 5'h8: instruction_o.op = ariane_pkg::AMO_ORW; 5'hC: instruction_o.op = ariane_pkg::AMO_ANDW; 5'h10: instruction_o.op = ariane_pkg::AMO_MINW; 5'h14: instruction_o.op = ariane_pkg::AMO_MAXW; 5'h18: instruction_o.op = ariane_pkg::AMO_MINWU; 5'h1C: instruction_o.op = ariane_pkg::AMO_MAXWU; default: illegal_instr = 1'b1; endcase // double words end else if (CVA6Cfg.IS_XLEN64 && CVA6Cfg.RVA && instr.stype.funct3 == 3'h3) begin unique case (instr.instr[31:27]) 5'h0: instruction_o.op = ariane_pkg::AMO_ADDD; 5'h1: instruction_o.op = ariane_pkg::AMO_SWAPD; 5'h2: begin instruction_o.op = ariane_pkg::AMO_LRD; if (instr.atype.rs2 != 0) illegal_instr = 1'b1; end 5'h3: instruction_o.op = ariane_pkg::AMO_SCD; 5'h4: instruction_o.op = ariane_pkg::AMO_XORD; 5'h8: instruction_o.op = ariane_pkg::AMO_ORD; 5'hC: instruction_o.op = ariane_pkg::AMO_ANDD; 5'h10: instruction_o.op = ariane_pkg::AMO_MIND; 5'h14: instruction_o.op = ariane_pkg::AMO_MAXD; 5'h18: instruction_o.op = ariane_pkg::AMO_MINDU; 5'h1C: instruction_o.op = ariane_pkg::AMO_MAXDU; default: illegal_instr = 1'b1; endcase end else begin illegal_instr = 1'b1; end if (CVA6Cfg.RVH) begin tinst = { instr.atype.funct5, instr.atype.aq, instr.atype.rl, instr.atype.rs2, 5'b0, instr.atype.funct3, instr.atype.rd, instr.atype.opcode }; end end // -------------------------------- // Control Flow Instructions // -------------------------------- riscv::OpcodeBranch: begin imm_select = SBIMM; instruction_o.fu = CTRL_FLOW; instruction_o.rs1 = instr.stype.rs1; instruction_o.rs2 = instr.stype.rs2; is_control_flow_instr_o = 1'b1; case (instr.stype.funct3) 3'b000: instruction_o.op = ariane_pkg::EQ; 3'b001: instruction_o.op = ariane_pkg::NE; 3'b100: instruction_o.op = ariane_pkg::LTS; 3'b101: instruction_o.op = ariane_pkg::GES; 3'b110: instruction_o.op = ariane_pkg::LTU; 3'b111: instruction_o.op = ariane_pkg::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 = ariane_pkg::JALR; instruction_o.rs1 = instr.itype.rs1; imm_select = IIMM; instruction_o.rd = 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 = 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 = instr.utype.rd; end riscv::OpcodeLui: begin imm_select = UIMM; instruction_o.fu = ALU; instruction_o.rd = instr.utype.rd; end default: illegal_instr = 1'b1; endcase end if (CVA6Cfg.CvxifEn) begin if (~ex_i.valid && (is_illegal_i || illegal_instr)) begin instruction_o.fu = CVXIF; instruction_o.rs1 = instr.r4type.rs1; instruction_o.rs2 = instr.r4type.rs2; instruction_o.rd = instr.r4type.rd; instruction_o.op = ariane_pkg::OFFLOAD; imm_select = instr.rtype.opcode == riscv::OpcodeMadd || instr.rtype.opcode == riscv::OpcodeMsub || instr.rtype.opcode == riscv::OpcodeNmadd || instr.rtype.opcode == riscv::OpcodeNmsub ? RS3 : MUX_RD_RS3; end end // Accelerator instructions. // These can overwrite the previous decoding entirely. if (CVA6Cfg.EnableAccelerator) begin // only generate decoder if accelerators are enabled (static) if (is_accel) begin instruction_o.fu = acc_instruction.fu; instruction_o.vfp = acc_instruction.vfp; instruction_o.rs1 = acc_instruction.rs1; instruction_o.rs2 = acc_instruction.rs2; instruction_o.rd = acc_instruction.rd; instruction_o.op = acc_instruction.op; illegal_instr = acc_illegal_instr; is_control_flow_instr_o = acc_is_control_flow_instr; end end end // -------------------------------- // Sign extend immediate // -------------------------------- always_comb begin : sign_extend imm_i_type = {{CVA6Cfg.XLEN - 12{instruction_i[31]}}, instruction_i[31:20]}; imm_s_type = { {CVA6Cfg.XLEN - 12{instruction_i[31]}}, instruction_i[31:25], instruction_i[11:7] }; imm_sb_type = { {CVA6Cfg.XLEN - 13{instruction_i[31]}}, instruction_i[31], instruction_i[7], instruction_i[30:25], instruction_i[11:8], 1'b0 }; imm_u_type = { {CVA6Cfg.XLEN - 32{instruction_i[31]}}, instruction_i[31:12], 12'b0 }; // JAL, AUIPC, sign extended to 64 bit imm_uj_type = { {CVA6Cfg.XLEN - 20{instruction_i[31]}}, instruction_i[19:12], instruction_i[20], instruction_i[30:21], 1'b0 }; // NOIMM, IIMM, SIMM, SBIMM, 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 = {{CVA6Cfg.XLEN - 5{1'b0}}, instr.r4type.rs3}; instruction_o.use_imm = 1'b0; end MUX_RD_RS3: begin // result holds address of operand rs3 which is in rd field instruction_o.result = {{CVA6Cfg.XLEN - 5{1'b0}}, instr.rtype.rd}; instruction_o.use_imm = 1'b0; end default: begin instruction_o.result = {CVA6Cfg.XLEN{1'b0}}; instruction_o.use_imm = 1'b0; end endcase if (CVA6Cfg.EnableAccelerator) begin if (is_accel) begin instruction_o.result = acc_instruction.result; instruction_o.use_imm = acc_instruction.use_imm; end end end // --------------------- // Exception handling // --------------------- logic [CVA6Cfg.XLEN-1:0] interrupt_cause; // this instruction has already executed if the exception is valid assign instruction_o.valid = instruction_o.ex.valid; always_comb begin : exception_handling interrupt_cause = '0; instruction_o.ex = ex_i; orig_instr_o = '0; // 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 if (CVA6Cfg.CvxifEn || CVA6Cfg.RVF) orig_instr_o = (is_compressed_i) ? {{CVA6Cfg.XLEN-16{1'b0}}, compressed_instr_i} : {{CVA6Cfg.XLEN-32{1'b0}}, instruction_i}; if (CVA6Cfg.TvalEn) instruction_o.ex.tval = (is_compressed_i) ? {{CVA6Cfg.XLEN-16{1'b0}}, compressed_instr_i} : {{CVA6Cfg.XLEN-32{1'b0}}, instruction_i}; else instruction_o.ex.tval = '0; if (CVA6Cfg.RVH) instruction_o.ex.tinst = tinst; else instruction_o.ex.tinst = '0; // 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 if (!CVA6Cfg.CvxifEn) instruction_o.ex.valid = 1'b1; // we decoded an illegal exception here instruction_o.ex.cause = riscv::ILLEGAL_INSTR; end else if (CVA6Cfg.RVH && virtual_illegal_instr) begin instruction_o.ex.valid = 1'b1; // we decoded an virtual illegal exception here instruction_o.ex.cause = riscv::VIRTUAL_INSTRUCTION; // we got an ecall, set the correct cause depending on the current privilege level end else if (ecall) begin // this exception is valid instruction_o.ex.valid = 1'b1; // depending on the privilege mode, set the appropriate cause if (priv_lvl_i == riscv::PRIV_LVL_S && CVA6Cfg.RVS) begin instruction_o.ex.cause = (CVA6Cfg.RVH && v_i) ? riscv::ENV_CALL_VSMODE : riscv::ENV_CALL_SMODE; end else if (priv_lvl_i == riscv::PRIV_LVL_U && CVA6Cfg.RVU) begin instruction_o.ex.cause = riscv::ENV_CALL_UMODE; end else if (priv_lvl_i == riscv::PRIV_LVL_M) begin instruction_o.ex.cause = riscv::ENV_CALL_MMODE; end end else if (ebreak) begin // this exception is valid instruction_o.ex.valid = 1'b1; // set breakpoint cause instruction_o.ex.cause = riscv::BREAKPOINT; // set gva bit if (CVA6Cfg.RVH) instruction_o.ex.gva = v_i; else instruction_o.ex.gva = 1'b0; end // ----------------- // Interrupt Control // ----------------- // we decode an interrupt the same as an exception, hence it will be taken if the instruction did not // throw any previous exception. // we have three interrupt sources: external interrupts, software interrupts, timer interrupts (order of precedence) // for two privilege levels: Supervisor and Machine Mode // Virtual Supervisor Timer Interrupt if (CVA6Cfg.RVH) begin if (irq_ctrl_i.mie[riscv::IRQ_VS_TIMER] && irq_ctrl_i.mip[riscv::IRQ_VS_TIMER]) begin interrupt_cause = INTERRUPTS.VS_TIMER; end // Virtual Supervisor Software Interrupt if (irq_ctrl_i.mie[riscv::IRQ_VS_SOFT] && irq_ctrl_i.mip[riscv::IRQ_VS_SOFT]) begin interrupt_cause = INTERRUPTS.VS_SW; end // Virtual Supervisor External Interrupt if (irq_ctrl_i.mie[riscv::IRQ_VS_EXT] && (irq_ctrl_i.mip[riscv::IRQ_VS_EXT])) begin interrupt_cause = INTERRUPTS.VS_EXT; end // Hypervisor Guest External Interrupts if (irq_ctrl_i.mie[riscv::IRQ_HS_EXT] && irq_ctrl_i.mip[riscv::IRQ_HS_EXT]) begin interrupt_cause = INTERRUPTS.HS_EXT; end end if (CVA6Cfg.RVS) begin // Supervisor Timer Interrupt if (irq_ctrl_i.mie[riscv::IRQ_S_TIMER] && irq_ctrl_i.mip[riscv::IRQ_S_TIMER]) begin interrupt_cause = INTERRUPTS.S_TIMER; end // Supervisor Software Interrupt if (irq_ctrl_i.mie[riscv::IRQ_S_SOFT] && irq_ctrl_i.mip[riscv::IRQ_S_SOFT]) begin interrupt_cause = INTERRUPTS.S_SW; end // Supervisor External Interrupt // The logical-OR of the software-writable bit and the signal from the external interrupt controller is // used to generate external interrupts to the supervisor if (irq_ctrl_i.mie[riscv::IRQ_S_EXT] && (irq_ctrl_i.mip[riscv::IRQ_S_EXT] | irq_i[ariane_pkg::SupervisorIrq])) begin interrupt_cause = INTERRUPTS.S_EXT; end end // Machine Timer Interrupt if (irq_ctrl_i.mip[riscv::IRQ_M_TIMER] && irq_ctrl_i.mie[riscv::IRQ_M_TIMER]) begin interrupt_cause = INTERRUPTS.M_TIMER; end // Machine Mode Software Interrupt if (irq_ctrl_i.mip[riscv::IRQ_M_SOFT] && irq_ctrl_i.mie[riscv::IRQ_M_SOFT]) begin interrupt_cause = INTERRUPTS.M_SW; end // Machine Mode External Interrupt if (irq_ctrl_i.mip[riscv::IRQ_M_EXT] && irq_ctrl_i.mie[riscv::IRQ_M_EXT]) begin interrupt_cause = INTERRUPTS.M_EXT; end if (interrupt_cause[CVA6Cfg.XLEN-1] && irq_ctrl_i.global_enable) begin // However, if bit i in mideleg is set, interrupts are considered to be globally enabled if the hart’s current privilege // mode equals the delegated privilege mode (S or U) and that mode’s interrupt enable bit // (SIE or UIE in mstatus) is set, or if the current privilege mode is less than the delegated privilege mode. if (irq_ctrl_i.mideleg[interrupt_cause[$clog2(CVA6Cfg.XLEN)-1:0]]) begin if (CVA6Cfg.RVH) begin : hyp_int_gen if (v_i && irq_ctrl_i.hideleg[interrupt_cause[$clog2(CVA6Cfg.XLEN)-1:0]]) begin if ((irq_ctrl_i.sie && priv_lvl_i == riscv::PRIV_LVL_S) || priv_lvl_i == riscv::PRIV_LVL_U) begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = interrupt_cause; end end else if (v_i && ~irq_ctrl_i.hideleg[interrupt_cause[$clog2( CVA6Cfg.XLEN )-1:0]]) begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = interrupt_cause; end else if (!v_i && ((irq_ctrl_i.sie && priv_lvl_i == riscv::PRIV_LVL_S) || priv_lvl_i == riscv::PRIV_LVL_U) && ~irq_ctrl_i.hideleg[interrupt_cause[$clog2( CVA6Cfg.XLEN )-1:0]]) begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = interrupt_cause; end end else begin if ((CVA6Cfg.RVS && irq_ctrl_i.sie && priv_lvl_i == riscv::PRIV_LVL_S) || (CVA6Cfg.RVU && priv_lvl_i == riscv::PRIV_LVL_U)) begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = interrupt_cause; end end end else begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = interrupt_cause; end end end // a debug request has precendece over everything else if (CVA6Cfg.DebugEn && debug_req_i && !debug_mode_i) begin instruction_o.ex.valid = 1'b1; instruction_o.ex.cause = riscv::DEBUG_REQUEST; end end endmodule