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) 2016, Dresden University of Technology (TU Dresden) 28 * All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions are 32 * met: 33 * 34 * 1. Redistributions of source code must retain the above copyright notice, 35 * this list of conditions and the following disclaimer. 36 * 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 41 * 3. Neither the name of the copyright holder nor the names of its 42 * contributors may be used to endorse or promote products derived from 43 * this software without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 49 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 * 57 * Authors: Gabe Black 58 * Christian Menard 59 */ 60 61#include "systemc/tlm_bridge/tlm_to_gem5.hh" 62 63#include "params/TlmToGem5Bridge32.hh" 64#include "params/TlmToGem5Bridge64.hh" 65#include "sim/system.hh" 66#include "systemc/ext/core/sc_module_name.hh" 67#include "systemc/ext/core/sc_time.hh" 68 69namespace sc_gem5 70{ 71 72PacketPtr 73payload2packet(MasterID masterId, tlm::tlm_generic_payload &trans) 74{ 75 MemCmd cmd; 76 77 switch (trans.get_command()) { 78 case tlm::TLM_READ_COMMAND: 79 cmd = MemCmd::ReadReq; 80 break; 81 case tlm::TLM_WRITE_COMMAND: 82 cmd = MemCmd::WriteReq; 83 break; 84 case tlm::TLM_IGNORE_COMMAND: 85 return nullptr; 86 default: 87 SC_REPORT_FATAL("TlmToGem5Bridge", 88 "received transaction with unsupported command"); 89 } 90 91 Request::Flags flags; 92 auto req = std::make_shared<Request>( 93 trans.get_address(), trans.get_data_length(), flags, masterId); 94 95 /* 96 * Allocate a new Packet. The packet will be deleted when it returns from 97 * the gem5 world as a response. 98 */ 99 auto pkt = new Packet(req, cmd); 100 pkt->dataStatic(trans.get_data_ptr()); 101 102 return pkt; 103} 104 105template <unsigned int BITWIDTH> 106void 107TlmToGem5Bridge<BITWIDTH>::sendEndReq(tlm::tlm_generic_payload &trans) 108{ 109 tlm::tlm_phase phase = tlm::END_REQ; 110 auto delay = sc_core::SC_ZERO_TIME; 111 112 auto status = socket->nb_transport_bw(trans, phase, delay); 113 panic_if(status != tlm::TLM_ACCEPTED, 114 "Unexpected status after sending END_REQ"); 115} 116 117template <unsigned int BITWIDTH> 118void 119TlmToGem5Bridge<BITWIDTH>::sendBeginResp(tlm::tlm_generic_payload &trans, 120 sc_core::sc_time &delay) 121{ 122 tlm::tlm_phase phase = tlm::BEGIN_RESP; 123 124 trans.set_response_status(tlm::TLM_OK_RESPONSE); 125 126 auto status = socket->nb_transport_bw(trans, phase, delay); 127 128 if (status == tlm::TLM_COMPLETED || 129 (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) { 130 // transaction completed -> no need to wait for tlm::END_RESP 131 responseInProgress = false; 132 } else if (status == tlm::TLM_ACCEPTED) { 133 // we need to wait for tlm::END_RESP 134 responseInProgress = true; 135 } else { 136 panic("Unexpected status after sending BEGIN_RESP"); 137 } 138} 139 140template <unsigned int BITWIDTH> 141void 142TlmToGem5Bridge<BITWIDTH>::handleBeginReq(tlm::tlm_generic_payload &trans) 143{ 144 sc_assert(!waitForRetry); 145 sc_assert(pendingRequest == nullptr); 146 sc_assert(pendingPacket == nullptr); 147 148 trans.acquire(); 149 150 PacketPtr pkt = nullptr; 151 152 Gem5SystemC::Gem5Extension *extension = nullptr; 153 trans.get_extension(extension); 154 155 // If there is an extension, this transaction was initiated by the gem5 156 // world and we can pipe through the original packet. Otherwise, we 157 // generate a new packet based on the transaction. 158 if (extension != nullptr) { 159 extension->setPipeThrough(); 160 pkt = extension->getPacket(); 161 } else { 162 pkt = payload2packet(masterId, trans); 163 } 164 165 auto tlmSenderState = new TlmSenderState(trans); 166 pkt->pushSenderState(tlmSenderState); 167 168 if (bmp.sendTimingReq(pkt)) { // port is free -> send END_REQ immediately 169 sendEndReq(trans); 170 trans.release(); 171 } else { // port is blocked -> wait for retry before sending END_REQ 172 waitForRetry = true; 173 pendingRequest = &trans; 174 pendingPacket = pkt; 175 } 176} 177 178template <unsigned int BITWIDTH> 179void 180TlmToGem5Bridge<BITWIDTH>::handleEndResp(tlm::tlm_generic_payload &trans) 181{ 182 sc_assert(responseInProgress); 183 184 responseInProgress = false; 185 186 checkTransaction(trans); 187 188 if (needToSendRetry) { 189 bmp.sendRetryResp(); 190 needToSendRetry = false; 191 } 192} 193 194template <unsigned int BITWIDTH> 195void 196TlmToGem5Bridge<BITWIDTH>::destroyPacket(PacketPtr pkt) 197{ 198 delete pkt; 199} 200 201template <unsigned int BITWIDTH> 202void 203TlmToGem5Bridge<BITWIDTH>::checkTransaction(tlm::tlm_generic_payload &trans) 204{ 205 if (trans.is_response_error()) { 206 std::stringstream ss; 207 ss << "Transaction returned with error, response status = " 208 << trans.get_response_string(); 209 SC_REPORT_ERROR("TLM-2", ss.str().c_str()); 210 } 211} 212 213template <unsigned int BITWIDTH> 214void 215TlmToGem5Bridge<BITWIDTH>::invalidateDmi(const ::MemBackdoor &backdoor) 216{ 217 socket->invalidate_direct_mem_ptr( 218 backdoor.range().start(), backdoor.range().end()); 219} 220 221template <unsigned int BITWIDTH> 222void 223TlmToGem5Bridge<BITWIDTH>::peq_cb(tlm::tlm_generic_payload &trans, 224 const tlm::tlm_phase &phase) 225{ 226 switch (phase) { 227 case tlm::BEGIN_REQ: 228 handleBeginReq(trans); 229 break; 230 case tlm::END_RESP: 231 handleEndResp(trans); 232 break; 233 default: 234 panic("unimplemented phase in callback"); 235 } 236} 237 238template <unsigned int BITWIDTH> 239tlm::tlm_sync_enum 240TlmToGem5Bridge<BITWIDTH>::nb_transport_fw( 241 tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, 242 sc_core::sc_time &delay) 243{ 244 unsigned len = trans.get_data_length(); 245 unsigned char *byteEnable = trans.get_byte_enable_ptr(); 246 unsigned width = trans.get_streaming_width(); 247 248 // check the transaction attributes for unsupported features ... 249 if (byteEnable != 0) { 250 trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE); 251 return tlm::TLM_COMPLETED; 252 } 253 if (width < len) { // is this a burst request? 254 trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE); 255 return tlm::TLM_COMPLETED; 256 } 257 258 // ... and queue the valid transaction 259 trans.acquire(); 260 peq.notify(trans, phase, delay); 261 return tlm::TLM_ACCEPTED; 262} 263 264template <unsigned int BITWIDTH> 265void 266TlmToGem5Bridge<BITWIDTH>::b_transport(tlm::tlm_generic_payload &trans, 267 sc_core::sc_time &t) 268{ 269 Gem5SystemC::Gem5Extension *extension = nullptr; 270 trans.get_extension(extension); 271 272 PacketPtr pkt = nullptr; 273 274 // If there is an extension, this transaction was initiated by the gem5 275 // world and we can pipe through the original packet. 276 if (extension != nullptr) { 277 extension->setPipeThrough(); 278 pkt = extension->getPacket(); 279 } else { 280 pkt = payload2packet(masterId, trans); 281 } 282 283 MemBackdoorPtr backdoor = nullptr; 284 Tick ticks = bmp.sendAtomicBackdoor(pkt, backdoor); 285 if (backdoor) 286 trans.set_dmi_allowed(true); 287 288 // send an atomic request to gem5 289 panic_if(pkt->needsResponse() && !pkt->isResponse(), 290 "Packet sending failed!\n"); 291 292 auto delay = 293 sc_core::sc_time((double)(ticks / SimClock::Int::ps), sc_core::SC_PS); 294 295 // update time 296 t += delay; 297 298 if (extension == nullptr) 299 destroyPacket(pkt); 300 301 trans.set_response_status(tlm::TLM_OK_RESPONSE); 302} 303 304template <unsigned int BITWIDTH> 305unsigned int 306TlmToGem5Bridge<BITWIDTH>::transport_dbg(tlm::tlm_generic_payload &trans) 307{ 308 Gem5SystemC::Gem5Extension *extension = nullptr; 309 trans.get_extension(extension); 310 311 // If there is an extension, this transaction was initiated by the gem5 312 // world and we can pipe through the original packet. 313 if (extension != nullptr) { 314 extension->setPipeThrough(); 315 bmp.sendFunctional(extension->getPacket()); 316 } else { 317 auto pkt = payload2packet(masterId, trans); 318 if (pkt) { 319 bmp.sendFunctional(pkt); 320 destroyPacket(pkt); 321 } 322 } 323 324 return trans.get_data_length(); 325} 326 327template <unsigned int BITWIDTH> 328bool 329TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr(tlm::tlm_generic_payload &trans, 330 tlm::tlm_dmi &dmi_data) 331{ 332 Gem5SystemC::Gem5Extension *extension = nullptr; 333 trans.get_extension(extension); 334 335 PacketPtr pkt = nullptr; 336 337 // If there is an extension, this transaction was initiated by the gem5 338 // world and we can pipe through the original packet. 339 if (extension != nullptr) { 340 extension->setPipeThrough(); 341 pkt = extension->getPacket(); 342 } else { 343 pkt = payload2packet(masterId, trans); 344 pkt->req->setFlags(Request::NO_ACCESS); 345 } 346 347 MemBackdoorPtr backdoor = nullptr; 348 bmp.sendAtomicBackdoor(pkt, backdoor); 349 if (backdoor) { 350 trans.set_dmi_allowed(true); 351 dmi_data.set_dmi_ptr(backdoor->ptr()); 352 dmi_data.set_start_address(backdoor->range().start()); 353 dmi_data.set_end_address(backdoor->range().end()); 354 355 typedef tlm::tlm_dmi::dmi_access_e access_t; 356 access_t access = tlm::tlm_dmi::DMI_ACCESS_NONE; 357 if (backdoor->readable()) 358 access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_READ); 359 if (backdoor->writeable()) 360 access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_WRITE); 361 dmi_data.set_granted_access(access); 362 363 backdoor->addInvalidationCallback( 364 [this](const MemBackdoor &backdoor) 365 { 366 invalidateDmi(backdoor); 367 } 368 ); 369 } 370 371 if (extension == nullptr) 372 destroyPacket(pkt); 373 374 trans.set_response_status(tlm::TLM_OK_RESPONSE); 375 376 return backdoor != nullptr; 377} 378 379template <unsigned int BITWIDTH> 380bool 381TlmToGem5Bridge<BITWIDTH>::recvTimingResp(PacketPtr pkt) 382{ 383 // exclusion rule 384 // We need to Wait for END_RESP before sending next BEGIN_RESP 385 if (responseInProgress) { 386 sc_assert(!needToSendRetry); 387 needToSendRetry = true; 388 return false; 389 } 390 391 sc_assert(pkt->isResponse()); 392 393 /* 394 * Pay for annotated transport delays. 395 * 396 * See recvTimingReq in sc_slave_port.cc for a detailed description. 397 */ 398 auto delay = sc_core::sc_time::from_value(pkt->payloadDelay); 399 // reset the delays 400 pkt->payloadDelay = 0; 401 pkt->headerDelay = 0; 402 403 auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState()); 404 sc_assert(tlmSenderState != nullptr); 405 406 auto &trans = tlmSenderState->trans; 407 408 Gem5SystemC::Gem5Extension *extension = nullptr; 409 trans.get_extension(extension); 410 411 // clean up 412 delete tlmSenderState; 413 414 // If there is an extension the packet was piped through and we must not 415 // delete it. The packet travels back with the transaction. 416 if (extension == nullptr) 417 destroyPacket(pkt); 418 else 419 sc_assert(extension->isPipeThrough()); 420 421 sendBeginResp(trans, delay); 422 trans.release(); 423 424 return true; 425} 426 427template <unsigned int BITWIDTH> 428void 429TlmToGem5Bridge<BITWIDTH>::recvReqRetry() 430{ 431 sc_assert(waitForRetry); 432 sc_assert(pendingRequest != nullptr); 433 sc_assert(pendingPacket != nullptr); 434 435 if (bmp.sendTimingReq(pendingPacket)) { 436 waitForRetry = false; 437 pendingPacket = nullptr; 438 439 auto &trans = *pendingRequest; 440 sendEndReq(trans); 441 trans.release(); 442 443 pendingRequest = nullptr; 444 } 445} 446 447template <unsigned int BITWIDTH> 448void 449TlmToGem5Bridge<BITWIDTH>::recvRangeChange() 450{ 451 SC_REPORT_WARNING("TlmToGem5Bridge", 452 "received address range change but ignored it"); 453} 454 455template <unsigned int BITWIDTH> 456::Port & 457TlmToGem5Bridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx) 458{ 459 if (if_name == "gem5") 460 return bmp; 461 else if (if_name == "tlm") 462 return wrapper; 463 464 return sc_core::sc_module::gem5_getPort(if_name, idx); 465} 466 467template <unsigned int BITWIDTH> 468TlmToGem5Bridge<BITWIDTH>::TlmToGem5Bridge( 469 Params *params, const sc_core::sc_module_name &mn) : 470 TlmToGem5BridgeBase(mn), peq(this, &TlmToGem5Bridge<BITWIDTH>::peq_cb), 471 waitForRetry(false), pendingRequest(nullptr), pendingPacket(nullptr), 472 needToSendRetry(false), responseInProgress(false), 473 bmp(std::string(name()) + "master", *this), socket("tlm_socket"), 474 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID), 475 system(params->system), 476 masterId(params->system->getGlobalMasterId( 477 std::string("[systemc].") + name())) 478{ 479} 480 481template <unsigned int BITWIDTH> 482void 483TlmToGem5Bridge<BITWIDTH>::before_end_of_elaboration() 484{ 485 /* 486 * Register the TLM non-blocking interface when using gem5 Timing mode and 487 * the TLM blocking interface when using the gem5 Atomic mode. 488 * Then the magic (TM) in simple_target_socket automatically transforms 489 * non-blocking in blocking transactions and vice versa. 490 * 491 * NOTE: The mode may change during execution. 492 */ 493 if (system->isTimingMode()) { 494 SC_REPORT_INFO("TlmToGem5Bridge", "register non-blocking interface"); 495 socket.register_nb_transport_fw( 496 this, &TlmToGem5Bridge<BITWIDTH>::nb_transport_fw); 497 } else if (system->isAtomicMode()) { 498 SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface"); 499 socket.register_b_transport( 500 this, &TlmToGem5Bridge<BITWIDTH>::b_transport); 501 socket.register_get_direct_mem_ptr( 502 this, &TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr); 503 } else { 504 panic("gem5 operates neither in Timing nor in Atomic mode"); 505 } 506 507 socket.register_transport_dbg( 508 this, &TlmToGem5Bridge<BITWIDTH>::transport_dbg); 509 510 sc_core::sc_module::before_end_of_elaboration(); 511} 512 513} // namespace sc_gem5 514 515sc_gem5::TlmToGem5Bridge<32> * 516TlmToGem5Bridge32Params::create() 517{ 518 return new sc_gem5::TlmToGem5Bridge<32>( 519 this, sc_core::sc_module_name(name.c_str())); 520} 521 522sc_gem5::TlmToGem5Bridge<64> * 523TlmToGem5Bridge64Params::create() 524{ 525 return new sc_gem5::TlmToGem5Bridge<64>( 526 this, sc_core::sc_module_name(name.c_str())); 527} 528