mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 05:37:16 -04:00
commit
c74bb21d21
4 changed files with 31 additions and 28 deletions
25
src/alu.sv
25
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}));
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
.*
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue