Skip to content

Branch prediction unit implementation #240

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions core/BPTypes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

namespace olympia
{
class PredictionInput
{
public:
uint64_t PC;
uint8_t instType;
};

class PredictionOutput
{
public:
bool predDirection;
uint64_t predPC;
};

class UpdateInput
{
public:
uint64_t instrPC;
bool correctedDirection;
uint64_t correctedPC;
};

enum class branchType {
CONDITIONAL_BRANCH,
JMP,
RET
};

}
40 changes: 40 additions & 0 deletions core/BPU.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "BPU.hpp"
#include "BPTypes.hpp"

#include <iostream>

namespace olympia
{
BPU::name = "bpu";
BPU::BPU(sparta::TreeNode* node, BPUParameterSet* p) :
sparta::Unit(node),
ghr_size_(p->ghr_size)

{
in_fetch_prediction_credits_.createConsumerHandler(
CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionCredits_, uint32_t));

in_fetch_prediction_req_.createConsumerHandler(
CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionInput_, PredictionInput));

}
void BPU::receivePredictionCredits_(uint32_t credit) {
std::cout << credit << std::endl;
}

void BPU::recievePredictionInput(PredictionInput) {
std::cout << "hello" << std::endl;
}

void BPU::updateGHRTaken() {
ghr_ = ghr_ << 1;
ghr_ = ghr_ | 0b1;
}

void BPU::updateGHRNotTaken() {
ghr_ = ghr_ << 1;
ghr_ = ghr_ & 0b0;
}
}


78 changes: 78 additions & 0 deletions core/BPU.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

#include "sparta/simulation/Unit.hpp"
#include "sparta/simulation/ParameterSet.hpp"
#include "sparta/ports/DataPort.hpp"
#include "sparta/ports/SignalPort.hpp"

#include "BPTypes.hpp"

#include <climits>
#include <map>
#include <stack>

namespace olympia
{
class BPU : public sparta::Unit
{
public:
class BPUParameterSet : public sparta::ParameterSet
{
public:
BPUParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) {}

// Parameters for the Branch Prediction Unit
PARAMETER(uint32_t, ghr_size, 1024, "Number of history bits in GHR");


};
static const char name[];
BPU(sparta::TreeNode* n, sparta::ParameterSet* p);

private:
void receivePredictionCredits_(uint32_t);
void recievePredictionInput(PredictionInput);

// update GHR when last branch is taken
void updateGHRTaken();
// update GHR when last branch is not taken
void updateGHRNotTaken();

// Number of history bits in GHR
uint32_t ghr_size_;

// Global History Register(GHR)
uint32_t ghr_ = 0;;

// input ports
// verify cycle delay required
sparta::DataInPort<uint32_t> in_fetch_prediction_credits_ {&unit_port_set_,
"in_fetch_prediction_credits", 0};

// verify cycle delay required
sparta::DataInPort<PredictionInput> in_fetch_prediction_req_ {&unit_port_set_,
"in_fetch_prediction_req", 0};

// input port to receieve update input


// output ports
// verify cycle delay required
sparta::DataOutPort<PredictionOutput> out_fetch_prediction_res_ {&unit_port_set_,
"out_fetch_prediction_res", 0};


// counters
sparta::Counter pred_req_num_ {getStatisticSet(), "pred_req_num",
"Number of prediction requests made",
sparta::Counter::COUNT_NORMAL};

sparta::Counter mispred_num_ {getStatisticSet(), "mispred_num",
"Number of mispredictions",
sparta::Counter::COUNT_NORMAL};

sparta::StatisticDef mispred_ratio_ {getStatisticSet(), "misprediction ratio",
"misprediction/total_prediction", getStatisticSet(),
"pred_req_num/mispred_num"};
};
}
120 changes: 120 additions & 0 deletions core/BasePredictor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#include "BasePredictor.hpp"

namespace olympia
{
// Pattern History Table
void PatternHistoryTable::incrementCounter(uint32_t idx) {
if(pattern_history_table_.at(idx) == ctr_bits_val_) {
return;
}
else {
pattern_history_table_.at(idx)++;
}
}

void PatternHistoryTable::decrementCounter(uint32_t idx) {
if(pattern_history_table_.at(idx) == 0) {
return;
}
else {
pattern_history_table_.at(idx)--;
}
}

uint8_t PatternHistoryTable::getPrediction(uint32_t idx) {
return pattern_history_table_.at(idx);
}

// Branch Target Buffer
bool BranchTargetBuffer::isHit(uint64_t PC) {
if(branch_target_buffer_.count(PC)) {
return true;
}
else {
return false;
}
}


uint64_t BranchTargetBuffer::getPredictedPC(uint64_t PC) {
if(branch_target_buffer_.count(PC)) {
return branch_target_buffer_[PC];
}
else {
return 0; // recheck what to return in this condition
}

}

bool BranchTargetBuffer::addEntry(uint64_t PC, uint64_t targetPC) {
if(branch_target_buffer_.size() == btb_size_) {
return false;
}
else {
branch_target_buffer_.insert(std::pair<uint64_t, uint64_t>(PC, targetPC) );
return true;
}
}

bool BranchTargetBuffer::removeEntry(uint64_t PC) {
if(branch_target_buffer_.count(PC)) {
branch_target_buffer_.erase(PC);
return true;
}
else {
return false;
}
}

// Return Address Stack
bool ReturnAddressStack::pushAddress(uint64_t address) {
if(return_address_stack_.size() == ras_size_) {
return false;
}
else {
return_address_stack_.push(address);
return true;
}
}

uint64_t ReturnAddressStack::popAddress() {
if(return_address_stack_.size() == 0) {
return 0; // recheck what to return in this condition
}
else {
uint64_t address_ = return_address_stack_.top();
return_address_stack_.pop();
return address_;
}
}

// BasePredictor
void BasePredictor::handlePredictionReq(PredictionInput predIn) {
if(predIn.instType == branchType.JMP) {
handleJMP(predIn);
}
else if(predIn.instType == branchType.RET ||
predIn.instType == branchType.CONDITIONAL_BRANCH) {
// make prediction
// event to send prediction to fetch
}
}

void BasePredictor::handleJMP(PredictionInput predInput) {
// push PC to RAS
returnAddressStack.pushAddress(predInput.PC);

// PC hit on BTB?
if(branchTargetBuffer.isHit(predInput.PC)) {
// event to send PC
}
else {
// allocate entry in BTB
}

}

void BasePredictor::handleRET(PredictionInput predInput);
void BasePredictor::handleBRANCH(PredictionInput predInput);

}
83 changes: 83 additions & 0 deletions core/BasePredictor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#pragma once

#include <map>
#include "BPTypes.hpp"

namespace olympia
{
class PatternHistoryTable
{
public:
PatternHistoryTable(uint32_t pht_size, uint8_t ctr_bits) :
pht_size_(pht_size), ctr_bits_(ctr_bits)
{
ctr_bits_val_ = pow(2, ctr_bits_);
}

// To increment and decrement within set bounds of ctr_bits
void incrementCounter(uint32_t idx);
void decrementCounter(uint32_t idx);
uint8_t getPrediction(uint32_t idx);

private:
const uint32_t pht_size_;
const uint8_t ctr_bits_;
const uint8_t ctr_bits_val_;

std::map<uint64_t, uint8_t> pattern_history_table_;

};

class BranchTargetBuffer
{
public:
BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {}

bool isHit(uint64_t PC);
uint64_t getPredictedPC(uint64_t PC);
bool addEntry(uint64_t PC, uint64_t targetPC);
bool removeEntry(uint64_t PC);

private:
const uint32_t btb_size_;
std::map <uint64_t, uint64_t> branch_target_buffer_;
};

class ReturnAddressStack
{
public:
ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {}

// To bound the size of RAS
bool pushAddress(uint64_t address);
uint64_t popAddress();

private:
const uint32_t ras_size_;
std::stack<uint64_t> return_address_stack_;

};

class BasePredictor
{
public:
BasePredictor(uint32_t pht_size, uint8_t ctr_bits,
uint32_t btb_size, uint32_t ras_size) :
patternHistoryTable(pht_size, ctr_bits),
branchTargetBuffer(bht_size),
returnAddressStack(ras_size);
{}

PatternHistoryTable patternHistoryTable;
BranchTargetBuffer branchTargetBuffer;
ReturnAddressStack returnAddressStack;

void receivedPredictionReq();
PredictionOutput makePrediction(PredictionInput predInput);
void handleJMP(PredictionInput predInput);
void handleRET(PredictionInput predInput);
void handleBRANCH(PredictionInput predInput);

};
}

1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_library(core
SimpleBranchPred.cpp
ICache.cpp
Fetch.cpp
BPU.cpp
Decode.cpp
VectorUopGenerator.cpp
Rename.cpp
Expand Down
5 changes: 5 additions & 0 deletions core/CPUFactories.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "Core.hpp"
#include "ICache.hpp"
#include "Fetch.hpp"
#include "BPU.hpp"
#include "Decode.hpp"
#include "VectorUopGenerator.hpp"
#include "Rename.hpp"
Expand Down Expand Up @@ -49,6 +50,10 @@ namespace olympia{
sparta::ResourceFactory<olympia::Fetch,
olympia::Fetch::FetchParameterSet> fetch_rf;

//! \brief Resource Factory to build a BPU Unit
sparta::ResourceFactory<olympia::BPU,
olympia::BPU::BPUParameterSet> bpu_rf;

//! \brief Resource Factory to build a Decode Unit
sparta::ResourceFactory<olympia::Decode,
olympia::Decode::DecodeParameterSet> decode_rf;
Expand Down
Loading
Loading