diff --git a/.gitignore b/.gitignore index c2403c1b..1912d553 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ DRAMSys/docs/doxygen .vscode cmake-build* .idea +.cache diff --git a/src/configuration/DRAMSys/config/McConfig.cpp b/src/configuration/DRAMSys/config/McConfig.cpp index 04556b78..ff9f479d 100644 --- a/src/configuration/DRAMSys/config/McConfig.cpp +++ b/src/configuration/DRAMSys/config/McConfig.cpp @@ -60,7 +60,9 @@ void to_json(json_t &j, const McConfig &c) {"ThinkDelayFw", c.thinkDelayFw}, {"ThinkDelayBw", c.thinkDelayBw}, {"PhyDelayFw", c.phyDelayFw}, - {"PhyDelayBw", c.phyDelayBw}}; + {"PhyDelayBw", c.phyDelayBw}, + {"BlockingReadDelay", c.blockingReadDelay}, + {"BlockingWriteDelay", c.blockingWriteDelay}}; remove_null_values(j); } @@ -132,6 +134,12 @@ void from_json(const json_t &j, McConfig &c) if (j_mcconfig.contains("PhyDelayBw")) j_mcconfig.at("PhyDelayBw").get_to(c.phyDelayBw); + if (j_mcconfig.contains("BlockingReadDelay")) + j_mcconfig.at("BlockingReadDelay").get_to(c.blockingReadDelay); + + if (j_mcconfig.contains("BlockingWriteDelay")) + j_mcconfig.at("BlockingWriteDelay").get_to(c.blockingWriteDelay); + invalidateEnum(c.pagePolicy); invalidateEnum(c.scheduler); invalidateEnum(c.schedulerBuffer); diff --git a/src/configuration/DRAMSys/config/McConfig.h b/src/configuration/DRAMSys/config/McConfig.h index 16769e4b..da697981 100644 --- a/src/configuration/DRAMSys/config/McConfig.h +++ b/src/configuration/DRAMSys/config/McConfig.h @@ -171,6 +171,8 @@ struct McConfig std::optional thinkDelayBw; std::optional phyDelayFw; std::optional phyDelayBw; + std::optional blockingReadDelay; + std::optional blockingWriteDelay; }; void to_json(json_t &j, const McConfig &c); diff --git a/src/libdramsys/DRAMSys/configuration/Configuration.cpp b/src/libdramsys/DRAMSys/configuration/Configuration.cpp index d7ca08d7..b3ae5fe4 100644 --- a/src/libdramsys/DRAMSys/configuration/Configuration.cpp +++ b/src/libdramsys/DRAMSys/configuration/Configuration.cpp @@ -274,6 +274,16 @@ void Configuration::loadMCConfig(const DRAMSys::Config::McConfig &mcConfig) { phyDelayBw = std::round(sc_time(*_phyDelayBw, SC_NS) / memSpec->tCK) * memSpec->tCK; } + + { + auto _blockingReadDelay = mcConfig.blockingReadDelay.value_or(60); + blockingReadDelay = std::round(sc_time(_blockingReadDelay, SC_NS) / memSpec->tCK) * memSpec->tCK; + } + + { + auto _blockingWriteDelay = mcConfig.blockingWriteDelay.value_or(60); + blockingWriteDelay = std::round(sc_time(_blockingWriteDelay, SC_NS) / memSpec->tCK) * memSpec->tCK; + } } void Configuration::loadMemSpec(const DRAMSys::Config::MemSpec &memSpecConfig) diff --git a/src/libdramsys/DRAMSys/configuration/Configuration.h b/src/libdramsys/DRAMSys/configuration/Configuration.h index 7a4cfc20..f9c7fff0 100644 --- a/src/libdramsys/DRAMSys/configuration/Configuration.h +++ b/src/libdramsys/DRAMSys/configuration/Configuration.h @@ -79,6 +79,8 @@ public: sc_core::sc_time thinkDelayBw = sc_core::SC_ZERO_TIME; sc_core::sc_time phyDelayFw = sc_core::SC_ZERO_TIME; sc_core::sc_time phyDelayBw = sc_core::SC_ZERO_TIME; + sc_core::sc_time blockingReadDelay = sc_core::SC_ZERO_TIME; + sc_core::sc_time blockingWriteDelay = sc_core::SC_ZERO_TIME; // SimConfig std::string simulationName = "default"; diff --git a/src/libdramsys/DRAMSys/controller/Command.h b/src/libdramsys/DRAMSys/controller/Command.h index bbd5437d..75e982f1 100644 --- a/src/libdramsys/DRAMSys/controller/Command.h +++ b/src/libdramsys/DRAMSys/controller/Command.h @@ -147,7 +147,7 @@ public: struct CommandTuple { - using Type = std::tuple<::Command, tlm::tlm_generic_payload *, sc_core::sc_time>; + using Type = std::tuple<::Command, tlm::tlm_generic_payload*, sc_core::sc_time>; enum Accessor { Command = 0, diff --git a/src/libdramsys/DRAMSys/controller/Controller.cpp b/src/libdramsys/DRAMSys/controller/Controller.cpp index 0965809a..2c9689c6 100644 --- a/src/libdramsys/DRAMSys/controller/Controller.cpp +++ b/src/libdramsys/DRAMSys/controller/Controller.cpp @@ -80,6 +80,7 @@ Controller::Controller(const sc_module_name& name, const Configuration& config, ControllerIF(name, config), addressDecoder(addressDecoder), thinkDelayFw(config.thinkDelayFw), thinkDelayBw(config.thinkDelayBw), phyDelayFw(config.phyDelayFw), phyDelayBw(config.phyDelayBw), + blockingReadDelay(config.blockingReadDelay), blockingWriteDelay(config.blockingWriteDelay), minBytesPerBurst(config.memSpec->defaultBytesPerBurst), maxBytesPerBurst(config.memSpec->maxBytesPerBurst) { @@ -302,11 +303,11 @@ void Controller::controllerMethod() { commandTuple = cmdMux->selectCommand(readyCommands); Command command = std::get(commandTuple); - tlm_generic_payload *payload = std::get(commandTuple); + tlm_generic_payload* trans = std::get(commandTuple); if (command != Command::NOP) // can happen with FIFO strict { - Rank rank = ControllerExtension::getRank(*payload); - Bank bank = ControllerExtension::getBank(*payload); + Rank rank = ControllerExtension::getRank(*trans); + Bank bank = ControllerExtension::getBank(*trans); if (command.isRankCommand()) { @@ -329,16 +330,16 @@ void Controller::controllerMethod() refreshManagers[rank.ID()]->updateState(command); powerDownManagers[rank.ID()]->updateState(command); - checker->insert(command, *payload); + checker->insert(command, *trans); if (command.isCasCommand()) { - scheduler->removeRequest(*payload); + scheduler->removeRequest(*trans); manageRequests(thinkDelayFw); - respQueue->insertPayload(payload, sc_time_stamp() - + thinkDelayFw + phyDelayFw - + memSpec.getIntervalOnDataStrobe(command, *payload).end - + phyDelayBw + thinkDelayBw); + respQueue->insertPayload(trans, sc_time_stamp() + + thinkDelayFw + phyDelayFw + + memSpec.getIntervalOnDataStrobe(command, *trans).end + + phyDelayBw + thinkDelayBw); sc_time triggerTime = respQueue->getTriggerTime(); if (triggerTime != sc_max_time()) @@ -351,7 +352,7 @@ void Controller::controllerMethod() sc_time fwDelay = thinkDelayFw + phyDelayFw; tlm_phase phase = command.toPhase(); - iSocket->nb_transport_fw(*payload, phase, fwDelay); + iSocket->nb_transport_fw(*trans, phase, fwDelay); } else readyCmdBlocked = true; @@ -383,18 +384,17 @@ void Controller::controllerMethod() controllerEvent.notify(timeForNextTrigger - sc_time_stamp()); } -tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &trans, - tlm_phase &phase, sc_time &delay) +tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload& trans, tlm_phase& phase, sc_time& delay) { if (phase == BEGIN_REQ) { transToAcquire.payload = &trans; - transToAcquire.time = sc_time_stamp() + delay; + transToAcquire.arrival = sc_time_stamp() + delay; beginReqEvent.notify(delay); } else if (phase == END_RESP) { - transToRelease.time = sc_time_stamp() + delay; + transToRelease.arrival = sc_time_stamp() + delay; endRespEvent.notify(delay); } else @@ -406,21 +406,26 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &trans, return TLM_ACCEPTED; } -tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &, - tlm_phase &, sc_time &) +tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload& ,tlm_phase& , sc_time&) { SC_REPORT_FATAL("Controller", "nb_transport_bw of controller must not be called!"); return TLM_ACCEPTED; } -unsigned int Controller::transport_dbg(tlm_generic_payload &trans) +void Controller::b_transport(tlm_generic_payload& trans, sc_time& delay) +{ + iSocket->b_transport(trans, delay); + delay += trans.is_write() ? blockingWriteDelay : blockingReadDelay; +} + +unsigned int Controller::transport_dbg(tlm_generic_payload& trans) { return iSocket->transport_dbg(trans); } -void Controller::manageRequests(const sc_time &delay) +void Controller::manageRequests(const sc_time& delay) { - if (transToAcquire.payload != nullptr && transToAcquire.time <= sc_time_stamp()) + if (transToAcquire.payload != nullptr && transToAcquire.arrival <= sc_time_stamp()) { // TODO: here we assume that the scheduler always has space not only for a single burst transaction // but for a maximum size transaction @@ -492,8 +497,8 @@ void Controller::manageResponses() { if (transToRelease.payload != nullptr) { - assert(transToRelease.time >= sc_time_stamp()); - if (transToRelease.time == sc_time_stamp()) // END_RESP completed + assert(transToRelease.arrival >= sc_time_stamp()); + if (transToRelease.arrival == sc_time_stamp()) // END_RESP completed { transToRelease.payload->release(); transToRelease.payload = nullptr; @@ -508,25 +513,25 @@ void Controller::manageResponses() return; // END_RESP not completed } - tlm_generic_payload* nextPayloadInRespQueue = respQueue->nextPayload(); - if (nextPayloadInRespQueue != nullptr) + tlm_generic_payload* nextTransInRespQueue = respQueue->nextPayload(); + if (nextTransInRespQueue != nullptr) { - numberOfBeatsServed += ControllerExtension::getBurstLength(*nextPayloadInRespQueue); - if (ChildExtension::isChildTrans(*nextPayloadInRespQueue)) + numberOfBeatsServed += ControllerExtension::getBurstLength(*nextTransInRespQueue); + if (ChildExtension::isChildTrans(*nextTransInRespQueue)) { - tlm_generic_payload& parentTrans = ChildExtension::getParentTrans(*nextPayloadInRespQueue); + tlm_generic_payload& parentTrans = ChildExtension::getParentTrans(*nextTransInRespQueue); if (ParentExtension::notifyChildTransCompletion(parentTrans)) { transToRelease.payload = &parentTrans; tlm_phase bwPhase = BEGIN_RESP; sc_time bwDelay; - if (transToRelease.time == sc_time_stamp()) // last payload was released in this cycle + if (transToRelease.arrival == sc_time_stamp()) // last payload was released in this cycle bwDelay = memSpec.tCK; else bwDelay = SC_ZERO_TIME; sendToFrontend(*transToRelease.payload, bwPhase, bwDelay); - transToRelease.time = sc_max_time(); + transToRelease.arrival = sc_max_time(); } else { @@ -537,16 +542,16 @@ void Controller::manageResponses() } else { - transToRelease.payload = nextPayloadInRespQueue; + transToRelease.payload = nextTransInRespQueue; tlm_phase bwPhase = BEGIN_RESP; sc_time bwDelay; - if (transToRelease.time == sc_time_stamp()) // last payload was released in this cycle + if (transToRelease.arrival == sc_time_stamp()) // last payload was released in this cycle bwDelay = memSpec.tCK; else bwDelay = SC_ZERO_TIME; sendToFrontend(*transToRelease.payload, bwPhase, bwDelay); - transToRelease.time = sc_max_time(); + transToRelease.arrival = sc_max_time(); } } else @@ -557,19 +562,19 @@ void Controller::manageResponses() } } -void Controller::sendToFrontend(tlm_generic_payload& payload, tlm_phase& phase, sc_time& delay) +void Controller::sendToFrontend(tlm_generic_payload& trans, tlm_phase& phase, sc_time& delay) { - tSocket->nb_transport_bw(payload, phase, delay); + tSocket->nb_transport_bw(trans, phase, delay); } Controller::MemoryManager::~MemoryManager() { while (!freePayloads.empty()) { - tlm_generic_payload* payload = freePayloads.top(); + tlm_generic_payload* trans = freePayloads.top(); freePayloads.pop(); - payload->reset(); - delete payload; + trans->reset(); + delete trans; } } @@ -588,9 +593,9 @@ tlm::tlm_generic_payload& Controller::MemoryManager::allocate() } } -void Controller::MemoryManager::free(tlm::tlm_generic_payload* payload) +void Controller::MemoryManager::free(tlm::tlm_generic_payload* trans) { - freePayloads.push(payload); + freePayloads.push(trans); } void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans) diff --git a/src/libdramsys/DRAMSys/controller/Controller.h b/src/libdramsys/DRAMSys/controller/Controller.h index 5154102e..b8e190d7 100644 --- a/src/libdramsys/DRAMSys/controller/Controller.h +++ b/src/libdramsys/DRAMSys/controller/Controller.h @@ -61,6 +61,7 @@ protected: sc_core::sc_time& delay) override; tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) override; + void b_transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) override; unsigned int transport_dbg(tlm::tlm_generic_payload& trans) override; virtual void sendToFrontend(tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay); @@ -73,6 +74,8 @@ protected: const sc_core::sc_time thinkDelayBw; const sc_core::sc_time phyDelayFw; const sc_core::sc_time phyDelayBw; + const sc_core::sc_time blockingReadDelay; + const sc_core::sc_time blockingWriteDelay; private: unsigned totalNumberOfPayloads = 0; @@ -90,10 +93,10 @@ private: const AddressDecoder& addressDecoder; uint64_t nextChannelPayloadIDToAppend = 1; - struct Transaction + struct PayloadAndArrival { tlm::tlm_generic_payload* payload = nullptr; - sc_core::sc_time time = sc_core::sc_max_time(); + sc_core::sc_time arrival = sc_core::sc_max_time(); } transToAcquire, transToRelease; void manageResponses(); @@ -113,7 +116,7 @@ private: public: ~MemoryManager() override; tlm::tlm_generic_payload& allocate(); - void free(tlm::tlm_generic_payload* payload) override; + void free(tlm::tlm_generic_payload* trans) override; private: std::stack freePayloads; diff --git a/src/libdramsys/DRAMSys/controller/ControllerIF.h b/src/libdramsys/DRAMSys/controller/ControllerIF.h index cc80c655..920c581d 100644 --- a/src/libdramsys/DRAMSys/controller/ControllerIF.h +++ b/src/libdramsys/DRAMSys/controller/ControllerIF.h @@ -111,6 +111,7 @@ protected: { tSocket.register_nb_transport_fw(this, &ControllerIF::nb_transport_fw); tSocket.register_transport_dbg(this, &ControllerIF::transport_dbg); + tSocket.register_b_transport(this, &ControllerIF::b_transport); iSocket.register_nb_transport_bw(this, &ControllerIF::nb_transport_bw); idleTimeCollector.start(); @@ -120,9 +121,10 @@ protected: // Virtual transport functions virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) = 0; - virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans) = 0; virtual tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) = 0; + virtual void b_transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) = 0; + virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans) = 0; // Bandwidth related class IdleTimeCollector diff --git a/src/libdramsys/DRAMSys/simulation/Arbiter.cpp b/src/libdramsys/DRAMSys/simulation/Arbiter.cpp index 6e56b92c..ac6a060a 100644 --- a/src/libdramsys/DRAMSys/simulation/Arbiter.cpp +++ b/src/libdramsys/DRAMSys/simulation/Arbiter.cpp @@ -59,6 +59,7 @@ Arbiter::Arbiter(const sc_module_name& name, const Configuration& config, { iSocket.register_nb_transport_bw(this, &Arbiter::nb_transport_bw); tSocket.register_nb_transport_fw(this, &Arbiter::nb_transport_fw); + tSocket.register_b_transport(this, &Arbiter::b_transport); tSocket.register_transport_dbg(this, &Arbiter::transport_dbg); } @@ -161,6 +162,14 @@ tlm_sync_enum Arbiter::nb_transport_bw(int, tlm_generic_payload& payload, return TLM_ACCEPTED; } +void Arbiter::b_transport(int, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) +{ + trans.set_address(trans.get_address() - addressOffset); + + DecodedAddress decodedAddress = addressDecoder.decodeAddress(trans.get_address()); + iSocket[static_cast(decodedAddress.channel)]->b_transport(trans, delay); +} + unsigned int Arbiter::transport_dbg(int /*id*/, tlm::tlm_generic_payload& trans) { trans.set_address(trans.get_address() - addressOffset); diff --git a/src/libdramsys/DRAMSys/simulation/Arbiter.h b/src/libdramsys/DRAMSys/simulation/Arbiter.h index 7865eff6..a8eaef59 100644 --- a/src/libdramsys/DRAMSys/simulation/Arbiter.h +++ b/src/libdramsys/DRAMSys/simulation/Arbiter.h @@ -86,6 +86,7 @@ protected: tlm::tlm_phase& phase, sc_core::sc_time& fwDelay); tlm::tlm_sync_enum nb_transport_bw(int, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& bwDelay); + void b_transport(int, tlm::tlm_generic_payload& trans, sc_core::sc_time& delay); unsigned int transport_dbg(int /*id*/, tlm::tlm_generic_payload& trans); const sc_core::sc_time tCK; diff --git a/src/libdramsys/DRAMSys/simulation/DRAMSys.cpp b/src/libdramsys/DRAMSys/simulation/DRAMSys.cpp index 0a1e92d5..7d02beab 100644 --- a/src/libdramsys/DRAMSys/simulation/DRAMSys.cpp +++ b/src/libdramsys/DRAMSys/simulation/DRAMSys.cpp @@ -103,7 +103,7 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name& name, } } -const Configuration& DRAMSys::getConfig() +const Configuration& DRAMSys::getConfig() const { return config; } diff --git a/src/libdramsys/DRAMSys/simulation/DRAMSys.h b/src/libdramsys/DRAMSys/simulation/DRAMSys.h index 94ca9388..cec3a6d9 100644 --- a/src/libdramsys/DRAMSys/simulation/DRAMSys.h +++ b/src/libdramsys/DRAMSys/simulation/DRAMSys.h @@ -69,7 +69,7 @@ public: DRAMSys(const sc_core::sc_module_name& name, const ::DRAMSys::Config::Configuration& configLib); - const Configuration& getConfig(); + const Configuration& getConfig() const; protected: DRAMSys(const sc_core::sc_module_name& name, diff --git a/src/libdramsys/DRAMSys/simulation/dram/Dram.cpp b/src/libdramsys/DRAMSys/simulation/dram/Dram.cpp index 315c2b3e..dea6203f 100644 --- a/src/libdramsys/DRAMSys/simulation/dram/Dram.cpp +++ b/src/libdramsys/DRAMSys/simulation/dram/Dram.cpp @@ -35,6 +35,7 @@ * Peter Ehses * Eder F. Zulian * Felipe S. Prado + * Derek Christ */ #include "Dram.h" @@ -82,12 +83,14 @@ Dram::Dram(const sc_module_name& name, const Configuration& config) SC_REPORT_FATAL("Dram", "On Windows Storage is not yet supported"); memory = 0; // FIXME #else - memory = (unsigned char *)mmap(nullptr, channelSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); + memory = (unsigned char *)mmap(nullptr, channelSize, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); #endif } } tSocket.register_nb_transport_fw(this, &Dram::nb_transport_fw); + tSocket.register_b_transport(this, &Dram::b_transport); tSocket.register_transport_dbg(this, &Dram::transport_dbg); } @@ -119,15 +122,14 @@ void Dram::reportPower() #endif } -tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload, - tlm_phase &phase, sc_time &delay) +tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload& trans, tlm_phase& phase, sc_time& delay) { assert(phase >= BEGIN_RD && phase <= END_SREF); #ifdef DRAMPOWER if (powerAnalysis) { - int bank = static_cast(ControllerExtension::getBank(payload).ID()); + int bank = static_cast(ControllerExtension::getBank(trans).ID()); int64_t cycle = std::lround((sc_time_stamp() + delay) / memSpec.tCK); DRAMPower->doCommand(phaseToDRAMPowerCommand(phase), bank, cycle); } @@ -137,44 +139,39 @@ tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload, { if (phase == BEGIN_RD || phase == BEGIN_RDA) { - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(payload.get_data_ptr(), phyAddr, payload.get_data_length()); + unsigned char* phyAddr = memory + trans.get_address(); + memcpy(trans.get_data_ptr(), phyAddr, trans.get_data_length()); } else if (phase == BEGIN_WR || phase == BEGIN_WRA) { - unsigned char *phyAddr = memory + payload.get_address(); - memcpy(phyAddr, payload.get_data_ptr(), payload.get_data_length()); + unsigned char* phyAddr = memory + trans.get_address(); + memcpy(phyAddr, trans.get_data_ptr(), trans.get_data_length()); } } return TLM_ACCEPTED; } -unsigned int Dram::transport_dbg(tlm_generic_payload &trans) +unsigned int Dram::transport_dbg(tlm_generic_payload& trans) { PRINTDEBUGMESSAGE(name(), "transport_dgb"); // TODO: This part is not tested yet, neither with traceplayers nor with GEM5 coupling if (storeMode == Configuration::StoreMode::NoStorage) { - SC_REPORT_FATAL("DRAM", - "Debug Transport is used in combination with NoStorage"); + SC_REPORT_FATAL("DRAM", "Debug Transport is used in combination with NoStorage"); } else { tlm_command cmd = trans.get_command(); - //uint64_t adr = trans.get_address(); // TODO: - offset; - unsigned char *ptr = trans.get_data_ptr(); - unsigned int len = trans.get_data_length(); - //unsigned int bank = DramExtension::getExtension(trans).getBank().ID(); - - //cout << "cmd " << (cmd ? "write" : "read") << " adr " << hex << adr << " len " << len << endl; + unsigned char* ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); if (cmd == TLM_READ_COMMAND) { if (storeMode == Configuration::StoreMode::Store) - { // Use Storage - unsigned char *phyAddr = memory + trans.get_address(); + { + unsigned char* phyAddr = memory + trans.get_address(); memcpy(ptr, phyAddr, trans.get_data_length()); } else @@ -186,8 +183,8 @@ unsigned int Dram::transport_dbg(tlm_generic_payload &trans) else if (cmd == TLM_WRITE_COMMAND) { if (storeMode == Configuration::StoreMode::Store) - { // Use Storage - unsigned char *phyAddr = memory + trans.get_address(); + { + unsigned char* phyAddr = memory + trans.get_address(); memcpy(phyAddr, ptr, trans.get_data_length()); } else @@ -200,3 +197,32 @@ unsigned int Dram::transport_dbg(tlm_generic_payload &trans) } return 0; } + +void Dram::b_transport(tlm_generic_payload& trans, sc_time& delay) +{ + static bool printedWarning = false; + + if (!printedWarning) + { + SC_REPORT_WARNING("DRAM", BLOCKING_WARNING.data()); + printedWarning = true; + } + + if (storeMode == Configuration::StoreMode::Store) + { + if (trans.is_read()) + { + unsigned char* phyAddr = memory + trans.get_address(); + memcpy(trans.get_data_ptr(), phyAddr, trans.get_data_length()); + } + else + { + unsigned char* phyAddr = memory + trans.get_address(); + memcpy(phyAddr, trans.get_data_ptr(), trans.get_data_length()); + } + } + else if (storeMode != Configuration::StoreMode::NoStorage) + { + SC_REPORT_FATAL("DRAM", "Blocking transport not supported with error model yet."); + } +} diff --git a/src/libdramsys/DRAMSys/simulation/dram/Dram.h b/src/libdramsys/DRAMSys/simulation/dram/Dram.h index f9b339ce..e30872db 100644 --- a/src/libdramsys/DRAMSys/simulation/dram/Dram.h +++ b/src/libdramsys/DRAMSys/simulation/dram/Dram.h @@ -35,6 +35,7 @@ * Peter Ehses * Eder F. Zulian * Felipe S. Prado + * Derek Christ */ #ifndef DRAM_H @@ -68,12 +69,16 @@ protected: std::unique_ptr DRAMPower; #endif - virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload& payload, + virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay); - + virtual void b_transport(tlm::tlm_generic_payload& trans, sc_core::sc_time& delay); virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans); public: + static constexpr std::string_view BLOCKING_WARNING = + "Use the blocking mode of DRAMSys with caution! " + "The simulated timings do not reflect the real system!"; + tlm_utils::simple_target_socket tSocket; virtual void reportPower(); diff --git a/tests/tests_dramsys/CMakeLists.txt b/tests/tests_dramsys/CMakeLists.txt index b200fcc9..c60c83e7 100644 --- a/tests/tests_dramsys/CMakeLists.txt +++ b/tests/tests_dramsys/CMakeLists.txt @@ -19,6 +19,8 @@ target_link_libraries(${PROJECT_NAME} gtest_main ) -gtest_discover_tests(${PROJECT_NAME}) +gtest_discover_tests(${PROJECT_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) build_source_group() \ No newline at end of file diff --git a/tests/tests_dramsys/b_transport/b_transport.cpp b/tests/tests_dramsys/b_transport/b_transport.cpp new file mode 100644 index 00000000..9fde8579 --- /dev/null +++ b/tests/tests_dramsys/b_transport/b_transport.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023, Technische Universität 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: + * Derek Christ + */ + +#include + +#include +#include + +class SystemCTest : public testing::Test +{ +public: + ~SystemCTest() override { sc_core::sc_get_curr_simcontext()->reset(); } +}; + +class BTransportNoStorage : public SystemCTest +{ +protected: + BTransportNoStorage() + : no_storage_config(DRAMSys::Config::from_path("b_transport/configs/no_storage.json")), + dramSysNoStorage("NoStorageDRAMSys", no_storage_config) + { + } + + DRAMSys::Config::Configuration no_storage_config; + DRAMSys::DRAMSys dramSysNoStorage; +}; + +class BTransportStorage : public SystemCTest +{ +protected: + BTransportStorage() + : storage_config(DRAMSys::Config::from_path("b_transport/configs/storage.json")), + dramSysStorage("StorageDRAMSys", storage_config) + { + } + + DRAMSys::Config::Configuration storage_config; + DRAMSys::DRAMSys dramSysStorage; +}; + +struct BlockingInitiator : sc_core::sc_module +{ + tlm_utils::simple_initiator_socket iSocket; + static constexpr std::array TEST_DATA = {0xDEADBEEF}; + DRAMSys::DRAMSys const &dramSys; + + BlockingInitiator(sc_core::sc_module_name const &name, DRAMSys::DRAMSys const &dramSys) + : sc_core::sc_module(name), dramSys(dramSys) + { + SC_THREAD(readAccess); + SC_THREAD(writeAccess); + } + SC_HAS_PROCESS(BlockingInitiator); + + void readAccess() + { + tlm::tlm_generic_payload payload; + payload.set_command(tlm::TLM_READ_COMMAND); + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + iSocket->b_transport(payload, delay); + + EXPECT_EQ(delay, dramSys.getConfig().blockingReadDelay); + } + + void writeAccess() + { + std::array data{TEST_DATA}; + tlm::tlm_generic_payload payload; + payload.set_command(tlm::TLM_WRITE_COMMAND); + payload.set_data_length(64); + payload.set_data_ptr(reinterpret_cast(&data)); + sc_core::sc_time delay = sc_core::SC_ZERO_TIME; + iSocket->b_transport(payload, delay); + + EXPECT_EQ(delay, dramSys.getConfig().blockingWriteDelay); + } +}; + +TEST_F(BTransportNoStorage, RWDelay) +{ + BlockingInitiator initiator("initiator", dramSysNoStorage); + initiator.iSocket.bind(dramSysNoStorage.tSocket); + + sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_US)); +} + +TEST_F(BTransportStorage, RWDelay) +{ + BlockingInitiator initiator("initiator", dramSysStorage); + initiator.iSocket.bind(dramSysStorage.tSocket); + + sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_US)); +} + +TEST_F(BTransportStorage, DataWritten) +{ + BlockingInitiator initiator("initiator", dramSysStorage); + initiator.iSocket.bind(dramSysStorage.tSocket); + + sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_US)); + + // Debug transaction to check if data really has been written + std::array data{}; + tlm::tlm_generic_payload payload; + payload.set_command(tlm::TLM_READ_COMMAND); + payload.set_data_length(64); + payload.set_data_ptr(reinterpret_cast(&data)); + initiator.iSocket->transport_dbg(payload); + + EXPECT_EQ(data, BlockingInitiator::TEST_DATA); +} + +TEST_F(BTransportNoStorage, Warning) +{ + BlockingInitiator initiator("initiator", dramSysNoStorage); + initiator.iSocket.bind(dramSysNoStorage.tSocket); + + // Redirect stdout to buffer + std::stringstream buffer; + std::streambuf *sbuf = std::cout.rdbuf(); + std::cout.rdbuf(buffer.rdbuf()); + + sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_US)); + + // Try to find the warning string + std::string output = buffer.str(); + auto warning_pos = output.find(Dram::BLOCKING_WARNING); + + // Warning should be printed once ... + EXPECT_NE(warning_pos, std::string::npos); + + // ... but not twice + warning_pos = output.find(Dram::BLOCKING_WARNING, warning_pos + 1); + EXPECT_EQ(warning_pos, std::string::npos); + + // Restore stdout + std::cout.rdbuf(sbuf); +} diff --git a/tests/tests_dramsys/b_transport/configs/no_storage.json b/tests/tests_dramsys/b_transport/configs/no_storage.json new file mode 100644 index 00000000..c2950e40 --- /dev/null +++ b/tests/tests_dramsys/b_transport/configs/no_storage.json @@ -0,0 +1,155 @@ +{ + "simulation": { + "addressmapping": { + "CONGEN": { + "BANKGROUP_BIT": [ + 28, + 29 + ], + "BANK_BIT": [ + 30, + 31 + ], + "BYTE_BIT": [ + 0, + 1, + 2 + ], + "COLUMN_BIT": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ], + "ROW_BIT": [ + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27 + ] + } + }, + "mcconfig": { + "Arbiter": "Simple", + "CmdMux": "Oldest", + "MaxActiveTransactions": 128, + "PagePolicy": "Open", + "PowerDownPolicy": "NoPowerDown", + "RefreshManagement": false, + "RefreshMaxPostponed": 0, + "RefreshMaxPulledin": 0, + "RefreshPolicy": "AllBank", + "RequestBufferSize": 8, + "RespQueue": "Fifo", + "Scheduler": "FrFcfs", + "SchedulerBuffer": "Bankwise", + "BlockingReadDelay": 80, + "BlockingWriteDelay": 100 + }, + "memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 16, + "nbrOfChannels": 1, + "nbrOfColumns": 1024, + "nbrOfDevices": 8, + "nbrOfRanks": 1, + "nbrOfRows": 32768, + "width": 8 + }, + "memoryId": "MICRON_4Gb_DDR4-1866_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "idd0": 56.25, + "idd02": 4.05, + "idd2n": 33.75, + "idd2p0": 17.0, + "idd2p1": 17.0, + "idd3n": 39.5, + "idd3p0": 22.5, + "idd3p1": 22.5, + "idd4r": 157.5, + "idd4w": 135.0, + "idd5": 118.0, + "idd6": 20.25, + "idd62": 2.6, + "vdd": 1.2, + "vdd2": 2.5 + }, + "memtimingspec": { + "ACTPDEN": 1, + "AL": 0, + "CCD_L": 5, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 13, + "DQSCK": 2, + "FAW": 22, + "PRPDEN": 1, + "RAS": 32, + "RC": 45, + "RCD": 13, + "REFI": 7280, + "REFM": 1, + "REFPDEN": 1, + "RFC": 243, + "RFC2": 150, + "RFC4": 103, + "RL": 13, + "RP": 13, + "RPRE": 1, + "RRD_L": 5, + "RRD_S": 4, + "RTP": 8, + "RTRS": 1, + "WL": 12, + "WPRE": 1, + "WR": 14, + "WTR_L": 7, + "WTR_S": 3, + "XP": 8, + "XPDLL": 255, + "XS": 252, + "XSDLL": 512, + "clkMhz": 933 + } + }, + "simconfig": { + "AddressOffset": 0, + "CheckTLM2Protocol": false, + "DatabaseRecording": true, + "Debug": false, + "EnableWindowing": false, + "ErrorCSVFile": "", + "ErrorChipSeed": 42, + "PowerAnalysis": false, + "SimulationName": "example", + "SimulationProgressBar": true, + "StoreMode": "NoStorage", + "ThermalSimulation": false, + "UseMalloc": false, + "WindowSize": 1000 + }, + "simulationid": "ddr4-example" + } +} \ No newline at end of file diff --git a/tests/tests_dramsys/b_transport/configs/storage.json b/tests/tests_dramsys/b_transport/configs/storage.json new file mode 100644 index 00000000..3535eaeb --- /dev/null +++ b/tests/tests_dramsys/b_transport/configs/storage.json @@ -0,0 +1,153 @@ +{ + "simulation": { + "addressmapping": { + "CONGEN": { + "BANKGROUP_BIT": [ + 28, + 29 + ], + "BANK_BIT": [ + 30, + 31 + ], + "BYTE_BIT": [ + 0, + 1, + 2 + ], + "COLUMN_BIT": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12 + ], + "ROW_BIT": [ + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27 + ] + } + }, + "mcconfig": { + "Arbiter": "Simple", + "CmdMux": "Oldest", + "MaxActiveTransactions": 128, + "PagePolicy": "Open", + "PowerDownPolicy": "NoPowerDown", + "RefreshManagement": false, + "RefreshMaxPostponed": 0, + "RefreshMaxPulledin": 0, + "RefreshPolicy": "AllBank", + "RequestBufferSize": 8, + "RespQueue": "Fifo", + "Scheduler": "FrFcfs", + "SchedulerBuffer": "Bankwise" + }, + "memspec": { + "memarchitecturespec": { + "burstLength": 8, + "dataRate": 2, + "nbrOfBankGroups": 4, + "nbrOfBanks": 16, + "nbrOfChannels": 1, + "nbrOfColumns": 1024, + "nbrOfDevices": 8, + "nbrOfRanks": 1, + "nbrOfRows": 32768, + "width": 8 + }, + "memoryId": "MICRON_4Gb_DDR4-1866_8bit_A", + "memoryType": "DDR4", + "mempowerspec": { + "idd0": 56.25, + "idd02": 4.05, + "idd2n": 33.75, + "idd2p0": 17.0, + "idd2p1": 17.0, + "idd3n": 39.5, + "idd3p0": 22.5, + "idd3p1": 22.5, + "idd4r": 157.5, + "idd4w": 135.0, + "idd5": 118.0, + "idd6": 20.25, + "idd62": 2.6, + "vdd": 1.2, + "vdd2": 2.5 + }, + "memtimingspec": { + "ACTPDEN": 1, + "AL": 0, + "CCD_L": 5, + "CCD_S": 4, + "CKE": 6, + "CKESR": 7, + "CL": 13, + "DQSCK": 2, + "FAW": 22, + "PRPDEN": 1, + "RAS": 32, + "RC": 45, + "RCD": 13, + "REFI": 7280, + "REFM": 1, + "REFPDEN": 1, + "RFC": 243, + "RFC2": 150, + "RFC4": 103, + "RL": 13, + "RP": 13, + "RPRE": 1, + "RRD_L": 5, + "RRD_S": 4, + "RTP": 8, + "RTRS": 1, + "WL": 12, + "WPRE": 1, + "WR": 14, + "WTR_L": 7, + "WTR_S": 3, + "XP": 8, + "XPDLL": 255, + "XS": 252, + "XSDLL": 512, + "clkMhz": 933 + } + }, + "simconfig": { + "AddressOffset": 0, + "CheckTLM2Protocol": false, + "DatabaseRecording": true, + "Debug": false, + "EnableWindowing": false, + "ErrorCSVFile": "", + "ErrorChipSeed": 42, + "PowerAnalysis": false, + "SimulationName": "example", + "SimulationProgressBar": true, + "StoreMode": "Store", + "ThermalSimulation": false, + "UseMalloc": false, + "WindowSize": 1000 + }, + "simulationid": "ddr4-example" + } +} \ No newline at end of file