diff --git a/DRAMSys/library/src/simulation/Arbiter.cpp b/DRAMSys/library/src/simulation/Arbiter.cpp index b25f3c2f..85b26716 100644 --- a/DRAMSys/library/src/simulation/Arbiter.cpp +++ b/DRAMSys/library/src/simulation/Arbiter.cpp @@ -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; @@ -235,7 +235,7 @@ void Arbiter::appendDramExtension(int socketId, tlm_generic_payload &payload) 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/simulator/CMakeLists.txt b/DRAMSys/simulator/CMakeLists.txt index 6dc49e0b..f43029b8 100644 --- a/DRAMSys/simulator/CMakeLists.txt +++ b/DRAMSys/simulator/CMakeLists.txt @@ -45,7 +45,7 @@ add_executable(DRAMSys main.cpp ExampleInitiator.h MemoryManager.cpp - StlPlayer.h + StlPlayer.cpp TraceGenerator.h TracePlayer.cpp TracePlayerListener.h diff --git a/DRAMSys/simulator/StlPlayer.cpp b/DRAMSys/simulator/StlPlayer.cpp new file mode 100644 index 00000000..a336a330 --- /dev/null +++ b/DRAMSys/simulator/StlPlayer.cpp @@ -0,0 +1,215 @@ +/* + * 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" + +StlPlayer::StlPlayer(sc_module_name name, + std::string pathToTrace, + sc_time playerClk, + TracePlayerListener *listener, + bool relative) + : TracePlayer(name, listener), 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::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) + { + // 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++; +} + +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..0a8cea6b 100644 --- a/DRAMSys/simulator/StlPlayer.h +++ b/DRAMSys/simulator/StlPlayer.h @@ -54,186 +54,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()); + TracePlayerListener *listener, + 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 +94,8 @@ private: std::string line; std::istringstream iss; + + const bool relative; }; #endif // STLPLAYER_H diff --git a/DRAMSys/simulator/TracePlayer.cpp b/DRAMSys/simulator/TracePlayer.cpp index 1162963e..06305557 100644 --- a/DRAMSys/simulator/TracePlayer.cpp +++ b/DRAMSys/simulator/TracePlayer.cpp @@ -79,13 +79,18 @@ 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) { + if (phase == BEGIN_REQ) + { sendToTarget(payload, phase, SC_ZERO_TIME); transactionsSent++; PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); - } else if (phase == END_REQ) { + } + else 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) @@ -95,11 +100,14 @@ void TracePlayer::peqCallback(tlm_generic_payload &payload, // If all answers were received: if (finished == true && numberOfTransactions == transactionsReceived) - { this->terminate(); - } - } else if (phase == END_RESP) { - } else { + + } + else if (phase == END_RESP) + { + } + else + { SC_REPORT_FATAL(0, "TracePlayer PEQ was triggered with unknown phase"); } } diff --git a/DRAMSys/simulator/TraceSetup.cpp b/DRAMSys/simulator/TraceSetup.cpp index 73bdb3f1..b2e7e512 100644 --- a/DRAMSys/simulator/TraceSetup.cpp +++ b/DRAMSys/simulator/TraceSetup.cpp @@ -79,9 +79,9 @@ 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);