diff --git a/DRAMSys/library/CMakeLists.txt b/DRAMSys/library/CMakeLists.txt index ada20041..8549b70d 100644 --- a/DRAMSys/library/CMakeLists.txt +++ b/DRAMSys/library/CMakeLists.txt @@ -91,6 +91,7 @@ add_library(DRAMSysLibrary src/configuration/memspec/MemSpecDDR4.cpp src/configuration/memspec/MemSpecDDR5.cpp src/configuration/memspec/MemSpecLPDDR4.cpp + src/configuration/memspec/MemSpecLPDDR5.cpp src/configuration/memspec/MemSpecWideIO.cpp src/configuration/memspec/MemSpecWideIO2.cpp src/configuration/memspec/MemSpecGDDR5.cpp @@ -109,6 +110,7 @@ add_library(DRAMSysLibrary src/controller/checker/CheckerDDR4.cpp src/controller/checker/CheckerDDR5.cpp src/controller/checker/CheckerLPDDR4.cpp + src/controller/checker/CheckerLPDDR5.cpp src/controller/checker/CheckerWideIO.cpp src/controller/checker/CheckerWideIO2.cpp src/controller/checker/CheckerGDDR5.cpp @@ -129,6 +131,7 @@ add_library(DRAMSysLibrary src/controller/refresh/RefreshManagerDummy.cpp src/controller/refresh/RefreshManagerAllBank.cpp src/controller/refresh/RefreshManagerPerBank.cpp + src/controller/refresh/RefreshManagerPer2Bank.cpp src/controller/refresh/RefreshManagerSameBank.cpp src/controller/respqueue/RespQueueIF.h @@ -164,6 +167,7 @@ add_library(DRAMSysLibrary src/simulation/dram/DramDDR4.cpp src/simulation/dram/DramDDR5.cpp src/simulation/dram/DramLPDDR4.cpp + src/simulation/dram/DramLPDDR5.cpp src/simulation/dram/DramWideIO.cpp src/simulation/dram/DramWideIO2.cpp src/simulation/dram/DramGDDR5.cpp diff --git a/DRAMSys/library/src/configuration/Configuration.cpp b/DRAMSys/library/src/configuration/Configuration.cpp index 75dd7d5e..d9de822b 100644 --- a/DRAMSys/library/src/configuration/Configuration.cpp +++ b/DRAMSys/library/src/configuration/Configuration.cpp @@ -46,6 +46,7 @@ #include "memspec/MemSpecDDR5.h" #include "memspec/MemSpecWideIO.h" #include "memspec/MemSpecLPDDR4.h" +#include "memspec/MemSpecLPDDR5.h" #include "memspec/MemSpecWideIO2.h" #include "memspec/MemSpecHBM2.h" #include "memspec/MemSpecGDDR5.h" @@ -161,6 +162,8 @@ void Configuration::setParameter(const std::string &name, const nlohmann::json & refreshPolicy = RefreshPolicy::AllBank; else if (value == "PerBank" || value == "Bankwise") refreshPolicy = RefreshPolicy::PerBank; + else if (value == "Per2Bank") + refreshPolicy = RefreshPolicy::Per2Bank; else if (value == "SameBank" || value == "Groupwise") refreshPolicy = RefreshPolicy::SameBank; else @@ -348,6 +351,8 @@ void Configuration::loadMemSpec(Configuration &config, const std::string &_memsp memSpec = new MemSpecDDR5(jMemSpec); else if (memoryType == "LPDDR4") memSpec = new MemSpecLPDDR4(jMemSpec); + else if (memoryType == "LPDDR5") + memSpec = new MemSpecLPDDR5(jMemSpec); else if (memoryType == "WIDEIO_SDR") memSpec = new MemSpecWideIO(jMemSpec); else if (memoryType == "WIDEIO2") diff --git a/DRAMSys/library/src/configuration/Configuration.h b/DRAMSys/library/src/configuration/Configuration.h index 800a8286..a7538f24 100644 --- a/DRAMSys/library/src/configuration/Configuration.h +++ b/DRAMSys/library/src/configuration/Configuration.h @@ -73,7 +73,7 @@ public: enum class RespQueue {Fifo, Reorder} respQueue = RespQueue::Fifo; enum class Arbiter {Simple, Fifo, Reorder} arbiter = Arbiter::Simple; unsigned int requestBufferSize = 8; - enum class RefreshPolicy {NoRefresh, AllBank, PerBank, SameBank} refreshPolicy = RefreshPolicy::AllBank; + enum class RefreshPolicy {NoRefresh, PerBank, Per2Bank, SameBank, AllBank} refreshPolicy = RefreshPolicy::AllBank; unsigned int refreshMaxPostponed = 0; unsigned int refreshMaxPulledin = 0; enum class PowerDownPolicy {NoPowerDown, Staggered} powerDownPolicy = PowerDownPolicy::NoPowerDown; diff --git a/DRAMSys/library/src/configuration/memspec/MemSpec.h b/DRAMSys/library/src/configuration/memspec/MemSpec.h index 6e1ee9c0..3054eb61 100644 --- a/DRAMSys/library/src/configuration/memspec/MemSpec.h +++ b/DRAMSys/library/src/configuration/memspec/MemSpec.h @@ -71,7 +71,7 @@ public: const sc_core::sc_time tCK; const std::string memoryId; - const enum class MemoryType {DDR3, DDR4, DDR5, LPDDR4, WideIO, + const enum class MemoryType {DDR3, DDR4, DDR5, LPDDR4, LPDDR5, WideIO, WideIO2, GDDR5, GDDR5X, GDDR6, HBM2, STTMRAM} memoryType; virtual ~MemSpec() = default; diff --git a/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.cpp b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.cpp new file mode 100644 index 00000000..5b87b436 --- /dev/null +++ b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include + +#include "../../common/utils.h" +#include "MemSpecLPDDR5.h" + +using namespace sc_core; +using namespace tlm; +using json = nlohmann::json; + +MemSpecLPDDR5::MemSpecLPDDR5(json &memspec) + : MemSpec(memspec, MemoryType::LPDDR5, + parseUint(memspec["memarchitecturespec"]["nbrOfChannels"],"nbrOfChannels"), + parseUint(memspec["memarchitecturespec"]["nbrOfRanks"],"nbrOfRanks"), + parseUint(memspec["memarchitecturespec"]["nbrOfBanks"],"nbrOfBanks"), + parseUint(memspec["memarchitecturespec"]["nbrOfBankGroups"], "nbrOfBankGroups"), + parseUint(memspec["memarchitecturespec"]["nbrOfBanks"],"nbrOfBanks") + / parseUint(memspec["memarchitecturespec"]["nbrOfBankGroups"], "nbrOfBankGroups"), + parseUint(memspec["memarchitecturespec"]["nbrOfBanks"],"nbrOfBanks") + * parseUint(memspec["memarchitecturespec"]["nbrOfRanks"],"nbrOfRanks"), + parseUint(memspec["memarchitecturespec"]["nbrOfBankGroups"], "nbrOfBankGroups") + * parseUint(memspec["memarchitecturespec"]["nbrOfRanks"],"nbrOfRanks"), + 1), + per2BankOffset(parseUint(memspec["memarchitecturespec"]["per2BankOffset"], "per2BankOffset")), + tREFI (tCK * parseUint(memspec["memtimingspec"]["REFI"], "REFI")), + tREFIpb (tCK * parseUint(memspec["memtimingspec"]["REFIpb"], "REFIpb")), + tRFCab (tCK * parseUint(memspec["memtimingspec"]["RFCab"], "RFCab")), + tRFCpb (tCK * parseUint(memspec["memtimingspec"]["RFCpb"], "RFCpb")), + tRPab (tCK * parseUint(memspec["memtimingspec"]["RPab"], "RPab")), + tRPpb (tCK * parseUint(memspec["memtimingspec"]["RPpb"], "RPpb")), + tRCab (tCK * parseUint(memspec["memtimingspec"]["RCab"], "RCab")), + tRCpb (tCK * parseUint(memspec["memtimingspec"]["RCpb"], "RCpb")), + tPPD (tCK * parseUint(memspec["memtimingspec"]["PPD"], "PPD")), + tRAS (tCK * parseUint(memspec["memtimingspec"]["RAS"], "RAS")), + tRCD (tCK * parseUint(memspec["memtimingspec"]["RCD"], "RCD")), + tFAW (tCK * parseUint(memspec["memtimingspec"]["FAW"], "FAW")), + tRRD (tCK * parseUint(memspec["memtimingspec"]["RRD"], "RRD")), + //tCCD (tCK * parseUint(memspec["memtimingspec"]["CCD"], "CCD")), + tRL (tCK * parseUint(memspec["memtimingspec"]["RL"], "RL")), + //tRPST (tCK * parseUint(memspec["memtimingspec"]["RPST"], "RPST")), + //tDQSCK (tCK * parseUint(memspec["memtimingspec"]["DQSCK"], "DQSCK")), + tRBTP (tCK * parseUint(memspec["memtimingspec"]["RBTP"], "RBTP")), + tWL (tCK * parseUint(memspec["memtimingspec"]["WL"], "WL")), + //tDQSS (tCK * parseUint(memspec["memtimingspec"]["DQSS"], "DQSS")), + //tDQS2DQ (tCK * parseUint(memspec["memtimingspec"]["DQS2DQ"], "DQS2DQ")), + tWR (tCK * parseUint(memspec["memtimingspec"]["WR"], "WR")), + //tWPRE (tCK * parseUint(memspec["memtimingspec"]["WPRE"], "WPRE")), + //tWTR (tCK * parseUint(memspec["memtimingspec"]["WTR"], "WTR")), + //tXP (tCK * parseUint(memspec["memtimingspec"]["XP"], "XP")), + //tSR (tCK * parseUint(memspec["memtimingspec"]["SR"], "SR")), + //tXSR (tCK * parseUint(memspec["memtimingspec"]["XSR"], "XSR")), + //tESCKE (tCK * parseUint(memspec["memtimingspec"]["ESCKE"], "ESCKE")), + //tCKE (tCK * parseUint(memspec["memtimingspec"]["CKE"], "CKE")), + //tCMDCKE (tCK * parseUint(memspec["memtimingspec"]["CMDCKE"], "CMDCKE")), + BL_n_min_16(tCK * parseUint(memspec["memtimingspec"]["BL_n_min_16"], "BL_n_min_16")), + BL_n_max_16(tCK * parseUint(memspec["memtimingspec"]["BL_n_max_16"], "BL_n_max_16")), + BL_n_L_16(tCK * parseUint(memspec["memtimingspec"]["BL_n_L_16"], "BL_n_L_16")), + BL_n_S_16(tCK * parseUint(memspec["memtimingspec"]["BL_n_S_16"], "BL_n_S_16")), + BL_n_min_32(tCK * parseUint(memspec["memtimingspec"]["BL_n_min_32"], "BL_n_min_32")), + BL_n_max_32(tCK * parseUint(memspec["memtimingspec"]["BL_n_max_32"], "BL_n_max_32")), + BL_n_L_32(tCK * parseUint(memspec["memtimingspec"]["BL_n_L_32"], "BL_n_L_32")), + BL_n_S_32(tCK * parseUint(memspec["memtimingspec"]["BL_n_S_32"], "BL_n_S_32")), + tWTR_L (tCK * parseUint(memspec["memtimingspec"]["WTR_L"], "WTR_L")), + tWTR_S (tCK * parseUint(memspec["memtimingspec"]["WTR_S"], "WTR_S")), + tWCK2DQO(tCK * parseUint(memspec["memtimingspec"]["WCK2DQO"], "WCK2DQO")), + tpbR2act(tCK * parseUint(memspec["memtimingspec"]["pbR2act"], "pbR2act")), + tpbR2pbR(tCK * parseUint(memspec["memtimingspec"]["pbR2pbR"], "tpbR2pbR")), + tRTRS (tCK * parseUint(memspec["memtimingspec"]["RTRS"], "RTRS")) +{ + commandLengthInCycles[Command::ACT] = 2; + + uint64_t deviceSizeBits = static_cast(banksPerRank) * numberOfRows * numberOfColumns * bitWidth; + uint64_t deviceSizeBytes = deviceSizeBits / 8; + memorySizeBytes = deviceSizeBytes * numberOfRanks * numberOfChannels; + + std::cout << headline << std::endl; + std::cout << "Memory Configuration:" << std::endl << std::endl; + std::cout << " Memory type: " << "LPDDR5" << std::endl; + std::cout << " Memory size in bytes: " << memorySizeBytes << std::endl; + std::cout << " Channels: " << numberOfChannels << std::endl; + std::cout << " Ranks per channel: " << numberOfRanks << std::endl; + std::cout << " Banks per rank: " << banksPerRank << std::endl; + std::cout << " Rows per bank: " << numberOfRows << std::endl; + std::cout << " Columns per row: " << numberOfColumns << std::endl; + std::cout << " Device width in bits: " << bitWidth << std::endl; + std::cout << " Device size in bits: " << deviceSizeBits << std::endl; + std::cout << " Device size in bytes: " << deviceSizeBytes << std::endl; + std::cout << std::endl; +} + +sc_time MemSpecLPDDR5::getRefreshIntervalAB() const +{ + return tREFI; +} + +sc_time MemSpecLPDDR5::getRefreshIntervalPB() const +{ + return tREFIpb; +} + +sc_time MemSpecLPDDR5::getRefreshIntervalP2B() const +{ + return tREFIpb; +} + +unsigned MemSpecLPDDR5::getPer2BankOffset() const +{ + return per2BankOffset; +} + +sc_time MemSpecLPDDR5::getExecutionTime(Command command, const tlm_generic_payload &) const +{ + if (command == Command::PREPB) + return tRPpb; + else if (command == Command::PREAB) + return tRPab; + else if (command == Command::ACT) + return tRCD + tCK; + else if (command == Command::RD) + return tRL + burstDuration; + else if (command == Command::RDA) + return burstDuration + tRBTP + tRPpb; + else if (command == Command::WR) + return tWL + burstDuration; + else if (command == Command::WRA) + return tWL + burstDuration + tWR + tRPpb; + else if (command == Command::REFAB) + return tRFCab; + else if (command == Command::REFPB || command == Command::REFP2B) + return tRFCpb; + else + { + SC_REPORT_FATAL("getExecutionTime", + "command not known or command doesn't have a fixed execution time"); + return SC_ZERO_TIME; + } +} + +TimeInterval MemSpecLPDDR5::getIntervalOnDataStrobe(Command command, const tlm_generic_payload &) const +{ + if (command == Command::RD || command == Command::RDA) + return {tRL, tRL + burstDuration}; + else if (command == Command::WR || command == Command::WRA) + return {tWL, tWL + burstDuration}; + else + { + SC_REPORT_FATAL("MemSpecLPDDR5", "Method was called with invalid argument"); + return {}; + } +} diff --git a/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.h b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.h new file mode 100644 index 00000000..48fc7b2c --- /dev/null +++ b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR5.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef MEMSPECLPDDR5_H +#define MEMSPECLPDDR5_H + +#include +#include "MemSpec.h" +#include "../../common/third_party/nlohmann/single_include/nlohmann/json.hpp" + +class MemSpecLPDDR5 final : public MemSpec +{ +public: + explicit MemSpecLPDDR5(nlohmann::json &memspec); + + // Memspec Variables: + const sc_core::sc_time tREFI; + const sc_core::sc_time tREFIpb; + const sc_core::sc_time tRFCab; + const sc_core::sc_time tRFCpb; + const sc_core::sc_time tRAS; + const sc_core::sc_time tRPab; + const sc_core::sc_time tRPpb; + const sc_core::sc_time tRCpb; + const sc_core::sc_time tRCab; + const sc_core::sc_time tPPD; + const sc_core::sc_time tRCD; + const sc_core::sc_time tFAW; + const sc_core::sc_time tRRD; + //const sc_core::sc_time tCCD; + const sc_core::sc_time tRL; + //const sc_core::sc_time tRPST; + //const sc_core::sc_time tDQSCK; + const sc_core::sc_time tRBTP; + const sc_core::sc_time tWL; + //const sc_core::sc_time tDQSS; + //const sc_core::sc_time tDQS2DQ; + const sc_core::sc_time tWR; + //const sc_core::sc_time tWPRE; + //const sc_core::sc_time tWTR; + //const sc_core::sc_time tXP; + //const sc_core::sc_time tSR; + //const sc_core::sc_time tXSR; + //const sc_core::sc_time tESCKE; + //const sc_core::sc_time tCKE; + //const sc_core::sc_time tCMDCKE; + const sc_core::sc_time tRTRS; + + const sc_core::sc_time BL_n_min_16; + const sc_core::sc_time BL_n_max_16; + const sc_core::sc_time BL_n_L_16; + const sc_core::sc_time BL_n_S_16; + + const sc_core::sc_time BL_n_min_32; + const sc_core::sc_time BL_n_max_32; + const sc_core::sc_time BL_n_L_32; + const sc_core::sc_time BL_n_S_32; + + const sc_core::sc_time tWTR_L; + const sc_core::sc_time tWTR_S; + const sc_core::sc_time tWCK2DQO; + + const sc_core::sc_time tpbR2act; + const sc_core::sc_time tpbR2pbR; + + // Currents and Voltages: + // TODO: to be completed + + sc_core::sc_time getRefreshIntervalAB() const override; + sc_core::sc_time getRefreshIntervalPB() const override; + sc_core::sc_time getRefreshIntervalP2B() const override; + + unsigned getPer2BankOffset() const override; + + sc_core::sc_time getExecutionTime(Command command, const tlm::tlm_generic_payload &payload) const override; + TimeInterval getIntervalOnDataStrobe(Command command, const tlm::tlm_generic_payload &payload) const override; + +private: + unsigned per2BankOffset; +}; + +#endif // MEMSPECLPDDR5_H diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index b15feb12..3953620c 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -42,6 +42,7 @@ #include "checker/CheckerDDR5.h" #include "checker/CheckerWideIO.h" #include "checker/CheckerLPDDR4.h" +#include "checker/CheckerLPDDR5.h" #include "checker/CheckerWideIO2.h" #include "checker/CheckerHBM2.h" #include "checker/CheckerGDDR5.h" @@ -58,6 +59,7 @@ #include "refresh/RefreshManagerDummy.h" #include "refresh/RefreshManagerAllBank.h" #include "refresh/RefreshManagerPerBank.h" +#include "refresh/RefreshManagerPer2Bank.h" #include "refresh/RefreshManagerSameBank.h" #include "powerdown/PowerDownManagerStaggered.h" #include "powerdown/PowerDownManagerDummy.h" @@ -94,6 +96,8 @@ Controller::Controller(const sc_module_name &name) : checker = new CheckerWideIO(); else if (memSpec->memoryType == MemSpec::MemoryType::LPDDR4) checker = new CheckerLPDDR4(); + else if (memSpec->memoryType == MemSpec::MemoryType::LPDDR5) + checker = new CheckerLPDDR5(); else if (memSpec->memoryType == MemSpec::MemoryType::WideIO2) checker = new CheckerWideIO2(); else if (memSpec->memoryType == MemSpec::MemoryType::HBM2) @@ -216,6 +220,16 @@ Controller::Controller(const sc_module_name &name) : refreshManagers.push_back(manager); } } + else if (config.refreshPolicy == Configuration::RefreshPolicy::Per2Bank) + { + for (unsigned rankID = 0; rankID < memSpec->numberOfRanks; rankID++) + { + // TODO: remove bankMachines in constructor + RefreshManagerIF *manager = new RefreshManagerPer2Bank + (bankMachinesOnRank[rankID], powerDownManagers[rankID], Rank(rankID), checker); + refreshManagers.push_back(manager); + } + } else SC_REPORT_FATAL("Controller", "Selected refresh mode not supported!"); @@ -303,6 +317,11 @@ void Controller::controllerMethod() bankID < memSpec->banksPerRank; bankID += memSpec->banksPerGroup) bankMachinesOnRank[rank.ID()][bankID]->updateState(command); } + else if (command.is2BankCommand()) + { + bankMachines[bank.ID()]->updateState(command); + bankMachines[bank.ID() + memSpec->getPer2BankOffset()]->updateState(command); + } else // if (isBankCommand(command)) bankMachines[bank.ID()]->updateState(command); diff --git a/DRAMSys/library/src/controller/checker/CheckerLPDDR5.cpp b/DRAMSys/library/src/controller/checker/CheckerLPDDR5.cpp new file mode 100644 index 00000000..a62313c6 --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerLPDDR5.cpp @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Lukas Steiner + */ + +#include + +#include "CheckerLPDDR5.h" + +using namespace sc_core; +using namespace tlm; + +CheckerLPDDR5::CheckerLPDDR5() +{ + Configuration &config = Configuration::getInstance(); + memSpec = dynamic_cast(config.memSpec); + if (memSpec == nullptr) + SC_REPORT_FATAL("CheckerLPDDR5", "Wrong MemSpec chosen"); + else + { + lastScheduledByCommandAndRank = std::vector> + (Command::numberOfCommands(), std::vector(memSpec->numberOfRanks, sc_max_time())); + lastScheduledByCommandAndBankGroup = std::vector> + (Command::numberOfCommands(), std::vector(memSpec->numberOfBankGroups, sc_max_time())); + lastScheduledByCommandAndBank = std::vector> + (Command::numberOfCommands(), std::vector(memSpec->numberOfBanks, sc_max_time())); + lastScheduledByCommand = std::vector(Command::numberOfCommands(), sc_max_time()); + lastCommandOnBus = sc_max_time(); + + last4Activates = std::vector>(memSpec->numberOfRanks); + + lastBurstLengthByCommandAndRank = std::vector> + (Command::WRA + 1, std::vector(memSpec->numberOfRanks)); + lastBurstLengthByCommandAndBankGroup = std::vector> + (Command::WRA + 1, std::vector(memSpec->numberOfBankGroups)); + lastBurstLengthByCommandAndBank = std::vector> + (Command::WRA + 1, std::vector(memSpec->numberOfBanks)); + lastBurstLengthByCommand = std::vector(Command::WRA + 1); + + tBURST16 = 16 / memSpec->dataRate * memSpec->tCK; + tBURST32 = 32 / memSpec->dataRate * memSpec->tCK; + } +} + +sc_time CheckerLPDDR5::timeToSatisfyConstraints(Command command, tlm_generic_payload *payload) const +{ + Rank rank = DramExtension::getRank(payload); + BankGroup bankGroup = DramExtension::getBankGroup(payload); + Bank bank = DramExtension::getBank(payload); + unsigned burstLength = DramExtension::getBurstLength(payload); + assert(!(memSpec->bitWidth == 8) || (burstLength == 32)); // x8 device -> BL32 + assert(!(memSpec->groupsPerRank > 1) || (burstLength == 16)); // BG mode -> BL16 + + sc_time lastCommandStart; + sc_time earliestTimeToStart = sc_time_stamp(); + + if (command == Command::RD || command == Command::RDA) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::RD][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::RD][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_16); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::RD][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RD][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_16); + } + + lastCommandStart = lastScheduledByCommand[Command::RD] != lastScheduledByCommandAndRank[Command::RD][rank.ID()] ? + lastScheduledByCommand[Command::RD] : sc_max_time(); + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommand[Command::RD] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST32 + memSpec->tRTRS); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST16 + memSpec->tRTRS); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::RDA][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::RDA][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_16); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::RDA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RDA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_16); + } + + lastCommandStart = lastScheduledByCommand[Command::RDA] != lastScheduledByCommandAndRank[Command::RDA][rank.ID()] ? + lastScheduledByCommand[Command::RDA] : sc_max_time(); + if (lastCommandStart != sc_max_time()) + { + // TODO: BG mode with BL32 + if (lastBurstLengthByCommand[Command::RDA] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST32 + memSpec->tRTRS); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST16 + memSpec->tRTRS); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::WR][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::WR][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_max_32 + memSpec->tWTR_L); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_max_16 + memSpec->tWTR_L); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WR][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WR][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tWTR_S); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tWTR_S); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::WRA][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::WRA][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_max_32 + memSpec->tWTR_L); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_max_16 + memSpec->tWTR_L); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WRA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WRA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tWTR_S); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tWTR_S); + } + } + else if (command == Command::WR || command == Command::WRA) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::RD][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::RD][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_max_32 + memSpec->tWCK2DQO - memSpec->tWL); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_max_16 + memSpec->tWCK2DQO - memSpec->tWL); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::RD][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RD][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_min_32 + memSpec->tWCK2DQO - memSpec->tWL); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_min_16 + memSpec->tWCK2DQO - memSpec->tWL); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::RDA][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::RDA][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_max_32 + memSpec->tWCK2DQO - memSpec->tWL); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_max_16 + memSpec->tWCK2DQO - memSpec->tWL); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::RDA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RDA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_min_32 + memSpec->tWCK2DQO - memSpec->tWL); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + + memSpec->BL_n_min_16 + memSpec->tWCK2DQO - memSpec->tWL); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::WR][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::WR][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_16); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WR][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WR][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_16); + } + + lastCommandStart = lastScheduledByCommand[Command::WR] != lastScheduledByCommandAndRank[Command::WR][rank.ID()] ? + lastScheduledByCommand[Command::WR] : sc_max_time(); + if (lastCommandStart != sc_max_time()) + { + // TODO: BG mode with BL32 + if (lastBurstLengthByCommand[Command::WR] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST32 + memSpec->tRTRS); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST16 + memSpec->tRTRS); + } + + lastCommandStart = lastScheduledByCommandAndBankGroup[Command::WRA][bankGroup.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBankGroup[Command::WRA][bankGroup.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_L_16); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WRA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WRA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_32); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_S_16); + } + + lastCommandStart = lastScheduledByCommand[Command::WRA] != lastScheduledByCommandAndRank[Command::WRA][rank.ID()] ? + lastScheduledByCommand[Command::WRA] : sc_max_time(); + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommand[Command::WRA] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST32 + memSpec->tRTRS); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + tBURST16 + memSpec->tRTRS); + } + } + else if (command == Command::ACT) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRRD); + + lastCommandStart = lastScheduledByCommandAndBank[Command::RDA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RDA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP + memSpec->tRPpb - memSpec->tCK); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP + memSpec->tRPpb - memSpec->tCK); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::WRA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RDA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb - memSpec->tCK); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb - memSpec->tCK); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::PREPB][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPab - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCab - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFPB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tpbR2act - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFP2B][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tpbR2act - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::REFPB][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCpb - memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::REFP2B][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCpb - memSpec->tCK); + + if (last4Activates[rank.ID()].size() >= 4) + earliestTimeToStart = std::max(earliestTimeToStart, last4Activates[rank.ID()].front() + memSpec->tFAW - memSpec->tCK); + } + else if (command == Command::PREPB) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRAS + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::RD][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RD][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::WR][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::WR][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREPB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tPPD); + } + else if (command == Command::PREAB) + { + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRAS + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::RD][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RD][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::RDA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RDA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WR][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WR][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WRA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WRA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREPB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tPPD); + } + else if (command == Command::REFAB) + { + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCpb + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::RDA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::RDA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::WRA][rank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndRank[Command::WRA][rank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREPB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPab); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCab); + } + else if (command == Command::REFPB) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCpb + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRRD + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::RDA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RDA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::WRA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::WRA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::PREPB][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPab); + + lastCommandStart = lastScheduledByCommandAndBank[Command::REFPB][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFPB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tpbR2pbR); + + if (last4Activates[rank.ID()].size() >= 4) + earliestTimeToStart = std::max(earliestTimeToStart, last4Activates[rank.ID()].front() + memSpec->tFAW); + } + else if (command == Command::REFP2B) + { + Bank secondBank = Bank(bank.ID() + memSpec->getPer2BankOffset()); + + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCpb + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][secondBank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCpb + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRRD + memSpec->tCK); + + lastCommandStart = lastScheduledByCommandAndBank[Command::RDA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RDA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::RDA][secondBank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::RDA][secondBank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_32 + + memSpec->tRBTP + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->BL_n_min_16 + + memSpec->tRBTP + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::WRA][bank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::WRA][bank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::WRA][secondBank.ID()]; + if (lastCommandStart != sc_max_time()) + { + if (lastBurstLengthByCommandAndBank[Command::WRA][secondBank.ID()] == 32) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_32 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + else + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + + memSpec->BL_n_min_16 + memSpec->tCK + memSpec->tWR + memSpec->tRPpb); + } + + lastCommandStart = lastScheduledByCommandAndBank[Command::PREPB][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndBank[Command::PREPB][secondBank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::PREAB][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPab); + + lastCommandStart = lastScheduledByCommandAndBank[Command::REFP2B][bank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFP2B][rank.ID()]; + if (lastCommandStart != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tpbR2pbR); + + if (last4Activates[rank.ID()].size() >= 4) + earliestTimeToStart = std::max(earliestTimeToStart, last4Activates[rank.ID()].front() + memSpec->tFAW); + } + else + SC_REPORT_FATAL("CheckerLPDDR5", "Unknown command!"); + + // Check if command bus is free + if (lastCommandOnBus != sc_max_time()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandOnBus + memSpec->tCK); + + return earliestTimeToStart; +} + +void CheckerLPDDR5::insert(Command command, tlm_generic_payload *payload) +{ + Rank rank = DramExtension::getRank(payload); + BankGroup bankGroup = DramExtension::getBankGroup(payload); + Bank bank = DramExtension::getBank(payload); + unsigned burstLength = DramExtension::getBurstLength(payload); + + PRINTDEBUGMESSAGE("CheckerLPDDR5", "Changing state on bank " + std::to_string(bank.ID()) + + " command is " + command.toString()); + + lastScheduledByCommandAndRank[command][rank.ID()] = sc_time_stamp(); + lastScheduledByCommandAndBankGroup[command][bankGroup.ID()] = sc_time_stamp(); + lastScheduledByCommandAndBank[command][bank.ID()] = sc_time_stamp(); + lastScheduledByCommand[command] = sc_time_stamp(); + + if (command.isCasCommand()) + { + lastBurstLengthByCommandAndRank[command][rank.ID()] = burstLength; + lastBurstLengthByCommandAndBankGroup[command][bankGroup.ID()] = burstLength; + lastBurstLengthByCommandAndBank[command][bank.ID()] = burstLength; + lastBurstLengthByCommand[command] = burstLength; + } + + if (command == Command::REFP2B) + lastScheduledByCommandAndBank[command][bank.ID() + memSpec->getPer2BankOffset()] = sc_time_stamp(); + + lastCommandOnBus = sc_time_stamp() + memSpec->getCommandLength(command) - memSpec->tCK; + + if (command == Command::ACT || command == Command::REFPB || command == Command::REFP2B + || command == Command::RFMPB || command == Command::RFMP2B) + { + if (last4Activates[rank.ID()].size() == 4) + last4Activates[rank.ID()].pop(); + last4Activates[rank.ID()].push(lastCommandOnBus); + } +} diff --git a/DRAMSys/library/src/controller/checker/CheckerLPDDR5.h b/DRAMSys/library/src/controller/checker/CheckerLPDDR5.h new file mode 100644 index 00000000..56645016 --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerLPDDR5.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Lukas Steiner + */ + +#ifndef CHECKERLPDDR5_H +#define CHECKERLPDDR5_H + +#include +#include + +#include "CheckerIF.h" +#include "../../configuration/memspec/MemSpecLPDDR5.h" +#include "../../configuration/Configuration.h" +#include "../../common/utils.h" + +class CheckerLPDDR5 final : public CheckerIF +{ +public: + CheckerLPDDR5(); + sc_core::sc_time timeToSatisfyConstraints(Command command, tlm::tlm_generic_payload *payload) const override; + void insert(Command command, tlm::tlm_generic_payload *payload) override; + +private: + const MemSpecLPDDR5 *memSpec; + + std::vector> lastScheduledByCommandAndRank; + std::vector> lastScheduledByCommandAndBankGroup; + std::vector> lastScheduledByCommandAndBank; + std::vector lastScheduledByCommand; + sc_core::sc_time lastCommandOnBus; + std::vector> last4Activates; + + std::vector> lastBurstLengthByCommandAndRank; + std::vector> lastBurstLengthByCommandAndBankGroup; + std::vector> lastBurstLengthByCommandAndBank; + std::vector lastBurstLengthByCommand; + + sc_core::sc_time tBURST16; + sc_core::sc_time tBURST32; + sc_core::sc_time tRDWR; + sc_core::sc_time tRDWR_R; + sc_core::sc_time tWRRD_S; + sc_core::sc_time tWRRD_L; + sc_core::sc_time tWRRD_R; + sc_core::sc_time tRDAACT; + sc_core::sc_time tWRPRE; + sc_core::sc_time tWRAACT; + sc_core::sc_time tRDPDEN; + sc_core::sc_time tWRPDEN; + sc_core::sc_time tWRAPDEN; +}; + +#endif // CHECKERLPDDR5_H diff --git a/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.cpp b/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.cpp new file mode 100644 index 00000000..941cf965 --- /dev/null +++ b/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.cpp @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Lukas Steiner + */ + +#include "RefreshManagerPer2Bank.h" +#include "../../configuration/Configuration.h" +#include "../../common/utils.h" +#include "../../common/dramExtensions.h" + +using namespace sc_core; +using namespace tlm; + +RefreshManagerPer2Bank::RefreshManagerPer2Bank(std::vector &bankMachinesOnRank, + PowerDownManagerIF *powerDownManager, Rank rank, CheckerIF *checker) + : powerDownManager(powerDownManager), checker(checker) +{ + Configuration &config = Configuration::getInstance(); + memSpec = config.memSpec; + timeForNextTrigger = getTimeForFirstTrigger(memSpec->getRefreshIntervalP2B(), + rank, memSpec->numberOfRanks); + + // each bank pair has one payload (e.g. 0-8, 1-9, 2-10, 3-11, ...) + for (unsigned outerID = 0; outerID < memSpec->banksPerRank; outerID += (memSpec->getPer2BankOffset() * 2)) + { + for (unsigned bankID = outerID; bankID < (outerID + memSpec->getPer2BankOffset()); bankID++) + { + unsigned bankID2 = bankID + memSpec->getPer2BankOffset(); + setUpDummy(refreshPayloads[bankMachinesOnRank[bankID]], 0, rank, + bankMachinesOnRank[bankID]->getBankGroup(), bankMachinesOnRank[bankID]->getBank()); + setUpDummy(refreshPayloads[bankMachinesOnRank[bankID2]], 0, rank, + bankMachinesOnRank[bankID2]->getBankGroup(), bankMachinesOnRank[bankID2]->getBank()); + allBankMachines.push_back({bankMachinesOnRank[bankID], bankMachinesOnRank[bankID2]}); + } + } + + remainingBankMachines = allBankMachines; + currentIterator = remainingBankMachines.begin(); + currentRefreshPayload = &refreshPayloads[currentIterator->front()]; + + maxPostponed = static_cast(config.refreshMaxPostponed * memSpec->banksPerRank / 2); + maxPulledin = -static_cast(config.refreshMaxPulledin * memSpec->banksPerRank / 2); +} + +CommandTuple::Type RefreshManagerPer2Bank::getNextCommand() +{ + return {nextCommand, currentRefreshPayload, std::max(timeToSchedule, sc_time_stamp())}; +} + +sc_time RefreshManagerPer2Bank::start() +{ + timeToSchedule = sc_max_time(); + nextCommand = Command::NOP; + + if (sc_time_stamp() >= timeForNextTrigger) + { + powerDownManager->triggerInterruption(); + if (sleeping) + return timeToSchedule; + + if (sc_time_stamp() >= timeForNextTrigger + memSpec->getRefreshIntervalP2B()) + { + timeForNextTrigger += memSpec->getRefreshIntervalP2B(); + state = State::Regular; + } + + if (state == State::Regular) + { + bool forcedRefresh = (flexibilityCounter == maxPostponed); + bool allBankPairsBusy = true; + + if (!skipSelection) + { + currentIterator = remainingBankMachines.begin(); + for (auto bankIt = remainingBankMachines.begin(); bankIt != remainingBankMachines.end(); bankIt++) + { + bool pairIsBusy = false; + for (auto pairIt : *bankIt) + { + if (!pairIt->isIdle()) + { + pairIsBusy = true; + break; + } + } + if (!pairIsBusy) + { + allBankPairsBusy = false; + currentIterator = bankIt; + break; + } + } + } + + if (allBankPairsBusy && !forcedRefresh) + { + flexibilityCounter++; + timeForNextTrigger += memSpec->getRefreshIntervalP2B(); + return timeForNextTrigger; + } + else + { + nextCommand = Command::REFP2B; + currentRefreshPayload = &refreshPayloads[currentIterator->front()]; + for (auto it : *currentIterator) + { + if (it->isActivated()) + { + nextCommand = Command::PREPB; + currentRefreshPayload = &refreshPayloads[it]; + break; + } + } + + // TODO: banks should already be blocked for precharge and selection should be skipped + if (nextCommand == Command::REFP2B && forcedRefresh) + { + for (auto it : *currentIterator) + it->block(); + skipSelection = true; + } + + timeToSchedule = checker->timeToSatisfyConstraints(nextCommand, currentRefreshPayload); + return timeToSchedule; + } + } + else // if (state == RmState::Pulledin) + { + bool allBankPairsBusy = true; + + currentIterator = remainingBankMachines.begin(); + for (auto bankIt = remainingBankMachines.begin(); bankIt != remainingBankMachines.end(); bankIt++) + { + bool pairIsBusy = false; + for (auto pairIt : *bankIt) + { + if (!pairIt->isIdle()) + { + pairIsBusy = true; + break; + } + } + if (!pairIsBusy) + { + allBankPairsBusy = false; + currentIterator = bankIt; + break; + } + } + + if (allBankPairsBusy) + { + state = State::Regular; + timeForNextTrigger += memSpec->getRefreshIntervalP2B(); + return timeForNextTrigger; + } + else + { + nextCommand = Command::REFP2B; + currentRefreshPayload = &refreshPayloads[currentIterator->front()]; + for (auto it : *currentIterator) + { + if (it->isActivated()) + { + nextCommand = Command::PREPB; + currentRefreshPayload = &refreshPayloads[it]; + break; + } + } + + timeToSchedule = checker->timeToSatisfyConstraints(nextCommand, currentRefreshPayload); + return timeToSchedule; + } + } + } + else + return timeForNextTrigger; +} + +void RefreshManagerPer2Bank::updateState(Command command) +{ + switch (command) + { + case Command::REFP2B: + skipSelection = false; + remainingBankMachines.erase(currentIterator); + if (remainingBankMachines.empty()) + remainingBankMachines = allBankMachines; + currentIterator = remainingBankMachines.begin(); + + if (state == State::Pulledin) + flexibilityCounter--; + else + state = State::Pulledin; + + if (flexibilityCounter == maxPulledin) + { + state = State::Regular; + timeForNextTrigger += memSpec->getRefreshIntervalP2B(); + } + break; + case Command::REFAB: + // Refresh command after SREFEX + state = State::Regular; // TODO: check if this assignment is necessary + timeForNextTrigger = sc_time_stamp() + memSpec->getRefreshIntervalP2B(); + sleeping = false; + remainingBankMachines = allBankMachines; + currentIterator = remainingBankMachines.begin(); + skipSelection = false; + break; + case Command::PDEA: case Command::PDEP: + sleeping = true; + break; + case Command::SREFEN: + sleeping = true; + timeForNextTrigger = sc_max_time(); + break; + case Command::PDXA: case Command::PDXP: + sleeping = false; + break; + default: + break; + } +} diff --git a/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.h b/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.h new file mode 100644 index 00000000..0b6c393c --- /dev/null +++ b/DRAMSys/library/src/controller/refresh/RefreshManagerPer2Bank.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Author: Lukas Steiner + */ + +#ifndef REFRESHMANAGERPER2BANK_H +#define REFRESHMANAGERPER2BANK_H + +#include +#include +#include + +#include +#include +#include "RefreshManagerIF.h" +#include "../../configuration/memspec/MemSpec.h" +#include "../BankMachine.h" +#include "../powerdown/PowerDownManagerIF.h" + +class RefreshManagerPer2Bank final : public RefreshManagerIF +{ +public: + RefreshManagerPer2Bank(std::vector &, PowerDownManagerIF *, Rank, CheckerIF *); + + CommandTuple::Type getNextCommand() override; + sc_core::sc_time start() override; + void updateState(Command) override; + +private: + enum class State {Regular, Pulledin} state = State::Regular; + const MemSpec *memSpec; + PowerDownManagerIF *powerDownManager; + std::unordered_map refreshPayloads; + tlm::tlm_generic_payload *currentRefreshPayload; + sc_core::sc_time timeForNextTrigger = sc_core::sc_max_time(); + sc_core::sc_time timeToSchedule = sc_core::sc_max_time(); + CheckerIF *checker; + Command nextCommand = Command::NOP; + + std::list> remainingBankMachines; + std::list> allBankMachines; + std::list>::iterator currentIterator; + + int flexibilityCounter = 0; + int maxPostponed = 0; + int maxPulledin = 0; + + bool sleeping = false; + bool skipSelection = false; +}; + +#endif // REFRESHMANAGERPER2BANK_H diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 06f6415d..796a46d1 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -53,6 +53,7 @@ #include "dram/DramDDR5.h" #include "dram/DramWideIO.h" #include "dram/DramLPDDR4.h" +#include "dram/DramLPDDR5.h" #include "dram/DramWideIO2.h" #include "dram/DramHBM2.h" #include "dram/DramGDDR5.h" @@ -220,6 +221,8 @@ void DRAMSys::instantiateModules(const std::string &pathToResources, dram = new DramWideIO(str.c_str()); else if (memoryType == MemSpec::MemoryType::LPDDR4) dram = new DramLPDDR4(str.c_str()); + else if (memoryType == MemSpec::MemoryType::LPDDR5) + dram = new DramLPDDR5(str.c_str()); else if (memoryType == MemSpec::MemoryType::WideIO2) dram = new DramWideIO2(str.c_str()); else if (memoryType == MemSpec::MemoryType::HBM2) diff --git a/DRAMSys/library/src/simulation/DRAMSysRecordable.cpp b/DRAMSys/library/src/simulation/DRAMSysRecordable.cpp index b8f9a8c8..62fbc6b1 100644 --- a/DRAMSys/library/src/simulation/DRAMSysRecordable.cpp +++ b/DRAMSys/library/src/simulation/DRAMSysRecordable.cpp @@ -41,6 +41,7 @@ #include "dram/DramDDR5.h" #include "dram/DramWideIO.h" #include "dram/DramLPDDR4.h" +#include "dram/DramLPDDR5.h" #include "dram/DramWideIO2.h" #include "dram/DramHBM2.h" #include "dram/DramGDDR5.h" @@ -166,6 +167,8 @@ void DRAMSysRecordable::instantiateModules(const std::string &traceName, dram = new DramRecordable(str.c_str(), tlmRecorders[i]); else if (memoryType == MemSpec::MemoryType::LPDDR4) dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else if (memoryType == MemSpec::MemoryType::LPDDR5) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); else if (memoryType == MemSpec::MemoryType::WideIO2) dram = new DramRecordable(str.c_str(), tlmRecorders[i]); else if (memoryType == MemSpec::MemoryType::HBM2) diff --git a/DRAMSys/library/src/simulation/dram/DramLPDDR5.cpp b/DRAMSys/library/src/simulation/dram/DramLPDDR5.cpp new file mode 100644 index 00000000..9233d7da --- /dev/null +++ b/DRAMSys/library/src/simulation/dram/DramLPDDR5.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#include "DramLPDDR5.h" + +#include "Dram.h" +#include "../../configuration/Configuration.h" +#include "../../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h" +#include "../../configuration/memspec/MemSpecLPDDR5.h" + +DramLPDDR5::DramLPDDR5(const sc_module_name &name) : Dram(name) +{ + if (storeMode == Configuration::StoreMode::ErrorModel) + SC_REPORT_FATAL("DramLPDDR5", "Error Model not supported for LPDDR5"); + + if (Configuration::getInstance().powerAnalysis) + SC_REPORT_FATAL("DramLPDDR5", "DRAMPower does not support LPDDR5"); +} diff --git a/DRAMSys/library/src/simulation/dram/DramLPDDR5.h b/DRAMSys/library/src/simulation/dram/DramLPDDR5.h new file mode 100644 index 00000000..2c8a707b --- /dev/null +++ b/DRAMSys/library/src/simulation/dram/DramLPDDR5.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, Technische Universität Kaiserslautern + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: + * Lukas Steiner + */ + +#ifndef DRAMLPDDR5_H +#define DRAMLPDDR5_H + +#include +#include "Dram.h" + +class DramLPDDR5 : public Dram +{ +public: + explicit DramLPDDR5(const sc_module_name &name); + SC_HAS_PROCESS(DramLPDDR5); +}; + +#endif // DRAMLPDDR5_H diff --git a/DRAMSys/library/src/simulation/dram/DramRecordable.cpp b/DRAMSys/library/src/simulation/dram/DramRecordable.cpp index 283346aa..827dcb88 100644 --- a/DRAMSys/library/src/simulation/dram/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/dram/DramRecordable.cpp @@ -43,6 +43,7 @@ #include "DramDDR5.h" #include "DramWideIO.h" #include "DramLPDDR4.h" +#include "DramLPDDR5.h" #include "DramWideIO2.h" #include "DramHBM2.h" #include "DramGDDR5.h" @@ -152,6 +153,7 @@ template class DramRecordable; template class DramRecordable; template class DramRecordable; template class DramRecordable; +template class DramRecordable; template class DramRecordable; template class DramRecordable; template class DramRecordable;