diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index e97f529b..badadba5 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -132,7 +132,8 @@ SOURCES += \ src/controller/checker/CheckerDDR3.cpp \ src/controller/refresh/RefreshManager.cpp \ src/controller/refresh/RefreshManagerDummy.cpp \ - src/controller/refresh/RefreshManagerBankwise.cpp + src/controller/refresh/RefreshManagerBankwise.cpp \ + src/controller/checker/CheckerWideIO.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ @@ -199,7 +200,8 @@ HEADERS += \ src/controller/refresh/RefreshManagerIF.h \ src/controller/refresh/RefreshManager.h \ src/controller/refresh/RefreshManagerDummy.h \ - src/controller/refresh/RefreshManagerBankwise.h + src/controller/refresh/RefreshManagerBankwise.h \ + src/controller/checker/CheckerWideIO.h #src/common/third_party/json/include/nlohmann/json.hpp \ thermalsim = $$(THERMALSIM) diff --git a/DRAMSys/library/src/controller/ControllerNew.cpp b/DRAMSys/library/src/controller/ControllerNew.cpp index 4e7290b4..85b05f2b 100644 --- a/DRAMSys/library/src/controller/ControllerNew.cpp +++ b/DRAMSys/library/src/controller/ControllerNew.cpp @@ -43,6 +43,7 @@ #include "../common/protocol.h" #include "core/scheduling/ScheduledCommand.h" #include "checker/CheckerDDR3.h" +#include "checker/CheckerWideIO.h" #include "refresh/RefreshManager.h" #include "refresh/RefreshManagerDummy.h" #include "refresh/RefreshManagerBankwise.h" @@ -57,7 +58,13 @@ ControllerNew::ControllerNew(sc_module_name name) : Configuration config = Configuration::getInstance(); - checker = new CheckerDDR3(); + if (config.memSpec->MemoryType == "DDR3") + checker = new CheckerDDR3(); + else if (config.memSpec->MemoryType == "WIDEIO_SDR") + checker = new CheckerWideIO(); + else + SC_REPORT_FATAL("ControllerNew", "Unsupported DRAM type"); + if (config.ControllerCoreRefDisable) refreshManager = new RefreshManagerDummy(); else if (config.BankwiseLogic) @@ -70,6 +77,7 @@ ControllerNew::ControllerNew(sc_module_name name) : refreshManager = new RefreshManager(bankMachines); refreshEvent.notify(refreshManager->getTriggerDelay()); } + if (config.Scheduler == "FifoStrict") { scheduler = new SchedulerFifo(); @@ -82,6 +90,7 @@ ControllerNew::ControllerNew(sc_module_name name) : } else SC_REPORT_FATAL("ControllerNew", "Selected scheduler not supported"); + for (unsigned bankID = 0; bankID < Configuration::getInstance().memSpec->NumberOfBanks; bankID++) bankMachines[Bank(bankID)] = new BankMachine(scheduler, checker, Bank(bankID)); diff --git a/DRAMSys/library/src/controller/checker/CheckerDDR3.cpp b/DRAMSys/library/src/controller/checker/CheckerDDR3.cpp index 60d5cf53..ec859bde 100644 --- a/DRAMSys/library/src/controller/checker/CheckerDDR3.cpp +++ b/DRAMSys/library/src/controller/checker/CheckerDDR3.cpp @@ -172,7 +172,6 @@ void CheckerDDR3::insert(const ScheduledCommand &scheduledCommand) lastScheduledByCommand[command] = scheduledCommand; lastScheduled = scheduledCommand; - // TODO: implement FAW for ACTB if (command == Command::ACT) { if (lastActivates.size() == 4) diff --git a/DRAMSys/library/src/controller/checker/CheckerDDR3.h b/DRAMSys/library/src/controller/checker/CheckerDDR3.h index b3416ea4..b30192eb 100644 --- a/DRAMSys/library/src/controller/checker/CheckerDDR3.h +++ b/DRAMSys/library/src/controller/checker/CheckerDDR3.h @@ -58,9 +58,6 @@ private: std::queue lastActivates; void delayToSatisfyFAW(sc_time &); - sc_time timeForNextREFA; - sc_time timeForNextPREA; - RefreshCheckerDDR3Dummy *refreshChecker; // PowerDown TODO: Implement this method? diff --git a/DRAMSys/library/src/controller/checker/CheckerWideIO.cpp b/DRAMSys/library/src/controller/checker/CheckerWideIO.cpp new file mode 100644 index 00000000..05e9585c --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerWideIO.cpp @@ -0,0 +1,252 @@ +/* + * 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 "CheckerWideIO.h" + +CheckerWideIO::CheckerWideIO() +{ + Configuration config = Configuration::getInstance(); + memSpec = dynamic_cast(config.memSpec); + if (memSpec == nullptr) + SC_REPORT_FATAL("CheckerWideIO", "Wrong MemSpec chosen"); + + if (config.ControllerCoreRefDisable) + refreshChecker = new RefreshCheckerWideIODummy(memSpec); + else if (config.BankwiseLogic) + refreshChecker = new RefreshCheckerWideIOBankwise(memSpec); + else + refreshChecker = new RefreshCheckerWideIO(memSpec); +} + +CheckerWideIO::~CheckerWideIO() +{ + delete refreshChecker; +} + +sc_time CheckerWideIO::delayToSatisfyConstraints(Command command, Bank bank) +{ + ScheduledCommand lastCommand; + + sc_time earliestTimeToStart = sc_time_stamp(); + + if (command == Command::ACT) + { + lastCommand = lastScheduledByCommandAndBank[Command::RDA][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRTP + memSpec->tRP); + + lastCommand = lastScheduledByCommandAndBank[Command::WRA][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tWL + memSpec->tCCD + memSpec->tWR + memSpec->tRP); + + lastCommand = lastScheduledByCommandAndBank[Command::PRE][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRP); + + lastCommand = lastScheduledByCommandAndBank[Command::ACT][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRC); + + lastCommand = lastScheduledByCommand[Command::ACT]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRRD); + + lastCommand = lastScheduledByCommand[Command::REFA]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRFC); + + lastCommand = lastScheduledByCommandAndBank[Command::REFB][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRFC); + + delayToSatisfyTAW(earliestTimeToStart); + + refreshChecker->delayToSatisfyACT(bank, earliestTimeToStart); + } + else if (command == Command::RD || command == Command::RDA) + { + lastCommand = lastScheduledByCommandAndBank[Command::ACT][bank]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRCD); + + lastCommand = lastScheduledByCommand[Command::RD]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tCCD); + + lastCommand = lastScheduledByCommand[Command::WR]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tWL + memSpec->tCCD + memSpec->tWTR); + + refreshChecker->delayToSatisfyRD(bank, earliestTimeToStart); + } + else if (command == Command::WR || command == Command::WRA) + { + lastCommand = lastScheduledByCommandAndBank[Command::ACT][bank]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRCD); + + lastCommand = lastScheduledByCommand[Command::RD]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRL + memSpec->tCCD + 2 * memSpec->clk - memSpec->tWL); + + lastCommand = lastScheduledByCommand[Command::WR]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tCCD); + + refreshChecker->delayToSatisfyWR(bank, earliestTimeToStart); + } + else if (command == Command::PRE) + { + lastCommand = lastScheduledByCommandAndBank[Command::ACT][bank]; + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRAS); + + lastCommand = lastScheduledByCommandAndBank[Command::RD][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tRTP); + + lastCommand = lastScheduledByCommandAndBank[Command::WR][bank]; + if (lastCommand.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastCommand.getStart() + memSpec->tWL + memSpec->tCCD + memSpec->tWR); + + refreshChecker->delayToSatisfyPRE(bank, earliestTimeToStart); + } + else + { + reportFatal("CheckerWideIO", "Unknown command!"); + } + // Check if command bus is free + if (lastScheduled.isValidCommand()) + earliestTimeToStart = std::max(earliestTimeToStart, lastScheduled.getStart() + memSpec->clk); + + return (earliestTimeToStart - sc_time_stamp()); +} + +void CheckerWideIO::delayToSatisfyTAW(sc_time &earliestTimeToStart) +{ + if (lastActivates.size() >= 2) + { + sc_time earliestTime = lastActivates.front() + memSpec->tTAW; + if (earliestTime > earliestTimeToStart) + earliestTimeToStart = earliestTime; + } +} + +void CheckerWideIO::insert(const ScheduledCommand &scheduledCommand) +{ + Command command = scheduledCommand.getCommand(); + Bank bank = scheduledCommand.getBank(); + PRINTDEBUGMESSAGE("CheckerWideIO", "Changing state on bank " + + to_string(scheduledCommand.getBank().ID()) + + " command is " + commandToString(command)); + + lastScheduledByCommandAndBank[command][bank] = scheduledCommand; + lastScheduledByCommand[command] = scheduledCommand; + lastScheduled = scheduledCommand; + + if (command == Command::ACT) + { + if (lastActivates.size() == 2) + lastActivates.pop(); + lastActivates.push(scheduledCommand.getStart()); + } + else if (command == Command::REFA || command == Command::REFB) + refreshChecker->insert(bank); +} + +// TODO: max(earliestTimeToStart, ...) needed? +void RefreshCheckerWideIO::delayToSatisfyACT(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tRAS)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFC; +} + +void RefreshCheckerWideIO::delayToSatisfyRD(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tRTP)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFC; +} + +void RefreshCheckerWideIO::delayToSatisfyWR(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timeForNextPREA - memSpec->tWL - memSpec->tCCD - memSpec->tWR)) + earliestTimeToStart = timeForNextREFA + memSpec->tRFC; +} + +void RefreshCheckerWideIO::delayToSatisfyPRE(Bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= timeForNextPREA) + earliestTimeToStart = timeForNextREFA + memSpec->tRFC; +} + +void RefreshCheckerWideIO::insert(Bank) +{ + timeForNextREFA += memSpec->tREFI; + timeForNextPREA += memSpec->tREFI; +} + +RefreshCheckerWideIOBankwise::RefreshCheckerWideIOBankwise(const MemSpecWideIO *memSpec) + : RefreshCheckerWideIODummy(memSpec) +{ + sc_time currentREFB = memSpec->tREFI - memSpec->clk * (memSpec->NumberOfBanks - 1); + sc_time currentPRE = currentREFB - std::max(memSpec->clk * memSpec->NumberOfBanks, memSpec->tRP); + for (unsigned bankID = 0; bankID < memSpec->NumberOfBanks; bankID++) + { + timesForNextREFB[Bank(bankID)] = currentREFB; + timesForNextPRE[Bank(bankID)] = currentPRE; + currentREFB += memSpec->clk; + currentPRE += memSpec->clk; + } +} + +void RefreshCheckerWideIOBankwise::delayToSatisfyACT(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank] - memSpec->tRAS)) + earliestTimeToStart = timesForNextREFB[bank] + memSpec->tRFC; +} + +void RefreshCheckerWideIOBankwise::delayToSatisfyRD(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank] - memSpec->tRTP)) + earliestTimeToStart = timesForNextREFB[bank] + memSpec->tRFC; +} + +void RefreshCheckerWideIOBankwise::delayToSatisfyWR(Bank bank, sc_time &earliestTimeToStart) +{ + if (earliestTimeToStart >= (timesForNextPRE[bank] - memSpec->tWL - memSpec->tCCD - memSpec->tWR)) + earliestTimeToStart = timesForNextREFB[bank] + memSpec->tRFC; +} + +void RefreshCheckerWideIOBankwise::insert(Bank bank) +{ + timesForNextREFB[bank] += memSpec->tREFI; + timesForNextPRE[bank] += memSpec->tREFI; +} diff --git a/DRAMSys/library/src/controller/checker/CheckerWideIO.h b/DRAMSys/library/src/controller/checker/CheckerWideIO.h new file mode 100644 index 00000000..1751d3cc --- /dev/null +++ b/DRAMSys/library/src/controller/checker/CheckerWideIO.h @@ -0,0 +1,115 @@ +/* + * 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 CHECKERWIDEIO_H +#define CHECKERWIDEIO_H + +#include "CheckerIF.h" +#include +#include +#include "../core/configuration/MemSpec.h" +#include "../core/configuration/Configuration.h" + +class RefreshCheckerWideIODummy; + +class CheckerWideIO final : public CheckerIF +{ +public: + CheckerWideIO(); + ~CheckerWideIO(); + sc_time delayToSatisfyConstraints(Command, Bank); + void insert(const ScheduledCommand &); + +private: + const MemSpecWideIO *memSpec; + + // Four activate window + std::queue lastActivates; + void delayToSatisfyTAW(sc_time &); + + RefreshCheckerWideIODummy *refreshChecker; + + // PowerDown TODO: Implement this method? + //sc_time getTimeConstraintToEnterPowerDown(Command lastCmd, Command pdnCmd) const; +}; + +class RefreshCheckerWideIODummy +{ +protected: + friend class CheckerWideIO; + RefreshCheckerWideIODummy(const MemSpecWideIO *memSpec) : memSpec(memSpec) {} + virtual ~RefreshCheckerWideIODummy() {} + + 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 MemSpecWideIO *memSpec; +}; + +class RefreshCheckerWideIO final : public RefreshCheckerWideIODummy +{ +private: + friend class CheckerWideIO; + RefreshCheckerWideIO(const MemSpecWideIO *memSpec) + : RefreshCheckerWideIODummy(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->tRP; +}; + +class RefreshCheckerWideIOBankwise final : public RefreshCheckerWideIODummy +{ +private: + friend class CheckerWideIO; + RefreshCheckerWideIOBankwise(const MemSpecWideIO *); + + void delayToSatisfyACT(Bank, sc_time &); + void delayToSatisfyRD(Bank, sc_time &); + void delayToSatisfyWR(Bank, sc_time &); + void insert(Bank); + + std::map timesForNextREFB; + std::map timesForNextPRE; +}; + +#endif // CHECKERWIDEIO_H diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index e41e1862..ebaac161 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -269,13 +269,6 @@ void DRAMSys::instantiateModules(const string &traceName, else dram = new DramDDR3(str.c_str()); } - else if (memoryType == "DDR4") - { - if (recordingEnabled) - dram = new DramRecordable(str.c_str(), tlmRecorders[i]); - else - dram = new DramDDR4(str.c_str()); - } else if (memoryType == "WIDEIO_SDR") { if (recordingEnabled) @@ -283,6 +276,13 @@ void DRAMSys::instantiateModules(const string &traceName, else dram = new DramWideIO(str.c_str()); } + else if (memoryType == "DDR4") + { + if (recordingEnabled) + dram = new DramRecordable(str.c_str(), tlmRecorders[i]); + else + dram = new DramDDR4(str.c_str()); + } else { SC_REPORT_FATAL("DRAMSys", "Unsupported DRAM type");