diff --git a/src/frontend/frontend.sv b/src/frontend/frontend.sv index b9104b92b1e952984a893dcb4d8211b2a083263c..6178aab4cdded77bc47dcfe7c9150a6c9191d165 100644 --- a/src/frontend/frontend.sv +++ b/src/frontend/frontend.sv @@ -136,11 +136,11 @@ module frontend import ariane_pkg::*; #( // unconditional jumps with known target -> immediately resolved assign is_jump[i] = instruction_valid[i] & (rvi_jump[i] | rvc_jump[i]); // unconditional jumps with unknown target -> BTB - assign is_jalr[i] = instruction_valid[i] & ~is_return[i] & ~is_call[i] & (rvi_jalr[i] | rvc_jalr[i] | rvc_jr[i]); + assign is_jalr[i] = instruction_valid[i] & (rvi_jalr[i] | rvc_jalr[i] | rvc_jr[i]); end logic should_stall; - assign should_stall = (stalling_q | (|is_branch) | (|is_return) | (|is_jalr)) & (!resolved_branch_i.valid); + assign should_stall = (stalling_q | (|is_branch) | (|is_jalr)) & (!resolved_branch_i.valid || (resolved_branch_i.cf_type == Jump)); // taken/not taken always_comb begin @@ -150,15 +150,19 @@ module frontend import ariane_pkg::*; #( predict_address = '0; bp_valid = 1'b0; - if (!should_stall) begin + if (replay) begin + stalling_d = 1'b0; + end else if (!stalling_q || (resolved_branch_i.valid && resolved_branch_i.cf_type != Jump)) begin stalling_d = 1'b0; for (int unsigned i = 0; i < INSTR_PER_FETCH; i++) begin - unique case ({is_branch[i] | is_return[i] | is_jalr[i], is_jump[i]}) + cf_type[i] = ariane_pkg::NoCF; + + unique case ({is_branch[i] | is_jalr[i], is_jump[i]}) 2'b00:; 2'b01: begin if (!(|taken_rvi_cf) && !(|taken_rvc_cf)) - predict_address = addr[i] + (taken_rvc_cf[i] ? rvc_imm[i] : rvi_imm[i]); + predict_address = addr[i] + (rvc_jump[i] ? rvc_imm[i] : rvi_imm[i]); taken_rvi_cf[i] = rvi_jump[i]; taken_rvc_cf[i] = rvc_jump[i]; @@ -166,6 +170,9 @@ module frontend import ariane_pkg::*; #( bp_valid = 1'b1; end 2'b10: begin + if (!(|taken_rvi_cf) && !(|taken_rvc_cf)) + predict_address = addr[i] + 'h4; + taken_rvi_cf[i] = 1'b1; taken_rvc_cf[i] = 1'b1; bp_valid = 1'b1; @@ -180,13 +187,13 @@ module frontend import ariane_pkg::*; #( assign is_mispredict = resolved_branch_i.valid & resolved_branch_i.is_mispredict; // Cache interface - assign icache_dreq_o.req = instr_queue_ready & (!should_stall); - assign if_ready = icache_dreq_i.ready & instr_queue_ready; + assign icache_dreq_o.req = instr_queue_ready & (!should_stall | replay); + assign if_ready = icache_dreq_i.ready & instr_queue_ready & (!should_stall); // We need to flush the cache pipeline if: // 1. We mispredicted // 2. Want to flush the whole processor front-end // 3. Need to replay an instruction because the fetch-fifo was full - assign icache_dreq_o.kill_s1 = is_mispredict | flush_i | replay; + assign icache_dreq_o.kill_s1 = is_mispredict | flush_i; // if we have a valid branch-prediction we need to only kill the last cache request // also if we killed the first stage we also need to kill the second stage (inclusive flush) assign icache_dreq_o.kill_s2 = icache_dreq_o.kill_s1 | bp_valid; @@ -220,35 +227,33 @@ module frontend import ariane_pkg::*; #( npc_d = npc_q; end - if (!should_stall) begin - // 0. Branch Prediction - if (bp_valid) begin - fetch_address = predict_address; - npc_d = predict_address; - end - // 1. Default assignment - if (if_ready) npc_d = {fetch_address[riscv::VLEN-1:2], 2'b0} + 'h4; - // 2. Replay instruction fetch - if (replay) npc_d = replay_addr; - // 3. Control flow change request - if (is_mispredict) npc_d = resolved_branch_i.target_address; - // 4. Return from environment call - if (eret_i) npc_d = epc_i; - // 5. Exception/Interrupt - if (ex_valid_i) npc_d = trap_vector_base_i; - // 6. Pipeline Flush because of CSR side effects - // On a pipeline flush start fetching from the next address - // of the instruction in the commit stage - // we came here from a flush request of a CSR instruction or AMO, - // as CSR or AMO instructions do not exist in a compressed form - // we can unconditionally do PC + 4 here - // TODO(zarubaf) This adder can at least be merged with the one in the csr_regfile stage - if (set_pc_commit_i) npc_d = pc_commit_i + {{riscv::VLEN-3{1'b0}}, 3'b100}; - // 7. Debug - // enter debug on a hard-coded base-address - if (set_debug_pc_i) npc_d = ArianeCfg.DmBaseAddress[riscv::VLEN-1:0] + dm::HaltAddress[riscv::VLEN-1:0]; - icache_dreq_o.vaddr = fetch_address; + // 0. Branch Prediction + if (bp_valid) begin + fetch_address = predict_address; + npc_d = predict_address; end + // 1. Default assignment + if (if_ready) npc_d = {fetch_address[riscv::VLEN-1:2], 2'b0} + 'h4; + // 2. Replay instruction fetch + if (replay) npc_d = replay_addr; + // 3. Control flow change request + if (is_mispredict) npc_d = resolved_branch_i.target_address; + // 4. Return from environment call + if (eret_i) npc_d = epc_i; + // 5. Exception/Interrupt + if (ex_valid_i) npc_d = trap_vector_base_i; + // 6. Pipeline Flush because of CSR side effects + // On a pipeline flush start fetching from the next address + // of the instruction in the commit stage + // we came here from a flush request of a CSR instruction or AMO, + // as CSR or AMO instructions do not exist in a compressed form + // we can unconditionally do PC + 4 here + // TODO(zarubaf) This adder can at least be merged with the one in the csr_regfile stage + if (set_pc_commit_i) npc_d = pc_commit_i + {{riscv::VLEN-3{1'b0}}, 3'b100}; + // 7. Debug + // enter debug on a hard-coded base-address + if (set_debug_pc_i) npc_d = ArianeCfg.DmBaseAddress[riscv::VLEN-1:0] + dm::HaltAddress[riscv::VLEN-1:0]; + icache_dreq_o.vaddr = fetch_address; end logic [FETCH_WIDTH-1:0] icache_data; @@ -281,7 +286,11 @@ module frontend import ariane_pkg::*; #( end else icache_ex_valid_q <= ariane_pkg::FE_NONE; // save the uppermost prediction end - stalling_q <= stalling_d; + + if (flush_i) + stalling_q <= 1'b0; + else + stalling_q <= stalling_d; end end