diff --git a/src/branch_engine.sv b/src/branch_engine.sv deleted file mode 100644 index fcf7467f9..000000000 --- a/src/branch_engine.sv +++ /dev/null @@ -1,128 +0,0 @@ -// Author: Florian Zaruba, ETH Zurich -// Date: 09.05.2017 -// Description: Branch target calculation and comparison -// -// -// Copyright (C) 2017 ETH Zurich, University of Bologna -// All rights reserved. -// -// This code is under development and not yet released to the public. -// Until it is released, the code is under the copyright of ETH Zurich and -// the University of Bologna, and may contain confidential and/or unpublished -// work. Any reuse/redistribution is strictly forbidden without written -// permission from ETH Zurich. -// -// Bug fixes and contributions will eventually be released under the -// SolderPad open hardware license in the context of the PULP platform -// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the -// University of Bologna. -// -import ariane_pkg::*; - -module branch_engine ( - input fu_op operator_i, - input logic [63:0] operand_a_i, - input logic [63:0] operand_b_i, - input logic [63:0] operand_c_i, - input logic [63:0] imm_i, - input logic [63:0] pc_i, - 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 valid_i, - - input branchpredict_sbe branch_predict_i, // this is the address we predicted - output branchpredict resolved_branch_o, // this is the actual address we are targeting - output logic resolve_branch_o, // to ID to clear that we resolved the branch and we can - // accept new entries to the scoreboard - output exception branch_ex_o // branch exception out -); - logic [63:0] target_address; - logic [63:0] next_pc; - logic comparison_result; // result of comparison - logic sgn; // sign extend - - 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: comparison_result = ($signed({sgn & operand_a_i[63], operand_a_i}) < $signed({sgn & operand_b_i[63], operand_b_i})); - GES: 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 - target_address = 64'b0; - resolved_branch_o.pc = 64'b0; - resolved_branch_o.target_address = 64'b0; - resolved_branch_o.is_taken = 1'b0; - resolved_branch_o.valid = valid_i; - resolved_branch_o.is_mispredict = 1'b0; - resolved_branch_o.is_lower_16 = 1'b0; - resolve_branch_o = 1'b0; - // calculate next PC, depending on whether the instruction is compressed or not this may be different - next_pc = pc_i + ((is_compressed_instr_i) ? 64'h2 : 64'h4); - // calculate target address simple 64 bit addition - target_address = $unsigned($signed(operand_c_i) + $signed(imm_i)); - - if (valid_i) begin - // save PC - we need this to get the target row in the branch target buffer - // we play this trick with the branch instruction which wraps a byte boundary: - // |---------- Place the prediction on this PC - // \/ - // ____________________________________________________ - // |branch [15:0] | branch[31:16] | compressed 1[15:0] | - // |____________________________________________________ - // This will relief the prefetcher to re-fetch partially fetched unaligned branch instructions e.g.: - // we don't have a back arch between prefetcher and decoder/instruction FIFO. - resolved_branch_o.pc = (is_compressed_instr_i || pc_i[1] == 1'b0) ? pc_i : ({pc_i[63:2], 2'b0} + 64'h4); - // save if the branch instruction was in the lower 16 bit of the instruction word - // the first case is a compressed instruction which is in slot 0 - // 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; - // 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 - // TODO in case of branch which is not taken it is not necessary to check for the address - if (target_address != branch_predict_i.predict_address // we mis-predicted the address of the branch - || branch_predict_i.predict_taken != comparison_result // we mis-predicted the outcome of the branch - || branch_predict_i.valid == 1'b0 // this means branch-prediction thought it was no - // branch but in reality it was one - ) begin - resolved_branch_o.is_mispredict = 1'b1; - end - end - // to resolve the branch in ID -> only do this if this was indeed a branch (hence vald_i is asserted) - resolve_branch_o = 1'b1; - // the other case would be that this instruction was no branch but branch prediction thought that it was one - // this is essentially also a mis-predict - end else if (fu_valid_i && branch_predict_i.valid) begin - // re-set the branch to the next PC - resolved_branch_o.is_mispredict = 1'b1; - resolved_branch_o.target_address = next_pc; - end - end - // use ALU exception signal for storing instruction fetch exceptions if - // the target address is not aligned to a 2 byte boundary - always_comb begin : exception_handling - branch_ex_o.cause = INSTR_ADDR_MISALIGNED; - branch_ex_o.valid = 1'b0; - branch_ex_o.tval = pc_i; - // only throw exception if this is indeed a branch - if (valid_i && target_address[0] != 1'b0) - branch_ex_o.valid = 1'b1; - end -endmodule \ No newline at end of file diff --git a/src/ex_stage.sv b/src/ex_stage.sv index a0be87cc6..13336f037 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -111,7 +111,7 @@ module ex_stage #( // -------------------- // Branch Engine // -------------------- - branch_engine branch_engine_i ( + branch_unit branch_unit_i ( .fu_valid_i ( alu_valid_i & lsu_valid_i & csr_valid_i ), .valid_i ( branch_valid_i ), .branch_ex_o ( alu_exception_o ), // we use the ALU exception WB for the branch exception diff --git a/src/lsu.sv b/src/lsu.sv index 82efbfbc1..d327b3b26 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -81,7 +81,6 @@ module lsu #( output exception lsu_exception_o // to WB, signal exception status LD/ST exception ); - mem_if ptw_if(clk_i); // byte enable based on operation to perform // data is misaligned logic data_misaligned; @@ -128,7 +127,7 @@ module lsu #( // ------------------------------ // Address Generation Unit (AGU) // ------------------------------ - assign vaddr_i = imm_i + operand_a_i; + assign vaddr_i = $signed(imm_i) + $signed(operand_a_i); // --------------- // Memory Arbiter @@ -247,8 +246,7 @@ module lsu #( always_comb begin : address_checker page_offset_match = 1'b0; // check if the LSBs are identical and the entry is valid - if ((vaddr[11:3] == st_buffer_paddr[11:3]) & st_buffer_valid) begin - // TODO: implement propperly, this is overly pessimistic + if ((vaddr[11:3] == st_buffer_paddr[11:3]) && st_buffer_valid) begin page_offset_match = 1'b1; end end