From 984dad9d8a7bc537769e2ed71e756f697807c764 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 2 Dec 2024 00:47:32 +0530 Subject: [PATCH] Branch prediction unit init --- core/BPTypes.hpp | 27 ++++++++++ core/BPU.cpp | 29 +++++++++++ core/BPU.hpp | 69 ++++++++++++++++++++++++++ core/BasePredictor.cpp | 110 +++++++++++++++++++++++++++++++++++++++++ core/BasePredictor.hpp | 73 +++++++++++++++++++++++++++ core/CMakeLists.txt | 1 + core/CPUFactories.hpp | 5 ++ core/CPUTopology.cpp | 16 ++++++ core/Fetch.hpp | 8 +++ core/TAGE_SC_L.cpp | 1 + core/TAGE_SC_L.hpp | 38 ++++++++++++++ 11 files changed, 377 insertions(+) create mode 100644 core/BPTypes.hpp create mode 100644 core/BPU.cpp create mode 100644 core/BPU.hpp create mode 100644 core/BasePredictor.cpp create mode 100644 core/BasePredictor.hpp create mode 100644 core/TAGE_SC_L.cpp create mode 100644 core/TAGE_SC_L.hpp diff --git a/core/BPTypes.hpp b/core/BPTypes.hpp new file mode 100644 index 00000000..a9945f43 --- /dev/null +++ b/core/BPTypes.hpp @@ -0,0 +1,27 @@ +#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; + }; + +} \ No newline at end of file diff --git a/core/BPU.cpp b/core/BPU.cpp new file mode 100644 index 00000000..21b704a9 --- /dev/null +++ b/core/BPU.cpp @@ -0,0 +1,29 @@ +#include "BPU.hpp" +#include "BPTypes.hpp" + +#include + +namespace olympia +{ + BPU::name = "bpu"; + BPU::BPU(sparta::TreeNode* node, BPUParameterSet* p) : + sparta::Unit(node) + + { + 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; + } +} + + diff --git a/core/BPU.hpp b/core/BPU.hpp new file mode 100644 index 00000000..61fd8fc6 --- /dev/null +++ b/core/BPU.hpp @@ -0,0 +1,69 @@ +#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 +#include +#include + +namespace olympia +{ +namespace BPU +{ + 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 + + }; + static const char name[]; + BPU(sparta::TreeNode* n, sparta::ParameterSet* p); + + private: + void receivePredictionCredits_(uint32_t); + void recievePredictionInput(PredictionInput); + + + // input ports + // verify cycle delay required + sparta::DataInPort in_fetch_prediction_credits_ {&unit_port_set_, + "in_fetch_prediction_credits", 0}; + + // verify cycle delay required + sparta::DataInPort 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 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"}; + }; +} +} \ No newline at end of file diff --git a/core/BasePredictor.cpp b/core/BasePredictor.cpp new file mode 100644 index 00000000..846125ac --- /dev/null +++ b/core/BasePredictor.cpp @@ -0,0 +1,110 @@ +// +// Created by shobhit on 12/1/24. +// + +#include "BasePredictor.hpp" + +namespace olympia +{ +// PHT +void PatternHistoryTable::incrementCounter(uint32_t idx) { + if(pattern_history_table_[idx] == ctr_bits_val_) { + return; + } + else { + pattern_history_table_[idx]++; + } +} + +void PatternHistoryTable::decrementCounter(uint32_t idx) { + if(pattern_history_table_[idx] == 0) { + return; + } + else { + pattern_history_table_[idx]--; + } +} + +uint8_t PatternHistoryTable::getPrediction(uint32_t idx) { + return pattern_history_table_[idx]; +} + +// BTB +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(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; + } +} + +// RAS +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() { + return; +} + +PredictionOutput BasePredictor::makePrediction(PredictionInput predInput) { + + PredictionOutput predOutput; + + // branch instruction + if(predInput.instType == 1) { + predOutput.predDirection = false; + predOutput.predPC = 5; + } + // call instructions + //else if(predInput.instType == 2) { + // in this case no prediction is made, only data is stored for future reference + //} + // ret instruction + else if(predInput.instType == 3) { + predOutput.predDirection = true; + predOutput.predPC = returnAddressStack.popAddress(); + } + return predOutput; +} +} diff --git a/core/BasePredictor.hpp b/core/BasePredictor.hpp new file mode 100644 index 00000000..b27dcbae --- /dev/null +++ b/core/BasePredictor.hpp @@ -0,0 +1,73 @@ +#pragma once + +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_; + + uint8_t pattern_history_table_[pht_size_]; + + }; + + class BranchTargetBuffer + { + public: + BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} + + 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 branch_target_buffer_; // define size of this map too + }; + + 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 return_address_stack_; + + }; + + class BasePredictor + { + public: + BasePredictor(uint32_t pht_size, uint8_t ctr_bits, + uint32_t btb_size, uint32_t ras_size) + { + PatternHistoryTable patternHistoryTable(pht_size, ctr_bits); + BranchTargetBuffer branchTargetBuffer(btb_size); + ReturnAddressStack returnAddressStack(ras_size); + } + + void receivedPredictionReq(); + PredictionOutput makePrediction(PredictionInput predInput); + + }; +} + diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 47657c75..db351767 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(core SimpleBranchPred.cpp ICache.cpp Fetch.cpp + BPU.cpp Decode.cpp VectorUopGenerator.cpp Rename.cpp diff --git a/core/CPUFactories.hpp b/core/CPUFactories.hpp index 2947ba89..35e7ea7e 100644 --- a/core/CPUFactories.hpp +++ b/core/CPUFactories.hpp @@ -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" @@ -49,6 +50,10 @@ namespace olympia{ sparta::ResourceFactory fetch_rf; + //! \brief Resource Factory to build a BPU Unit + sparta::ResourceFactory bpu_rf; + //! \brief Resource Factory to build a Decode Unit sparta::ResourceFactory decode_rf; diff --git a/core/CPUTopology.cpp b/core/CPUTopology.cpp index c2fc310a..21a6e219 100644 --- a/core/CPUTopology.cpp +++ b/core/CPUTopology.cpp @@ -43,6 +43,14 @@ olympia::CoreTopologySimple::CoreTopologySimple(){ sparta::TreeNode::GROUP_IDX_NONE, &factories->fetch_rf }, + { + "bpu", + "cpu.core*", + "BPU Unit", + sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, + &factories->bpu_rf + }, { "decode", "cpu.core*", @@ -188,6 +196,14 @@ olympia::CoreTopologySimple::CoreTopologySimple(){ "cpu.core*.fetch.ports.in_fetch_queue_credits", "cpu.core*.decode.ports.out_fetch_queue_credits" }, + { + "cpu.core*.fetch.ports.out_bpu_prediction_credits", + "cpu.core*.bpu.ports.in_fetch_prediction_credits" + }, + { + "cpu.core*.fetch.ports.out_bpu_prediction_req", + "cpu.core*.bpu.ports.in_fetch_prediction_req" + }, { "cpu.core*.decode.ports.out_uop_queue_write", "cpu.core*.rename.ports.in_uop_queue_append" diff --git a/core/Fetch.hpp b/core/Fetch.hpp index 8eb46c38..e323c073 100644 --- a/core/Fetch.hpp +++ b/core/Fetch.hpp @@ -20,6 +20,7 @@ #include "InstGroup.hpp" #include "FlushManager.hpp" #include "MemoryAccessInfo.hpp" +#include "BPU.hpp" namespace olympia { @@ -103,6 +104,13 @@ namespace olympia sparta::DataInPort in_icache_fetch_credits_ {&unit_port_set_, "in_icache_fetch_credits", sparta::SchedulingPhase::Tick, 0}; + sparta::DataOutPort out_bpu_prediction_credits_ {&unit_port_set_, + "out_bpu_prediction_credits", 0}; + + // verify cycle delay required + sparta::DataOutPort out_bpu_prediction_req_ {&unit_port_set_, + "out_bpu_prediction_req", 0}; + //////////////////////////////////////////////////////////////////////////////// // Instruction fetch diff --git a/core/TAGE_SC_L.cpp b/core/TAGE_SC_L.cpp new file mode 100644 index 00000000..f14dfb94 --- /dev/null +++ b/core/TAGE_SC_L.cpp @@ -0,0 +1 @@ +#include "TAGE_SC_L.hpp" diff --git a/core/TAGE_SC_L.hpp b/core/TAGE_SC_L.hpp new file mode 100644 index 00000000..2c20ae08 --- /dev/null +++ b/core/TAGE_SC_L.hpp @@ -0,0 +1,38 @@ +#pragma once + +namespace olympia +{ + class TageBIM + { + public: + TageBIM(uint32_t tage_bim_size, uint8_t tage_bim_ctr_bits) : + tage_bim_size_(tage_bim_size), + tage_bim_ctr_bits_(tage_bim_ctr_bits) + { + tage_bim_ctr_bits_val_ = pow(2, tage_bim_ctr_bits_); + } + + private: + const uint32_t tage_bim_size_; + const uint8_t tage_bim_ctr_bits_; + const uint8_t tage_bim_ctr_bits_val_; + + }; + + class TageTaggedComponent + { + public: + TageTaggedComponent(uint16_t tag, uint8_t ctr, uint8_t u) : + tag_(tag), ctr_(ctr), u_(u) {} + private: + const uint16_t tag_; + const uint8_t ctr_; + const uint8_t u_; + }; + + class Tage + { + public: + + }; +} \ No newline at end of file