/* * ControllerWrapper.h * * Created on: Mar 15, 2014 * Author: gernhard */ #ifndef CONTROLLERWRAPPER_H_ #define CONTROLLERWRAPPER_H_ #include #include #include #include #include #include #include #include "common/protocol.h" #include "common/tlmDBPhaseRecorder.h" #include "../core/IWrapperConnector.h" #include "../core/Controller.h" #include "../scheduler/Scheduler.h" #include "../scheduler/Fifo.h" using namespace std; using namespace tlm; using namespace core; using namespace scheduler; template struct ControllerWrapper: public sc_module, public IWrapperConnector { public: tlm_utils::simple_initiator_socket iSocket; tlm_utils::simple_target_socket tSocket; ControllerWrapper(sc_module_name name, tlmDBPhaseRecorder& tpr): frontendPEQ(this, &ControllerWrapper::frontendPEQCallback), dramPEQ( this, &ControllerWrapper::dramPEQCallback), controllerPEQ(this, &ControllerWrapper::controllerPEQCallback), tpr(tpr) { controller = new DramController(*this); scheduler = new Fifo(controller->getBankStates()); inputBufferDelay = controller->config.Timings.clk; iSocket.register_nb_transport_bw(this, &ControllerWrapper::nb_transport_bw); tSocket.register_nb_transport_fw(this, &ControllerWrapper::nb_transport_fw); for(Bank bank:controller->getBankStates().getBanks()) bankIsFreeForRequest[bank] = true; } ~ControllerWrapper() { delete controller; delete scheduler; } virtual void send(const ScheduledCommand& command) override { assert(command.getStart() >= sc_time_stamp()); sc_time delay = command.getStart() - sc_time_stamp(); tlm::tlm_phase phase; switch (command.getCommand()) { case Read: phase = BEGIN_RD; break; case Write: phase = BEGIN_WR; break; case Refresh: phase = BEGIN_REFA; break; case Activate: phase = BEGIN_ACT; break; case Precharge: phase = BEGIN_PRE; break; default: SC_REPORT_FATAL(0, "unsupported command in controller wrapper"); break; } dramPEQ.notify(command.getTransaction(), phase, delay); } virtual void send(Trigger trigger, sc_time time) override { assert(time >= sc_time_stamp()); sc_time delay = time - sc_time_stamp(); controllerPEQ.notify(triggerDummy, REFRESH_TRIGGER, delay); } private: DramController* controller; Scheduler* scheduler; map bankIsFreeForRequest; tlm_utils::peq_with_cb_and_phase frontendPEQ; tlm_utils::peq_with_cb_and_phase dramPEQ; tlm_utils::peq_with_cb_and_phase controllerPEQ; sc_time inputBufferDelay; tlm::tlm_generic_payload triggerDummy; tlmDBPhaseRecorder& tpr; void payloadEntersSystem(tlm_generic_payload& payload) { //std::cout << "----------------------------------------------------------------------- " << std::endl; //std::cout << "Transaction enters system at " << sc_time_stamp() << std::endl; Bank bank = DramExtension::getExtension(payload).getBank(); scheduler->schedule(&payload); scheduleNextPayload(bank); } void scheduleNextPayload(Bank bank) { //std::cout << "----------------------------------------------------------------------- " << std::endl; //std::cout << "In trigger for bank " << bank.ID() << std::endl; if(controller->isBusy(sc_time_stamp(), bank)) return; else if(scheduler->hasTransactionForBank(bank)) { tlm_generic_payload* nextTransaction = scheduler->getTransactionForBank(bank); if(controller->schedule(sc_time_stamp(), *nextTransaction)) { //std::cout << "Next payload was scheduled by core " << std::endl; scheduler->popTransactionForBank(bank); } else { //std::cout << "Next payload was not scheduled because of refresh " << std::endl; } } } void payloadLeavesSystem(tlm_generic_payload& payload) { } // Initiated by dram tlm_sync_enum nb_transport_bw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay) { dramPEQ.notify(payload, phase, bwDelay); return TLM_ACCEPTED; } // Initiated by dram frontend tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay) { DramExtension::getExtension(payload); tpr.recordPhase(payload,phase,sc_time_stamp()); if (phase == BEGIN_REQ) { payload.acquire(); frontendPEQ.notify(payload, phase, inputBufferDelay); } else if (phase == END_RESP) { payloadLeavesSystem(payload); payload.release(); } return TLM_ACCEPTED; } void frontendPEQCallback(tlm_generic_payload& payload, const tlm_phase& phase) { if (phase == BEGIN_REQ) { payloadEntersSystem(payload); payload.set_response_status(tlm::TLM_OK_RESPONSE); tpr.recordPhase(payload, END_REQ, sc_time_stamp()); sendToFrontend(payload, END_REQ, SC_ZERO_TIME); } else { SC_REPORT_FATAL(0, "Frontend PEQ event queue in controller wrapper was triggered with unknown phase"); } } void dramPEQCallback(tlm_generic_payload& payload, const tlm_phase& phase) { tpr.recordPhase(payload,phase,sc_time_stamp()); DramExtension *result = NULL; payload.get_extension(result); if(result==NULL) { cout << "ERROR AT TIME " << sc_time_stamp() << std::endl; cout << "Payload " << payload.get_address() << " " << phase; assert(result != NULL); } if (phase == BEGIN_RD || phase == BEGIN_WR) { //std::cout << "BEGIN_RD at " <getBankStates().getBanks()) scheduleNextPayload(bank); } else if (phase == END_RD || phase == END_WR) { tpr.recordPhase(payload, BEGIN_RESP, sc_time_stamp()); sendToFrontend(payload, BEGIN_RESP, SC_ZERO_TIME); } else if (phase == END_PRE || phase == END_ACT) { } else { SC_REPORT_FATAL(0, "dramPEQCallback queue in controller wrapper was triggered with unknown phase"); } } void controllerPEQCallback(tlm_generic_payload& payload, const tlm_phase& phase) { if (phase == REFRESH_TRIGGER) { controller->scheduleRefresh(sc_time_stamp()); } else { SC_REPORT_FATAL(0, "controllerPEQCallback queue in controller wrapper was triggered with unknown phase"); } } void sendToDram(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay) { DramExtension::getExtension(payload); tlm_phase TPhase = phase; sc_time TDelay = delay; iSocket->nb_transport_fw(payload, TPhase, TDelay); } void 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); } }; #endif /* CONTROLLERWRAPPER_H_ */