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