Files
DRAMSys/dram/src/controller/core/ControllerCore.cpp
2015-05-13 12:26:21 +02:00

230 lines
8.2 KiB
C++

/*
* Copyright (c) 2015, 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.
*
* Authors:
* Janik Schlemminger
* Matthias Jung
*/
#include <systemc.h>
#include "ControllerCore.h"
#include "scheduling/checker/ActivateChecker.h"
#include "scheduling/checker/PrechargeChecker.h"
#include "scheduling/checker/PrechargeAllChecker.h"
#include "scheduling/checker/ReadChecker.h"
#include "scheduling/checker/WriteChecker.h"
#include "scheduling/checker/RefreshChecker.h"
#include "scheduling/checker/PowerDownChecker.h"
#include "refresh/RefreshManagerBankwise.h"
#include "refresh/RefreshManager.h"
#include "../../common/dramExtension.h"
#include "../../common/Utils.h"
#include "TimingCalculation.h"
#include "powerdown/PowerDownManager.h"
#include "powerdown/PowerDownManagerTimeout.h"
#include "powerdown/PowerDownManagerBankwise.h"
#include "powerdown/NoPowerDown.h"
#include "../../common/DebugManager.h"
std::string ControllerCore::senderName = "Controller Core";
ControllerCore::ControllerCore(IController& wrapperConnector, std::map<Bank, int>& numberOfPayloads) :
config(Configuration::getInstance()), state(&config), controller(wrapperConnector), numberOfPayloads(
numberOfPayloads), commandChecker()
{
commandChecker[Command::Activate] = new ActivateChecker(config, state);
commandChecker[Command::Precharge] = new PrechargeChecker(config, state);
commandChecker[Command::PrechargeAll] = new PrechargeAllChecker(config, state);
commandChecker[Command::Read] = new ReadChecker(config, state);
commandChecker[Command::ReadA] = commandChecker[Command::Read];
commandChecker[Command::Write] = new WriteChecker(config, state);
commandChecker[Command::WriteA] = commandChecker[Command::Write];
commandChecker[Command::AutoRefresh] = new RefreshChecker(config, state);
commandChecker[Command::PDNA] = new PowerDownChecker(config, state);
commandChecker[Command::PDNP] = commandChecker[Command::PDNA];
commandChecker[Command::SREF] = commandChecker[Command::PDNA];
commandChecker[Command::PDNAX] = commandChecker[Command::PDNA];
commandChecker[Command::PDNPX] = commandChecker[Command::PDNA];
commandChecker[Command::SREFX] = commandChecker[Command::PDNA];
if (config.BankwiseLogic)
{
refreshManager = new RefreshManagerBankwise(*this);
powerDownManager = new PowerDownManagerBankwise(*this);
}
else
{
refreshManager = new RefreshManager(*this);
if(config.PowerDownMode == EPowerDownMode::Staggered)
{
powerDownManager = new PowerDownManager(*this);
}
else if(config.PowerDownMode == EPowerDownMode::TimeoutPDN || config.PowerDownMode == EPowerDownMode::TimeoutSREF)
{
powerDownManager = new PowerDownManagerTimeout(*this);
}
else if(config.PowerDownMode == EPowerDownMode::NoPowerDown)
{
powerDownManager = new NoPowerDown();
}
else
{
SC_REPORT_FATAL(0, "Unsupported powerdown mode in constructor of controller core");
}
}
}
ControllerCore::~ControllerCore()
{
delete commandChecker[Command::Activate];
delete commandChecker[Command::Precharge];
delete commandChecker[Command::Read];
delete commandChecker[Command::Write];
delete commandChecker[Command::AutoRefresh];
delete commandChecker[Command::PDNA];
delete refreshManager;
delete powerDownManager;
}
void ControllerCore::triggerRefresh(tlm::tlm_generic_payload& payload)
{
sc_time time = sc_time_stamp();
Bank bank = DramExtension::getExtension(payload).getBank();
state.cleanUp(time);
if (!refreshManager->isInvalidated(payload, time) && !powerDownManager->isInSelfRefresh(bank))
{
printDebugMessage("Triggering refresh on bank " + to_string(bank.ID()));
powerDownManager->wakeUpForRefresh(bank, time); //expects PDNA and PDNP to exit without delay
refreshManager->scheduleRefresh(payload, time);
}
}
void ControllerCore::scheduleRequest(Command command, tlm::tlm_generic_payload &payload)
{
sc_time start = clkAlign(sc_time_stamp());
state.cleanUp(start);
ScheduledCommand scheduledCommand = schedule(command, start, payload);
state.change(scheduledCommand);
controller.send(scheduledCommand, payload);
}
ScheduledCommand ControllerCore::schedule(Command command, sc_time start,
tlm::tlm_generic_payload& payload)
{
ControllerCore::printDebugMessage("Scheduling command " + commandToString(command) + " on " + DramExtension::getBank(payload).toString());
ICommandChecker& checker = getCommandChecker(command);
sc_time executionTime = getExecutionTime(command, payload);
ScheduledCommand scheduledCommand(command, start, executionTime, DramExtension::getExtension(payload));
checker.delayToSatisfyConstraints(scheduledCommand);
return scheduledCommand;
}
bool ControllerCore::bankIsBusy(Bank bank)
{
sc_time time = sc_time_stamp();
ScheduledCommand lastScheduledCommand = state.getLastScheduledCommand(bank);
if (lastScheduledCommand.isNoCommand())
return false;
else if (lastScheduledCommand.commandIsIn( { Command::Write, Command::Read }))
{
// Read and writes can overlap, so the bank should not be busy during a rd/wr
return (time < lastScheduledCommand.getStart());
}
else if (lastScheduledCommand.commandIsIn( { Command::WriteA, Command::ReadA, Command::Precharge, Command::PrechargeAll, Command::Activate }))
{
return (time < lastScheduledCommand.getEnd());
}
else if (lastScheduledCommand.getCommand() == Command::AutoRefresh)
{
return (time < lastScheduledCommand.getEnd());
}
else if (lastScheduledCommand.commandIsIn( { Command::SREFX, Command::PDNPX, Command::PDNAX, Command::SREF, Command::PDNP,
Command::PDNA }))
{
return false;
}
else
{
SC_REPORT_FATAL("Core", "Last command unkown");
return false;
}
}
const std::vector<Bank>& ControllerCore::getBanks()
{
static std::vector<Bank> banks;
if (banks.size() == 0)
{
for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; i++)
{
banks.push_back(Bank(i));
}
}
return banks;
}
std::vector<Bank> ControllerCore::getFreeBanks()
{
std::vector<Bank> freeBanks;
for(Bank bank: getBanks())
{
if(!bankIsBusy(bank))
freeBanks.push_back(bank);
}
return freeBanks;
}
ICommandChecker& ControllerCore::getCommandChecker(Command command)
{
return *getElementFromMap(commandChecker, command);
}
void ControllerCore::printDebugMessage(string message)
{
DebugManager::getInstance().printDebugMessage(ControllerCore::senderName, message);
}