misc: Clean up and complete the gem5<->SystemC-TLM bridge [7/10]
The current TLM bridge only provides a Slave Port that allows the gem5 world to send request to the SystemC world. This patch series refractors and cleans up the existing code, and adds a Master Port that allows the SystemC world to send requests to the gem5 world. This patch: * Implement 'pipe through' for gem5 Packets (see explanation below) Basically, this patch ensures that all transactions that originated in the gem5 world are converted back to the original packet when entering the gem5 world. So far, this only worked for packets that are responded to by a SyctemC component (e.g. when a gem5 CPU sends a request to a SystemC memory). By implementing the 'pipe through' this patch ensures, that packets that are responded to by a gem5 component (e.g. when a gem5 CPU sends a request to a gem5 memory via a SystemC interconnect) are handled properly. Reviewed at http://reviews.gem5.org/r/3796/ Signed-off-by: Jason Lowe-Power <jason@lowepower.com>
This commit is contained in:
parent
03f740664b
commit
b5045005de
5 changed files with 101 additions and 22 deletions
|
@ -45,6 +45,7 @@ namespace Gem5SystemC
|
||||||
Gem5Extension::Gem5Extension(PacketPtr packet)
|
Gem5Extension::Gem5Extension(PacketPtr packet)
|
||||||
{
|
{
|
||||||
Packet = packet;
|
Packet = packet;
|
||||||
|
pipeThrough = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gem5Extension& Gem5Extension::getExtension(const tlm_generic_payload *payload)
|
Gem5Extension& Gem5Extension::getExtension(const tlm_generic_payload *payload)
|
||||||
|
|
|
@ -62,8 +62,12 @@ class Gem5Extension: public tlm::tlm_extension<Gem5Extension>
|
||||||
getExtension(const tlm::tlm_generic_payload &payload);
|
getExtension(const tlm::tlm_generic_payload &payload);
|
||||||
PacketPtr getPacket();
|
PacketPtr getPacket();
|
||||||
|
|
||||||
|
bool isPipeThrough() const { return pipeThrough; }
|
||||||
|
void setPipeThrough() { pipeThrough = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PacketPtr Packet;
|
PacketPtr Packet;
|
||||||
|
bool pipeThrough;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
#include "master_transactor.hh"
|
#include "master_transactor.hh"
|
||||||
#include "params/ExternalMaster.hh"
|
#include "params/ExternalMaster.hh"
|
||||||
|
#include "sc_ext.hh"
|
||||||
#include "sc_master_port.hh"
|
#include "sc_master_port.hh"
|
||||||
#include "sim/system.hh"
|
#include "sim/system.hh"
|
||||||
|
|
||||||
|
@ -87,6 +88,7 @@ SCMasterPort::SCMasterPort(const std::string& name_,
|
||||||
peq(this, &SCMasterPort::peq_cb),
|
peq(this, &SCMasterPort::peq_cb),
|
||||||
waitForRetry(false),
|
waitForRetry(false),
|
||||||
pendingRequest(nullptr),
|
pendingRequest(nullptr),
|
||||||
|
pendingPacket(nullptr),
|
||||||
needToSendRetry(false),
|
needToSendRetry(false),
|
||||||
responseInProgress(false),
|
responseInProgress(false),
|
||||||
transactor(nullptr),
|
transactor(nullptr),
|
||||||
|
@ -158,6 +160,7 @@ SCMasterPort::nb_transport_fw(tlm::tlm_generic_payload& trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... and queue the valid transaction
|
// ... and queue the valid transaction
|
||||||
|
trans.acquire();
|
||||||
peq.notify(trans, phase, delay);
|
peq.notify(trans, phase, delay);
|
||||||
return tlm::TLM_ACCEPTED;
|
return tlm::TLM_ACCEPTED;
|
||||||
}
|
}
|
||||||
|
@ -191,18 +194,35 @@ SCMasterPort::handleBeginReq(tlm::tlm_generic_payload& trans)
|
||||||
{
|
{
|
||||||
sc_assert(!waitForRetry);
|
sc_assert(!waitForRetry);
|
||||||
sc_assert(pendingRequest == nullptr);
|
sc_assert(pendingRequest == nullptr);
|
||||||
|
sc_assert(pendingPacket == nullptr);
|
||||||
|
|
||||||
trans.acquire();
|
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);
|
auto tlmSenderState = new TlmSenderState(trans);
|
||||||
pkt->pushSenderState(tlmSenderState);
|
pkt->pushSenderState(tlmSenderState);
|
||||||
|
|
||||||
if (sendTimingReq(pkt)) { // port is free -> send END_REQ immediately
|
if (sendTimingReq(pkt)) { // port is free -> send END_REQ immediately
|
||||||
sendEndReq(trans);
|
sendEndReq(trans);
|
||||||
|
trans.release();
|
||||||
} else { // port is blocked -> wait for retry before sending END_REQ
|
} else { // port is blocked -> wait for retry before sending END_REQ
|
||||||
waitForRetry = true;
|
waitForRetry = true;
|
||||||
pendingRequest = &trans;
|
pendingRequest = &trans;
|
||||||
|
pendingPacket = pkt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,11 +256,25 @@ void
|
||||||
SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
|
SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
|
||||||
sc_core::sc_time& t)
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tick ticks = sendAtomic(pkt);
|
||||||
|
|
||||||
// send an atomic request to gem5
|
// send an atomic request to gem5
|
||||||
Tick ticks = sendAtomic(pkt);
|
panic_if(pkt->needsResponse() && !pkt->isResponse(),
|
||||||
panic_if(!pkt->isResponse(), "Packet sending failed!\n");
|
"Packet sending failed!\n");
|
||||||
|
|
||||||
// one tick is a pico second
|
// one tick is a pico second
|
||||||
auto delay =
|
auto delay =
|
||||||
|
@ -249,7 +283,8 @@ SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
|
||||||
// update time
|
// update time
|
||||||
t += delay;
|
t += delay;
|
||||||
|
|
||||||
destroyPacket(pkt);
|
if (extension != nullptr)
|
||||||
|
destroyPacket(pkt);
|
||||||
|
|
||||||
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
trans.set_response_status(tlm::TLM_OK_RESPONSE);
|
||||||
}
|
}
|
||||||
|
@ -257,11 +292,19 @@ SCMasterPort::b_transport(tlm::tlm_generic_payload& trans,
|
||||||
unsigned int
|
unsigned int
|
||||||
SCMasterPort::transport_dbg(tlm::tlm_generic_payload& trans)
|
SCMasterPort::transport_dbg(tlm::tlm_generic_payload& trans)
|
||||||
{
|
{
|
||||||
auto pkt = generatePacket(trans);
|
Gem5Extension* extension = nullptr;
|
||||||
|
trans.get_extension(extension);
|
||||||
|
|
||||||
sendFunctional(pkt);
|
// If there is an extension, this transaction was initiated by the gem5
|
||||||
|
// world and we can pipe through the original packet.
|
||||||
destroyPacket(pkt);
|
if (extension != nullptr) {
|
||||||
|
extension->setPipeThrough();
|
||||||
|
sendFunctional(extension->getPacket());
|
||||||
|
} else {
|
||||||
|
auto pkt = generatePacket(trans);
|
||||||
|
sendFunctional(pkt);
|
||||||
|
destroyPacket(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
return trans.get_data_length();
|
return trans.get_data_length();
|
||||||
}
|
}
|
||||||
|
@ -291,11 +334,22 @@ SCMasterPort::recvTimingResp(PacketPtr pkt)
|
||||||
sc_core::sc_time::from_value(pkt->payloadDelay + pkt->headerDelay);
|
sc_core::sc_time::from_value(pkt->payloadDelay + pkt->headerDelay);
|
||||||
|
|
||||||
auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState());
|
auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState());
|
||||||
|
sc_assert(tlmSenderState != nullptr);
|
||||||
|
|
||||||
auto& trans = tlmSenderState->trans;
|
auto& trans = tlmSenderState->trans;
|
||||||
|
|
||||||
|
Gem5Extension* extension = nullptr;
|
||||||
|
trans.get_extension(extension);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
delete tlmSenderState;
|
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);
|
sendBeginResp(trans, delay);
|
||||||
trans.release();
|
trans.release();
|
||||||
|
@ -330,14 +384,18 @@ SCMasterPort::recvReqRetry()
|
||||||
{
|
{
|
||||||
sc_assert(waitForRetry);
|
sc_assert(waitForRetry);
|
||||||
sc_assert(pendingRequest != nullptr);
|
sc_assert(pendingRequest != nullptr);
|
||||||
|
sc_assert(pendingPacket != nullptr);
|
||||||
|
|
||||||
auto& trans = *pendingRequest;
|
if (sendTimingReq(pendingPacket)) {
|
||||||
|
waitForRetry = false;
|
||||||
|
pendingPacket = nullptr;
|
||||||
|
|
||||||
waitForRetry = false;
|
auto& trans = *pendingRequest;
|
||||||
pendingRequest = nullptr;
|
sendEndReq(trans);
|
||||||
|
trans.release();
|
||||||
|
|
||||||
// retry
|
pendingRequest = nullptr;
|
||||||
handleBeginReq(trans);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -59,6 +59,13 @@ class Gem5MasterTransactor;
|
||||||
* added as a sender state to the gem5 packet. This way the payload can be
|
* added as a sender state to the gem5 packet. This way the payload can be
|
||||||
* restored when the response packet arrives at the port.
|
* 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
|
* If gem5 operates in atomic mode, the master port registers the TLM blocking
|
||||||
* interface and automatically translates non-blocking requests to blocking.
|
* interface and automatically translates non-blocking requests to blocking.
|
||||||
* If gem5 operates in timing mode, the transactor registers the non-blocking
|
* If gem5 operates in timing mode, the transactor registers the non-blocking
|
||||||
|
@ -82,6 +89,7 @@ class SCMasterPort : public ExternalMaster::Port
|
||||||
|
|
||||||
bool waitForRetry;
|
bool waitForRetry;
|
||||||
tlm::tlm_generic_payload* pendingRequest;
|
tlm::tlm_generic_payload* pendingRequest;
|
||||||
|
PacketPtr pendingPacket;
|
||||||
|
|
||||||
bool needToSendRetry;
|
bool needToSendRetry;
|
||||||
|
|
||||||
|
|
|
@ -265,16 +265,26 @@ SCSlavePort::pec(
|
||||||
{
|
{
|
||||||
CAUGHT_UP;
|
CAUGHT_UP;
|
||||||
|
|
||||||
PacketPtr packet = Gem5Extension::getExtension(trans).getPacket();
|
auto& extension = Gem5Extension::getExtension(trans);
|
||||||
|
auto packet = extension.getPacket();
|
||||||
|
|
||||||
sc_assert(!blockingResponse);
|
sc_assert(!blockingResponse);
|
||||||
|
|
||||||
bool need_retry;
|
bool need_retry = false;
|
||||||
if (packet->needsResponse()) {
|
|
||||||
|
/*
|
||||||
|
* 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();
|
packet->makeResponse();
|
||||||
need_retry = !sendTimingResp(packet);
|
need_retry = !sendTimingResp(packet);
|
||||||
} else {
|
|
||||||
need_retry = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_retry) {
|
if (need_retry) {
|
||||||
|
@ -289,8 +299,6 @@ SCSlavePort::pec(
|
||||||
trans.release();
|
trans.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
SC_REPORT_FATAL("SCSlavePort", "Invalid protocol phase in pec");
|
|
||||||
}
|
}
|
||||||
delete pe;
|
delete pe;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue