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