From 729d9949f74a2fef8ed27de83e1f918fbb8c431d Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 21 Mar 2019 17:28:26 -0700 Subject: [PATCH] systemc: Teach the TLM bridges how to use gem5's new backdoor mechanism. This change teaches the TLM bridges to translate between TLM's DMI mechanism and gem5's backdoor mechanism. Change-Id: I942a6cce4fb87f10e8173f4ee49b6c7b0ffa7e4a Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/17591 Reviewed-by: Jason Lowe-Power Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/systemc/tlm_bridge/gem5_to_tlm.cc | 157 ++++++++++++++++++-------- src/systemc/tlm_bridge/gem5_to_tlm.hh | 11 ++ src/systemc/tlm_bridge/tlm_to_gem5.cc | 62 +++++++++- src/systemc/tlm_bridge/tlm_to_gem5.hh | 2 + 4 files changed, 185 insertions(+), 47 deletions(-) diff --git a/src/systemc/tlm_bridge/gem5_to_tlm.cc b/src/systemc/tlm_bridge/gem5_to_tlm.cc index f78c679ee..03cce22a2 100644 --- a/src/systemc/tlm_bridge/gem5_to_tlm.cc +++ b/src/systemc/tlm_bridge/gem5_to_tlm.cc @@ -80,32 +80,45 @@ Gem5SystemC::MemoryManager mm; /** * 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(); - 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 @@ -166,6 +179,37 @@ Gem5ToTlmBridge::pec( delete pe; } +template +MemBackdoorPtr +Gem5ToTlmBridge::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 Tick @@ -174,36 +218,51 @@ Gem5ToTlmBridge::recvAtomic(PacketPtr packet) 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 +Tick +Gem5ToTlmBridge::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(); @@ -254,13 +313,7 @@ Gem5ToTlmBridge::recvTimingReq(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); /* * Pay for annotated transport delays. @@ -362,13 +415,7 @@ void Gem5ToTlmBridge::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); @@ -393,6 +440,24 @@ Gem5ToTlmBridge::nb_transport_bw(tlm::tlm_generic_payload &trans, return tlm::TLM_ACCEPTED; } +template +void +Gem5ToTlmBridge::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 Gem5ToTlmBridge::Gem5ToTlmBridge( Params *params, const sc_core::sc_module_name &mn) : @@ -424,6 +489,8 @@ Gem5ToTlmBridge::before_end_of_elaboration() 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(); } diff --git a/src/systemc/tlm_bridge/gem5_to_tlm.hh b/src/systemc/tlm_bridge/gem5_to_tlm.hh index e36058ac6..182512a93 100644 --- a/src/systemc/tlm_bridge/gem5_to_tlm.hh +++ b/src/systemc/tlm_bridge/gem5_to_tlm.hh @@ -103,6 +103,11 @@ class Gem5ToTlmBridge : public Gem5ToTlmBridgeBase { return bridge.recvAtomic(pkt); } + Tick + recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor) override + { + return bridge.recvAtomicBackdoor(pkt, backdoor); + } void recvFunctional(PacketPtr pkt) override { @@ -163,8 +168,12 @@ class Gem5ToTlmBridge : public Gem5ToTlmBridgeBase void pec(Gem5SystemC::PayloadEvent> *pe, tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase); + MemBackdoorPtr getBackdoor(tlm::tlm_generic_payload &trans); + AddrRangeMap backdoorMap; + // The gem5 port interface. Tick recvAtomic(PacketPtr packet); + Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor); void recvFunctional(PacketPtr packet); bool recvTimingReq(PacketPtr packet); bool tryTiming(PacketPtr packet); @@ -177,6 +186,8 @@ class Gem5ToTlmBridge : public Gem5ToTlmBridgeBase tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, sc_core::sc_time &t); + void invalidate_direct_mem_ptr( + sc_dt::uint64 start_range, sc_dt::uint64 end_range); public: ::Port &gem5_getPort(const std::string &if_name, int idx=-1) override; diff --git a/src/systemc/tlm_bridge/tlm_to_gem5.cc b/src/systemc/tlm_bridge/tlm_to_gem5.cc index 4b69286d0..d978aa648 100644 --- a/src/systemc/tlm_bridge/tlm_to_gem5.cc +++ b/src/systemc/tlm_bridge/tlm_to_gem5.cc @@ -64,6 +64,7 @@ #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 { @@ -210,6 +211,14 @@ TlmToGem5Bridge::checkTransaction(tlm::tlm_generic_payload &trans) } } +template +void +TlmToGem5Bridge::invalidateDmi(const ::MemBackdoor &backdoor) +{ + socket->invalidate_direct_mem_ptr( + backdoor.range().start(), backdoor.range().end()); +} + template void TlmToGem5Bridge::peq_cb(tlm::tlm_generic_payload &trans, @@ -272,7 +281,10 @@ TlmToGem5Bridge::b_transport(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(), @@ -318,7 +330,51 @@ bool TlmToGem5Bridge::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 @@ -443,6 +499,8 @@ TlmToGem5Bridge::before_end_of_elaboration() SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface"); socket.register_b_transport( this, &TlmToGem5Bridge::b_transport); + socket.register_get_direct_mem_ptr( + this, &TlmToGem5Bridge::get_direct_mem_ptr); } else { panic("gem5 operates neither in Timing nor in Atomic mode"); } diff --git a/src/systemc/tlm_bridge/tlm_to_gem5.hh b/src/systemc/tlm_bridge/tlm_to_gem5.hh index d2b15af67..82d3d103a 100644 --- a/src/systemc/tlm_bridge/tlm_to_gem5.hh +++ b/src/systemc/tlm_bridge/tlm_to_gem5.hh @@ -139,6 +139,8 @@ class TlmToGem5Bridge : public TlmToGem5BridgeBase void checkTransaction(tlm::tlm_generic_payload &trans); + void invalidateDmi(const ::MemBackdoor &backdoor); + protected: // payload event call back void peq_cb(tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase); -- 2.30.2