Merge branch 'develop' into DDR5

This commit is contained in:
Lukas Steiner
2020-10-22 14:10:24 +02:00
16 changed files with 426 additions and 351 deletions

View File

@@ -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)

View File

@@ -88,10 +88,11 @@ private:
std::vector<RefreshManagerIF *> refreshManagers;
std::vector<PowerDownManagerIF *> 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();

View File

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

View File

@@ -43,6 +43,7 @@
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <tlm_utils/multi_passthrough_target_socket.h>
#include <tlm_utils/multi_passthrough_initiator_socket.h>
#include <tlm_utils/peq_with_cb_and_phase.h>
@@ -70,7 +71,7 @@ private:
std::vector<std::queue<tlm::tlm_generic_payload *>> 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<unsigned int, std::queue<tlm::tlm_generic_payload *>> pendingResponses;
std::unordered_map<unsigned int, std::queue<tlm::tlm_generic_payload *>> 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<uint64_t> nextPayloadID;
};

View File

@@ -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
)

View File

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

View File

@@ -52,6 +52,7 @@ private:
uint64_t numberOfAllocations;
uint64_t numberOfFrees;
std::vector<tlm::tlm_generic_payload *> freePayloads;
bool storageEnabled = false;
};
#endif // MEMORYMANAGER_H

View File

@@ -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<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

@@ -44,6 +44,7 @@
#include <vector>
#include <array>
#include <thread>
#include "TraceSetup.h"
#include "TracePlayer.h"
struct LineContent
@@ -54,186 +55,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());
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<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 +95,8 @@ private:
std::string line;
std::istringstream iss;
const bool relative;
};
#endif // STLPLAYER_H

View File

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

View File

@@ -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;

View File

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

View File

@@ -46,37 +46,35 @@
#include <tlm_utils/peq_with_cb_and_phase.h>
#include <iostream>
#include <string>
#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<TracePlayer> 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<TracePlayer> 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;
};

View File

@@ -35,10 +35,13 @@
*/
#include "TraceSetup.h"
#include "StlPlayer.h"
using namespace tlm;
TraceSetup::TraceSetup(std::string uri,
std::string pathToResources,
std::vector<TracePlayer *> *devices)
std::vector<TracePlayer *> *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<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);
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();
}

View File

@@ -38,28 +38,28 @@
#include <vector>
#include <string>
#include <tlm.h>
#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<TracePlayer *> *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

View File

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