diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index 095f0c77..88b450ef 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -139,7 +139,8 @@ SOURCES += \ src/configuration/memspec/MemSpecWideIO.cpp \ src/configuration/memspec/MemSpecLPDDR4.cpp \ src/controller/checker/CheckerDDR4.cpp \ - src/simulation/DramLPDDR4.cpp + src/simulation/DramLPDDR4.cpp \ + src/controller/checker/CheckerLPDDR4.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -212,7 +213,8 @@ HEADERS += \ src/configuration/memspec/MemSpecDDR4.h \ src/configuration/memspec/MemSpecLPDDR4.h \ src/controller/checker/CheckerDDR4.h \ - src/simulation/DramLPDDR4.h + src/simulation/DramLPDDR4.h \ + src/controller/checker/CheckerLPDDR4.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/resources/configs/simulator/lpddr4.xml b/DRAMSys/library/resources/configs/simulator/lpddr4.xml new file mode 100644 index 00000000..87b02763 --- /dev/null +++ b/DRAMSys/library/resources/configs/simulator/lpddr4.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/DRAMSys/library/resources/simulations/lpddr4-example.xml b/DRAMSys/library/resources/simulations/lpddr4-example.xml new file mode 100644 index 00000000..6f227578 --- /dev/null +++ b/DRAMSys/library/resources/simulations/lpddr4-example.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + ddr3_example.stl + + diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index 97c6709b..8944286e 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -358,21 +358,21 @@ void TlmRecorder::insertCommandLengths() { MemSpec *memSpec = Configuration::getInstance().memSpec; - sqlite3_bind_int(insertCommandLengthsStatement, 1, memSpec->clACT); - sqlite3_bind_int(insertCommandLengthsStatement, 2, memSpec->clPRE); - sqlite3_bind_int(insertCommandLengthsStatement, 3, memSpec->clPREA); - sqlite3_bind_int(insertCommandLengthsStatement, 4, memSpec->clRD); - sqlite3_bind_int(insertCommandLengthsStatement, 5, memSpec->clRDA); - sqlite3_bind_int(insertCommandLengthsStatement, 6, memSpec->clWR); - sqlite3_bind_int(insertCommandLengthsStatement, 7, memSpec->clWRA); - sqlite3_bind_int(insertCommandLengthsStatement, 8, memSpec->clREFA); - sqlite3_bind_int(insertCommandLengthsStatement, 9, memSpec->clREFB); - sqlite3_bind_int(insertCommandLengthsStatement, 10, memSpec->clPDEA); - sqlite3_bind_int(insertCommandLengthsStatement, 11, memSpec->clPDXA); - sqlite3_bind_int(insertCommandLengthsStatement, 12, memSpec->clPDEP); - sqlite3_bind_int(insertCommandLengthsStatement, 13, memSpec->clPDXP); - sqlite3_bind_int(insertCommandLengthsStatement, 14, memSpec->clSREFEN); - sqlite3_bind_int(insertCommandLengthsStatement, 15, memSpec->clSREFEX); + sqlite3_bind_int(insertCommandLengthsStatement, 1, memSpec->commandLength[Command::ACT]); + sqlite3_bind_int(insertCommandLengthsStatement, 2, memSpec->commandLength[Command::PRE]); + sqlite3_bind_int(insertCommandLengthsStatement, 3, memSpec->commandLength[Command::PREA]); + sqlite3_bind_int(insertCommandLengthsStatement, 4, memSpec->commandLength[Command::RD]); + sqlite3_bind_int(insertCommandLengthsStatement, 5, memSpec->commandLength[Command::RDA]); + sqlite3_bind_int(insertCommandLengthsStatement, 6, memSpec->commandLength[Command::WR]); + sqlite3_bind_int(insertCommandLengthsStatement, 7, memSpec->commandLength[Command::WRA]); + sqlite3_bind_int(insertCommandLengthsStatement, 8, memSpec->commandLength[Command::REFA]); + sqlite3_bind_int(insertCommandLengthsStatement, 9, memSpec->commandLength[Command::REFB]); + sqlite3_bind_int(insertCommandLengthsStatement, 10, memSpec->commandLength[Command::PDEA]); + sqlite3_bind_int(insertCommandLengthsStatement, 11, memSpec->commandLength[Command::PDXA]); + sqlite3_bind_int(insertCommandLengthsStatement, 12, memSpec->commandLength[Command::PDEP]); + sqlite3_bind_int(insertCommandLengthsStatement, 13, memSpec->commandLength[Command::PDXP]); + sqlite3_bind_int(insertCommandLengthsStatement, 14, memSpec->commandLength[Command::SREFEN]); + sqlite3_bind_int(insertCommandLengthsStatement, 15, memSpec->commandLength[Command::SREFEX]); executeSqlStatement(insertCommandLengthsStatement); } diff --git a/DRAMSys/library/src/configuration/memspec/MemSpec.cpp b/DRAMSys/library/src/configuration/memspec/MemSpec.cpp index 1dd1c790..d7e77ab3 100644 --- a/DRAMSys/library/src/configuration/memspec/MemSpec.cpp +++ b/DRAMSys/library/src/configuration/memspec/MemSpec.cpp @@ -42,6 +42,11 @@ using namespace tlm; +MemSpec::MemSpec() +{ + commandLength = std::vector(numberOfCommands(), 1); +} + const std::vector &MemSpec::getBanks() const { static std::vector banks; @@ -62,6 +67,11 @@ sc_time MemSpec::getWriteAccessTime() const return clk * (BurstLength / DataRate); } +unsigned MemSpec::getCommandLength(Command command) const +{ + return commandLength[command]; +} + //sc_time MemSpec::getMinExecutionTimeForPowerDownCmd(Command command) const //{ // if (command == Command::PDEA || command == Command::PDEP) diff --git a/DRAMSys/library/src/configuration/memspec/MemSpec.h b/DRAMSys/library/src/configuration/memspec/MemSpec.h index 687eedb9..84ae02ba 100644 --- a/DRAMSys/library/src/configuration/memspec/MemSpec.h +++ b/DRAMSys/library/src/configuration/memspec/MemSpec.h @@ -39,7 +39,7 @@ #define MEMSPEC_H #include -#include +#include #include "../../common/dramExtensions.h" #include "../../controller/Command.h" #include "../../common/utils.h" @@ -48,6 +48,9 @@ using namespace tlm; struct MemSpec { + MemSpec(); + virtual ~MemSpec() {} + const std::vector &getBanks() const; sc_time getWriteAccessTime() const; @@ -59,6 +62,8 @@ struct MemSpec virtual sc_time getExecutionTime(Command) const = 0; virtual TimeInterval getIntervalOnDataStrobe(Command) const = 0; + unsigned getCommandLength(Command) const; + // Returns the minimum execution time for commands that have a variable execution time //virtual sc_time getMinExecutionTimeForPowerDownCmd(Command command) const = 0; @@ -88,24 +93,8 @@ struct MemSpec double iDD6; double vDD; - // Command lengths on bus, standardly one clock cycle: - unsigned clACT = 1; - unsigned clPRE = 1; - unsigned clPREA = 1; - unsigned clRD = 1; - unsigned clRDA = 1; - unsigned clWR = 1; - unsigned clWRA = 1; - unsigned clREFA = 1; - unsigned clREFB = 1; - unsigned clPDEA = 1; - unsigned clPDXA = 1; - unsigned clPDEP = 1; - unsigned clPDXP = 1; - unsigned clSREFEN = 1; - unsigned clSREFEX = 1; - - virtual ~MemSpec() {} + // Command lengths on bus, standardly one clock cycle + std::vector commandLength; }; #endif // MEMSPEC_H diff --git a/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR4.cpp b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR4.cpp index 12566856..11c3c29d 100644 --- a/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR4.cpp +++ b/DRAMSys/library/src/configuration/memspec/MemSpecLPDDR4.cpp @@ -37,17 +37,17 @@ MemSpecLPDDR4::MemSpecLPDDR4() { - clACT = 4; - clPRE = 2; - clPREA = 2; - clRD = 4; - clRDA = 4; - clWR = 4; - clWRA = 4; - clREFA = 2; - clREFB = 2; - clSREFEN = 2; - clSREFEX = 2; + commandLength[Command::ACT] = 4; + commandLength[Command::PRE] = 2; + commandLength[Command::PREA] = 2; + commandLength[Command::RD] = 4; + commandLength[Command::RDA] = 4; + commandLength[Command::WR] = 4; + commandLength[Command::WRA] = 4; + commandLength[Command::REFA] = 2; + commandLength[Command::REFB] = 2; + commandLength[Command::SREFEN] = 2; + commandLength[Command::SREFEX] = 2; } sc_time MemSpecLPDDR4::getRefreshIntervalAB() const @@ -68,14 +68,14 @@ sc_time MemSpecLPDDR4::getExecutionTime(Command command) const return tRPab + clk; else if (command == Command::ACT) return tRCD + 3 * clk; - else if (command == Command::RD) + else if (command == Command::RD || command == Command::RDA) return tRL + tDQSCK + getReadAccessTime() + 3 * clk; - else if (command == Command::RDA) - return getReadAccessTime() - 5 * clk + tRTP + tRPpb; - else if (command == Command::WR) +// else if (command == Command::RDA) +// return getReadAccessTime() - 5 * clk + tRTP + tRPpb; + else if (command == Command::WR || command == Command::WRA) return tWL + tDQSS + tDQS2DQ + getWriteAccessTime() + 3 * clk; - else if (command == Command::WRA) - return tWL + getWriteAccessTime() + 4 * clk + tWR + tRPpb; +// else if (command == Command::WRA) +// return tWL + getWriteAccessTime() + 4 * clk + tWR + tRPpb; else if (command == Command::REFA) return tRFCab + clk; else if (command == Command::REFB) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index cc50efd3..612acac8 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -44,6 +44,7 @@ #include "checker/CheckerDDR3.h" #include "checker/CheckerDDR4.h" #include "checker/CheckerWideIO.h" +#include "checker/CheckerLPDDR4.h" #include "refresh/RefreshManager.h" #include "refresh/RefreshManagerDummy.h" #include "refresh/RefreshManagerBankwise.h" @@ -64,6 +65,8 @@ Controller::Controller(sc_module_name name) : checker = new CheckerDDR4(); else if (config.memSpec->MemoryType == "WIDEIO_SDR") checker = new CheckerWideIO(); + else if (config.memSpec->MemoryType == "LPDDR4") + checker = new CheckerLPDDR4(); else SC_REPORT_FATAL("Controller", "Unsupported DRAM type"); diff --git a/DRAMSys/library/src/controller/checker/CheckerLPDDR4.cpp b/DRAMSys/library/src/controller/checker/CheckerLPDDR4.cpp new file mode 100644 index 00000000..70ceb04d --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerLPDDR4.cpp @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2019, University of 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 "CheckerLPDDR4.h" + +CheckerLPDDR4::CheckerLPDDR4() +{ + Configuration config = Configuration::getInstance(); + memSpec = dynamic_cast(config.memSpec); + if (memSpec == nullptr) + SC_REPORT_FATAL("CheckerLPDDR4", "Wrong MemSpec chosen"); + + if (config.ControllerCoreRefDisable) + refreshChecker = new RefreshCheckerLPDDR4Dummy(memSpec); + else if (config.BankwiseLogic) + refreshChecker = new RefreshCheckerLPDDR4Bankwise(memSpec); + else + refreshChecker = new RefreshCheckerLPDDR4(memSpec); + + lastScheduledByCommandAndBank = std::vector> + (numberOfCommands(), std::vector(memSpec->NumberOfBanks)); + lastScheduledByCommandAndRank = std::vector> + (numberOfCommands(), std::vector(memSpec->NumberOfRanks)); + lastScheduledByCommand = std::vector(numberOfCommands()); + + lastActivates = std::vector>(memSpec->NumberOfRanks); +} + +CheckerLPDDR4::~CheckerLPDDR4() +{ + delete refreshChecker; +} + +sc_time CheckerLPDDR4::delayToSatisfyConstraints(Command command, Rank rank, BankGroup, Bank bank) const +{ + sc_time lastCommandStart; + sc_time earliestTimeToStart = sc_time_stamp(); + + if (command == Command::ACT) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::RDA][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRTP + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndBank[Command::WRA][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + memSpec->tCCD + + memSpec->tWR + memSpec->clk + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndBank[Command::PRE][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRPpb - 2 * memSpec->clk); + + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRAS + memSpec->tRPpb); + + lastCommandStart = lastScheduledByCommandAndRank[Command::ACT][rank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRRD); + + lastCommandStart = lastScheduledByCommandAndRank[Command::REFA][rank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCab - 2 * memSpec->clk); + + lastCommandStart = lastScheduledByCommandAndBank[Command::REFB][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRFCpb - 2 * memSpec->clk); + + if (lastActivates[rank.ID()].size() >= 4) + earliestTimeToStart = std::max(earliestTimeToStart, lastActivates[rank.ID()].front() + memSpec->tFAW); + + refreshChecker->delayToSatisfyACT(bank, earliestTimeToStart); + } + else if (command == Command::RD || command == Command::RDA) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD); + + lastCommandStart = lastScheduledByCommand[Command::RD]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tCCD); + + lastCommandStart = lastScheduledByCommand[Command::RDA]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tCCD); + + lastCommandStart = lastScheduledByCommand[Command::WR]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + memSpec->clk + memSpec->tCCD + memSpec->tWTR); + + lastCommandStart = lastScheduledByCommand[Command::WRA]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + memSpec->clk + memSpec->tCCD + memSpec->tWTR); + + refreshChecker->delayToSatisfyRD(bank, earliestTimeToStart); + } + else if (command == Command::WR || command == Command::WRA) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRCD); + + lastCommandStart = lastScheduledByCommand[Command::RD]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + memSpec->tDQSCK + memSpec->tCCD - memSpec->tWL + memSpec->tWPRE + memSpec->tRPST); + + lastCommandStart = lastScheduledByCommand[Command::RDA]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRL + memSpec->tDQSCK + memSpec->tCCD - memSpec->tWL + memSpec->tWPRE + memSpec->tRPST); + + lastCommandStart = lastScheduledByCommand[Command::WR]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tCCD); + + lastCommandStart = lastScheduledByCommand[Command::WRA]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tCCD); + + refreshChecker->delayToSatisfyWR(bank, earliestTimeToStart); + } + else if (command == Command::PRE) + { + lastCommandStart = lastScheduledByCommandAndBank[Command::ACT][bank.ID()]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tRAS + 2 * memSpec->clk); + + lastCommandStart = lastScheduledByCommandAndBank[Command::RD][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tCCD + memSpec->tRTP - 6 * memSpec->clk); + + lastCommandStart = lastScheduledByCommandAndBank[Command::WR][bank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tWL + memSpec->tCCD + memSpec->tWR + 3 * memSpec->clk); + + lastCommandStart = lastScheduledByCommandAndRank[Command::PRE][rank.ID()]; + if (lastCommandStart != SC_ZERO_TIME) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandStart + memSpec->tPPD); + + refreshChecker->delayToSatisfyPRE(bank, earliestTimeToStart); + } + else + { + reportFatal("CheckerLPDDR4", "Unknown command!"); + } + // Check if command bus is free + earliestTimeToStart = std::max(earliestTimeToStart, lastCommandOnBus + memSpec->clk); + + return (earliestTimeToStart - sc_time_stamp()); +} + +void CheckerLPDDR4::insert(Command command, Rank rank, BankGroup, Bank bank) +{ + PRINTDEBUGMESSAGE("CheckerLPDDR4", "Changing state on bank " + bank.ID() + + " command is " + commandToString(command)); + + lastScheduledByCommandAndBank[command][bank.ID()] = sc_time_stamp(); + lastScheduledByCommandAndRank[command][rank.ID()] = sc_time_stamp(); + lastScheduledByCommand[command] = sc_time_stamp(); + lastCommandOnBus = sc_time_stamp() + (memSpec->getCommandLength(command) - 1) * memSpec->clk; + + if (command == Command::ACT) + { + if (lastActivates[rank.ID()].size() == 4) + lastActivates[rank.ID()].pop(); + lastActivates[rank.ID()].push(sc_time_stamp()); + } + else if (command == Command::REFA || command == Command::REFB) + refreshChecker->insert(bank); +} + +// TODO: max(earliestTimeToStart, ...) needed? +void RefreshCheckerLPDDR4::delayToSatisfyACT(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tRAS)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFCab; +} + +void RefreshCheckerLPDDR4::delayToSatisfyRD(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tRTP)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFCab; +} + +void RefreshCheckerLPDDR4::delayToSatisfyWR(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tWL - memSpec->tCCD - memSpec->tWR)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFCab; +} + +void RefreshCheckerLPDDR4::delayToSatisfyPRE(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= timeForNextPREA) + earliestTimeToStart = timeForNextREFA + memSpec->tRFCab; +} + +void RefreshCheckerLPDDR4::insert(Bank) +{ + timeForNextREFA += memSpec->tREFI; + timeForNextPREA += memSpec->tREFI; +} + +RefreshCheckerLPDDR4Bankwise::RefreshCheckerLPDDR4Bankwise(const MemSpecLPDDR4 *memSpec) + : RefreshCheckerLPDDR4Dummy(memSpec) +{ + sc_time currentREFB = memSpec->tREFI - memSpec->clk * (memSpec->NumberOfBanks - 1); + sc_time currentPRE = currentREFB - std::max(memSpec->clk * memSpec->NumberOfBanks, memSpec->tRPpb); + for (unsigned bankID = 0; bankID < memSpec->NumberOfBanks; bankID++) + { + timesForNextREFB.push_back(currentREFB); + timesForNextPRE.push_back(currentPRE); + currentREFB += memSpec->clk; + currentPRE += memSpec->clk; + } +} + +void RefreshCheckerLPDDR4Bankwise::delayToSatisfyACT(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank.ID()] - memSpec->tRAS)) + earliestTimeToStart = timesForNextREFB[bank.ID()] + memSpec->tRFCpb; +} + +void RefreshCheckerLPDDR4Bankwise::delayToSatisfyRD(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank.ID()] - memSpec->tRTP)) + earliestTimeToStart = timesForNextREFB[bank.ID()] + memSpec->tRFCpb; +} + +void RefreshCheckerLPDDR4Bankwise::delayToSatisfyWR(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank.ID()] - memSpec->tWL - memSpec->tCCD - memSpec->tWR)) + earliestTimeToStart = timesForNextREFB[bank.ID()] + memSpec->tRFCpb; +} + +void RefreshCheckerLPDDR4Bankwise::insert(Bank bank) +{ + timesForNextREFB[bank.ID()] += memSpec->tREFI; + timesForNextPRE[bank.ID()] += memSpec->tREFI; +} diff --git a/DRAMSys/library/src/controller/checker/CheckerLPDDR4.h b/DRAMSys/library/src/controller/checker/CheckerLPDDR4.h new file mode 100644 index 00000000..1d8f6ffd --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerLPDDR4.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2019, University of 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 CHECKERLPDDR4_H +#define CHECKERLPDDR4_H + +#include "CheckerIF.h" +#include +#include +#include "../../configuration/memspec/MemSpecLPDDR4.h" +#include "../../configuration/Configuration.h" + +class RefreshCheckerLPDDR4Dummy; + +class CheckerLPDDR4 final : public CheckerIF +{ +public: + CheckerLPDDR4(); + ~CheckerLPDDR4(); + sc_time delayToSatisfyConstraints(Command, Rank, BankGroup, Bank) const; + void insert(Command, Rank, BankGroup, Bank); + +private: + const MemSpecLPDDR4 *memSpec; + + std::vector> lastScheduledByCommandAndBank; + std::vector> lastScheduledByCommandAndRank; + std::vector lastScheduledByCommand; + sc_time lastCommandOnBus; + + // Four activate window + std::vector> lastActivates; + + RefreshCheckerLPDDR4Dummy *refreshChecker; + + // PowerDown TODO: Implement this method? + //sc_time getTimeConstraintToEnterPowerDown(Command lastCmd, Command pdnCmd) const; +}; + +class RefreshCheckerLPDDR4Dummy +{ +protected: + friend class CheckerLPDDR4; + RefreshCheckerLPDDR4Dummy(const MemSpecLPDDR4 *memSpec) : memSpec(memSpec) {} + virtual ~RefreshCheckerLPDDR4Dummy() {} + + virtual void delayToSatisfyACT(Bank, sc_time &) {} + virtual void delayToSatisfyRD(Bank, sc_time &) {} + virtual void delayToSatisfyWR(Bank, sc_time &) {} + virtual void delayToSatisfyPRE(Bank, sc_time &) {} + virtual void insert(Bank) {} + + const MemSpecLPDDR4 *memSpec; +}; + +class RefreshCheckerLPDDR4 final : public RefreshCheckerLPDDR4Dummy +{ +private: + friend class CheckerLPDDR4; + RefreshCheckerLPDDR4(const MemSpecLPDDR4 *memSpec) + : RefreshCheckerLPDDR4Dummy(memSpec) {} + + void delayToSatisfyACT(Bank, sc_time &); + void delayToSatisfyRD(Bank, sc_time &); + void delayToSatisfyWR(Bank, sc_time &); + void delayToSatisfyPRE(Bank, sc_time &); + void insert(Bank); + + sc_time timeForNextREFA = memSpec->tREFI; + sc_time timeForNextPREA = timeForNextREFA - memSpec->tRPpb; +}; + +class RefreshCheckerLPDDR4Bankwise final : public RefreshCheckerLPDDR4Dummy +{ +private: + friend class CheckerLPDDR4; + RefreshCheckerLPDDR4Bankwise(const MemSpecLPDDR4 *); + + void delayToSatisfyACT(Bank, sc_time &); + void delayToSatisfyRD(Bank, sc_time &); + void delayToSatisfyWR(Bank, sc_time &); + void insert(Bank); + + std::vector timesForNextREFB; + std::vector timesForNextPRE; +}; + +#endif // CHECKERLPDDR4_H diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 21ce0f0b..ecf8af92 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -56,6 +56,7 @@ #include "DramDDR3.h" #include "DramDDR4.h" #include "DramWideIO.h" +#include "DramLPDDR4.h" #include "../controller/Controller.h" #include "../controller/ControllerRecordable.h" @@ -282,6 +283,13 @@ void DRAMSys::instantiateModules(const string &traceName, else dram = new DramDDR4(str.c_str()); } + else if (memoryType == "LPDDR4") + { + if (recordingEnabled) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else + dram = new DramLPDDR4(str.c_str()); + } else { SC_REPORT_FATAL("DRAMSys", "Unsupported DRAM type"); diff --git a/DRAMSys/library/src/simulation/DramRecordable.cpp b/DRAMSys/library/src/simulation/DramRecordable.cpp index c0eeec7d..15093d8c 100644 --- a/DRAMSys/library/src/simulation/DramRecordable.cpp +++ b/DRAMSys/library/src/simulation/DramRecordable.cpp @@ -40,6 +40,7 @@ #include "DramDDR3.h" #include "DramDDR4.h" #include "DramWideIO.h" +#include "DramLPDDR4.h" #include "../common/utils.h" using namespace tlm; @@ -142,4 +143,5 @@ void DramRecordable::powerWindow() template class DramRecordable; template class DramRecordable; template class DramRecordable; +template class DramRecordable;