Split up StlPlayer into source and header file.

This commit is contained in:
Lukas Steiner
2020-10-06 13:33:50 +02:00
parent f0f9687ff4
commit d40462dcf7
6 changed files with 250 additions and 188 deletions

View File

@@ -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<unsigned>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(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<unsigned>(socketId)),
Channel(decodedAddress.channel), Rank(decodedAddress.rank),
BankGroup(decodedAddress.bankgroup), Bank(decodedAddress.bank),
Row(decodedAddress.row), Column(decodedAddress.column),

View File

@@ -45,7 +45,7 @@ add_executable(DRAMSys
main.cpp
ExampleInitiator.h
MemoryManager.cpp
StlPlayer.h
StlPlayer.cpp
TraceGenerator.h
TracePlayer.cpp
TracePlayerListener.h

View File

@@ -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<unsigned char>
(std::stoi(dataStr.substr(i * 2 + 2, 2).c_str(), nullptr, 16)));
}
}
}
std::vector<LineContent>::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();
}

View File

@@ -54,186 +54,23 @@ struct LineContent
std::vector<unsigned char> data;
};
template<bool relative>
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<LineContent>::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<LineContent>::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<relative>::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

View File

@@ -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");
}
}

View File

@@ -79,9 +79,9 @@ TraceSetup::TraceSetup(std::string uri,
TracePlayer *player;
if (ext == "stl")
player = new StlPlayer<false>(moduleName.c_str(), stlFile, playerClk, this);
player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this, false);
else if (ext == "rstl")
player = new StlPlayer<true>(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);