diff --git a/core/BPTypes.hpp b/core/BPTypes.hpp new file mode 100644 index 00000000..e9642982 --- /dev/null +++ b/core/BPTypes.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace olympia +{ + class PredictionInput + { + public: + uint64_t PC; + uint8_t instType; + }; + + class PredictionOutput + { + public: + bool predDirection; + uint64_t predPC; + }; + + class UpdateInput + { + public: + uint64_t instrPC; + bool correctedDirection; + uint64_t correctedPC; + }; + + enum class branchType { + CONDITIONAL_BRANCH, + JMP, + RET + }; + +} \ No newline at end of file diff --git a/core/BPU.cpp b/core/BPU.cpp new file mode 100644 index 00000000..cbfc9c41 --- /dev/null +++ b/core/BPU.cpp @@ -0,0 +1,40 @@ +#include "BPU.hpp" +#include "BPTypes.hpp" + +#include + +namespace olympia +{ + BPU::name = "bpu"; + BPU::BPU(sparta::TreeNode* node, BPUParameterSet* p) : + sparta::Unit(node), + ghr_size_(p->ghr_size) + + { + in_fetch_prediction_credits_.createConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionCredits_, uint32_t)); + + in_fetch_prediction_req_.createConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(BPU, receivePredictionInput_, PredictionInput)); + + } + void BPU::receivePredictionCredits_(uint32_t credit) { + std::cout << credit << std::endl; + } + + void BPU::recievePredictionInput(PredictionInput) { + std::cout << "hello" << std::endl; + } + + void BPU::updateGHRTaken() { + ghr_ = ghr_ << 1; + ghr_ = ghr_ | 0b1; + } + + void BPU::updateGHRNotTaken() { + ghr_ = ghr_ << 1; + ghr_ = ghr_ & 0b0; + } +} + + diff --git a/core/BPU.hpp b/core/BPU.hpp new file mode 100644 index 00000000..814e8962 --- /dev/null +++ b/core/BPU.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/ParameterSet.hpp" +#include "sparta/ports/DataPort.hpp" +#include "sparta/ports/SignalPort.hpp" + +#include "BPTypes.hpp" + +#include +#include +#include + +namespace olympia +{ + class BPU : public sparta::Unit + { + public: + class BPUParameterSet : public sparta::ParameterSet + { + public: + BPUParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) {} + + // Parameters for the Branch Prediction Unit + PARAMETER(uint32_t, ghr_size, 1024, "Number of history bits in GHR"); + + + }; + static const char name[]; + BPU(sparta::TreeNode* n, sparta::ParameterSet* p); + + private: + void receivePredictionCredits_(uint32_t); + void recievePredictionInput(PredictionInput); + + // update GHR when last branch is taken + void updateGHRTaken(); + // update GHR when last branch is not taken + void updateGHRNotTaken(); + + // Number of history bits in GHR + uint32_t ghr_size_; + + // Global History Register(GHR) + uint32_t ghr_ = 0;; + + // input ports + // verify cycle delay required + sparta::DataInPort in_fetch_prediction_credits_ {&unit_port_set_, + "in_fetch_prediction_credits", 0}; + + // verify cycle delay required + sparta::DataInPort in_fetch_prediction_req_ {&unit_port_set_, + "in_fetch_prediction_req", 0}; + + // input port to receieve update input + + + // output ports + // verify cycle delay required + sparta::DataOutPort out_fetch_prediction_res_ {&unit_port_set_, + "out_fetch_prediction_res", 0}; + + + // counters + sparta::Counter pred_req_num_ {getStatisticSet(), "pred_req_num", + "Number of prediction requests made", + sparta::Counter::COUNT_NORMAL}; + + sparta::Counter mispred_num_ {getStatisticSet(), "mispred_num", + "Number of mispredictions", + sparta::Counter::COUNT_NORMAL}; + + sparta::StatisticDef mispred_ratio_ {getStatisticSet(), "misprediction ratio", + "misprediction/total_prediction", getStatisticSet(), + "pred_req_num/mispred_num"}; + }; +} \ No newline at end of file diff --git a/core/BasePredictor.cpp b/core/BasePredictor.cpp new file mode 100644 index 00000000..5fcc307a --- /dev/null +++ b/core/BasePredictor.cpp @@ -0,0 +1,120 @@ +#include "BasePredictor.hpp" + +namespace olympia +{ +// Pattern History Table +void PatternHistoryTable::incrementCounter(uint32_t idx) { + if(pattern_history_table_.at(idx) == ctr_bits_val_) { + return; + } + else { + pattern_history_table_.at(idx)++; + } +} + +void PatternHistoryTable::decrementCounter(uint32_t idx) { + if(pattern_history_table_.at(idx) == 0) { + return; + } + else { + pattern_history_table_.at(idx)--; + } +} + +uint8_t PatternHistoryTable::getPrediction(uint32_t idx) { + return pattern_history_table_.at(idx); +} + +// Branch Target Buffer +bool BranchTargetBuffer::isHit(uint64_t PC) { + if(branch_target_buffer_.count(PC)) { + return true; + } + else { + return false; + } +} + + +uint64_t BranchTargetBuffer::getPredictedPC(uint64_t PC) { + if(branch_target_buffer_.count(PC)) { + return branch_target_buffer_[PC]; + } + else { + return 0; // recheck what to return in this condition + } + +} + +bool BranchTargetBuffer::addEntry(uint64_t PC, uint64_t targetPC) { + if(branch_target_buffer_.size() == btb_size_) { + return false; + } + else { + branch_target_buffer_.insert(std::pair(PC, targetPC) ); + return true; + } +} + +bool BranchTargetBuffer::removeEntry(uint64_t PC) { + if(branch_target_buffer_.count(PC)) { + branch_target_buffer_.erase(PC); + return true; + } + else { + return false; + } +} + +// Return Address Stack +bool ReturnAddressStack::pushAddress(uint64_t address) { + if(return_address_stack_.size() == ras_size_) { + return false; + } + else { + return_address_stack_.push(address); + return true; + } +} + +uint64_t ReturnAddressStack::popAddress() { + if(return_address_stack_.size() == 0) { + return 0; // recheck what to return in this condition + } + else { + uint64_t address_ = return_address_stack_.top(); + return_address_stack_.pop(); + return address_; + } +} + +// BasePredictor +void BasePredictor::handlePredictionReq(PredictionInput predIn) { + if(predIn.instType == branchType.JMP) { + handleJMP(predIn); + } + else if(predIn.instType == branchType.RET || + predIn.instType == branchType.CONDITIONAL_BRANCH) { + // make prediction + // event to send prediction to fetch + } +} + +void BasePredictor::handleJMP(PredictionInput predInput) { + // push PC to RAS + returnAddressStack.pushAddress(predInput.PC); + + // PC hit on BTB? + if(branchTargetBuffer.isHit(predInput.PC)) { + // event to send PC + } + else { + // allocate entry in BTB + } + +} + +void BasePredictor::handleRET(PredictionInput predInput); +void BasePredictor::handleBRANCH(PredictionInput predInput); + +} diff --git a/core/BasePredictor.hpp b/core/BasePredictor.hpp new file mode 100644 index 00000000..28e56fa4 --- /dev/null +++ b/core/BasePredictor.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include "BPTypes.hpp" + +namespace olympia +{ + class PatternHistoryTable + { + public: + PatternHistoryTable(uint32_t pht_size, uint8_t ctr_bits) : + pht_size_(pht_size), ctr_bits_(ctr_bits) + { + ctr_bits_val_ = pow(2, ctr_bits_); + } + + // To increment and decrement within set bounds of ctr_bits + void incrementCounter(uint32_t idx); + void decrementCounter(uint32_t idx); + uint8_t getPrediction(uint32_t idx); + + private: + const uint32_t pht_size_; + const uint8_t ctr_bits_; + const uint8_t ctr_bits_val_; + + std::map pattern_history_table_; + + }; + + class BranchTargetBuffer + { + public: + BranchTargetBuffer(uint32_t btb_size) : btb_size_(btb_size) {} + + bool isHit(uint64_t PC); + uint64_t getPredictedPC(uint64_t PC); + bool addEntry(uint64_t PC, uint64_t targetPC); + bool removeEntry(uint64_t PC); + + private: + const uint32_t btb_size_; + std::map branch_target_buffer_; + }; + + class ReturnAddressStack + { + public: + ReturnAddressStack(uint32_t ras_size) : ras_size_(ras_size) {} + + // To bound the size of RAS + bool pushAddress(uint64_t address); + uint64_t popAddress(); + + private: + const uint32_t ras_size_; + std::stack return_address_stack_; + + }; + + class BasePredictor + { + public: + BasePredictor(uint32_t pht_size, uint8_t ctr_bits, + uint32_t btb_size, uint32_t ras_size) : + patternHistoryTable(pht_size, ctr_bits), + branchTargetBuffer(bht_size), + returnAddressStack(ras_size); + {} + + PatternHistoryTable patternHistoryTable; + BranchTargetBuffer branchTargetBuffer; + ReturnAddressStack returnAddressStack; + + void receivedPredictionReq(); + PredictionOutput makePrediction(PredictionInput predInput); + void handleJMP(PredictionInput predInput); + void handleRET(PredictionInput predInput); + void handleBRANCH(PredictionInput predInput); + + }; +} + diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 47657c75..db351767 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(core SimpleBranchPred.cpp ICache.cpp Fetch.cpp + BPU.cpp Decode.cpp VectorUopGenerator.cpp Rename.cpp diff --git a/core/CPUFactories.hpp b/core/CPUFactories.hpp index 2947ba89..35e7ea7e 100644 --- a/core/CPUFactories.hpp +++ b/core/CPUFactories.hpp @@ -7,6 +7,7 @@ #include "Core.hpp" #include "ICache.hpp" #include "Fetch.hpp" +#include "BPU.hpp" #include "Decode.hpp" #include "VectorUopGenerator.hpp" #include "Rename.hpp" @@ -49,6 +50,10 @@ namespace olympia{ sparta::ResourceFactory fetch_rf; + //! \brief Resource Factory to build a BPU Unit + sparta::ResourceFactory bpu_rf; + //! \brief Resource Factory to build a Decode Unit sparta::ResourceFactory decode_rf; diff --git a/core/CPUTopology.cpp b/core/CPUTopology.cpp index c2fc310a..21a6e219 100644 --- a/core/CPUTopology.cpp +++ b/core/CPUTopology.cpp @@ -43,6 +43,14 @@ olympia::CoreTopologySimple::CoreTopologySimple(){ sparta::TreeNode::GROUP_IDX_NONE, &factories->fetch_rf }, + { + "bpu", + "cpu.core*", + "BPU Unit", + sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, + &factories->bpu_rf + }, { "decode", "cpu.core*", @@ -188,6 +196,14 @@ olympia::CoreTopologySimple::CoreTopologySimple(){ "cpu.core*.fetch.ports.in_fetch_queue_credits", "cpu.core*.decode.ports.out_fetch_queue_credits" }, + { + "cpu.core*.fetch.ports.out_bpu_prediction_credits", + "cpu.core*.bpu.ports.in_fetch_prediction_credits" + }, + { + "cpu.core*.fetch.ports.out_bpu_prediction_req", + "cpu.core*.bpu.ports.in_fetch_prediction_req" + }, { "cpu.core*.decode.ports.out_uop_queue_write", "cpu.core*.rename.ports.in_uop_queue_append" diff --git a/core/Fetch.hpp b/core/Fetch.hpp index 8eb46c38..e323c073 100644 --- a/core/Fetch.hpp +++ b/core/Fetch.hpp @@ -20,6 +20,7 @@ #include "InstGroup.hpp" #include "FlushManager.hpp" #include "MemoryAccessInfo.hpp" +#include "BPU.hpp" namespace olympia { @@ -103,6 +104,13 @@ namespace olympia sparta::DataInPort in_icache_fetch_credits_ {&unit_port_set_, "in_icache_fetch_credits", sparta::SchedulingPhase::Tick, 0}; + sparta::DataOutPort out_bpu_prediction_credits_ {&unit_port_set_, + "out_bpu_prediction_credits", 0}; + + // verify cycle delay required + sparta::DataOutPort out_bpu_prediction_req_ {&unit_port_set_, + "out_bpu_prediction_req", 0}; + //////////////////////////////////////////////////////////////////////////////// // Instruction fetch diff --git a/core/TAGE_SC_L.cpp b/core/TAGE_SC_L.cpp new file mode 100644 index 00000000..f14dfb94 --- /dev/null +++ b/core/TAGE_SC_L.cpp @@ -0,0 +1 @@ +#include "TAGE_SC_L.hpp" diff --git a/core/TAGE_SC_L.hpp b/core/TAGE_SC_L.hpp new file mode 100644 index 00000000..2c20ae08 --- /dev/null +++ b/core/TAGE_SC_L.hpp @@ -0,0 +1,38 @@ +#pragma once + +namespace olympia +{ + class TageBIM + { + public: + TageBIM(uint32_t tage_bim_size, uint8_t tage_bim_ctr_bits) : + tage_bim_size_(tage_bim_size), + tage_bim_ctr_bits_(tage_bim_ctr_bits) + { + tage_bim_ctr_bits_val_ = pow(2, tage_bim_ctr_bits_); + } + + private: + const uint32_t tage_bim_size_; + const uint8_t tage_bim_ctr_bits_; + const uint8_t tage_bim_ctr_bits_val_; + + }; + + class TageTaggedComponent + { + public: + TageTaggedComponent(uint16_t tag, uint8_t ctr, uint8_t u) : + tag_(tag), ctr_(ctr), u_(u) {} + private: + const uint16_t tag_; + const uint8_t ctr_; + const uint8_t u_; + }; + + class Tage + { + public: + + }; +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 41d1472b..f5e96f76 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,6 +34,7 @@ add_subdirectory(core/lsu) add_subdirectory(core/issue_queue) add_subdirectory(core/icache) add_subdirectory(core/branch_pred) +add_subdirectory(core/bpu) add_subdirectory(core/dcache) add_subdirectory(core/vector) add_subdirectory(fusion) diff --git a/test/core/bpu/BPTypes.hpp b/test/core/bpu/BPTypes.hpp new file mode 100644 index 00000000..e9642982 --- /dev/null +++ b/test/core/bpu/BPTypes.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace olympia +{ + class PredictionInput + { + public: + uint64_t PC; + uint8_t instType; + }; + + class PredictionOutput + { + public: + bool predDirection; + uint64_t predPC; + }; + + class UpdateInput + { + public: + uint64_t instrPC; + bool correctedDirection; + uint64_t correctedPC; + }; + + enum class branchType { + CONDITIONAL_BRANCH, + JMP, + RET + }; + +} \ No newline at end of file diff --git a/test/core/bpu/BPU_test.cpp b/test/core/bpu/BPU_test.cpp new file mode 100644 index 00000000..fafb3215 --- /dev/null +++ b/test/core/bpu/BPU_test.cpp @@ -0,0 +1,141 @@ +// BPU test + +#include "sparta/sparta.hpp" +#include "sparta/app/Simulation.hpp" +#include "sparta/app/CommandLineSimulator.hpp" +#include "sparta/utils/SpartaTester.hpp" + +#include + +TEST_INIT +olympia::InstAllocator inst_allocator(2000, 1000); + +class BPUSim : public class sparta::app::Simulation +{ + using BPUFactory = sparta::ResourceFactory; + public: + BPUSim(sparta::Scheduler *sched) : sparta::app::Simulatiuon("BPUSim", sched) + input_file_(input_file), + test_tap_(getRoot(), "info", output_file) + {} + + virtual ~ICacheSim(){ + getRoot()->enterTeardown(); + } + + private: + void buildTree_() override { + auto rtn = getRoot(); + + allocators_tn.reset(new olympia::OlympiaAllocators(rtn)); + + 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* dut = + new sparta::ResourceTreeNode(rtn, "dut", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "DUT", &dut_fact); + + tns_to_delete_.emplace_back(dut); + + // 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(); + +// set all ports appropriately + sparta::bind(root_node->getChildAs(), root_node->getChildAs()); + + sparta::bind(root_node->getChildAs(), root_node->getChildAs()); + + sparta::bind(root_node->getChildAs(), root_node->getChildAs()); + + sparta::bind(root_node->getChildAs(), root_node->getChildAs()); + + } + + std::unique_ptr allocators_tn_; + + olympia::MavisFactory mavis_fact; + BPUFactory bpu_fact; + + core_test::SrcFactory source_fact; + core_test::SinkFactory sink_fact; + + std::vector> tns_to_delete_; + std::vector exe_units_; + + const std::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"; + std::vector datafiles; + std::string input_file; + + sparta::app::CommandLineSimulator cls(USAGE, DEFAULTS); + auto & app_opts = cls.getApplicationOptions(); + + 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(); + + pos_opts.add("output_file", -1); + + int err_code = 0; + if(!cls.parse(argc, argv, err_code)){ + sparta_assert(false, "Command line parsing failed"); // Any errors already printed to cerr + } +} + +int main(int argc, char **argv) { + if(!runTest(argc, argv)) { + return 1; + } + + REPORT_ERROR; + return (int)ERROR_CODE; +} \ No newline at end of file diff --git a/test/core/bpu/Bpu_unit.cpp b/test/core/bpu/Bpu_unit.cpp new file mode 100644 index 00000000..0fc0f0b1 --- /dev/null +++ b/test/core/bpu/Bpu_unit.cpp @@ -0,0 +1,42 @@ +#include "Bpu_unit.hpp" +#include "sparta/utils/LogUtils.hpp" + +namespace olympia +{ + Bpu_unit::Bpu_unit(sparta::TreeNode* node, const Bpu_unitParameterSet* p) : + sparta::Unit(node), + ghr_size_(p->ghr_size), + pht_size_(p->pht_size), + pht_ctr_bits_(p->pht_ctr_bits) + { + in_bpu_predInput_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(receivePredictionInput_, PredictionInput)); + in_bpu_sinkCredits_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(receiveSinkCredits_, uint32_t)); + in_dut_flush_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA()); + + sparta::StartupEvent(node, CREATE_SPARTA_HANDLER()); + } + // function definitions below + void Bpu_unit::sendInitialCredits_() { + out_src_credits_.send(1); + } + void Bpu_unit::receivePredictionInput_(const PredictionInput & pred_input) { + predInput_buffer_.push_back(pred_input); + } + uint8_t Bpu_unit::predictBranch(int idx) { + + } + + PredictionOutput genOutput(uint8_t pred) { + PredictionOutput temp; + temp.predDirection = pred; + } + + void Bpu_unit::receiveSinkCredits_(const uint32_t & credits) { + sink_credits_ += credits; + + // put some mechanism to send prediction output to sink below this + } + void sendPrediction_() { + + } +} \ No newline at end of file diff --git a/test/core/bpu/Bpu_unit.hpp b/test/core/bpu/Bpu_unit.hpp new file mode 100644 index 00000000..72352da5 --- /dev/null +++ b/test/core/bpu/Bpu_unit.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "FlushManager.hpp" +#include "InstGroup.hpp" +#include "BPTypes.hpp" + +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/UniqueEvent.hpp" +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/simulation/ParameterSet.hpp" + +#include +#include + +namespace olympia +{ + class Bpu_unit : public sparta::Unit + { + public: + class Bpu_unitParameterSet : public sparta::ParameterSet + { + public: + Bpu_unitParameterSet(sparta::TreeNode *n) : sparta::ParameterSet(n) + {} + + PARAMETER(uint32_t, ghr_size, 1000, "Size of GHR") + PARAMETER(uint32_t, pht_size, 1024, "Size of PHT") + PARAMETER(uint32_t, pht_ctr_bits, 2, "Counter bits of PHT") + }; + Bpu_unit(sparta::TreeNode* node, const Bpu_unitParameterSet* p); + + static constexpr char name[] = "Bpu_unit"; + + private: + // Input port to BPU from source + sparta::DataInPort in_bpu_predInput_{&unit_port_set_, "in_bpu_predInput", 1}; + // Output port of BPU to send credit to source + sparta::DataOutPort out_src_credits_{&unit_port_set_, "out_src_credits"}; + + // output port to sink from BPU + sparta::DataOutPort out_sink_predOutput_{&unit_port_set_, "out_sink_predOutput"}; + // input port of BPU to receive credit from sink + sparta::DataInPort in_bpu_sinkCredits_{&unit_port_set_, "in_bpu_sinkCredits", sparta::SchedulingPhase::Tick, 0}; + + // for flush + sparta::DataInPort in_dut_flush_{&unit_port_set_, "in_dut_flush", sparta::SchedulingPhase::Flush, 1}; + + // TODO: put events here + + // send credits from BPU to source + void sendInitialCredits_(); + // receive prediction input from source + void receivePredictionInput_(const PredictionInput & pred_input); + // mechanism to make prediction + uint8_t predictBranch(int idx); + // generate prediction output + PredictionOutput genOutput(uint8_t pred); + // receive credits from sink + void receiveSinkCredits_(const uint32_t & credits); + // send prediction output to sink + void sendPrediction_(); + + uint32_t sink_credits_ = 0; + uint32_t ghr_size_; + uint32_t pht_size_; + uint32_t pht_ctr_bits_; + std::vector predInput_buffer_; + + std::map pattern_history_table_; + + + } +} \ No newline at end of file diff --git a/test/core/bpu/CMakeLists.txt b/test/core/bpu/CMakeLists.txt new file mode 100644 index 00000000..cfdde3eb --- /dev/null +++ b/test/core/bpu/CMakeLists.txt @@ -0,0 +1,33 @@ +set(PRJ "Bpu_test") +set(EXE "${PRJ}_exec") + +# sanity check +set(TST1, "${PRJ}_test") +#zstf input file +set(TST2, "${PRJ}_stf_test") + +# test args +set(STF ./traces/bpu_basic_test.stf) + +# configuration +set(CFG config/config.yaml) + +project(${PRJ}) + +add_executable(${EXE} Bpu_test.cpp Bpu_unit.cpp src.cpp sink.cpp) +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} tb.out -c ${CFG}) +sparta_named_test(${TST2} ${EXE} tb_stf.out --input_file ${STF} -c ${CFG}) + + diff --git a/test/core/bpu/sink.cpp b/test/core/bpu/sink.cpp new file mode 100644 index 00000000..51b8da19 --- /dev/null +++ b/test/core/bpu/sink.cpp @@ -0,0 +1,19 @@ +#include "sink.hpp" + +namespace olympia +{ + sink::sink(sparta::TreeNode* n, const sinkParameterSet* p) : + sparta::Unit(n), + { + // register handle all ports + in_bpu_predOutput_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(receivePrediction_, PredictionOutput)); + } + + void sink::sendCreditsToBPU_() { + out_bpu_sinkCredits_.send(1); + } + + void sink::receivePrediction_(const PredictionOutput & pred_output) { + pred_output_buffer_.push_back(pred_output); + } +} \ No newline at end of file diff --git a/test/core/bpu/sink.hpp b/test/core/bpu/sink.hpp new file mode 100644 index 00000000..c39b803d --- /dev/null +++ b/test/core/bpu/sink.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "FlushManager.hpp" +#include "InstGroup.hpp" +#include "BPTypes.hpp" + +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/UniqueEvent.hpp" +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/simulation/ParameterSet.hpp" + +#include + +namespace olympia +{ + class sink : public sparta::Unit + { + public: + class sinkParamterSet : public sparta::ParameterSet + { + public: + sinkParameterSet(sparta::TreeNode* n) : sparta::ParameterSet(n) + {} + }; + sink(sparta::TreeNode* n, const sinkParameterSet* p); + + void sendCreditsToBPU_(); + + void receivePrediction_(const PredictionOutput & pred_output); + + private: + // input port to receive prediction output from bpu + sparta::DataInPort in_bpu_predOutput{&unit_port_set_, "in_bpu_predOutput"}; // yet to add cycle delay + + // port to send credits to bpu + sparta::DataOutPort out_bpu_sinkCredits_{&unit_port_set, "out_bpu_sinkCredits"}; + + std::vector pred_output_buffer_; + + + } +} \ No newline at end of file diff --git a/test/core/bpu/src.cpp b/test/core/bpu/src.cpp new file mode 100644 index 00000000..27f214fe --- /dev/null +++ b/test/core/bpu/src.cpp @@ -0,0 +1,43 @@ +#include "src.hpp" + +namespace olympia +{ + src::src(sparta::TreeNode* n, const srcParameterSet* p) : + sparta::Unit(n) + { + // register handle all ports + in_bpu_credits_.regsiterConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(receieveCreditsFromBPU_, uint32_t)); + } + + + + void src::readInstruction_() { + olympia::InstGroupPtr inst_groups(new olympia::InstGroup); + olympia::Inst::PtrType dinst; + + if (inst_generator_) + { + if (dinst = inst_generator_->getNextInst(getClock()), nullptr != dinst) + { + dinst->setUniqueID(unique_id_++); + inst_groups->emplace_back(dinst); + --dut_credits_; + } + } + // Send inst group to the BPU + if (!inst_groups->empty()) + { + sendPredictionRequest_(inst_group); + } + + } + + void src::sendPredictionRequest_(olympia::InstGroupPtr & inst_group) { + // extract relevant data from inst_groups, generate predictionRequest + // then send to BPU through out_bpu_predReq_ + } + + void src::receieveCreditsFromBPU_(const uint32_t & credits) { + bpu_credits_ += credits; + } +} \ No newline at end of file diff --git a/test/core/bpu/src.hpp b/test/core/bpu/src.hpp new file mode 100644 index 00000000..66318013 --- /dev/null +++ b/test/core/bpu/src.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "FlushManager.hpp" +#include "InstGroup.hpp" +#include "BPTypes.hpp" + +#include "sparta/ports/DataPort.hpp" +#include "sparta/events/UniqueEvent.hpp" +#include "sparta/simulation/Unit.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/simulation/ParameterSet.hpp" + +namespace olympia +{ + class src : public sparta::Unit + { + public: + class srcParamterSet : public sparta::ParamterSet + { + public: + srcParameterSet(sparta::TreeNode *n) : sparta::ParameterSet(n) + {} + }; + src(sparta::TreeNode* n, const srcParameterSet* p); + + private: + // port from source to bpu to send prediction input + sparta::DataOutPort out_bpu_predReq_{&unit_port_set_, "out_bpu_predReq"}; + + // input port in bpu to receive credits from bpu + sparta::DataInPort in_bpu_credits_{&unit_port_set_, "in_bpu_credits", 0}; + + // todo: sparta event comes here + + uint32_t bpu_credits_ = 0; + + void receieveCreditsFromBPU_(const uint32_t & credits); + void readInstruction_(); + void sendPredictionRequest_(olympia::InstGroupPtr & inst_group); + }; + + using srcFactory = sparta::ResourceFactory; +} \ No newline at end of file