blob: 5e113e0338ad16d8ee50d246c3053efd27f961a3 [file] [log] [blame]
module ibex_alu (
operator_i,
operand_a_i,
operand_b_i,
multdiv_operand_a_i,
multdiv_operand_b_i,
multdiv_en_i,
adder_result_o,
adder_result_ext_o,
result_o,
comparison_result_o,
is_equal_result_o
);
input wire [4:0] operator_i;
input wire [31:0] operand_a_i;
input wire [31:0] operand_b_i;
input wire [32:0] multdiv_operand_a_i;
input wire [32:0] multdiv_operand_b_i;
input wire multdiv_en_i;
output wire [31:0] adder_result_o;
output wire [33:0] adder_result_ext_o;
output reg [31:0] result_o;
output wire comparison_result_o;
output wire is_equal_result_o;
wire [31:0] operand_a_rev;
wire [32:0] operand_b_neg;
generate
genvar k;
for (k = 0; k < 32; k = k + 1) begin : gen_revloop
assign operand_a_rev[k] = operand_a_i[31 - k];
end
endgenerate
reg adder_op_b_negate;
wire [32:0] adder_in_a;
wire [32:0] adder_in_b;
wire [31:0] adder_result;
localparam [4:0] ibex_defines_ALU_EQ = 16;
localparam [4:0] ibex_defines_ALU_GE = 14;
localparam [4:0] ibex_defines_ALU_GEU = 15;
localparam [4:0] ibex_defines_ALU_GT = 12;
localparam [4:0] ibex_defines_ALU_GTU = 13;
localparam [4:0] ibex_defines_ALU_LE = 10;
localparam [4:0] ibex_defines_ALU_LEU = 11;
localparam [4:0] ibex_defines_ALU_LT = 8;
localparam [4:0] ibex_defines_ALU_LTU = 9;
localparam [4:0] ibex_defines_ALU_NE = 17;
localparam [4:0] ibex_defines_ALU_SLET = 20;
localparam [4:0] ibex_defines_ALU_SLETU = 21;
localparam [4:0] ibex_defines_ALU_SLT = 18;
localparam [4:0] ibex_defines_ALU_SLTU = 19;
localparam [4:0] ibex_defines_ALU_SUB = 1;
always @(*) begin
adder_op_b_negate = 1'b0;
case (operator_i)
ibex_defines_ALU_SUB, ibex_defines_ALU_EQ, ibex_defines_ALU_NE, ibex_defines_ALU_GTU, ibex_defines_ALU_GEU, ibex_defines_ALU_LTU, ibex_defines_ALU_LEU, ibex_defines_ALU_GT, ibex_defines_ALU_GE, ibex_defines_ALU_LT, ibex_defines_ALU_LE, ibex_defines_ALU_SLT, ibex_defines_ALU_SLTU, ibex_defines_ALU_SLET, ibex_defines_ALU_SLETU: adder_op_b_negate = 1'b1;
default:
;
endcase
end
assign adder_in_a = (multdiv_en_i ? multdiv_operand_a_i : {operand_a_i, 1'b1});
assign operand_b_neg = {operand_b_i, 1'b0} ^ {33 {adder_op_b_negate}};
assign adder_in_b = (multdiv_en_i ? multdiv_operand_b_i : operand_b_neg);
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
assign adder_result = adder_result_ext_o[32:1];
assign adder_result_o = adder_result;
wire shift_left;
wire shift_arithmetic;
wire [4:0] shift_amt;
wire [31:0] shift_op_a;
wire [31:0] shift_result;
wire [31:0] shift_right_result;
wire [31:0] shift_left_result;
assign shift_amt = operand_b_i[4:0];
localparam [4:0] ibex_defines_ALU_SLL = 7;
assign shift_left = operator_i == ibex_defines_ALU_SLL;
localparam [4:0] ibex_defines_ALU_SRA = 5;
assign shift_arithmetic = operator_i == ibex_defines_ALU_SRA;
assign shift_op_a = (shift_left ? operand_a_rev : operand_a_i);
wire [32:0] shift_op_a_32;
assign shift_op_a_32 = {shift_arithmetic & shift_op_a[31], shift_op_a};
wire signed [32:0] shift_right_result_signed;
assign shift_right_result_signed = $signed(shift_op_a_32) >>> shift_amt[4:0];
assign shift_right_result = shift_right_result_signed[31:0];
generate
genvar j;
for (j = 0; j < 32; j = j + 1) begin : gen_resrevloop
assign shift_left_result[j] = shift_right_result[31 - j];
end
endgenerate
assign shift_result = (shift_left ? shift_left_result : shift_right_result);
wire is_equal;
reg is_greater_equal;
reg cmp_signed;
always @(*) begin
cmp_signed = 1'b0;
case (operator_i)
ibex_defines_ALU_GT, ibex_defines_ALU_GE, ibex_defines_ALU_LT, ibex_defines_ALU_LE, ibex_defines_ALU_SLT, ibex_defines_ALU_SLET: cmp_signed = 1'b1;
default:
;
endcase
end
assign is_equal = adder_result == 32'b00000000000000000000000000000000;
assign is_equal_result_o = is_equal;
always @(*)
if ((operand_a_i[31] ^ operand_b_i[31]) == 1'b0)
is_greater_equal = adder_result[31] == 1'b0;
else
is_greater_equal = operand_a_i[31] ^ cmp_signed;
reg cmp_result;
always @(*) begin
cmp_result = is_equal;
case (operator_i)
ibex_defines_ALU_EQ: cmp_result = is_equal;
ibex_defines_ALU_NE: cmp_result = ~is_equal;
ibex_defines_ALU_GT, ibex_defines_ALU_GTU: cmp_result = is_greater_equal & ~is_equal;
ibex_defines_ALU_GE, ibex_defines_ALU_GEU: cmp_result = is_greater_equal;
ibex_defines_ALU_LT, ibex_defines_ALU_SLT, ibex_defines_ALU_LTU, ibex_defines_ALU_SLTU: cmp_result = ~is_greater_equal;
ibex_defines_ALU_SLET, ibex_defines_ALU_SLETU, ibex_defines_ALU_LE, ibex_defines_ALU_LEU: cmp_result = ~is_greater_equal | is_equal;
default:
;
endcase
end
assign comparison_result_o = cmp_result;
localparam [4:0] ibex_defines_ALU_ADD = 0;
localparam [4:0] ibex_defines_ALU_AND = 4;
localparam [4:0] ibex_defines_ALU_OR = 3;
localparam [4:0] ibex_defines_ALU_SRL = 6;
localparam [4:0] ibex_defines_ALU_XOR = 2;
always @(*) begin
result_o = {32 {1'sb0}};
case (operator_i)
ibex_defines_ALU_AND: result_o = operand_a_i & operand_b_i;
ibex_defines_ALU_OR: result_o = operand_a_i | operand_b_i;
ibex_defines_ALU_XOR: result_o = operand_a_i ^ operand_b_i;
ibex_defines_ALU_ADD, ibex_defines_ALU_SUB: result_o = adder_result;
ibex_defines_ALU_SLL, ibex_defines_ALU_SRL, ibex_defines_ALU_SRA: result_o = shift_result;
ibex_defines_ALU_EQ, ibex_defines_ALU_NE, ibex_defines_ALU_GTU, ibex_defines_ALU_GEU, ibex_defines_ALU_LTU, ibex_defines_ALU_LEU, ibex_defines_ALU_GT, ibex_defines_ALU_GE, ibex_defines_ALU_LT, ibex_defines_ALU_LE, ibex_defines_ALU_SLT, ibex_defines_ALU_SLTU, ibex_defines_ALU_SLET, ibex_defines_ALU_SLETU: result_o = {31'h00000000, cmp_result};
default:
;
endcase
end
endmodule