// 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 /** * Execution stage * * Execution block: Hosts ALU and MUL/DIV unit */ module ibex_ex_block #( parameter bit RV32M = 1, parameter ibex_pkg::rv32b_e RV32B = ibex_pkg::RV32BNone, parameter bit BranchTargetALU = 0, parameter MultiplierImplementation = "fast" ) ( input logic clk_i, input logic rst_ni, // ALU input ibex_pkg::alu_op_e alu_operator_i, input logic [31:0] alu_operand_a_i, input logic [31:0] alu_operand_b_i, input logic alu_instr_first_cycle_i, // Branch Target ALU // All of these signals are unusued when BranchTargetALU == 0 input logic [31:0] bt_a_operand_i, input logic [31:0] bt_b_operand_i, // Multiplier/Divider input ibex_pkg::md_op_e multdiv_operator_i, input logic mult_en_i, // dynamic enable signal, for FSM control input logic div_en_i, // dynamic enable signal, for FSM control input logic mult_sel_i, // static decoder output, for data muxes input logic div_sel_i, // static decoder output, for data muxes input logic [1:0] multdiv_signed_mode_i, input logic [31:0] multdiv_operand_a_i, input logic [31:0] multdiv_operand_b_i, input logic multdiv_ready_id_i, input logic data_ind_timing_i, // intermediate val reg output logic [1:0] imd_val_we_o, output logic [33:0] imd_val_d_o[2], input logic [33:0] imd_val_q_i[2], // Outputs output logic [31:0] alu_adder_result_ex_o, // to LSU output logic [31:0] result_ex_o, output logic [31:0] branch_target_o, // to IF output logic branch_decision_o, // to ID output logic ex_valid_o // EX has valid output ); import ibex_pkg::*; logic [31:0] alu_result, multdiv_result; logic [32:0] multdiv_alu_operand_b, multdiv_alu_operand_a; logic [33:0] alu_adder_result_ext; logic alu_cmp_result, alu_is_equal_result; logic multdiv_valid; logic multdiv_sel; logic [31:0] alu_imd_val_q[2]; logic [31:0] alu_imd_val_d[2]; logic [ 1:0] alu_imd_val_we; logic [33:0] multdiv_imd_val_d[2]; logic [ 1:0] multdiv_imd_val_we; /* The multdiv_i output is never selected if RV32M=0 At synthesis time, all the combinational and sequential logic from the multdiv_i module are eliminated */ if (RV32M) begin : gen_multdiv_m assign multdiv_sel = mult_sel_i | div_sel_i; end else begin : gen_multdiv_no_m assign multdiv_sel = 1'b0; end // Intermediate Value Register Mux assign imd_val_d_o[0] = multdiv_sel ? multdiv_imd_val_d[0] : {2'b0, alu_imd_val_d[0]}; assign imd_val_d_o[1] = multdiv_sel ? multdiv_imd_val_d[1] : {2'b0, alu_imd_val_d[1]}; assign imd_val_we_o = multdiv_sel ? multdiv_imd_val_we : alu_imd_val_we; assign alu_imd_val_q = '{imd_val_q_i[0][31:0], imd_val_q_i[1][31:0]}; assign result_ex_o = multdiv_sel ? multdiv_result : alu_result; // branch handling assign branch_decision_o = alu_cmp_result; if (BranchTargetALU) begin : g_branch_target_alu logic [32:0] bt_alu_result; logic unused_bt_carry; assign bt_alu_result = bt_a_operand_i + bt_b_operand_i; assign unused_bt_carry = bt_alu_result[32]; assign branch_target_o = bt_alu_result[31:0]; end else begin : g_no_branch_target_alu // Unused bt_operand signals cause lint errors, this avoids them logic [31:0] unused_bt_a_operand, unused_bt_b_operand; assign unused_bt_a_operand = bt_a_operand_i; assign unused_bt_b_operand = bt_b_operand_i; assign branch_target_o = alu_adder_result_ex_o; end ///////// // ALU // ///////// ibex_alu #( .RV32B(RV32B) ) alu_i ( .operator_i ( alu_operator_i ), .operand_a_i ( alu_operand_a_i ), .operand_b_i ( alu_operand_b_i ), .instr_first_cycle_i ( alu_instr_first_cycle_i ), .imd_val_q_i ( alu_imd_val_q ), .imd_val_we_o ( alu_imd_val_we ), .imd_val_d_o ( alu_imd_val_d ), .multdiv_operand_a_i ( multdiv_alu_operand_a ), .multdiv_operand_b_i ( multdiv_alu_operand_b ), .multdiv_sel_i ( multdiv_sel ), .adder_result_o ( alu_adder_result_ex_o ), .adder_result_ext_o ( alu_adder_result_ext ), .result_o ( alu_result ), .comparison_result_o ( alu_cmp_result ), .is_equal_result_o ( alu_is_equal_result ) ); //////////////// // Multiplier // //////////////// if (MultiplierImplementation == "slow") begin : gen_multdiv_slow ibex_multdiv_slow multdiv_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .mult_en_i ( mult_en_i ), .div_en_i ( div_en_i ), .mult_sel_i ( mult_sel_i ), .div_sel_i ( div_sel_i ), .operator_i ( multdiv_operator_i ), .signed_mode_i ( multdiv_signed_mode_i ), .op_a_i ( multdiv_operand_a_i ), .op_b_i ( multdiv_operand_b_i ), .alu_adder_ext_i ( alu_adder_result_ext ), .alu_adder_i ( alu_adder_result_ex_o ), .equal_to_zero_i ( alu_is_equal_result ), .data_ind_timing_i ( data_ind_timing_i ), .valid_o ( multdiv_valid ), .alu_operand_a_o ( multdiv_alu_operand_a ), .alu_operand_b_o ( multdiv_alu_operand_b ), .imd_val_q_i ( imd_val_q_i ), .imd_val_d_o ( multdiv_imd_val_d ), .imd_val_we_o ( multdiv_imd_val_we ), .multdiv_ready_id_i ( multdiv_ready_id_i ), .multdiv_result_o ( multdiv_result ) ); end else if (MultiplierImplementation == "fast") begin : gen_multdiv_fast ibex_multdiv_fast # ( .SingleCycleMultiply (0) ) multdiv_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .mult_en_i ( mult_en_i ), .div_en_i ( div_en_i ), .mult_sel_i ( mult_sel_i ), .div_sel_i ( div_sel_i ), .operator_i ( multdiv_operator_i ), .signed_mode_i ( multdiv_signed_mode_i ), .op_a_i ( multdiv_operand_a_i ), .op_b_i ( multdiv_operand_b_i ), .alu_operand_a_o ( multdiv_alu_operand_a ), .alu_operand_b_o ( multdiv_alu_operand_b ), .alu_adder_ext_i ( alu_adder_result_ext ), .alu_adder_i ( alu_adder_result_ex_o ), .equal_to_zero_i ( alu_is_equal_result ), .data_ind_timing_i ( data_ind_timing_i ), .imd_val_q_i ( imd_val_q_i ), .imd_val_d_o ( multdiv_imd_val_d ), .imd_val_we_o ( multdiv_imd_val_we ), .multdiv_ready_id_i ( multdiv_ready_id_i ), .valid_o ( multdiv_valid ), .multdiv_result_o ( multdiv_result ) ); end else if (MultiplierImplementation == "single-cycle") begin: gen_multdiv_single_cycle ibex_multdiv_fast #( .SingleCycleMultiply(1) ) multdiv_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .mult_en_i ( mult_en_i ), .div_en_i ( div_en_i ), .mult_sel_i ( mult_sel_i ), .div_sel_i ( div_sel_i ), .operator_i ( multdiv_operator_i ), .signed_mode_i ( multdiv_signed_mode_i ), .op_a_i ( multdiv_operand_a_i ), .op_b_i ( multdiv_operand_b_i ), .alu_operand_a_o ( multdiv_alu_operand_a ), .alu_operand_b_o ( multdiv_alu_operand_b ), .alu_adder_ext_i ( alu_adder_result_ext ), .alu_adder_i ( alu_adder_result_ex_o ), .equal_to_zero_i ( alu_is_equal_result ), .data_ind_timing_i ( data_ind_timing_i ), .imd_val_q_i ( imd_val_q_i ), .imd_val_d_o ( multdiv_imd_val_d ), .imd_val_we_o ( multdiv_imd_val_we ), .multdiv_ready_id_i ( multdiv_ready_id_i ), .valid_o ( multdiv_valid ), .multdiv_result_o ( multdiv_result ) ); end // Multiplier/divider may require multiple cycles. The ALU output is valid in the same cycle // unless the intermediate result register is being written (which indicates this isn't the // final cycle of ALU operation). assign ex_valid_o = multdiv_sel ? multdiv_valid : ~(|alu_imd_val_we); endmodule