diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index 588587ff..3417ca2b 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -232,24 +232,14 @@ Controller::~Controller() void Controller::controllerMethod() { - // clear command buffer - readyCommands.clear(); - // (1) Release payload if arbiter has accepted the result (finish END_RESP) - if (payloadToRelease != nullptr && timeToRelease <= sc_time_stamp()) - finishEndResp(); + finishEndResp(); // (2) Send next result to arbiter (start BEGIN_RESP) - if (payloadToRelease == nullptr) - startBeginResp(); + startBeginResp(); // (3) Insert new request from arbiter into scheduler and restart appropriate BM (finish BEGIN_REQ) - if (payloadToAcquire != nullptr && timeToAcquire <= sc_time_stamp()) - { - unsigned bankID = DramExtension::getBank(payloadToAcquire).ID(); - finishBeginReq(); - bankMachines[bankID]->start(); - } + finishBeginReq(); // (4) Start refresh and power-down managers to issue requests for the current time for (auto it : refreshManagers) @@ -257,8 +247,10 @@ void Controller::controllerMethod() for (auto it : powerDownManagers) it->start(); - // (5) Choose one request and send it to DRAM + // (5) Collect all ready commands from BMs, RMs and PDMs CommandTuple::Type commandTuple; + // clear command buffer + readyCommands.clear(); for (unsigned rankID = 0; rankID < memSpec->numberOfRanks; rankID++) { @@ -283,6 +275,7 @@ void Controller::controllerMethod() } } + // (6) Select one of the ready commands and issue it to the DRAM bool readyCmdBlocked = false; if (!readyCommands.empty()) { @@ -333,12 +326,10 @@ void Controller::controllerMethod() readyCmdBlocked = true; } - // (6) Accept request from arbiter if scheduler is not full, otherwise backpressure (start END_REQ) - if (payloadToAcquire != nullptr && timeToAcquire == sc_max_time()) - startEndReq(); + // (7) Accept request from arbiter if scheduler is not full, otherwise backpressure (start END_REQ) + startEndReq(); - // (7) Restart bank machines, refresh managers and power-down managers to issue new requests for the future - // TODO: check if all calls are necessary + // (8) Restart bank machines, refresh managers and power-down managers to issue new requests for the future sc_time timeForNextTrigger = sc_max_time(); for (auto it : bankMachines) { @@ -362,13 +353,13 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &trans, if (phase == BEGIN_REQ) { - payloadToAcquire = &trans; - timeToAcquire = sc_time_stamp() + notificationDelay; + transToAcquire.payload = &trans; + transToAcquire.time = sc_time_stamp() + notificationDelay; beginReqEvent.notify(notificationDelay); } else if (phase == END_RESP) { - timeToRelease = sc_time_stamp() + notificationDelay; + transToRelease.time = sc_time_stamp() + notificationDelay; endRespEvent.notify(notificationDelay); } else @@ -394,63 +385,80 @@ unsigned int Controller::transport_dbg(tlm_generic_payload &trans) void Controller::finishBeginReq() { - NDEBUG_UNUSED(uint64_t id) = DramExtension::getPayloadID(payloadToAcquire); - PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " entered system."); + if (transToAcquire.payload != nullptr && transToAcquire.time <= sc_time_stamp()) + { + NDEBUG_UNUSED(uint64_t id) = DramExtension::getPayloadID(transToAcquire.payload); + PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " entered system."); - if (totalNumberOfPayloads == 0) - idleTimeCollector.end(); - totalNumberOfPayloads++; + if (totalNumberOfPayloads == 0) + idleTimeCollector.end(); + totalNumberOfPayloads++; - Rank rank = DramExtension::getRank(payloadToAcquire); - if (ranksNumberOfPayloads[rank.ID()] == 0) - powerDownManagers[rank.ID()]->triggerExit(); + Rank rank = DramExtension::getRank(transToAcquire.payload); + if (ranksNumberOfPayloads[rank.ID()] == 0) + powerDownManagers[rank.ID()]->triggerExit(); - ranksNumberOfPayloads[rank.ID()]++; + ranksNumberOfPayloads[rank.ID()]++; - scheduler->storeRequest(payloadToAcquire); - payloadToAcquire->acquire(); - timeToAcquire = sc_max_time(); + scheduler->storeRequest(transToAcquire.payload); + transToAcquire.payload->acquire(); + transToAcquire.time = sc_max_time(); + + Bank bank = DramExtension::getBank(transToAcquire.payload); + bankMachines[bank.ID()]->start(); + } } void Controller::startEndReq() { - if (scheduler->hasBufferSpace()) + if (transToAcquire.payload != nullptr && transToAcquire.time == sc_max_time()) { - payloadToAcquire->set_response_status(TLM_OK_RESPONSE); - sendToFrontend(payloadToAcquire, END_REQ); - payloadToAcquire = nullptr; + if (scheduler->hasBufferSpace()) + { + transToAcquire.payload->set_response_status(TLM_OK_RESPONSE); + sendToFrontend(transToAcquire.payload, END_REQ); + transToAcquire.payload = nullptr; + } + else + PRINTDEBUGMESSAGE(name(), "Total number of payloads exceeded, backpressure!"); } - else - PRINTDEBUGMESSAGE(name(), "Total number of payloads exceeded, backpressure!"); } void Controller::startBeginResp() { - payloadToRelease = respQueue->nextPayload(); - - if (payloadToRelease != nullptr) - sendToFrontend(payloadToRelease, BEGIN_RESP); - else + if (transToRelease.payload == nullptr) { - sc_time triggerTime = respQueue->getTriggerTime(); - if (triggerTime != sc_max_time()) - dataResponseEvent.notify(triggerTime - sc_time_stamp()); + transToRelease.payload = respQueue->nextPayload(); + + if (transToRelease.payload != nullptr) + { + transToRelease.time = sc_max_time(); + sendToFrontend(transToRelease.payload, BEGIN_RESP); + } + else + { + sc_time triggerTime = respQueue->getTriggerTime(); + if (triggerTime != sc_max_time()) + dataResponseEvent.notify(triggerTime - sc_time_stamp()); + } } } void Controller::finishEndResp() { - NDEBUG_UNUSED(uint64_t id) = DramExtension::getPayloadID(payloadToRelease); - PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " left system."); + if (transToRelease.payload != nullptr && transToRelease.time <= sc_time_stamp()) + { + NDEBUG_UNUSED(uint64_t id) = DramExtension::getPayloadID(transToRelease.payload); + PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " left system."); - payloadToRelease->release(); - payloadToRelease = nullptr; - timeToRelease = sc_max_time(); - numberOfTransactionsServed++; + transToRelease.payload->release(); + transToRelease.payload = nullptr; + numberOfTransactionsServed++; - totalNumberOfPayloads--; - if (totalNumberOfPayloads == 0) - idleTimeCollector.start(); + totalNumberOfPayloads--; + if (totalNumberOfPayloads == 0) + idleTimeCollector.start(); + } } void Controller::sendToFrontend(tlm_generic_payload *payload, tlm_phase phase) diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 9002c007..4fef0c65 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -88,10 +88,11 @@ private: std::vector refreshManagers; std::vector powerDownManagers; - tlm::tlm_generic_payload *payloadToAcquire = nullptr; - sc_time timeToAcquire = sc_max_time(); - tlm::tlm_generic_payload *payloadToRelease = nullptr; - sc_time timeToRelease = sc_max_time(); + struct Transaction + { + tlm::tlm_generic_payload *payload = nullptr; + sc_time time = sc_max_time(); + } transToAcquire, transToRelease; void finishBeginReq(); void startEndReq(); diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp index b25f3c2f..8ed91d8e 100644 --- a/DRAMSys/library/src/simulation/Arbiter.cpp +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -84,7 +84,7 @@ tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload, // In the begin request phase the socket ID is appended to the payload. // It will extracted from the payload and used later. - appendDramExtension(id, payload); + appendDramExtension(id, payload, fwDelay); payload.acquire(); } else if (phase == END_RESP) @@ -105,7 +105,7 @@ tlm_sync_enum Arbiter::nb_transport_bw(int channelId, tlm_generic_payload &paylo tlm_phase &phase, sc_time &bwDelay) { // Check channel ID - assert((unsigned int)channelId == DramExtension::getExtension(payload).getChannel().ID()); + assert(static_cast(channelId) == DramExtension::getExtension(payload).getChannel().ID()); PRINTDEBUGMESSAGE(name(), "[bw] " + getPhaseName(phase) + " notification in " + bwDelay.to_string()); @@ -120,7 +120,7 @@ unsigned int Arbiter::transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans) Configuration::getInstance().addressOffset); DecodedAddress decodedAddress = addressDecoder->decodeAddress(trans.get_address()); - return iSocket[decodedAddress.channel]->transport_dbg(trans); + return iSocket[static_cast(decodedAddress.channel)]->transport_dbg(trans); } void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) @@ -141,7 +141,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) channelIsFree[channelId] = false; tlm_phase tPhase = BEGIN_REQ; sc_time tDelay = SC_ZERO_TIME; - iSocket[channelId]->nb_transport_fw(payload, tPhase, tDelay); + iSocket[static_cast(channelId)]->nb_transport_fw(payload, tPhase, tDelay); // TODO: early completion of channel controller!!! } else @@ -158,7 +158,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) // The arbiter receives a transaction which phase is END_REQ from memory controller and forwards it to the requester device. tlm_phase tPhase = END_REQ; sc_time tDelay = SC_ZERO_TIME; - tSocket[threadId]->nb_transport_bw(payload, tPhase, tDelay); + tlm_sync_enum response = tSocket[static_cast(threadId)]->nb_transport_bw(payload, tPhase, tDelay); // This channel is now free! Dispatch a new transaction (phase is BEGIN_REQ) from the queue, if any. Send it to the memory controller. if (!pendingRequests[channelId].empty()) @@ -168,7 +168,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) pendingRequests[channelId].pop(); tlm_phase tPhase = BEGIN_REQ; sc_time tDelay = SC_ZERO_TIME; - iSocket[channelId]->nb_transport_fw(payloadToSend, tPhase, tDelay); + iSocket[static_cast(channelId)]->nb_transport_fw(payloadToSend, tPhase, tDelay); // TODO: early completion of channel controller // Mark the channel as busy again. channelIsFree[channelId] = false; @@ -183,7 +183,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) { tlm_phase tPhase = BEGIN_RESP; sc_time tDelay = SC_ZERO_TIME; - tlm_sync_enum returnValue = tSocket[threadId]->nb_transport_bw(payload, tPhase, tDelay); + tlm_sync_enum returnValue = tSocket[static_cast(threadId)]->nb_transport_bw(payload, tPhase, tDelay); if (returnValue != TLM_ACCEPTED) { tPhase = END_RESP; @@ -201,7 +201,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) { tlm_phase tPhase = END_RESP; sc_time tDelay = SC_ZERO_TIME; - iSocket[channelId]->nb_transport_fw(payload, tPhase, tDelay); + iSocket[static_cast(channelId)]->nb_transport_fw(payload, tPhase, tDelay); } // Drop one element of the queue of BEGIN_RESP from memory to this device pendingResponses[threadId].pop(); @@ -215,7 +215,7 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) // Send ONE extra BEGIN_RESP to the device tlm_phase tPhase = BEGIN_RESP; sc_time tDelay = SC_ZERO_TIME; - tlm_sync_enum returnValue = tSocket[threadId]->nb_transport_bw(payloadToSend, tPhase, tDelay); + tlm_sync_enum returnValue = tSocket[static_cast(threadId)]->nb_transport_bw(payloadToSend, tPhase, tDelay); if (returnValue != TLM_ACCEPTED) { tPhase = END_RESP; @@ -228,14 +228,14 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) "Payload event queue in arbiter was triggered with unknown phase"); } -void Arbiter::appendDramExtension(int socketId, tlm_generic_payload &payload) +void Arbiter::appendDramExtension(int socketId, tlm_generic_payload &payload, sc_time delay) { // Set Generation Extension and DRAM Extension - GenerationExtension::setExtension(&payload, sc_time_stamp()); + GenerationExtension::setExtension(&payload, sc_time_stamp() + delay); unsigned int burstlength = payload.get_streaming_width(); DecodedAddress decodedAddress = addressDecoder->decodeAddress(payload.get_address()); - DramExtension::setExtension(payload, Thread(socketId), + DramExtension::setExtension(payload, Thread(static_cast(socketId)), Channel(decodedAddress.channel), Rank(decodedAddress.rank), BankGroup(decodedAddress.bankgroup), Bank(decodedAddress.bank), Row(decodedAddress.row), Column(decodedAddress.column), diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index a6373b33..c2c83222 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ private: std::vector> pendingRequests; // used to account for the response_accept_delay in the initiators (traceplayer, core etc.) // This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP. - std::map> pendingResponses; + std::unordered_map> pendingResponses; // Initiated by initiator side // This function is called when an arbiter's target socket receives a transaction from a device @@ -86,7 +87,7 @@ private: void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase); - void appendDramExtension(int socketId, tlm::tlm_generic_payload &payload); + void appendDramExtension(int socketId, tlm::tlm_generic_payload &payload, sc_time delay); std::vector nextPayloadID; }; diff --git a/DRAMSys/simulator/CMakeLists.txt b/DRAMSys/simulator/CMakeLists.txt index 6dc49e0b..1b3a9851 100644 --- a/DRAMSys/simulator/CMakeLists.txt +++ b/DRAMSys/simulator/CMakeLists.txt @@ -45,10 +45,9 @@ add_executable(DRAMSys main.cpp ExampleInitiator.h MemoryManager.cpp - StlPlayer.h - TraceGenerator.h + StlPlayer.cpp + TraceGenerator.cpp TracePlayer.cpp - TracePlayerListener.h TraceSetup.cpp ) diff --git a/DRAMSys/simulator/MemoryManager.cpp b/DRAMSys/simulator/MemoryManager.cpp index 24ef8d12..361b3f68 100644 --- a/DRAMSys/simulator/MemoryManager.cpp +++ b/DRAMSys/simulator/MemoryManager.cpp @@ -42,14 +42,23 @@ using namespace tlm; MemoryManager::MemoryManager() - : numberOfAllocations(0), numberOfFrees(0) {} + : numberOfAllocations(0), numberOfFrees(0) +{ + if (Configuration::getInstance().storeMode == "NoStorage") + storageEnabled = false; + else + storageEnabled = true; +} MemoryManager::~MemoryManager() { for (tlm_generic_payload *payload : freePayloads) { - // Delete data buffer - delete[] payload->get_data_ptr(); + if (storageEnabled) + { + // Delete data buffer + delete[] payload->get_data_ptr(); + } // Delete all extensions payload->reset(); delete payload; @@ -68,12 +77,15 @@ tlm_generic_payload *MemoryManager::allocate() numberOfAllocations++; tlm_generic_payload *payload = new tlm_generic_payload(this); - // Allocate a data buffer and initialize it with zeroes: - unsigned int dataLength = Configuration::getInstance().getBytesPerBurst(); - unsigned char *data = new unsigned char[dataLength]; - std::fill(data, data + dataLength, 0); + if (storageEnabled) + { + // Allocate a data buffer and initialize it with zeroes: + unsigned int dataLength = Configuration::getInstance().getBytesPerBurst(); + unsigned char *data = new unsigned char[dataLength]; + std::fill(data, data + dataLength, 0); + payload->set_data_ptr(data); + } - payload->set_data_ptr(data); return payload; } else @@ -88,4 +100,3 @@ void MemoryManager::free(tlm_generic_payload *payload) { freePayloads.push_back(payload); } - diff --git a/DRAMSys/simulator/MemoryManager.h b/DRAMSys/simulator/MemoryManager.h index 397ed40d..9893496d 100644 --- a/DRAMSys/simulator/MemoryManager.h +++ b/DRAMSys/simulator/MemoryManager.h @@ -52,6 +52,7 @@ private: uint64_t numberOfAllocations; uint64_t numberOfFrees; std::vector freePayloads; + bool storageEnabled = false; }; #endif // MEMORYMANAGER_H diff --git a/DRAMSys/simulator/StlPlayer.cpp b/DRAMSys/simulator/StlPlayer.cpp new file mode 100644 index 00000000..4aa918ec --- /dev/null +++ b/DRAMSys/simulator/StlPlayer.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015, 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: + * Janik Schlemminger + * Robert Gernhardt + * Matthias Jung + * Éder F. Zulian + * Felipe S. Prado + */ + +#include "StlPlayer.h" + +using namespace tlm; + +StlPlayer::StlPlayer(sc_module_name name, + std::string pathToTrace, + sc_time playerClk, + TraceSetup *setup, + bool relative) + : TracePlayer(name, setup), file(pathToTrace), + currentBuffer(&lineContents[0]), + parseBuffer(&lineContents[1]), + relative(relative) +{ + if (!file.is_open()) + SC_REPORT_FATAL(0, (std::string("Could not open trace ") + pathToTrace).c_str()); + + this->playerClk = playerClk; + burstlength = Configuration::getInstance().memSpec->burstLength; + dataLength = Configuration::getInstance().getBytesPerBurst(); + lineCnt = 0; + + currentBuffer->reserve(lineBufferSize); + parseBuffer->reserve(lineBufferSize); + + parseTraceFile(); + lineIterator = currentBuffer->cend(); +} + +StlPlayer::~StlPlayer() +{ + if (parserThread.joinable()) + parserThread.join(); +} + +void StlPlayer::nextPayload() +{ + if (lineIterator == currentBuffer->cend()) + { + lineIterator = swapBuffers(); + if (lineIterator == currentBuffer->cend()) + { + // The file is empty. Nothing more to do. + this->finish(); + return; + } + } + + numberOfTransactions++; + + // Allocate a generic payload for this request. + tlm_generic_payload *payload = setup->allocatePayload(); + payload->acquire(); + + // Fill up the payload. + payload->set_address(lineIterator->addr); + payload->set_response_status(TLM_INCOMPLETE_RESPONSE); + payload->set_dmi_allowed(false); + payload->set_byte_enable_length(0); + payload->set_streaming_width(burstlength); + payload->set_data_length(dataLength); + payload->set_command(lineIterator->cmd); + std::copy(lineIterator->data.begin(), lineIterator->data.end(), payload->get_data_ptr()); + + if (!relative) + { + if (lineIterator->sendingTime <= sc_time_stamp()) + sendToTarget(*payload, BEGIN_REQ, SC_ZERO_TIME); + else + sendToTarget(*payload, BEGIN_REQ, lineIterator->sendingTime - sc_time_stamp()); + } + else + sendToTarget(*payload, BEGIN_REQ, lineIterator->sendingTime); + + transactionsSent++; + PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); + lineIterator++; +} + +void StlPlayer::parseTraceFile() +{ + unsigned parsedLines = 0; + parseBuffer->clear(); + while (file && !file.eof() && parsedLines < lineBufferSize) + { + // Get a new line from the input file. + std::getline(file, line); + lineCnt++; + // If the line starts with '#' (commented lines) the transaction is ignored. + if (line.empty() || line.at(0) == '#') + continue; + + parsedLines++; + parseBuffer->emplace_back(); + LineContent &content = parseBuffer->back(); + + // Trace files MUST provide timestamp, command and address for every + // transaction. The data information depends on the storage mode + // configuration. + time.clear(); + command.clear(); + address.clear(); + dataStr.clear(); + + iss.clear(); + iss.str(line); + + // Get the timestamp for the transaction. + iss >> time; + if (time.empty()) + SC_REPORT_FATAL("StlPlayer", + ("Malformed trace file. Timestamp could not be found (line " + std::to_string( + lineCnt) + ").").c_str()); + content.sendingTime = std::stoull(time.c_str()) * playerClk; + + // Get the command. + iss >> command; + if (command.empty()) + SC_REPORT_FATAL("StlPlayer", + ("Malformed trace file. Command could not be found (line " + std::to_string( + lineCnt) + ").").c_str()); + + if (command == "read") + content.cmd = tlm::TLM_READ_COMMAND; + else if (command == "write") + content.cmd = tlm::TLM_WRITE_COMMAND; + else + SC_REPORT_FATAL("StlPlayer", + (std::string("Corrupted tracefile, command ") + command + + std::string(" unknown")).c_str()); + + // Get the address. + iss >> address; + if (address.empty()) + SC_REPORT_FATAL("StlPlayer", + ("Malformed trace file. Address could not be found (line " + + std::to_string(lineCnt) + ").").c_str()); + content.addr = std::stoull(address.c_str(), nullptr, 16); + + // Get the data if necessary. + if (storageEnabled && content.cmd == tlm::TLM_WRITE_COMMAND) + { + // The input trace file must provide the data to be stored into the memory. + iss >> dataStr; + if (dataStr.empty()) + SC_REPORT_FATAL("StlPlayer", + ("Malformed trace file. Data information could not be found (line " + std::to_string( + lineCnt) + ").").c_str()); + + // Check if data length in the trace file is correct. + // We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix. + if (dataStr.length() != (dataLength * 2 + 2)) + SC_REPORT_FATAL("StlPlayer", + ("Data in the trace file has an invalid length (line " + std::to_string( + lineCnt) + ").").c_str()); + + // Set data + for (unsigned i = 0; i < dataLength; i++) + content.data.emplace_back(static_cast + (std::stoi(dataStr.substr(i * 2 + 2, 2).c_str(), nullptr, 16))); + } + } +} + +std::vector::const_iterator StlPlayer::swapBuffers() +{ + // Wait for parser to finish + if (parserThread.joinable()) + parserThread.join(); + + // Swap buffers + std::swap(currentBuffer, parseBuffer); + + // Start new parser thread + parserThread = std::thread(&StlPlayer::parseTraceFile, this); + + return currentBuffer->cbegin(); +} diff --git a/DRAMSys/simulator/StlPlayer.h b/DRAMSys/simulator/StlPlayer.h index 787f00d5..74e4f713 100644 --- a/DRAMSys/simulator/StlPlayer.h +++ b/DRAMSys/simulator/StlPlayer.h @@ -44,6 +44,7 @@ #include #include #include +#include "TraceSetup.h" #include "TracePlayer.h" struct LineContent @@ -54,186 +55,23 @@ struct LineContent std::vector data; }; -template class StlPlayer : public TracePlayer { public: StlPlayer(sc_module_name name, std::string pathToTrace, sc_time playerClk, - TracePlayerListener *listener) : - TracePlayer(name, listener), - file(pathToTrace), - currentBuffer(&lineContents[0]), - parseBuffer(&lineContents[1]) - { - if (!file.is_open()) - SC_REPORT_FATAL(0, (std::string("Could not open trace ") + pathToTrace).c_str()); + TraceSetup *setup, + bool relative); - this->playerClk = playerClk; - burstlength = Configuration::getInstance().memSpec->burstLength; - dataLength = Configuration::getInstance().getBytesPerBurst(); - lineCnt = 0; + virtual ~StlPlayer() override; - currentBuffer->reserve(lineBufferSize); - parseBuffer->reserve(lineBufferSize); - - parseTraceFile(); - lineIterator = currentBuffer->cend(); - } - - ~StlPlayer() - { - if (parserThread.joinable()) - parserThread.join(); - } + virtual void nextPayload() override; private: - void parseTraceFile() - { - unsigned parsedLines = 0; - parseBuffer->clear(); - while (file && !file.eof() && parsedLines < lineBufferSize) - { - // Get a new line from the input file. - std::getline(file, line); - lineCnt++; - // If the line starts with '#' (commented lines) the transaction is ignored. - if (line.empty() || line.at(0) == '#') - continue; + void parseTraceFile(); + std::vector::const_iterator swapBuffers(); - parsedLines++; - parseBuffer->emplace_back(); - LineContent &content = parseBuffer->back(); - - // Trace files MUST provide timestamp, command and address for every - // transaction. The data information depends on the storage mode - // configuration. - time.clear(); - command.clear(); - address.clear(); - dataStr.clear(); - - iss.clear(); - iss.str(line); - - // Get the timestamp for the transaction. - iss >> time; - if (time.empty()) - SC_REPORT_FATAL("StlPlayer", - ("Malformed trace file. Timestamp could not be found (line " + std::to_string( - lineCnt) + ").").c_str()); - content.sendingTime = std::stoull(time.c_str()) * playerClk; - - // Get the command. - iss >> command; - if (command.empty()) - SC_REPORT_FATAL("StlPlayer", - ("Malformed trace file. Command could not be found (line " + std::to_string( - lineCnt) + ").").c_str()); - - if (command == "read") - content.cmd = tlm::TLM_READ_COMMAND; - else if (command == "write") - content.cmd = tlm::TLM_WRITE_COMMAND; - else - SC_REPORT_FATAL("StlPlayer", - (std::string("Corrupted tracefile, command ") + command + - std::string(" unknown")).c_str()); - - // Get the address. - iss >> address; - if (address.empty()) - SC_REPORT_FATAL("StlPlayer", - ("Malformed trace file. Address could not be found (line " - + std::to_string(lineCnt) + ").").c_str()); - content.addr = std::stoull(address.c_str(), nullptr, 16); - - // Get the data if necessary. - if (storageEnabled && content.cmd == tlm::TLM_WRITE_COMMAND) - { - // The input trace file must provide the data to be stored into the memory. - iss >> dataStr; - if (dataStr.empty()) - SC_REPORT_FATAL("StlPlayer", - ("Malformed trace file. Data information could not be found (line " + std::to_string( - lineCnt) + ").").c_str()); - - // Check if data length in the trace file is correct. - // We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix. - if (dataStr.length() != (dataLength * 2 + 2)) - SC_REPORT_FATAL("StlPlayer", - ("Data in the trace file has an invalid length (line " + std::to_string( - lineCnt) + ").").c_str()); - - // Set data - for (unsigned i = 0; i < dataLength; i++) - content.data.emplace_back((unsigned char)std::stoi(dataStr.substr(i * 2 + 2, 2).c_str(), nullptr, 16)); - } - } - } - - std::vector::const_iterator swapBuffers() - { - // Wait for parser to finish - if (parserThread.joinable()) - parserThread.join(); - - // Swap buffers - std::swap(currentBuffer, parseBuffer); - - // Start new parser thread - parserThread = std::thread(&StlPlayer::parseTraceFile, this); - - return currentBuffer->cbegin(); - } - -public: - void nextPayload() - { - if (lineIterator == currentBuffer->cend()) - { - lineIterator = swapBuffers(); - if (lineIterator == currentBuffer->cend()) - { - // The file is empty. Nothing more to do. - this->finish(); - return; - } - } - - numberOfTransactions++; - - // Allocate a generic payload for this request. - tlm::tlm_generic_payload *payload = this->allocatePayload(); - payload->acquire(); - - // Fill up the payload. - payload->set_address(lineIterator->addr); - payload->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - payload->set_dmi_allowed(false); - payload->set_byte_enable_length(0); - payload->set_streaming_width(burstlength); - payload->set_data_length(dataLength); - payload->set_command(lineIterator->cmd); - std::copy(lineIterator->data.begin(), lineIterator->data.end(), payload->get_data_ptr()); - - if (relative == false) - { - // Send the transaction directly or schedule it to be sent in the future. - if (lineIterator->sendingTime <= sc_time_stamp()) - this->payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, SC_ZERO_TIME); - else - this->payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, - lineIterator->sendingTime - sc_time_stamp()); - } - else - payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, lineIterator->sendingTime); - - lineIterator++; - } - -private: std::ifstream file; unsigned int lineCnt; @@ -257,6 +95,8 @@ private: std::string line; std::istringstream iss; + + const bool relative; }; #endif // STLPLAYER_H diff --git a/DRAMSys/simulator/TracePlayerListener.h b/DRAMSys/simulator/TraceGenerator.cpp similarity index 58% rename from DRAMSys/simulator/TracePlayerListener.h rename to DRAMSys/simulator/TraceGenerator.cpp index c4bd7460..3a3069ff 100644 --- a/DRAMSys/simulator/TracePlayerListener.h +++ b/DRAMSys/simulator/TraceGenerator.cpp @@ -35,15 +35,41 @@ * Matthias Jung */ -#ifndef TRACEPLAYERLISTENER_H -#define TRACEPLAYERLISTENER_H +#include "TraceGenerator.h" -class TracePlayerListener +TraceGenerator::TraceGenerator(sc_module_name name, + unsigned int fCKMhz, TraceSetup *setup) + : TracePlayer(name, setup), transCounter(0) { -public: - virtual void tracePlayerTerminates() = 0; - virtual void transactionFinished() = 0; - virtual ~TracePlayerListener() {} -}; + if (fCKMhz == 0) + tCK = Configuration::getInstance().memSpec->tCK; + else + tCK = sc_time(1.0 / fCKMhz, SC_US); -#endif // TRACEPLAYERLISTENER_H + burstlenght = Configuration::getInstance().memSpec->burstLength; +} + +void TraceGenerator::nextPayload() +{ + if (transCounter >= 1000) // TODO set limit! + terminate(); + + tlm::tlm_generic_payload *payload = setup->allocatePayload(); + payload->acquire(); + unsigned char *dataElement = new unsigned char[16]; + // TODO: column / burst breite + + payload->set_address(0x0); + payload->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); + payload->set_dmi_allowed(false); + payload->set_byte_enable_length(0); + payload->set_streaming_width(burstlenght); + payload->set_data_ptr(dataElement); + payload->set_data_length(16); + payload->set_command(tlm::TLM_READ_COMMAND); + transCounter++; + + sendToTarget(*payload, tlm::BEGIN_REQ, SC_ZERO_TIME); + transactionsSent++; + PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); +} diff --git a/DRAMSys/simulator/TraceGenerator.h b/DRAMSys/simulator/TraceGenerator.h index d39edfc6..8993e8d3 100644 --- a/DRAMSys/simulator/TraceGenerator.h +++ b/DRAMSys/simulator/TraceGenerator.h @@ -39,43 +39,13 @@ #define TRACEGENERATOR_H #include "TracePlayer.h" +#include "TraceSetup.h" -struct TraceGenerator : public TracePlayer +class TraceGenerator : public TracePlayer { public: - TraceGenerator(sc_module_name name, unsigned int fCKMhz, TracePlayerListener *listener) - : TracePlayer(name, listener), transCounter(0) - { - if (fCKMhz == 0) - tCK = Configuration::getInstance().memSpec->tCK; - else - tCK = sc_time(1.0 / fCKMhz, SC_US); - - this->burstlenght = Configuration::getInstance().memSpec->burstLength; - } - - virtual void nextPayload() override - { - if (transCounter >= 1000) { // TODO set limit! - this->terminate(); - } - - tlm::tlm_generic_payload *payload = this->allocatePayload(); - payload->acquire(); - unsigned char *dataElement = new unsigned - char[16]; // TODO: column / burst breite - - payload->set_address(0x0); - payload->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); - payload->set_dmi_allowed(false); - payload->set_byte_enable_length(0); - payload->set_streaming_width(this->burstlenght); - payload->set_data_ptr(dataElement); - payload->set_data_length(16); - payload->set_command(tlm::TLM_READ_COMMAND); - transCounter++; - this->payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, SC_ZERO_TIME); - } + TraceGenerator(sc_module_name name, unsigned int fCKMhz, TraceSetup *setup); + virtual void nextPayload() override; private: unsigned int burstlenght; diff --git a/DRAMSys/simulator/TracePlayer.cpp b/DRAMSys/simulator/TracePlayer.cpp index 1162963e..69e8b16a 100644 --- a/DRAMSys/simulator/TracePlayer.cpp +++ b/DRAMSys/simulator/TracePlayer.cpp @@ -37,14 +37,16 @@ */ #include "TracePlayer.h" +#include "TraceSetup.h" using namespace tlm; -TracePlayer::TracePlayer(sc_module_name name, TracePlayerListener *listener) : +TracePlayer::TracePlayer(sc_module_name name, TraceSetup *setup) : sc_module(name), payloadEventQueue(this, &TracePlayer::peqCallback), - listener(listener) + setup(setup) { + SC_METHOD(nextPayload); iSocket.register_nb_transport_bw(this, &TracePlayer::nb_transport_bw); if (Configuration::getInstance().storeMode == "NoStorage") @@ -53,11 +55,6 @@ TracePlayer::TracePlayer(sc_module_name name, TracePlayerListener *listener) : storageEnabled = true; } -tlm_generic_payload *TracePlayer::allocatePayload() -{ - return memoryManager.allocate(); -} - void TracePlayer::finish() { finished = true; @@ -66,7 +63,7 @@ void TracePlayer::finish() void TracePlayer::terminate() { cout << sc_time_stamp() << " " << this->name() << " terminated " << std::endl; - listener->tracePlayerTerminates(); + setup->tracePlayerTerminates(); } tlm_sync_enum TracePlayer::nb_transport_bw(tlm_generic_payload &payload, @@ -79,27 +76,25 @@ tlm_sync_enum TracePlayer::nb_transport_bw(tlm_generic_payload &payload, void TracePlayer::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase) { - if (phase == BEGIN_REQ) { - sendToTarget(payload, phase, SC_ZERO_TIME); - transactionsSent++; - PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); - } else if (phase == END_REQ) { + if (phase == END_REQ) + { nextPayload(); - } else if (phase == BEGIN_RESP) { + } + else if (phase == BEGIN_RESP) + { payload.release(); sendToTarget(payload, END_RESP, SC_ZERO_TIME); if (Configuration::getInstance().simulationProgressBar) - listener->transactionFinished(); + setup->transactionFinished(); transactionsReceived++; // If all answers were received: if (finished == true && numberOfTransactions == transactionsReceived) - { this->terminate(); - } - } else if (phase == END_RESP) { - } else { + } + else + { SC_REPORT_FATAL(0, "TracePlayer PEQ was triggered with unknown phase"); } } diff --git a/DRAMSys/simulator/TracePlayer.h b/DRAMSys/simulator/TracePlayer.h index e1a35b56..998929c9 100644 --- a/DRAMSys/simulator/TracePlayer.h +++ b/DRAMSys/simulator/TracePlayer.h @@ -46,37 +46,35 @@ #include #include #include -#include "MemoryManager.h" #include "configuration/Configuration.h" #include "common/DebugManager.h" -#include "TracePlayerListener.h" +#include "TraceSetup.h" -struct TracePlayer : public sc_module +class TracePlayer : public sc_module { public: tlm_utils::simple_initiator_socket iSocket; - TracePlayer(sc_module_name name, TracePlayerListener *listener); + TracePlayer(sc_module_name name, TraceSetup *setup); + SC_HAS_PROCESS(TracePlayer); virtual void nextPayload() = 0; unsigned int getNumberOfLines(std::string pathToTrace); protected: - tlm::tlm_generic_payload *allocatePayload(); tlm_utils::peq_with_cb_and_phase payloadEventQueue; void finish(); void terminate(); - unsigned int numberOfTransactions = 0; bool storageEnabled = false; + TraceSetup *setup; + void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase, + const sc_time &delay); + unsigned int numberOfTransactions = 0; + unsigned int transactionsSent = 0; private: tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, sc_time &bwDelay); void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase); - void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase, - const sc_time &delay); - MemoryManager memoryManager; - unsigned int transactionsSent = 0; unsigned int transactionsReceived = 0; - TracePlayerListener *listener; bool finished = false; }; diff --git a/DRAMSys/simulator/TraceSetup.cpp b/DRAMSys/simulator/TraceSetup.cpp index 73bdb3f1..decd5423 100644 --- a/DRAMSys/simulator/TraceSetup.cpp +++ b/DRAMSys/simulator/TraceSetup.cpp @@ -35,10 +35,13 @@ */ #include "TraceSetup.h" +#include "StlPlayer.h" + +using namespace tlm; TraceSetup::TraceSetup(std::string uri, std::string pathToResources, - std::vector *devices) + std::vector *players) { // Load Simulation: nlohmann::json simulationdoc = parseJSON(uri); @@ -79,13 +82,13 @@ TraceSetup::TraceSetup(std::string uri, TracePlayer *player; if (ext == "stl") - player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this); + player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this, false); else if (ext == "rstl") - player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this); + player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this, true); else throw std::runtime_error("Unsupported file extension in " + name); - devices->push_back(player); + players->push_back(player); if (Configuration::getInstance().simulationProgressBar) totalTransactions += player->getNumberOfLines(stlFile); @@ -93,7 +96,7 @@ TraceSetup::TraceSetup(std::string uri, } remainingTransactions = totalTransactions; - numberOfTracePlayers = devices->size(); + numberOfTracePlayers = players->size(); } void TraceSetup::tracePlayerTerminates() @@ -113,3 +116,8 @@ void TraceSetup::transactionFinished() if (remainingTransactions == 0) std::cout << std::endl; } + +tlm_generic_payload *TraceSetup::allocatePayload() +{ + return memoryManager.allocate(); +} diff --git a/DRAMSys/simulator/TraceSetup.h b/DRAMSys/simulator/TraceSetup.h index 6d3f1f48..165c8747 100644 --- a/DRAMSys/simulator/TraceSetup.h +++ b/DRAMSys/simulator/TraceSetup.h @@ -38,28 +38,28 @@ #include #include +#include +#include "MemoryManager.h" -#include "common/utils.h" -#include "TracePlayer.h" -#include "StlPlayer.h" +class TracePlayer; - -class TraceSetup : public TracePlayerListener +class TraceSetup { public: TraceSetup(std::string uri, std::string pathToResources, std::vector *devices); - virtual void tracePlayerTerminates() override; - virtual void transactionFinished() override; - virtual ~TraceSetup() {} + void tracePlayerTerminates(); + void transactionFinished(); + tlm::tlm_generic_payload *allocatePayload(); private: unsigned int numberOfTracePlayers; unsigned int totalTransactions = 0; unsigned int remainingTransactions; unsigned int finishedTracePlayers = 0; + MemoryManager memoryManager; }; #endif // TRACESETUP_H diff --git a/DRAMSys/simulator/main.cpp b/DRAMSys/simulator/main.cpp index f352ce25..87ef8d35 100644 --- a/DRAMSys/simulator/main.cpp +++ b/DRAMSys/simulator/main.cpp @@ -45,6 +45,7 @@ #include "simulation/DRAMSys.h" #include "TraceSetup.h" +#include "TracePlayer.h" #ifdef RECORDING #include "simulation/DRAMSysRecordable.h" @@ -70,21 +71,24 @@ int sc_main(int argc, char **argv) std::string resources; std::string simulationJson; // Run only with default config (ddr3-example.json): - if (argc == 1) { + if (argc == 1) + { // Get path of resources: resources = pathOfFile(argv[0]) + std::string("/../../DRAMSys/library/resources/"); simulationJson = resources + "simulations/ddr5-example.json"; } // Run with specific config but default resource folders: - else if (argc == 2) { + else if (argc == 2) + { // Get path of resources: resources = pathOfFile(argv[0]) + std::string("/../../DRAMSys/library/resources/"); simulationJson = argv[1]; } // Run with spefific config and specific resource folder: - else if (argc == 3) { + else if (argc == 3) + { simulationJson = argv[1]; resources = argv[2]; } @@ -105,7 +109,7 @@ int sc_main(int argc, char **argv) dramSys = new DRAMSys("DRAMSys", simulationJson, resources); // Instantiate STL Players: - TraceSetup *ts = new TraceSetup(simulationJson, resources, &players); + TraceSetup *setup = new TraceSetup(simulationJson, resources, &players); // Bind STL Players with DRAMSys: for (size_t i = 0; i < players.size(); i++) @@ -128,10 +132,6 @@ int sc_main(int argc, char **argv) // Store the starting of the simulation in wallclock time: auto start = std::chrono::high_resolution_clock::now(); - // Kickstart the players: - for (auto &p : players) - p->nextPayload(); - // Start SystemC Simulation: sc_set_stop_mode(SC_STOP_FINISH_DELTA); sc_start(); @@ -143,7 +143,7 @@ int sc_main(int argc, char **argv) delete dramSys; for (auto player : players) delete player; - delete ts; + delete setup; return 0; }