2 * Copyright 2019 Google, Inc.
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.
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.
27 * Copyright (c) 2016, Dresden University of Technology (TU Dresden)
28 * All rights reserved.
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions are
34 * 1. Redistributions of source code must retain the above copyright notice,
35 * this list of conditions and the following disclaimer.
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.
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.
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.
58 #include "systemc/tlm_bridge/tlm_to_gem5.hh"
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"
70 payload2packet(RequestorID _id
, tlm::tlm_generic_payload
&trans
)
74 switch (trans
.get_command()) {
75 case tlm::TLM_READ_COMMAND
:
76 cmd
= MemCmd::ReadReq
;
78 case tlm::TLM_WRITE_COMMAND
:
79 cmd
= MemCmd::WriteReq
;
81 case tlm::TLM_IGNORE_COMMAND
:
84 SC_REPORT_FATAL("TlmToGem5Bridge",
85 "received transaction with unsupported command");
89 auto req
= std::make_shared
<Request
>(
90 trans
.get_address(), trans
.get_data_length(), flags
, _id
);
93 * Allocate a new Packet. The packet will be deleted when it returns from
94 * the gem5 world as a response.
96 auto pkt
= new Packet(req
, cmd
);
97 pkt
->dataStatic(trans
.get_data_ptr());
102 template <unsigned int BITWIDTH
>
104 TlmToGem5Bridge
<BITWIDTH
>::sendEndReq(tlm::tlm_generic_payload
&trans
)
106 tlm::tlm_phase phase
= tlm::END_REQ
;
107 auto delay
= sc_core::SC_ZERO_TIME
;
109 auto status
= socket
->nb_transport_bw(trans
, phase
, delay
);
110 panic_if(status
!= tlm::TLM_ACCEPTED
,
111 "Unexpected status after sending END_REQ");
114 template <unsigned int BITWIDTH
>
116 TlmToGem5Bridge
<BITWIDTH
>::sendBeginResp(tlm::tlm_generic_payload
&trans
,
117 sc_core::sc_time
&delay
)
119 tlm::tlm_phase phase
= tlm::BEGIN_RESP
;
121 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
123 auto status
= socket
->nb_transport_bw(trans
, phase
, delay
);
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;
133 panic("Unexpected status after sending BEGIN_RESP");
137 template <unsigned int BITWIDTH
>
139 TlmToGem5Bridge
<BITWIDTH
>::handleBeginReq(tlm::tlm_generic_payload
&trans
)
141 sc_assert(!waitForRetry
);
142 sc_assert(pendingRequest
== nullptr);
143 sc_assert(pendingPacket
== nullptr);
147 PacketPtr pkt
= nullptr;
149 Gem5SystemC::Gem5Extension
*extension
= nullptr;
150 trans
.get_extension(extension
);
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();
159 pkt
= payload2packet(_id
, trans
);
162 auto tlmSenderState
= new TlmSenderState(trans
);
163 pkt
->pushSenderState(tlmSenderState
);
165 // If the packet doesn't need a response, we should send BEGIN_RESP by
167 bool needsResponse
= pkt
->needsResponse();
168 if (bmp
.sendTimingReq(pkt
)) { // port is free -> send END_REQ immediately
170 if (!needsResponse
) {
171 auto delay
= sc_core::SC_ZERO_TIME
;
172 sendBeginResp(trans
, delay
);
175 } else { // port is blocked -> wait for retry before sending END_REQ
177 pendingRequest
= &trans
;
182 template <unsigned int BITWIDTH
>
184 TlmToGem5Bridge
<BITWIDTH
>::handleEndResp(tlm::tlm_generic_payload
&trans
)
186 sc_assert(responseInProgress
);
188 responseInProgress
= false;
190 checkTransaction(trans
);
192 if (needToSendRetry
) {
194 needToSendRetry
= false;
198 template <unsigned int BITWIDTH
>
200 TlmToGem5Bridge
<BITWIDTH
>::destroyPacket(PacketPtr pkt
)
205 template <unsigned int BITWIDTH
>
207 TlmToGem5Bridge
<BITWIDTH
>::checkTransaction(tlm::tlm_generic_payload
&trans
)
209 if (trans
.is_response_error()) {
210 std::stringstream ss
;
211 ss
<< "Transaction returned with error, response status = "
212 << trans
.get_response_string();
213 SC_REPORT_ERROR("TLM-2", ss
.str().c_str());
217 template <unsigned int BITWIDTH
>
219 TlmToGem5Bridge
<BITWIDTH
>::invalidateDmi(const ::MemBackdoor
&backdoor
)
221 socket
->invalidate_direct_mem_ptr(
222 backdoor
.range().start(), backdoor
.range().end());
225 template <unsigned int BITWIDTH
>
227 TlmToGem5Bridge
<BITWIDTH
>::peq_cb(tlm::tlm_generic_payload
&trans
,
228 const tlm::tlm_phase
&phase
)
232 handleBeginReq(trans
);
235 handleEndResp(trans
);
238 panic("unimplemented phase in callback");
242 template <unsigned int BITWIDTH
>
244 TlmToGem5Bridge
<BITWIDTH
>::nb_transport_fw(
245 tlm::tlm_generic_payload
&trans
, tlm::tlm_phase
&phase
,
246 sc_core::sc_time
&delay
)
248 unsigned len
= trans
.get_data_length();
249 unsigned char *byteEnable
= trans
.get_byte_enable_ptr();
250 unsigned width
= trans
.get_streaming_width();
252 // check the transaction attributes for unsupported features ...
253 if (byteEnable
!= 0) {
254 trans
.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE
);
255 return tlm::TLM_COMPLETED
;
257 if (width
< len
) { // is this a burst request?
258 trans
.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE
);
259 return tlm::TLM_COMPLETED
;
262 // ... and queue the valid transaction
264 peq
.notify(trans
, phase
, delay
);
265 return tlm::TLM_ACCEPTED
;
268 template <unsigned int BITWIDTH
>
270 TlmToGem5Bridge
<BITWIDTH
>::b_transport(tlm::tlm_generic_payload
&trans
,
273 Gem5SystemC::Gem5Extension
*extension
= nullptr;
274 trans
.get_extension(extension
);
276 PacketPtr pkt
= nullptr;
278 // If there is an extension, this transaction was initiated by the gem5
279 // world and we can pipe through the original packet.
280 if (extension
!= nullptr) {
281 extension
->setPipeThrough();
282 pkt
= extension
->getPacket();
284 pkt
= payload2packet(_id
, trans
);
287 MemBackdoorPtr backdoor
= nullptr;
288 Tick ticks
= bmp
.sendAtomicBackdoor(pkt
, backdoor
);
290 trans
.set_dmi_allowed(true);
292 // send an atomic request to gem5
293 panic_if(pkt
->needsResponse() && !pkt
->isResponse(),
294 "Packet sending failed!\n");
297 sc_core::sc_time((double)(ticks
/ SimClock::Int::ps
), sc_core::SC_PS
);
302 if (extension
== nullptr)
305 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
308 template <unsigned int BITWIDTH
>
310 TlmToGem5Bridge
<BITWIDTH
>::transport_dbg(tlm::tlm_generic_payload
&trans
)
312 Gem5SystemC::Gem5Extension
*extension
= nullptr;
313 trans
.get_extension(extension
);
315 // If there is an extension, this transaction was initiated by the gem5
316 // world and we can pipe through the original packet.
317 if (extension
!= nullptr) {
318 extension
->setPipeThrough();
319 bmp
.sendFunctional(extension
->getPacket());
321 auto pkt
= payload2packet(_id
, trans
);
323 bmp
.sendFunctional(pkt
);
328 return trans
.get_data_length();
331 template <unsigned int BITWIDTH
>
333 TlmToGem5Bridge
<BITWIDTH
>::get_direct_mem_ptr(tlm::tlm_generic_payload
&trans
,
334 tlm::tlm_dmi
&dmi_data
)
336 Gem5SystemC::Gem5Extension
*extension
= nullptr;
337 trans
.get_extension(extension
);
339 PacketPtr pkt
= nullptr;
341 // If there is an extension, this transaction was initiated by the gem5
342 // world and we can pipe through the original packet.
343 if (extension
!= nullptr) {
344 extension
->setPipeThrough();
345 pkt
= extension
->getPacket();
347 pkt
= payload2packet(_id
, trans
);
348 pkt
->req
->setFlags(Request::NO_ACCESS
);
351 MemBackdoorPtr backdoor
= nullptr;
352 bmp
.sendAtomicBackdoor(pkt
, backdoor
);
354 trans
.set_dmi_allowed(true);
355 dmi_data
.set_dmi_ptr(backdoor
->ptr());
356 dmi_data
.set_start_address(backdoor
->range().start());
357 dmi_data
.set_end_address(backdoor
->range().end());
359 typedef tlm::tlm_dmi::dmi_access_e access_t
;
360 access_t access
= tlm::tlm_dmi::DMI_ACCESS_NONE
;
361 if (backdoor
->readable())
362 access
= (access_t
)(access
| tlm::tlm_dmi::DMI_ACCESS_READ
);
363 if (backdoor
->writeable())
364 access
= (access_t
)(access
| tlm::tlm_dmi::DMI_ACCESS_WRITE
);
365 dmi_data
.set_granted_access(access
);
367 backdoor
->addInvalidationCallback(
368 [this](const MemBackdoor
&backdoor
)
370 invalidateDmi(backdoor
);
375 if (extension
== nullptr)
378 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
380 return backdoor
!= nullptr;
383 template <unsigned int BITWIDTH
>
385 TlmToGem5Bridge
<BITWIDTH
>::recvTimingResp(PacketPtr pkt
)
388 // We need to Wait for END_RESP before sending next BEGIN_RESP
389 if (responseInProgress
) {
390 sc_assert(!needToSendRetry
);
391 needToSendRetry
= true;
395 sc_assert(pkt
->isResponse());
398 * Pay for annotated transport delays.
400 * See recvTimingReq in sc_slave_port.cc for a detailed description.
402 auto delay
= sc_core::sc_time::from_value(pkt
->payloadDelay
);
404 pkt
->payloadDelay
= 0;
405 pkt
->headerDelay
= 0;
407 auto tlmSenderState
= dynamic_cast<TlmSenderState
*>(pkt
->popSenderState());
408 sc_assert(tlmSenderState
!= nullptr);
410 auto &trans
= tlmSenderState
->trans
;
412 Gem5SystemC::Gem5Extension
*extension
= nullptr;
413 trans
.get_extension(extension
);
416 delete tlmSenderState
;
418 // If there is an extension the packet was piped through and we must not
419 // delete it. The packet travels back with the transaction.
420 if (extension
== nullptr)
423 sc_assert(extension
->isPipeThrough());
425 sendBeginResp(trans
, delay
);
431 template <unsigned int BITWIDTH
>
433 TlmToGem5Bridge
<BITWIDTH
>::recvReqRetry()
435 sc_assert(waitForRetry
);
436 sc_assert(pendingRequest
!= nullptr);
437 sc_assert(pendingPacket
!= nullptr);
439 // If the packet doesn't need a response, we should send BEGIN_RESP by
441 bool needsResponse
= pendingPacket
->needsResponse();
442 if (bmp
.sendTimingReq(pendingPacket
)) {
443 waitForRetry
= false;
444 pendingPacket
= nullptr;
446 auto &trans
= *pendingRequest
;
448 if (!needsResponse
) {
449 auto delay
= sc_core::SC_ZERO_TIME
;
450 sendBeginResp(trans
, delay
);
454 pendingRequest
= nullptr;
458 template <unsigned int BITWIDTH
>
460 TlmToGem5Bridge
<BITWIDTH
>::recvRangeChange()
462 SC_REPORT_WARNING("TlmToGem5Bridge",
463 "received address range change but ignored it");
466 template <unsigned int BITWIDTH
>
468 TlmToGem5Bridge
<BITWIDTH
>::gem5_getPort(const std::string
&if_name
, int idx
)
470 if (if_name
== "gem5")
472 else if (if_name
== "tlm")
475 return sc_core::sc_module::gem5_getPort(if_name
, idx
);
478 template <unsigned int BITWIDTH
>
479 TlmToGem5Bridge
<BITWIDTH
>::TlmToGem5Bridge(
480 Params
*params
, const sc_core::sc_module_name
&mn
) :
481 TlmToGem5BridgeBase(mn
), peq(this, &TlmToGem5Bridge
<BITWIDTH
>::peq_cb
),
482 waitForRetry(false), pendingRequest(nullptr), pendingPacket(nullptr),
483 needToSendRetry(false), responseInProgress(false),
484 bmp(std::string(name()) + "master", *this), socket("tlm_socket"),
485 wrapper(socket
, std::string(name()) + ".tlm", InvalidPortID
),
486 system(params
->system
),
487 _id(params
->system
->getGlobalRequestorId(
488 std::string("[systemc].") + name()))
492 template <unsigned int BITWIDTH
>
494 TlmToGem5Bridge
<BITWIDTH
>::before_end_of_elaboration()
497 * Register the TLM non-blocking interface when using gem5 Timing mode and
498 * the TLM blocking interface when using the gem5 Atomic mode.
499 * Then the magic (TM) in simple_target_socket automatically transforms
500 * non-blocking in blocking transactions and vice versa.
502 * NOTE: The mode may change during execution.
504 if (system
->isTimingMode()) {
505 SC_REPORT_INFO("TlmToGem5Bridge", "register non-blocking interface");
506 socket
.register_nb_transport_fw(
507 this, &TlmToGem5Bridge
<BITWIDTH
>::nb_transport_fw
);
508 } else if (system
->isAtomicMode()) {
509 SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface");
510 socket
.register_b_transport(
511 this, &TlmToGem5Bridge
<BITWIDTH
>::b_transport
);
512 socket
.register_get_direct_mem_ptr(
513 this, &TlmToGem5Bridge
<BITWIDTH
>::get_direct_mem_ptr
);
515 panic("gem5 operates neither in Timing nor in Atomic mode");
518 socket
.register_transport_dbg(
519 this, &TlmToGem5Bridge
<BITWIDTH
>::transport_dbg
);
521 sc_core::sc_module::before_end_of_elaboration();
524 } // namespace sc_gem5
526 sc_gem5::TlmToGem5Bridge
<32> *
527 TlmToGem5Bridge32Params::create()
529 return new sc_gem5::TlmToGem5Bridge
<32>(
530 this, sc_core::sc_module_name(name
.c_str()));
533 sc_gem5::TlmToGem5Bridge
<64> *
534 TlmToGem5Bridge64Params::create()
536 return new sc_gem5::TlmToGem5Bridge
<64>(
537 this, sc_core::sc_module_name(name
.c_str()));