// Copyright lowRISC contributors. // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 /** * Instruction decoder * * This module is fully combinatorial, clock and reset are used for * assertions only. */ `include "prim_assert.sv" module ibex_decoder #( parameter bit RV32E = 0, parameter ibex_pkg::rv32m_e RV32M = ibex_pkg::RV32MFast, parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, parameter bit BranchTargetALU = 0 ) ( input logic clk_i, input logic rst_ni, // to/from controller output logic illegal_insn_o, // illegal instr encountered output logic ebrk_insn_o, // trap instr encountered output logic mret_insn_o, // return from exception instr // encountered output logic dret_insn_o, // return from debug instr encountered output logic ecall_insn_o, // syscall instr encountered output logic wfi_insn_o, // wait for interrupt instr encountered output logic jump_set_o, // jump taken set signal input logic branch_taken_i, // registered branch decision output logic icache_inval_o, // from IF-ID pipeline register input logic instr_first_cycle_i, // instruction read is in its first cycle input logic [31:0] instr_rdata_i, // instruction read from memory/cache input logic [31:0] instr_rdata_alu_i, // instruction read from memory/cache // replicated to ease fan-out) input logic illegal_c_insn_i, // compressed instruction decode failed // immediates output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b output ibex_pkg::op_a_sel_e bt_a_mux_sel_o, // branch target selection operand a output ibex_pkg::imm_b_sel_e bt_b_mux_sel_o, // branch target selection operand b output logic [31:0] imm_i_type_o, output logic [31:0] imm_s_type_o, output logic [31:0] imm_b_type_o, output logic [31:0] imm_u_type_o, output logic [31:0] imm_j_type_o, output logic [31:0] zimm_rs1_type_o, // register file output ibex_pkg::rf_wd_sel_e rf_wdata_sel_o, // RF write data selection output logic rf_we_o, // write enable for regfile output logic [4:0] rf_raddr_a_o, output logic [4:0] rf_raddr_b_o, output logic [4:0] rf_waddr_o, output logic rf_ren_a_o, // Instruction reads from RF addr A output logic rf_ren_b_o, // Instruction reads from RF addr B // ALU output ibex_pkg::alu_op_e alu_operator_o, // ALU operation selection output ibex_pkg::op_a_sel_e alu_op_a_mux_sel_o, // operand a selection: reg value, PC, // immediate or zero output ibex_pkg::op_b_sel_e alu_op_b_mux_sel_o, // operand b selection: reg value or // immediate output logic alu_multicycle_o, // ternary bitmanip instruction // MULT & DIV output logic mult_en_o, // perform integer multiplication output logic div_en_o, // perform integer division or remainder output logic mult_sel_o, // as above but static, for data muxes output logic div_sel_o, // as above but static, for data muxes output ibex_pkg::md_op_e multdiv_operator_o, output logic [1:0] multdiv_signed_mode_o, // CSRs output logic csr_access_o, // access to CSR output ibex_pkg::csr_op_e csr_op_o, // operation to perform on CSR // LSU output logic data_req_o, // start transaction to data memory output logic data_we_o, // write enable output logic [1:0] data_type_o, // size of transaction: byte, half // word or word output logic data_sign_extension_o, // sign extension for data read from // memory // jump/branches output logic jump_in_dec_o, // jump is being calculated in ALU output logic branch_in_dec_o ); import ibex_pkg::*; logic illegal_insn; logic illegal_reg_rv32e; logic csr_illegal; logic rf_we; logic [31:0] instr; logic [31:0] instr_alu; logic [9:0] unused_instr_alu; // Source/Destination register instruction index logic [4:0] instr_rs1; logic [4:0] instr_rs2; logic [4:0] instr_rs3; logic [4:0] instr_rd; logic use_rs3_d; logic use_rs3_q; csr_op_e csr_op; opcode_e opcode; opcode_e opcode_alu; // To help timing the flops containing the current instruction are replicated to reduce fan-out. // instr_alu is used to determine the ALU control logic and associated operand/imm select signals // as the ALU is often on the more critical timing paths. instr is used for everything else. assign instr = instr_rdata_i; assign instr_alu = instr_rdata_alu_i; ////////////////////////////////////// // Register and immediate selection // ////////////////////////////////////// // immediate extraction and sign extension assign imm_i_type_o = { {20{instr[31]}}, instr[31:20] }; assign imm_s_type_o = { {20{instr[31]}}, instr[31:25], instr[11:7] }; assign imm_b_type_o = { {19{instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8], 1'b0 }; assign imm_u_type_o = { instr[31:12], 12'b0 }; assign imm_j_type_o = { {12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 }; // immediate for CSR manipulation (zero extended) assign zimm_rs1_type_o = { 27'b0, instr_rs1 }; // rs1 if (RV32B != RV32BNone) begin : gen_rs3_flop // the use of rs3 is known one cycle ahead. always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin use_rs3_q <= 1'b0; end else begin use_rs3_q <= use_rs3_d; end end end else begin : gen_no_rs3_flop logic unused_clk; logic unused_rst_n; // Clock and reset unused when there's no rs3 flop assign unused_clk = clk_i; assign unused_rst_n = rst_ni; // always zero assign use_rs3_q = use_rs3_d; end // source registers assign instr_rs1 = instr[19:15]; assign instr_rs2 = instr[24:20]; assign instr_rs3 = instr[31:27]; assign rf_raddr_a_o = (use_rs3_q & ~instr_first_cycle_i) ? instr_rs3 : instr_rs1; // rs3 / rs1 assign rf_raddr_b_o = instr_rs2; // rs2 // destination register assign instr_rd = instr[11:7]; assign rf_waddr_o = instr_rd; // rd //////////////////// // Register check // //////////////////// if (RV32E) begin : gen_rv32e_reg_check_active assign illegal_reg_rv32e = ((rf_raddr_a_o[4] & (alu_op_a_mux_sel_o == OP_A_REG_A)) | (rf_raddr_b_o[4] & (alu_op_b_mux_sel_o == OP_B_REG_B)) | (rf_waddr_o[4] & rf_we)); end else begin : gen_rv32e_reg_check_inactive assign illegal_reg_rv32e = 1'b0; end /////////////////////// // CSR operand check // /////////////////////// always_comb begin : csr_operand_check csr_op_o = csr_op; // CSRRSI/CSRRCI must not write 0 to CSRs (uimm[4:0]=='0) // CSRRS/CSRRC must not write from x0 to CSRs (rs1=='0) if ((csr_op == CSR_OP_SET || csr_op == CSR_OP_CLEAR) && instr_rs1 == '0) begin csr_op_o = CSR_OP_READ; end end ///////////// // Decoder // ///////////// always_comb begin jump_in_dec_o = 1'b0; jump_set_o = 1'b0; branch_in_dec_o = 1'b0; icache_inval_o = 1'b0; multdiv_operator_o = MD_OP_MULL; multdiv_signed_mode_o = 2'b00; rf_wdata_sel_o = RF_WD_EX; rf_we = 1'b0; rf_ren_a_o = 1'b0; rf_ren_b_o = 1'b0; csr_access_o = 1'b0; csr_illegal = 1'b0; csr_op = CSR_OP_READ; data_we_o = 1'b0; data_type_o = 2'b00; data_sign_extension_o = 1'b0; data_req_o = 1'b0; illegal_insn = 1'b0; ebrk_insn_o = 1'b0; mret_insn_o = 1'b0; dret_insn_o = 1'b0; ecall_insn_o = 1'b0; wfi_insn_o = 1'b0; opcode = opcode_e'(instr[6:0]); unique case (opcode) /////////// // Jumps // /////////// OPCODE_JAL: begin // Jump and Link jump_in_dec_o = 1'b1; if (instr_first_cycle_i) begin // Calculate jump target (and store PC + 4 if BranchTargetALU is configured) rf_we = BranchTargetALU; jump_set_o = 1'b1; end else begin // Calculate and store PC+4 rf_we = 1'b1; end end OPCODE_JALR: begin // Jump and Link Register jump_in_dec_o = 1'b1; if (instr_first_cycle_i) begin // Calculate jump target (and store PC + 4 if BranchTargetALU is configured) rf_we = BranchTargetALU; jump_set_o = 1'b1; end else begin // Calculate and store PC+4 rf_we = 1'b1; end if (instr[14:12] != 3'b0) begin illegal_insn = 1'b1; end rf_ren_a_o = 1'b1; end OPCODE_BRANCH: begin // Branch branch_in_dec_o = 1'b1; // Check branch condition selection unique case (instr[14:12]) 3'b000, 3'b001, 3'b100, 3'b101, 3'b110, 3'b111: illegal_insn = 1'b0; default: illegal_insn = 1'b1; endcase rf_ren_a_o = 1'b1; rf_ren_b_o = 1'b1; end //////////////// // Load/store // //////////////// OPCODE_STORE: begin rf_ren_a_o = 1'b1; rf_ren_b_o = 1'b1; data_req_o = 1'b1; data_we_o = 1'b1; if (instr[14]) begin illegal_insn = 1'b1; end // store size unique case (instr[13:12]) 2'b00: data_type_o = 2'b10; // sb 2'b01: data_type_o = 2'b01; // sh 2'b10: data_type_o = 2'b00; // sw default: illegal_insn = 1'b1; endcase end OPCODE_LOAD: begin rf_ren_a_o = 1'b1; data_req_o = 1'b1; data_type_o = 2'b00; // sign/zero extension data_sign_extension_o = ~instr[14]; // load size unique case (instr[13:12]) 2'b00: data_type_o = 2'b10; // lb(u) 2'b01: data_type_o = 2'b01; // lh(u) 2'b10: begin data_type_o = 2'b00; // lw if (instr[14]) begin illegal_insn = 1'b1; // lwu does not exist end end default: begin illegal_insn = 1'b1; end endcase end ///////// // ALU // ///////// OPCODE_LUI: begin // Load Upper Immediate rf_we = 1'b1; end OPCODE_AUIPC: begin // Add Upper Immediate to PC rf_we = 1'b1; end OPCODE_OP_IMM: begin // Register-Immediate ALU Operations rf_ren_a_o = 1'b1; rf_we = 1'b1; unique case (instr[14:12]) 3'b000, 3'b010, 3'b011, 3'b100, 3'b110, 3'b111: illegal_insn = 1'b0; 3'b001: begin unique case (instr[31:27]) 5'b0_0000: illegal_insn = (instr[26:25] == 2'b00) ? 1'b0 : 1'b1; // slli 5'b0_0100: begin // sloi illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end 5'b0_1001, // bclri 5'b0_0101, // bseti 5'b0_1101: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // binvi 5'b0_0001: begin if (instr[26] == 1'b0) begin // shfl illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end else begin illegal_insn = 1'b1; end end 5'b0_1100: begin unique case(instr[26:20]) 7'b000_0000, // clz 7'b000_0001, // ctz 7'b000_0010, // cpop 7'b000_0100, // sext.b 7'b000_0101: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // sext.h 7'b001_0000, // crc32.b 7'b001_0001, // crc32.h 7'b001_0010, // crc32.w 7'b001_1000, // crc32c.b 7'b001_1001, // crc32c.h 7'b001_1010: begin // crc32c.w illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end default: illegal_insn = 1'b1; endcase end default : illegal_insn = 1'b1; endcase end 3'b101: begin if (instr[26]) begin illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // fsri end else begin unique case (instr[31:27]) 5'b0_0000, // srli 5'b0_1000: illegal_insn = (instr[26:25] == 2'b00) ? 1'b0 : 1'b1; // srai 5'b0_0100: begin // sroi illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end 5'b0_1100, // rori 5'b0_1001: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // bexti 5'b0_1101: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin illegal_insn = 1'b0; // grevi end else if (RV32B == RV32BBalanced) begin illegal_insn = (instr[24:20] == 5'b11000) ? 1'b0 : 1'b1; // rev8 end else begin illegal_insn = 1'b1; end end 5'b0_0101: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin illegal_insn = 1'b0; // gorci end else if (instr[24:20] == 5'b00111) begin illegal_insn = (RV32B == RV32BBalanced) ? 1'b0 : 1'b1; // orc.b end else begin illegal_insn = 1'b1; end end 5'b0_0001: begin if (instr[26] == 1'b0) begin // unshfl illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end else begin illegal_insn = 1'b1; end end default: illegal_insn = 1'b1; endcase end end default: illegal_insn = 1'b1; endcase end OPCODE_OP: begin // Register-Register ALU operation rf_ren_a_o = 1'b1; rf_ren_b_o = 1'b1; rf_we = 1'b1; if ({instr[26], instr[13:12]} == {1'b1, 2'b01}) begin illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // cmix / cmov / fsl / fsr end else begin unique case ({instr[31:25], instr[14:12]}) // RV32I ALU operations {7'b000_0000, 3'b000}, {7'b010_0000, 3'b000}, {7'b000_0000, 3'b010}, {7'b000_0000, 3'b011}, {7'b000_0000, 3'b100}, {7'b000_0000, 3'b110}, {7'b000_0000, 3'b111}, {7'b000_0000, 3'b001}, {7'b000_0000, 3'b101}, {7'b010_0000, 3'b101}: illegal_insn = 1'b0; // RV32B zba {7'b001_0000, 3'b010}, // sh1add {7'b001_0000, 3'b100}, // sh2add {7'b001_0000, 3'b110}, // sh3add // RV32B zbb {7'b010_0000, 3'b111}, // andn {7'b010_0000, 3'b110}, // orn {7'b010_0000, 3'b100}, // xnor {7'b011_0000, 3'b001}, // rol {7'b011_0000, 3'b101}, // ror {7'b000_0101, 3'b100}, // min {7'b000_0101, 3'b110}, // max {7'b000_0101, 3'b101}, // minu {7'b000_0101, 3'b111}, // maxu {7'b000_0100, 3'b100}, // pack {7'b010_0100, 3'b100}, // packu {7'b000_0100, 3'b111}, // packh // RV32B zbs {7'b010_0100, 3'b001}, // bclr {7'b001_0100, 3'b001}, // bset {7'b011_0100, 3'b001}, // binv {7'b010_0100, 3'b101}, // bext // RV32B zbf {7'b010_0100, 3'b111}: illegal_insn = (RV32B != RV32BNone) ? 1'b0 : 1'b1; // bfp // RV32B zbp {7'b011_0100, 3'b101}, // grev {7'b001_0100, 3'b101}, // gorc {7'b000_0100, 3'b001}, // shfl {7'b000_0100, 3'b101}, // unshfl {7'b001_0100, 3'b010}, // xperm.n {7'b001_0100, 3'b100}, // xperm.b {7'b001_0100, 3'b110}, // xperm.h {7'b001_0000, 3'b001}, // slo {7'b001_0000, 3'b101}, // sro // RV32B zbc {7'b000_0101, 3'b001}, // clmul {7'b000_0101, 3'b010}, // clmulr {7'b000_0101, 3'b011}: begin // clmulh illegal_insn = (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) ? 1'b0 : 1'b1; end // RV32B zbe {7'b010_0100, 3'b110}, // bdecompress {7'b000_0100, 3'b110}: illegal_insn = (RV32B == RV32BFull) ? 1'b0 : 1'b1; // bcompress // RV32M instructions {7'b000_0001, 3'b000}: begin // mul multdiv_operator_o = MD_OP_MULL; multdiv_signed_mode_o = 2'b00; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b001}: begin // mulh multdiv_operator_o = MD_OP_MULH; multdiv_signed_mode_o = 2'b11; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b010}: begin // mulhsu multdiv_operator_o = MD_OP_MULH; multdiv_signed_mode_o = 2'b01; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b011}: begin // mulhu multdiv_operator_o = MD_OP_MULH; multdiv_signed_mode_o = 2'b00; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b100}: begin // div multdiv_operator_o = MD_OP_DIV; multdiv_signed_mode_o = 2'b11; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b101}: begin // divu multdiv_operator_o = MD_OP_DIV; multdiv_signed_mode_o = 2'b00; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b110}: begin // rem multdiv_operator_o = MD_OP_REM; multdiv_signed_mode_o = 2'b11; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end {7'b000_0001, 3'b111}: begin // remu multdiv_operator_o = MD_OP_REM; multdiv_signed_mode_o = 2'b00; illegal_insn = (RV32M == RV32MNone) ? 1'b1 : 1'b0; end default: begin illegal_insn = 1'b1; end endcase end end ///////////// // Special // ///////////// OPCODE_MISC_MEM: begin unique case (instr[14:12]) 3'b000: begin // FENCE is treated as a NOP since all memory operations are already strictly ordered. rf_we = 1'b0; end 3'b001: begin // FENCE.I is implemented as a jump to the next PC, this gives the required flushing // behaviour (iside prefetch buffer flushed and response to any outstanding iside // requests will be ignored). // If present, the ICache will also be flushed. jump_in_dec_o = 1'b1; rf_we = 1'b0; if (instr_first_cycle_i) begin jump_set_o = 1'b1; icache_inval_o = 1'b1; end end default: begin illegal_insn = 1'b1; end endcase end OPCODE_SYSTEM: begin if (instr[14:12] == 3'b000) begin // non CSR related SYSTEM instructions unique case (instr[31:20]) 12'h000: // ECALL // environment (system) call ecall_insn_o = 1'b1; 12'h001: // ebreak // debugger trap ebrk_insn_o = 1'b1; 12'h302: // mret mret_insn_o = 1'b1; 12'h7b2: // dret dret_insn_o = 1'b1; 12'h105: // wfi wfi_insn_o = 1'b1; default: illegal_insn = 1'b1; endcase // rs1 and rd must be 0 if (instr_rs1 != 5'b0 || instr_rd != 5'b0) begin illegal_insn = 1'b1; end end else begin // instruction to read/modify CSR csr_access_o = 1'b1; rf_wdata_sel_o = RF_WD_CSR; rf_we = 1'b1; if (~instr[14]) begin rf_ren_a_o = 1'b1; end unique case (instr[13:12]) 2'b01: csr_op = CSR_OP_WRITE; 2'b10: csr_op = CSR_OP_SET; 2'b11: csr_op = CSR_OP_CLEAR; default: csr_illegal = 1'b1; endcase illegal_insn = csr_illegal; end end default: begin illegal_insn = 1'b1; end endcase // make sure illegal compressed instructions cause illegal instruction exceptions if (illegal_c_insn_i) begin illegal_insn = 1'b1; end // make sure illegal instructions detected in the decoder do not propagate from decoder // into register file, LSU, EX, WB, CSRs, PC // NOTE: instructions can also be detected to be illegal inside the CSRs (upon accesses with // insufficient privileges), or when accessing non-available registers in RV32E, // these cases are not handled here if (illegal_insn) begin rf_we = 1'b0; data_req_o = 1'b0; data_we_o = 1'b0; jump_in_dec_o = 1'b0; jump_set_o = 1'b0; branch_in_dec_o = 1'b0; csr_access_o = 1'b0; end end ///////////////////////////// // Decoder for ALU control // ///////////////////////////// always_comb begin alu_operator_o = ALU_SLTU; alu_op_a_mux_sel_o = OP_A_IMM; alu_op_b_mux_sel_o = OP_B_IMM; imm_a_mux_sel_o = IMM_A_ZERO; imm_b_mux_sel_o = IMM_B_I; bt_a_mux_sel_o = OP_A_CURRPC; bt_b_mux_sel_o = IMM_B_I; opcode_alu = opcode_e'(instr_alu[6:0]); use_rs3_d = 1'b0; alu_multicycle_o = 1'b0; mult_sel_o = 1'b0; div_sel_o = 1'b0; unique case (opcode_alu) /////////// // Jumps // /////////// OPCODE_JAL: begin // Jump and Link if (BranchTargetALU) begin bt_a_mux_sel_o = OP_A_CURRPC; bt_b_mux_sel_o = IMM_B_J; end // Jumps take two cycles without the BTALU if (instr_first_cycle_i && !BranchTargetALU) begin // Calculate jump target alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_J; alu_operator_o = ALU_ADD; end else begin // Calculate and store PC+4 alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_INCR_PC; alu_operator_o = ALU_ADD; end end OPCODE_JALR: begin // Jump and Link Register if (BranchTargetALU) begin bt_a_mux_sel_o = OP_A_REG_A; bt_b_mux_sel_o = IMM_B_I; end // Jumps take two cycles without the BTALU if (instr_first_cycle_i && !BranchTargetALU) begin // Calculate jump target alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_I; alu_operator_o = ALU_ADD; end else begin // Calculate and store PC+4 alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_INCR_PC; alu_operator_o = ALU_ADD; end end OPCODE_BRANCH: begin // Branch // Check branch condition selection unique case (instr_alu[14:12]) 3'b000: alu_operator_o = ALU_EQ; 3'b001: alu_operator_o = ALU_NE; 3'b100: alu_operator_o = ALU_LT; 3'b101: alu_operator_o = ALU_GE; 3'b110: alu_operator_o = ALU_LTU; 3'b111: alu_operator_o = ALU_GEU; default: ; endcase if (BranchTargetALU) begin bt_a_mux_sel_o = OP_A_CURRPC; // Not-taken branch will jump to next instruction (used in secure mode) bt_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC; end // Without branch target ALU, a branch is a two-stage operation using the Main ALU in both // stages if (instr_first_cycle_i) begin // First evaluate the branch condition alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_REG_B; end else if (!BranchTargetALU) begin // Then calculate jump target alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; // Not-taken branch will jump to next instruction (used in secure mode) imm_b_mux_sel_o = branch_taken_i ? IMM_B_B : IMM_B_INCR_PC; alu_operator_o = ALU_ADD; end end //////////////// // Load/store // //////////////// OPCODE_STORE: begin alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_REG_B; alu_operator_o = ALU_ADD; if (!instr_alu[14]) begin // offset from immediate imm_b_mux_sel_o = IMM_B_S; alu_op_b_mux_sel_o = OP_B_IMM; end end OPCODE_LOAD: begin alu_op_a_mux_sel_o = OP_A_REG_A; // offset from immediate alu_operator_o = ALU_ADD; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_I; end ///////// // ALU // ///////// OPCODE_LUI: begin // Load Upper Immediate alu_op_a_mux_sel_o = OP_A_IMM; alu_op_b_mux_sel_o = OP_B_IMM; imm_a_mux_sel_o = IMM_A_ZERO; imm_b_mux_sel_o = IMM_B_U; alu_operator_o = ALU_ADD; end OPCODE_AUIPC: begin // Add Upper Immediate to PC alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_U; alu_operator_o = ALU_ADD; end OPCODE_OP_IMM: begin // Register-Immediate ALU Operations alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_I; unique case (instr_alu[14:12]) 3'b000: alu_operator_o = ALU_ADD; // Add Immediate 3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate 3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned 3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate 3'b110: alu_operator_o = ALU_OR; // Or with Immediate 3'b111: alu_operator_o = ALU_AND; // And with Immediate 3'b001: begin if (RV32B != RV32BNone) begin unique case (instr_alu[31:27]) 5'b0_0000: alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate // Shift Left Ones by Immediate 5'b0_0100: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_SLO; end 5'b0_1001: alu_operator_o = ALU_BCLR; // Clear bit specified by immediate 5'b0_0101: alu_operator_o = ALU_BSET; // Set bit specified by immediate 5'b0_1101: alu_operator_o = ALU_BINV; // Invert bit specified by immediate. // Shuffle with Immediate Control Value 5'b0_0001: if (instr_alu[26] == 0) alu_operator_o = ALU_SHFL; 5'b0_1100: begin unique case (instr_alu[26:20]) 7'b000_0000: alu_operator_o = ALU_CLZ; // clz 7'b000_0001: alu_operator_o = ALU_CTZ; // ctz 7'b000_0010: alu_operator_o = ALU_CPOP; // cpop 7'b000_0100: alu_operator_o = ALU_SEXTB; // sext.b 7'b000_0101: alu_operator_o = ALU_SEXTH; // sext.h 7'b001_0000: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32_B; // crc32.b alu_multicycle_o = 1'b1; end end 7'b001_0001: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32_H; // crc32.h alu_multicycle_o = 1'b1; end end 7'b001_0010: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32_W; // crc32.w alu_multicycle_o = 1'b1; end end 7'b001_1000: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32C_B; // crc32c.b alu_multicycle_o = 1'b1; end end 7'b001_1001: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32C_H; // crc32c.h alu_multicycle_o = 1'b1; end end 7'b001_1010: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin alu_operator_o = ALU_CRC32C_W; // crc32c.w alu_multicycle_o = 1'b1; end end default: ; endcase end default: ; endcase end else begin alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate end end 3'b101: begin if (RV32B != RV32BNone) begin if (instr_alu[26] == 1'b1) begin alu_operator_o = ALU_FSR; alu_multicycle_o = 1'b1; if (instr_first_cycle_i) begin use_rs3_d = 1'b1; end else begin use_rs3_d = 1'b0; end end else begin unique case (instr_alu[31:27]) 5'b0_0000: alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate 5'b0_1000: alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate // Shift Right Ones by Immediate 5'b0_0100: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_SRO; end 5'b0_1001: alu_operator_o = ALU_BEXT; // Extract bit specified by immediate. 5'b0_1100: begin alu_operator_o = ALU_ROR; // Rotate Right by Immediate alu_multicycle_o = 1'b1; end 5'b0_1101: alu_operator_o = ALU_GREV; // General Reverse with Imm Control Val 5'b0_0101: alu_operator_o = ALU_GORC; // General Or-combine with Imm Control Val // Unshuffle with Immediate Control Value 5'b0_0001: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) begin if (instr_alu[26] == 1'b0) alu_operator_o = ALU_UNSHFL; end end default: ; endcase end end else begin if (instr_alu[31:27] == 5'b0_0000) begin alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate end else if (instr_alu[31:27] == 5'b0_1000) begin alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate end end end default: ; endcase end OPCODE_OP: begin // Register-Register ALU operation alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_REG_B; if (instr_alu[26]) begin if (RV32B != RV32BNone) begin unique case ({instr_alu[26:25], instr_alu[14:12]}) {2'b11, 3'b001}: begin alu_operator_o = ALU_CMIX; // cmix alu_multicycle_o = 1'b1; if (instr_first_cycle_i) begin use_rs3_d = 1'b1; end else begin use_rs3_d = 1'b0; end end {2'b11, 3'b101}: begin alu_operator_o = ALU_CMOV; // cmov alu_multicycle_o = 1'b1; if (instr_first_cycle_i) begin use_rs3_d = 1'b1; end else begin use_rs3_d = 1'b0; end end {2'b10, 3'b001}: begin alu_operator_o = ALU_FSL; // fsl alu_multicycle_o = 1'b1; if (instr_first_cycle_i) begin use_rs3_d = 1'b1; end else begin use_rs3_d = 1'b0; end end {2'b10, 3'b101}: begin alu_operator_o = ALU_FSR; // fsr alu_multicycle_o = 1'b1; if (instr_first_cycle_i) begin use_rs3_d = 1'b1; end else begin use_rs3_d = 1'b0; end end default: ; endcase end end else begin unique case ({instr_alu[31:25], instr_alu[14:12]}) // RV32I ALU operations {7'b000_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add {7'b010_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub {7'b000_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than {7'b000_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned {7'b000_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor {7'b000_0000, 3'b110}: alu_operator_o = ALU_OR; // Or {7'b000_0000, 3'b111}: alu_operator_o = ALU_AND; // And {7'b000_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical {7'b000_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical {7'b010_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic // RV32B ALU Operations {7'b011_0000, 3'b001}: begin if (RV32B != RV32BNone) begin alu_operator_o = ALU_ROL; alu_multicycle_o = 1'b1; end end {7'b011_0000, 3'b101}: begin if (RV32B != RV32BNone) begin alu_operator_o = ALU_ROR; alu_multicycle_o = 1'b1; end end {7'b000_0101, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_MIN; {7'b000_0101, 3'b110}: if (RV32B != RV32BNone) alu_operator_o = ALU_MAX; {7'b000_0101, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_MINU; {7'b000_0101, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_MAXU; {7'b000_0100, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACK; {7'b010_0100, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACKU; {7'b000_0100, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_PACKH; {7'b010_0000, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_XNOR; {7'b010_0000, 3'b110}: if (RV32B != RV32BNone) alu_operator_o = ALU_ORN; {7'b010_0000, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_ANDN; // RV32B zba {7'b001_0000, 3'b010}: if (RV32B != RV32BNone) alu_operator_o = ALU_SH1ADD; {7'b001_0000, 3'b100}: if (RV32B != RV32BNone) alu_operator_o = ALU_SH2ADD; {7'b001_0000, 3'b110}: if (RV32B != RV32BNone) alu_operator_o = ALU_SH3ADD; // RV32B zbs {7'b010_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_BCLR; {7'b001_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_BSET; {7'b011_0100, 3'b001}: if (RV32B != RV32BNone) alu_operator_o = ALU_BINV; {7'b010_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_BEXT; // RV32B zbf {7'b010_0100, 3'b111}: if (RV32B != RV32BNone) alu_operator_o = ALU_BFP; // RV32B zbp {7'b011_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_GREV; {7'b001_0100, 3'b101}: if (RV32B != RV32BNone) alu_operator_o = ALU_GORC; {7'b000_0100, 3'b001}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_SHFL; end {7'b000_0100, 3'b101}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_UNSHFL; end {7'b001_0100, 3'b010}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_XPERM_N; end {7'b001_0100, 3'b100}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_XPERM_B; end {7'b001_0100, 3'b110}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_XPERM_H; end {7'b001_0000, 3'b001}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_SLO; end {7'b001_0000, 3'b101}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_SRO; end // RV32B zbc {7'b000_0101, 3'b001}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_CLMUL; end {7'b000_0101, 3'b010}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_CLMULR; end {7'b000_0101, 3'b011}: begin if (RV32B == RV32BOTEarlGrey || RV32B == RV32BFull) alu_operator_o = ALU_CLMULH; end // RV32B zbe {7'b010_0100, 3'b110}: begin if (RV32B == RV32BFull) begin alu_operator_o = ALU_BDECOMPRESS; alu_multicycle_o = 1'b1; end end {7'b000_0100, 3'b110}: begin if (RV32B == RV32BFull) begin alu_operator_o = ALU_BCOMPRESS; alu_multicycle_o = 1'b1; end end // RV32M instructions, all use the same ALU operation {7'b000_0001, 3'b000}: begin // mul alu_operator_o = ALU_ADD; mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b001}: begin // mulh alu_operator_o = ALU_ADD; mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b010}: begin // mulhsu alu_operator_o = ALU_ADD; mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b011}: begin // mulhu alu_operator_o = ALU_ADD; mult_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b100}: begin // div alu_operator_o = ALU_ADD; div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b101}: begin // divu alu_operator_o = ALU_ADD; div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b110}: begin // rem alu_operator_o = ALU_ADD; div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end {7'b000_0001, 3'b111}: begin // remu alu_operator_o = ALU_ADD; div_sel_o = (RV32M == RV32MNone) ? 1'b0 : 1'b1; end default: ; endcase end end ///////////// // Special // ///////////// OPCODE_MISC_MEM: begin unique case (instr_alu[14:12]) 3'b000: begin // FENCE is treated as a NOP since all memory operations are already strictly ordered. alu_operator_o = ALU_ADD; // nop alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_IMM; end 3'b001: begin // FENCE.I will flush the IF stage, prefetch buffer and ICache if present. if (BranchTargetALU) begin bt_a_mux_sel_o = OP_A_CURRPC; bt_b_mux_sel_o = IMM_B_INCR_PC; end else begin alu_op_a_mux_sel_o = OP_A_CURRPC; alu_op_b_mux_sel_o = OP_B_IMM; imm_b_mux_sel_o = IMM_B_INCR_PC; alu_operator_o = ALU_ADD; end end default: ; endcase end OPCODE_SYSTEM: begin if (instr_alu[14:12] == 3'b000) begin // non CSR related SYSTEM instructions alu_op_a_mux_sel_o = OP_A_REG_A; alu_op_b_mux_sel_o = OP_B_IMM; end else begin // instruction to read/modify CSR alu_op_b_mux_sel_o = OP_B_IMM; imm_a_mux_sel_o = IMM_A_Z; imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm if (instr_alu[14]) begin // rs1 field is used as immediate alu_op_a_mux_sel_o = OP_A_IMM; end else begin alu_op_a_mux_sel_o = OP_A_REG_A; end end end default: ; endcase end // do not enable multdiv in case of illegal instruction exceptions assign mult_en_o = illegal_insn ? 1'b0 : mult_sel_o; assign div_en_o = illegal_insn ? 1'b0 : div_sel_o; // make sure instructions accessing non-available registers in RV32E cause illegal // instruction exceptions assign illegal_insn_o = illegal_insn | illegal_reg_rv32e; // do not propgate regfile write enable if non-available registers are accessed in RV32E assign rf_we_o = rf_we & ~illegal_reg_rv32e; // Not all bits are used assign unused_instr_alu = {instr_alu[19:15],instr_alu[11:7]}; //////////////// // Assertions // //////////////// // Selectors must be known/valid. `ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |-> !$isunknown(instr[14:12])) endmodule // controller