ibex/rtl/ibex_ex_block.sv
Philipp Wagner a25790abf9 [style] Indent module header with two spaces
Both the parameter and the port list in a module header should be
indented with two spaces, according to our style guide.
2021-08-31 15:30:28 +02:00

199 lines
7.3 KiB
Systemverilog

// 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 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,
// 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=RV32MNone
At synthesis time, all the combinational and sequential logic
from the multdiv_i module are eliminated
*/
if (RV32M != RV32MNone) 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 (RV32M == RV32MSlow) 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 (RV32M == RV32MFast || RV32M == RV32MSingleCycle) begin : gen_multdiv_fast
ibex_multdiv_fast #(
.RV32M(RV32M)
) 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