1/* 2 * Copyright 2019 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Copyright (c) 2015, University of Kaiserslautern 28 * Copyright (c) 2016, Dresden University of Technology (TU Dresden) 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions are 33 * met: 34 * 35 * 1. Redistributions of source code must retain the above copyright notice, 36 * this list of conditions and the following disclaimer. 37 * 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 42 * 3. Neither the name of the copyright holder nor the names of its 43 * contributors may be used to endorse or promote products derived from 44 * this software without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 47 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 48 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 50 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 52 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 53 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 54 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 55 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 56 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 * 58 * Authors: Gabe Black 59 * Matthias Jung 60 * Abdul Mutaal Ahmad 61 * Christian Menard 62 */ 63 64#include "systemc/tlm_bridge/gem5_to_tlm.hh" 65 66#include "params/Gem5ToTlmBridge32.hh" 67#include "params/Gem5ToTlmBridge64.hh" 68#include "sim/system.hh" 69#include "systemc/tlm_bridge/sc_ext.hh" 70#include "systemc/tlm_bridge/sc_mm.hh" 71 72namespace sc_gem5 73{ 74 75/** 76 * Instantiate a tlm memory manager that takes care about all the 77 * tlm transactions in the system. 78 */ 79Gem5SystemC::MemoryManager mm; 80 81/** 82 * Convert a gem5 packet to a TLM payload by copying all the relevant 83 * information to new tlm payload. 84 */ 85tlm::tlm_generic_payload * 86packet2payload(PacketPtr packet) 87{ 88 tlm::tlm_generic_payload *trans = mm.allocate(); 89 trans->acquire(); 90 91 trans->set_address(packet->getAddr()); 92 93 /* Check if this transaction was allocated by mm */ 94 sc_assert(trans->has_mm()); 95 96 unsigned int size = packet->getSize(); 97 unsigned char *data = packet->getPtr<unsigned char>(); 98 99 trans->set_data_length(size); 100 trans->set_streaming_width(size); 101 trans->set_data_ptr(data); 102 103 if ((packet->req->getFlags() & Request::NO_ACCESS) != 0) { 104 /* Do nothing */ 105 trans->set_command(tlm::TLM_IGNORE_COMMAND); 106 } else if (packet->isRead()) { 107 trans->set_command(tlm::TLM_READ_COMMAND); 108 } else if (packet->isInvalidate()) { 109 /* Do nothing */ 110 trans->set_command(tlm::TLM_IGNORE_COMMAND); 111 } else if (packet->isWrite()) { 112 trans->set_command(tlm::TLM_WRITE_COMMAND); 113 } else { 114 SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet"); 115 } 116 117 // Attach the packet pointer to the TLM transaction to keep track. 118 auto *extension = new Gem5SystemC::Gem5Extension(packet); 119 trans->set_auto_extension(extension); 120 121 return trans; 122} 123 124template <unsigned int BITWIDTH> 125void 126Gem5ToTlmBridge<BITWIDTH>::pec( 127 Gem5SystemC::PayloadEvent<Gem5ToTlmBridge<BITWIDTH>> *pe, 128 tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase) 129{ 130 sc_core::sc_time delay; 131 132 if (phase == tlm::END_REQ || 133 (&trans == blockingRequest && phase == tlm::BEGIN_RESP)) { 134 sc_assert(&trans == blockingRequest); 135 blockingRequest = nullptr; 136 137 // Did another request arrive while blocked, schedule a retry. 138 if (needToSendRequestRetry) { 139 needToSendRequestRetry = false; 140 bsp.sendRetryReq(); 141 } 142 } 143 if (phase == tlm::BEGIN_RESP) { 144 auto &extension = Gem5SystemC::Gem5Extension::getExtension(trans); 145 auto packet = extension.getPacket(); 146 147 sc_assert(!blockingResponse); 148 149 bool need_retry = false; 150 151 /* 152 * If the packet was piped through and needs a response, we don't need 153 * to touch the packet and can forward it directly as a response. 154 * Otherwise, we need to make a response and send the transformed 155 * packet. 156 */ 157 if (extension.isPipeThrough()) { 158 if (packet->isResponse()) { 159 need_retry = !bsp.sendTimingResp(packet); 160 } 161 } else if (packet->needsResponse()) { 162 packet->makeResponse(); 163 need_retry = !bsp.sendTimingResp(packet); 164 } 165 166 if (need_retry) { 167 blockingResponse = &trans; 168 } else { 169 if (phase == tlm::BEGIN_RESP) { 170 // Send END_RESP and we're finished: 171 tlm::tlm_phase fw_phase = tlm::END_RESP; 172 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 173 socket->nb_transport_fw(trans, fw_phase, delay); 174 // Release the transaction with all the extensions. 175 trans.release(); 176 } 177 } 178 } 179 delete pe; 180} 181 182template <unsigned int BITWIDTH> 183MemBackdoorPtr 184Gem5ToTlmBridge<BITWIDTH>::getBackdoor(tlm::tlm_generic_payload &trans) 185{ 186 sc_dt::uint64 start = trans.get_address(); 187 sc_dt::uint64 end = start + trans.get_data_length(); 188 189 // Check for a back door we already know about. 190 AddrRange r(start, end); 191 auto it = backdoorMap.contains(r); 192 if (it != backdoorMap.end()) 193 return it->second; 194 195 // If not, ask the target for one. 196 tlm::tlm_dmi dmi_data; 197 if (!socket->get_direct_mem_ptr(trans, dmi_data)) 198 return nullptr; 199 200 // If the target gave us one, translate it to a gem5 MemBackdoor and 201 // store it in our cache. 202 AddrRange dmi_r(dmi_data.get_start_address(), dmi_data.get_end_address()); 203 auto backdoor = new MemBackdoor( 204 dmi_r, dmi_data.get_dmi_ptr(), MemBackdoor::NoAccess); 205 backdoor->readable(dmi_data.is_read_allowed()); 206 backdoor->writeable(dmi_data.is_write_allowed()); 207 208 backdoorMap.insert(dmi_r, backdoor); 209 210 return backdoor; 211} 212 213// Similar to TLM's blocking transport (LT) 214template <unsigned int BITWIDTH> 215Tick 216Gem5ToTlmBridge<BITWIDTH>::recvAtomic(PacketPtr packet) 217{ 218 panic_if(packet->cacheResponding(), 219 "Should not see packets where cache is responding"); 220 221 // Prepare the transaction. 222 auto *trans = packet2payload(packet); 223 224 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 225 226 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) { 227 // Execute b_transport: 228 socket->b_transport(*trans, delay); 229 } 230 231 if (packet->needsResponse()) 232 packet->makeResponse(); 233 234 trans->release(); 235 236 return delay.value(); 237} 238 239template <unsigned int BITWIDTH> 240Tick 241Gem5ToTlmBridge<BITWIDTH>::recvAtomicBackdoor( 242 PacketPtr packet, MemBackdoorPtr &backdoor) 243{ 244 panic_if(packet->cacheResponding(), 245 "Should not see packets where cache is responding"); 246 247 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 248 249 // Prepare the transaction. 250 auto *trans = packet2payload(packet); 251 252 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) { 253 // Execute b_transport: 254 socket->b_transport(*trans, delay); 255 // If the hint said we could use DMI, set that up. 256 if (trans->is_dmi_allowed()) 257 backdoor = getBackdoor(*trans); 258 } else { 259 // There's no transaction to piggy back on, so just request the 260 // backdoor normally. 261 backdoor = getBackdoor(*trans); 262 } 263 264 if (packet->needsResponse()) 265 packet->makeResponse(); 266 267 trans->release(); 268 269 return delay.value(); 270} 271 272template <unsigned int BITWIDTH> 273void 274Gem5ToTlmBridge<BITWIDTH>::recvFunctionalSnoop(PacketPtr packet) 275{ 276 // Snooping should be implemented with tlm_dbg_transport. 277 SC_REPORT_FATAL("Gem5ToTlmBridge", 278 "unimplemented func.: recvFunctionalSnoop"); 279} 280 281// Similar to TLM's non-blocking transport (AT). 282template <unsigned int BITWIDTH> 283bool 284Gem5ToTlmBridge<BITWIDTH>::recvTimingReq(PacketPtr packet) 285{ 286 panic_if(packet->cacheResponding(), 287 "Should not see packets where cache is responding"); 288 289 panic_if(!(packet->isRead() || packet->isWrite()), 290 "Should only see read and writes at TLM memory\n"); 291 292 293 // We should never get a second request after noting that a retry is 294 // required. 295 sc_assert(!needToSendRequestRetry); 296 297 // Remember if a request comes in while we're blocked so that a retry 298 // can be sent to gem5. 299 if (blockingRequest) { 300 needToSendRequestRetry = true; 301 return false; 302 } 303 304 /* 305 * NOTE: normal tlm is blocking here. But in our case we return false 306 * and tell gem5 when a retry can be done. This is the main difference 307 * in the protocol: 308 * if (requestInProgress) 309 * { 310 * wait(endRequestEvent); 311 * } 312 * requestInProgress = trans; 313 */ 314 315 // Prepare the transaction. 316 auto *trans = packet2payload(packet); 317 318 /* 319 * Pay for annotated transport delays. 320 * 321 * The header delay marks the point in time, when the packet first is seen 322 * by the transactor. This is the point in time when the transactor needs 323 * to send the BEGIN_REQ to the SystemC world. 324 * 325 * NOTE: We drop the payload delay here. Normally, the receiver would be 326 * responsible for handling the payload delay. In this case, however, 327 * the receiver is a SystemC module and has no notion of the gem5 328 * transport protocol and we cannot simply forward the 329 * payload delay to the receiving module. Instead, we expect the 330 * receiving SystemC module to model the payload delay by deferring 331 * the END_REQ. This could lead to incorrect delays, if the XBar 332 * payload delay is longer than the time the receiver needs to accept 333 * the request (time between BEGIN_REQ and END_REQ). 334 * 335 * TODO: We could detect the case described above by remembering the 336 * payload delay and comparing it to the time between BEGIN_REQ and 337 * END_REQ. Then, a warning should be printed. 338 */ 339 auto delay = sc_core::sc_time::from_value(packet->payloadDelay); 340 // Reset the delays 341 packet->payloadDelay = 0; 342 packet->headerDelay = 0; 343 344 // Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC 345 // Standard Page 507 for a visualisation of the procedure. 346 tlm::tlm_phase phase = tlm::BEGIN_REQ; 347 tlm::tlm_sync_enum status; 348 status = socket->nb_transport_fw(*trans, phase, delay); 349 // Check returned value: 350 if (status == tlm::TLM_ACCEPTED) { 351 sc_assert(phase == tlm::BEGIN_REQ); 352 // Accepted but is now blocking until END_REQ (exclusion rule). 353 blockingRequest = trans; 354 } else if (status == tlm::TLM_UPDATED) { 355 // The Timing annotation must be honored: 356 sc_assert(phase == tlm::END_REQ || phase == tlm::BEGIN_RESP); 357 358 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>( 359 *this, &Gem5ToTlmBridge::pec, "PEQ"); 360 Tick nextEventTick = curTick() + delay.value(); 361 system->wakeupEventQueue(nextEventTick); 362 system->schedule(pe, nextEventTick); 363 } else if (status == tlm::TLM_COMPLETED) { 364 // Transaction is over nothing has do be done. 365 sc_assert(phase == tlm::END_RESP); 366 trans->release(); 367 } 368 369 return true; 370} 371 372template <unsigned int BITWIDTH> 373bool 374Gem5ToTlmBridge<BITWIDTH>::recvTimingSnoopResp(PacketPtr packet) 375{ 376 // Snooping should be implemented with tlm_dbg_transport. 377 SC_REPORT_FATAL("Gem5ToTlmBridge", 378 "unimplemented func.: recvTimingSnoopResp"); 379 return false; 380} 381 382template <unsigned int BITWIDTH> 383bool 384Gem5ToTlmBridge<BITWIDTH>::tryTiming(PacketPtr packet) 385{ 386 panic("tryTiming(PacketPtr) isn't implemented."); 387} 388 389template <unsigned int BITWIDTH> 390void 391Gem5ToTlmBridge<BITWIDTH>::recvRespRetry() 392{ 393 /* Retry a response */ 394 sc_assert(blockingResponse); 395 396 tlm::tlm_generic_payload *trans = blockingResponse; 397 blockingResponse = nullptr; 398 PacketPtr packet = 399 Gem5SystemC::Gem5Extension::getExtension(trans).getPacket(); 400 401 bool need_retry = !bsp.sendTimingResp(packet); 402 403 sc_assert(!need_retry); 404 405 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 406 tlm::tlm_phase phase = tlm::END_RESP; 407 socket->nb_transport_fw(*trans, phase, delay); 408 // Release transaction with all the extensions 409 trans->release(); 410} 411 412// Similar to TLM's debug transport. 413template <unsigned int BITWIDTH> 414void 415Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet) 416{ 417 // Prepare the transaction. 418 auto *trans = packet2payload(packet); 419 420 /* Execute Debug Transport: */ 421 unsigned int bytes = socket->transport_dbg(*trans); 422 if (bytes != trans->get_data_length()) { 423 SC_REPORT_FATAL("Gem5ToTlmBridge", 424 "debug transport was not completed"); 425 } 426 427 trans->release(); 428} 429 430template <unsigned int BITWIDTH> 431tlm::tlm_sync_enum 432Gem5ToTlmBridge<BITWIDTH>::nb_transport_bw(tlm::tlm_generic_payload &trans, 433 tlm::tlm_phase &phase, sc_core::sc_time &delay) 434{ 435 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>( 436 *this, &Gem5ToTlmBridge::pec, "PE"); 437 Tick nextEventTick = curTick() + delay.value(); 438 system->wakeupEventQueue(nextEventTick); 439 system->schedule(pe, nextEventTick); 440 return tlm::TLM_ACCEPTED; 441} 442 443template <unsigned int BITWIDTH> 444void 445Gem5ToTlmBridge<BITWIDTH>::invalidate_direct_mem_ptr( 446 sc_dt::uint64 start_range, sc_dt::uint64 end_range) 447{ 448 AddrRange r(start_range, end_range); 449 450 for (;;) { 451 auto it = backdoorMap.intersects(r); 452 if (it == backdoorMap.end()) 453 break; 454 455 it->second->invalidate(); 456 delete it->second; 457 backdoorMap.erase(it); 458 }; 459} 460 461template <unsigned int BITWIDTH> 462Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge( 463 Params *params, const sc_core::sc_module_name &mn) : 464 Gem5ToTlmBridgeBase(mn), bsp(std::string(name()) + ".gem5", *this), 465 socket("tlm_socket"), 466 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID), 467 system(params->system), blockingRequest(nullptr), 468 needToSendRequestRetry(false), blockingResponse(nullptr), 469 addrRanges(params->addr_ranges.begin(), params->addr_ranges.end()) 470{ 471} 472 473template <unsigned int BITWIDTH> 474::Port & 475Gem5ToTlmBridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx) 476{ 477 if (if_name == "gem5") 478 return bsp; 479 else if (if_name == "tlm") 480 return wrapper; 481 482 return sc_core::sc_module::gem5_getPort(if_name, idx); 483} 484 485template <unsigned int BITWIDTH> 486void 487Gem5ToTlmBridge<BITWIDTH>::before_end_of_elaboration() 488{ 489 bsp.sendRangeChange(); 490 491 socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw); 492 socket.register_invalidate_direct_mem_ptr( 493 this, &Gem5ToTlmBridge::invalidate_direct_mem_ptr); 494 sc_core::sc_module::before_end_of_elaboration(); 495} 496 497} // namespace sc_gem5 498 499sc_gem5::Gem5ToTlmBridge<32> * 500Gem5ToTlmBridge32Params::create() 501{ 502 return new sc_gem5::Gem5ToTlmBridge<32>( 503 this, sc_core::sc_module_name(name.c_str())); 504} 505 506sc_gem5::Gem5ToTlmBridge<64> * 507Gem5ToTlmBridge64Params::create() 508{ 509 return new sc_gem5::Gem5ToTlmBridge<64>( 510 this, sc_core::sc_module_name(name.c_str())); 511} 512