04efce87b7d18995a1a1942541282d16aa07ca9a
2 * Copyright (c) 2015, University of Kaiserslautern
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Authors: Matthias Jung
40 #include "debug/ExternalPort.hh"
49 * Instantiate a tlm memory manager that takes care about all the
50 * tlm transactions in the system
55 * Convert a gem5 packet to a TLM payload by copying all the relevant
56 * information to a previously allocated tlm payload
59 packet2payload(PacketPtr packet
, tlm::tlm_generic_payload
&trans
)
61 trans
.set_address(packet
->getAddr());
63 /* Check if this transaction was allocated by mm */
64 sc_assert(trans
.has_mm());
66 unsigned int size
= packet
->getSize();
67 unsigned char *data
= packet
->getPtr
<unsigned char>();
69 trans
.set_data_length(size
);
70 trans
.set_streaming_width(size
);
71 trans
.set_data_ptr(data
);
73 if (packet
->isRead()) {
74 trans
.set_command(tlm::TLM_READ_COMMAND
);
76 else if (packet
->isInvalidate()) {
78 } else if (packet
->isWrite()) {
79 trans
.set_command(tlm::TLM_WRITE_COMMAND
);
81 SC_REPORT_FATAL("transactor", "No R/W packet");
86 * Similar to TLM's blocking transport (LT)
89 sc_transactor::recvAtomic(PacketPtr packet
)
92 SC_REPORT_INFO("transactor", "recvAtomic hasn't been tested much");
94 sc_core::sc_time delay
= sc_core::SC_ZERO_TIME
;
97 /* Prepare the transaction */
98 tlm::tlm_generic_payload
* trans
= mm
.allocate();
100 packet2payload(packet
, *trans
);
102 /* Attach the packet pointer to the TLM transaction to keep track */
103 gem5Extension
* extension
= new gem5Extension(packet
);
104 trans
->set_auto_extension(extension
);
106 /* Execute b_transport: */
107 if (packet
->cmd
== MemCmd::SwapReq
) {
108 SC_REPORT_FATAL("transactor", "SwapReq not supported");
109 } else if (packet
->isRead()) {
110 iSocket
->b_transport(*trans
, delay
);
111 } else if (packet
->isInvalidate()) {
113 } else if (packet
->isWrite()) {
114 iSocket
->b_transport(*trans
, delay
);
116 SC_REPORT_FATAL("transactor", "Typo of request not supported");
119 if (packet
->needsResponse()) {
120 packet
->makeResponse();
125 return delay
.value();
129 * Similar to TLM's debug transport
132 sc_transactor::recvFunctional(PacketPtr packet
)
134 /* Prepare the transaction */
135 tlm::tlm_generic_payload
* trans
= mm
.allocate();
137 packet2payload(packet
, *trans
);
139 /* Attach the packet pointer to the TLM transaction to keep track */
140 gem5Extension
* extension
= new gem5Extension(packet
);
141 trans
->set_auto_extension(extension
);
143 /* Execute Debug Transport: */
144 unsigned int bytes
= iSocket
->transport_dbg(*trans
);
145 if (bytes
!= trans
->get_data_length()) {
146 SC_REPORT_FATAL("transactor","debug transport was not completed");
153 sc_transactor::recvTimingSnoopResp(PacketPtr packet
)
155 /* Snooping should be implemented with tlm_dbg_transport */
156 SC_REPORT_FATAL("transactor","unimplemented func.: recvTimingSnoopResp");
161 sc_transactor::recvFunctionalSnoop(PacketPtr packet
)
163 /* Snooping should be implemented with tlm_dbg_transport */
164 SC_REPORT_FATAL("transactor","unimplemented func.: recvFunctionalSnoop");
168 * Similar to TLM's non-blocking transport (AT)
171 sc_transactor::recvTimingReq(PacketPtr packet
)
175 /* We should never get a second request after noting that a retry is
177 sc_assert(!needToSendRequestRetry
);
179 // simply drop inhibited packets and clean evictions
180 if (packet
->memInhibitAsserted() ||
181 packet
->cmd
== MemCmd::CleanEvict
)
184 /* Remember if a request comes in while we're blocked so that a retry
185 * can be sent to gem5 */
186 if (blockingRequest
) {
187 needToSendRequestRetry
= true;
191 /* NOTE: normal tlm is blocking here. But in our case we return false
192 * and tell gem5 when a retry can be done. This is the main difference
194 * if (requestInProgress)
196 * wait(endRequestEvent);
198 * requestInProgress = trans;
201 /* Prepare the transaction */
202 tlm::tlm_generic_payload
* trans
= mm
.allocate();
204 packet2payload(packet
, *trans
);
206 /* Attach the packet pointer to the TLM transaction to keep track */
207 gem5Extension
* extension
= new gem5Extension(packet
);
208 trans
->set_auto_extension(extension
);
210 /* Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC
211 * Standard Page 507 for a visualisation of the procedure */
212 sc_core::sc_time delay
= sc_core::SC_ZERO_TIME
;
213 tlm::tlm_phase phase
= tlm::BEGIN_REQ
;
214 tlm::tlm_sync_enum status
;
215 status
= iSocket
->nb_transport_fw(*trans
, phase
, delay
);
216 /* Check returned value: */
217 if (status
== tlm::TLM_ACCEPTED
) {
218 sc_assert(phase
== tlm::BEGIN_REQ
);
219 /* Accepted but is now blocking until END_REQ (exclusion rule)*/
220 blockingRequest
= trans
;
221 } else if (status
== tlm::TLM_UPDATED
) {
222 /* The Timing annotation must be honored: */
223 sc_assert(phase
== tlm::END_REQ
|| phase
== tlm::BEGIN_RESP
);
225 payloadEvent
<sc_transactor
> * pe
;
226 pe
= new payloadEvent
<sc_transactor
>(*this,
227 &sc_transactor::pec
, "PEQ");
228 pe
->notify(*trans
, phase
, delay
);
229 } else if (status
== tlm::TLM_COMPLETED
) {
230 /* Transaction is over nothing has do be done. */
231 sc_assert(phase
== tlm::END_RESP
);
240 sc_transactor::payloadEvent
<sc_transactor
> * pe
,
241 tlm::tlm_generic_payload
& trans
,
242 const tlm::tlm_phase
& phase
)
246 if (phase
== tlm::END_REQ
||
247 &trans
== blockingRequest
&& phase
== tlm::BEGIN_RESP
) {
248 sc_assert(&trans
== blockingRequest
);
249 blockingRequest
= NULL
;
251 /* Did another request arrive while blocked, schedule a retry */
252 if (needToSendRequestRetry
) {
253 needToSendRequestRetry
= false;
254 iSocket
.sendRetryReq();
257 else if (phase
== tlm::BEGIN_RESP
)
261 PacketPtr packet
= gem5Extension::getExtension(trans
).getPacket();
263 sc_assert(!blockingResponse
);
266 if (packet
->needsResponse()) {
267 packet
->makeResponse();
268 need_retry
= !iSocket
.sendTimingResp(packet
);
274 blockingResponse
= &trans
;
276 if (phase
== tlm::BEGIN_RESP
) {
277 /* Send END_RESP and we're finished: */
278 tlm::tlm_phase fw_phase
= tlm::END_RESP
;
279 sc_time delay
= SC_ZERO_TIME
;
280 iSocket
->nb_transport_fw(trans
, fw_phase
, delay
);
281 /* Release the transaction with all the extensions */
286 SC_REPORT_FATAL("transactor", "Invalid protocol phase in pec");
292 sc_transactor::recvRespRetry()
296 /* Retry a response */
297 sc_assert(blockingResponse
);
299 tlm::tlm_generic_payload
*trans
= blockingResponse
;
300 blockingResponse
= NULL
;
301 PacketPtr packet
= gem5Extension::getExtension(trans
).getPacket();
303 bool need_retry
= !iSocket
.sendTimingResp(packet
);
305 sc_assert(!need_retry
);
307 sc_core::sc_time delay
= sc_core::SC_ZERO_TIME
;
308 tlm::tlm_phase phase
= tlm::END_RESP
;
309 iSocket
->nb_transport_fw(*trans
, phase
, delay
);
310 // Release transaction with all the extensions
315 sc_transactor::nb_transport_bw(tlm::tlm_generic_payload
& trans
,
316 tlm::tlm_phase
& phase
,
317 sc_core::sc_time
& delay
)
319 payloadEvent
<sc_transactor
> * pe
;
320 pe
= new payloadEvent
<sc_transactor
>(*this, &sc_transactor::pec
, "PE");
321 pe
->notify(trans
, phase
, delay
);
322 return tlm::TLM_ACCEPTED
;
326 sc_transactor::invalidate_direct_mem_ptr(sc_dt::uint64 start_range
,
327 sc_dt::uint64 end_range
)
329 SC_REPORT_FATAL("transactor", "unimpl. func: invalidate_direct_mem_ptr");
332 sc_transactor::sc_transactor(const std::string
&name_
,
333 const std::string
&systemc_name
,
334 ExternalSlave
&owner_
) :
335 tlm::tlm_initiator_socket
<>(systemc_name
.c_str()),
336 ExternalSlave::Port(name_
, owner_
),
338 blockingRequest(NULL
),
339 needToSendRequestRetry(false),
340 blockingResponse(NULL
)
342 m_export
.bind(*this);
345 class sc_transactorHandler
: public ExternalSlave::Handler
348 ExternalSlave::Port
*getExternalPort(const std::string
&name
,
349 ExternalSlave
&owner
,
350 const std::string
&port_data
)
352 // This will make a new initiatiator port
353 return new sc_transactor(name
, port_data
, owner
);
360 ExternalSlave::registerHandler("tlm", new sc_transactorHandler
);