/* * controller.cpp * * Created on: Mar 5, 2014 * Author: jonny */ #include #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& 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& ControllerCore::getBanks() { static std::vector banks; if (banks.size() == 0) { for (unsigned int i = 0; i < config.memSpec.NumberOfBanks; i++) { banks.push_back(Bank(i)); } } return banks; } std::vector ControllerCore::getFreeBanks() { std::vector 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); }