|
|
|
|
@@ -43,6 +43,14 @@
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include "TracePlayer.h"
|
|
|
|
|
|
|
|
|
|
struct LineContent
|
|
|
|
|
{
|
|
|
|
|
sc_time sendingTime;
|
|
|
|
|
tlm::tlm_command cmd;
|
|
|
|
|
uint64_t addr;
|
|
|
|
|
std::vector<unsigned char> data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<bool relative>
|
|
|
|
|
class StlPlayer : public TracePlayer
|
|
|
|
|
{
|
|
|
|
|
@@ -58,120 +66,141 @@ public:
|
|
|
|
|
SC_REPORT_FATAL(0, (std::string("Could not open trace ") + pathToTrace).c_str());
|
|
|
|
|
|
|
|
|
|
this->playerClk = playerClk;
|
|
|
|
|
this->burstlength = Configuration::getInstance().memSpec->burstLength;
|
|
|
|
|
this->dataLength = Configuration::getInstance().getBytesPerBurst();
|
|
|
|
|
this->lineCnt = 0;
|
|
|
|
|
burstlength = Configuration::getInstance().memSpec->burstLength;
|
|
|
|
|
dataLength = Configuration::getInstance().getBytesPerBurst();
|
|
|
|
|
lineCnt = 0;
|
|
|
|
|
|
|
|
|
|
parseTraceFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nextPayload()
|
|
|
|
|
void parseTraceFile()
|
|
|
|
|
{
|
|
|
|
|
std::string line;
|
|
|
|
|
while (line.empty() && file) {
|
|
|
|
|
unsigned parsedLines = 0;
|
|
|
|
|
lineContents.clear();
|
|
|
|
|
while (file && !file.eof() && parsedLines < 10000)
|
|
|
|
|
{
|
|
|
|
|
// 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) == '#')
|
|
|
|
|
line.clear();
|
|
|
|
|
if (line.empty() || line.at(0) == '#')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
parsedLines++;
|
|
|
|
|
lineContents.emplace_back();
|
|
|
|
|
LineContent &content = lineContents.back();
|
|
|
|
|
|
|
|
|
|
// Trace files MUST provide timestamp, command and address for every
|
|
|
|
|
// transaction. The data information depends on the storage mode
|
|
|
|
|
// configuration.
|
|
|
|
|
std::string time;
|
|
|
|
|
std::string command;
|
|
|
|
|
std::string address;
|
|
|
|
|
std::string dataStr;
|
|
|
|
|
|
|
|
|
|
std::istringstream iss(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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lineIterator = lineContents.cbegin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nextPayload()
|
|
|
|
|
{
|
|
|
|
|
if (lineIterator == lineContents.cend())
|
|
|
|
|
{
|
|
|
|
|
// Read new lines of file.
|
|
|
|
|
parseTraceFile();
|
|
|
|
|
if (lineIterator == lineContents.cend())
|
|
|
|
|
{
|
|
|
|
|
// The file is empty. Nothing more to do.
|
|
|
|
|
this->finish();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
// The file is empty. Nothing more to do.
|
|
|
|
|
this->finish();
|
|
|
|
|
return;
|
|
|
|
|
} else {
|
|
|
|
|
numberOfTransactions++;
|
|
|
|
|
}
|
|
|
|
|
numberOfTransactions++;
|
|
|
|
|
|
|
|
|
|
// Allocate a generic payload for this request.
|
|
|
|
|
tlm::tlm_generic_payload *payload = this->allocatePayload();
|
|
|
|
|
payload->acquire();
|
|
|
|
|
unsigned char *data = payload->get_data_ptr();
|
|
|
|
|
|
|
|
|
|
// Trace files MUST provide timestamp, command and address for every
|
|
|
|
|
// transaction. The data information depends on the storage mode
|
|
|
|
|
// configuration.
|
|
|
|
|
std::string time;
|
|
|
|
|
std::string command;
|
|
|
|
|
std::string address;
|
|
|
|
|
std::string dataStr;
|
|
|
|
|
|
|
|
|
|
std::istringstream iss(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());
|
|
|
|
|
sc_time 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());
|
|
|
|
|
enum tlm::tlm_command cmd;
|
|
|
|
|
if (command == "read") {
|
|
|
|
|
cmd = tlm::TLM_READ_COMMAND;
|
|
|
|
|
} else if (command == "write") {
|
|
|
|
|
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());
|
|
|
|
|
unsigned long long addr = std::stoull(address.c_str(), 0, 16);
|
|
|
|
|
|
|
|
|
|
// Get the data if necessary.
|
|
|
|
|
if (storageEnabled && 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++)
|
|
|
|
|
data[i] = (unsigned char)std::stoi(dataStr.substr(i * 2 + 2, 2).c_str(), 0, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fill up the payload.
|
|
|
|
|
payload->set_address(addr);
|
|
|
|
|
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_data_ptr(data);
|
|
|
|
|
payload->set_command(cmd);
|
|
|
|
|
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 (sendingTime <= sc_time_stamp())
|
|
|
|
|
if (lineIterator->sendingTime <= sc_time_stamp())
|
|
|
|
|
this->payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, SC_ZERO_TIME);
|
|
|
|
|
else
|
|
|
|
|
this->payloadEventQueue.notify(*payload, tlm::BEGIN_REQ,
|
|
|
|
|
sendingTime - sc_time_stamp());
|
|
|
|
|
lineIterator->sendingTime - sc_time_stamp());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, sendingTime);
|
|
|
|
|
payloadEventQueue.notify(*payload, tlm::BEGIN_REQ, lineIterator->sendingTime);
|
|
|
|
|
|
|
|
|
|
lineIterator++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
@@ -181,7 +210,9 @@ private:
|
|
|
|
|
unsigned int burstlength;
|
|
|
|
|
unsigned int dataLength;
|
|
|
|
|
sc_time playerClk; // May be different from the memory clock!
|
|
|
|
|
|
|
|
|
|
std::vector<LineContent> lineContents;
|
|
|
|
|
std::vector<LineContent>::const_iterator lineIterator;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // STLPLAYER_H
|
|
|
|
|
|
|
|
|
|
|