Included LPDDR4 timing checker and example.
This commit is contained in:
@@ -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)
|
||||
|
||||
29
DRAMSys/library/resources/configs/simulator/lpddr4.xml
Normal file
29
DRAMSys/library/resources/configs/simulator/lpddr4.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<simconfig>
|
||||
<SimulationName value="lpddr4" />
|
||||
<Debug value="0" />
|
||||
<DatabaseRecording value="1" />
|
||||
<PowerAnalysis value="0" />
|
||||
<EnableWindowing value = "0" />
|
||||
<WindowSize value="1000" />
|
||||
<ThermalSimulation value="0"/>
|
||||
<SimulationProgressBar value="1"/>
|
||||
<NumberOfMemChannels value="1"/>
|
||||
<NumberOfDevicesOnDIMM value = "1" />
|
||||
<CheckTLM2Protocol value = "0" />
|
||||
<AddressOffset value = "0" />
|
||||
<ECCControllerMode value = "Disabled" />
|
||||
<ErrorChipSeed value="42" />
|
||||
<ErrorCSVFile value="" />
|
||||
<!-- Modes:
|
||||
- NoStorage,
|
||||
- Store (store data without errormodel),
|
||||
- ErrorModel (store data with errormodel)
|
||||
-->
|
||||
<StoreMode value="NoStorage" />
|
||||
<!-- Gem5 Related Configuration:
|
||||
In the memory controller file the storage mode should be set to Store
|
||||
E.g. the DRAM is located at 0x80000000 for gem5
|
||||
<AddressOffset value = "2147483648" />
|
||||
-->
|
||||
<UseMalloc value="0" />
|
||||
</simconfig>
|
||||
25
DRAMSys/library/resources/simulations/lpddr4-example.xml
Normal file
25
DRAMSys/library/resources/simulations/lpddr4-example.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<simulation>
|
||||
<!-- Simulation file identifier -->
|
||||
<simulationid id="lpddr4-example"></simulationid>
|
||||
<!-- Configuration for the DRAMSys Simulator -->
|
||||
<simconfig src="lpddr4.xml" />
|
||||
<!-- Temperature Simulator Configuration -->
|
||||
<thermalconfig src="config.xml" />
|
||||
<!-- Memory Device Specification: Which Device is on the DDR3 DIMM -->
|
||||
<memspec src="JEDEC_8Gb_LPDDR4-3200_16bit.xml"></memspec>
|
||||
<!-- Addressmapping Configuration of the Memory Controller -->
|
||||
<addressmapping src="am_lpddr4_8Gbx16_brc.xml"></addressmapping>
|
||||
<!-- Memory Controller Configuration: -->
|
||||
<mcconfig src="fifoStrict.xml"/>
|
||||
<!--
|
||||
The following trace setup is only used in standalone mode.
|
||||
In library mode e.g. in Platform Architect the trace setup is ignored.
|
||||
-->
|
||||
<tracesetup>
|
||||
<!--
|
||||
This device mimics an image processing application
|
||||
running on an FPGA with 200 Mhz.
|
||||
-->
|
||||
<device clkMhz="200">ddr3_example.stl</device>
|
||||
</tracesetup>
|
||||
</simulation>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
|
||||
using namespace tlm;
|
||||
|
||||
MemSpec::MemSpec()
|
||||
{
|
||||
commandLength = std::vector<unsigned>(numberOfCommands(), 1);
|
||||
}
|
||||
|
||||
const std::vector<Bank> &MemSpec::getBanks() const
|
||||
{
|
||||
static std::vector<Bank> 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)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#define MEMSPEC_H
|
||||
|
||||
#include <systemc.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#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<Bank> &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<unsigned> commandLength;
|
||||
};
|
||||
|
||||
#endif // MEMSPEC_H
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
268
DRAMSys/library/src/controller/checker/CheckerLPDDR4.cpp
Normal file
268
DRAMSys/library/src/controller/checker/CheckerLPDDR4.cpp
Normal file
@@ -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<MemSpecLPDDR4 *>(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<std::vector<sc_time>>
|
||||
(numberOfCommands(), std::vector<sc_time>(memSpec->NumberOfBanks));
|
||||
lastScheduledByCommandAndRank = std::vector<std::vector<sc_time>>
|
||||
(numberOfCommands(), std::vector<sc_time>(memSpec->NumberOfRanks));
|
||||
lastScheduledByCommand = std::vector<sc_time>(numberOfCommands());
|
||||
|
||||
lastActivates = std::vector<std::queue<sc_time>>(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;
|
||||
}
|
||||
119
DRAMSys/library/src/controller/checker/CheckerLPDDR4.h
Normal file
119
DRAMSys/library/src/controller/checker/CheckerLPDDR4.h
Normal file
@@ -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 <queue>
|
||||
#include <vector>
|
||||
#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<std::vector<sc_time>> lastScheduledByCommandAndBank;
|
||||
std::vector<std::vector<sc_time>> lastScheduledByCommandAndRank;
|
||||
std::vector<sc_time> lastScheduledByCommand;
|
||||
sc_time lastCommandOnBus;
|
||||
|
||||
// Four activate window
|
||||
std::vector<std::queue<sc_time>> 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<sc_time> timesForNextREFB;
|
||||
std::vector<sc_time> timesForNextPRE;
|
||||
};
|
||||
|
||||
#endif // CHECKERLPDDR4_H
|
||||
@@ -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<DramLPDDR4>(str.c_str(), tlmRecorders[i]);
|
||||
else
|
||||
dram = new DramLPDDR4(str.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
SC_REPORT_FATAL("DRAMSys", "Unsupported DRAM type");
|
||||
|
||||
@@ -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<BaseDram>::powerWindow()
|
||||
template class DramRecordable<DramDDR3>;
|
||||
template class DramRecordable<DramDDR4>;
|
||||
template class DramRecordable<DramWideIO>;
|
||||
template class DramRecordable<DramLPDDR4>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user