diff options
-rw-r--r-- | util/tlm/sc_ext.cc | 1 | ||||
-rw-r--r-- | util/tlm/sc_ext.hh | 4 | ||||
-rw-r--r-- | util/tlm/sc_master_port.cc | 90 | ||||
-rw-r--r-- | util/tlm/sc_master_port.hh | 8 | ||||
-rw-r--r-- | util/tlm/sc_slave_port.cc | 22 |
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; } |