tlm_to_gem5.cc revision 13823:040971e0f728
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 68namespace sc_gem5 69{ 70 71template <unsigned int BITWIDTH> 72void 73TlmToGem5Bridge<BITWIDTH>::sendEndReq(tlm::tlm_generic_payload &trans) 74{ 75 tlm::tlm_phase phase = tlm::END_REQ; 76 auto delay = sc_core::SC_ZERO_TIME; 77 78 auto status = socket->nb_transport_bw(trans, phase, delay); 79 panic_if(status != tlm::TLM_ACCEPTED, 80 "Unexpected status after sending END_REQ"); 81} 82 83template <unsigned int BITWIDTH> 84void 85TlmToGem5Bridge<BITWIDTH>::sendBeginResp(tlm::tlm_generic_payload &trans, 86 sc_core::sc_time &delay) 87{ 88 tlm::tlm_phase phase = tlm::BEGIN_RESP; 89 90 trans.set_response_status(tlm::TLM_OK_RESPONSE); 91 92 auto status = socket->nb_transport_bw(trans, phase, delay); 93 94 if (status == tlm::TLM_COMPLETED || 95 (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) { 96 // transaction completed -> no need to wait for tlm::END_RESP 97 responseInProgress = false; 98 } else if (status == tlm::TLM_ACCEPTED) { 99 // we need to wait for tlm::END_RESP 100 responseInProgress = true; 101 } else { 102 panic("Unexpected status after sending BEGIN_RESP"); 103 } 104} 105 106template <unsigned int BITWIDTH> 107void 108TlmToGem5Bridge<BITWIDTH>::handleBeginReq(tlm::tlm_generic_payload &trans) 109{ 110 sc_assert(!waitForRetry); 111 sc_assert(pendingRequest == nullptr); 112 sc_assert(pendingPacket == nullptr); 113 114 trans.acquire(); 115 116 PacketPtr pkt = nullptr; 117 118 Gem5SystemC::Gem5Extension *extension = nullptr; 119 trans.get_extension(extension); 120 121 // If there is an extension, this transaction was initiated by the gem5 122 // world and we can pipe through the original packet. Otherwise, we 123 // generate a new packet based on the transaction. 124 if (extension != nullptr) { 125 extension->setPipeThrough(); 126 pkt = extension->getPacket(); 127 } else { 128 pkt = generatePacket(trans); 129 } 130 131 auto tlmSenderState = new TlmSenderState(trans); 132 pkt->pushSenderState(tlmSenderState); 133 134 if (bmp.sendTimingReq(pkt)) { // port is free -> send END_REQ immediately 135 sendEndReq(trans); 136 trans.release(); 137 } else { // port is blocked -> wait for retry before sending END_REQ 138 waitForRetry = true; 139 pendingRequest = &trans; 140 pendingPacket = pkt; 141 } 142} 143 144template <unsigned int BITWIDTH> 145void 146TlmToGem5Bridge<BITWIDTH>::handleEndResp(tlm::tlm_generic_payload &trans) 147{ 148 sc_assert(responseInProgress); 149 150 responseInProgress = false; 151 152 checkTransaction(trans); 153 154 if (needToSendRetry) { 155 bmp.sendRetryResp(); 156 needToSendRetry = false; 157 } 158} 159 160template <unsigned int BITWIDTH> 161PacketPtr 162TlmToGem5Bridge<BITWIDTH>::generatePacket(tlm::tlm_generic_payload &trans) 163{ 164 MemCmd cmd; 165 166 switch (trans.get_command()) { 167 case tlm::TLM_READ_COMMAND: 168 cmd = MemCmd::ReadReq; 169 break; 170 case tlm::TLM_WRITE_COMMAND: 171 cmd = MemCmd::WriteReq; 172 break; 173 case tlm::TLM_IGNORE_COMMAND: 174 return nullptr; 175 default: 176 SC_REPORT_FATAL("TlmToGem5Bridge", 177 "received transaction with unsupported command"); 178 } 179 180 Request::Flags flags; 181 auto req = std::make_shared<Request>( 182 trans.get_address(), trans.get_data_length(), flags, masterId); 183 184 /* 185 * Allocate a new Packet. The packet will be deleted when it returns from 186 * the gem5 world as a response. 187 */ 188 auto pkt = new Packet(req, cmd); 189 pkt->dataStatic(trans.get_data_ptr()); 190 191 return pkt; 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>::peq_cb(tlm::tlm_generic_payload &trans, 216 const tlm::tlm_phase &phase) 217{ 218 switch (phase) { 219 case tlm::BEGIN_REQ: 220 handleBeginReq(trans); 221 break; 222 case tlm::END_RESP: 223 handleEndResp(trans); 224 break; 225 default: 226 panic("unimplemented phase in callback"); 227 } 228} 229 230template <unsigned int BITWIDTH> 231tlm::tlm_sync_enum 232TlmToGem5Bridge<BITWIDTH>::nb_transport_fw( 233 tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase, 234 sc_core::sc_time &delay) 235{ 236 unsigned len = trans.get_data_length(); 237 unsigned char *byteEnable = trans.get_byte_enable_ptr(); 238 unsigned width = trans.get_streaming_width(); 239 240 // check the transaction attributes for unsupported features ... 241 if (byteEnable != 0) { 242 trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE); 243 return tlm::TLM_COMPLETED; 244 } 245 if (width < len) { // is this a burst request? 246 trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE); 247 return tlm::TLM_COMPLETED; 248 } 249 250 // ... and queue the valid transaction 251 trans.acquire(); 252 peq.notify(trans, phase, delay); 253 return tlm::TLM_ACCEPTED; 254} 255 256template <unsigned int BITWIDTH> 257void 258TlmToGem5Bridge<BITWIDTH>::b_transport(tlm::tlm_generic_payload &trans, 259 sc_core::sc_time &t) 260{ 261 Gem5SystemC::Gem5Extension *extension = nullptr; 262 trans.get_extension(extension); 263 264 PacketPtr pkt = nullptr; 265 266 // If there is an extension, this transaction was initiated by the gem5 267 // world and we can pipe through the original packet. 268 if (extension != nullptr) { 269 extension->setPipeThrough(); 270 pkt = extension->getPacket(); 271 } else { 272 pkt = generatePacket(trans); 273 } 274 275 Tick ticks = bmp.sendAtomic(pkt); 276 277 // send an atomic request to gem5 278 panic_if(pkt->needsResponse() && !pkt->isResponse(), 279 "Packet sending failed!\n"); 280 281 auto delay = 282 sc_core::sc_time((double)(ticks / SimClock::Int::ps), sc_core::SC_PS); 283 284 // update time 285 t += delay; 286 287 if (extension == nullptr) 288 destroyPacket(pkt); 289 290 trans.set_response_status(tlm::TLM_OK_RESPONSE); 291} 292 293template <unsigned int BITWIDTH> 294unsigned int 295TlmToGem5Bridge<BITWIDTH>::transport_dbg(tlm::tlm_generic_payload &trans) 296{ 297 Gem5SystemC::Gem5Extension *extension = nullptr; 298 trans.get_extension(extension); 299 300 // If there is an extension, this transaction was initiated by the gem5 301 // world and we can pipe through the original packet. 302 if (extension != nullptr) { 303 extension->setPipeThrough(); 304 bmp.sendFunctional(extension->getPacket()); 305 } else { 306 auto pkt = generatePacket(trans); 307 if (pkt) { 308 bmp.sendFunctional(pkt); 309 destroyPacket(pkt); 310 } 311 } 312 313 return trans.get_data_length(); 314} 315 316template <unsigned int BITWIDTH> 317bool 318TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr(tlm::tlm_generic_payload &trans, 319 tlm::tlm_dmi &dmi_data) 320{ 321 return false; 322} 323 324template <unsigned int BITWIDTH> 325bool 326TlmToGem5Bridge<BITWIDTH>::recvTimingResp(PacketPtr pkt) 327{ 328 // exclusion rule 329 // We need to Wait for END_RESP before sending next BEGIN_RESP 330 if (responseInProgress) { 331 sc_assert(!needToSendRetry); 332 needToSendRetry = true; 333 return false; 334 } 335 336 sc_assert(pkt->isResponse()); 337 338 /* 339 * Pay for annotated transport delays. 340 * 341 * See recvTimingReq in sc_slave_port.cc for a detailed description. 342 */ 343 auto delay = sc_core::sc_time::from_value(pkt->payloadDelay); 344 // reset the delays 345 pkt->payloadDelay = 0; 346 pkt->headerDelay = 0; 347 348 auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState()); 349 sc_assert(tlmSenderState != nullptr); 350 351 auto &trans = tlmSenderState->trans; 352 353 Gem5SystemC::Gem5Extension *extension = nullptr; 354 trans.get_extension(extension); 355 356 // clean up 357 delete tlmSenderState; 358 359 // If there is an extension the packet was piped through and we must not 360 // delete it. The packet travels back with the transaction. 361 if (extension == nullptr) 362 destroyPacket(pkt); 363 else 364 sc_assert(extension->isPipeThrough()); 365 366 sendBeginResp(trans, delay); 367 trans.release(); 368 369 return true; 370} 371 372template <unsigned int BITWIDTH> 373void 374TlmToGem5Bridge<BITWIDTH>::recvReqRetry() 375{ 376 sc_assert(waitForRetry); 377 sc_assert(pendingRequest != nullptr); 378 sc_assert(pendingPacket != nullptr); 379 380 if (bmp.sendTimingReq(pendingPacket)) { 381 waitForRetry = false; 382 pendingPacket = nullptr; 383 384 auto &trans = *pendingRequest; 385 sendEndReq(trans); 386 trans.release(); 387 388 pendingRequest = nullptr; 389 } 390} 391 392template <unsigned int BITWIDTH> 393void 394TlmToGem5Bridge<BITWIDTH>::recvRangeChange() 395{ 396 SC_REPORT_WARNING("TlmToGem5Bridge", 397 "received address range change but ignored it"); 398} 399 400template <unsigned int BITWIDTH> 401::Port & 402TlmToGem5Bridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx) 403{ 404 if (if_name == "gem5") 405 return bmp; 406 else if (if_name == "tlm") 407 return wrapper; 408 409 return sc_core::sc_module::gem5_getPort(if_name, idx); 410} 411 412template <unsigned int BITWIDTH> 413TlmToGem5Bridge<BITWIDTH>::TlmToGem5Bridge( 414 Params *params, const sc_core::sc_module_name &mn) : 415 TlmToGem5BridgeBase(mn), peq(this, &TlmToGem5Bridge<BITWIDTH>::peq_cb), 416 waitForRetry(false), pendingRequest(nullptr), pendingPacket(nullptr), 417 needToSendRetry(false), responseInProgress(false), 418 bmp(std::string(name()) + "master", *this), socket("tlm_socket"), 419 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID), 420 system(params->system), 421 masterId(params->system->getGlobalMasterId( 422 std::string("[systemc].") + name())) 423{ 424} 425 426template <unsigned int BITWIDTH> 427void 428TlmToGem5Bridge<BITWIDTH>::before_end_of_elaboration() 429{ 430 /* 431 * Register the TLM non-blocking interface when using gem5 Timing mode and 432 * the TLM blocking interface when using the gem5 Atomic mode. 433 * Then the magic (TM) in simple_target_socket automatically transforms 434 * non-blocking in blocking transactions and vice versa. 435 * 436 * NOTE: The mode may change during execution. 437 */ 438 if (system->isTimingMode()) { 439 SC_REPORT_INFO("TlmToGem5Bridge", "register non-blocking interface"); 440 socket.register_nb_transport_fw( 441 this, &TlmToGem5Bridge<BITWIDTH>::nb_transport_fw); 442 } else if (system->isAtomicMode()) { 443 SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface"); 444 socket.register_b_transport( 445 this, &TlmToGem5Bridge<BITWIDTH>::b_transport); 446 } else { 447 panic("gem5 operates neither in Timing nor in Atomic mode"); 448 } 449 450 socket.register_transport_dbg( 451 this, &TlmToGem5Bridge<BITWIDTH>::transport_dbg); 452 453 sc_core::sc_module::before_end_of_elaboration(); 454} 455 456} // namespace sc_gem5 457 458sc_gem5::TlmToGem5Bridge<32> * 459TlmToGem5Bridge32Params::create() 460{ 461 return new sc_gem5::TlmToGem5Bridge<32>( 462 this, sc_core::sc_module_name(name.c_str())); 463} 464 465sc_gem5::TlmToGem5Bridge<64> * 466TlmToGem5Bridge64Params::create() 467{ 468 return new sc_gem5::TlmToGem5Bridge<64>( 469 this, sc_core::sc_module_name(name.c_str())); 470} 471