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