Major change to simulation logic in dramSys: Commands in a transaction are now scheduled one at a time, instead of scheduling a whole transaction at once. Since single commands (e.g. Pre or Act) are not that long, refreshes are allowed to be delayed to allow a command to finsh. Consequently, the whole loop in the ControllerCore about trying to scheduleding a transaction and aborting it when it collides with a refresh could be ommitted. Lastly, Fifo_Strict has been added, which is a Fifo Scheduler that forces the read and write transactions, even between different banks to be executed in order. Fifo and FR_FCFS have been modified to fit into the new scheduling logic.
201 lines
6.6 KiB
C++
201 lines
6.6 KiB
C++
/*
|
|
* controller.cpp
|
|
*
|
|
* Created on: Mar 5, 2014
|
|
* Author: jonny
|
|
*/
|
|
|
|
#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);
|
|
}
|
|
|
|
|