/**
* Convert a gem5 packet to a TLM payload by copying all the relevant
- * information to a previously allocated tlm payload
+ * information to new tlm payload.
*/
-void
-packet2payload(PacketPtr packet, tlm::tlm_generic_payload &trans)
+tlm::tlm_generic_payload *
+packet2payload(PacketPtr packet)
{
- trans.set_address(packet->getAddr());
+ tlm::tlm_generic_payload *trans = mm.allocate();
+ trans->acquire();
+
+ trans->set_address(packet->getAddr());
/* Check if this transaction was allocated by mm */
- sc_assert(trans.has_mm());
+ sc_assert(trans->has_mm());
unsigned int size = packet->getSize();
unsigned char *data = packet->getPtr<unsigned char>();
- trans.set_data_length(size);
- trans.set_streaming_width(size);
- trans.set_data_ptr(data);
+ trans->set_data_length(size);
+ trans->set_streaming_width(size);
+ trans->set_data_ptr(data);
- if (packet->isRead()) {
- trans.set_command(tlm::TLM_READ_COMMAND);
+ if ((packet->req->getFlags() & Request::NO_ACCESS) != 0) {
+ /* Do nothing */
+ trans->set_command(tlm::TLM_IGNORE_COMMAND);
+ } else if (packet->isRead()) {
+ trans->set_command(tlm::TLM_READ_COMMAND);
} else if (packet->isInvalidate()) {
/* Do nothing */
+ trans->set_command(tlm::TLM_IGNORE_COMMAND);
} else if (packet->isWrite()) {
- trans.set_command(tlm::TLM_WRITE_COMMAND);
+ trans->set_command(tlm::TLM_WRITE_COMMAND);
} else {
SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet");
}
+
+ // Attach the packet pointer to the TLM transaction to keep track.
+ auto *extension = new Gem5SystemC::Gem5Extension(packet);
+ trans->set_auto_extension(extension);
+
+ return trans;
}
template <unsigned int BITWIDTH>
delete pe;
}
+template <unsigned int BITWIDTH>
+MemBackdoorPtr
+Gem5ToTlmBridge<BITWIDTH>::getBackdoor(tlm::tlm_generic_payload &trans)
+{
+ sc_dt::uint64 start = trans.get_address();
+ sc_dt::uint64 end = start + trans.get_data_length();
+
+ // Check for a back door we already know about.
+ AddrRange r(start, end);
+ auto it = backdoorMap.contains(r);
+ if (it != backdoorMap.end())
+ return it->second;
+
+ // If not, ask the target for one.
+ tlm::tlm_dmi dmi_data;
+ if (!socket->get_direct_mem_ptr(trans, dmi_data))
+ return nullptr;
+
+ // If the target gave us one, translate it to a gem5 MemBackdoor and
+ // store it in our cache.
+ AddrRange dmi_r(dmi_data.get_start_address(), dmi_data.get_end_address());
+ auto backdoor = new MemBackdoor(
+ dmi_r, dmi_data.get_dmi_ptr(), MemBackdoor::NoAccess);
+ backdoor->readable(dmi_data.is_read_allowed());
+ backdoor->writeable(dmi_data.is_write_allowed());
+
+ backdoorMap.insert(dmi_r, backdoor);
+
+ return backdoor;
+}
+
// Similar to TLM's blocking transport (LT)
template <unsigned int BITWIDTH>
Tick
panic_if(packet->cacheResponding(),
"Should not see packets where cache is responding");
- panic_if(!(packet->isRead() || packet->isWrite()),
- "Should only see read and writes at TLM memory\n");
+ // Prepare the transaction.
+ auto *trans = packet2payload(packet);
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
- // Prepare the transaction.
- tlm::tlm_generic_payload *trans = mm.allocate();
- trans->acquire();
- packet2payload(packet, *trans);
+ if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
+ // Execute b_transport:
+ socket->b_transport(*trans, delay);
+ }
- // Attach the packet pointer to the TLM transaction to keep track.
- auto *extension = new Gem5SystemC::Gem5Extension(packet);
- trans->set_auto_extension(extension);
+ if (packet->needsResponse())
+ packet->makeResponse();
- // Execute b_transport:
- if (packet->cmd == MemCmd::SwapReq) {
- SC_REPORT_FATAL("Gem5ToTlmBridge", "SwapReq not supported");
- } else if (packet->isRead()) {
- socket->b_transport(*trans, delay);
- } else if (packet->isInvalidate()) {
- // do nothing
- } else if (packet->isWrite()) {
+ trans->release();
+
+ return delay.value();
+}
+
+template <unsigned int BITWIDTH>
+Tick
+Gem5ToTlmBridge<BITWIDTH>::recvAtomicBackdoor(
+ PacketPtr packet, MemBackdoorPtr &backdoor)
+{
+ panic_if(packet->cacheResponding(),
+ "Should not see packets where cache is responding");
+
+ sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
+
+ // Prepare the transaction.
+ auto *trans = packet2payload(packet);
+
+ if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
+ // Execute b_transport:
socket->b_transport(*trans, delay);
+ // If the hint said we could use DMI, set that up.
+ if (trans->is_dmi_allowed())
+ backdoor = getBackdoor(*trans);
} else {
- SC_REPORT_FATAL("Gem5ToTlmBridge", "Typo of request not supported");
+ // There's no transaction to piggy back on, so just request the
+ // backdoor normally.
+ backdoor = getBackdoor(*trans);
}
- if (packet->needsResponse()) {
+ if (packet->needsResponse())
packet->makeResponse();
- }
trans->release();
*/
// Prepare the transaction.
- tlm::tlm_generic_payload *trans = mm.allocate();
- trans->acquire();
- packet2payload(packet, *trans);
-
- // Attach the packet pointer to the TLM transaction to keep track.
- auto *extension = new Gem5SystemC::Gem5Extension(packet);
- trans->set_auto_extension(extension);
+ auto *trans = packet2payload(packet);
/*
* Pay for annotated transport delays.
Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet)
{
// Prepare the transaction.
- tlm::tlm_generic_payload *trans = mm.allocate();
- trans->acquire();
- packet2payload(packet, *trans);
-
- // Attach the packet pointer to the TLM transaction to keep track.
- auto *extension = new Gem5SystemC::Gem5Extension(packet);
- trans->set_auto_extension(extension);
+ auto *trans = packet2payload(packet);
/* Execute Debug Transport: */
unsigned int bytes = socket->transport_dbg(*trans);
return tlm::TLM_ACCEPTED;
}
+template <unsigned int BITWIDTH>
+void
+Gem5ToTlmBridge<BITWIDTH>::invalidate_direct_mem_ptr(
+ sc_dt::uint64 start_range, sc_dt::uint64 end_range)
+{
+ AddrRange r(start_range, end_range);
+
+ for (;;) {
+ auto it = backdoorMap.intersects(r);
+ if (it == backdoorMap.end())
+ break;
+
+ it->second->invalidate();
+ delete it->second;
+ backdoorMap.erase(it);
+ };
+}
+
template <unsigned int BITWIDTH>
Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge(
Params *params, const sc_core::sc_module_name &mn) :
bsp.sendRangeChange();
socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw);
+ socket.register_invalidate_direct_mem_ptr(
+ this, &Gem5ToTlmBridge::invalidate_direct_mem_ptr);
sc_core::sc_module::before_end_of_elaboration();
}
#include "params/TlmToGem5Bridge64.hh"
#include "sim/system.hh"
#include "systemc/ext/core/sc_module_name.hh"
+#include "systemc/ext/core/sc_time.hh"
namespace sc_gem5
{
}
}
+template <unsigned int BITWIDTH>
+void
+TlmToGem5Bridge<BITWIDTH>::invalidateDmi(const ::MemBackdoor &backdoor)
+{
+ socket->invalidate_direct_mem_ptr(
+ backdoor.range().start(), backdoor.range().end());
+}
+
template <unsigned int BITWIDTH>
void
TlmToGem5Bridge<BITWIDTH>::peq_cb(tlm::tlm_generic_payload &trans,
pkt = generatePacket(trans);
}
- Tick ticks = bmp.sendAtomic(pkt);
+ MemBackdoorPtr backdoor = nullptr;
+ Tick ticks = bmp.sendAtomicBackdoor(pkt, backdoor);
+ if (backdoor)
+ trans.set_dmi_allowed(true);
// send an atomic request to gem5
panic_if(pkt->needsResponse() && !pkt->isResponse(),
TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
tlm::tlm_dmi &dmi_data)
{
- return false;
+ Gem5SystemC::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);
+ pkt->req->setFlags(Request::NO_ACCESS);
+ }
+
+ MemBackdoorPtr backdoor = nullptr;
+ bmp.sendAtomicBackdoor(pkt, backdoor);
+ if (backdoor) {
+ trans.set_dmi_allowed(true);
+ dmi_data.set_dmi_ptr(backdoor->ptr());
+ dmi_data.set_start_address(backdoor->range().start());
+ dmi_data.set_end_address(backdoor->range().end());
+
+ typedef tlm::tlm_dmi::dmi_access_e access_t;
+ access_t access = tlm::tlm_dmi::DMI_ACCESS_NONE;
+ if (backdoor->readable())
+ access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_READ);
+ if (backdoor->writeable())
+ access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_WRITE);
+ dmi_data.set_granted_access(access);
+
+ backdoor->addInvalidationCallback(
+ [this](const MemBackdoor &backdoor)
+ {
+ invalidateDmi(backdoor);
+ }
+ );
+ }
+
+ if (extension == nullptr)
+ destroyPacket(pkt);
+
+ trans.set_response_status(tlm::TLM_OK_RESPONSE);
+
+ return backdoor != nullptr;
}
template <unsigned int BITWIDTH>
SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface");
socket.register_b_transport(
this, &TlmToGem5Bridge<BITWIDTH>::b_transport);
+ socket.register_get_direct_mem_ptr(
+ this, &TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr);
} else {
panic("gem5 operates neither in Timing nor in Atomic mode");
}