gem5_to_tlm.cc revision 13823
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 a previously allocated tlm payload 84 */ 85void 86packet2payload(PacketPtr packet, tlm::tlm_generic_payload &trans) 87{ 88 trans.set_address(packet->getAddr()); 89 90 /* Check if this transaction was allocated by mm */ 91 sc_assert(trans.has_mm()); 92 93 unsigned int size = packet->getSize(); 94 unsigned char *data = packet->getPtr<unsigned char>(); 95 96 trans.set_data_length(size); 97 trans.set_streaming_width(size); 98 trans.set_data_ptr(data); 99 100 if (packet->isRead()) { 101 trans.set_command(tlm::TLM_READ_COMMAND); 102 } else if (packet->isInvalidate()) { 103 /* Do nothing */ 104 } else if (packet->isWrite()) { 105 trans.set_command(tlm::TLM_WRITE_COMMAND); 106 } else { 107 SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet"); 108 } 109} 110 111template <unsigned int BITWIDTH> 112void 113Gem5ToTlmBridge<BITWIDTH>::pec( 114 Gem5SystemC::PayloadEvent<Gem5ToTlmBridge<BITWIDTH>> *pe, 115 tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase) 116{ 117 sc_core::sc_time delay; 118 119 if (phase == tlm::END_REQ || 120 (&trans == blockingRequest && phase == tlm::BEGIN_RESP)) { 121 sc_assert(&trans == blockingRequest); 122 blockingRequest = nullptr; 123 124 // Did another request arrive while blocked, schedule a retry. 125 if (needToSendRequestRetry) { 126 needToSendRequestRetry = false; 127 bsp.sendRetryReq(); 128 } 129 } 130 if (phase == tlm::BEGIN_RESP) { 131 auto &extension = Gem5SystemC::Gem5Extension::getExtension(trans); 132 auto packet = extension.getPacket(); 133 134 sc_assert(!blockingResponse); 135 136 bool need_retry = false; 137 138 /* 139 * If the packet was piped through and needs a response, we don't need 140 * to touch the packet and can forward it directly as a response. 141 * Otherwise, we need to make a response and send the transformed 142 * packet. 143 */ 144 if (extension.isPipeThrough()) { 145 if (packet->isResponse()) { 146 need_retry = !bsp.sendTimingResp(packet); 147 } 148 } else if (packet->needsResponse()) { 149 packet->makeResponse(); 150 need_retry = !bsp.sendTimingResp(packet); 151 } 152 153 if (need_retry) { 154 blockingResponse = &trans; 155 } else { 156 if (phase == tlm::BEGIN_RESP) { 157 // Send END_RESP and we're finished: 158 tlm::tlm_phase fw_phase = tlm::END_RESP; 159 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 160 socket->nb_transport_fw(trans, fw_phase, delay); 161 // Release the transaction with all the extensions. 162 trans.release(); 163 } 164 } 165 } 166 delete pe; 167} 168 169// Similar to TLM's blocking transport (LT) 170template <unsigned int BITWIDTH> 171Tick 172Gem5ToTlmBridge<BITWIDTH>::recvAtomic(PacketPtr packet) 173{ 174 panic_if(packet->cacheResponding(), 175 "Should not see packets where cache is responding"); 176 177 panic_if(!(packet->isRead() || packet->isWrite()), 178 "Should only see read and writes at TLM memory\n"); 179 180 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 181 182 // Prepare the transaction. 183 tlm::tlm_generic_payload *trans = mm.allocate(); 184 trans->acquire(); 185 packet2payload(packet, *trans); 186 187 // Attach the packet pointer to the TLM transaction to keep track. 188 auto *extension = new Gem5SystemC::Gem5Extension(packet); 189 trans->set_auto_extension(extension); 190 191 // Execute b_transport: 192 if (packet->cmd == MemCmd::SwapReq) { 193 SC_REPORT_FATAL("Gem5ToTlmBridge", "SwapReq not supported"); 194 } else if (packet->isRead()) { 195 socket->b_transport(*trans, delay); 196 } else if (packet->isInvalidate()) { 197 // do nothing 198 } else if (packet->isWrite()) { 199 socket->b_transport(*trans, delay); 200 } else { 201 SC_REPORT_FATAL("Gem5ToTlmBridge", "Typo of request not supported"); 202 } 203 204 if (packet->needsResponse()) { 205 packet->makeResponse(); 206 } 207 208 trans->release(); 209 210 return delay.value(); 211} 212 213template <unsigned int BITWIDTH> 214void 215Gem5ToTlmBridge<BITWIDTH>::recvFunctionalSnoop(PacketPtr packet) 216{ 217 // Snooping should be implemented with tlm_dbg_transport. 218 SC_REPORT_FATAL("Gem5ToTlmBridge", 219 "unimplemented func.: recvFunctionalSnoop"); 220} 221 222// Similar to TLM's non-blocking transport (AT). 223template <unsigned int BITWIDTH> 224bool 225Gem5ToTlmBridge<BITWIDTH>::recvTimingReq(PacketPtr packet) 226{ 227 panic_if(packet->cacheResponding(), 228 "Should not see packets where cache is responding"); 229 230 panic_if(!(packet->isRead() || packet->isWrite()), 231 "Should only see read and writes at TLM memory\n"); 232 233 234 // We should never get a second request after noting that a retry is 235 // required. 236 sc_assert(!needToSendRequestRetry); 237 238 // Remember if a request comes in while we're blocked so that a retry 239 // can be sent to gem5. 240 if (blockingRequest) { 241 needToSendRequestRetry = true; 242 return false; 243 } 244 245 /* 246 * NOTE: normal tlm is blocking here. But in our case we return false 247 * and tell gem5 when a retry can be done. This is the main difference 248 * in the protocol: 249 * if (requestInProgress) 250 * { 251 * wait(endRequestEvent); 252 * } 253 * requestInProgress = trans; 254 */ 255 256 // Prepare the transaction. 257 tlm::tlm_generic_payload *trans = mm.allocate(); 258 trans->acquire(); 259 packet2payload(packet, *trans); 260 261 // Attach the packet pointer to the TLM transaction to keep track. 262 auto *extension = new Gem5SystemC::Gem5Extension(packet); 263 trans->set_auto_extension(extension); 264 265 /* 266 * Pay for annotated transport delays. 267 * 268 * The header delay marks the point in time, when the packet first is seen 269 * by the transactor. This is the point in time when the transactor needs 270 * to send the BEGIN_REQ to the SystemC world. 271 * 272 * NOTE: We drop the payload delay here. Normally, the receiver would be 273 * responsible for handling the payload delay. In this case, however, 274 * the receiver is a SystemC module and has no notion of the gem5 275 * transport protocol and we cannot simply forward the 276 * payload delay to the receiving module. Instead, we expect the 277 * receiving SystemC module to model the payload delay by deferring 278 * the END_REQ. This could lead to incorrect delays, if the XBar 279 * payload delay is longer than the time the receiver needs to accept 280 * the request (time between BEGIN_REQ and END_REQ). 281 * 282 * TODO: We could detect the case described above by remembering the 283 * payload delay and comparing it to the time between BEGIN_REQ and 284 * END_REQ. Then, a warning should be printed. 285 */ 286 auto delay = sc_core::sc_time::from_value(packet->payloadDelay); 287 // Reset the delays 288 packet->payloadDelay = 0; 289 packet->headerDelay = 0; 290 291 // Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC 292 // Standard Page 507 for a visualisation of the procedure. 293 tlm::tlm_phase phase = tlm::BEGIN_REQ; 294 tlm::tlm_sync_enum status; 295 status = socket->nb_transport_fw(*trans, phase, delay); 296 // Check returned value: 297 if (status == tlm::TLM_ACCEPTED) { 298 sc_assert(phase == tlm::BEGIN_REQ); 299 // Accepted but is now blocking until END_REQ (exclusion rule). 300 blockingRequest = trans; 301 } else if (status == tlm::TLM_UPDATED) { 302 // The Timing annotation must be honored: 303 sc_assert(phase == tlm::END_REQ || phase == tlm::BEGIN_RESP); 304 305 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>( 306 *this, &Gem5ToTlmBridge::pec, "PEQ"); 307 Tick nextEventTick = curTick() + delay.value(); 308 system->wakeupEventQueue(nextEventTick); 309 system->schedule(pe, nextEventTick); 310 } else if (status == tlm::TLM_COMPLETED) { 311 // Transaction is over nothing has do be done. 312 sc_assert(phase == tlm::END_RESP); 313 trans->release(); 314 } 315 316 return true; 317} 318 319template <unsigned int BITWIDTH> 320bool 321Gem5ToTlmBridge<BITWIDTH>::recvTimingSnoopResp(PacketPtr packet) 322{ 323 // Snooping should be implemented with tlm_dbg_transport. 324 SC_REPORT_FATAL("Gem5ToTlmBridge", 325 "unimplemented func.: recvTimingSnoopResp"); 326 return false; 327} 328 329template <unsigned int BITWIDTH> 330bool 331Gem5ToTlmBridge<BITWIDTH>::tryTiming(PacketPtr packet) 332{ 333 panic("tryTiming(PacketPtr) isn't implemented."); 334} 335 336template <unsigned int BITWIDTH> 337void 338Gem5ToTlmBridge<BITWIDTH>::recvRespRetry() 339{ 340 /* Retry a response */ 341 sc_assert(blockingResponse); 342 343 tlm::tlm_generic_payload *trans = blockingResponse; 344 blockingResponse = nullptr; 345 PacketPtr packet = 346 Gem5SystemC::Gem5Extension::getExtension(trans).getPacket(); 347 348 bool need_retry = !bsp.sendTimingResp(packet); 349 350 sc_assert(!need_retry); 351 352 sc_core::sc_time delay = sc_core::SC_ZERO_TIME; 353 tlm::tlm_phase phase = tlm::END_RESP; 354 socket->nb_transport_fw(*trans, phase, delay); 355 // Release transaction with all the extensions 356 trans->release(); 357} 358 359// Similar to TLM's debug transport. 360template <unsigned int BITWIDTH> 361void 362Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet) 363{ 364 // Prepare the transaction. 365 tlm::tlm_generic_payload *trans = mm.allocate(); 366 trans->acquire(); 367 packet2payload(packet, *trans); 368 369 // Attach the packet pointer to the TLM transaction to keep track. 370 auto *extension = new Gem5SystemC::Gem5Extension(packet); 371 trans->set_auto_extension(extension); 372 373 /* Execute Debug Transport: */ 374 unsigned int bytes = socket->transport_dbg(*trans); 375 if (bytes != trans->get_data_length()) { 376 SC_REPORT_FATAL("Gem5ToTlmBridge", 377 "debug transport was not completed"); 378 } 379 380 trans->release(); 381} 382 383template <unsigned int BITWIDTH> 384tlm::tlm_sync_enum 385Gem5ToTlmBridge<BITWIDTH>::nb_transport_bw(tlm::tlm_generic_payload &trans, 386 tlm::tlm_phase &phase, sc_core::sc_time &delay) 387{ 388 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>( 389 *this, &Gem5ToTlmBridge::pec, "PE"); 390 Tick nextEventTick = curTick() + delay.value(); 391 system->wakeupEventQueue(nextEventTick); 392 system->schedule(pe, nextEventTick); 393 return tlm::TLM_ACCEPTED; 394} 395 396template <unsigned int BITWIDTH> 397Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge( 398 Params *params, const sc_core::sc_module_name &mn) : 399 Gem5ToTlmBridgeBase(mn), bsp(std::string(name()) + ".gem5", *this), 400 socket("tlm_socket"), 401 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID), 402 system(params->system), blockingRequest(nullptr), 403 needToSendRequestRetry(false), blockingResponse(nullptr), 404 addrRanges(params->addr_ranges.begin(), params->addr_ranges.end()) 405{ 406} 407 408template <unsigned int BITWIDTH> 409::Port & 410Gem5ToTlmBridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx) 411{ 412 if (if_name == "gem5") 413 return bsp; 414 else if (if_name == "tlm") 415 return wrapper; 416 417 return sc_core::sc_module::gem5_getPort(if_name, idx); 418} 419 420template <unsigned int BITWIDTH> 421void 422Gem5ToTlmBridge<BITWIDTH>::before_end_of_elaboration() 423{ 424 bsp.sendRangeChange(); 425 426 socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw); 427 sc_core::sc_module::before_end_of_elaboration(); 428} 429 430} // namespace sc_gem5 431 432sc_gem5::Gem5ToTlmBridge<32> * 433Gem5ToTlmBridge32Params::create() 434{ 435 return new sc_gem5::Gem5ToTlmBridge<32>( 436 this, sc_core::sc_module_name(name.c_str())); 437} 438 439sc_gem5::Gem5ToTlmBridge<64> * 440Gem5ToTlmBridge64Params::create() 441{ 442 return new sc_gem5::Gem5ToTlmBridge<64>( 443 this, sc_core::sc_module_name(name.c_str())); 444} 445