diff --git a/DRAMSys/simulator/simulator.pro b/DRAMSys/simulator/simulator.pro index 7eed4ce4..a3ce17e7 100644 --- a/DRAMSys/simulator/simulator.pro +++ b/DRAMSys/simulator/simulator.pro @@ -103,7 +103,8 @@ SOURCES += \ src/controller/RowBufferStates.cpp \ src/controller/scheduler/IScheduler.cpp \ src/controller/scheduler/FifoStrict.cpp \ - src/error/errormodel.cpp + src/error/errormodel.cpp \ + src/controller/Controller.cpp HEADERS += \ src/common/third_party/tinyxml2/tinyxml2.h \ diff --git a/DRAMSys/simulator/src/controller/Controller.cpp b/DRAMSys/simulator/src/controller/Controller.cpp new file mode 100644 index 00000000..52b416d6 --- /dev/null +++ b/DRAMSys/simulator/src/controller/Controller.cpp @@ -0,0 +1,526 @@ +/* + * 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: + * Robert Gernhardt + * Matthias Jung + */ + +#include "Controller.h" + +void Controller::buildScheduler() +{ + string selectedScheduler = Configuration::getInstance().Scheduler; + + if (selectedScheduler == "FIFO") + { + scheduler = new Fifo(*controllerCore); + } + else if (selectedScheduler == "FIFO_STRICT") + { + scheduler = new FifoStrict(*this, *controllerCore); + } + else if (selectedScheduler == "FR_FCFS") + { + scheduler = new FR_FCFS(*controllerCore); + } + // else if (selectedScheduler == "PAR_BS") + // { + // scheduler = new PAR_BS(*controllerCore, Configuration::getInstance().RefreshAwareScheduling, + // Configuration::getInstance().Capsize); + // } + // else if (selectedScheduler == "Grouper") + // { + // scheduler = new ReadWriteGrouper(*controllerCore); + // } + else + reportFatal(name(), "unsupported scheduler: " + selectedScheduler); +} + +void Controller::send(const ScheduledCommand &command, tlm_generic_payload &payload) +{ + sc_assert(command.getStart() >= sc_time_stamp()); + TimeInterval dataStrobe; + + switch (command.getCommand()) + { + //TODO: refactor tlm recorder + case Command::Read: + dataStrobe = command.getIntervalOnDataStrobe(); + tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_RD, command.getStart() - sc_time_stamp()); + break; + case Command::ReadA: + dataStrobe = command.getIntervalOnDataStrobe(); + tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_RDA, command.getStart() - sc_time_stamp()); + break; + case Command::Write: + dataStrobe = command.getIntervalOnDataStrobe(); + tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_WR, command.getStart() - sc_time_stamp()); + break; + case Command::WriteA: + dataStrobe = command.getIntervalOnDataStrobe(); + tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); + controllerCorePEQ.notify(payload, BEGIN_WRA, command.getStart() - sc_time_stamp()); + break; + case Command::AutoRefresh: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, BEGIN_REFA, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, BEGIN_REFB, command.getStart() - sc_time_stamp()); + break; + case Command::Activate: + controllerCorePEQ.notify(payload, BEGIN_ACT, command.getStart() - sc_time_stamp()); + break; + case Command::Precharge: + controllerCorePEQ.notify(payload, BEGIN_PRE, command.getStart() - sc_time_stamp()); + break; + case Command::PrechargeAll: + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, BEGIN_PRE_ALL, command.getStart() - sc_time_stamp()); + break; + case Command::PDNA: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, BEGIN_PDNA, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, BEGIN_PDNAB, command.getStart() - sc_time_stamp()); + break; + case Command::PDNAX: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, END_PDNA, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, END_PDNAB, command.getStart() - sc_time_stamp()); + break; + case Command::PDNP: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, BEGIN_PDNP, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, BEGIN_PDNPB, command.getStart() - sc_time_stamp()); + break; + case Command::PDNPX: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, END_PDNP, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, END_PDNPB, command.getStart() - sc_time_stamp()); + break; + case Command::SREF: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, BEGIN_SREF, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, BEGIN_SREFB, command.getStart() - sc_time_stamp()); + break; + case Command::SREFX: + if(!Configuration::getInstance().BankwiseLogic) + { + if(command.getBank() == Bank(0)) + controllerCorePEQ.notify(payload, END_SREF, command.getStart() - sc_time_stamp()); + } + else + controllerCorePEQ.notify(payload, END_SREFB, command.getStart() - sc_time_stamp()); + break; + default: + SC_REPORT_FATAL(0, "unsupported command was sent by controller"); + break; + } +} + +void Controller::send(Trigger trigger, sc_time time, tlm_generic_payload &payload) +{ + sc_assert(time >= sc_time_stamp()); + + sc_time delay = time - sc_time_stamp(); + if (trigger == Trigger::REFTrigger) + { + controllerCorePEQ.notify(payload, REF_TRIGGER, delay); + } + else if (trigger == Trigger::PDNTrigger) + { + controllerCorePEQ.notify(payload, PDN_TRIGGER, delay); + } + else + { + SC_REPORT_FATAL("controller wrapper", "unknown trigger"); + } +} + +void Controller::controllerCorePEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) +{ + if (phase == REF_TRIGGER) + { + controllerCore->triggerRefresh(payload); + } + else if (phase == PDN_TRIGGER) + { + controllerCore->powerDownManager->sleep(DramExtension::getExtension(payload).getBank(),sc_time_stamp()); + } + else + { + Bank bank = DramExtension::getBank(payload); + sendToDram(payload, phase, SC_ZERO_TIME); + + if (phase == BEGIN_RD || phase == BEGIN_WR) + { + scheduleNextFromScheduler(DramExtension::getBank(payload)); + } + else if (phase == BEGIN_REFB) + printDebugMessage("Entering REFB on bank " + to_string(bank.ID())); + else if (phase == BEGIN_REFA) + printDebugMessage("Entering REFA"); + else if (containsPhase(phase, { BEGIN_PDNAB, BEGIN_PDNPB, BEGIN_SREFB })) + printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); + else if (containsPhase(phase, { END_PDNAB, END_PDNPB, END_SREFB })) + printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); + else if (containsPhase(phase, { BEGIN_PDNA, BEGIN_PDNP, BEGIN_SREF })) + printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on all banks"); + else if (containsPhase(phase, { END_PDNA, END_PDNP, END_SREF })) + printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on all banks" ); + else if (containsPhase(phase, { BEGIN_RD, BEGIN_WR, BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA })) + { + } + else + SC_REPORT_FATAL(0, "refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase"); + } +} + +tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &fwDelay) +{ + sc_time recTime; + sc_time notDelay; + if (phase == BEGIN_REQ) + { + recTime = fwDelay + sc_time_stamp(); + notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) + Configuration::getInstance().memSpec.clk; + + printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); + + tlmRecorder->recordPhase(payload, phase, recTime); + frontendPEQ.notify(payload, phase, notDelay); + + //Bandwidth IDLE + if ((getTotalNumberOfPayloadsInSystem()== 0)&& idleState){ + endBandwidthIdleCollector(); + } + } + else if (phase == END_RESP) + { + recTime = fwDelay + sc_time_stamp() + Configuration::getInstance().memSpec.clk; + notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay); + + printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); + + // Badnwith IDLE + if (getTotalNumberOfPayloadsInSystem()==1){ + startBandwidthIdleCollector(); + } + + tlmRecorder->recordPhase(payload, phase, recTime); + frontendPEQ.notify(payload, phase, notDelay); + } + return TLM_ACCEPTED; +} + +unsigned int Controller::transport_dbg(tlm::tlm_generic_payload& trans) +{ + return iSocket->transport_dbg(trans); +} + +void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) +{ + if (phase == BEGIN_REQ) + { + printDebugMessage(string("Payload in system: ") + to_string(getTotalNumberOfPayloadsInSystem())); + payload.acquire(); + payloadEntersSystem(payload); + if (getTotalNumberOfPayloadsInSystem() > controllerCore->config.MaxNrOfTransactions) + { + printDebugMessage("##Backpressure: Max number of transactions in system reached"); + backpressure = &payload; + return; + } + payload.set_response_status(tlm::TLM_OK_RESPONSE); + sendToFrontend(payload, END_REQ, SC_ZERO_TIME); + + scheduler->schedule(&payload); + scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); + } + else if (phase == END_RESP) + { + if (backpressure != NULL) + { + printDebugMessage("##Backpressure released"); + backpressure->set_response_status(tlm::TLM_OK_RESPONSE); + sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME); + + scheduler->schedule(backpressure); + scheduleNextFromScheduler(DramExtension::getExtension(backpressure).getBank()); + backpressure = NULL; + } + + payloadLeavesSystem(payload); + payload.release(); + } + else + { + SC_REPORT_FATAL(0, "Frontend PEQ event queue in controller wrapper was triggered with unknown phase"); + } +} + +void Controller::payloadEntersSystem(tlm_generic_payload &payload) +{ + Bank bank = DramExtension::getExtension(payload).getBank(); + printDebugMessage( + "Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + + to_string(getTotalNumberOfPayloadsInSystem())); + numberOfPayloadsInSystem[bank]++; + // Set Start Time for Simulation + if (startTimeSet == false){ + printDebugMessage("Simulation Timer Start"); + startTime = sc_time_stamp()-Configuration::getInstance().memSpec.clk; + startTimeSet = true; + } +} + +void Controller::payloadLeavesSystem(tlm_generic_payload &payload) +{ + Bank bank = DramExtension::getExtension(payload).getBank(); + numberOfPayloadsInSystem[bank]--; + printDebugMessage( + "Payload left system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " + + to_string(getTotalNumberOfPayloadsInSystem())); + controllerCore->powerDownManager->triggerSleep(bank, sc_time_stamp()); +} + +unsigned int Controller::getTotalNumberOfPayloadsInSystem() +{ + unsigned int sum = 0; + for (Bank bank : controllerCore->getBanks()) + { + sum += numberOfPayloadsInSystem[bank]; + } + return sum; +} + +void Controller::scheduleNextFromScheduler(Bank bank) +{ + + if(controllerCore->bankIsBusy(bank)) + { + return; + } + + pair nextRequest = scheduler->getNextRequest(bank); + if(nextRequest.second != NULL) + { + controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp()); + controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); + printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "]"); + } + + while (!blockedRequests.empty()) { + bank = blockedRequests.front(); + blockedRequests.pop(); + + pair nextRequest = scheduler->getNextRequest(bank); + if (nextRequest.second != NULL) { + controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp()); + controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); + printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "] (unblocked)"); + } + } + +} + +void Controller::sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + tSocket->nb_transport_bw(payload, TPhase, TDelay); +} + +tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &bwDelay) +{ + sc_time recTime = bwDelay + sc_time_stamp(); + sc_time notDelay = bwDelay; + + printDebugMessage("[bw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); + + dramPEQ.notify(payload, phase, notDelay); + tlmRecorder->recordPhase(payload, phase, recTime); + + return TLM_ACCEPTED; +} + +void Controller::dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) +{ + Bank bank = DramExtension::getExtension(payload).getBank(); + printDebugMessage("Received " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()) + " from DRAM"); + + if (phase == END_RD || phase == END_WR) + { + sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + } + else if (phase == END_RDA || phase == END_WRA) + { + sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); + scheduleNextFromScheduler(bank); + } + else if (phase == END_REFA) + { + printDebugMessage("Finished auto refresh on all banks "); + + bool sleepy = true; + for(Bank bank : controllerCore->getBanks()) + { + if(numberOfPayloadsInSystem[bank] != 0) + { + sleepy = false; + scheduleNextFromScheduler(bank); + } + } + + if(sleepy == true) + { + controllerCore->powerDownManager->sleep(0,sc_time_stamp()); + } + } + else if(phase == END_REFB) + { + printDebugMessage("Finished auto refresh on bank " + to_string(bank.ID())); + + if(numberOfPayloadsInSystem[bank] == 0) + { + controllerCore->powerDownManager->sleep(bank,sc_time_stamp()); + } + else + { + scheduleNextFromScheduler(bank); + } + scheduleNextFromScheduler(bank); + } + else if (containsPhase(phase, { END_PRE, END_ACT })) + { + scheduleNextFromScheduler(bank); + } + else if(phase == END_PRE_ALL) + { + // No need to trigger anything for a END_PRE_ALL. It is followed by a AUTO_REFRESH anyway (in our current + // scheduler implementation) + } + else + { + string str = string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ") + + phaseNameToString(phase); + SC_REPORT_FATAL(0, str.c_str()); + } +} + +void Controller::sendToDram(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) +{ + tlm_phase TPhase = phase; + sc_time TDelay = delay; + iSocket->nb_transport_fw(payload, TPhase, TDelay); +} + +void Controller::printDebugMessage(string message) +{ + debugManager.printDebugMessage(name(), message); +} + +bool Controller::containsPhase(tlm_phase phase, std::vector phases) +{ + for (tlm_phase p : phases) + { + if (p == phase) + return true; + } + return false; +} + +void Controller::terminateSimulation() +{ + for (Bank bank : controllerCore->getBanks()) + { + controllerCore->powerDownManager->wakeUp(bank, clkAlign(sc_time_stamp())); + } +} + +void Controller::startBandwidthIdleCollector() +{ + printDebugMessage("IDLE Start"); + idleStart = sc_time_stamp(); + endTime = sc_time_stamp(); + idleState = true; +} + +void Controller::endBandwidthIdleCollector() +{ + printDebugMessage("IDLE End"); + idleTime += sc_time_stamp()-idleStart+ Configuration::getInstance().memSpec.clk; + idleState = false; +} + +sc_time Controller::getIdleTime() +{ + printDebugMessage("IDLE Time: "+idleTime.to_string()); + return idleTime; +} + +sc_time Controller::getEndTime() +{ + printDebugMessage("End Time: "+endTime.to_string()); + return endTime; +} + +sc_time Controller::getStartTime() +{ + printDebugMessage("Start Time: "+startTime.to_string()); + return startTime; +} diff --git a/DRAMSys/simulator/src/controller/Controller.h b/DRAMSys/simulator/src/controller/Controller.h index 577e3964..a07a8b74 100644 --- a/DRAMSys/simulator/src/controller/Controller.h +++ b/DRAMSys/simulator/src/controller/Controller.h @@ -72,18 +72,17 @@ using namespace std; using namespace tlm; -template struct Controller: public sc_module, public IController { public: Controller(sc_module_name /*name*/, TlmRecorder *rec) : - frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, &Controller::dramPEQCallback), controllerCorePEQ(this, &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()), tlmRecorder(rec) + frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this, &Controller::dramPEQCallback), controllerCorePEQ(this, &Controller::controllerCorePEQCallback), debugManager(DebugManager::getInstance()), tlmRecorder(rec) { controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem); buildScheduler(); - iSocket.register_nb_transport_bw(this, &Controller::nb_transport_bw); - tSocket.register_nb_transport_fw(this, &Controller::nb_transport_fw); - tSocket.register_transport_dbg(this, &Controller::transport_dbg); + iSocket.register_nb_transport_bw(this, &Controller::nb_transport_bw); + tSocket.register_nb_transport_fw(this, &Controller::nb_transport_fw); + tSocket.register_transport_dbg(this, &Controller::transport_dbg); } ~Controller() @@ -156,511 +155,5 @@ private: }; -// --- IMPLEMENTATION ----- -template -void Controller::buildScheduler() -{ - string selectedScheduler = Configuration::getInstance().Scheduler; - - if (selectedScheduler == "FIFO") - { - scheduler = new Fifo(*controllerCore); - } - else if (selectedScheduler == "FIFO_STRICT") - { - scheduler = new FifoStrict(*this, *controllerCore); - } - else if (selectedScheduler == "FR_FCFS") - { - scheduler = new FR_FCFS(*controllerCore); - } -// else if (selectedScheduler == "PAR_BS") -// { -// scheduler = new PAR_BS(*controllerCore, Configuration::getInstance().RefreshAwareScheduling, -// Configuration::getInstance().Capsize); -// } -// else if (selectedScheduler == "Grouper") -// { -// scheduler = new ReadWriteGrouper(*controllerCore); -// } - else - reportFatal(name(), "unsupported scheduler: " + selectedScheduler); -} - -template -void Controller::send(const ScheduledCommand &command, tlm_generic_payload &payload) -{ - sc_assert(command.getStart() >= sc_time_stamp()); - TimeInterval dataStrobe; - - switch (command.getCommand()) - { - //TODO: refactor tlm recorder - case Command::Read: - dataStrobe = command.getIntervalOnDataStrobe(); - tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerCorePEQ.notify(payload, BEGIN_RD, command.getStart() - sc_time_stamp()); - break; - case Command::ReadA: - dataStrobe = command.getIntervalOnDataStrobe(); - tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerCorePEQ.notify(payload, BEGIN_RDA, command.getStart() - sc_time_stamp()); - break; - case Command::Write: - dataStrobe = command.getIntervalOnDataStrobe(); - tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerCorePEQ.notify(payload, BEGIN_WR, command.getStart() - sc_time_stamp()); - break; - case Command::WriteA: - dataStrobe = command.getIntervalOnDataStrobe(); - tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload); - controllerCorePEQ.notify(payload, BEGIN_WRA, command.getStart() - sc_time_stamp()); - break; - case Command::AutoRefresh: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, BEGIN_REFA, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, BEGIN_REFB, command.getStart() - sc_time_stamp()); - break; - case Command::Activate: - controllerCorePEQ.notify(payload, BEGIN_ACT, command.getStart() - sc_time_stamp()); - break; - case Command::Precharge: - controllerCorePEQ.notify(payload, BEGIN_PRE, command.getStart() - sc_time_stamp()); - break; - case Command::PrechargeAll: - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, BEGIN_PRE_ALL, command.getStart() - sc_time_stamp()); - break; - case Command::PDNA: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, BEGIN_PDNA, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, BEGIN_PDNAB, command.getStart() - sc_time_stamp()); - break; - case Command::PDNAX: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, END_PDNA, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, END_PDNAB, command.getStart() - sc_time_stamp()); - break; - case Command::PDNP: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, BEGIN_PDNP, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, BEGIN_PDNPB, command.getStart() - sc_time_stamp()); - break; - case Command::PDNPX: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, END_PDNP, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, END_PDNPB, command.getStart() - sc_time_stamp()); - break; - case Command::SREF: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, BEGIN_SREF, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, BEGIN_SREFB, command.getStart() - sc_time_stamp()); - break; - case Command::SREFX: - if(!Configuration::getInstance().BankwiseLogic) - { - if(command.getBank() == Bank(0)) - controllerCorePEQ.notify(payload, END_SREF, command.getStart() - sc_time_stamp()); - } - else - controllerCorePEQ.notify(payload, END_SREFB, command.getStart() - sc_time_stamp()); - break; - default: - SC_REPORT_FATAL(0, "unsupported command was sent by controller"); - break; - } -} - -template -void Controller::send(Trigger trigger, sc_time time, tlm_generic_payload &payload) -{ - sc_assert(time >= sc_time_stamp()); - - sc_time delay = time - sc_time_stamp(); - if (trigger == Trigger::REFTrigger) - { - controllerCorePEQ.notify(payload, REF_TRIGGER, delay); - } - else if (trigger == Trigger::PDNTrigger) - { - controllerCorePEQ.notify(payload, PDN_TRIGGER, delay); - } - else - { - SC_REPORT_FATAL("controller wrapper", "unknown trigger"); - } -} - -template -void Controller::controllerCorePEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) -{ - if (phase == REF_TRIGGER) - { - controllerCore->triggerRefresh(payload); - } - else if (phase == PDN_TRIGGER) - { - controllerCore->powerDownManager->sleep(DramExtension::getExtension(payload).getBank(),sc_time_stamp()); - } - else - { - Bank bank = DramExtension::getBank(payload); - sendToDram(payload, phase, SC_ZERO_TIME); - - if (phase == BEGIN_RD || phase == BEGIN_WR) - { - scheduleNextFromScheduler(DramExtension::getBank(payload)); - } - else if (phase == BEGIN_REFB) - printDebugMessage("Entering REFB on bank " + to_string(bank.ID())); - else if (phase == BEGIN_REFA) - printDebugMessage("Entering REFA"); - else if (containsPhase(phase, { BEGIN_PDNAB, BEGIN_PDNPB, BEGIN_SREFB })) - printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); - else if (containsPhase(phase, { END_PDNAB, END_PDNPB, END_SREFB })) - printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on bank " + to_string(bank.ID())); - else if (containsPhase(phase, { BEGIN_PDNA, BEGIN_PDNP, BEGIN_SREF })) - printDebugMessage("Entering PowerDown " + phaseNameToString(phase) + " on all banks"); - else if (containsPhase(phase, { END_PDNA, END_PDNP, END_SREF })) - printDebugMessage("Leaving PowerDown " + phaseNameToString(phase) + " on all banks" ); - else if (containsPhase(phase, { BEGIN_RD, BEGIN_WR, BEGIN_ACT, BEGIN_PRE, BEGIN_PRE_ALL, BEGIN_RDA, BEGIN_WRA })) - { - } - else - SC_REPORT_FATAL(0, "refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase"); - } -} - -template -tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &fwDelay) -{ - sc_time recTime; - sc_time notDelay; - if (phase == BEGIN_REQ) - { - recTime = fwDelay + sc_time_stamp(); - notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) + Configuration::getInstance().memSpec.clk; - - printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); - - tlmRecorder->recordPhase(payload, phase, recTime); - frontendPEQ.notify(payload, phase, notDelay); - - //Bandwidth IDLE - if ((getTotalNumberOfPayloadsInSystem()== 0)&& idleState){ - endBandwidthIdleCollector(); - } - } - else if (phase == END_RESP) - { - recTime = fwDelay + sc_time_stamp() + Configuration::getInstance().memSpec.clk; - notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay); - - printDebugMessage("[fw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); - - // Badnwith IDLE - if (getTotalNumberOfPayloadsInSystem()==1){ - startBandwidthIdleCollector(); - } - - tlmRecorder->recordPhase(payload, phase, recTime); - frontendPEQ.notify(payload, phase, notDelay); - } - return TLM_ACCEPTED; -} - -template -unsigned int Controller::transport_dbg(tlm::tlm_generic_payload& trans) -{ - return iSocket->transport_dbg(trans); -} - -template -void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) -{ - if (phase == BEGIN_REQ) - { - printDebugMessage(string("Payload in system: ") + to_string(getTotalNumberOfPayloadsInSystem())); - payload.acquire(); - payloadEntersSystem(payload); - if (getTotalNumberOfPayloadsInSystem() > controllerCore->config.MaxNrOfTransactions) - { - printDebugMessage("##Backpressure: Max number of transactions in system reached"); - backpressure = &payload; - return; - } - payload.set_response_status(tlm::TLM_OK_RESPONSE); - sendToFrontend(payload, END_REQ, SC_ZERO_TIME); - - scheduler->schedule(&payload); - scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); - } - else if (phase == END_RESP) - { - if (backpressure != NULL) - { - printDebugMessage("##Backpressure released"); - backpressure->set_response_status(tlm::TLM_OK_RESPONSE); - sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME); - - scheduler->schedule(backpressure); - scheduleNextFromScheduler(DramExtension::getExtension(backpressure).getBank()); - backpressure = NULL; - } - - payloadLeavesSystem(payload); - payload.release(); - } - else - { - SC_REPORT_FATAL(0, "Frontend PEQ event queue in controller wrapper was triggered with unknown phase"); - } -} - -template -void Controller::payloadEntersSystem(tlm_generic_payload &payload) -{ - Bank bank = DramExtension::getExtension(payload).getBank(); - printDebugMessage( - "Payload enters system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " - + to_string(getTotalNumberOfPayloadsInSystem())); - numberOfPayloadsInSystem[bank]++; - // Set Start Time for Simulation - if (startTimeSet == false){ - printDebugMessage("Simulation Timer Start"); - startTime = sc_time_stamp()-Configuration::getInstance().memSpec.clk; - startTimeSet = true; - } -} - -template -void Controller::payloadLeavesSystem(tlm_generic_payload &payload) -{ - Bank bank = DramExtension::getExtension(payload).getBank(); - numberOfPayloadsInSystem[bank]--; - printDebugMessage( - "Payload left system on bank " + to_string(bank.ID()) + ". Total number of payloads in Controller: " - + to_string(getTotalNumberOfPayloadsInSystem())); - controllerCore->powerDownManager->triggerSleep(bank, sc_time_stamp()); -} - -template -unsigned int Controller::getTotalNumberOfPayloadsInSystem() -{ - unsigned int sum = 0; - for (Bank bank : controllerCore->getBanks()) - { - sum += numberOfPayloadsInSystem[bank]; - } - return sum; -} - -template -void Controller::scheduleNextFromScheduler(Bank bank) -{ - - if(controllerCore->bankIsBusy(bank)) - { - return; - } - - pair nextRequest = scheduler->getNextRequest(bank); - if(nextRequest.second != NULL) - { - controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp()); - controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); - printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "]"); - } - - while (!blockedRequests.empty()) { - bank = blockedRequests.front(); - blockedRequests.pop(); - - pair nextRequest = scheduler->getNextRequest(bank); - if (nextRequest.second != NULL) { - controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(nextRequest.second).getBank(), sc_time_stamp()); - controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); - printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "] (unblocked)"); - } - } - -} - -template -void Controller::sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) -{ - tlm_phase TPhase = phase; - sc_time TDelay = delay; - tSocket->nb_transport_bw(payload, TPhase, TDelay); -} - -template -tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase, sc_time &bwDelay) -{ - sc_time recTime = bwDelay + sc_time_stamp(); - sc_time notDelay = bwDelay; - - printDebugMessage("[bw] Recording " + phaseNameToString(phase) + " at " + recTime.to_string() + " notification in " + notDelay.to_string()); - - dramPEQ.notify(payload, phase, notDelay); - tlmRecorder->recordPhase(payload, phase, recTime); - - return TLM_ACCEPTED; -} - -template -void Controller::dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase) -{ - Bank bank = DramExtension::getExtension(payload).getBank(); - printDebugMessage("Received " + phaseNameToString(phase) + " on bank " + to_string(bank.ID()) + " from DRAM"); - - if (phase == END_RD || phase == END_WR) - { - sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); - } - else if (phase == END_RDA || phase == END_WRA) - { - sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); - scheduleNextFromScheduler(bank); - } - else if (phase == END_REFA) - { - printDebugMessage("Finished auto refresh on all banks "); - - bool sleepy = true; - for(Bank bank : controllerCore->getBanks()) - { - if(numberOfPayloadsInSystem[bank] != 0) - { - sleepy = false; - scheduleNextFromScheduler(bank); - } - } - - if(sleepy == true) - { - controllerCore->powerDownManager->sleep(0,sc_time_stamp()); - } - } - else if(phase == END_REFB) - { - printDebugMessage("Finished auto refresh on bank " + to_string(bank.ID())); - - if(numberOfPayloadsInSystem[bank] == 0) - { - controllerCore->powerDownManager->sleep(bank,sc_time_stamp()); - } - else - { - scheduleNextFromScheduler(bank); - } - scheduleNextFromScheduler(bank); - } - else if (containsPhase(phase, { END_PRE, END_ACT })) - { - scheduleNextFromScheduler(bank); - } - else if(phase == END_PRE_ALL) - { - // No need to trigger anything for a END_PRE_ALL. It is followed by a AUTO_REFRESH anyway (in our current - // scheduler implementation) - } - else - { - string str = string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ") - + phaseNameToString(phase); - SC_REPORT_FATAL(0, str.c_str()); - } -} - -template -void Controller::sendToDram(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) -{ - tlm_phase TPhase = phase; - sc_time TDelay = delay; - iSocket->nb_transport_fw(payload, TPhase, TDelay); -} - -template -void Controller::printDebugMessage(string message) -{ - debugManager.printDebugMessage(name(), message); -} - -template -bool Controller::containsPhase(tlm_phase phase, std::vector phases) -{ - for (tlm_phase p : phases) - { - if (p == phase) - return true; - } - return false; -} - -template -void Controller::terminateSimulation() -{ - for (Bank bank : controllerCore->getBanks()) - { - controllerCore->powerDownManager->wakeUp(bank, clkAlign(sc_time_stamp())); - } -} - -template -void Controller::startBandwidthIdleCollector(){ - printDebugMessage("IDLE Start"); - idleStart = sc_time_stamp(); - endTime = sc_time_stamp(); - idleState = true; -} - -template -void Controller::endBandwidthIdleCollector(){ - printDebugMessage("IDLE End"); - idleTime += sc_time_stamp()-idleStart+ Configuration::getInstance().memSpec.clk; - idleState = false; -} -template -sc_time Controller::getIdleTime(){ - printDebugMessage("IDLE Time: "+idleTime.to_string()); - return idleTime; -} -template -sc_time Controller::getEndTime(){ - printDebugMessage("End Time: "+endTime.to_string()); - return endTime; -} -template -sc_time Controller::getStartTime(){ - printDebugMessage("Start Time: "+startTime.to_string()); - return startTime; -} - - #endif /* CONTROLLERWRAPPER_H_ */ diff --git a/DRAMSys/simulator/src/simulation/Dram.h b/DRAMSys/simulator/src/simulation/Dram.h index 59ac2513..f02b7ea4 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -88,7 +88,7 @@ struct Dram : sc_module map< unsigned long int, std::array > memory; TlmRecorder *tlmRecorder; - Controller<>* dramController; + Controller *dramController; SC_CTOR(Dram) : tSocket("socket") { @@ -583,7 +583,7 @@ struct Dram : sc_module { tlmRecorder = rec; } - void setDramController(Controller<> *contr) + void setDramController(Controller *contr) { dramController = contr; } diff --git a/DRAMSys/simulator/src/simulation/Simulation.cpp b/DRAMSys/simulator/src/simulation/Simulation.cpp index dae8d5dc..19e863ed 100644 --- a/DRAMSys/simulator/src/simulation/Simulation.cpp +++ b/DRAMSys/simulator/src/simulation/Simulation.cpp @@ -148,7 +148,7 @@ void Simulation::instantiateModules(const string &traceName, const string &pathT for (size_t i = 0; i < Configuration::getInstance().NumberOfMemChannels; i++) { std::string str = "controller" + std::to_string(i); - Controller<> *controller = new Controller<>(str.c_str(), tlmRecorders[i]); + Controller *controller = new Controller(str.c_str(), tlmRecorders[i]); controllers.push_back(controller); str = "dram" + std::to_string(i); diff --git a/DRAMSys/simulator/src/simulation/Simulation.h b/DRAMSys/simulator/src/simulation/Simulation.h index 29d4ae09..96a8abe1 100644 --- a/DRAMSys/simulator/src/simulation/Simulation.h +++ b/DRAMSys/simulator/src/simulation/Simulation.h @@ -100,7 +100,7 @@ private: // All transactions pass through the same arbiter Arbiter *arbiter; // Each DRAM unit has a controller - std::vector *> controllers; + std::vector controllers; // TODO: Each DRAM has a reorder buffer (check this!) ReorderBuffer *reorder; // DRAM units