summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/tlm/sc_ext.cc1
-rw-r--r--util/tlm/sc_ext.hh4
-rw-r--r--util/tlm/sc_master_port.cc90
-rw-r--r--util/tlm/sc_master_port.hh8
-rw-r--r--util/tlm/sc_slave_port.cc22
5 files changed, 102 insertions, 23 deletions
diff --git a/util/tlm/sc_ext.cc b/util/tlm/sc_ext.cc
index db0c36f03..439e1ca15 100644
--- a/util/tlm/sc_ext.cc
+++ b/util/tlm/sc_ext.cc
@@ -45,6 +45,7 @@ namespace Gem5SystemC
Gem5Extension::Gem5Extension(PacketPtr packet)
{
Packet = packet;
+ pipeThrough = false;
}
Gem5Extension& Gem5Extension::getExtension(const tlm_generic_payload *payload)
diff --git a/util/tlm/sc_ext.hh b/util/tlm/sc_ext.hh
index 79416f5ce..970a1b73d 100644
--- a/util/tlm/sc_ext.hh
+++ b/util/tlm/sc_ext.hh
@@ -62,8 +62,12 @@ class Gem5Extension: public tlm::tlm_extension<Gem5Extension>
getExtension(const tlm::tlm_generic_payload &payload);
PacketPtr getPacket();
+ bool isPipeThrough() const { return pipeThrough; }
+ void setPipeThrough() { pipeThrough = true; }
+
private:
PacketPtr Packet;
+ bool pipeThrough;
};
}
diff --git a/util/tlm/sc_master_port.cc b/util/tlm/sc_master_port.cc
index 4ab1f51c6..5f3950260 100644
--- a/util/tlm/sc_master_port.cc
+++ b/util/tlm/sc_master_port.cc
@@ -36,6 +36,7 @@
#include "master_transactor.hh"
#include "params/ExternalMaster.hh"
+#include "sc_ext.hh"
#include "sc_master_port.hh"
#include "sim/system.hh"
@@ -87,6 +88,7 @@ SCMasterPort::SCMasterPort(const std::string& name_,
peq(this, &SCMasterPort::peq_cb),
waitForRetry(false),
pendingRequest(nullptr),
+ pendingPacket(nullptr),
needToSendRetry(false),
responseInProgress(false),
transactor(nullptr),
@@ -158,6 +160,7 @@ SCMasterPort::nb_transport_fw(tlm::tlm_generic_payload& trans,
}
// ... and queue the valid transaction
+ trans.acquire();
peq.notify(trans, phase, delay);
return tlm::TLM_ACCEPTED;
}
@@ -191,18 +194,35 @@ SCMasterPort::handleBeginReq(tlm::tlm_generic_payload& trans)
{
sc_assert(!waitForRetry);
sc_assert(pendingRequest == nullptr);
+ sc_assert(pendingPacket == nullptr);
trans.acquire();
- auto pkt = generatePacket(trans);
+
+ PacketPtr pkt = nullptr;
+
+ Gem5Extension* extension = nullptr;
+ trans.get_extension(extension);
+
+ // If there is an extension, this transaction was initiated by the gem5
+ // world and we can pipe through the original packet. Otherwise, we
+ // generate a new packet based on the transaction.
+ if (extension != nullptr) {
+ extension->setPipeThrough();
+ pkt = extension->getPacket();
+ } else {
+ pkt = generatePacket(trans);
+ }
auto tlmSenderState = new TlmSenderState(trans);
pkt->pushSenderState(tlmSenderState);
if (sendTimingReq(pkt)) { // port is free -> send END_REQ immediately
sendEndReq(trans);
+ trans.release();
} else { // port is blocked -> wait for retry before sending END_REQ
waitForRetry = true;
pendingRequest = &trans;
+ pendingPacket = pkt;
}
}
@@ -236,11 +256,25 @@ void
SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
sc_core::sc_time& t)
{
- auto pkt = generatePacket(trans);
+ Gem5Extension* extension = nullptr;
+ trans.get_extension(extension);
+
+ PacketPtr pkt = nullptr;
+
+ // If there is an extension, this transaction was initiated by the gem5
+ // world and we can pipe through the original packet.
+ if (extension != nullptr) {
+ extension->setPipeThrough();
+ pkt = extension->getPacket();
+ } else {
+ pkt = generatePacket(trans);
+ }
- // send an atomic request to gem5
Tick ticks = sendAtomic(pkt);
- panic_if(!pkt->isResponse(), "Packet sending failed!\n");
+
+ // send an atomic request to gem5
+ panic_if(pkt->needsResponse() && !pkt->isResponse(),
+ "Packet sending failed!\n");
// one tick is a pico second
auto delay =
@@ -249,7 +283,8 @@ SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
// update time
t += delay;
- destroyPacket(pkt);
+ if (extension != nullptr)
+ destroyPacket(pkt);
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
@@ -257,11 +292,19 @@ SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
unsigned int
SCMasterPort::transport_dbg(tlm::tlm_generic_payload& trans)
{
- auto pkt = generatePacket(trans);
-
- sendFunctional(pkt);
-
- destroyPacket(pkt);
+ Gem5Extension* extension = nullptr;
+ trans.get_extension(extension);
+
+ // If there is an extension, this transaction was initiated by the gem5
+ // world and we can pipe through the original packet.
+ if (extension != nullptr) {
+ extension->setPipeThrough();
+ sendFunctional(extension->getPacket());
+ } else {
+ auto pkt = generatePacket(trans);
+ sendFunctional(pkt);
+ destroyPacket(pkt);
+ }
return trans.get_data_length();
}
@@ -291,11 +334,22 @@ SCMasterPort::recvTimingResp(PacketPtr pkt)
sc_core::sc_time::from_value(pkt->payloadDelay + pkt->headerDelay);
auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState());
+ sc_assert(tlmSenderState != nullptr);
+
auto& trans = tlmSenderState->trans;
+ Gem5Extension* extension = nullptr;
+ trans.get_extension(extension);
+
// clean up
delete tlmSenderState;
- destroyPacket(pkt);
+
+ // If there is an extension the packet was piped through and we must not
+ // delete it. The packet travels back with the transaction.
+ if (extension == nullptr)
+ destroyPacket(pkt);
+ else
+ sc_assert(extension->isPipeThrough());
sendBeginResp(trans, delay);
trans.release();
@@ -330,14 +384,18 @@ SCMasterPort::recvReqRetry()
{
sc_assert(waitForRetry);
sc_assert(pendingRequest != nullptr);
+ sc_assert(pendingPacket != nullptr);
- auto& trans = *pendingRequest;
+ if (sendTimingReq(pendingPacket)) {
+ waitForRetry = false;
+ pendingPacket = nullptr;
- waitForRetry = false;
- pendingRequest = nullptr;
+ auto& trans = *pendingRequest;
+ sendEndReq(trans);
+ trans.release();
- // retry
- handleBeginReq(trans);
+ pendingRequest = nullptr;
+ }
}
void
diff --git a/util/tlm/sc_master_port.hh b/util/tlm/sc_master_port.hh
index 5fae9b6b4..a1ab3a8f2 100644
--- a/util/tlm/sc_master_port.hh
+++ b/util/tlm/sc_master_port.hh
@@ -59,6 +59,13 @@ class Gem5MasterTransactor;
* added as a sender state to the gem5 packet. This way the payload can be
* restored when the response packet arrives at the port.
*
+ * Special care is required, when the TLM transaction originates from a
+ * SCSlavePort (i.e. it is a gem5 packet that enters back into the gem5 world).
+ * This is a common scenario, when multiple gem5 CPUs communicate via a SystemC
+ * interconnect. In this case, the master port restores the original packet
+ * from the payload extension (added by the SCSlavePort) and forwards it to the
+ * gem5 world. Throughout the code, this mechanism is called 'pipe through'.
+ *
* If gem5 operates in atomic mode, the master port registers the TLM blocking
* interface and automatically translates non-blocking requests to blocking.
* If gem5 operates in timing mode, the transactor registers the non-blocking
@@ -82,6 +89,7 @@ class SCMasterPort : public ExternalMaster::Port
bool waitForRetry;
tlm::tlm_generic_payload* pendingRequest;
+ PacketPtr pendingPacket;
bool needToSendRetry;
diff --git a/util/tlm/sc_slave_port.cc b/util/tlm/sc_slave_port.cc
index cc4218fc0..b62c64724 100644
--- a/util/tlm/sc_slave_port.cc
+++ b/util/tlm/sc_slave_port.cc
@@ -265,16 +265,26 @@ SCSlavePort::pec(
{
CAUGHT_UP;
- PacketPtr packet = Gem5Extension::getExtension(trans).getPacket();
+ auto& extension = Gem5Extension::getExtension(trans);
+ auto packet = extension.getPacket();
sc_assert(!blockingResponse);
- bool need_retry;
- if (packet->needsResponse()) {
+ bool need_retry = false;
+
+ /*
+ * If the packet was piped through and needs a response, we don't need
+ * to touch the packet and can forward it directly as a response.
+ * Otherwise, we need to make a response and send the transformed
+ * packet.
+ */
+ if (extension.isPipeThrough()) {
+ if (packet->isResponse()) {
+ need_retry = !sendTimingResp(packet);
+ }
+ } else if (packet->needsResponse()) {
packet->makeResponse();
need_retry = !sendTimingResp(packet);
- } else {
- need_retry = false;
}
if (need_retry) {
@@ -289,8 +299,6 @@ SCSlavePort::pec(
trans.release();
}
}
- } else {
- SC_REPORT_FATAL("SCSlavePort", "Invalid protocol phase in pec");
}
delete pe;
}