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