First working implementation.

This commit is contained in:
Lukas Steiner
2022-05-09 13:09:19 +02:00
parent d41f3d8578
commit e9942d5aa2
6 changed files with 358 additions and 56 deletions

View File

@@ -119,22 +119,41 @@ void TlmRecorder::recordPhase(tlm_generic_payload& trans, const tlm_phase& phase
{
const sc_time& currentTime = sc_time_stamp();
if (currentTransactionsInSystem.find(&trans) == currentTransactionsInSystem.end())
introduceTransactionSystem(trans);
if (phase == BEGIN_REQ || phase == BEGIN_RESP)
if (phase == BEGIN_REQ)
{
introduceTransactionToSystem(trans);
std::string phaseName = getPhaseName(phase).substr(6);
currentTransactionsInSystem.at(&trans).recordedPhases.emplace_back(phaseName, currentTime + delay);
}
if (phase == BEGIN_RESP)
{
std::string phaseName = getPhaseName(phase).substr(6);
currentTransactionsInSystem.at(&trans).recordedPhases.emplace_back(phaseName, currentTime + delay);
}
else if (phase == END_REQ || phase == END_RESP)
else if (phase == END_REQ)
{
assert(getPhaseName(phase).substr(4) == currentTransactionsInSystem.at(&trans).recordedPhases.back().name);
// TODO: this assumes that the controller does not start with a transaction until END_REQ has been sent, which is not true any more for big transactions
// BEGIN_REQ is always the first phase of a normal transaction
currentTransactionsInSystem.at(&trans).recordedPhases.front().interval.end = currentTime + delay;
}
else if (phase == END_RESP)
{
// BEGIN_RESP is always the last phase of a normal transaction at this point
currentTransactionsInSystem.at(&trans).recordedPhases.back().interval.end = currentTime + delay;
}
else if (isFixedCommandPhase(phase))
{
tlm_generic_payload* keyTrans;
if (ChildExtension::isChildTrans(trans))
{
keyTrans = &trans.get_extension<ChildExtension>()->getParentTrans();
}
else
{
if (currentTransactionsInSystem.find(&trans) == currentTransactionsInSystem.end())
introduceTransactionToSystem(trans);
keyTrans = &trans;
}
std::string phaseName = getPhaseName(phase).substr(6); // remove "BEGIN_"
const ControllerExtension& extension = ControllerExtension::getExtension(trans);
TimeInterval intervalOnDataStrobe;
@@ -145,7 +164,7 @@ void TlmRecorder::recordPhase(tlm_generic_payload& trans, const tlm_phase& phase
intervalOnDataStrobe.end = currentTime + intervalOnDataStrobe.end;
}
currentTransactionsInSystem.at(&trans).recordedPhases.emplace_back(std::move(phaseName),
currentTransactionsInSystem.at(keyTrans).recordedPhases.emplace_back(std::move(phaseName),
std::move(TimeInterval(currentTime + delay,
currentTime + delay + memSpec.getExecutionTime(Command(phase), trans))),
std::move(intervalOnDataStrobe), extension.getRank(), extension.getBankGroup(), extension.getBank(),
@@ -181,7 +200,7 @@ void TlmRecorder::recordDebugMessage(const std::string &message, const sc_time &
// ------------- internal -----------------------
void TlmRecorder::introduceTransactionSystem(tlm_generic_payload& trans)
void TlmRecorder::introduceTransactionToSystem(tlm_generic_payload& trans)
{
totalNumTransactions++;

View File

@@ -136,7 +136,7 @@ private:
void openDB(const std::string &dbName);
void closeConnection();
void introduceTransactionSystem(tlm::tlm_generic_payload &trans);
void introduceTransactionToSystem(tlm::tlm_generic_payload &trans);
void removeTransactionFromSystem(tlm::tlm_generic_payload &trans);
void terminateRemainingTransactions();

View File

@@ -360,3 +360,103 @@ bool operator !=(const Column &lhs, const Column &rhs)
{
return !(lhs == rhs);
}
tlm::tlm_extension_base* ChildExtension::clone() const
{
return new ChildExtension(*parentTrans);
}
void ChildExtension::copy_from(const tlm::tlm_extension_base& ext)
{
const auto& cpyFrom = dynamic_cast<const ChildExtension&>(ext);
parentTrans = cpyFrom.parentTrans;
}
tlm::tlm_generic_payload& ChildExtension::getParentTrans()
{
return *parentTrans;
}
void ChildExtension::setExtension(tlm::tlm_generic_payload& childTrans, tlm::tlm_generic_payload& parentTrans)
{
auto* extension = childTrans.get_extension<ChildExtension>();
if (extension != nullptr)
{
extension->parentTrans = &parentTrans;
}
else
{
extension = new ChildExtension(parentTrans);
childTrans.set_auto_extension(extension);
}
}
bool ChildExtension::isChildTrans(const tlm::tlm_generic_payload& trans)
{
if (trans.get_extension<ChildExtension>() != nullptr)
return true;
else
return false;
}
bool ChildExtension::notifyChildTransCompletion()
{
return parentTrans->get_extension<ParentExtension>()->notifyChildTransCompletion();
}
tlm_extension_base* ParentExtension::clone() const
{
return new ParentExtension(childTranses);
}
void ParentExtension::copy_from(const tlm_extension_base& ext)
{
const auto& cpyFrom = dynamic_cast<const ParentExtension&>(ext);
childTranses = cpyFrom.childTranses;
}
bool ParentExtension::isParentTrans(const tlm::tlm_generic_payload& trans)
{
auto* extension = trans.get_extension<ParentExtension>();
if (extension != nullptr)
return !extension->childTranses.empty();
else
return false;
}
void ParentExtension::setExtension(tlm::tlm_generic_payload& parentTrans, std::vector<tlm::tlm_generic_payload*> childTranses)
{
auto* extension = parentTrans.get_extension<ParentExtension>();
if (extension != nullptr)
{
extension->childTranses = std::move(childTranses);
extension->nextEndReqChildId = 0;
extension->completedChildTranses = 0;
}
else
{
extension = new ParentExtension(std::move(childTranses));
parentTrans.set_auto_extension(extension);
}
}
const std::vector<tlm::tlm_generic_payload*>& ParentExtension::getChildTranses()
{
return childTranses;
}
bool ParentExtension::notifyChildTransCompletion()
{
completedChildTranses++;
return completedChildTranses == childTranses.size();
}
void ParentExtension::releaseChildTranses()
{
std::for_each(childTranses.begin(), childTranses.end(),
[](tlm::tlm_generic_payload* childTrans){childTrans->release();});
childTranses.clear();
}

View File

@@ -252,4 +252,42 @@ bool operator!=(const Row &lhs, const Row &rhs);
bool operator==(const Column &lhs, const Column &rhs);
bool operator!=(const Column &lhs, const Column &rhs);
class ChildExtension : public tlm::tlm_extension<ChildExtension>
{
private:
tlm::tlm_generic_payload* parentTrans;
explicit ChildExtension(tlm::tlm_generic_payload& parentTrans) : parentTrans(&parentTrans) {}
public:
//ChildExtension() = delete;
tlm::tlm_extension_base* clone() const override;
void copy_from(const tlm::tlm_extension_base& ext) override;
tlm::tlm_generic_payload& getParentTrans();
static void setExtension(tlm::tlm_generic_payload& childTrans, tlm::tlm_generic_payload& parentTrans);
static bool isChildTrans(const tlm::tlm_generic_payload& trans);
bool notifyChildTransCompletion();
};
class ParentExtension : public tlm::tlm_extension<ParentExtension>
{
private:
std::vector<tlm::tlm_generic_payload*> childTranses;
unsigned nextEndReqChildId = 0;
unsigned completedChildTranses = 0;
explicit ParentExtension(std::vector<tlm::tlm_generic_payload*> _childTranses)
: childTranses(std::move(_childTranses)) {}
public:
ParentExtension() = delete;
tlm_extension_base* clone() const override;
void copy_from(const tlm_extension_base& ext) override;
static bool isParentTrans(const tlm::tlm_generic_payload& trans);
static void setExtension(tlm::tlm_generic_payload& parentTrans, std::vector<tlm::tlm_generic_payload*> childTranses);
const std::vector<tlm::tlm_generic_payload*>& getChildTranses();
bool notifyChildTransCompletion();
void releaseChildTranses();
};
#endif // DRAMEXTENSIONS_H

View File

@@ -72,7 +72,8 @@ using namespace tlm;
Controller::Controller(const sc_module_name& name, const Configuration& config, const AddressDecoder& addressDecoder) :
ControllerIF(name, config), addressDecoder(addressDecoder),
thinkDelayFw(config.thinkDelayFw), thinkDelayBw(config.thinkDelayBw),
phyDelayFw(config.phyDelayFw), phyDelayBw(config.phyDelayBw)
phyDelayFw(config.phyDelayFw), phyDelayBw(config.phyDelayBw),
maxBytesPerBurst(config.memSpec->maxBytesPerBurst)
{
SC_METHOD(controllerMethod);
sensitive << beginReqEvent << endRespEvent << controllerEvent << dataResponseEvent;
@@ -370,13 +371,6 @@ tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &trans,
transToAcquire.payload = &trans;
transToAcquire.time = sc_time_stamp() + delay;
beginReqEvent.notify(delay);
DecodedAddress decodedAddress = addressDecoder.decodeAddress(transToAcquire.payload->get_address());
ControllerExtension::setAutoExtension(*transToAcquire.payload, nextChannelPayloadIDToAppend++,
Rank(decodedAddress.rank), BankGroup(decodedAddress.bankgroup),
Bank(decodedAddress.bank), Row(decodedAddress.row),
Column(decodedAddress.column),
transToAcquire.payload->get_data_length() / memSpec.bytesPerBeat);
}
else if (phase == END_RESP)
{
@@ -408,34 +402,62 @@ void Controller::manageRequests(const sc_time &delay)
{
if (transToAcquire.payload != nullptr && transToAcquire.time <= sc_time_stamp())
{
// Check size of transaction
// unsigned numSubTrans = transToAcquire.payload->get_data_length() / memSpec.maxBytesPerBurst;
// if (numSubTrans > 1)
// {
// // Split create child transactions
// // Address decoding!!!
// }
// TODO: here we assume that the scheduler always has space not only for a single burst transaction but for a maximum size transaction
if (scheduler->hasBufferSpace())
{
NDEBUG_UNUSED(uint64_t id) = ControllerExtension::getChannelPayloadID(*transToAcquire.payload);
PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " entered system.");
//NDEBUG_UNUSED(uint64_t id) = ControllerExtension::getChannelPayloadID(*transToAcquire.payload);
//PRINTDEBUGMESSAGE(name(), "Payload " + std::to_string(id) + " entered system.");
if (totalNumberOfPayloads == 0)
idleTimeCollector.end();
totalNumberOfPayloads++;
totalNumberOfPayloads++; // seems to be ok
Rank rank = ControllerExtension::getRank(*transToAcquire.payload);
if (ranksNumberOfPayloads[rank.ID()] == 0)
powerDownManagers[rank.ID()]->triggerExit();
ranksNumberOfPayloads[rank.ID()]++;
scheduler->storeRequest(*transToAcquire.payload);
transToAcquire.payload->acquire();
Bank bank = ControllerExtension::getBank(*transToAcquire.payload);
bankMachines[bank.ID()]->start();
unsigned numChildTranses = transToAcquire.payload->get_data_length() / maxBytesPerBurst;
if (numChildTranses <= 1)
{
DecodedAddress decodedAddress = addressDecoder.decodeAddress(transToAcquire.payload->get_address());
ControllerExtension::setAutoExtension(*transToAcquire.payload, nextChannelPayloadIDToAppend++,
Rank(decodedAddress.rank), BankGroup(decodedAddress.bankgroup),
Bank(decodedAddress.bank), Row(decodedAddress.row),
Column(decodedAddress.column),
transToAcquire.payload->get_data_length() / memSpec.bytesPerBeat);
Rank rank = Rank(decodedAddress.rank);
if (ranksNumberOfPayloads[rank.ID()] == 0)
powerDownManagers[rank.ID()]->triggerExit();
ranksNumberOfPayloads[rank.ID()]++;
scheduler->storeRequest(*transToAcquire.payload);
Bank bank = Bank(decodedAddress.bank);
bankMachines[bank.ID()]->start();
}
else
{
createChildTranses(*transToAcquire.payload, numChildTranses);
const std::vector<tlm_generic_payload*>& childTranses =
transToAcquire.payload->get_extension<ParentExtension>()->getChildTranses();
for (auto* childTrans : childTranses)
{
DecodedAddress decodedAddress = addressDecoder.decodeAddress(childTrans->get_address());
ControllerExtension::setAutoExtension(*childTrans, nextChannelPayloadIDToAppend,
Rank(decodedAddress.rank), BankGroup(decodedAddress.bankgroup),
Bank(decodedAddress.bank), Row(decodedAddress.row),
Column(decodedAddress.column),
childTrans->get_data_length() / memSpec.bytesPerBeat);
Rank rank = Rank(decodedAddress.rank);
if (ranksNumberOfPayloads[rank.ID()] == 0)
powerDownManagers[rank.ID()]->triggerExit();
ranksNumberOfPayloads[rank.ID()]++;
scheduler->storeRequest(*childTrans);
Bank bank = Bank(decodedAddress.bank);
bankMachines[bank.ID()]->start();
}
nextChannelPayloadIDToAppend++;
}
transToAcquire.payload->set_response_status(TLM_OK_RESPONSE);
tlm_phase bwPhase = END_REQ;
@@ -463,7 +485,7 @@ void Controller::manageResponses()
numberOfBeatsServed += ControllerExtension::getBurstLength(*transToRelease.payload);
transToRelease.payload->release();
transToRelease.payload = nullptr;
totalNumberOfPayloads--;
totalNumberOfPayloads--; // Important!! has to be done once for parent transaction
if (totalNumberOfPayloads == 0)
{
@@ -471,15 +493,42 @@ void Controller::manageResponses()
}
else
{
transToRelease.payload = respQueue->nextPayload();
// TODO: hier fehlt noch was
tlm_generic_payload* nextPayloadInQueue = respQueue->nextPayload();
//transToRelease.payload = respQueue->nextPayload();
if (transToRelease.payload != nullptr)
if (nextPayloadInQueue != nullptr)
{
// last payload was released in this cycle
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = memSpec.tCK;
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
if (ChildExtension::isChildTrans(*nextPayloadInQueue))
{
tlm_generic_payload& parentTrans = nextPayloadInQueue->get_extension<ChildExtension>()->getParentTrans();
bool allChildTransesCompleted = parentTrans.get_extension<ParentExtension>()->notifyChildTransCompletion();
if (allChildTransesCompleted)
{
parentTrans.get_extension<ParentExtension>()->releaseChildTranses();
transToRelease.payload = &parentTrans;
// last payload was released in this cycle
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = memSpec.tCK;
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
}
else
{
sc_time triggerTime = respQueue->getTriggerTime();
if (triggerTime != sc_max_time())
dataResponseEvent.notify(triggerTime - sc_time_stamp());
}
}
else
{
transToRelease.payload = nextPayloadInQueue;
// last payload was released in this cycle
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay = memSpec.tCK;
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
}
}
else
{
@@ -492,19 +541,50 @@ void Controller::manageResponses()
}
else
{
transToRelease.payload = respQueue->nextPayload();
tlm_generic_payload* nextPayloadInQueue = respQueue->nextPayload();
if (transToRelease.payload != nullptr)
if (nextPayloadInQueue != nullptr)
{
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay;
if (transToRelease.time == sc_time_stamp()) // last payload was released in this cycle
bwDelay = memSpec.tCK;
else
bwDelay = SC_ZERO_TIME;
if (ChildExtension::isChildTrans(*nextPayloadInQueue))
{
tlm_generic_payload& parentTrans = nextPayloadInQueue->get_extension<ChildExtension>()->getParentTrans();
bool allChildTransesCompleted = parentTrans.get_extension<ParentExtension>()->notifyChildTransCompletion();
if (allChildTransesCompleted)
{
parentTrans.get_extension<ParentExtension>()->releaseChildTranses();
transToRelease.payload = &parentTrans;
// last payload was released in this cycle
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay;
if (transToRelease.time == sc_time_stamp()) // last payload was released in this cycle
bwDelay = memSpec.tCK;
else
bwDelay = SC_ZERO_TIME;
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
}
else
{
sc_time triggerTime = respQueue->getTriggerTime();
if (triggerTime != sc_max_time())
dataResponseEvent.notify(triggerTime - sc_time_stamp());
}
}
else
{
transToRelease.payload = nextPayloadInQueue;
// last payload was released in this cycle
tlm_phase bwPhase = BEGIN_RESP;
sc_time bwDelay;
if (transToRelease.time == sc_time_stamp()) // last payload was released in this cycle
bwDelay = memSpec.tCK;
else
bwDelay = SC_ZERO_TIME;
sendToFrontend(*transToRelease.payload, bwPhase, bwDelay);
transToRelease.time = sc_max_time();
}
}
else
{
@@ -519,3 +599,52 @@ void Controller::sendToFrontend(tlm_generic_payload& payload, tlm_phase& phase,
{
tSocket->nb_transport_bw(payload, phase, delay);
}
Controller::MemoryManager::~MemoryManager()
{
while (!freePayloads.empty())
{
tlm_generic_payload* payload = freePayloads.top();
freePayloads.pop();
payload->reset();
delete payload;
}
}
tlm::tlm_generic_payload& Controller::MemoryManager::allocate()
{
if (freePayloads.empty())
{
return *new tlm_generic_payload(this);
}
else
{
tlm_generic_payload* result = freePayloads.top();
freePayloads.pop();
return *result;
}
}
void Controller::MemoryManager::free(tlm::tlm_generic_payload* payload)
{
freePayloads.push(payload);
}
void Controller::createChildTranses(tlm::tlm_generic_payload& parentTrans, unsigned int numChildTranses)
{
std::vector<tlm_generic_payload*> childTranses;
for (unsigned childId = 0; childId < numChildTranses; childId++)
{
tlm_generic_payload& childTrans = memoryManager.allocate();
childTrans.acquire();
childTrans.set_command(parentTrans.get_command());
childTrans.set_address(parentTrans.get_address() + childId * maxBytesPerBurst);
childTrans.set_data_length(maxBytesPerBurst);
childTrans.set_data_ptr(parentTrans.get_data_ptr() + childId * maxBytesPerBurst);
ChildExtension::setExtension(childTrans, parentTrans);
childTranses.push_back(&childTrans);
}
ParentExtension::setExtension(parentTrans, std::move(childTranses));
}

View File

@@ -37,6 +37,7 @@
#include <vector>
#include <stack>
#include <systemc>
#include <tlm>
@@ -100,6 +101,21 @@ private:
void manageRequests(const sc_core::sc_time &delay);
sc_core::sc_event beginReqEvent, endRespEvent, controllerEvent, dataResponseEvent;
const unsigned maxBytesPerBurst;
void createChildTranses(tlm::tlm_generic_payload& parentTrans, unsigned numChildTranses);
class MemoryManager : public tlm::tlm_mm_interface
{
public:
~MemoryManager() override;
tlm::tlm_generic_payload& allocate();
void free(tlm::tlm_generic_payload* payload) override;
private:
std::stack<tlm::tlm_generic_payload*> freePayloads;
} memoryManager;
};
#endif // CONTROLLER_H