Add LP5 source files.

This commit is contained in:
Lukas Steiner
2021-12-13 11:38:08 +01:00
parent 4e1407eb51
commit 0e3ac61979
16 changed files with 1520 additions and 2 deletions

View File

@@ -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

View File

@@ -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")

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 <iostream>
#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<uint64_t>(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 {};
}
}

View File

@@ -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 <systemc>
#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

View File

@@ -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);

View File

@@ -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 <algorithm>
#include "CheckerLPDDR5.h"
using namespace sc_core;
using namespace tlm;
CheckerLPDDR5::CheckerLPDDR5()
{
Configuration &config = Configuration::getInstance();
memSpec = dynamic_cast<const MemSpecLPDDR5 *>(config.memSpec);
if (memSpec == nullptr)
SC_REPORT_FATAL("CheckerLPDDR5", "Wrong MemSpec chosen");
else
{
lastScheduledByCommandAndRank = std::vector<std::vector<sc_time>>
(Command::numberOfCommands(), std::vector<sc_time>(memSpec->numberOfRanks, sc_max_time()));
lastScheduledByCommandAndBankGroup = std::vector<std::vector<sc_time>>
(Command::numberOfCommands(), std::vector<sc_time>(memSpec->numberOfBankGroups, sc_max_time()));
lastScheduledByCommandAndBank = std::vector<std::vector<sc_time>>
(Command::numberOfCommands(), std::vector<sc_time>(memSpec->numberOfBanks, sc_max_time()));
lastScheduledByCommand = std::vector<sc_time>(Command::numberOfCommands(), sc_max_time());
lastCommandOnBus = sc_max_time();
last4Activates = std::vector<std::queue<sc_time>>(memSpec->numberOfRanks);
lastBurstLengthByCommandAndRank = std::vector<std::vector<uint8_t>>
(Command::WRA + 1, std::vector<uint8_t>(memSpec->numberOfRanks));
lastBurstLengthByCommandAndBankGroup = std::vector<std::vector<uint8_t>>
(Command::WRA + 1, std::vector<uint8_t>(memSpec->numberOfBankGroups));
lastBurstLengthByCommandAndBank = std::vector<std::vector<uint8_t>>
(Command::WRA + 1, std::vector<uint8_t>(memSpec->numberOfBanks));
lastBurstLengthByCommand = std::vector<uint8_t>(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);
}
}

View File

@@ -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 <queue>
#include <vector>
#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<std::vector<sc_core::sc_time>> lastScheduledByCommandAndRank;
std::vector<std::vector<sc_core::sc_time>> lastScheduledByCommandAndBankGroup;
std::vector<std::vector<sc_core::sc_time>> lastScheduledByCommandAndBank;
std::vector<sc_core::sc_time> lastScheduledByCommand;
sc_core::sc_time lastCommandOnBus;
std::vector<std::queue<sc_core::sc_time>> last4Activates;
std::vector<std::vector<uint8_t>> lastBurstLengthByCommandAndRank;
std::vector<std::vector<uint8_t>> lastBurstLengthByCommandAndBankGroup;
std::vector<std::vector<uint8_t>> lastBurstLengthByCommandAndBank;
std::vector<uint8_t> 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

View File

@@ -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<BankMachine *> &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<int>(config.refreshMaxPostponed * memSpec->banksPerRank / 2);
maxPulledin = -static_cast<int>(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;
}
}

View File

@@ -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 <vector>
#include <list>
#include <unordered_map>
#include <systemc>
#include <tlm>
#include "RefreshManagerIF.h"
#include "../../configuration/memspec/MemSpec.h"
#include "../BankMachine.h"
#include "../powerdown/PowerDownManagerIF.h"
class RefreshManagerPer2Bank final : public RefreshManagerIF
{
public:
RefreshManagerPer2Bank(std::vector<BankMachine *> &, 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<BankMachine *, tlm::tlm_generic_payload> 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<std::vector<BankMachine *>> remainingBankMachines;
std::list<std::vector<BankMachine *>> allBankMachines;
std::list<std::vector<BankMachine *>>::iterator currentIterator;
int flexibilityCounter = 0;
int maxPostponed = 0;
int maxPulledin = 0;
bool sleeping = false;
bool skipSelection = false;
};
#endif // REFRESHMANAGERPER2BANK_H

View File

@@ -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)

View File

@@ -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<DramWideIO>(str.c_str(), tlmRecorders[i]);
else if (memoryType == MemSpec::MemoryType::LPDDR4)
dram = new DramRecordable<DramLPDDR4>(str.c_str(), tlmRecorders[i]);
else if (memoryType == MemSpec::MemoryType::LPDDR5)
dram = new DramRecordable<DramLPDDR5>(str.c_str(), tlmRecorders[i]);
else if (memoryType == MemSpec::MemoryType::WideIO2)
dram = new DramRecordable<DramWideIO2>(str.c_str(), tlmRecorders[i]);
else if (memoryType == MemSpec::MemoryType::HBM2)

View File

@@ -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");
}

View File

@@ -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 <systemc.h>
#include "Dram.h"
class DramLPDDR5 : public Dram
{
public:
explicit DramLPDDR5(const sc_module_name &name);
SC_HAS_PROCESS(DramLPDDR5);
};
#endif // DRAMLPDDR5_H

View File

@@ -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<DramDDR3>;
template class DramRecordable<DramDDR4>;
template class DramRecordable<DramDDR5>;
template class DramRecordable<DramLPDDR4>;
template class DramRecordable<DramLPDDR5>;
template class DramRecordable<DramWideIO>;
template class DramRecordable<DramWideIO2>;
template class DramRecordable<DramGDDR5>;