From 1f8800afc03e633172a19e94e4345e43a054223c Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 27 Jan 2025 05:40:00 +0530 Subject: [PATCH 01/15] Add Basic BPU testbench structure --- core/fetch/BPU.cpp | 65 ++++++++++ core/fetch/BPU.hpp | 119 ++++++++++++++++++ test/CMakeLists.txt | 1 + test/core/bpu/BPUSink.hpp | 65 ++++++++++ test/core/bpu/BPUSource.hpp | 101 +++++++++++++++ test/core/bpu/BPU_testbench.cpp | 206 +++++++++++++++++++++++++++++++ test/core/bpu/CMakeLists.txt | 39 ++++++ test/core/bpu/check_files.sh | 42 +++++++ test/core/bpu/config/config.yaml | 11 ++ test/core/bpu/json/branch.json | 14 +++ 10 files changed, 663 insertions(+) create mode 100644 core/fetch/BPU.cpp create mode 100644 core/fetch/BPU.hpp create mode 100644 test/core/bpu/BPUSink.hpp create mode 100644 test/core/bpu/BPUSource.hpp create mode 100644 test/core/bpu/BPU_testbench.cpp create mode 100644 test/core/bpu/CMakeLists.txt create mode 100644 test/core/bpu/check_files.sh create mode 100644 test/core/bpu/config/config.yaml create mode 100644 test/core/bpu/json/branch.json diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp new file mode 100644 index 00000000..eeb4ad1f --- /dev/null +++ b/core/fetch/BPU.cpp @@ -0,0 +1,65 @@ + +#include "fetch/BPU.hpp" + +namespace olympia +{ +namespace BranchPredictor +{ + const char* BPU::name = "BPU"; + + BPU::BPU(sparta::TreeNode * name, const BPUParameterSet * p) : + sparta::Unit(node) + { + in_fetch_predictionRequest_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); + + in_fetch_predictionOutput_credits_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receiveCreditsFromFetch, uint32_t)); + } + + BPU::~BPU() {} + + void BPU::sendPredictionRequestCredits_(uint32_t credits) + { + ILOG("Send prediction request credits to Fetch"); + out_fetch_predictionRequest_credits_.send(credits); + } + void BPU::sendInitialPredictionRequestCredits_() + { + ILOG("Sending initial prediction request credits to Fetch"); + sendPredictionRequestCredits_(1); + } + + void BPU::recievePredictionRequest_(const PredictionRequest & predReq) + { + ILOG("Received prediction request from Fetch"); + predictionRequestBuffer_.push_back(predReq); + } + + //void BPU::recievePredictionUpdate_() + //{} + + void BPU::receivePredictionOutputCredits_(const uint32_t & credits) + { + ILOG("Recieve prediction output credits from Fetch"); + predictionOutputCredits_ += credits; + } + + void BPU::makePrediction_() + { + auto output = PredictionOutput(true, 100000); + generatedPredictionOutputBuffer_.push_back(output); + } + + void BPU::sendPrediction_() + { + if(predictionOutputCredits_ > 0) { + ILOG("Sending prediction output to fetch"); + auto predOutput = generatedPredictionOutputBuffer_.pop_front(); + out_fetch_predictionOutput_.send(predOutput); + predictionOutputCredits_--; + } + } + +} +} diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp new file mode 100644 index 00000000..ae197e69 --- /dev/null +++ b/core/fetch/BPU.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/SingleCycleUniqueEvent.hpp" +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/simulation/ParameterSet.hpp" + +#include "BranchPredIF.hpp" + +#include + +namespace olympia +{ +namespace BranchPredictor +{ + class PredictionRequest + { + public: + PredictionRequest(uint64_t PC, uint8_t instType) : + PC_(PC), instType_(instType) {} + private: + uint64_t PC_; + uint8_t instType_; + }; + + class PredictionOutput + { + public: + PredictionOutput(bool predDirection, uint64_t predPC) : + predDirection_(predDirection), predPC_(predPC) {} + private: + bool predDirection_; + uint64_t predPC_; + }; + + class UpdateInput + { + public: + UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) : + instrPC_(instrPC), correctedDirection_(correctedDirection), correctedTargetPC_(correctedTargetPC) {} + private: + uint64_t instrPC_; + bool correctedDirection_; + uint64_t correctedTargetPC_; + }; + + class BPU : public BranchPredictorIF, public sparta::Unit + { + public: + class BPUParameterSet : public sparta::ParameterSet + { + public: + BPUParameterSet(sparta::TreeNode* n) : + sparta::ParameterSet(n) {} + + PARAMETER(uint32_t, ghr_size, 1024, "Number of history bits in GHR"); + }; + BPU(sparta::TreeNode * name, + const BPUParameterSet * p); + + ~BPU(); + + //DefaultPrediction getPrediction(const PredictionRequest &); + //void updatePredictor(const UpdateInput &); + + //! \brief Name of this resource. Required by sparta::UnitFactory + static const char *name; + + private: + + void sendPredictionRequestCredits_(uint32_t credits); + void sendInitialPredictionRequestCredits_(); + void recievePredictionRequest_(const PredictionRequest & predReq); + //void recievePredictionUpdate_(); + void receivePredictionOutputCredits_(const uint32_t & credits); + void makePrediction_(); + void sendPrediction_(); + + std::list predictionRequestBuffer_; + std::list generatedPredictionOutputBuffer_; + uint32_t predictionRequestCredits_ = 0; + uint32_t predictionOutputCredit_ = 0; + + + /////////////////////////////////////////////////////////////////////////////// + // Ports + /////////////////////////////////////////////////////////////////////////////// + + // Internal DataInPort from fetch unit for prediction request + sparta::DataInPort in_fetch_predictionRequest_ + {&unit_port_set_, "in_fetch_predictionRequest", sparta::SchedulingPhase::Tick, 0}; + + // Internal DataInPort from fetch unit for credits to indicate + // availabilty of slots for sending prediction output + sparta::DataInPort in_fetch_predictionOutput_credits_ + {&unit_port_set_, "in_fetch_predictionOutput_credits", sparta::SchedulingPhase::Tick, 0}; + + // TODO + + // DataOutPort to fetch unit to send credits to indicate availability + // of slots to receive prediction request + sparta::DataOutPort out_fetch_predictionRequest_credits_ + {&unit_port_set_, "out_fetch_predictionRequest_credits"}; + + // DataOutPort to fetch unit to send prediction output + sparta::DataOutPort out_fetch_predictionOutput_ + {&unit_port_set_, "out_fetch_predictionOutput"}; + + ////////////////////////////////////////////////////////////////////////////// + // Events + ////////////////////////////////////////////////////////////////////////////// + /***sparta::PayloadEvent ev_sendPrediction_{ + &unit_event_set_, "ev_sendPrediction", + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, sendPrediction_, PredictionOutput)}; + ***/ + }; +} +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index deaa9ec9..b7a4baa3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,4 +37,5 @@ add_subdirectory(core/branch_pred) add_subdirectory(core/dcache) add_subdirectory(core/vector) add_subdirectory(core/unit_template) +add_subdirectory(core/bpu) add_subdirectory(fusion) diff --git a/test/core/bpu/BPUSink.hpp b/test/core/bpu/BPUSink.hpp new file mode 100644 index 00000000..05fa4b02 --- /dev/null +++ b/test/core/bpu/BPUSink.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "core/MemoryAccessInfo.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/SingleCycleUniqueEvent.hpp" +#include "sparta/utils/SpartaSharedPointer.hpp" +#include "sparta/utils/LogUtils.hpp" + +#include "../../../core/fetch/BPU.hpp" + +#include + +namespace bpu_test +{ + class BPUSink : public sparta::Unit + { + public: + static constexpr char name[] = "bpu_sink_unit"; + + class BPUSinkParameters : public sparta::ParameterSet + { + public: + BPUSinkParameters(sparta::TreeNode *n) : sparta::ParameterSet(n) + {} + }; + + BPUSink(sparta::TreeNode *n, const BPUSinkParameters *params) : + sparta::Unit(n) + { + sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)); + } + + private: + + uint32_t predictionOutputCredits_ = 1; + + void sendPredictionOutputCredits_() + { + ILOG("send prediction output credits to bpu"); + out_bpu_predictionOutput_credits_.send(predictionOutputCredits_); + } + void recievePredictionOutput_(const olympia::BranchPredictor::PredictionOutput &predOutput) + { + ILOG("recieve prediction output from bpu"); + predictionOutputResult_.push_back(predOutput); + ev_return_credits_.schedule(1); + } + + std::list predictionOutputResult_; + + //////////////////////////////////////////////////////////////////////////////// + // Ports + //////////////////////////////////////////////////////////////////////////////// + sparta::DataInPort in_bpu_predictionOutput_{&unit_port_set_, + "in_bpu_predictionOutput", 0}; + + sparta::DataOutPort out_bpu_predictionOutput_credits_{&unit_port_set_, + "out_bpu_predictionOutput_credits"}; + + sparta::UniqueEvent<> ev_return_credits_{&unit_event_set_, "return_credits", + CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)}; + }; + using SinkFactory = sparta::ResourceFactory; +} \ No newline at end of file diff --git a/test/core/bpu/BPUSource.hpp b/test/core/bpu/BPUSource.hpp new file mode 100644 index 00000000..20464b45 --- /dev/null +++ b/test/core/bpu/BPUSource.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include "core/InstGenerator.hpp" +#include "core/decode/MavisUnit.hpp" +#include "core/InstGroup.hpp" +#include "mavis/ExtractorDirectInfo.h" +#include "core/MemoryAccessInfo.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/SingleCycleUniqueEvent.hpp" +#include "sparta/utils/SpartaSharedPointer.hpp" +#include "sparta/utils/LogUtils.hpp" + +#include "OlympiaAllocators.hpp" + +#include "../../../core/fetch/BPU.hpp" + +#include + +namespace bpu_test +{ + class BPUSource : public sparta::Unit + { + public: + static constexpr char name[] = "bpu_source_unit"; + + class BPUSourceParameters : public sparta::ParameterSet + { + public: + explicit BPUSourceParameters(sparta::TreeNode *n) : sparta::ParameterSet(n) + {} + + PARAMETER(std::string, test_type, "single", "Test mode to run: single or multiple") + + PARAMETER(std::string, input_file, "", "Input file: STF or JSON") + }; + + BPUSource(sparta::TreeNode *n, const BPUSourceParameters *params) : + sparta::Unit(n), + test_type_(params->test_type), + mavis_facade_(olympia::getMavis(n)) + { + sparta_assert(mavis_facade_ != nullptr, "Could not find the Mavis Unit"); + in_bpu_predictionRequest_credits_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, receivePredictionRequestCredits_, uint32_t)); + + if (params->input_file != "") + { + inst_generator_ = olympia::InstGenerator::createGenerator( + mavis_facade_, params->input_file, false); + } + } + + void initiate() + { + olympia::BranchPredictor::PredictionRequest pred(0x01, 2); + generatedPredictedRequest_.push_back(pred); + } + + private: + const std::string test_type_; + olympia::MavisType* mavis_facade_ = nullptr; + std::unique_ptr inst_generator_; + + void receivePredictionRequestCredits_(const uint32_t & credits) + { + ILOG("Received prediction request credits from BPU"); + predictionRequestCredits_ += credits; + + if(predictionRequestCredits_ > 0) { + ev_gen_insts_.schedule(); + } + } + void sendPredictionRequest_() + { + if(predictionRequestCredits_ > 0) { + auto output = generatedPredictedRequest_.front(); + generatedPredictedRequest_.pop_front(); + out_bpu_predictionRequest_.send(output); + predictionRequestCredits_--; + } + } + + uint32_t predictionRequestCredits_ = 0; + std::list generatedPredictedRequest_; + + //////////////////////////////////////////////////////////////////////////////// + // Ports + //////////////////////////////////////////////////////////////////////////////// + sparta::DataOutPort out_bpu_predictionRequest_{&unit_port_set_, + "out_bpu_predictionRequest"}; + + sparta::DataInPort in_bpu_predictionRequest_credits_{&unit_port_set_, + "in_bpu_predictionRequest_credits", 0}; + + sparta::SingleCycleUniqueEvent<> ev_gen_insts_{&unit_event_set_, "gen_inst", + CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; + + }; + using SrcFactory = sparta::ResourceFactory; +} \ No newline at end of file diff --git a/test/core/bpu/BPU_testbench.cpp b/test/core/bpu/BPU_testbench.cpp new file mode 100644 index 00000000..6be59bf9 --- /dev/null +++ b/test/core/bpu/BPU_testbench.cpp @@ -0,0 +1,206 @@ +#include "../../../core/fetch/BPU.hpp" +#include "decode/MavisUnit.hpp" +#include "OlympiaAllocators.hpp" +#include "BPUSink.hpp" +#include "BPUSource.hpp" + +#include "sparta/app/CommandLineSimulator.hpp" +#include "sparta/log/MessageSource.hpp" +#include "sparta/utils/SpartaTester.hpp" + +#include +#include + +using namespace std; + +TEST_INIT +olympia::InstAllocator inst_allocator(2000, 1000); + + +// ---------------------------------------------------------------------- +// Testbench reference - example starting point for unit benches +// ---------------------------------------------------------------------- +class Simulator : public sparta::app::Simulation +{ + using BPUFactory = sparta::ResourceFactory; + + public: + Simulator(sparta::Scheduler* sched, const string & mavis_isa_files, + const string & mavis_uarch_files, const string & output_file, + const string & input_file) : + sparta::app::Simulation("Simulator", sched), + input_file_(input_file), + test_tap_(getRoot(), "info", output_file) + { + } + + ~Simulator() { getRoot()->enterTeardown(); } + + void runRaw(uint64_t run_time) override final + { + (void)run_time; // ignored + + sparta::app::Simulation::runRaw(run_time); + } + + private: + void buildTree_() override + { + auto rtn = getRoot(); + + // Create the common allocators + allocators_tn_.reset(new olympia::OlympiaAllocators(rtn)); + + // Create a Mavis Unit + tns_to_delete_.emplace_back(new sparta::ResourceTreeNode( + rtn, olympia::MavisUnit::name, sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "Mavis Unit", &mavis_fact)); + + // Create a Source Unit + sparta::ResourceTreeNode* src_unit = new sparta::ResourceTreeNode( + rtn, "src", sparta::TreeNode::GROUP_NAME_NONE, sparta::TreeNode::GROUP_IDX_NONE, + "Source Unit", &source_fact); + + tns_to_delete_.emplace_back(src_unit); + + auto* src_params = src_unit->getParameterSet(); + src_params->getParameter("input_file")->setValueFromString(input_file_); + + // Create the device under test + sparta::ResourceTreeNode* bpu = + new sparta::ResourceTreeNode(rtn, "bpu", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "BPU", &bpu_fact); + + tns_to_delete_.emplace_back(bpu); + + // Create the Sink unit + sparta::ResourceTreeNode* sink = + new sparta::ResourceTreeNode(rtn, "sink", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "Sink Unit", &sink_fact); + + tns_to_delete_.emplace_back(sink); + + auto* sink_params = sink->getParameterSet(); + sink_params->getParameter("purpose")->setValueFromString("grp"); + } + + void configureTree_() override {} + + void bindTree_() override + { + auto* root_node = getRoot(); + + // See the README.md for A/B/Cx/Dx + // + // A - bpu sends prediction request credits to source + sparta::bind(root_node->getChildAs("bpu.ports.out_fetch_predictionRequest_credits"), + root_node->getChildAs("src.ports.in_bpu_predictionRequest_credits")); + + // B - source sends prediction request to bpu + sparta::bind(root_node->getChildAs("bpu.ports.in_fetch_predictionRequest"), + root_node->getChildAs("src.ports.out_bpu_predictionRequest")); + + // C - sink sends prediction output credits to bpu + sparta::bind(root_node->getChildAs("bpu.ports.in_fetch_predictionOutput_credits"), + root_node->getChildAs("sink.ports.out_bpu_predictionOutput_credits")); + + // D - bpu sends prediction output to sink + sparta::bind(root_node->getChildAs("bpu.ports.out_fetch_predictionOutput"), + root_node->getChildAs("sink.ports.in_bpu_predictionOutput")); + } + + // Allocators. Last thing to delete + std::unique_ptr allocators_tn_; + + olympia::MavisFactory mavis_fact; + BPUFactory bpu_fact; + + bpu_test::SrcFactory source_fact; + bpu_test::SinkFactory sink_fact; + + vector> tns_to_delete_; + vector exe_units_; + + const string input_file_; + sparta::log::Tap test_tap_; +}; + +const char USAGE[] = "Usage:\n\n" + "Testbench options \n" + " [ --input_file ] : json or stf input file\n" + " [ --output_file ] : output file for results checking\n" + " \n" + "Commonly used options \n" + " [-i insts] [-r RUNTIME] [--show-tree] [--show-dag]\n" + " [-p PATTERN VAL] [-c FILENAME]\n" + " [-l PATTERN CATEGORY DEST]\n" + " [-h,--help] \n" + "\n"; + +sparta::app::DefaultValues DEFAULTS; + +// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +bool runTest(int argc, char** argv) +{ + DEFAULTS.auto_summary_default = "off"; + vector datafiles; + string input_file; + + sparta::app::CommandLineSimulator cls(USAGE, DEFAULTS); + auto & app_opts = cls.getApplicationOptions(); + + app_opts.add_options()("output_file", + sparta::app::named_value>("output_file", &datafiles), + "Specifies the output file") + + ("input_file", + sparta::app::named_value("INPUT_FILE", &input_file)->default_value(""), + "Provide a JSON or STF instruction stream"); + + po::positional_options_description & pos_opts = cls.getPositionalOptions(); + // example, look for the at the end + pos_opts.add("output_file", -1); + + int err_code = 0; + + if (!cls.parse(argc, argv, err_code)) + { + sparta_assert(false, "Command line parsing failed"); + } + + auto & vm = cls.getVariablesMap(); + if (vm.count("tbhelp") != 0) + { + cout << USAGE << endl; + return false; + } + + sparta_assert(false == datafiles.empty(), + "Need an output file as the last argument of the test"); + + sparta::Scheduler sched; + Simulator sim(&sched, "mavis_isa_files", "arch/isa_json", datafiles[0], input_file); + + if (input_file.length() == 0) + { + sparta::log::MessageSource il(sim.getRoot(), "info", "Info Messages"); + il << "No input file specified, exiting gracefully, output not checked"; + return true; // not an error + } + + cls.populateSimulation(&sim); + cls.runSimulator(&sim); + + EXPECT_FILES_EQUAL(datafiles[0], "expected_output/" + datafiles[0] + ".EXPECTED"); + return true; +} + +int main(int argc, char** argv) +{ + if (!runTest(argc, argv)) + return 1; + + REPORT_ERROR; + return (int)ERROR_CODE; +} diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt new file mode 100644 index 00000000..79c83356 --- /dev/null +++ b/test/core/bpu/CMakeLists.txt @@ -0,0 +1,39 @@ +set(PRJ "BPU_TESTBENCH") +set(EXE "BPU_TESTBENCH_EXE") + +set(TST1 "${PRJ}_tst1") +set(TST2 "${PRJ}_json") +set(TST3 "${PRJ}_stf") + +set(CFG config/config.yaml) + +set(BPUDir ../../../core/fetch) + +project(${PRJ}) + +add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp BPUSource.hpp BPUSink.hpp) +target_include_directories(${EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(${EXE} core common_test ${STF_LINK_LIBS} mavis SPARTA::sparta) + +file(CREATE_LINK ${SIM_BASE}/mavis/json + ${CMAKE_CURRENT_BINARY_DIR}/mavis_isa_files SYMBOLIC) + +file(CREATE_LINK ${SIM_BASE}/arches + ${CMAKE_CURRENT_BINARY_DIR}/arches SYMBOLIC) + +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/config + ${CMAKE_CURRENT_BINARY_DIR}/config SYMBOLIC) + +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/json + ${CMAKE_CURRENT_BINARY_DIR}/json SYMBOLIC) + +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/traces + ${CMAKE_CURRENT_BINARY_DIR}/traces SYMBOLIC) + +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/expected_output + ${CMAKE_CURRENT_BINARY_DIR}/expected_output SYMBOLIC) + +sparta_named_test(${TST1} ${EXE} bpu_tb_test1.out -c ${CFG}) +sparta_named_test(${TST2} ${EXE} bpu_tb_json.out --input_file ${STF} -c ${CFG}) +sparta_named_test(${TST3} ${EXE} bpu_tb_stf.out --input_file ${JSON} -c ${CFG}) \ No newline at end of file diff --git a/test/core/bpu/check_files.sh b/test/core/bpu/check_files.sh new file mode 100644 index 00000000..31f4beb6 --- /dev/null +++ b/test/core/bpu/check_files.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Check files w/ clang-format +# This does not modify the source files + +# The argument is required +if [[ -z "$1" ]]; then + echo "Usage: $0 " + exit 1 +fi + +compile_commands="$1" + +# Make sure the json exists +if [[ ! -f "$compile_commands" ]]; then + echo "Error: File '$compile_commands' does not exist." + exit 1 +fi + +# List of files +files=( + "../../../core/fetch/BPU.cpp" + "../../../core/fetch/BPU.hpp" + "BPUSink.hpp" + "BPUSource.hpp" + "BPU_testbench.cpp" +) + +for file in "${files[@]}"; do + echo "Checking $file for formatting issues..." + if [[ -f "$file" ]]; then + clang-format --dry-run --Werror "$file" + if [[ $? -eq 0 ]]; then + echo "$file is properly formatted." + else + echo "$file needs formatting." + clang-format "$file" > "$file.formatted" + fi + else + echo "Warning: File $file does not exist, skipping." + fi +done diff --git a/test/core/bpu/config/config.yaml b/test/core/bpu/config/config.yaml new file mode 100644 index 00000000..8a95e130 --- /dev/null +++ b/test/core/bpu/config/config.yaml @@ -0,0 +1,11 @@ +# +# Placeholder +# +#top.cpu: +# dispatch.num_to_dispatch: 2 + +#top.extension.core_extensions: +# execution_topology: +# [["alu", "10"], +# ["fpu", "10"], +# ["br", "10"]] diff --git a/test/core/bpu/json/branch.json b/test/core/bpu/json/branch.json new file mode 100644 index 00000000..02dfe7a0 --- /dev/null +++ b/test/core/bpu/json/branch.json @@ -0,0 +1,14 @@ +[ + { + "mnemonic": "beq", + "rs1": 1, + "rs2": 4, + "offset": 2 + }, + { + "mnemonic": "bne", + "rs1": 1, + "rs2": 4, + "offset": 1 + } +] \ No newline at end of file From 7067ae185e62bf61a2c213bb3462732d7272752c Mon Sep 17 00:00:00 2001 From: Shobhit Date: Sun, 2 Feb 2025 19:08:05 +0530 Subject: [PATCH 02/15] added operator overload for bpu types to facilitate building --- core/fetch/BPU.cpp | 115 +++++++++++--------- core/fetch/BPU.hpp | 186 ++++++++++++++++---------------- test/core/bpu/BPUSink.hpp | 32 +++--- test/core/bpu/BPUSource.hpp | 41 +++---- test/core/bpu/BPU_testbench.cpp | 18 ++-- 5 files changed, 208 insertions(+), 184 deletions(-) diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index eeb4ad1f..61b2c889 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -1,65 +1,80 @@ #include "fetch/BPU.hpp" -namespace olympia +namespace olympia { -namespace BranchPredictor -{ - const char* BPU::name = "BPU"; - - BPU::BPU(sparta::TreeNode * name, const BPUParameterSet * p) : - sparta::Unit(node) + namespace BranchPredictor { - in_fetch_predictionRequest_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); + const char* BPU::name = "BPU"; - in_fetch_predictionOutput_credits_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receiveCreditsFromFetch, uint32_t)); - } + BPU::BPU(sparta::TreeNode* node, const BPUParameterSet* p) : sparta::Unit(node) + { + in_fetch_predictionRequest_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); - BPU::~BPU() {} + in_fetch_predictionOutput_credits_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionOutputCredits_, uint32_t)); + } - void BPU::sendPredictionRequestCredits_(uint32_t credits) - { - ILOG("Send prediction request credits to Fetch"); - out_fetch_predictionRequest_credits_.send(credits); - } - void BPU::sendInitialPredictionRequestCredits_() - { - ILOG("Sending initial prediction request credits to Fetch"); - sendPredictionRequestCredits_(1); - } + PredictionOutput BPU::getPrediction(const PredictionRequest & pred) + { + PredictionOutput output; + output.predDirection_ = true; + output.predPC_ = 0x0220; - void BPU::recievePredictionRequest_(const PredictionRequest & predReq) - { - ILOG("Received prediction request from Fetch"); - predictionRequestBuffer_.push_back(predReq); - } + return output; + } - //void BPU::recievePredictionUpdate_() - //{} + void BPU::updatePredictor(const UpdateInput & update) {} - void BPU::receivePredictionOutputCredits_(const uint32_t & credits) - { - ILOG("Recieve prediction output credits from Fetch"); - predictionOutputCredits_ += credits; - } + BPU::~BPU() {} - void BPU::makePrediction_() - { - auto output = PredictionOutput(true, 100000); - generatedPredictionOutputBuffer_.push_back(output); - } + void BPU::sendPredictionRequestCredits_(uint32_t credits) + { + ILOG("Send prediction request credits to Fetch"); + out_fetch_predictionRequest_credits_.send(credits); + } - void BPU::sendPrediction_() - { - if(predictionOutputCredits_ > 0) { - ILOG("Sending prediction output to fetch"); - auto predOutput = generatedPredictionOutputBuffer_.pop_front(); - out_fetch_predictionOutput_.send(predOutput); - predictionOutputCredits_--; + void BPU::sendInitialPredictionRequestCredits_() + { + ILOG("Sending initial prediction request credits to Fetch"); + sendPredictionRequestCredits_(1); + } + + void BPU::recievePredictionRequest_(const PredictionRequest & predReq) + { + ILOG("Received prediction request from Fetch"); + predictionRequestBuffer_.push_back(predReq); + } + + // void BPU::recievePredictionUpdate_() + //{} + + void BPU::receivePredictionOutputCredits_(const uint32_t & credits) + { + ILOG("Recieve prediction output credits from Fetch"); + predictionOutputCredits_ += credits; + } + + void BPU::makePrediction_() + { + PredictionOutput output; + output.predDirection_ = true; + output.predPC_ = 100000; + generatedPredictionOutputBuffer_.push_back(output); + } + + void BPU::sendPrediction_() + { + if (predictionOutputCredits_ > 0) + { + ILOG("Sending prediction output to fetch"); + auto predOutput = generatedPredictionOutputBuffer_.front(); + generatedPredictionOutputBuffer_.pop_front(); + out_fetch_predictionOutput_.send(predOutput); + predictionOutputCredits_--; + } } - } -} -} + } // namespace BranchPredictor +} // namespace olympia diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index ae197e69..16a2366b 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -5,6 +5,7 @@ #include "sparta/simulation/Unit.hpp" #include "sparta/simulation/TreeNode.hpp" #include "sparta/simulation/ParameterSet.hpp" +#include "sparta/utils/LogUtils.hpp" #include "BranchPredIF.hpp" @@ -12,108 +13,111 @@ namespace olympia { -namespace BranchPredictor -{ - class PredictionRequest + namespace BranchPredictor { - public: - PredictionRequest(uint64_t PC, uint8_t instType) : - PC_(PC), instType_(instType) {} - private: + class PredictionRequest + { + public: + PredictionRequest() {} + uint64_t PC_; - uint8_t instType_; - }; + uint8_t instType_; + friend std::ostream & operator<<(std::ostream &, const PredictionRequest &); + }; + + class PredictionOutput + { + public: + PredictionOutput() {} - class PredictionOutput - { - public: - PredictionOutput(bool predDirection, uint64_t predPC) : - predDirection_(predDirection), predPC_(predPC) {} - private: bool predDirection_; uint64_t predPC_; - }; + friend std::ostream & operator<<(std::ostream &, const PredictionOutput &); + }; + + class UpdateInput + { + public: + UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) {} - class UpdateInput - { - public: - UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) : - instrPC_(instrPC), correctedDirection_(correctedDirection), correctedTargetPC_(correctedTargetPC) {} - private: uint64_t instrPC_; bool correctedDirection_; uint64_t correctedTargetPC_; - }; + friend std::ostream & operator<<(std::ostream &, const UpdateInput &); + }; - class BPU : public BranchPredictorIF, public sparta::Unit - { - public: - class BPUParameterSet : public sparta::ParameterSet + class BPU : + public BranchPredictorIF, + public sparta::Unit { - public: - BPUParameterSet(sparta::TreeNode* n) : - sparta::ParameterSet(n) {} + public: + class BPUParameterSet : public sparta::ParameterSet + { + public: + BPUParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) {} PARAMETER(uint32_t, ghr_size, 1024, "Number of history bits in GHR"); + }; + + BPU(sparta::TreeNode* node, const BPUParameterSet* p); + + PredictionOutput getPrediction(const PredictionRequest &); + void updatePredictor(const UpdateInput &); + + ~BPU(); + + // DefaultPrediction getPrediction(const PredictionRequest &); + // void updatePredictor(const UpdateInput &); + + //! \brief Name of this resource. Required by sparta::UnitFactory + static const char* name; + + private: + void sendPredictionRequestCredits_(uint32_t credits); + void sendInitialPredictionRequestCredits_(); + void recievePredictionRequest_(const PredictionRequest & predReq); + // void recievePredictionUpdate_(); + void receivePredictionOutputCredits_(const uint32_t & credits); + void makePrediction_(); + void sendPrediction_(); + + std::list predictionRequestBuffer_; + std::list generatedPredictionOutputBuffer_; + uint32_t predictionRequestCredits_ = 0; + uint32_t predictionOutputCredits_ = 0; + + /////////////////////////////////////////////////////////////////////////////// + // Ports + /////////////////////////////////////////////////////////////////////////////// + + // Internal DataInPort from fetch unit for prediction request + sparta::DataInPort in_fetch_predictionRequest_{ + &unit_port_set_, "in_fetch_predictionRequest", sparta::SchedulingPhase::Tick, 0}; + + // Internal DataInPort from fetch unit for credits to indicate + // availabilty of slots for sending prediction output + sparta::DataInPort in_fetch_predictionOutput_credits_{ + &unit_port_set_, "in_fetch_predictionOutput_credits", sparta::SchedulingPhase::Tick, + 0}; + + // TODO + + // DataOutPort to fetch unit to send credits to indicate availability + // of slots to receive prediction request + sparta::DataOutPort out_fetch_predictionRequest_credits_{ + &unit_port_set_, "out_fetch_predictionRequest_credits"}; + + // DataOutPort to fetch unit to send prediction output + sparta::DataOutPort out_fetch_predictionOutput_{ + &unit_port_set_, "out_fetch_predictionOutput"}; + + ////////////////////////////////////////////////////////////////////////////// + // Events + ////////////////////////////////////////////////////////////////////////////// + /***sparta::PayloadEvent ev_sendPrediction_{ + &unit_event_set_, "ev_sendPrediction", + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, sendPrediction_, PredictionOutput)}; + ***/ }; - BPU(sparta::TreeNode * name, - const BPUParameterSet * p); - - ~BPU(); - - //DefaultPrediction getPrediction(const PredictionRequest &); - //void updatePredictor(const UpdateInput &); - - //! \brief Name of this resource. Required by sparta::UnitFactory - static const char *name; - - private: - - void sendPredictionRequestCredits_(uint32_t credits); - void sendInitialPredictionRequestCredits_(); - void recievePredictionRequest_(const PredictionRequest & predReq); - //void recievePredictionUpdate_(); - void receivePredictionOutputCredits_(const uint32_t & credits); - void makePrediction_(); - void sendPrediction_(); - - std::list predictionRequestBuffer_; - std::list generatedPredictionOutputBuffer_; - uint32_t predictionRequestCredits_ = 0; - uint32_t predictionOutputCredit_ = 0; - - - /////////////////////////////////////////////////////////////////////////////// - // Ports - /////////////////////////////////////////////////////////////////////////////// - - // Internal DataInPort from fetch unit for prediction request - sparta::DataInPort in_fetch_predictionRequest_ - {&unit_port_set_, "in_fetch_predictionRequest", sparta::SchedulingPhase::Tick, 0}; - - // Internal DataInPort from fetch unit for credits to indicate - // availabilty of slots for sending prediction output - sparta::DataInPort in_fetch_predictionOutput_credits_ - {&unit_port_set_, "in_fetch_predictionOutput_credits", sparta::SchedulingPhase::Tick, 0}; - - // TODO - - // DataOutPort to fetch unit to send credits to indicate availability - // of slots to receive prediction request - sparta::DataOutPort out_fetch_predictionRequest_credits_ - {&unit_port_set_, "out_fetch_predictionRequest_credits"}; - - // DataOutPort to fetch unit to send prediction output - sparta::DataOutPort out_fetch_predictionOutput_ - {&unit_port_set_, "out_fetch_predictionOutput"}; - - ////////////////////////////////////////////////////////////////////////////// - // Events - ////////////////////////////////////////////////////////////////////////////// - /***sparta::PayloadEvent ev_sendPrediction_{ - &unit_event_set_, "ev_sendPrediction", - CREATE_SPARTA_HANDLER_WITH_DATA(BPU, sendPrediction_, PredictionOutput)}; - ***/ - }; -} -} + } // namespace BranchPredictor +} // namespace olympia diff --git a/test/core/bpu/BPUSink.hpp b/test/core/bpu/BPUSink.hpp index 05fa4b02..591e0ba1 100644 --- a/test/core/bpu/BPUSink.hpp +++ b/test/core/bpu/BPUSink.hpp @@ -15,24 +15,21 @@ namespace bpu_test { class BPUSink : public sparta::Unit { - public: + public: static constexpr char name[] = "bpu_sink_unit"; class BPUSinkParameters : public sparta::ParameterSet { - public: - BPUSinkParameters(sparta::TreeNode *n) : sparta::ParameterSet(n) - {} + public: + BPUSinkParameters(sparta::TreeNode* n) : sparta::ParameterSet(n) {} }; - BPUSink(sparta::TreeNode *n, const BPUSinkParameters *params) : - sparta::Unit(n) + BPUSink(sparta::TreeNode* n, const BPUSinkParameters* params) : sparta::Unit(n) { sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)); } - private: - + private: uint32_t predictionOutputCredits_ = 1; void sendPredictionOutputCredits_() @@ -40,7 +37,8 @@ namespace bpu_test ILOG("send prediction output credits to bpu"); out_bpu_predictionOutput_credits_.send(predictionOutputCredits_); } - void recievePredictionOutput_(const olympia::BranchPredictor::PredictionOutput &predOutput) + + void recievePredictionOutput_(const olympia::BranchPredictor::PredictionOutput & predOutput) { ILOG("recieve prediction output from bpu"); predictionOutputResult_.push_back(predOutput); @@ -52,14 +50,16 @@ namespace bpu_test //////////////////////////////////////////////////////////////////////////////// // Ports //////////////////////////////////////////////////////////////////////////////// - sparta::DataInPort in_bpu_predictionOutput_{&unit_port_set_, - "in_bpu_predictionOutput", 0}; + sparta::DataInPort in_bpu_predictionOutput_{ + &unit_port_set_, "in_bpu_predictionOutput", 0}; - sparta::DataOutPort out_bpu_predictionOutput_credits_{&unit_port_set_, - "out_bpu_predictionOutput_credits"}; + sparta::DataOutPort out_bpu_predictionOutput_credits_{ + &unit_port_set_, "out_bpu_predictionOutput_credits"}; - sparta::UniqueEvent<> ev_return_credits_{&unit_event_set_, "return_credits", - CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)}; + sparta::UniqueEvent<> ev_return_credits_{ + &unit_event_set_, "return_credits", + CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)}; }; + using SinkFactory = sparta::ResourceFactory; -} \ No newline at end of file +} // namespace bpu_test \ No newline at end of file diff --git a/test/core/bpu/BPUSource.hpp b/test/core/bpu/BPUSource.hpp index 20464b45..340c0a4b 100644 --- a/test/core/bpu/BPUSource.hpp +++ b/test/core/bpu/BPUSource.hpp @@ -21,28 +21,28 @@ namespace bpu_test { class BPUSource : public sparta::Unit { - public: + public: static constexpr char name[] = "bpu_source_unit"; class BPUSourceParameters : public sparta::ParameterSet { - public: - explicit BPUSourceParameters(sparta::TreeNode *n) : sparta::ParameterSet(n) - {} + public: + explicit BPUSourceParameters(sparta::TreeNode* n) : sparta::ParameterSet(n) {} PARAMETER(std::string, test_type, "single", "Test mode to run: single or multiple") PARAMETER(std::string, input_file, "", "Input file: STF or JSON") }; - BPUSource(sparta::TreeNode *n, const BPUSourceParameters *params) : + BPUSource(sparta::TreeNode* n, const BPUSourceParameters* params) : sparta::Unit(n), test_type_(params->test_type), mavis_facade_(olympia::getMavis(n)) { sparta_assert(mavis_facade_ != nullptr, "Could not find the Mavis Unit"); in_bpu_predictionRequest_credits_.registerConsumerHandler( - CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, receivePredictionRequestCredits_, uint32_t)); + CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, receivePredictionRequestCredits_, + uint32_t)); if (params->input_file != "") { @@ -53,11 +53,11 @@ namespace bpu_test void initiate() { - olympia::BranchPredictor::PredictionRequest pred(0x01, 2); - generatedPredictedRequest_.push_back(pred); + // olympia::BranchPredictor::PredictionRequest pred; + generatedPredictedRequest_.emplace_back(); } - private: + private: const std::string test_type_; olympia::MavisType* mavis_facade_ = nullptr; std::unique_ptr inst_generator_; @@ -67,13 +67,16 @@ namespace bpu_test ILOG("Received prediction request credits from BPU"); predictionRequestCredits_ += credits; - if(predictionRequestCredits_ > 0) { + if (predictionRequestCredits_ > 0) + { ev_gen_insts_.schedule(); } } + void sendPredictionRequest_() { - if(predictionRequestCredits_ > 0) { + if (predictionRequestCredits_ > 0) + { auto output = generatedPredictedRequest_.front(); generatedPredictedRequest_.pop_front(); out_bpu_predictionRequest_.send(output); @@ -87,15 +90,15 @@ namespace bpu_test //////////////////////////////////////////////////////////////////////////////// // Ports //////////////////////////////////////////////////////////////////////////////// - sparta::DataOutPort out_bpu_predictionRequest_{&unit_port_set_, - "out_bpu_predictionRequest"}; + sparta::DataOutPort out_bpu_predictionRequest_{ + &unit_port_set_, "out_bpu_predictionRequest"}; - sparta::DataInPort in_bpu_predictionRequest_credits_{&unit_port_set_, - "in_bpu_predictionRequest_credits", 0}; - - sparta::SingleCycleUniqueEvent<> ev_gen_insts_{&unit_event_set_, "gen_inst", - CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; + sparta::DataInPort in_bpu_predictionRequest_credits_{ + &unit_port_set_, "in_bpu_predictionRequest_credits", 0}; + sparta::SingleCycleUniqueEvent<> ev_gen_insts_{ + &unit_event_set_, "gen_inst", CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; }; + using SrcFactory = sparta::ResourceFactory; -} \ No newline at end of file +} // namespace bpu_test \ No newline at end of file diff --git a/test/core/bpu/BPU_testbench.cpp b/test/core/bpu/BPU_testbench.cpp index 6be59bf9..7cbb0eae 100644 --- a/test/core/bpu/BPU_testbench.cpp +++ b/test/core/bpu/BPU_testbench.cpp @@ -16,13 +16,13 @@ using namespace std; TEST_INIT olympia::InstAllocator inst_allocator(2000, 1000); - // ---------------------------------------------------------------------- // Testbench reference - example starting point for unit benches // ---------------------------------------------------------------------- class Simulator : public sparta::app::Simulation { - using BPUFactory = sparta::ResourceFactory; + using BPUFactory = sparta::ResourceFactory; public: Simulator(sparta::Scheduler* sched, const string & mavis_isa_files, @@ -56,7 +56,7 @@ class Simulator : public sparta::app::Simulation rtn, olympia::MavisUnit::name, sparta::TreeNode::GROUP_NAME_NONE, sparta::TreeNode::GROUP_IDX_NONE, "Mavis Unit", &mavis_fact)); - // Create a Source Unit + // Create a Source Unit sparta::ResourceTreeNode* src_unit = new sparta::ResourceTreeNode( rtn, "src", sparta::TreeNode::GROUP_NAME_NONE, sparta::TreeNode::GROUP_IDX_NONE, "Source Unit", &source_fact); @@ -65,7 +65,7 @@ class Simulator : public sparta::app::Simulation auto* src_params = src_unit->getParameterSet(); src_params->getParameter("input_file")->setValueFromString(input_file_); - + // Create the device under test sparta::ResourceTreeNode* bpu = new sparta::ResourceTreeNode(rtn, "bpu", sparta::TreeNode::GROUP_NAME_NONE, @@ -93,16 +93,18 @@ class Simulator : public sparta::app::Simulation // See the README.md for A/B/Cx/Dx // // A - bpu sends prediction request credits to source - sparta::bind(root_node->getChildAs("bpu.ports.out_fetch_predictionRequest_credits"), - root_node->getChildAs("src.ports.in_bpu_predictionRequest_credits")); + sparta::bind( + root_node->getChildAs("bpu.ports.out_fetch_predictionRequest_credits"), + root_node->getChildAs("src.ports.in_bpu_predictionRequest_credits")); // B - source sends prediction request to bpu sparta::bind(root_node->getChildAs("bpu.ports.in_fetch_predictionRequest"), root_node->getChildAs("src.ports.out_bpu_predictionRequest")); // C - sink sends prediction output credits to bpu - sparta::bind(root_node->getChildAs("bpu.ports.in_fetch_predictionOutput_credits"), - root_node->getChildAs("sink.ports.out_bpu_predictionOutput_credits")); + sparta::bind( + root_node->getChildAs("bpu.ports.in_fetch_predictionOutput_credits"), + root_node->getChildAs("sink.ports.out_bpu_predictionOutput_credits")); // D - bpu sends prediction output to sink sparta::bind(root_node->getChildAs("bpu.ports.out_fetch_predictionOutput"), From e1b343d7f3665b897a1132eeb1f522ad46308a00 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 3 Feb 2025 05:02:03 +0530 Subject: [PATCH 03/15] Added BPU counters --- core/fetch/BPU.hpp | 63 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 16a2366b..92a758c9 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -22,7 +22,11 @@ namespace olympia uint64_t PC_; uint8_t instType_; - friend std::ostream & operator<<(std::ostream &, const PredictionRequest &); + + friend std::ostream & operator<<(std::ostream & os, const PredictionRequest &) + { + return os; + } }; class PredictionOutput @@ -32,7 +36,11 @@ namespace olympia bool predDirection_; uint64_t predPC_; - friend std::ostream & operator<<(std::ostream &, const PredictionOutput &); + + friend std::ostream & operator<<(std::ostream & os, const PredictionOutput &) + { + return os; + } }; class UpdateInput @@ -43,7 +51,8 @@ namespace olympia uint64_t instrPC_; bool correctedDirection_; uint64_t correctedTargetPC_; - friend std::ostream & operator<<(std::ostream &, const UpdateInput &); + + friend std::ostream & operator<<(std::ostream & os, const UpdateInput &) { return os; } }; class BPU : @@ -118,6 +127,54 @@ namespace olympia &unit_event_set_, "ev_sendPrediction", CREATE_SPARTA_HANDLER_WITH_DATA(BPU, sendPrediction_, PredictionOutput)}; ***/ + + ////////////////////////////////////////////////////////////////////////////// + // Counters + ////////////////////////////////////////////////////////////////////////////// + sparta::Counter pred_req_num_{getStatisticSet(), "pred_req_num", + "Number of prediction requests", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter mispred_num_{getStatisticSet(), "mispred_num", + "Number of mis-predictions", + sparta::Counter::COUNT_NORMAL}; + sparta::StatisticDef mispred_ratio_{getStatisticSet(), "mispred_ratio", + "Percenatge of mis-prediction", getStatisticSet(), + "mispred_num/pred_req_num"}; + sparta::Counter branch_req_num_{getStatisticSet(), "branch_req_num", + "Number of branch requests", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter call_req_num_{getStatisticSet(), "call_req_num", + "Number of call requests", sparta::Counter::COUNT_NORMAL}; + sparta::Counter return_req_num_{getStatisticSet(), "return_req_num", + "Number of return requests", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter pht_req_num_{getStatisticSet(), "pht_req_num", + "Number of requests made to PHT", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter pht_hit_num_{getStatisticSet(), "pht_hit_num", "Number of hits on PHT", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter pht_miss_num_{getStatisticSet(), "pht_miss_num", + "Number of misses on PHT", sparta::Counter::COUNT_NORMAL}; + sparta::StatisticDef pht_mispred_ratio_{getStatisticSet(), "pht_mispred_ratio", + "Percentage of PHT mis-prediction", + getStatisticSet(), "pht_miss_num/pht_req_num"}; + sparta::Counter btb_req_num_{getStatisticSet(), "btb_req_num", + "Number of requests to BTB", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter btb_hit_num_{getStatisticSet(), "btb_hit_num", "NUmber of BTB hits", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter btb_miss_num_{getStatisticSet(), "btb_miss_num", "Number of BTB misses", + sparta::Counter::COUNT_NORMAL}; + sparta::StatisticDef btb_hit_rate_{getStatisticSet(), "btb_hit_rate", + "Rate of BTB hits", getStatisticSet(), + "btb_hit_num/btb_req_num"}; + sparta::StatisticDef btb_miss_rate_{getStatisticSet(), "btb_miss_rate", + "Rate of BTB misses", getStatisticSet(), + "btb_miss_num/btb_req_num"}; + sparta::Counter ras_high_mark_{getStatisticSet(), "ras_high_mark", "RAS high mark", + sparta::Counter::COUNT_NORMAL}; + sparta::Counter ras_low_mark_{getStatisticSet(), "ras_low_mark", "RAS low mark", + sparta::Counter::COUNT_NORMAL}; }; } // namespace BranchPredictor } // namespace olympia From 3c7204e1734a4dca87254bc4bc824013d4ecbbfb Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 3 Feb 2025 05:08:34 +0530 Subject: [PATCH 04/15] test executable name update --- test/core/bpu/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt index 79c83356..93a8d2dd 100644 --- a/test/core/bpu/CMakeLists.txt +++ b/test/core/bpu/CMakeLists.txt @@ -1,5 +1,5 @@ -set(PRJ "BPU_TESTBENCH") -set(EXE "BPU_TESTBENCH_EXE") +set(PRJ "BPU_test") +set(EXE "BPU_test") set(TST1 "${PRJ}_tst1") set(TST2 "${PRJ}_json") From efa02d3794a81f98e8f13b5e3fbbcb7acb658355 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 3 Feb 2025 06:11:56 +0530 Subject: [PATCH 05/15] Added BPU parameters --- core/fetch/BPU.cpp | 16 +++++++++++++++- core/fetch/BPU.hpp | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index 61b2c889..25e1ef35 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -7,7 +7,21 @@ namespace olympia { const char* BPU::name = "BPU"; - BPU::BPU(sparta::TreeNode* node, const BPUParameterSet* p) : sparta::Unit(node) + BPU::BPU(sparta::TreeNode* node, const BPUParameterSet* p) : + sparta::Unit(node), + ghr_size_(p->ghr_size), + ghr_hash_bits_(p->ghr_hash_bits), + pht_size_(p->pht_size), + ctr_bits_(p->ctr_bits), + btb_size_(p->btb_size), + ras_size_(p->ras_size), + ras_enable_overwrite_(p->ras_enable_overwrite), + tage_bim_table_size_(p->tage_bim_table_size), + tage_bim_ctr_bits_(p->tage_bim_ctr_bits), + tage_tagged_table_num_(p->tage_tagged_table_num), + logical_table_num_(p->logical_table_num), + loop_pred_table_size_(p->loop_pred_table_size), + loop_pred_table_way_(p->loop_pred_table_way) { in_fetch_predictionRequest_.registerConsumerHandler( CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 92a758c9..8671668c 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -65,7 +65,27 @@ namespace olympia public: BPUParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) {} - PARAMETER(uint32_t, ghr_size, 1024, "Number of history bits in GHR"); + // TODO: choose default values properly + // currently values were chosen randomly + PARAMETER(uint32_t, ghr_size, 1024, "Number of branch history bits stored in GHR"); + PARAMETER(uint32_t, ghr_hash_bits, 4, + "Number of bits from GHR used for hashing with PC, to index PHT") + PARAMETER(uint32_t, pht_size, 1024, "Number of entries stored in PHT") + PARAMETER(uint32_t, ctr_bits, 8, + "Number of bits used by counter in PHT to make prediction") + PARAMETER(uint32_t, btb_size, 512, "Maximum possible number of entries in BTB") + PARAMETER(uint32_t, ras_size, 128, "Maximum possible number of entries in RAS") + PARAMETER(bool, ras_enable_overwrite, true, + "New entries on maximum capacity overwrite") + PARAMETER(uint32_t, tage_bim_table_size, 1024, "Size of TAGE bimodal table") + PARAMETER(uint32_t, tage_bim_ctr_bits, 8, + "Number of bits used by TAGE bimodal table to make prediction") + PARAMETER(uint32_t, tage_tagged_table_num, 6, + "Number of tagged components in TAGE predictor") + PARAMETER(uint32_t, logical_table_num, 8, "Number of logical table in SC"); + PARAMETER(uint32_t, loop_pred_table_size, 64, + "Maximum possible entries in loop predictor table") + PARAMETER(uint32_t, loop_pred_table_way, 4, "Way size of loop predictor table") }; BPU(sparta::TreeNode* node, const BPUParameterSet* p); @@ -75,9 +95,6 @@ namespace olympia ~BPU(); - // DefaultPrediction getPrediction(const PredictionRequest &); - // void updatePredictor(const UpdateInput &); - //! \brief Name of this resource. Required by sparta::UnitFactory static const char* name; @@ -90,6 +107,20 @@ namespace olympia void makePrediction_(); void sendPrediction_(); + uint32_t ghr_size_; + uint32_t ghr_hash_bits_; + uint32_t pht_size_; + uint32_t ctr_bits_; + uint32_t btb_size_; + uint32_t ras_size_; + bool ras_enable_overwrite_; + uint32_t tage_bim_table_size_; + uint32_t tage_bim_ctr_bits_; + uint32_t tage_tagged_table_num_; + uint32_t logical_table_num_; + uint32_t loop_pred_table_size_; + uint32_t loop_pred_table_way_; + std::list predictionRequestBuffer_; std::list generatedPredictionOutputBuffer_; uint32_t predictionRequestCredits_ = 0; From c7f74fbf088bd1e757a3b9c9fff9e3e722148ed4 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 3 Feb 2025 19:20:55 +0530 Subject: [PATCH 06/15] Added high level structure of the BasePredictor --- core/fetch/BPU.cpp | 3 +- core/fetch/BPU.hpp | 3 ++ core/fetch/BasePredictor.cpp | 26 ++++++++++++++ core/fetch/BasePredictor.hpp | 68 ++++++++++++++++++++++++++++++++++++ test/core/bpu/CMakeLists.txt | 2 +- 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 core/fetch/BasePredictor.cpp create mode 100644 core/fetch/BasePredictor.hpp diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index 25e1ef35..e0889941 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -21,7 +21,8 @@ namespace olympia tage_tagged_table_num_(p->tage_tagged_table_num), logical_table_num_(p->logical_table_num), loop_pred_table_size_(p->loop_pred_table_size), - loop_pred_table_way_(p->loop_pred_table_way) + loop_pred_table_way_(p->loop_pred_table_way), + base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_) { in_fetch_predictionRequest_.registerConsumerHandler( CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 8671668c..581254be 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -8,6 +8,7 @@ #include "sparta/utils/LogUtils.hpp" #include "BranchPredIF.hpp" +#include "BasePredictor.hpp" #include @@ -126,6 +127,8 @@ namespace olympia uint32_t predictionRequestCredits_ = 0; uint32_t predictionOutputCredits_ = 0; + BasePredictor base_predictor_; + /////////////////////////////////////////////////////////////////////////////// // Ports /////////////////////////////////////////////////////////////////////////////// diff --git a/core/fetch/BasePredictor.cpp b/core/fetch/BasePredictor.cpp new file mode 100644 index 00000000..564d82d4 --- /dev/null +++ b/core/fetch/BasePredictor.cpp @@ -0,0 +1,26 @@ +#include "BasePredictor.hpp" + +namespace olympia +{ + namespace BranchPredictor + { + BasePredictor::BasePredictor(uint32_t pht_size, uint8_t ctr_bits, uint32_t btb_size, + uint32_t ras_size) : + pattern_history_table(pht_size, ctr_bits), + branch_target_buffer(btb_size), + return_address_stack(ras_size) + { + } + + PatternHistoryTable::PatternHistoryTable(uint32_t pht_size, uint8_t ctr_bits) : + pht_size_(pht_size), + ctr_bits_(ctr_bits), + ctr_bits_val_(pow(2, ctr_bits)) + { + } + + BranchTargetBuffer::BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} + + ReturnAddressStack::ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} + } // namespace BranchPredictor +} // namespace olympia \ No newline at end of file diff --git a/core/fetch/BasePredictor.hpp b/core/fetch/BasePredictor.hpp new file mode 100644 index 00000000..14636f47 --- /dev/null +++ b/core/fetch/BasePredictor.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include + +namespace olympia +{ + namespace BranchPredictor + { + class PatternHistoryTable + { + public: + PatternHistoryTable(uint32_t pht_size, uint8_t 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 pht_; + }; + + class BranchTargetBuffer + { + public: + BranchTargetBuffer(uint32_t btb_size); + + bool addEntry(uint64_t PC, uint64_t targetPC); + bool removeEntry(uint64_t PC); + uint64_t getPredictedPC(uint64_t PC); + bool isHit(uint64_t PC); + + private: + const uint32_t btb_size_; + std::map btb_; + }; + + class ReturnAddressStack + { + public: + ReturnAddressStack(uint32_t ras_size); + + void pushAddress(); + uint64_t popAddress(); + + private: + const uint32_t ras_size_; + std::stack ras_; + }; + + class BasePredictor + { + public: + BasePredictor(uint32_t pht_size, uint8_t ctr_bits, uint32_t btb_size, + uint32_t ras_size); + + private: + PatternHistoryTable pattern_history_table; + BranchTargetBuffer branch_target_buffer; + ReturnAddressStack return_address_stack; + }; + } // namespace BranchPredictor +} // namespace olympia \ No newline at end of file diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt index 93a8d2dd..8db93f17 100644 --- a/test/core/bpu/CMakeLists.txt +++ b/test/core/bpu/CMakeLists.txt @@ -11,7 +11,7 @@ set(BPUDir ../../../core/fetch) project(${PRJ}) -add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp BPUSource.hpp BPUSink.hpp) +add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp ${BPUDir}/BasePredictor.cpp ${BPUDir}/BasePredictor.hpp BPUSource.hpp BPUSink.hpp) target_include_directories(${EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(${EXE} core common_test ${STF_LINK_LIBS} mavis SPARTA::sparta) From 68e0381700957e9b8aa0577b0fbfb2113a2e0e44 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Thu, 6 Feb 2025 20:57:51 +0530 Subject: [PATCH 07/15] Functions of BasePredictor --- core/fetch/BasePredictor.cpp | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/core/fetch/BasePredictor.cpp b/core/fetch/BasePredictor.cpp index 564d82d4..e5292c19 100644 --- a/core/fetch/BasePredictor.cpp +++ b/core/fetch/BasePredictor.cpp @@ -19,8 +19,80 @@ namespace olympia { } + void PatternHistoryTable::incrementCounter(uint32_t idx) + { + if(pht_.find(idx) != pht_.end()) { + if(pht_[idx] < ctr_bits_val_) { + pht_[idx]++; + } + } + } + + void PatternHistoryTable::decrementCounter(uint32_t idx) + { + if(pht_.find(idx) != pht_.end()) { + if(pht_[idx] > 0) { + pht_[idx]--; + } + } + } + + uint8_t PatternHistoryTable::getPrediction(uint32_t idx) + { + if(pht_.find(idx) != pht_.end()) { + return pht_[idx]; + } + else { + return 0; + } + } + BranchTargetBuffer::BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} + bool BranchTargetBuffer::addEntry(uint64_t PC, uint64_t targetPC) + { + if(btb_.size() < btb_size_) { + btb_[PC] = targetPC; + return true; + } + return false; + } + + bool BranchTargetBuffer::removeEntry(uint64_t PC) + { + return btb_.erase(PC); + } + + uint64_t BranchTargetBuffer::getPredictedPC(uint64_t PC) + { + if(isHit(PC)) { + return btb_[PC]; + } + else { + return 0; // change it later + } + } + + bool BranchTargetBuffer::isHit(uint64_t PC) + { + if(btb_.find(PC) != btb_.end()) { + return true; + } + else { + return false; + } + } + ReturnAddressStack::ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} + + void ReturnAddressStack::pushAddress() + { + + } + + uint64_t ReturnAddressStack::popAddress() + { + return 0; + } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file From 304ae3cbc3891e34c84a2eee919c5013e2d3f886 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 10 Mar 2025 05:26:02 +0530 Subject: [PATCH 08/15] Added skeleton body of TAGE --- core/fetch/BPU.hpp | 3 +- core/fetch/BasePredictor.cpp | 74 ++++++++++++++++----------- core/fetch/BasePredictor.hpp | 11 +++-- core/fetch/CMakeLists.txt | 3 ++ core/fetch/TAGE_SC_L.cpp | 83 +++++++++++++++++++++++++++++++ core/fetch/TAGE_SC_L.hpp | 96 ++++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 35 deletions(-) create mode 100644 core/fetch/TAGE_SC_L.cpp create mode 100644 core/fetch/TAGE_SC_L.hpp diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 581254be..9e0221c6 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -9,6 +9,7 @@ #include "BranchPredIF.hpp" #include "BasePredictor.hpp" +#include "TAGE_SC_L.hpp" #include @@ -83,7 +84,7 @@ namespace olympia "Number of bits used by TAGE bimodal table to make prediction") PARAMETER(uint32_t, tage_tagged_table_num, 6, "Number of tagged components in TAGE predictor") - PARAMETER(uint32_t, logical_table_num, 8, "Number of logical table in SC"); + PARAMETER(uint32_t, logical_table_num, 8, "Number of logical table in SC") PARAMETER(uint32_t, loop_pred_table_size, 64, "Maximum possible entries in loop predictor table") PARAMETER(uint32_t, loop_pred_table_way, 4, "Way size of loop predictor table") diff --git a/core/fetch/BasePredictor.cpp b/core/fetch/BasePredictor.cpp index e5292c19..4514d56f 100644 --- a/core/fetch/BasePredictor.cpp +++ b/core/fetch/BasePredictor.cpp @@ -6,9 +6,9 @@ namespace olympia { BasePredictor::BasePredictor(uint32_t pht_size, uint8_t ctr_bits, uint32_t btb_size, uint32_t ras_size) : - pattern_history_table(pht_size, ctr_bits), - branch_target_buffer(btb_size), - return_address_stack(ras_size) + pattern_history_table_(pht_size, ctr_bits), + branch_target_buffer_(btb_size), + return_address_stack_(ras_size) { } @@ -21,8 +21,10 @@ namespace olympia void PatternHistoryTable::incrementCounter(uint32_t idx) { - if(pht_.find(idx) != pht_.end()) { - if(pht_[idx] < ctr_bits_val_) { + if (pht_.find(idx) != pht_.end()) + { + if (pht_[idx] < ctr_bits_val_) + { pht_[idx]++; } } @@ -30,8 +32,10 @@ namespace olympia void PatternHistoryTable::decrementCounter(uint32_t idx) { - if(pht_.find(idx) != pht_.end()) { - if(pht_[idx] > 0) { + if (pht_.find(idx) != pht_.end()) + { + if (pht_[idx] > 0) + { pht_[idx]--; } } @@ -39,60 +43,72 @@ namespace olympia uint8_t PatternHistoryTable::getPrediction(uint32_t idx) { - if(pht_.find(idx) != pht_.end()) { + if (pht_.find(idx) != pht_.end()) + { return pht_[idx]; } - else { + else + { return 0; } } + // Branch Target Buffer BranchTargetBuffer::BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} bool BranchTargetBuffer::addEntry(uint64_t PC, uint64_t targetPC) { - if(btb_.size() < btb_size_) { + if (btb_.size() < btb_size_) + { btb_[PC] = targetPC; return true; } return false; } - bool BranchTargetBuffer::removeEntry(uint64_t PC) + bool BranchTargetBuffer::removeEntry(uint64_t PC) { return btb_.erase(PC); } + + bool BranchTargetBuffer::isHit(uint64_t PC) { - return btb_.erase(PC); + if (btb_.find(PC) != btb_.end()) + { + return true; + } + else + { + return false; + } } uint64_t BranchTargetBuffer::getPredictedPC(uint64_t PC) { - if(isHit(PC)) { + if (isHit(PC)) + { return btb_[PC]; } - else { + else + { return 0; // change it later } } - bool BranchTargetBuffer::isHit(uint64_t PC) + // Return Address Stack + ReturnAddressStack::ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} + + void ReturnAddressStack::pushAddress(uint64_t PC) { - if(btb_.find(PC) != btb_.end()) { - return true; + if (ras_.size() < ras_size_) + { + ras_.push(PC); } - else { - return false; + else + { + return; } } - ReturnAddressStack::ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} - - void ReturnAddressStack::pushAddress() - { + uint64_t ReturnAddressStack::popAddress() { return 0; } - } - - uint64_t ReturnAddressStack::popAddress() - { - return 0; - } + uint32_t ReturnAddressStack::getSize() { return ras_.size(); } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/BasePredictor.hpp b/core/fetch/BasePredictor.hpp index 14636f47..e52bb061 100644 --- a/core/fetch/BasePredictor.hpp +++ b/core/fetch/BasePredictor.hpp @@ -32,8 +32,8 @@ namespace olympia bool addEntry(uint64_t PC, uint64_t targetPC); bool removeEntry(uint64_t PC); - uint64_t getPredictedPC(uint64_t PC); bool isHit(uint64_t PC); + uint64_t getPredictedPC(uint64_t PC); private: const uint32_t btb_size_; @@ -45,8 +45,9 @@ namespace olympia public: ReturnAddressStack(uint32_t ras_size); - void pushAddress(); + void pushAddress(uint64_t PC); uint64_t popAddress(); + uint32_t getSize(); private: const uint32_t ras_size_; @@ -60,9 +61,9 @@ namespace olympia uint32_t ras_size); private: - PatternHistoryTable pattern_history_table; - BranchTargetBuffer branch_target_buffer; - ReturnAddressStack return_address_stack; + PatternHistoryTable pattern_history_table_; + BranchTargetBuffer branch_target_buffer_; + ReturnAddressStack return_address_stack_; }; } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/CMakeLists.txt b/core/fetch/CMakeLists.txt index c1ba38a0..76e2651a 100644 --- a/core/fetch/CMakeLists.txt +++ b/core/fetch/CMakeLists.txt @@ -2,5 +2,8 @@ add_library(fetch Fetch.cpp ICache.cpp SimpleBranchPred.cpp + BasePredictor.cpp + TAGE_SC_L.cpp + BPU.cpp ) target_link_libraries(fetch instgen) diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp new file mode 100644 index 00000000..0a7db162 --- /dev/null +++ b/core/fetch/TAGE_SC_L.cpp @@ -0,0 +1,83 @@ +#include "TAGE_SC_L.hpp" + +namespace olympia +{ + namespace BranchPredictor + { + + // Tage Tagged Component Entry + TageTaggedComponentEntry::TageTaggedComponentEntry(uint8_t tage_ctr_bits, + uint8_t tage_useful_bits) : + tage_ctr_bits_(tage_ctr_bits), + tage_useful_bits_(tage_useful_bits) + { + } + + void TageTaggedComponentEntry::incrementCtr() {} + + void TageTaggedComponentEntry::decrementCtr() {} + + void TageTaggedComponentEntry::incrementUseful() {} + + void TageTaggedComponentEntry::decrementUseful() {} + + // Tagged component + TageTaggedComponent::TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, + uint16_t num_tagged_entry) : + tage_ctr_bits_(tage_ctr_bits), + tage_useful_bits_(tage_useful_bits), + num_tagged_entry_(num_tagged_entry), + tage_tagged_component_(num_tagged_entry_, {tage_ctr_bits_, tage_useful_bits_}) + { + } + + // Tage Bimodal + TageBIM::TageBIM(uint32_t tage_bim_table_size, uint8_t tage_base_ctr_bits) : + tage_bim_table_size_(tage_bim_table_size), + tage_base_ctr_bits_(tage_base_ctr_bits) + { + // recheck value + tage_base_max_ctr_ = 2 << tage_base_ctr_bits_; + + // initialize counter at all index to be 0 + for (auto & val : Tage_Bimodal_) + { + val = 0; + } + } + + void TageBIM::incrementCtr(uint32_t ip) + { + if (Tage_Bimodal_[ip] < tage_base_max_ctr_) + { + Tage_Bimodal_[ip]++; + } + } + + void TageBIM::decrementCtr(uint32_t ip) + { + if (Tage_Bimodal_[ip] > 0) + { + Tage_Bimodal_[ip]--; + } + } + + uint8_t TageBIM::getPrediction(uint32_t ip) { return Tage_Bimodal_[ip]; } + + // TAGE + Tage::Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, + uint8_t tage_tagged_ctr_bits, uint8_t tage_tagged_useful_bits, + uint8_t num_tage_component) : + tage_bim_table_size_(tage_bim_table_size), + tage_bim_ctr_bits_(tage_bim_ctr_bits), + tage_tagged_ctr_bits_(tage_tagged_ctr_bits), + tage_tagged_useful_bits_(tage_tagged_useful_bits), + num_tage_component_(num_tage_component), + tage_bim_(tage_bim_table_size_, tage_bim_table_size_), + // for now number of tagged component entry in each component is set as 10 + tage_tagged_components_(num_tage_component_, + {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, 10}) + { + } + } // namespace BranchPredictor +} // namespace olympia \ No newline at end of file diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp new file mode 100644 index 00000000..9e848dc9 --- /dev/null +++ b/core/fetch/TAGE_SC_L.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +namespace olympia +{ + namespace BranchPredictor + { + class TageTaggedComponentEntry + { + public: + TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits); + + void incrementCtr(); + void decrementCtr(); + void incrementUseful(); + void decrementUseful(); + + private: + uint16_t tag_; + uint8_t tage_ctr_bits_; + uint8_t tage_useful_bits_; + uint8_t ctr_; + uint8_t useful_; + }; + + class TageTaggedComponent + { + public: + TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, + uint16_t num_tagged_entry); + + private: + uint8_t tage_ctr_bits_; + uint8_t tage_useful_bits_; + uint16_t num_tagged_entry_; + std::vector tage_tagged_component_; + }; + + class TageBIM + { + public: + TageBIM(uint32_t tage_bim_table_size, uint8_t tage_base_ctr_bits); + + void incrementCtr(uint32_t ip); + void decrementCtr(uint32_t ip); + uint8_t getPrediction(uint32_t ip); + + private: + uint32_t tage_bim_table_size_; + uint8_t tage_base_ctr_bits_; + uint8_t tage_base_max_ctr_; + std::vector Tage_Bimodal_; + }; + + class Tage + { + public: + Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, + uint8_t tage_tagged_ctr_bits, uint8_t tage_tagged_useful_bits, + uint8_t num_tage_component); + + private: + uint32_t tage_bim_table_size_; + uint8_t tage_bim_ctr_bits_; + uint8_t tage_tagged_ctr_bits_; + uint8_t tage_tagged_useful_bits_; + uint8_t num_tage_component_; + + TageBIM tage_bim_; + std::vector tage_tagged_components_; + }; + + class StatisticalCorrector + { + public: + private: + }; + + class LoopPredictor + { + public: + private: + }; + + class TAGE_SC_L + { + public: + private: + Tage tage; + StatisticalCorrector sc; + LoopPredictor l; + }; + } // namespace BranchPredictor +} // namespace olympia \ No newline at end of file From e076b56a47bbe8f034bc75f54cdefe1277b8fe8f Mon Sep 17 00:00:00 2001 From: Shobhit Date: Mon, 10 Mar 2025 06:18:28 +0530 Subject: [PATCH 09/15] Added generic prediction and more constructor parameters for TAGE --- core/fetch/TAGE_SC_L.cpp | 23 ++++++++++++++++++----- core/fetch/TAGE_SC_L.hpp | 17 +++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp index 0a7db162..bf123675 100644 --- a/core/fetch/TAGE_SC_L.cpp +++ b/core/fetch/TAGE_SC_L.cpp @@ -66,18 +66,31 @@ namespace olympia // TAGE Tage::Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint8_t tage_tagged_ctr_bits, uint8_t tage_tagged_useful_bits, - uint8_t num_tage_component) : + uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, + uint8_t tage_tagged_useful_bits, uint32_t tage_global_hist_buff_len, + uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, + uint32_t tage_reset_useful_interval, uint8_t tage_num_component) : tage_bim_table_size_(tage_bim_table_size), tage_bim_ctr_bits_(tage_bim_ctr_bits), + tage_max_index_bits_(tage_max_index_bits), tage_tagged_ctr_bits_(tage_tagged_ctr_bits), tage_tagged_useful_bits_(tage_tagged_useful_bits), - num_tage_component_(num_tage_component), + tage_global_hist_buff_len_(tage_global_hist_buff_len), + tage_min_hist_len_(tage_min_hist_len), + tage_hist_alpha_(tage_hist_alpha), + tage_reset_useful_interval_(tage_reset_useful_interval), + tage_num_component_(tage_num_component), tage_bim_(tage_bim_table_size_, tage_bim_table_size_), // for now number of tagged component entry in each component is set as 10 - tage_tagged_components_(num_tage_component_, - {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, 10}) + tage_tagged_components_(tage_num_component_, + {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, 10}), + global_history_buff_(tage_global_hist_buff_len, 0) { } + + // for now return 1 + uint8_t Tage::predict(uint64_t ip) { + return 1; + } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index 9e848dc9..4ffa69b3 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -58,18 +58,27 @@ namespace olympia { public: Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint8_t tage_tagged_ctr_bits, uint8_t tage_tagged_useful_bits, - uint8_t num_tage_component); + uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, + uint8_t tage_tagged_useful_bits, uint32_t tage_global_hist_buff_len, + uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, + uint32_t tage_reset_useful_interval, uint8_t tage_num_component); + + uint8_t predict(uint64_t ip); private: uint32_t tage_bim_table_size_; uint8_t tage_bim_ctr_bits_; + uint16_t tage_max_index_bits_; uint8_t tage_tagged_ctr_bits_; uint8_t tage_tagged_useful_bits_; - uint8_t num_tage_component_; - + uint32_t tage_global_hist_buff_len_; + uint32_t tage_min_hist_len_; + uint8_t tage_hist_alpha_; + uint32_t tage_reset_useful_interval_; + uint8_t tage_num_component_; TageBIM tage_bim_; std::vector tage_tagged_components_; + std::vector global_history_buff_; }; class StatisticalCorrector From a9f46d6dc8cc337223cdaf8889c1a59d5591a971 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Sat, 22 Mar 2025 11:23:19 +0530 Subject: [PATCH 10/15] Minimally working BPU testbench --- core/FTQ.cpp | 94 ++++++++++++ core/FTQ.hpp | 87 +++++++++++ core/fetch/BPU.cpp | 136 ++++++++++++------ core/fetch/BPU.hpp | 97 +++++++------ core/fetch/CMakeLists.txt | 4 +- core/fetch/TAGE_SC_L.cpp | 8 +- core/fetch/TAGE_SC_L.hpp | 41 +++--- test/core/bpu/BPUSink.hpp | 38 ++--- test/core/bpu/BPUSource.hpp | 51 +++++-- test/core/bpu/BPU_testbench.cpp | 83 ++++++++--- test/core/bpu/CMakeLists.txt | 9 +- .../expected_output/bpu_tb_json.out.EXPECTED | 26 ++++ test/core/bpu/json/branch.json | 38 ++++- 13 files changed, 546 insertions(+), 166 deletions(-) create mode 100644 core/FTQ.cpp create mode 100644 core/FTQ.hpp create mode 100644 test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED diff --git a/core/FTQ.cpp b/core/FTQ.cpp new file mode 100644 index 00000000..4959b25a --- /dev/null +++ b/core/FTQ.cpp @@ -0,0 +1,94 @@ +#include "FTQ.hpp" + +namespace olympia +{ + const char* FTQ::name = "ftq"; + + FTQ::FTQ(sparta::TreeNode *node, const FTQParameterSet *p) : + sparta::Unit(node), + ftq_capacity_(p->ftq_capacity) + { + in_bpu_first_prediction_output_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getFirstPrediction_, BranchPredictor::PredictionOutput)); + + in_bpu_second_prediction_output_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getSecondPrediction_, BranchPredictor::PredictionOutput)); + + in_fetch_credits_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getFetchCredits_, uint32_t)); + + /**in_rob_signal_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getROBSignal_, uint32_t)); + **/ + sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(FTQ, sendInitialCreditsToBPU_)); + } + + FTQ::~FTQ() {} + + void FTQ::sendInitialCreditsToBPU_() + { + sendCreditsToBPU_(5); + } + + void FTQ::sendCreditsToBPU_(const uint32_t & credits) + { + ILOG("FTQ: Sending " << credits << " credits to BPU"); + out_bpu_credits_.send(credits); + } + + void FTQ::getFirstPrediction_(const BranchPredictor::PredictionOutput & prediction) + { + if(fetch_target_queue_.size() < ftq_capacity_) { + ILOG("FTQ: Received first PredictionOutput from BPU"); + fetch_target_queue_.push(prediction); + + sendPrediction_(); + } + } + + void FTQ::getSecondPrediction_(const BranchPredictor::PredictionOutput & prediction) + { + // check if it matches the prediction made by first tier of bpu + + + } + + void FTQ::getFetchCredits_(const uint32_t & credits) + { + ILOG("FTQ: Received " << credits << " credits from Fetch") + fetchCredits_ += credits; + + sendPrediction_(); + } + + void FTQ::sendPrediction_() + { + ILOG("In sendPrediction function") + if(fetchCredits_ > 0) { + ILOG("fetchCredits > 0"); + // send prediction to Fetch + if(fetch_target_queue_.size() > 0) { + fetchCredits_--; + ILOG("FTQ: Send prediction to Fetch"); + auto output = fetch_target_queue_.front(); + fetch_target_queue_.pop(); + out_fetch_prediction_output_.send(output); + } + } + } + + void FTQ::firstMispredictionFlush_() + { + + } + + void FTQ::getROBSignal_(const uint32_t & signal) + { + + } + + void FTQ::deallocateEntry_() + { + + } +} \ No newline at end of file diff --git a/core/FTQ.hpp b/core/FTQ.hpp new file mode 100644 index 00000000..1d60960b --- /dev/null +++ b/core/FTQ.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/UniqueEvent.hpp" +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/ParameterSet.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/log/MessageSource.hpp" +#include "sparta/utils/DataContainer.hpp" + +#include "fetch/BPU.hpp" +#include "ROB.hpp" +#include "FlushManager.hpp" + +#include + +namespace olympia +{ + class FTQ : public sparta::Unit + { + public: + class FTQParameterSet : public sparta::ParameterSet + { + public: + FTQParameterSet(sparta::TreeNode *n) : + sparta::ParameterSet(n) + {} + + // for now set default to 10, chnage it later + PARAMETER(uint32_t, ftq_capacity, 10, "Capacity of fetch target queue") + }; + + static const char* name; + + FTQ(sparta::TreeNode *node, + const FTQParameterSet *p); + + ~FTQ(); + + private: + const uint32_t ftq_capacity_; + uint32_t fetchCredits_ = 0; + std::queue fetch_target_queue_; + + sparta::DataInPort in_bpu_first_prediction_output_ + {&unit_port_set_, "in_bpu_first_prediction_output", 1}; + sparta::DataInPort in_bpu_second_prediction_output_ + {&unit_port_set_, "in_bpu_second_prediction_output", 1}; + sparta::DataInPort in_fetch_credits_ + {&unit_port_set_, "in_fetch_credits", 1}; + /**sparta::DataOutPort out_first_misprediction_flush_ + {&unit_port_set_, "out_first_misprediction_flush", 1};***/ + sparta::DataOutPort out_fetch_prediction_output_ + {&unit_port_set_, "out_fetch_prediction_output", 1}; + /***sparta::DataInPort in_rob_signal_ {&unit_port_set_, "in_rob_signal", 1}; ***/ + sparta::DataOutPort out_bpu_update_input_ + {&unit_port_set_, "out_bpu_update_input", 1}; + sparta::DataOutPort out_bpu_credits_ + {&unit_port_set_, "out_bpu_credits", 1}; + + + void sendInitialCreditsToBPU_(); + + void sendCreditsToBPU_(const uint32_t &); + + // receives prediction from BasePredictor and pushes it into FTQ + void getFirstPrediction_(const BranchPredictor::PredictionOutput &); + + // receives prediction from TAGE_SC_L, checks if there's a mismatch + // updates ftq appropriately + void getSecondPrediction_(const BranchPredictor::PredictionOutput &); + + void getFetchCredits_(const uint32_t &); + + // continuously send instructions to fetch/icache + void sendPrediction_(); + + // flushes instruction if first prediction does not matvh second prediction + void firstMispredictionFlush_(); + + // receives branch resolution signal from ROB at the time of commit + void getROBSignal_(const uint32_t & signal); + + // deallocate FTQ entry once branch instruction is committed + void deallocateEntry_(); + }; +} \ No newline at end of file diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index e0889941..cc9da414 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -5,7 +5,7 @@ namespace olympia { namespace BranchPredictor { - const char* BPU::name = "BPU"; + const char* BPU::name = "bpu"; BPU::BPU(sparta::TreeNode* node, const BPUParameterSet* p) : sparta::Unit(node), @@ -21,75 +21,121 @@ namespace olympia tage_tagged_table_num_(p->tage_tagged_table_num), logical_table_num_(p->logical_table_num), loop_pred_table_size_(p->loop_pred_table_size), - loop_pred_table_way_(p->loop_pred_table_way), - base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_) + loop_pred_table_way_(p->loop_pred_table_way) + //base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_) { - in_fetch_predictionRequest_.registerConsumerHandler( - CREATE_SPARTA_HANDLER_WITH_DATA(BPU, recievePredictionRequest_, PredictionRequest)); + sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(BPU, sendIntitialCreditsToFetch_)); - in_fetch_predictionOutput_credits_.registerConsumerHandler( - CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionOutputCredits_, uint32_t)); + in_fetch_prediction_request_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getPredictionRequest_, PredictionRequest)); + + in_ftq_credits_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getCreditsFromFTQ_, uint32_t)); + + in_ftq_update_input_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getUpdateInput_, UpdateInput)); } - PredictionOutput BPU::getPrediction(const PredictionRequest & pred) - { + BPU::~BPU() {} + + PredictionOutput BPU::getPrediction(const PredictionRequest &) { PredictionOutput output; output.predDirection_ = true; - output.predPC_ = 0x0220; - + output.predPC_ = 5; return output; } - void BPU::updatePredictor(const UpdateInput & update) {} - - BPU::~BPU() {} + void BPU::updatePredictor(const UpdateInput &) { - void BPU::sendPredictionRequestCredits_(uint32_t credits) - { - ILOG("Send prediction request credits to Fetch"); - out_fetch_predictionRequest_credits_.send(credits); } - void BPU::sendInitialPredictionRequestCredits_() - { - ILOG("Sending initial prediction request credits to Fetch"); - sendPredictionRequestCredits_(1); - } + void BPU::getPredictionRequest_(const PredictionRequest & request) { + predictionRequestBuffer_.push_back(request); + ILOG("BPU: received PredictionRequest from Fetch"); - void BPU::recievePredictionRequest_(const PredictionRequest & predReq) - { - ILOG("Received prediction request from Fetch"); - predictionRequestBuffer_.push_back(predReq); + makePrediction_(); } - // void BPU::recievePredictionUpdate_() - //{} + void BPU::makePrediction_() { + ILOG("making prediction"); + std::cout << "making prediction\n"; + if(predictionRequestBuffer_.size() > 0) { + //auto input = predictionRequestBuffer_.front(); + predictionRequestBuffer_.pop_front(); + + // call base predictor on input + PredictionOutput output; + + output.predDirection_ = true; + output.predPC_ = 100; + generatedPredictionOutputBuffer_.push_back(output); + + // call tage_sc_l on input + } + } - void BPU::receivePredictionOutputCredits_(const uint32_t & credits) - { - ILOG("Recieve prediction output credits from Fetch"); + void BPU::getCreditsFromFTQ_(const uint32_t & credits) { predictionOutputCredits_ += credits; - } + ILOG("BPU: received " << credits << " credits from FTQ"); - void BPU::makePrediction_() - { - PredictionOutput output; - output.predDirection_ = true; - output.predPC_ = 100000; - generatedPredictionOutputBuffer_.push_back(output); + sendFirstPrediction_(); } - void BPU::sendPrediction_() - { - if (predictionOutputCredits_ > 0) + + void BPU::sendFirstPrediction_() { + ILOG("SendFirstPrediction starting"); + // take first PredictionRequest from buffer + if(predictionOutputCredits_ > 0) { - ILOG("Sending prediction output to fetch"); - auto predOutput = generatedPredictionOutputBuffer_.front(); + auto firstPrediction = generatedPredictionOutputBuffer_.front(); generatedPredictionOutputBuffer_.pop_front(); - out_fetch_predictionOutput_.send(predOutput); + ILOG("BPU: Sending first PredictionOutput to FTQ"); + out_ftq_first_prediction_output_.send(firstPrediction); predictionOutputCredits_--; } } + /** + void BPU::sendSecondPrediction_() { + // send prediction made by TAGE_SC_L + } +***/ + void BPU::getUpdateInput_(const UpdateInput & input) { + //internal_update_input_ = input; + + ILOG("BPU: received UpdateInput from FTQ"); + + // updateBPU_(internal_update_input_); + } + /** + + void BPU::updateBPU_(const UpdateInput & input) { + + // Update internal state of BasePredictor according to UpdateInput received + //base_predictor_.update(input); + + // Update internal state of TAGE_SC_L according to UpdateInput received + // TODO + // tage_sc_l.update(input); + } + **/ + + + void BPU::sendCreditsToFetch_(const uint32_t & credits) { + ILOG("BPU: Send " << credits << " credits to Fetch"); + out_fetch_credits_.send(credits); + } + + void BPU::sendIntitialCreditsToFetch_() { + sendCreditsToFetch_(pred_req_buffer_capacity_); + } + + void BPU::updateGHRTaken_() { + + } + + void BPU::updateGHRNotTaken_() { + + } } // namespace BranchPredictor } // namespace olympia diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 9e0221c6..6c7e479e 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -48,7 +48,8 @@ namespace olympia class UpdateInput { public: - UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) {} + UpdateInput() {} + //UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) {} uint64_t instrPC_; bool correctedDirection_; @@ -92,68 +93,78 @@ namespace olympia BPU(sparta::TreeNode* node, const BPUParameterSet* p); + ~BPU(); + PredictionOutput getPrediction(const PredictionRequest &); void updatePredictor(const UpdateInput &); - ~BPU(); - //! \brief Name of this resource. Required by sparta::UnitFactory static const char* name; private: - void sendPredictionRequestCredits_(uint32_t credits); - void sendInitialPredictionRequestCredits_(); - void recievePredictionRequest_(const PredictionRequest & predReq); - // void recievePredictionUpdate_(); - void receivePredictionOutputCredits_(const uint32_t & credits); + void getPredictionRequest_(const PredictionRequest &); void makePrediction_(); - void sendPrediction_(); - - uint32_t ghr_size_; - uint32_t ghr_hash_bits_; - uint32_t pht_size_; - uint32_t ctr_bits_; - uint32_t btb_size_; - uint32_t ras_size_; - bool ras_enable_overwrite_; - uint32_t tage_bim_table_size_; - uint32_t tage_bim_ctr_bits_; - uint32_t tage_tagged_table_num_; - uint32_t logical_table_num_; - uint32_t loop_pred_table_size_; - uint32_t loop_pred_table_way_; + void getCreditsFromFTQ_(const uint32_t &); + void sendFirstPrediction_(); + void sendSecondPrediction_(); + void getUpdateInput_(const UpdateInput &); + void updateBPU_(const UpdateInput &); + void sendCreditsToFetch_(const uint32_t &); + void sendIntitialCreditsToFetch_(); + void updateGHRTaken_(); + void updateGHRNotTaken_(); + + const uint32_t ghr_size_; + const uint32_t ghr_hash_bits_; + const uint32_t pht_size_; + const uint32_t ctr_bits_; + const uint32_t btb_size_; + const uint32_t ras_size_; + const bool ras_enable_overwrite_; + const uint32_t tage_bim_table_size_; + const uint32_t tage_bim_ctr_bits_; + const uint32_t tage_tagged_table_num_; + const uint32_t logical_table_num_; + const uint32_t loop_pred_table_size_; + const uint32_t loop_pred_table_way_; std::list predictionRequestBuffer_; std::list generatedPredictionOutputBuffer_; - uint32_t predictionRequestCredits_ = 0; + const uint32_t pred_req_buffer_capacity_ = 10; uint32_t predictionOutputCredits_ = 0; + //UpdateInput internal_update_input_; - BasePredictor base_predictor_; + //BasePredictor base_predictor_; /////////////////////////////////////////////////////////////////////////////// // Ports /////////////////////////////////////////////////////////////////////////////// - // Internal DataInPort from fetch unit for prediction request - sparta::DataInPort in_fetch_predictionRequest_{ - &unit_port_set_, "in_fetch_predictionRequest", sparta::SchedulingPhase::Tick, 0}; + // Internal DataInPort from Fetch unit for PredictionRequest + sparta::DataInPort in_fetch_prediction_request_{ + &unit_port_set_, "in_fetch_prediction_request", sparta::SchedulingPhase::Tick, 0}; - // Internal DataInPort from fetch unit for credits to indicate - // availabilty of slots for sending prediction output - sparta::DataInPort in_fetch_predictionOutput_credits_{ - &unit_port_set_, "in_fetch_predictionOutput_credits", sparta::SchedulingPhase::Tick, + // Internal DataInPort from FTQ unit for credits to indicate + // availabilty of slots for sending PredictionOutput + sparta::DataInPort in_ftq_credits_{ + &unit_port_set_, "in_ftq_credits", sparta::SchedulingPhase::Tick, 0}; - - // TODO - - // DataOutPort to fetch unit to send credits to indicate availability - // of slots to receive prediction request - sparta::DataOutPort out_fetch_predictionRequest_credits_{ - &unit_port_set_, "out_fetch_predictionRequest_credits"}; - - // DataOutPort to fetch unit to send prediction output - sparta::DataOutPort out_fetch_predictionOutput_{ - &unit_port_set_, "out_fetch_predictionOutput"}; + // Internal DataInPort from FTQ for UpdateInput + sparta::DataInPort in_ftq_update_input_{ + &unit_port_set_, "in_ftq_update_input", sparta::SchedulingPhase::Tick, 0}; + + // DataOutPort to Fetch unit to send credits to indicate availability + // of slots to receive PredictionRequest + sparta::DataOutPort out_fetch_credits_{ + &unit_port_set_, "out_fetch_credits"}; + + // DataOutPort to FTQ unit to send prediction made by BasePredictor + sparta::DataOutPort out_ftq_first_prediction_output_{ + &unit_port_set_, "out_ftq_first_prediction_output"}; + + // DataOutPort to FTQ unit to send prediction made by TAGE_SC_L + sparta::DataOutPort out_ftq_second_prediction_output_{ + &unit_port_set_, "out_ftq_second_prediction_output"}; ////////////////////////////////////////////////////////////////////////////// // Events diff --git a/core/fetch/CMakeLists.txt b/core/fetch/CMakeLists.txt index 76e2651a..a4543cb3 100644 --- a/core/fetch/CMakeLists.txt +++ b/core/fetch/CMakeLists.txt @@ -2,8 +2,8 @@ add_library(fetch Fetch.cpp ICache.cpp SimpleBranchPred.cpp - BasePredictor.cpp - TAGE_SC_L.cpp + #BasePredictor.cpp + #TAGE_SC_L.cpp BPU.cpp ) target_link_libraries(fetch instgen) diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp index bf123675..aff2f48e 100644 --- a/core/fetch/TAGE_SC_L.cpp +++ b/core/fetch/TAGE_SC_L.cpp @@ -7,9 +7,13 @@ namespace olympia // Tage Tagged Component Entry TageTaggedComponentEntry::TageTaggedComponentEntry(uint8_t tage_ctr_bits, - uint8_t tage_useful_bits) : + uint8_t tage_useful_bits, + uint8_t ctr_initial, + uint8_t useful_initial) : tage_ctr_bits_(tage_ctr_bits), - tage_useful_bits_(tage_useful_bits) + tage_useful_bits_(tage_useful_bits), + ctr_(ctr_initial), + useful_(useful_initial) { } diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index 4ffa69b3..1db3860e 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -10,17 +10,20 @@ namespace olympia class TageTaggedComponentEntry { public: - TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits); + TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, + uint8_t ctr_initial, uint8_t useful_initial); void incrementCtr(); void decrementCtr(); void incrementUseful(); void decrementUseful(); + uint16_t tag; + private: - uint16_t tag_; - uint8_t tage_ctr_bits_; - uint8_t tage_useful_bits_; + const uint8_t tage_ctr_bits_; + const uint8_t tage_useful_bits_; + uint8_t ctr_; uint8_t useful_; }; @@ -32,9 +35,9 @@ namespace olympia uint16_t num_tagged_entry); private: - uint8_t tage_ctr_bits_; - uint8_t tage_useful_bits_; - uint16_t num_tagged_entry_; + const uint8_t tage_ctr_bits_; + const uint8_t tage_useful_bits_; + const uint16_t num_tagged_entry_; std::vector tage_tagged_component_; }; @@ -48,9 +51,9 @@ namespace olympia uint8_t getPrediction(uint32_t ip); private: - uint32_t tage_bim_table_size_; - uint8_t tage_base_ctr_bits_; - uint8_t tage_base_max_ctr_; + const uint32_t tage_bim_table_size_; + const uint8_t tage_bim_ctr_bits_; + const uint8_t tage_bim_max_ctr_; std::vector Tage_Bimodal_; }; @@ -66,16 +69,16 @@ namespace olympia uint8_t predict(uint64_t ip); private: - uint32_t tage_bim_table_size_; - uint8_t tage_bim_ctr_bits_; + const uint32_t tage_bim_table_size_; + const uint8_t tage_bim_ctr_bits_; uint16_t tage_max_index_bits_; - uint8_t tage_tagged_ctr_bits_; - uint8_t tage_tagged_useful_bits_; - uint32_t tage_global_hist_buff_len_; - uint32_t tage_min_hist_len_; - uint8_t tage_hist_alpha_; - uint32_t tage_reset_useful_interval_; - uint8_t tage_num_component_; + const uint8_t tage_tagged_ctr_bits_; + const uint8_t tage_tagged_useful_bits_; + const uint32_t tage_global_hist_buff_len_; + const uint32_t tage_min_hist_len_; + const uint8_t tage_hist_alpha_; + const uint32_t tage_reset_useful_interval_; + const uint8_t tage_num_component_; TageBIM tage_bim_; std::vector tage_tagged_components_; std::vector global_history_buff_; diff --git a/test/core/bpu/BPUSink.hpp b/test/core/bpu/BPUSink.hpp index 591e0ba1..8ba53712 100644 --- a/test/core/bpu/BPUSink.hpp +++ b/test/core/bpu/BPUSink.hpp @@ -26,39 +26,45 @@ namespace bpu_test BPUSink(sparta::TreeNode* n, const BPUSinkParameters* params) : sparta::Unit(n) { - sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)); + sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(BPUSink, sendInitialCreditsToFTQ_)); + + in_ftq_prediction_output_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(BPUSink, getPredictionOutput_, olympia::BranchPredictor::PredictionOutput)); } private: - uint32_t predictionOutputCredits_ = 1; + std::list pred_output_buffer_; + uint32_t ftq_credits_ = 0; - void sendPredictionOutputCredits_() + void sendCreditsToFTQ_(const uint32_t & credits) { - ILOG("send prediction output credits to bpu"); - out_bpu_predictionOutput_credits_.send(predictionOutputCredits_); + ILOG("Fetch: Send " << credits << " credits to FTQ"); + out_ftq_credits_.send(credits); } - void recievePredictionOutput_(const olympia::BranchPredictor::PredictionOutput & predOutput) - { - ILOG("recieve prediction output from bpu"); - predictionOutputResult_.push_back(predOutput); - ev_return_credits_.schedule(1); + void sendInitialCreditsToFTQ_() { + sendCreditsToFTQ_(5); } - std::list predictionOutputResult_; + void getPredictionOutput_(const olympia::BranchPredictor::PredictionOutput & output) + { + ILOG("Fetch: Recieve prediction output from FTQ"); + pred_output_buffer_.push_back(output); + } //////////////////////////////////////////////////////////////////////////////// // Ports //////////////////////////////////////////////////////////////////////////////// - sparta::DataInPort in_bpu_predictionOutput_{ - &unit_port_set_, "in_bpu_predictionOutput", 0}; + sparta::DataInPort in_ftq_prediction_output_{ + &unit_port_set_, "in_ftq_prediction_output", 0}; - sparta::DataOutPort out_bpu_predictionOutput_credits_{ - &unit_port_set_, "out_bpu_predictionOutput_credits"}; + sparta::DataOutPort out_ftq_credits_{ + &unit_port_set_, "out_ftq_credits"}; - sparta::UniqueEvent<> ev_return_credits_{ + /**sparta::UniqueEvent<> ev_return_credits_{ &unit_event_set_, "return_credits", CREATE_SPARTA_HANDLER(BPUSink, sendPredictionOutputCredits_)}; + ***/ }; using SinkFactory = sparta::ResourceFactory; diff --git a/test/core/bpu/BPUSource.hpp b/test/core/bpu/BPUSource.hpp index 340c0a4b..edab001c 100644 --- a/test/core/bpu/BPUSource.hpp +++ b/test/core/bpu/BPUSource.hpp @@ -40,8 +40,8 @@ namespace bpu_test mavis_facade_(olympia::getMavis(n)) { sparta_assert(mavis_facade_ != nullptr, "Could not find the Mavis Unit"); - in_bpu_predictionRequest_credits_.registerConsumerHandler( - CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, receivePredictionRequestCredits_, + in_bpu_credits_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, getCreditsFromBPU_, uint32_t)); if (params->input_file != "") @@ -51,17 +51,39 @@ namespace bpu_test } } - void initiate() - { - // olympia::BranchPredictor::PredictionRequest pred; - generatedPredictedRequest_.emplace_back(); - } - private: const std::string test_type_; olympia::MavisType* mavis_facade_ = nullptr; std::unique_ptr inst_generator_; + uint32_t bpu_credits_ = 0; + + std::list pred_request_buffer_; + + const uint32_t pred_req_buffer_capacity = 8; + + void getCreditsFromBPU_(const uint32_t & credits) { + bpu_credits_ += credits; + ILOG("Fetch: Received " << credits << " credits from BPU"); + + sendPredictionRequest_(); + } + + void sendPredictionRequest_() { + if(bpu_credits_ > 0) { + ILOG("Fetch: Current credits = " << bpu_credits_); + ILOG("Sending PredictionRequest to BPU"); + olympia::BranchPredictor::PredictionRequest pred_request; + pred_request.instType_ = 1; + pred_request.PC_ = 5; + out_bpu_prediction_request_.send(pred_request); + bpu_credits_--; + } + } + + // functions + + /** void receivePredictionRequestCredits_(const uint32_t & credits) { ILOG("Received prediction request credits from BPU"); @@ -86,18 +108,19 @@ namespace bpu_test uint32_t predictionRequestCredits_ = 0; std::list generatedPredictedRequest_; + ***/ //////////////////////////////////////////////////////////////////////////////// // Ports //////////////////////////////////////////////////////////////////////////////// - sparta::DataOutPort out_bpu_predictionRequest_{ - &unit_port_set_, "out_bpu_predictionRequest"}; + sparta::DataOutPort out_bpu_prediction_request_{ + &unit_port_set_, "out_bpu_prediction_request"}; - sparta::DataInPort in_bpu_predictionRequest_credits_{ - &unit_port_set_, "in_bpu_predictionRequest_credits", 0}; + sparta::DataInPort in_bpu_credits_{ + &unit_port_set_, "in_bpu_credits", 0}; - sparta::SingleCycleUniqueEvent<> ev_gen_insts_{ - &unit_event_set_, "gen_inst", CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; + //sparta::SingleCycleUniqueEvent<> ev_gen_insts_{ + // &unit_event_set_, "gen_inst", CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; }; using SrcFactory = sparta::ResourceFactory; diff --git a/test/core/bpu/BPU_testbench.cpp b/test/core/bpu/BPU_testbench.cpp index 7cbb0eae..3bab3ccd 100644 --- a/test/core/bpu/BPU_testbench.cpp +++ b/test/core/bpu/BPU_testbench.cpp @@ -1,4 +1,5 @@ #include "../../../core/fetch/BPU.hpp" +#include "../../../core/FTQ.hpp" #include "decode/MavisUnit.hpp" #include "OlympiaAllocators.hpp" #include "BPUSink.hpp" @@ -11,6 +12,8 @@ #include #include +#include + using namespace std; TEST_INIT @@ -24,6 +27,9 @@ class Simulator : public sparta::app::Simulation using BPUFactory = sparta::ResourceFactory; + using FTQFactory = sparta::ResourceFactory; + public: Simulator(sparta::Scheduler* sched, const string & mavis_isa_files, const string & mavis_uarch_files, const string & output_file, @@ -34,7 +40,10 @@ class Simulator : public sparta::app::Simulation { } - ~Simulator() { getRoot()->enterTeardown(); } + virtual ~Simulator() { + std::cout << "Simulator destructor\n"; + getRoot()->enterTeardown(); + } void runRaw(uint64_t run_time) override final { @@ -63,16 +72,25 @@ class Simulator : public sparta::app::Simulation tns_to_delete_.emplace_back(src_unit); - auto* src_params = src_unit->getParameterSet(); - src_params->getParameter("input_file")->setValueFromString(input_file_); + //auto* src_params = src_unit->getParameterSet(); + //src_params->getParameter("input_file")->setValueFromString(input_file_); // Create the device under test + + // Create BPU sparta::ResourceTreeNode* bpu = new sparta::ResourceTreeNode(rtn, "bpu", sparta::TreeNode::GROUP_NAME_NONE, sparta::TreeNode::GROUP_IDX_NONE, "BPU", &bpu_fact); tns_to_delete_.emplace_back(bpu); + // Create FTQ + sparta::ResourceTreeNode* ftq = + new sparta::ResourceTreeNode(rtn, "ftq", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "FTQ", &ftq_fact); + + tns_to_delete_.emplace_back(ftq); + // Create the Sink unit sparta::ResourceTreeNode* sink = new sparta::ResourceTreeNode(rtn, "sink", sparta::TreeNode::GROUP_NAME_NONE, @@ -80,8 +98,8 @@ class Simulator : public sparta::app::Simulation tns_to_delete_.emplace_back(sink); - auto* sink_params = sink->getParameterSet(); - sink_params->getParameter("purpose")->setValueFromString("grp"); + //auto* sink_params = sink->getParameterSet(); + //sink_params->getParameter("purpose")->setValueFromString("grp"); } void configureTree_() override {} @@ -92,23 +110,43 @@ class Simulator : public sparta::app::Simulation // See the README.md for A/B/Cx/Dx // - // A - bpu sends prediction request credits to source + // Credit is transferred from BPU to Source + sparta::bind( + root_node->getChildAs("bpu.ports.out_fetch_credits"), + root_node->getChildAs("src.ports.in_bpu_credits")); + + // Movement of PredictionRequest from Source to BPU + sparta::bind( + root_node->getChildAs("bpu.ports.in_fetch_prediction_request"), + root_node->getChildAs("src.ports.out_bpu_prediction_request")); + + // Credits is transferred from Sink to FTQ sparta::bind( - root_node->getChildAs("bpu.ports.out_fetch_predictionRequest_credits"), - root_node->getChildAs("src.ports.in_bpu_predictionRequest_credits")); + root_node->getChildAs("ftq.ports.in_fetch_credits"), + root_node->getChildAs("sink.ports.out_ftq_credits")); - // B - source sends prediction request to bpu - sparta::bind(root_node->getChildAs("bpu.ports.in_fetch_predictionRequest"), - root_node->getChildAs("src.ports.out_bpu_predictionRequest")); + // Movement of PredictionOutput from FTQ to Sink + sparta::bind( + root_node->getChildAs("ftq.ports.out_fetch_prediction_output"), + root_node->getChildAs("sink.ports.in_ftq_prediction_output")); - // C - sink sends prediction output credits to bpu + // Binding BPU and FTQ sparta::bind( - root_node->getChildAs("bpu.ports.in_fetch_predictionOutput_credits"), - root_node->getChildAs("sink.ports.out_bpu_predictionOutput_credits")); + root_node->getChildAs("ftq.ports.out_bpu_update_input"), + root_node->getChildAs("bpu.ports.in_ftq_update_input")); - // D - bpu sends prediction output to sink - sparta::bind(root_node->getChildAs("bpu.ports.out_fetch_predictionOutput"), - root_node->getChildAs("sink.ports.in_bpu_predictionOutput")); + sparta::bind( + root_node->getChildAs("ftq.ports.out_bpu_credits"), + root_node->getChildAs("bpu.ports.in_ftq_credits")); + + sparta::bind( + root_node->getChildAs("ftq.ports.in_bpu_first_prediction_output"), + root_node->getChildAs("bpu.ports.out_ftq_first_prediction_output")); + + sparta::bind( + root_node->getChildAs("ftq.ports.in_bpu_second_prediction_output"), + root_node->getChildAs("bpu.ports.out_ftq_second_prediction_output")); + } // Allocators. Last thing to delete @@ -116,6 +154,7 @@ class Simulator : public sparta::app::Simulation olympia::MavisFactory mavis_fact; BPUFactory bpu_fact; + FTQFactory ftq_fact; bpu_test::SrcFactory source_fact; bpu_test::SinkFactory sink_fact; @@ -190,10 +229,18 @@ bool runTest(int argc, char** argv) il << "No input file specified, exiting gracefully, output not checked"; return true; // not an error } - cls.populateSimulation(&sim); cls.runSimulator(&sim); + std::cout << "file name: " << datafiles[0] << std::endl; + ifstream Myfile(datafiles[0]); + + std::string str; + while(getline(Myfile, str)) { + std::cout << str << std::endl; + } + Myfile.close(); + EXPECT_FILES_EQUAL(datafiles[0], "expected_output/" + datafiles[0] + ".EXPECTED"); return true; } diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt index 8db93f17..aafed7db 100644 --- a/test/core/bpu/CMakeLists.txt +++ b/test/core/bpu/CMakeLists.txt @@ -8,10 +8,13 @@ set(TST3 "${PRJ}_stf") set(CFG config/config.yaml) set(BPUDir ../../../core/fetch) +set(CoreDir ../../../core) + +set(JSON ../json/branch.json) project(${PRJ}) -add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp ${BPUDir}/BasePredictor.cpp ${BPUDir}/BasePredictor.hpp BPUSource.hpp BPUSink.hpp) +add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp ${CoreDir}/FTQ.cpp ${CoreDir}/FTQ.hpp BPUSource.hpp BPUSink.hpp) target_include_directories(${EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(${EXE} core common_test ${STF_LINK_LIBS} mavis SPARTA::sparta) @@ -35,5 +38,5 @@ file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/expected_output ${CMAKE_CURRENT_BINARY_DIR}/expected_output SYMBOLIC) sparta_named_test(${TST1} ${EXE} bpu_tb_test1.out -c ${CFG}) -sparta_named_test(${TST2} ${EXE} bpu_tb_json.out --input_file ${STF} -c ${CFG}) -sparta_named_test(${TST3} ${EXE} bpu_tb_stf.out --input_file ${JSON} -c ${CFG}) \ No newline at end of file +sparta_named_test(${TST2} ${EXE} bpu_tb_json.out --input_file ${JSON} -c ${CFG}) +sparta_named_test(${TST3} ${EXE} bpu_tb_stf.out --input_file ${STF} -c ${CFG}) \ No newline at end of file diff --git a/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED new file mode 100644 index 00000000..14739a50 --- /dev/null +++ b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED @@ -0,0 +1,26 @@ +#Name: +#Cmdline: +#Exe: +#SimulatorVersion: +#Repro: +#Start: Saturday Sat Mar 22 11:12:35 2025 +#Elapsed: 0.001667s +{0000000000 00000000 top.bpu info} sendCreditsToFetch_: BPU: Send 10 credits to Fetch +{0000000000 00000000 top.ftq info} sendCreditsToBPU_: FTQ: Sending 5 credits to BPU +{0000000000 00000000 top.sink info} sendCreditsToFTQ_: Fetch: Send 5 credits to FTQ +{0000000000 00000000 top.src info} getCreditsFromBPU_: Fetch: Received 10 credits from BPU +{0000000000 00000000 top.src info} sendPredictionRequest_: Fetch: Current credits = 10 +{0000000000 00000000 top.src info} sendPredictionRequest_: Sending PredictionRequest to BPU +{0000000000 00000000 top.bpu info} getPredictionRequest_: BPU: received PredictionRequest from Fetch +{0000000000 00000000 top.bpu info} makePrediction_: making prediction +{0000000000 00000000 top.bpu info} getCreditsFromFTQ_: BPU: received 5 credits from FTQ +{0000000000 00000000 top.bpu info} sendFirstPrediction_: SendFirstPrediction starting +{0000000000 00000000 top.bpu info} sendFirstPrediction_: BPU: Sending first PredictionOutput to FTQ +{0000000001 00000001 top.ftq info} getFetchCredits_: FTQ: Received 5 credits from Fetch +{0000000001 00000001 top.ftq info} sendPrediction_: In sendPrediction function +{0000000001 00000001 top.ftq info} sendPrediction_: fetchCredits > 0 +{0000000001 00000001 top.ftq info} getFirstPrediction_: FTQ: Received first PredictionOutput from BPU +{0000000001 00000001 top.ftq info} sendPrediction_: In sendPrediction function +{0000000001 00000001 top.ftq info} sendPrediction_: fetchCredits > 0 +{0000000001 00000001 top.ftq info} sendPrediction_: FTQ: Send prediction to Fetch +{0000000001 00000001 top.sink info} getPredictionOutput_: Fetch: Recieve prediction output from FTQ diff --git a/test/core/bpu/json/branch.json b/test/core/bpu/json/branch.json index 02dfe7a0..18f5347e 100644 --- a/test/core/bpu/json/branch.json +++ b/test/core/bpu/json/branch.json @@ -2,13 +2,43 @@ { "mnemonic": "beq", "rs1": 1, - "rs2": 4, - "offset": 2 + "rs2": 2, + "vaddr": "0x1000", + "target": "0x2000" }, { "mnemonic": "bne", - "rs1": 1, + "rs1": 3, "rs2": 4, - "offset": 1 + "vaddr": "0x1004", + "target": "0x2004" + }, + { + "mnemonic": "blt", + "rs1": 5, + "rs2": 6, + "vaddr": "0x1008", + "target": "0x2008" + }, + { + "mnemonic": "bge", + "rs1": 7, + "rs2": 8, + "vaddr": "0x100C", + "target": "0x200C" + }, + { + "mnemonic": "bltu", + "rs1": 9, + "rs2": 10, + "vaddr": "0x1010", + "target": "0x2010" + }, + { + "mnemonic": "bgeu", + "rs1": 11, + "rs2": 12, + "vaddr": "0x1014", + "target": "0x2014" } ] \ No newline at end of file From 4d95561b9200d45c77b4d43409f62eb551a3b10f Mon Sep 17 00:00:00 2001 From: Shobhit Date: Sat, 22 Mar 2025 11:50:30 +0530 Subject: [PATCH 11/15] removed stf test for now --- core/fetch/TAGE_SC_L.hpp | 3 +++ test/core/bpu/CMakeLists.txt | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index 1db3860e..f04894c9 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -84,6 +84,8 @@ namespace olympia std::vector global_history_buff_; }; + /*** + * TODO class StatisticalCorrector { public: @@ -104,5 +106,6 @@ namespace olympia StatisticalCorrector sc; LoopPredictor l; }; + ***/ } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt index aafed7db..7f446be6 100644 --- a/test/core/bpu/CMakeLists.txt +++ b/test/core/bpu/CMakeLists.txt @@ -3,7 +3,7 @@ set(EXE "BPU_test") set(TST1 "${PRJ}_tst1") set(TST2 "${PRJ}_json") -set(TST3 "${PRJ}_stf") +#set(TST3 "${PRJ}_stf") set(CFG config/config.yaml) @@ -39,4 +39,4 @@ file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/expected_output sparta_named_test(${TST1} ${EXE} bpu_tb_test1.out -c ${CFG}) sparta_named_test(${TST2} ${EXE} bpu_tb_json.out --input_file ${JSON} -c ${CFG}) -sparta_named_test(${TST3} ${EXE} bpu_tb_stf.out --input_file ${STF} -c ${CFG}) \ No newline at end of file +#sparta_named_test(${TST3} ${EXE} bpu_tb_stf.out --input_file ${STF} -c ${CFG}) \ No newline at end of file From 7207d5b985d4da53d72f8dfd4d6c6129ac602326 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Sat, 5 Apr 2025 20:09:53 +0530 Subject: [PATCH 12/15] Basic Tage internal logic --- core/FTQ.cpp | 77 +++---- core/FTQ.hpp | 88 ++++---- core/fetch/BPU.cpp | 123 +++++----- core/fetch/BPU.hpp | 29 ++- core/fetch/BasePredictor.cpp | 213 ++++++++++++++---- core/fetch/BasePredictor.hpp | 68 +++--- core/fetch/CMakeLists.txt | 4 +- core/fetch/TAGE_SC_L.cpp | 100 ++++++-- core/fetch/TAGE_SC_L.hpp | 24 +- test/core/bpu/BPUSink.hpp | 15 +- test/core/bpu/BPUSource.hpp | 58 ++--- test/core/bpu/CMakeLists.txt | 2 +- .../expected_output/bpu_tb_json.out.EXPECTED | 38 ++-- 13 files changed, 506 insertions(+), 333 deletions(-) diff --git a/core/FTQ.cpp b/core/FTQ.cpp index 4959b25a..3cbbfaa3 100644 --- a/core/FTQ.cpp +++ b/core/FTQ.cpp @@ -4,42 +4,41 @@ namespace olympia { const char* FTQ::name = "ftq"; - FTQ::FTQ(sparta::TreeNode *node, const FTQParameterSet *p) : + FTQ::FTQ(sparta::TreeNode* node, const FTQParameterSet* p) : sparta::Unit(node), ftq_capacity_(p->ftq_capacity) - { - in_bpu_first_prediction_output_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getFirstPrediction_, BranchPredictor::PredictionOutput)); + { + sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(FTQ, sendInitialCreditsToBPU_)); - in_bpu_second_prediction_output_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getSecondPrediction_, BranchPredictor::PredictionOutput)); + in_bpu_first_prediction_output_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + FTQ, getFirstPrediction_, BranchPredictor::PredictionOutput)); - in_fetch_credits_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getFetchCredits_, uint32_t)); + in_bpu_second_prediction_output_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + FTQ, getSecondPrediction_, BranchPredictor::PredictionOutput)); - /**in_rob_signal_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getROBSignal_, uint32_t)); - **/ - sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(FTQ, sendInitialCreditsToBPU_)); - } - - FTQ::~FTQ() {} + in_fetch_credits_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getFetchCredits_, uint32_t)); - void FTQ::sendInitialCreditsToBPU_() - { - sendCreditsToBPU_(5); + /**in_rob_signal_.registerConsumerHandler + (CREATE_SPARTA_HANDLER_WITH_DATA(FTQ, getROBSignal_, uint32_t)); + **/ } - void FTQ::sendCreditsToBPU_(const uint32_t & credits) + FTQ::~FTQ() {} + + void FTQ::sendInitialCreditsToBPU_() { sendCreditsToBPU_(5); } + + void FTQ::sendCreditsToBPU_(const uint32_t & credits) { - ILOG("FTQ: Sending " << credits << " credits to BPU"); + ILOG("Send " << credits << " credits to BPU"); out_bpu_credits_.send(credits); } void FTQ::getFirstPrediction_(const BranchPredictor::PredictionOutput & prediction) { - if(fetch_target_queue_.size() < ftq_capacity_) { - ILOG("FTQ: Received first PredictionOutput from BPU"); + if (fetch_target_queue_.size() < ftq_capacity_) + { + ILOG("FTQ receives first PredictionOutput from BPU"); fetch_target_queue_.push(prediction); sendPrediction_(); @@ -49,27 +48,26 @@ namespace olympia void FTQ::getSecondPrediction_(const BranchPredictor::PredictionOutput & prediction) { // check if it matches the prediction made by first tier of bpu - - + ILOG("FTQ receives second PredictionOutput from BPU"); } void FTQ::getFetchCredits_(const uint32_t & credits) { ILOG("FTQ: Received " << credits << " credits from Fetch") - fetchCredits_ += credits; + fetch_credits_ += credits; sendPrediction_(); } void FTQ::sendPrediction_() { - ILOG("In sendPrediction function") - if(fetchCredits_ > 0) { - ILOG("fetchCredits > 0"); + if (fetch_credits_ > 0) + { // send prediction to Fetch - if(fetch_target_queue_.size() > 0) { - fetchCredits_--; - ILOG("FTQ: Send prediction to Fetch"); + if (fetch_target_queue_.size() > 0) + { + fetch_credits_--; + ILOG("Send prediction from FTQ to Fetch"); auto output = fetch_target_queue_.front(); fetch_target_queue_.pop(); out_fetch_prediction_output_.send(output); @@ -77,18 +75,9 @@ namespace olympia } } - void FTQ::firstMispredictionFlush_() - { + void FTQ::firstMispredictionFlush_() {} - } + void FTQ::getROBSignal_(const uint32_t & signal) {} - void FTQ::getROBSignal_(const uint32_t & signal) - { - - } - - void FTQ::deallocateEntry_() - { - - } -} \ No newline at end of file + void FTQ::deallocateEntry_() {} +} // namespace olympia \ No newline at end of file diff --git a/core/FTQ.hpp b/core/FTQ.hpp index 1d60960b..76abbff0 100644 --- a/core/FTQ.hpp +++ b/core/FTQ.hpp @@ -18,70 +18,66 @@ namespace olympia { class FTQ : public sparta::Unit { - public: + public: class FTQParameterSet : public sparta::ParameterSet { - public: - FTQParameterSet(sparta::TreeNode *n) : - sparta::ParameterSet(n) - {} + public: + FTQParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) {} - // for now set default to 10, chnage it later - PARAMETER(uint32_t, ftq_capacity, 10, "Capacity of fetch target queue") + // for now set default to 10, chnage it later + PARAMETER(uint32_t, ftq_capacity, 10, "Capacity of fetch target queue") }; static const char* name; - FTQ(sparta::TreeNode *node, - const FTQParameterSet *p); + FTQ(sparta::TreeNode* node, const FTQParameterSet* p); ~FTQ(); - private: - const uint32_t ftq_capacity_; - uint32_t fetchCredits_ = 0; - std::queue fetch_target_queue_; + private: + const uint32_t ftq_capacity_; - sparta::DataInPort in_bpu_first_prediction_output_ - {&unit_port_set_, "in_bpu_first_prediction_output", 1}; - sparta::DataInPort in_bpu_second_prediction_output_ - {&unit_port_set_, "in_bpu_second_prediction_output", 1}; - sparta::DataInPort in_fetch_credits_ - {&unit_port_set_, "in_fetch_credits", 1}; - /**sparta::DataOutPort out_first_misprediction_flush_ - {&unit_port_set_, "out_first_misprediction_flush", 1};***/ - sparta::DataOutPort out_fetch_prediction_output_ - {&unit_port_set_, "out_fetch_prediction_output", 1}; - /***sparta::DataInPort in_rob_signal_ {&unit_port_set_, "in_rob_signal", 1}; ***/ - sparta::DataOutPort out_bpu_update_input_ - {&unit_port_set_, "out_bpu_update_input", 1}; - sparta::DataOutPort out_bpu_credits_ - {&unit_port_set_, "out_bpu_credits", 1}; - + uint32_t fetch_credits_ = 0; + std::queue fetch_target_queue_; - void sendInitialCreditsToBPU_(); + sparta::DataInPort in_bpu_first_prediction_output_{ + &unit_port_set_, "in_bpu_first_prediction_output", 1}; + sparta::DataInPort in_bpu_second_prediction_output_{ + &unit_port_set_, "in_bpu_second_prediction_output", 1}; + sparta::DataInPort in_fetch_credits_{&unit_port_set_, "in_fetch_credits", 1}; + /**sparta::DataOutPort out_first_misprediction_flush_ + {&unit_port_set_, + "out_first_misprediction_flush", 1};***/ + sparta::DataOutPort out_fetch_prediction_output_{ + &unit_port_set_, "out_fetch_prediction_output", 1}; + /***sparta::DataInPort in_rob_signal_ {&unit_port_set_, "in_rob_signal", 1}; ***/ + sparta::DataOutPort out_bpu_update_input_{ + &unit_port_set_, "out_bpu_update_input", 1}; + sparta::DataOutPort out_bpu_credits_{&unit_port_set_, "out_bpu_credits", 1}; - void sendCreditsToBPU_(const uint32_t &); + void sendInitialCreditsToBPU_(); - // receives prediction from BasePredictor and pushes it into FTQ - void getFirstPrediction_(const BranchPredictor::PredictionOutput &); + void sendCreditsToBPU_(const uint32_t &); - // receives prediction from TAGE_SC_L, checks if there's a mismatch - // updates ftq appropriately - void getSecondPrediction_(const BranchPredictor::PredictionOutput &); + // receives prediction from BasePredictor and pushes it into FTQ + void getFirstPrediction_(const BranchPredictor::PredictionOutput &); - void getFetchCredits_(const uint32_t &); + // receives prediction from TAGE_SC_L, checks if there's a mismatch + // updates ftq appropriately + void getSecondPrediction_(const BranchPredictor::PredictionOutput &); - // continuously send instructions to fetch/icache - void sendPrediction_(); + void getFetchCredits_(const uint32_t &); - // flushes instruction if first prediction does not matvh second prediction - void firstMispredictionFlush_(); + // continuously send instructions to fetch/icache + void sendPrediction_(); - // receives branch resolution signal from ROB at the time of commit - void getROBSignal_(const uint32_t & signal); + // flushes instruction if first prediction does not matvh second prediction + void firstMispredictionFlush_(); - // deallocate FTQ entry once branch instruction is committed - void deallocateEntry_(); + // receives branch resolution signal from ROB at the time of commit + void getROBSignal_(const uint32_t & signal); + + // deallocate FTQ entry once branch instruction is committed + void deallocateEntry_(); }; -} \ No newline at end of file +} // namespace olympia \ No newline at end of file diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index cc9da414..751ef0b8 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -21,45 +21,45 @@ namespace olympia tage_tagged_table_num_(p->tage_tagged_table_num), logical_table_num_(p->logical_table_num), loop_pred_table_size_(p->loop_pred_table_size), - loop_pred_table_way_(p->loop_pred_table_way) - //base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_) + loop_pred_table_way_(p->loop_pred_table_way), + base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_, ras_enable_overwrite_), + tage_predictor_(tage_bim_table_size_, tage_bim_ctr_bits_, 5, 2, 3, 10, 2, 2, 1024, + tage_tagged_table_num_) { sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(BPU, sendIntitialCreditsToFetch_)); - in_fetch_prediction_request_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getPredictionRequest_, PredictionRequest)); + in_fetch_prediction_request_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getPredictionRequest_, PredictionRequest)); - in_ftq_credits_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getCreditsFromFTQ_, uint32_t)); + in_ftq_credits_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getCreditsFromFTQ_, uint32_t)); - in_ftq_update_input_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getUpdateInput_, UpdateInput)); + in_ftq_update_input_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, getUpdateInput_, UpdateInput)); } BPU::~BPU() {} - PredictionOutput BPU::getPrediction(const PredictionRequest &) { + PredictionOutput BPU::getPrediction(const PredictionRequest &) + { PredictionOutput output; output.predDirection_ = true; output.predPC_ = 5; return output; } - void BPU::updatePredictor(const UpdateInput &) { - - } + void BPU::updatePredictor(const UpdateInput &) {} - void BPU::getPredictionRequest_(const PredictionRequest & request) { + void BPU::getPredictionRequest_(const PredictionRequest & request) + { predictionRequestBuffer_.push_back(request); - ILOG("BPU: received PredictionRequest from Fetch"); - - makePrediction_(); + ILOG("BPU received PredictionRequest from Fetch"); } - void BPU::makePrediction_() { + /***void BPU::makePrediction_() { ILOG("making prediction"); std::cout << "making prediction\n"; - if(predictionRequestBuffer_.size() > 0) { + if(predictionRequestBuffer_.size() > ev_make_second_prediction_0) { //auto input = predictionRequestBuffer_.front(); predictionRequestBuffer_.pop_front(); @@ -69,44 +69,71 @@ namespace olympia output.predDirection_ = true; output.predPC_ = 100; generatedPredictionOutputBuffer_.push_back(output); - + + sendFirstPrediction_(); + // call tage_sc_l on input } - } + }**/ - void BPU::getCreditsFromFTQ_(const uint32_t & credits) { - predictionOutputCredits_ += credits; - ILOG("BPU: received " << credits << " credits from FTQ"); - - sendFirstPrediction_(); + void BPU::getCreditsFromFTQ_(const uint32_t & credits) + { + ftq_credits_ += credits; + ILOG("BPU received " << credits << " credits from FTQ"); + ev_send_first_prediction_.schedule(1); + ev_send_second_prediction_.schedule(4); } - - void BPU::sendFirstPrediction_() { - ILOG("SendFirstPrediction starting"); + void BPU::sendFirstPrediction_() + { // take first PredictionRequest from buffer - if(predictionOutputCredits_ > 0) + if (ftq_credits_ > 0 && predictionRequestBuffer_.size() > 0) { + PredictionOutput output; + + PredictionRequest in = predictionRequestBuffer_.front(); + + ILOG("Getting direction from base predictor"); + bool dir = base_predictor_.getDirection(in.PC_, in.instType_); + ILOG("Getting target from base predictor"); + uint64_t target = base_predictor_.getTarget(in.PC_, in.instType_); + + output.predPC_ = target; + output.predDirection_ = dir; + + generatedPredictionOutputBuffer_.push_back(output); + auto firstPrediction = generatedPredictionOutputBuffer_.front(); generatedPredictionOutputBuffer_.pop_front(); - ILOG("BPU: Sending first PredictionOutput to FTQ"); + ILOG("Sending first PredictionOutput from BPU to FTQ"); out_ftq_first_prediction_output_.send(firstPrediction); - predictionOutputCredits_--; + ftq_credits_--; } } - /** - void BPU::sendSecondPrediction_() { + void BPU::sendSecondPrediction_() + { // send prediction made by TAGE_SC_L + PredictionOutput output; + + PredictionRequest in = predictionRequestBuffer_.front(); + + ILOG("Getting direction prediction from TAGE"); + output.predDirection_ = tage_predictor_.predict(in.PC_); + output.predPC_ = 100; + ILOG("Sending second PredictionOutput from BPU to FTQ"); + out_ftq_second_prediction_output_.send(output); } -***/ - void BPU::getUpdateInput_(const UpdateInput & input) { - //internal_update_input_ = input; - ILOG("BPU: received UpdateInput from FTQ"); + void BPU::getUpdateInput_(const UpdateInput & input) + { + // internal_update_input_ = input; + + ILOG("BPU received UpdateInput from FTQ"); - // updateBPU_(internal_update_input_); + // updateBPU_(internal_update_input_); } + /** void BPU::updateBPU_(const UpdateInput & input) { @@ -115,27 +142,21 @@ namespace olympia //base_predictor_.update(input); // Update internal state of TAGE_SC_L according to UpdateInput received - // TODO + // TODO // tage_sc_l.update(input); } **/ - - void BPU::sendCreditsToFetch_(const uint32_t & credits) { - ILOG("BPU: Send " << credits << " credits to Fetch"); + void BPU::sendCreditsToFetch_(const uint32_t & credits) + { + ILOG("Send " << credits << " credits from BPU to Fetch"); out_fetch_credits_.send(credits); } - void BPU::sendIntitialCreditsToFetch_() { - sendCreditsToFetch_(pred_req_buffer_capacity_); - } - - void BPU::updateGHRTaken_() { - - } + void BPU::sendIntitialCreditsToFetch_() { sendCreditsToFetch_(pred_req_buffer_capacity_); } - void BPU::updateGHRNotTaken_() { + void BPU::updateGHRTaken_() {} - } + void BPU::updateGHRNotTaken_() {} } // namespace BranchPredictor } // namespace olympia diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 6c7e479e..5f7db2bd 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -49,7 +49,8 @@ namespace olympia { public: UpdateInput() {} - //UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) {} + + // UpdateInput(uint64_t instrPC, bool correctedDirection, uint64_t correctedTargetPC) {} uint64_t instrPC_; bool correctedDirection_; @@ -120,7 +121,7 @@ namespace olympia const uint32_t ctr_bits_; const uint32_t btb_size_; const uint32_t ras_size_; - const bool ras_enable_overwrite_; + const bool ras_enable_overwrite_; const uint32_t tage_bim_table_size_; const uint32_t tage_bim_ctr_bits_; const uint32_t tage_tagged_table_num_; @@ -131,10 +132,12 @@ namespace olympia std::list predictionRequestBuffer_; std::list generatedPredictionOutputBuffer_; const uint32_t pred_req_buffer_capacity_ = 10; - uint32_t predictionOutputCredits_ = 0; - //UpdateInput internal_update_input_; - //BasePredictor base_predictor_; + uint32_t ftq_credits_ = 0; + // UpdateInput internal_update_input_; + + BasePredictor base_predictor_; + Tage tage_predictor_; /////////////////////////////////////////////////////////////////////////////// // Ports @@ -146,17 +149,15 @@ namespace olympia // Internal DataInPort from FTQ unit for credits to indicate // availabilty of slots for sending PredictionOutput - sparta::DataInPort in_ftq_credits_{ - &unit_port_set_, "in_ftq_credits", sparta::SchedulingPhase::Tick, - 0}; + sparta::DataInPort in_ftq_credits_{&unit_port_set_, "in_ftq_credits", + sparta::SchedulingPhase::Tick, 0}; // Internal DataInPort from FTQ for UpdateInput sparta::DataInPort in_ftq_update_input_{ &unit_port_set_, "in_ftq_update_input", sparta::SchedulingPhase::Tick, 0}; // DataOutPort to Fetch unit to send credits to indicate availability // of slots to receive PredictionRequest - sparta::DataOutPort out_fetch_credits_{ - &unit_port_set_, "out_fetch_credits"}; + sparta::DataOutPort out_fetch_credits_{&unit_port_set_, "out_fetch_credits"}; // DataOutPort to FTQ unit to send prediction made by BasePredictor sparta::DataOutPort out_ftq_first_prediction_output_{ @@ -174,6 +175,14 @@ namespace olympia CREATE_SPARTA_HANDLER_WITH_DATA(BPU, sendPrediction_, PredictionOutput)}; ***/ + sparta::UniqueEvent<> ev_send_first_prediction_{ + &unit_event_set_, "ev_send_first_prediction_", + CREATE_SPARTA_HANDLER(BPU, sendFirstPrediction_)}; + + sparta::UniqueEvent<> ev_send_second_prediction_{ + &unit_event_set_, "ev_send_second_prediction_", + CREATE_SPARTA_HANDLER(BPU, sendSecondPrediction_)}; + ////////////////////////////////////////////////////////////////////////////// // Counters ////////////////////////////////////////////////////////////////////////////// diff --git a/core/fetch/BasePredictor.cpp b/core/fetch/BasePredictor.cpp index 4514d56f..280fe505 100644 --- a/core/fetch/BasePredictor.cpp +++ b/core/fetch/BasePredictor.cpp @@ -1,51 +1,120 @@ #include "BasePredictor.hpp" +#define CALL 0 +#define RET 1 +#define BRANCH 2 + namespace olympia { namespace BranchPredictor { - BasePredictor::BasePredictor(uint32_t pht_size, uint8_t ctr_bits, uint32_t btb_size, - uint32_t ras_size) : - pattern_history_table_(pht_size, ctr_bits), - branch_target_buffer_(btb_size), - return_address_stack_(ras_size) + BasePredictor::BasePredictor(uint32_t pht_size, uint8_t pht_ctr_bits, uint32_t btb_size, + uint32_t ras_size, bool ras_enable_overwrite) : + pht_size_(pht_size), + pht_ctr_bits_(pht_ctr_bits), + pht_ctr_max_val_(1 << pht_ctr_bits_), + btb_size_(btb_size), + ras_size_(ras_size), + ras_enable_overwrite_(ras_enable_overwrite) { + for (uint32_t i = 0; i < pht_size_; i++) + { + pattern_history_table_[i] = 0; + } + for (uint32_t i = 0; i < btb_size; i++) + { + branch_target_buffer_[i] = 0; + } } - PatternHistoryTable::PatternHistoryTable(uint32_t pht_size, uint8_t ctr_bits) : - pht_size_(pht_size), - ctr_bits_(ctr_bits), - ctr_bits_val_(pow(2, ctr_bits)) + bool BasePredictor::getDirection(const uint64_t & PC, const uint8_t & instType) { + std::cout << "ggggetting direction from base predictor\n"; + // branch taken or not-taken? + + // hardcoding values for each type for now + // instType_ = 0 -> call + // instType_ = 1 -> ret + // instType_ = 2 -> conditional branch + + // if instruction type is call/jump or ret branch is always taken + if (instType == 0 || instType == 1) + { + return true; + } + else + { + return branchTaken(PC); + } } - void PatternHistoryTable::incrementCounter(uint32_t idx) + uint64_t BasePredictor::getTarget(const uint64_t & PC, const uint8_t & instType) { - if (pht_.find(idx) != pht_.end()) + std::cout << "gggggetting pc from base predictor\n"; + // target PC + + // hardcoding values for each type for now + // instType_ = 0 -> call + // instType_ = 1 -> ret + // instType_ = 2 -> conditional branch + + // if call -> instruction then save current pc to ctr_max_val_RAS + // if ret -> pop pc from RAS + // if conditonal branch -> use BTB + uint64_t targetPC = 0; + if (instType == 0) { - if (pht_[idx] < ctr_bits_val_) + pushAddress(PC); + if (isHit(PC)) + { + targetPC = getTargetPC(PC, instType); + } + else { - pht_[idx]++; + targetPC = PC + 8; } } + else if (instType == RET) + { + targetPC = popAddress(); + } + else + { + targetPC = getTargetPC(PC, instType); + } + return targetPC; } - void PatternHistoryTable::decrementCounter(uint32_t idx) + // done + void BasePredictor::incrementCtr(uint32_t idx) { - if (pht_.find(idx) != pht_.end()) + if (pattern_history_table_.find(idx) != pattern_history_table_.end()) { - if (pht_[idx] > 0) + if (pattern_history_table_[idx] < pht_ctr_max_val_) { - pht_[idx]--; + pattern_history_table_[idx]++; } } } - uint8_t PatternHistoryTable::getPrediction(uint32_t idx) + // done + void BasePredictor::decrementCtr(uint32_t idx) { - if (pht_.find(idx) != pht_.end()) + if (pattern_history_table_.find(idx) != pattern_history_table_.end()) { - return pht_[idx]; + if (pattern_history_table_[idx] > 0) + { + pattern_history_table_[idx]--; + } + } + } + + // done + uint8_t BasePredictor::getCtr(uint32_t idx) + { + if (pattern_history_table_.find(idx) != pattern_history_table_.end()) + { + return pattern_history_table_[idx]; } else { @@ -53,24 +122,35 @@ namespace olympia } } - // Branch Target Buffer - BranchTargetBuffer::BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} + // done + bool BasePredictor::branchTaken(uint32_t idx) + { + uint8_t ctr = getCtr(idx); + if (ctr > pht_ctr_max_val_ / 2) + { + return true; + } + else + { + return false; + } + } - bool BranchTargetBuffer::addEntry(uint64_t PC, uint64_t targetPC) + // done + bool BasePredictor::addEntry(uint64_t PC, uint64_t targetPC) { - if (btb_.size() < btb_size_) + if (branch_target_buffer_.size() < btb_size_) { - btb_[PC] = targetPC; + branch_target_buffer_[PC] = targetPC; return true; } return false; } - bool BranchTargetBuffer::removeEntry(uint64_t PC) { return btb_.erase(PC); } - - bool BranchTargetBuffer::isHit(uint64_t PC) + // done + bool BasePredictor::isHit(uint64_t PC) { - if (btb_.find(PC) != btb_.end()) + if (branch_target_buffer_.find(PC) != branch_target_buffer_.end()) { return true; } @@ -80,26 +160,67 @@ namespace olympia } } - uint64_t BranchTargetBuffer::getPredictedPC(uint64_t PC) + // i think good enough for review + uint64_t BasePredictor::getTargetPC(uint64_t PC, uint8_t instType) { + uint64_t targetPC = PC + 8; if (isHit(PC)) { - return btb_[PC]; + if (instType == CALL) + { + targetPC = branch_target_buffer_[PC]; + } + else if (instType == BRANCH) + { + if (branchTaken(PC)) + { + targetPC = branch_target_buffer_[PC]; + } + else + { + branch_target_buffer_.erase(PC); + targetPC = PC + 8; + } + } } else { - return 0; // change it later + if (instType == CALL) + { + // TODO: put something random and + // rely on update to correct it later? + addEntry(PC, PC + 8); + targetPC = PC + 8; + } + else if (instType == BRANCH) + { + if (branchTaken(PC)) + { + // TODO: put something random and + // rely on update to correct it later? + addEntry(PC, PC + 8); + } + else + { + targetPC = PC + 8; + } + } } + return targetPC; } - // Return Address Stack - ReturnAddressStack::ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} - - void ReturnAddressStack::pushAddress(uint64_t PC) + // i think done + void BasePredictor::pushAddress(uint64_t PC) { - if (ras_.size() < ras_size_) + if (return_address_stack_.size() < ras_size_) { - ras_.push(PC); + return_address_stack_.push_front(PC); + } + else if (ras_enable_overwrite_) + { + // oldest entry of RAS is overwritten to make space for new entry + return_address_stack_.pop_back(); + return_address_stack_.push_front(PC); } else { @@ -107,8 +228,18 @@ namespace olympia } } - uint64_t ReturnAddressStack::popAddress() { return 0; } - - uint32_t ReturnAddressStack::getSize() { return ras_.size(); } + // i think done for now with TODO left + uint64_t BasePredictor::popAddress() + { + if (return_address_stack_.size() > 0) + { + uint64_t address = return_address_stack_.front(); + return_address_stack_.pop_front(); + return address; + } + // TODO: what to return when ras is empty but popAddress() is + // inocrrectly called? + return 0; + } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/BasePredictor.hpp b/core/fetch/BasePredictor.hpp index e52bb061..95cb23af 100644 --- a/core/fetch/BasePredictor.hpp +++ b/core/fetch/BasePredictor.hpp @@ -4,66 +4,52 @@ #include #include #include +#include +#include + +#include namespace olympia { namespace BranchPredictor { - class PatternHistoryTable + class BasePredictor { public: - PatternHistoryTable(uint32_t pht_size, uint8_t ctr_bits); - - void incrementCounter(uint32_t idx); - void decrementCounter(uint32_t idx); - uint8_t getPrediction(uint32_t idx); + BasePredictor(uint32_t pht_size, uint8_t pht_ctr_bits, uint32_t btb_size, + uint32_t ras_size, bool ras_enable_overwrite); - private: - const uint32_t pht_size_; - const uint8_t ctr_bits_; - const uint8_t ctr_bits_val_; - std::map pht_; - }; + bool getDirection(const uint64_t &, const uint8_t &); + uint64_t getTarget(const uint64_t &, const uint8_t &); - class BranchTargetBuffer - { - public: - BranchTargetBuffer(uint32_t btb_size); + // PHT + void incrementCtr(uint32_t idx); + void decrementCtr(uint32_t idx); + uint8_t getCtr(uint32_t idx); + bool branchTaken(uint32_t idx); + // BTB bool addEntry(uint64_t PC, uint64_t targetPC); - bool removeEntry(uint64_t PC); bool isHit(uint64_t PC); - uint64_t getPredictedPC(uint64_t PC); - - private: - const uint32_t btb_size_; - std::map btb_; - }; - - class ReturnAddressStack - { - public: - ReturnAddressStack(uint32_t ras_size); + uint64_t getTargetPC(uint64_t PC, uint8_t instType); + // RAS void pushAddress(uint64_t PC); uint64_t popAddress(); - uint32_t getSize(); private: + const uint32_t pht_size_; + const uint8_t pht_ctr_bits_; + const uint8_t pht_ctr_max_val_; + const uint32_t btb_size_; const uint32_t ras_size_; - std::stack ras_; - }; + // Boolean flag to set whether newer entries to RAS on maximum + // capacity should overwrite or not. + const bool ras_enable_overwrite_; - class BasePredictor - { - public: - BasePredictor(uint32_t pht_size, uint8_t ctr_bits, uint32_t btb_size, - uint32_t ras_size); - - private: - PatternHistoryTable pattern_history_table_; - BranchTargetBuffer branch_target_buffer_; - ReturnAddressStack return_address_stack_; + std::map pattern_history_table_; + std::map branch_target_buffer_; + std::deque return_address_stack_; }; } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/CMakeLists.txt b/core/fetch/CMakeLists.txt index a4543cb3..76e2651a 100644 --- a/core/fetch/CMakeLists.txt +++ b/core/fetch/CMakeLists.txt @@ -2,8 +2,8 @@ add_library(fetch Fetch.cpp ICache.cpp SimpleBranchPred.cpp - #BasePredictor.cpp - #TAGE_SC_L.cpp + BasePredictor.cpp + TAGE_SC_L.cpp BPU.cpp ) target_link_libraries(fetch instgen) diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp index aff2f48e..5ea845e8 100644 --- a/core/fetch/TAGE_SC_L.cpp +++ b/core/fetch/TAGE_SC_L.cpp @@ -1,4 +1,5 @@ #include "TAGE_SC_L.hpp" +#include namespace olympia { @@ -8,22 +9,48 @@ namespace olympia // Tage Tagged Component Entry TageTaggedComponentEntry::TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, - uint8_t ctr_initial, + uint8_t ctr_initial, uint8_t useful_initial) : tage_ctr_bits_(tage_ctr_bits), tage_useful_bits_(tage_useful_bits), ctr_(ctr_initial), - useful_(useful_initial) + useful_(useful_initial), + tage_ctr_max_val_(1 << tage_ctr_bits_), + tage_useful_max_val_(1 << tage_useful_bits_) { } - void TageTaggedComponentEntry::incrementCtr() {} + void TageTaggedComponentEntry::incrementCtr() + { + if(ctr_ < tage_ctr_max_val_) { + ctr_++; + } + } + + void TageTaggedComponentEntry::decrementCtr() + { + if(ctr_ > 0) { + ctr_--; + } + } - void TageTaggedComponentEntry::decrementCtr() {} + uint8_t TageTaggedComponentEntry::getCtr() { return ctr_; } - void TageTaggedComponentEntry::incrementUseful() {} + void TageTaggedComponentEntry::incrementUseful() + { + if(useful_ < tage_useful_max_val_) { + useful_++; + } + } + + void TageTaggedComponentEntry::decrementUseful() + { + if(useful_ > 0) { + useful_--; + } + } - void TageTaggedComponentEntry::decrementUseful() {} + uint8_t TageTaggedComponentEntry::getUseful() { return useful_; } // Tagged component TageTaggedComponent::TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, @@ -31,17 +58,23 @@ namespace olympia tage_ctr_bits_(tage_ctr_bits), tage_useful_bits_(tage_useful_bits), num_tagged_entry_(num_tagged_entry), - tage_tagged_component_(num_tagged_entry_, {tage_ctr_bits_, tage_useful_bits_}) + tage_tagged_component_(num_tagged_entry_, {tage_ctr_bits_, tage_useful_bits_, 0, 1}) { } + TageTaggedComponentEntry TageTaggedComponent::getTageComponentEntryAtIndex(uint16_t index) + { + return tage_tagged_component_[index]; + } + // Tage Bimodal TageBIM::TageBIM(uint32_t tage_bim_table_size, uint8_t tage_base_ctr_bits) : tage_bim_table_size_(tage_bim_table_size), - tage_base_ctr_bits_(tage_base_ctr_bits) + tage_bim_ctr_bits_(tage_base_ctr_bits), + Tage_Bimodal_(tage_bim_table_size_) { // recheck value - tage_base_max_ctr_ = 2 << tage_base_ctr_bits_; + tage_bim_max_ctr_ = 1 << tage_bim_ctr_bits_; // initialize counter at all index to be 0 for (auto & val : Tage_Bimodal_) @@ -52,7 +85,7 @@ namespace olympia void TageBIM::incrementCtr(uint32_t ip) { - if (Tage_Bimodal_[ip] < tage_base_max_ctr_) + if (Tage_Bimodal_[ip] < tage_bim_max_ctr_) { Tage_Bimodal_[ip]++; } @@ -70,16 +103,16 @@ namespace olympia // TAGE Tage::Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, - uint8_t tage_tagged_useful_bits, uint32_t tage_global_hist_buff_len, - uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, - uint32_t tage_reset_useful_interval, uint8_t tage_num_component) : + uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, + uint8_t tage_tagged_useful_bits, uint32_t tage_global_history_len, + uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, + uint32_t tage_reset_useful_interval, uint8_t tage_num_component) : tage_bim_table_size_(tage_bim_table_size), tage_bim_ctr_bits_(tage_bim_ctr_bits), tage_max_index_bits_(tage_max_index_bits), tage_tagged_ctr_bits_(tage_tagged_ctr_bits), tage_tagged_useful_bits_(tage_tagged_useful_bits), - tage_global_hist_buff_len_(tage_global_hist_buff_len), + tage_global_history_len_(tage_global_history_len), tage_min_hist_len_(tage_min_hist_len), tage_hist_alpha_(tage_hist_alpha), tage_reset_useful_interval_(tage_reset_useful_interval), @@ -88,13 +121,44 @@ namespace olympia // for now number of tagged component entry in each component is set as 10 tage_tagged_components_(tage_num_component_, {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, 10}), - global_history_buff_(tage_global_hist_buff_len, 0) + tage_global_history_(tage_global_history_len_, 0) { } + uint32_t Tage::hashAddr(uint64_t PC, uint8_t component_number) + { + // TODO: Write logic to calculate hash + uint32_t hashedValue = 0; + return hashedValue; + } + + uint16_t Tage::calculatedTag(uint64_t PC, uint8_t component_number) + { + // uint16_t tag_i = (PC ^ (PC >> shift1) ^ compressed_ghr); + uint16_t tag_i = 0; + return tag_i; + } + // for now return 1 - uint8_t Tage::predict(uint64_t ip) { - return 1; + uint8_t Tage::predict(uint64_t ip) + { + uint8_t def_pred = tage_bim_.getPrediction(ip); + uint8_t num_counter = 0; + uint8_t tage_pred = def_pred; + for (auto tage_i : tage_tagged_components_) + { + uint64_t effective_addr = hashAddr(ip, num_counter); + TageTaggedComponentEntry tage_entry = + tage_i.getTageComponentEntryAtIndex(effective_addr); + + if (tage_entry.tag == calculatedTag(ip, num_counter)) + { + tage_pred = tage_entry.getCtr(); + } + num_counter++; + } + std::cout << "getting tage prediction\n"; + return tage_pred; } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index f04894c9..8490d99c 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace olympia { @@ -10,19 +11,23 @@ namespace olympia class TageTaggedComponentEntry { public: - TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, - uint8_t ctr_initial, uint8_t useful_initial); + TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, + uint8_t ctr_initial, uint8_t useful_initial); void incrementCtr(); void decrementCtr(); + uint8_t getCtr(); void incrementUseful(); void decrementUseful(); + uint8_t getUseful(); uint16_t tag; private: const uint8_t tage_ctr_bits_; const uint8_t tage_useful_bits_; + const uint8_t tage_ctr_max_val_; + const uint8_t tage_useful_max_val_ uint8_t ctr_; uint8_t useful_; @@ -34,6 +39,8 @@ namespace olympia TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, uint16_t num_tagged_entry); + TageTaggedComponentEntry getTageComponentEntryAtIndex(uint16_t index); + private: const uint8_t tage_ctr_bits_; const uint8_t tage_useful_bits_; @@ -53,7 +60,7 @@ namespace olympia private: const uint32_t tage_bim_table_size_; const uint8_t tage_bim_ctr_bits_; - const uint8_t tage_bim_max_ctr_; + uint8_t tage_bim_max_ctr_; std::vector Tage_Bimodal_; }; @@ -61,8 +68,8 @@ namespace olympia { public: Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, - uint8_t tage_tagged_useful_bits, uint32_t tage_global_hist_buff_len, + uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, + uint8_t tage_tagged_useful_bits, uint32_t tage_global_history_len, uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, uint32_t tage_reset_useful_interval, uint8_t tage_num_component); @@ -74,14 +81,17 @@ namespace olympia uint16_t tage_max_index_bits_; const uint8_t tage_tagged_ctr_bits_; const uint8_t tage_tagged_useful_bits_; - const uint32_t tage_global_hist_buff_len_; + const uint32_t tage_global_history_len_; const uint32_t tage_min_hist_len_; const uint8_t tage_hist_alpha_; const uint32_t tage_reset_useful_interval_; const uint8_t tage_num_component_; TageBIM tage_bim_; std::vector tage_tagged_components_; - std::vector global_history_buff_; + std::vector tage_global_history_; + + uint32_t hashAddr(uint64_t PC, uint8_t component_number); + uint16_t calculatedTag(uint64_t PC, uint8_t component_number); }; /*** diff --git a/test/core/bpu/BPUSink.hpp b/test/core/bpu/BPUSink.hpp index 8ba53712..bed86892 100644 --- a/test/core/bpu/BPUSink.hpp +++ b/test/core/bpu/BPUSink.hpp @@ -28,8 +28,8 @@ namespace bpu_test { sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(BPUSink, sendInitialCreditsToFTQ_)); - in_ftq_prediction_output_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(BPUSink, getPredictionOutput_, olympia::BranchPredictor::PredictionOutput)); + in_ftq_prediction_output_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + BPUSink, getPredictionOutput_, olympia::BranchPredictor::PredictionOutput)); } private: @@ -38,17 +38,15 @@ namespace bpu_test void sendCreditsToFTQ_(const uint32_t & credits) { - ILOG("Fetch: Send " << credits << " credits to FTQ"); + ILOG("Send " << credits << " credits from Fetch to FTQ"); out_ftq_credits_.send(credits); } - void sendInitialCreditsToFTQ_() { - sendCreditsToFTQ_(5); - } + void sendInitialCreditsToFTQ_() { sendCreditsToFTQ_(5); } void getPredictionOutput_(const olympia::BranchPredictor::PredictionOutput & output) { - ILOG("Fetch: Recieve prediction output from FTQ"); + ILOG("Fetch recieves prediction output from FTQ"); pred_output_buffer_.push_back(output); } @@ -58,8 +56,7 @@ namespace bpu_test sparta::DataInPort in_ftq_prediction_output_{ &unit_port_set_, "in_ftq_prediction_output", 0}; - sparta::DataOutPort out_ftq_credits_{ - &unit_port_set_, "out_ftq_credits"}; + sparta::DataOutPort out_ftq_credits_{&unit_port_set_, "out_ftq_credits"}; /**sparta::UniqueEvent<> ev_return_credits_{ &unit_event_set_, "return_credits", diff --git a/test/core/bpu/BPUSource.hpp b/test/core/bpu/BPUSource.hpp index edab001c..bfb08212 100644 --- a/test/core/bpu/BPUSource.hpp +++ b/test/core/bpu/BPUSource.hpp @@ -41,8 +41,7 @@ namespace bpu_test { sparta_assert(mavis_facade_ != nullptr, "Could not find the Mavis Unit"); in_bpu_credits_.registerConsumerHandler( - CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, getCreditsFromBPU_, - uint32_t)); + CREATE_SPARTA_HANDLER_WITH_DATA(BPUSource, getCreditsFromBPU_, uint32_t)); if (params->input_file != "") { @@ -62,17 +61,20 @@ namespace bpu_test const uint32_t pred_req_buffer_capacity = 8; - void getCreditsFromBPU_(const uint32_t & credits) { + void getCreditsFromBPU_(const uint32_t & credits) + { bpu_credits_ += credits; - ILOG("Fetch: Received " << credits << " credits from BPU"); + ILOG("Received " << credits << " credits from BPU"); + //ev_send_pred_req_.schedule(sparta::Clock::Cycle(0)); sendPredictionRequest_(); } - void sendPredictionRequest_() { - if(bpu_credits_ > 0) { - ILOG("Fetch: Current credits = " << bpu_credits_); - ILOG("Sending PredictionRequest to BPU"); + void sendPredictionRequest_() + { + if (bpu_credits_ > 0) + { + ILOG("Sending PredictionRequest from Fetch to BPU"); olympia::BranchPredictor::PredictionRequest pred_request; pred_request.instType_ = 1; pred_request.PC_ = 5; @@ -81,46 +83,16 @@ namespace bpu_test } } - // functions - - /** - void receivePredictionRequestCredits_(const uint32_t & credits) - { - ILOG("Received prediction request credits from BPU"); - predictionRequestCredits_ += credits; - - if (predictionRequestCredits_ > 0) - { - ev_gen_insts_.schedule(); - } - } - - void sendPredictionRequest_() - { - if (predictionRequestCredits_ > 0) - { - auto output = generatedPredictedRequest_.front(); - generatedPredictedRequest_.pop_front(); - out_bpu_predictionRequest_.send(output); - predictionRequestCredits_--; - } - } - - uint32_t predictionRequestCredits_ = 0; - std::list generatedPredictedRequest_; - ***/ - //////////////////////////////////////////////////////////////////////////////// // Ports //////////////////////////////////////////////////////////////////////////////// - sparta::DataOutPort out_bpu_prediction_request_{ - &unit_port_set_, "out_bpu_prediction_request"}; + sparta::DataOutPort + out_bpu_prediction_request_{&unit_port_set_, "out_bpu_prediction_request"}; - sparta::DataInPort in_bpu_credits_{ - &unit_port_set_, "in_bpu_credits", 0}; + sparta::DataInPort in_bpu_credits_{&unit_port_set_, "in_bpu_credits", 0}; - //sparta::SingleCycleUniqueEvent<> ev_gen_insts_{ - // &unit_event_set_, "gen_inst", CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; + //sparta::Event<> ev_send_pred_req_{&unit_event_set_, "ev_send_pred_req_", + // CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; }; using SrcFactory = sparta::ResourceFactory; diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt index 7f446be6..05234b93 100644 --- a/test/core/bpu/CMakeLists.txt +++ b/test/core/bpu/CMakeLists.txt @@ -14,7 +14,7 @@ set(JSON ../json/branch.json) project(${PRJ}) -add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp ${CoreDir}/FTQ.cpp ${CoreDir}/FTQ.hpp BPUSource.hpp BPUSink.hpp) +add_executable(${EXE} BPU_testbench.cpp ${BPUDir}/BPU.cpp ${BPUDir}/BPU.hpp ${BPUDir}/BasePredictor.cpp ${BPUDir}/BasePredictor.hpp ${CoreDir}/FTQ.cpp ${CoreDir}/FTQ.hpp BPUSource.hpp BPUSink.hpp) target_include_directories(${EXE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(${EXE} core common_test ${STF_LINK_LIBS} mavis SPARTA::sparta) diff --git a/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED index 14739a50..c7850089 100644 --- a/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED +++ b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED @@ -3,24 +3,22 @@ #Exe: #SimulatorVersion: #Repro: -#Start: Saturday Sat Mar 22 11:12:35 2025 -#Elapsed: 0.001667s -{0000000000 00000000 top.bpu info} sendCreditsToFetch_: BPU: Send 10 credits to Fetch -{0000000000 00000000 top.ftq info} sendCreditsToBPU_: FTQ: Sending 5 credits to BPU -{0000000000 00000000 top.sink info} sendCreditsToFTQ_: Fetch: Send 5 credits to FTQ -{0000000000 00000000 top.src info} getCreditsFromBPU_: Fetch: Received 10 credits from BPU -{0000000000 00000000 top.src info} sendPredictionRequest_: Fetch: Current credits = 10 -{0000000000 00000000 top.src info} sendPredictionRequest_: Sending PredictionRequest to BPU -{0000000000 00000000 top.bpu info} getPredictionRequest_: BPU: received PredictionRequest from Fetch -{0000000000 00000000 top.bpu info} makePrediction_: making prediction -{0000000000 00000000 top.bpu info} getCreditsFromFTQ_: BPU: received 5 credits from FTQ -{0000000000 00000000 top.bpu info} sendFirstPrediction_: SendFirstPrediction starting -{0000000000 00000000 top.bpu info} sendFirstPrediction_: BPU: Sending first PredictionOutput to FTQ +#Start: Saturday Sat Apr 5 17:01:41 2025 +#Elapsed: 0.001278s +{0000000000 00000000 top.bpu info} sendCreditsToFetch_: Send 10 credits from BPU to Fetch +{0000000000 00000000 top.ftq info} sendCreditsToBPU_: Send 5 credits to BPU +{0000000000 00000000 top.sink info} sendCreditsToFTQ_: Send 5 credits from Fetch to FTQ +{0000000000 00000000 top.bpu info} getCreditsFromFTQ_: BPU received 5 credits from FTQ +{0000000000 00000000 top.src info} getCreditsFromBPU_: Received 10 credits from BPU +{0000000000 00000000 top.src info} sendPredictionRequest_: Sending PredictionRequest from Fetch to BPU +{0000000000 00000000 top.bpu info} getPredictionRequest_: BPU received PredictionRequest from Fetch {0000000001 00000001 top.ftq info} getFetchCredits_: FTQ: Received 5 credits from Fetch -{0000000001 00000001 top.ftq info} sendPrediction_: In sendPrediction function -{0000000001 00000001 top.ftq info} sendPrediction_: fetchCredits > 0 -{0000000001 00000001 top.ftq info} getFirstPrediction_: FTQ: Received first PredictionOutput from BPU -{0000000001 00000001 top.ftq info} sendPrediction_: In sendPrediction function -{0000000001 00000001 top.ftq info} sendPrediction_: fetchCredits > 0 -{0000000001 00000001 top.ftq info} sendPrediction_: FTQ: Send prediction to Fetch -{0000000001 00000001 top.sink info} getPredictionOutput_: Fetch: Recieve prediction output from FTQ +{0000000001 00000001 top.bpu info} sendFirstPrediction_: Getting direction from base predictor +{0000000001 00000001 top.bpu info} sendFirstPrediction_: Getting target from base predictor +{0000000001 00000001 top.bpu info} sendFirstPrediction_: Sending first PredictionOutput from BPU to FTQ +{0000000002 00000002 top.ftq info} getFirstPrediction_: FTQ receives first PredictionOutput from BPU +{0000000002 00000002 top.ftq info} sendPrediction_: Send prediction from FTQ to Fetch +{0000000002 00000002 top.sink info} getPredictionOutput_: Fetch recieves prediction output from FTQ +{0000000004 00000004 top.bpu info} sendSecondPrediction_: Getting direction prediction from TAGE +{0000000004 00000004 top.bpu info} sendSecondPrediction_: Sending second PredictionOutput from BPU to FTQ +{0000000005 00000005 top.ftq info} getSecondPrediction_: FTQ receives second PredictionOutput from BPU From 9536aa62c8aec5a710c965f34e0383c67ed3b5ba Mon Sep 17 00:00:00 2001 From: Shobhit Date: Sun, 6 Apr 2025 16:03:15 +0530 Subject: [PATCH 13/15] Added logic to find hash address and tag for TAGE, pass function parameters by const reference --- core/fetch/BasePredictor.cpp | 20 ++++---- core/fetch/BasePredictor.hpp | 20 ++++---- core/fetch/TAGE_SC_L.cpp | 93 ++++++++++++++++++++---------------- core/fetch/TAGE_SC_L.hpp | 42 ++++++++-------- 4 files changed, 96 insertions(+), 79 deletions(-) diff --git a/core/fetch/BasePredictor.cpp b/core/fetch/BasePredictor.cpp index 280fe505..0eb46f17 100644 --- a/core/fetch/BasePredictor.cpp +++ b/core/fetch/BasePredictor.cpp @@ -8,8 +8,8 @@ namespace olympia { namespace BranchPredictor { - BasePredictor::BasePredictor(uint32_t pht_size, uint8_t pht_ctr_bits, uint32_t btb_size, - uint32_t ras_size, bool ras_enable_overwrite) : + BasePredictor::BasePredictor(const uint32_t & pht_size, const uint8_t & pht_ctr_bits, const uint32_t & btb_size, + const uint32_t & ras_size, const bool & ras_enable_overwrite) : pht_size_(pht_size), pht_ctr_bits_(pht_ctr_bits), pht_ctr_max_val_(1 << pht_ctr_bits_), @@ -86,7 +86,7 @@ namespace olympia } // done - void BasePredictor::incrementCtr(uint32_t idx) + void BasePredictor::incrementCtr(const uint32_t & idx) { if (pattern_history_table_.find(idx) != pattern_history_table_.end()) { @@ -98,7 +98,7 @@ namespace olympia } // done - void BasePredictor::decrementCtr(uint32_t idx) + void BasePredictor::decrementCtr(const uint32_t & idx) { if (pattern_history_table_.find(idx) != pattern_history_table_.end()) { @@ -110,7 +110,7 @@ namespace olympia } // done - uint8_t BasePredictor::getCtr(uint32_t idx) + uint8_t BasePredictor::getCtr(const uint32_t & idx) { if (pattern_history_table_.find(idx) != pattern_history_table_.end()) { @@ -123,7 +123,7 @@ namespace olympia } // done - bool BasePredictor::branchTaken(uint32_t idx) + bool BasePredictor::branchTaken(const uint32_t & idx) { uint8_t ctr = getCtr(idx); if (ctr > pht_ctr_max_val_ / 2) @@ -137,7 +137,7 @@ namespace olympia } // done - bool BasePredictor::addEntry(uint64_t PC, uint64_t targetPC) + bool BasePredictor::addEntry(const uint64_t & PC, const uint64_t & targetPC) { if (branch_target_buffer_.size() < btb_size_) { @@ -148,7 +148,7 @@ namespace olympia } // done - bool BasePredictor::isHit(uint64_t PC) + bool BasePredictor::isHit(const uint64_t & PC) { if (branch_target_buffer_.find(PC) != branch_target_buffer_.end()) { @@ -161,7 +161,7 @@ namespace olympia } // i think good enough for review - uint64_t BasePredictor::getTargetPC(uint64_t PC, uint8_t instType) + uint64_t BasePredictor::getTargetPC(const uint64_t & PC, const uint8_t & instType) { uint64_t targetPC = PC + 8; if (isHit(PC)) @@ -210,7 +210,7 @@ namespace olympia } // i think done - void BasePredictor::pushAddress(uint64_t PC) + void BasePredictor::pushAddress(const uint64_t & PC) { if (return_address_stack_.size() < ras_size_) { diff --git a/core/fetch/BasePredictor.hpp b/core/fetch/BasePredictor.hpp index 95cb23af..41aedef2 100644 --- a/core/fetch/BasePredictor.hpp +++ b/core/fetch/BasePredictor.hpp @@ -16,25 +16,25 @@ namespace olympia class BasePredictor { public: - BasePredictor(uint32_t pht_size, uint8_t pht_ctr_bits, uint32_t btb_size, - uint32_t ras_size, bool ras_enable_overwrite); + BasePredictor(const uint32_t & pht_size, const uint8_t & pht_ctr_bits, const uint32_t & btb_size, + const uint32_t & ras_size, const bool & ras_enable_overwrite); bool getDirection(const uint64_t &, const uint8_t &); uint64_t getTarget(const uint64_t &, const uint8_t &); // PHT - void incrementCtr(uint32_t idx); - void decrementCtr(uint32_t idx); - uint8_t getCtr(uint32_t idx); - bool branchTaken(uint32_t idx); + void incrementCtr(const uint32_t & idx); + void decrementCtr(const uint32_t & idx); + uint8_t getCtr(const uint32_t & idx); + bool branchTaken(const uint32_t & idx); // BTB - bool addEntry(uint64_t PC, uint64_t targetPC); - bool isHit(uint64_t PC); - uint64_t getTargetPC(uint64_t PC, uint8_t instType); + bool addEntry(const uint64_t & PC, const uint64_t & targetPC); + bool isHit(const uint64_t & PC); + uint64_t getTargetPC(const uint64_t & PC, const uint8_t & instType); // RAS - void pushAddress(uint64_t PC); + void pushAddress(const uint64_t & PC); uint64_t popAddress(); private: diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp index 5ea845e8..074e3ee3 100644 --- a/core/fetch/TAGE_SC_L.cpp +++ b/core/fetch/TAGE_SC_L.cpp @@ -1,5 +1,6 @@ #include "TAGE_SC_L.hpp" #include +#include namespace olympia { @@ -7,16 +8,16 @@ namespace olympia { // Tage Tagged Component Entry - TageTaggedComponentEntry::TageTaggedComponentEntry(uint8_t tage_ctr_bits, - uint8_t tage_useful_bits, - uint8_t ctr_initial, - uint8_t useful_initial) : + TageTaggedComponentEntry::TageTaggedComponentEntry(const uint8_t & tage_ctr_bits, + const uint8_t & tage_useful_bits, + const uint8_t & ctr_initial, + const uint8_t & useful_initial) : tage_ctr_bits_(tage_ctr_bits), tage_useful_bits_(tage_useful_bits), - ctr_(ctr_initial), - useful_(useful_initial), tage_ctr_max_val_(1 << tage_ctr_bits_), - tage_useful_max_val_(1 << tage_useful_bits_) + tage_useful_max_val_(1 << tage_useful_bits_), + ctr_(ctr_initial), + useful_(useful_initial) { } @@ -53,8 +54,8 @@ namespace olympia uint8_t TageTaggedComponentEntry::getUseful() { return useful_; } // Tagged component - TageTaggedComponent::TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, - uint16_t num_tagged_entry) : + TageTaggedComponent::TageTaggedComponent(const uint8_t & tage_ctr_bits, const uint8_t & tage_useful_bits, + const uint16_t & num_tagged_entry) : tage_ctr_bits_(tage_ctr_bits), tage_useful_bits_(tage_useful_bits), num_tagged_entry_(num_tagged_entry), @@ -62,51 +63,51 @@ namespace olympia { } - TageTaggedComponentEntry TageTaggedComponent::getTageComponentEntryAtIndex(uint16_t index) + TageTaggedComponentEntry TageTaggedComponent::getTageComponentEntryAtIndex(const uint16_t & index) { return tage_tagged_component_[index]; } // Tage Bimodal - TageBIM::TageBIM(uint32_t tage_bim_table_size, uint8_t tage_base_ctr_bits) : + TageBIM::TageBIM(const uint32_t & tage_bim_table_size, const uint8_t & tage_base_ctr_bits) : tage_bim_table_size_(tage_bim_table_size), tage_bim_ctr_bits_(tage_base_ctr_bits), - Tage_Bimodal_(tage_bim_table_size_) + tage_bimodal_(tage_bim_table_size_) { // recheck value tage_bim_max_ctr_ = 1 << tage_bim_ctr_bits_; // initialize counter at all index to be 0 - for (auto & val : Tage_Bimodal_) + for (auto & val : tage_bimodal_) { val = 0; } } - void TageBIM::incrementCtr(uint32_t ip) + void TageBIM::incrementCtr(const uint32_t & ip) { - if (Tage_Bimodal_[ip] < tage_bim_max_ctr_) + if (tage_bimodal_[ip] < tage_bim_max_ctr_) { - Tage_Bimodal_[ip]++; + tage_bimodal_[ip]++; } } - void TageBIM::decrementCtr(uint32_t ip) + void TageBIM::decrementCtr(const uint32_t & ip) { - if (Tage_Bimodal_[ip] > 0) + if (tage_bimodal_[ip] > 0) { - Tage_Bimodal_[ip]--; + tage_bimodal_[ip]--; } } - uint8_t TageBIM::getPrediction(uint32_t ip) { return Tage_Bimodal_[ip]; } + uint8_t TageBIM::getPrediction(const uint32_t & ip) { return tage_bimodal_[ip]; } // TAGE - Tage::Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, - uint8_t tage_tagged_useful_bits, uint32_t tage_global_history_len, - uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, - uint32_t tage_reset_useful_interval, uint8_t tage_num_component) : + Tage::Tage(const uint32_t & tage_bim_table_size, const uint8_t & tage_bim_ctr_bits, + const uint16_t & tage_max_index_bits, const uint8_t & tage_tagged_ctr_bits, + const uint8_t & tage_tagged_useful_bits, const uint32_t & tage_global_history_len, + const uint32_t & tage_min_hist_len, const uint8_t & tage_hist_alpha, + const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component) : tage_bim_table_size_(tage_bim_table_size), tage_bim_ctr_bits_(tage_bim_ctr_bits), tage_max_index_bits_(tage_max_index_bits), @@ -125,40 +126,52 @@ namespace olympia { } - uint32_t Tage::hashAddr(uint64_t PC, uint8_t component_number) + uint64_t Tage::compressed_ghr(const uint8_t & req_length) + { + uint64_t resultant_ghr = 0; + // if req_length is more than tage_global_history_len_ then return whole tage_global_history_ + uint8_t length = (req_length > tage_global_history_len_) ? tage_global_history_len_ : req_length; + for(uint8_t idx = 0; idx < length; idx++) { + resultant_ghr = (resultant_ghr << 1) | tage_global_history_[tage_global_history_len_ - idx - 1]; + } + return resultant_ghr; + } + + uint32_t Tage::hashAddr(const uint64_t & PC, const uint8_t & component_number) { - // TODO: Write logic to calculate hash - uint32_t hashedValue = 0; + uint8_t local_hist_len = tage_min_hist_len_ * pow(tage_hist_alpha_, component_number - 1); + uint64_t effective_hist = compressed_ghr(local_hist_len); + uint32_t hashedValue = (uint32_t) (PC ^ effective_hist); return hashedValue; } - uint16_t Tage::calculatedTag(uint64_t PC, uint8_t component_number) + uint16_t Tage::calculatedTag(const uint64_t & PC, const uint8_t & component_number) { - // uint16_t tag_i = (PC ^ (PC >> shift1) ^ compressed_ghr); - uint16_t tag_i = 0; - return tag_i; + uint8_t local_hist_len = tage_min_hist_len_ * pow(tage_hist_alpha_, component_number - 1); + uint64_t effective_hist = compressed_ghr(local_hist_len); + uint16_t calculated_tag = (uint16_t) (PC ^ effective_hist); + return calculated_tag; } - // for now return 1 - uint8_t Tage::predict(uint64_t ip) + uint8_t Tage::predict(const uint64_t & ip) { - uint8_t def_pred = tage_bim_.getPrediction(ip); - uint8_t num_counter = 0; - uint8_t tage_pred = def_pred; + uint8_t default_prediction = tage_bim_.getPrediction(ip); + uint8_t num_counter = 1; + uint8_t tage_prediction = default_prediction; for (auto tage_i : tage_tagged_components_) { uint64_t effective_addr = hashAddr(ip, num_counter); TageTaggedComponentEntry tage_entry = tage_i.getTageComponentEntryAtIndex(effective_addr); + // Tag match if (tage_entry.tag == calculatedTag(ip, num_counter)) { - tage_pred = tage_entry.getCtr(); + tage_prediction = tage_entry.getCtr(); } num_counter++; } - std::cout << "getting tage prediction\n"; - return tage_pred; + return tage_prediction; } } // namespace BranchPredictor } // namespace olympia \ No newline at end of file diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index 8490d99c..1f30c69d 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -11,8 +11,8 @@ namespace olympia class TageTaggedComponentEntry { public: - TageTaggedComponentEntry(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, - uint8_t ctr_initial, uint8_t useful_initial); + TageTaggedComponentEntry(const uint8_t & tage_ctr_bits, const uint8_t & tage_useful_bits, + const uint8_t & ctr_initial, const uint8_t & useful_initial); void incrementCtr(); void decrementCtr(); @@ -27,7 +27,7 @@ namespace olympia const uint8_t tage_ctr_bits_; const uint8_t tage_useful_bits_; const uint8_t tage_ctr_max_val_; - const uint8_t tage_useful_max_val_ + const uint8_t tage_useful_max_val_; uint8_t ctr_; uint8_t useful_; @@ -36,10 +36,10 @@ namespace olympia class TageTaggedComponent { public: - TageTaggedComponent(uint8_t tage_ctr_bits, uint8_t tage_useful_bits, - uint16_t num_tagged_entry); + TageTaggedComponent(const uint8_t & tage_ctr_bits, const uint8_t & tage_useful_bits, + const uint16_t & num_tagged_entry); - TageTaggedComponentEntry getTageComponentEntryAtIndex(uint16_t index); + TageTaggedComponentEntry getTageComponentEntryAtIndex(const uint16_t & index); private: const uint8_t tage_ctr_bits_; @@ -51,29 +51,29 @@ namespace olympia class TageBIM { public: - TageBIM(uint32_t tage_bim_table_size, uint8_t tage_base_ctr_bits); + TageBIM(const uint32_t & tage_bim_table_size, const uint8_t & tage_base_ctr_bits); - void incrementCtr(uint32_t ip); - void decrementCtr(uint32_t ip); - uint8_t getPrediction(uint32_t ip); + void incrementCtr(const uint32_t & ip); + void decrementCtr(const uint32_t & ip); + uint8_t getPrediction(const uint32_t & ip); private: const uint32_t tage_bim_table_size_; const uint8_t tage_bim_ctr_bits_; uint8_t tage_bim_max_ctr_; - std::vector Tage_Bimodal_; + std::vector tage_bimodal_; }; class Tage { public: - Tage(uint32_t tage_bim_table_size, uint8_t tage_bim_ctr_bits, - uint16_t tage_max_index_bits, uint8_t tage_tagged_ctr_bits, - uint8_t tage_tagged_useful_bits, uint32_t tage_global_history_len, - uint32_t tage_min_hist_len, uint8_t tage_hist_alpha, - uint32_t tage_reset_useful_interval, uint8_t tage_num_component); + Tage(const uint32_t & tage_bim_table_size, const uint8_t & tage_bim_ctr_bits, + const uint16_t & tage_max_index_bits, const uint8_t & tage_tagged_ctr_bits, + const uint8_t & tage_tagged_useful_bits, const uint32_t & tage_global_history_len, + const uint32_t & tage_min_hist_len, const uint8_t & tage_hist_alpha, + const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component); - uint8_t predict(uint64_t ip); + uint8_t predict(const uint64_t & ip); private: const uint32_t tage_bim_table_size_; @@ -90,8 +90,12 @@ namespace olympia std::vector tage_tagged_components_; std::vector tage_global_history_; - uint32_t hashAddr(uint64_t PC, uint8_t component_number); - uint16_t calculatedTag(uint64_t PC, uint8_t component_number); + // Helper function to compress tage ghr into a numeric + uint64_t compressed_ghr(const uint8_t & req_length); + // Helper function to calculate hash too index into tage table + uint32_t hashAddr(const uint64_t & PC, const uint8_t & component_number); + // Helper function to calcuate tag + uint16_t calculatedTag(const uint64_t & PC, const uint8_t & component_number); }; /*** From df674df49e647d67b072b89b0a7444024d1f211c Mon Sep 17 00:00:00 2001 From: Shobhit Date: Tue, 22 Apr 2025 05:43:18 +0530 Subject: [PATCH 14/15] Handle mismatch between First and Second prediction --- core/FTQ.cpp | 49 +++++++++++++++++-- core/FTQ.hpp | 9 +++- test/core/bpu/BPUSource.hpp | 24 +++++++-- .../expected_output/bpu_tb_json.out.EXPECTED | 10 +++- 4 files changed, 80 insertions(+), 12 deletions(-) diff --git a/core/FTQ.cpp b/core/FTQ.cpp index 3cbbfaa3..f9ab2d2d 100644 --- a/core/FTQ.cpp +++ b/core/FTQ.cpp @@ -39,8 +39,11 @@ namespace olympia if (fetch_target_queue_.size() < ftq_capacity_) { ILOG("FTQ receives first PredictionOutput from BPU"); - fetch_target_queue_.push(prediction); + fetch_target_queue_.push_back(prediction); + if(fetch_target_queue_.size() == 1) { + ftq_it = fetch_target_queue_.begin(); + } sendPrediction_(); } } @@ -49,6 +52,45 @@ namespace olympia { // check if it matches the prediction made by first tier of bpu ILOG("FTQ receives second PredictionOutput from BPU"); + handleMismatch(prediction); + } + + #define TAKEN 0 + #define NOT_TAKEN 1 + + void FTQ::handleMismatch(const BranchPredictor::PredictionOutput & tage_prediction) + { + ILOG("Checking mismatch between BasePredictor and TAGE_SC_L"); + + std::deque :: iterator it = fetch_target_queue_.begin(); + while(it != fetch_target_queue_.end()) { + if(it->instrPC == tage_prediction.instrPC) { + ILOG("BasePredictor prediction direction: " << it->predDirection_); + ILOG("TAGE_SC_L prediction direction: " << tage_prediction.predDirection_); + if(it->predDirection_ != tage_prediction.predDirection_) { + ILOG("Prediction mismatch between tage and base predictor"); + + /*** + * TODO: + * We need to update predPC_ in case there is an update of output + * How to do it in case a not taken prediction is updated to taken? + */ + if(it->predDirection_ == TAKEN && tage_prediction.predDirection_ == NOT_TAKEN) { + it->predPC_ = it->instrPC + 4; + } + else if(it->predDirection_ == NOT_TAKEN && tage_prediction.predDirection_ == TAKEN) { + // ?? + } + + it->predDirection_ = tage_prediction.predDirection_; + + ftq_it = it; + + sendPrediction_(); + break; + } + } + } } void FTQ::getFetchCredits_(const uint32_t & credits) @@ -68,8 +110,9 @@ namespace olympia { fetch_credits_--; ILOG("Send prediction from FTQ to Fetch"); - auto output = fetch_target_queue_.front(); - fetch_target_queue_.pop(); + auto output = *ftq_it; + ftq_it++; + out_fetch_prediction_output_.send(output); } } diff --git a/core/FTQ.hpp b/core/FTQ.hpp index 76abbff0..7a5f8542 100644 --- a/core/FTQ.hpp +++ b/core/FTQ.hpp @@ -12,7 +12,7 @@ #include "ROB.hpp" #include "FlushManager.hpp" -#include +#include namespace olympia { @@ -38,7 +38,10 @@ namespace olympia const uint32_t ftq_capacity_; uint32_t fetch_credits_ = 0; - std::queue fetch_target_queue_; + std::deque fetch_target_queue_; + + // Iterator pointing to next element to send further + std::deque :: iterator ftq_it; sparta::DataInPort in_bpu_first_prediction_output_{ &unit_port_set_, "in_bpu_first_prediction_output", 1}; @@ -66,6 +69,8 @@ namespace olympia // updates ftq appropriately void getSecondPrediction_(const BranchPredictor::PredictionOutput &); + void handleMismatch(const BranchPredictor::PredictionOutput &); + void getFetchCredits_(const uint32_t &); // continuously send instructions to fetch/icache diff --git a/test/core/bpu/BPUSource.hpp b/test/core/bpu/BPUSource.hpp index bfb08212..f560c2fb 100644 --- a/test/core/bpu/BPUSource.hpp +++ b/test/core/bpu/BPUSource.hpp @@ -61,12 +61,27 @@ namespace bpu_test const uint32_t pred_req_buffer_capacity = 8; + void generatePredictionOutput_() { + while(pred_request_buffer_.size() < pred_req_buffer_capacity) { + olympia::BranchPredictor::PredictionRequest pred_request; + pred_request.instType_ = 1; + pred_request.PC_ = 5; + pred_request_buffer_.push_back(pred_request); + } + } + void getCreditsFromBPU_(const uint32_t & credits) { bpu_credits_ += credits; ILOG("Received " << credits << " credits from BPU"); + generatePredictionOutput_(); + //ev_send_pred_req_.schedule(sparta::Clock::Cycle(0)); + /**while(pred_request_buffer_.size() > 0) { + sendPredictionRequest_(); + //ev_send_pred_req_.schedule(sparta::Clock::Cycle(1)); + }**/ sendPredictionRequest_(); } @@ -75,10 +90,9 @@ namespace bpu_test if (bpu_credits_ > 0) { ILOG("Sending PredictionRequest from Fetch to BPU"); - olympia::BranchPredictor::PredictionRequest pred_request; - pred_request.instType_ = 1; - pred_request.PC_ = 5; - out_bpu_prediction_request_.send(pred_request); + olympia::BranchPredictor::PredictionRequest req_to_send = pred_request_buffer_.front(); + pred_request_buffer_.pop_front(); + out_bpu_prediction_request_.send(req_to_send); bpu_credits_--; } } @@ -92,7 +106,7 @@ namespace bpu_test sparta::DataInPort in_bpu_credits_{&unit_port_set_, "in_bpu_credits", 0}; //sparta::Event<> ev_send_pred_req_{&unit_event_set_, "ev_send_pred_req_", - // CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; + // CREATE_SPARTA_HANDLER(BPUSource, sendPredictionRequest_)}; }; using SrcFactory = sparta::ResourceFactory; diff --git a/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED index c7850089..d8386e28 100644 --- a/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED +++ b/test/core/bpu/expected_output/bpu_tb_json.out.EXPECTED @@ -3,8 +3,8 @@ #Exe: #SimulatorVersion: #Repro: -#Start: Saturday Sat Apr 5 17:01:41 2025 -#Elapsed: 0.001278s +#Start: Tuesday Tue Apr 22 05:37:54 2025 +#Elapsed: 0.001596s {0000000000 00000000 top.bpu info} sendCreditsToFetch_: Send 10 credits from BPU to Fetch {0000000000 00000000 top.ftq info} sendCreditsToBPU_: Send 5 credits to BPU {0000000000 00000000 top.sink info} sendCreditsToFTQ_: Send 5 credits from Fetch to FTQ @@ -22,3 +22,9 @@ {0000000004 00000004 top.bpu info} sendSecondPrediction_: Getting direction prediction from TAGE {0000000004 00000004 top.bpu info} sendSecondPrediction_: Sending second PredictionOutput from BPU to FTQ {0000000005 00000005 top.ftq info} getSecondPrediction_: FTQ receives second PredictionOutput from BPU +{0000000005 00000005 top.ftq info} handleMismatch: Checking mismatch between BasePredictor and TAGE_SC_L +{0000000005 00000005 top.ftq info} handleMismatch: BasePredictor prediction direction: 1 +{0000000005 00000005 top.ftq info} handleMismatch: TAGE_SC_L prediction direction: 0 +{0000000005 00000005 top.ftq info} handleMismatch: Prediction mismatch between tage and base predictor +{0000000005 00000005 top.ftq info} sendPrediction_: Send prediction from FTQ to Fetch +{0000000005 00000005 top.sink info} getPredictionOutput_: Fetch recieves prediction output from FTQ From 1bc59f72494e6abf755a6190d8e994e074406273 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Tue, 22 Apr 2025 05:46:34 +0530 Subject: [PATCH 15/15] Reset useful bits after interval --- core/fetch/BPU.cpp | 9 ++++++--- core/fetch/BPU.hpp | 4 ++++ core/fetch/TAGE_SC_L.cpp | 41 +++++++++++++++++++++++++++++++++------- core/fetch/TAGE_SC_L.hpp | 16 ++++++++++++---- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/core/fetch/BPU.cpp b/core/fetch/BPU.cpp index 751ef0b8..1934d536 100644 --- a/core/fetch/BPU.cpp +++ b/core/fetch/BPU.cpp @@ -23,8 +23,8 @@ namespace olympia loop_pred_table_size_(p->loop_pred_table_size), loop_pred_table_way_(p->loop_pred_table_way), base_predictor_(pht_size_, ctr_bits_, btb_size_, ras_size_, ras_enable_overwrite_), - tage_predictor_(tage_bim_table_size_, tage_bim_ctr_bits_, 5, 2, 3, 10, 2, 2, 1024, - tage_tagged_table_num_) + tage_predictor_(tage_bim_table_size_, tage_bim_ctr_bits_, /*5,*/ 2, 3, 10, 2, 2, 1024, + tage_tagged_table_num_, 10) { sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(BPU, sendIntitialCreditsToFetch_)); @@ -98,6 +98,7 @@ namespace olympia ILOG("Getting target from base predictor"); uint64_t target = base_predictor_.getTarget(in.PC_, in.instType_); + output.instrPC = in.PC_; output.predPC_ = target; output.predDirection_ = dir; @@ -119,8 +120,10 @@ namespace olympia PredictionRequest in = predictionRequestBuffer_.front(); ILOG("Getting direction prediction from TAGE"); + output.instrPC = in.PC_; output.predDirection_ = tage_predictor_.predict(in.PC_); - output.predPC_ = 100; + // TAGE only predicts whether branch will be taken or not, so predPC_ value will be ignored + output.predPC_ = 0; ILOG("Sending second PredictionOutput from BPU to FTQ"); out_ftq_second_prediction_output_.send(output); } diff --git a/core/fetch/BPU.hpp b/core/fetch/BPU.hpp index 5f7db2bd..b4d4a67a 100644 --- a/core/fetch/BPU.hpp +++ b/core/fetch/BPU.hpp @@ -36,6 +36,10 @@ namespace olympia public: PredictionOutput() {} + // PC of instruction for which PredictionOutput is generated + // this can be used as an index to find mismatch and update prediction + // between BasePredictor and TAGE_SC_L. + uint64_t instrPC; bool predDirection_; uint64_t predPC_; diff --git a/core/fetch/TAGE_SC_L.cpp b/core/fetch/TAGE_SC_L.cpp index 074e3ee3..c6d7035e 100644 --- a/core/fetch/TAGE_SC_L.cpp +++ b/core/fetch/TAGE_SC_L.cpp @@ -51,6 +51,11 @@ namespace olympia } } + void TageTaggedComponentEntry::resetUseful() + { + useful_ >>= 1; + } + uint8_t TageTaggedComponentEntry::getUseful() { return useful_; } // Tagged component @@ -74,7 +79,6 @@ namespace olympia tage_bim_ctr_bits_(tage_base_ctr_bits), tage_bimodal_(tage_bim_table_size_) { - // recheck value tage_bim_max_ctr_ = 1 << tage_bim_ctr_bits_; // initialize counter at all index to be 0 @@ -104,13 +108,15 @@ namespace olympia // TAGE Tage::Tage(const uint32_t & tage_bim_table_size, const uint8_t & tage_bim_ctr_bits, - const uint16_t & tage_max_index_bits, const uint8_t & tage_tagged_ctr_bits, + //const uint16_t & tage_max_index_bits, + const uint8_t & tage_tagged_ctr_bits, const uint8_t & tage_tagged_useful_bits, const uint32_t & tage_global_history_len, const uint32_t & tage_min_hist_len, const uint8_t & tage_hist_alpha, - const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component) : + const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component, + const uint16_t & tage_tagged_component_entry_num) : tage_bim_table_size_(tage_bim_table_size), tage_bim_ctr_bits_(tage_bim_ctr_bits), - tage_max_index_bits_(tage_max_index_bits), + //tage_max_index_bits_(tage_max_index_bits), tage_tagged_ctr_bits_(tage_tagged_ctr_bits), tage_tagged_useful_bits_(tage_tagged_useful_bits), tage_global_history_len_(tage_global_history_len), @@ -118,10 +124,10 @@ namespace olympia tage_hist_alpha_(tage_hist_alpha), tage_reset_useful_interval_(tage_reset_useful_interval), tage_num_component_(tage_num_component), - tage_bim_(tage_bim_table_size_, tage_bim_table_size_), - // for now number of tagged component entry in each component is set as 10 + tage_tagged_component_entry_num_(tage_tagged_component_entry_num), + tage_bim_(tage_bim_table_size_, tage_bim_ctr_bits_), tage_tagged_components_(tage_num_component_, - {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, 10}), + {tage_tagged_ctr_bits_, tage_tagged_useful_bits_, tage_tagged_component_entry_num_}), tage_global_history_(tage_global_history_len_, 0) { } @@ -153,8 +159,29 @@ namespace olympia return calculated_tag; } + void Tage::updateUsefulBits() + { + for(auto & tage_table : tage_tagged_components_) + { + for(auto & entry : tage_table.tage_tagged_component_) + { + entry.resetUseful(); + } + } + } + uint8_t Tage::predict(const uint64_t & ip) { + if(reset_counter < tage_reset_useful_interval_) + { + reset_counter++; + } + else if(reset_counter == tage_reset_useful_interval_) + { + reset_counter = 0; + updateUsefulBits(); + } + uint8_t default_prediction = tage_bim_.getPrediction(ip); uint8_t num_counter = 1; uint8_t tage_prediction = default_prediction; diff --git a/core/fetch/TAGE_SC_L.hpp b/core/fetch/TAGE_SC_L.hpp index 1f30c69d..e3adf564 100644 --- a/core/fetch/TAGE_SC_L.hpp +++ b/core/fetch/TAGE_SC_L.hpp @@ -19,6 +19,7 @@ namespace olympia uint8_t getCtr(); void incrementUseful(); void decrementUseful(); + void resetUseful(); uint8_t getUseful(); uint16_t tag; @@ -41,7 +42,7 @@ namespace olympia TageTaggedComponentEntry getTageComponentEntryAtIndex(const uint16_t & index); - private: + //private: const uint8_t tage_ctr_bits_; const uint8_t tage_useful_bits_; const uint16_t num_tagged_entry_; @@ -68,17 +69,19 @@ namespace olympia { public: Tage(const uint32_t & tage_bim_table_size, const uint8_t & tage_bim_ctr_bits, - const uint16_t & tage_max_index_bits, const uint8_t & tage_tagged_ctr_bits, + //const uint16_t & tage_max_index_bits, + const uint8_t & tage_tagged_ctr_bits, const uint8_t & tage_tagged_useful_bits, const uint32_t & tage_global_history_len, const uint32_t & tage_min_hist_len, const uint8_t & tage_hist_alpha, - const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component); + const uint32_t & tage_reset_useful_interval, const uint8_t & tage_num_component, + const uint16_t & tage_tagged_component_entry_num); uint8_t predict(const uint64_t & ip); private: const uint32_t tage_bim_table_size_; const uint8_t tage_bim_ctr_bits_; - uint16_t tage_max_index_bits_; + //uint16_t tage_max_index_bits_; const uint8_t tage_tagged_ctr_bits_; const uint8_t tage_tagged_useful_bits_; const uint32_t tage_global_history_len_; @@ -86,16 +89,21 @@ namespace olympia const uint8_t tage_hist_alpha_; const uint32_t tage_reset_useful_interval_; const uint8_t tage_num_component_; + const uint16_t tage_tagged_component_entry_num_; TageBIM tage_bim_; std::vector tage_tagged_components_; std::vector tage_global_history_; + uint32_t reset_counter = 0; + // Helper function to compress tage ghr into a numeric uint64_t compressed_ghr(const uint8_t & req_length); // Helper function to calculate hash too index into tage table uint32_t hashAddr(const uint64_t & PC, const uint8_t & component_number); // Helper function to calcuate tag uint16_t calculatedTag(const uint64_t & PC, const uint8_t & component_number); + + void updateUsefulBits(); }; /***