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(MasterID masterId
, 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
, masterId
);
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(masterId
, trans
);
162 auto tlmSenderState
= new TlmSenderState(trans
);
163 pkt
->pushSenderState(tlmSenderState
);
165 if (bmp
.sendTimingReq(pkt
)) { // port is free -> send END_REQ immediately
168 } else { // port is blocked -> wait for retry before sending END_REQ
170 pendingRequest
= &trans
;
175 template <unsigned int BITWIDTH
>
177 TlmToGem5Bridge
<BITWIDTH
>::handleEndResp(tlm::tlm_generic_payload
&trans
)
179 sc_assert(responseInProgress
);
181 responseInProgress
= false;
183 checkTransaction(trans
);
185 if (needToSendRetry
) {
187 needToSendRetry
= false;
191 template <unsigned int BITWIDTH
>
193 TlmToGem5Bridge
<BITWIDTH
>::destroyPacket(PacketPtr pkt
)
198 template <unsigned int BITWIDTH
>
200 TlmToGem5Bridge
<BITWIDTH
>::checkTransaction(tlm::tlm_generic_payload
&trans
)
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());
210 template <unsigned int BITWIDTH
>
212 TlmToGem5Bridge
<BITWIDTH
>::invalidateDmi(const ::MemBackdoor
&backdoor
)
214 socket
->invalidate_direct_mem_ptr(
215 backdoor
.range().start(), backdoor
.range().end());
218 template <unsigned int BITWIDTH
>
220 TlmToGem5Bridge
<BITWIDTH
>::peq_cb(tlm::tlm_generic_payload
&trans
,
221 const tlm::tlm_phase
&phase
)
225 handleBeginReq(trans
);
228 handleEndResp(trans
);
231 panic("unimplemented phase in callback");
235 template <unsigned int BITWIDTH
>
237 TlmToGem5Bridge
<BITWIDTH
>::nb_transport_fw(
238 tlm::tlm_generic_payload
&trans
, tlm::tlm_phase
&phase
,
239 sc_core::sc_time
&delay
)
241 unsigned len
= trans
.get_data_length();
242 unsigned char *byteEnable
= trans
.get_byte_enable_ptr();
243 unsigned width
= trans
.get_streaming_width();
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
;
250 if (width
< len
) { // is this a burst request?
251 trans
.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE
);
252 return tlm::TLM_COMPLETED
;
255 // ... and queue the valid transaction
257 peq
.notify(trans
, phase
, delay
);
258 return tlm::TLM_ACCEPTED
;
261 template <unsigned int BITWIDTH
>
263 TlmToGem5Bridge
<BITWIDTH
>::b_transport(tlm::tlm_generic_payload
&trans
,
266 Gem5SystemC::Gem5Extension
*extension
= nullptr;
267 trans
.get_extension(extension
);
269 PacketPtr pkt
= nullptr;
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();
277 pkt
= payload2packet(masterId
, trans
);
280 MemBackdoorPtr backdoor
= nullptr;
281 Tick ticks
= bmp
.sendAtomicBackdoor(pkt
, backdoor
);
283 trans
.set_dmi_allowed(true);
285 // send an atomic request to gem5
286 panic_if(pkt
->needsResponse() && !pkt
->isResponse(),
287 "Packet sending failed!\n");
290 sc_core::sc_time((double)(ticks
/ SimClock::Int::ps
), sc_core::SC_PS
);
295 if (extension
== nullptr)
298 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
301 template <unsigned int BITWIDTH
>
303 TlmToGem5Bridge
<BITWIDTH
>::transport_dbg(tlm::tlm_generic_payload
&trans
)
305 Gem5SystemC::Gem5Extension
*extension
= nullptr;
306 trans
.get_extension(extension
);
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());
314 auto pkt
= payload2packet(masterId
, trans
);
316 bmp
.sendFunctional(pkt
);
321 return trans
.get_data_length();
324 template <unsigned int BITWIDTH
>
326 TlmToGem5Bridge
<BITWIDTH
>::get_direct_mem_ptr(tlm::tlm_generic_payload
&trans
,
327 tlm::tlm_dmi
&dmi_data
)
329 Gem5SystemC::Gem5Extension
*extension
= nullptr;
330 trans
.get_extension(extension
);
332 PacketPtr pkt
= nullptr;
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();
340 pkt
= payload2packet(masterId
, trans
);
341 pkt
->req
->setFlags(Request::NO_ACCESS
);
344 MemBackdoorPtr backdoor
= nullptr;
345 bmp
.sendAtomicBackdoor(pkt
, 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());
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
);
360 backdoor
->addInvalidationCallback(
361 [this](const MemBackdoor
&backdoor
)
363 invalidateDmi(backdoor
);
368 if (extension
== nullptr)
371 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
373 return backdoor
!= nullptr;
376 template <unsigned int BITWIDTH
>
378 TlmToGem5Bridge
<BITWIDTH
>::recvTimingResp(PacketPtr pkt
)
381 // We need to Wait for END_RESP before sending next BEGIN_RESP
382 if (responseInProgress
) {
383 sc_assert(!needToSendRetry
);
384 needToSendRetry
= true;
388 sc_assert(pkt
->isResponse());
391 * Pay for annotated transport delays.
393 * See recvTimingReq in sc_slave_port.cc for a detailed description.
395 auto delay
= sc_core::sc_time::from_value(pkt
->payloadDelay
);
397 pkt
->payloadDelay
= 0;
398 pkt
->headerDelay
= 0;
400 auto tlmSenderState
= dynamic_cast<TlmSenderState
*>(pkt
->popSenderState());
401 sc_assert(tlmSenderState
!= nullptr);
403 auto &trans
= tlmSenderState
->trans
;
405 Gem5SystemC::Gem5Extension
*extension
= nullptr;
406 trans
.get_extension(extension
);
409 delete tlmSenderState
;
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)
416 sc_assert(extension
->isPipeThrough());
418 sendBeginResp(trans
, delay
);
424 template <unsigned int BITWIDTH
>
426 TlmToGem5Bridge
<BITWIDTH
>::recvReqRetry()
428 sc_assert(waitForRetry
);
429 sc_assert(pendingRequest
!= nullptr);
430 sc_assert(pendingPacket
!= nullptr);
432 if (bmp
.sendTimingReq(pendingPacket
)) {
433 waitForRetry
= false;
434 pendingPacket
= nullptr;
436 auto &trans
= *pendingRequest
;
440 pendingRequest
= nullptr;
444 template <unsigned int BITWIDTH
>
446 TlmToGem5Bridge
<BITWIDTH
>::recvRangeChange()
448 SC_REPORT_WARNING("TlmToGem5Bridge",
449 "received address range change but ignored it");
452 template <unsigned int BITWIDTH
>
454 TlmToGem5Bridge
<BITWIDTH
>::gem5_getPort(const std::string
&if_name
, int idx
)
456 if (if_name
== "gem5")
458 else if (if_name
== "tlm")
461 return sc_core::sc_module::gem5_getPort(if_name
, idx
);
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()))
478 template <unsigned int BITWIDTH
>
480 TlmToGem5Bridge
<BITWIDTH
>::before_end_of_elaboration()
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.
488 * NOTE: The mode may change during execution.
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
);
501 panic("gem5 operates neither in Timing nor in Atomic mode");
504 socket
.register_transport_dbg(
505 this, &TlmToGem5Bridge
<BITWIDTH
>::transport_dbg
);
507 sc_core::sc_module::before_end_of_elaboration();
510 } // namespace sc_gem5
512 sc_gem5::TlmToGem5Bridge
<32> *
513 TlmToGem5Bridge32Params::create()
515 return new sc_gem5::TlmToGem5Bridge
<32>(
516 this, sc_core::sc_module_name(name
.c_str()));
519 sc_gem5::TlmToGem5Bridge
<64> *
520 TlmToGem5Bridge64Params::create()
522 return new sc_gem5::TlmToGem5Bridge
<64>(
523 this, sc_core::sc_module_name(name
.c_str()));