diff --git a/src/alu.sv b/src/alu.sv index bdc33b87b..20be524c7 100644 --- a/src/alu.sv +++ b/src/alu.sv @@ -27,6 +27,7 @@ module alu input logic [63:0] operand_a_i, input logic [63:0] operand_b_i, output logic [63:0] result_o, + output logic alu_branch_res_o, output logic alu_valid_o, output logic alu_ready_o, output logic [TRANS_ID_BITS-1:0] alu_trans_id_o @@ -41,6 +42,8 @@ module alu logic [31:0] operand_a_rev32; logic [64:0] operand_b_neg; logic [65:0] adder_result_ext_o; + logic less; // handles both signed and unsigned forms + // bit reverse operand_a for left shifts and bit counting generate genvar k; @@ -55,6 +58,7 @@ module alu // Adder // ------ logic adder_op_b_negate; + logic adder_z_flag; logic [64:0] adder_in_a, adder_in_b; logic [63:0] adder_result; @@ -63,6 +67,7 @@ module alu unique case (operator_i) // ADDER OPS + EQ, NE, SUB, SUBW: adder_op_b_negate = 1'b1; default: ; @@ -79,6 +84,20 @@ module alu // actual adder assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b); assign adder_result = adder_result_ext_o[64:1]; + assign adder_z_flag = ~|adder_result; + + // get the right branch comparison result + always_comb begin : branch_resolve + // set comparison by default + alu_branch_res_o = 1'b1; + case (operator_i) + EQ: alu_branch_res_o = adder_z_flag; + NE: alu_branch_res_o = ~adder_z_flag; + LTS, LTU: alu_branch_res_o = less; + GES, GEU: alu_branch_res_o = ~less; + default: alu_branch_res_o = 1'b1; + endcase + end // --------- // Shifts @@ -138,14 +157,14 @@ module alu // ------------ // Comparisons // ------------ - logic less; // handles both signed and unsigned forms - always_comb begin logic sgn; sgn = 1'b0; - if (operator_i == SLTS) + if ((operator_i == SLTS) | + (operator_i == LTS) | + (operator_i == GES)) sgn = 1'b1; less = ($signed({sgn & operand_a_i[63], operand_a_i}) < $signed({sgn & operand_b_i[63], operand_b_i})); diff --git a/src/ariane.sv b/src/ariane.sv index 83e851ce7..54acda021 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -123,6 +123,7 @@ module ariane #( logic [TRANS_ID_BITS-1:0] alu_trans_id_ex_id; logic alu_valid_ex_id; logic [63:0] alu_result_ex_id; + logic alu_branch_res_ex_id; exception_t alu_exception_ex_id; // Branches and Jumps logic branch_ready_ex_id; @@ -421,6 +422,7 @@ module ariane #( .alu_result_o ( alu_result_ex_id ), .alu_trans_id_o ( alu_trans_id_ex_id ), .alu_valid_o ( alu_valid_ex_id ), + .alu_branch_res_o ( alu_branch_res_ex_id ), .alu_exception_o ( ), // Branches and Jumps .branch_ready_o ( branch_ready_ex_id ), diff --git a/src/branch_unit.sv b/src/branch_unit.sv index 896dbbd32..9f4816f97 100644 --- a/src/branch_unit.sv +++ b/src/branch_unit.sv @@ -24,6 +24,7 @@ module branch_unit ( input logic is_compressed_instr_i, input logic fu_valid_i, // any functional unit is valid, check that there is no accidental mis-predict input logic branch_valid_i, + input logic branch_comp_res_i, // branch comparison result from ALU output logic branch_ready_o, output logic branch_valid_o, output logic [63:0] branch_result_o, @@ -37,32 +38,11 @@ module branch_unit ( ); logic [63:0] target_address; logic [63:0] next_pc; - logic comparison_result; // result of comparison - logic sgn; // sign extend // branches are single cycle at the moment, feed-through the control signals assign branch_trans_id_o = trans_id_i; assign branch_valid_o = branch_valid_i; assign branch_ready_o = 1'b1; // we are always ready - always_comb begin : branch_resolve - // by default e.g.: when this is a jump, the branch is taken - // so set the comparison result to 1 - comparison_result = 1'b1; - // sign switch - sgn = 1'b1; - // if this is an unsigned operation clear the sign bit - // this should ease data-path extraction - if (operator_i inside {LTU, GEU}) - sgn = 1'b0; - // get the right comparison result - case (operator_i) - EQ: comparison_result = operand_a_i == operand_b_i; - NE: comparison_result = operand_a_i != operand_b_i; - LTS, LTU: comparison_result = ($signed({sgn & operand_a_i[63], operand_a_i}) < $signed({sgn & operand_b_i[63], operand_b_i})); - GES, GEU: comparison_result = ($signed({sgn & operand_a_i[63], operand_a_i}) >= $signed({sgn & operand_b_i[63], operand_b_i})); - default: comparison_result = 1'b1; - endcase - end // here we handle the various possibilities of mis-predicts always_comb begin : mispredict_handler // set the jump base, for JALR we need to look at the register, for all other control flow instructions we can take the current PC @@ -104,15 +84,15 @@ module branch_unit ( // the other case is a misaligned uncompressed instruction which we only predict in the next cycle (see notes above) resolved_branch_o.is_lower_16 = (is_compressed_instr_i && pc_i[1] == 1'b0) || (!is_compressed_instr_i && pc_i[1] == 1'b1); // write target address which goes to pc gen - resolved_branch_o.target_address = (comparison_result) ? target_address : next_pc; - resolved_branch_o.is_taken = comparison_result; + resolved_branch_o.target_address = (branch_comp_res_i) ? target_address : next_pc; + resolved_branch_o.is_taken = branch_comp_res_i; // we've detected a branch in ID with the following parameters // we mis-predicted e.g.: the predicted address is unequal to the actual address if (target_address[0] == 1'b0) begin // we've got a valid branch prediction if (branch_predict_i.valid) begin // if the outcome doesn't match we've got a mis-predict - if (branch_predict_i.predict_taken != comparison_result) begin + if (branch_predict_i.predict_taken != branch_comp_res_i) begin resolved_branch_o.is_mispredict = 1'b1; end // check if the address of the predict taken branch is correct @@ -122,7 +102,7 @@ module branch_unit ( // branch-prediction didn't do anything (e.g.: it fetched PC + 2/4), so if this branch is taken // we also have a mis-predict end else begin - if (comparison_result) begin + if (branch_comp_res_i) begin resolved_branch_o.is_mispredict = 1'b1; end end diff --git a/src/ex_stage.sv b/src/ex_stage.sv index 88a5a0013..befaf17ed 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -38,6 +38,7 @@ module ex_stage #( output logic alu_ready_o, // FU is ready input logic alu_valid_i, // Output is valid output logic alu_valid_o, // ALU result is valid + output logic alu_branch_res_o, // Branch comparison result output logic [63:0] alu_result_o, output logic [TRANS_ID_BITS-1:0] alu_trans_id_o, // ID of scoreboard entry at which to write back output exception_t alu_exception_o, @@ -127,6 +128,7 @@ module ex_stage #( // -------------------- branch_unit branch_unit_i ( .fu_valid_i ( alu_valid_i || lsu_valid_i || csr_valid_i || mult_valid_i), // any functional unit is valid, check that there is no accidental mis-predict + .branch_comp_res_i ( alu_branch_res_o), .* );