Removed arbiter's send methods to implement early completion.

This commit is contained in:
Lukas Steiner
2020-04-30 11:30:47 +02:00
parent f8b4e5b432
commit eb265f4bdd
3 changed files with 51 additions and 50 deletions

View File

@@ -333,18 +333,16 @@ void Controller::controllerMethod()
tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &trans,
tlm_phase &phase, sc_time &delay)
{
sc_time notificationDelay = delay;
sc_time notificationDelay = delay + Configuration::getInstance().memSpec->tCK;
if (phase == BEGIN_REQ)
{
notificationDelay += Configuration::getInstance().memSpec->tCK;
payloadToAcquire = &trans;
timeToAcquire = sc_time_stamp() + notificationDelay;
beginReqEvent.notify(notificationDelay);
}
else if (phase = END_RESP)
{
notificationDelay += Configuration::getInstance().memSpec->tCK;
timeToRelease = sc_time_stamp() + notificationDelay;
endRespEvent.notify(notificationDelay);
}

View File

@@ -76,6 +76,7 @@ tlm_sync_enum Arbiter::nb_transport_fw(int id, tlm_generic_payload &payload,
if (phase == BEGIN_REQ)
{
// TODO: do not adjust address permanently
// adjust address offset:
payload.set_address(payload.get_address() -
Configuration::getInstance().addressOffset);
@@ -103,8 +104,7 @@ tlm_sync_enum Arbiter::nb_transport_bw(int channelId, tlm_generic_payload &paylo
tlm_phase &phase, sc_time &bwDelay)
{
// Check channel ID
if ((unsigned int)channelId != DramExtension::getExtension(payload).getChannel().ID())
SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted");
assert((unsigned int)channelId == DramExtension::getExtension(payload).getChannel().ID());
PRINTDEBUGMESSAGE(name(), "[bw] " + phaseNameToString(phase) + " notification in " +
bwDelay.to_string());
@@ -124,39 +124,51 @@ unsigned int Arbiter::transport_dbg(int /*id*/, tlm::tlm_generic_payload &trans)
void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase)
{
unsigned int initiatorSocket = DramExtension::getExtension(
payload).getThread().ID();
unsigned int threadId = DramExtension::getExtension(payload).getThread().ID();
unsigned int channelId = DramExtension::getExtension(payload).getChannel().ID();
// Check the valid range of initiatorSocket ID and channel Id
// TODO: initiatorSocket ID not checked
// Check the valid range of thread ID and channel Id
// TODO: thread ID not checked
assert(channelId < Configuration::getInstance().numberOfMemChannels);
// Phases initiated by the intiator side from arbiter's point of view (devices performing memory requests to the arbiter)
if (phase == BEGIN_REQ)
{
if (channelIsFree[channelId]) {
if (channelIsFree[channelId])
{
// This channel was available. Forward the new transaction to the memory controller.
channelIsFree[channelId] = false;
sendToChannel(channelId, payload, phase, SC_ZERO_TIME);
} else {
tlm_phase tPhase = phase;
sc_time tDelay = SC_ZERO_TIME;
iSocket[channelId]->nb_transport_fw(payload, tPhase, tDelay);
// TODO: early completion of channel controller!!!
}
else
{
// This channel is busy. Enqueue the new transaction which phase is BEGIN_REQ.
pendingRequests[channelId].push(&payload);
}
}
// Phases initiated by the target side from arbiter's point of view (memory side)
else if (phase == END_REQ) {
else if (phase == END_REQ)
{
channelIsFree[channelId] = true;
// The arbiter receives a transaction which phase is END_REQ from memory controller and forwards it to the requester device.
sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME);
tlm_phase tPhase = phase;
sc_time tDelay = SC_ZERO_TIME;
tSocket[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()) {
tlm_generic_payload *payloadToSend = pendingRequests[channelId].front();
pendingRequests[channelId].pop();
if (!pendingRequests[channelId].empty())
{
// Send ONE of the enqueued new transactions (phase is BEGIN_REQ) through this channel.
sendToChannel(channelId, *payloadToSend, BEGIN_REQ, SC_ZERO_TIME);
tlm_generic_payload &payloadToSend = *pendingRequests[channelId].front();
pendingRequests[channelId].pop();
tlm_phase tPhase = BEGIN_REQ;
sc_time tDelay = SC_ZERO_TIME;
iSocket[channelId]->nb_transport_fw(payloadToSend, tPhase, tDelay);
// TODO: early completion of channel controller
// Mark the channel as busy again.
channelIsFree[channelId] = false;
}
@@ -166,26 +178,39 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase)
// The arbiter receives a transaction in BEGIN_RESP phase
// (that came from the memory side) and forwards it to the requester
// device
if (receivedResponses[initiatorSocket].empty()) {
sendToInitiator(initiatorSocket, payload, phase, SC_ZERO_TIME);
if (pendingResponses[threadId].empty())
{
tlm_phase tPhase = phase;
sc_time tDelay = SC_ZERO_TIME;
tSocket[threadId]->nb_transport_bw(payload, tPhase, tDelay);
// TODO: early completion of initiator!!!
}
// Enqueue the transaction in BEGIN_RESP phase until the initiator
// device acknowledge it (phase changes to END_RESP).
receivedResponses[initiatorSocket].push(&payload);
// device acknowledges it (phase changes to END_RESP).
pendingResponses[threadId].push(&payload);
}
else if (phase == END_RESP)
{
// Send the END_RESP message to the memory
sendToChannel(channelId, payload, phase, SC_ZERO_TIME);
{
tlm_phase tPhase = phase;
sc_time tDelay = SC_ZERO_TIME;
iSocket[channelId]->nb_transport_fw(payload, tPhase, tDelay);
}
// Drop one element of the queue of BEGIN_RESP from memory to this device
receivedResponses[initiatorSocket].pop();
pendingResponses[threadId].pop();
// Check if there are queued transactoins with phase BEGIN_RESP from memory to this device
if (!receivedResponses[initiatorSocket].empty()) {
if (!pendingResponses[threadId].empty())
{
// The queue is not empty.
tlm_generic_payload *payloadToSend = receivedResponses[initiatorSocket].front();
tlm_generic_payload &payloadToSend = *pendingResponses[threadId].front();
// Send ONE extra BEGIN_RESP to the device
sendToInitiator(initiatorSocket, *payloadToSend, BEGIN_RESP, SC_ZERO_TIME);
tlm_phase tPhase = BEGIN_RESP;
sc_time tDelay = SC_ZERO_TIME;
tSocket[threadId]->nb_transport_bw(payloadToSend, tPhase, tDelay);
// TODO: early completion of initiator!!!
}
}
else
@@ -193,22 +218,6 @@ void Arbiter::peqCallback(tlm_generic_payload &payload, const tlm_phase &phase)
"Payload event queue in arbiter was triggered with unknown phase");
}
void Arbiter::sendToChannel(unsigned int channelId, tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay)
{
tlm_phase TPhase = phase;
sc_time TDelay = delay;
iSocket[channelId]->nb_transport_fw(payload, TPhase, TDelay);
}
void Arbiter::sendToInitiator(unsigned int id, tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay)
{
tlm_phase TPhase = phase;
sc_time TDelay = delay;
tSocket[id]->nb_transport_bw(payload, TPhase, TDelay);
}
void Arbiter::appendDramExtension(int socketId, tlm_generic_payload &payload)
{
// Append Generation Extension

View File

@@ -71,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 *>> receivedResponses;
std::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
@@ -87,12 +87,6 @@ private:
void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase);
void sendToChannel(unsigned int channelId, tlm::tlm_generic_payload &payload,
const tlm::tlm_phase &phase, const sc_time &delay);
void sendToInitiator(unsigned int id, tlm::tlm_generic_payload &payload,
const tlm::tlm_phase &phase, const sc_time &delay);
void appendDramExtension(int socketId, tlm::tlm_generic_payload &payload);
std::vector<uint64_t> nextPayloadID;
};