|
| 1 | +#include "SimpleBranchPred.hpp" |
| 2 | + |
| 3 | +/* |
| 4 | + * The algorithm used for prediction / update is as follows: |
| 5 | + * Prediction: |
| 6 | + * - look up BHT to determine if the branch is predicted taken or not |
| 7 | + * using 2-bit saturated counter |
| 8 | + * - value 3: strongly taken |
| 9 | + * - value 2: weakly taken |
| 10 | + * - value 1: weakly not taken |
| 11 | + * - value 0: strongly not taken |
| 12 | + * - look up BTB to see if an entry exists for the input fetch pc |
| 13 | + * - if present in BTB and predicted taken, BTB entry is used to determine |
| 14 | + * prediction branch idx and predicted_PC |
| 15 | + * - if present in BTB but predicted not taken, BTB entry is used to determine |
| 16 | + * prediction branch idx, while predicted_PC is the fall through addr |
| 17 | + * - if not present in BTB entry, prediction branch idx is the last instr of |
| 18 | + * the FetchPacket, while predicted PC is the fall through addr. Also, create |
| 19 | + * a new BTB entry |
| 20 | + * Update: |
| 21 | + * - a valid BTB entry must be present for fetch PC |
| 22 | + * - TBD |
| 23 | + * |
| 24 | + */ |
| 25 | +namespace olympia |
| 26 | +{ |
| 27 | +namespace BranchPredictor |
| 28 | +{ |
| 29 | + |
| 30 | + void SimpleBranchPredictor::updatePredictor(const DefaultUpdate & update) { |
| 31 | + |
| 32 | + sparta_assert(branch_target_buffer_.find(update.fetch_PC) != branch_target_buffer_.end()); |
| 33 | + branch_target_buffer_[update.fetch_PC].branch_idx = update.branch_idx; |
| 34 | + if (update.actually_taken) { |
| 35 | + branch_history_table_[update.fetch_PC] = |
| 36 | + (branch_history_table_[update.fetch_PC] == 3) ? 3 : |
| 37 | + branch_history_table_[update.fetch_PC] + 1; |
| 38 | + branch_target_buffer_[update.fetch_PC].predicted_PC = update.corrected_PC; |
| 39 | + } else { |
| 40 | + branch_history_table_[update.fetch_PC] = |
| 41 | + (branch_history_table_[update.fetch_PC] == 0) ? 0 : |
| 42 | + branch_history_table_[update.fetch_PC] - 1; |
| 43 | + } |
| 44 | + } |
| 45 | + |
| 46 | + DefaultPrediction SimpleBranchPredictor::getPrediction(const DefaultInput & input) { |
| 47 | + bool predictTaken = false; |
| 48 | + if (branch_history_table_.find(input.fetch_PC) != branch_history_table_.end()) { |
| 49 | + predictTaken = (branch_history_table_[input.fetch_PC] > 1); |
| 50 | + } else { |
| 51 | + // add a new entry to BHT, biased towards not taken |
| 52 | + branch_history_table_.insert(std::pair<uint64_t, uint8_t>(input.fetch_PC, 1)); |
| 53 | + } |
| 54 | + |
| 55 | + DefaultPrediction prediction; |
| 56 | + if (branch_target_buffer_.find(input.fetch_PC) != branch_target_buffer_.end()) { |
| 57 | + // BTB hit |
| 58 | + const BTBEntry & btb_entry = branch_target_buffer_[input.fetch_PC]; |
| 59 | + prediction.branch_idx = btb_entry.branch_idx; |
| 60 | + if (predictTaken) { |
| 61 | + prediction.predicted_PC = btb_entry.predicted_PC; |
| 62 | + } else { |
| 63 | + // fall through address |
| 64 | + prediction.predicted_PC = input.fetch_PC + prediction.branch_idx + BranchPredictorIF::bytes_per_inst; |
| 65 | + } |
| 66 | + } else { |
| 67 | + // BTB miss |
| 68 | + prediction.branch_idx = max_fetch_insts_; |
| 69 | + prediction.predicted_PC = input.fetch_PC + max_fetch_insts_ * bytes_per_inst; |
| 70 | + // add new entry to BTB |
| 71 | + branch_target_buffer_.insert(std::pair<uint64_t,BTBEntry>( |
| 72 | + input.fetch_PC, BTBEntry(prediction.branch_idx, prediction.predicted_PC))); |
| 73 | + } |
| 74 | + |
| 75 | + return prediction; |
| 76 | + } |
| 77 | + |
| 78 | +} // namespace BranchPredictor |
| 79 | +} // namespace olympia |
0 commit comments