2 * Copyright (c) 2016, Dresden University of Technology (TU Dresden)
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: Christian Menard
37 #include "master_transactor.hh"
38 #include "params/ExternalMaster.hh"
40 #include "sc_master_port.hh"
41 #include "sim/system.hh"
47 SCMasterPort::generatePacket(tlm::tlm_generic_payload
& trans
)
50 auto req
= new Request(trans
.get_address(), trans
.get_data_length(), flags
,
55 switch (trans
.get_command()) {
56 case tlm::TLM_READ_COMMAND
:
57 cmd
= MemCmd::ReadReq
;
59 case tlm::TLM_WRITE_COMMAND
:
60 cmd
= MemCmd::WriteReq
;
63 SC_REPORT_FATAL("SCMasterPort",
64 "received transaction with unsupported command");
68 * Allocate a new Packet. The packet will be deleted when it returns from
69 * the gem5 world as a response.
71 auto pkt
= new Packet(req
, cmd
);
72 pkt
->dataStatic(trans
.get_data_ptr());
78 SCMasterPort::destroyPacket(PacketPtr pkt
)
83 SCMasterPort::SCMasterPort(const std::string
& name_
,
84 const std::string
& systemc_name
,
85 ExternalMaster
& owner_
,
86 Gem5SimControl
& simControl
)
87 : ExternalMaster::Port(name_
, owner_
),
88 peq(this, &SCMasterPort::peq_cb
),
90 pendingRequest(nullptr),
91 pendingPacket(nullptr),
92 needToSendRetry(false),
93 responseInProgress(false),
95 simControl(simControl
)
98 dynamic_cast<const ExternalMasterParams
*>(owner_
.params())->system
;
102 SCMasterPort::bindToTransactor(Gem5MasterTransactor
* transactor
)
104 sc_assert(this->transactor
== nullptr);
106 this->transactor
= transactor
;
109 * Register the TLM non-blocking interface when using gem5 Timing mode and
110 * the TLM blocking interface when using the gem5 Atomic mode.
111 * Then the magic (TM) in simple_target_socket automatically transforms
112 * non-blocking in blocking transactions and vice versa.
114 * NOTE: The mode may change during execution.
116 if (system
->isTimingMode()) {
117 SC_REPORT_INFO("SCMasterPort", "register non-blocking interface");
118 transactor
->socket
.register_nb_transport_fw(this,
119 &SCMasterPort::nb_transport_fw
);
120 } else if (system
->isAtomicMode()) {
121 SC_REPORT_INFO("SCMasterPort", "register blocking interface");
122 transactor
->socket
.register_b_transport(this,
123 &SCMasterPort::b_transport
);
125 panic("gem5 operates neither in Timing nor in Atomic mode");
128 transactor
->socket
.register_transport_dbg(this,
129 &SCMasterPort::transport_dbg
);
133 SCMasterPort::checkTransaction(tlm::tlm_generic_payload
& trans
)
135 if (trans
.is_response_error()) {
136 std::stringstream ss
;
137 ss
<< "Transaction returned with error, response status = "
138 << trans
.get_response_string();
139 SC_REPORT_ERROR("TLM-2", ss
.str().c_str());
144 SCMasterPort::nb_transport_fw(tlm::tlm_generic_payload
& trans
,
145 tlm::tlm_phase
& phase
, sc_core::sc_time
& delay
)
147 uint64_t adr
= trans
.get_address();
148 unsigned len
= trans
.get_data_length();
149 unsigned char* byteEnable
= trans
.get_byte_enable_ptr();
150 unsigned width
= trans
.get_streaming_width();
152 // check the transaction attributes for unsupported features ...
153 if (byteEnable
!= 0) {
154 trans
.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE
);
155 return tlm::TLM_COMPLETED
;
157 if (width
< len
) { // is this a burst request?
158 trans
.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE
);
159 return tlm::TLM_COMPLETED
;
162 // ... and queue the valid transaction
164 peq
.notify(trans
, phase
, delay
);
165 return tlm::TLM_ACCEPTED
;
169 SCMasterPort::peq_cb(tlm::tlm_generic_payload
& trans
,
170 const tlm::tlm_phase
& phase
)
172 // catch up with SystemC time
173 simControl
.catchup();
174 assert(curTick() == sc_core::sc_time_stamp().value());
178 handleBeginReq(trans
);
181 handleEndResp(trans
);
184 panic("unimplemented phase in callback");
187 // the functions called above may have scheduled gem5 events
188 // -> notify the event loop handler
193 SCMasterPort::handleBeginReq(tlm::tlm_generic_payload
& trans
)
195 sc_assert(!waitForRetry
);
196 sc_assert(pendingRequest
== nullptr);
197 sc_assert(pendingPacket
== nullptr);
201 PacketPtr pkt
= nullptr;
203 Gem5Extension
* extension
= nullptr;
204 trans
.get_extension(extension
);
206 // If there is an extension, this transaction was initiated by the gem5
207 // world and we can pipe through the original packet. Otherwise, we
208 // generate a new packet based on the transaction.
209 if (extension
!= nullptr) {
210 extension
->setPipeThrough();
211 pkt
= extension
->getPacket();
213 pkt
= generatePacket(trans
);
216 auto tlmSenderState
= new TlmSenderState(trans
);
217 pkt
->pushSenderState(tlmSenderState
);
219 if (sendTimingReq(pkt
)) { // port is free -> send END_REQ immediately
222 } else { // port is blocked -> wait for retry before sending END_REQ
224 pendingRequest
= &trans
;
230 SCMasterPort::handleEndResp(tlm::tlm_generic_payload
& trans
)
232 sc_assert(responseInProgress
);
234 responseInProgress
= false;
236 checkTransaction(trans
);
238 if (needToSendRetry
) {
240 needToSendRetry
= false;
245 SCMasterPort::sendEndReq(tlm::tlm_generic_payload
& trans
)
247 tlm::tlm_phase phase
= tlm::END_REQ
;
248 auto delay
= sc_core::SC_ZERO_TIME
;
250 auto status
= transactor
->socket
->nb_transport_bw(trans
, phase
, delay
);
251 panic_if(status
!= tlm::TLM_ACCEPTED
,
252 "Unexpected status after sending END_REQ");
256 SCMasterPort::b_transport(tlm::tlm_generic_payload
& trans
,
259 Gem5Extension
* extension
= nullptr;
260 trans
.get_extension(extension
);
262 PacketPtr pkt
= nullptr;
264 // If there is an extension, this transaction was initiated by the gem5
265 // world and we can pipe through the original packet.
266 if (extension
!= nullptr) {
267 extension
->setPipeThrough();
268 pkt
= extension
->getPacket();
270 pkt
= generatePacket(trans
);
273 Tick ticks
= sendAtomic(pkt
);
275 // send an atomic request to gem5
276 panic_if(pkt
->needsResponse() && !pkt
->isResponse(),
277 "Packet sending failed!\n");
279 // one tick is a pico second
281 sc_core::sc_time((double)(ticks
/ SimClock::Int::ps
), sc_core::SC_PS
);
286 if (extension
!= nullptr)
289 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
293 SCMasterPort::transport_dbg(tlm::tlm_generic_payload
& trans
)
295 Gem5Extension
* extension
= nullptr;
296 trans
.get_extension(extension
);
298 // If there is an extension, this transaction was initiated by the gem5
299 // world and we can pipe through the original packet.
300 if (extension
!= nullptr) {
301 extension
->setPipeThrough();
302 sendFunctional(extension
->getPacket());
304 auto pkt
= generatePacket(trans
);
309 return trans
.get_data_length();
313 SCMasterPort::get_direct_mem_ptr(tlm::tlm_generic_payload
& trans
,
314 tlm::tlm_dmi
& dmi_data
)
320 SCMasterPort::recvTimingResp(PacketPtr pkt
)
323 // We need to Wait for END_RESP before sending next BEGIN_RESP
324 if (responseInProgress
) {
325 sc_assert(!needToSendRetry
);
326 needToSendRetry
= true;
330 sc_assert(pkt
->isResponse());
333 * Pay for annotated transport delays.
335 * See recvTimingReq in sc_slave_port.cc for a detailed description.
337 auto delay
= sc_core::sc_time::from_value(pkt
->payloadDelay
);
339 pkt
->payloadDelay
= 0;
340 pkt
->headerDelay
= 0;
342 auto tlmSenderState
= dynamic_cast<TlmSenderState
*>(pkt
->popSenderState());
343 sc_assert(tlmSenderState
!= nullptr);
345 auto& trans
= tlmSenderState
->trans
;
347 Gem5Extension
* extension
= nullptr;
348 trans
.get_extension(extension
);
351 delete tlmSenderState
;
353 // If there is an extension the packet was piped through and we must not
354 // delete it. The packet travels back with the transaction.
355 if (extension
== nullptr)
358 sc_assert(extension
->isPipeThrough());
360 sendBeginResp(trans
, delay
);
367 SCMasterPort::sendBeginResp(tlm::tlm_generic_payload
& trans
,
368 sc_core::sc_time
& delay
)
370 tlm::tlm_phase phase
= tlm::BEGIN_RESP
;
372 trans
.set_response_status(tlm::TLM_OK_RESPONSE
);
374 auto status
= transactor
->socket
->nb_transport_bw(trans
, phase
, delay
);
376 if (status
== tlm::TLM_COMPLETED
||
377 status
== tlm::TLM_UPDATED
&& phase
== tlm::END_RESP
) {
378 // transaction completed -> no need to wait for tlm::END_RESP
379 responseInProgress
= false;
380 } else if (status
== tlm::TLM_ACCEPTED
) {
381 // we need to wait for tlm::END_RESP
382 responseInProgress
= true;
384 panic("Unexpected status after sending BEGIN_RESP");
389 SCMasterPort::recvReqRetry()
391 sc_assert(waitForRetry
);
392 sc_assert(pendingRequest
!= nullptr);
393 sc_assert(pendingPacket
!= nullptr);
395 if (sendTimingReq(pendingPacket
)) {
396 waitForRetry
= false;
397 pendingPacket
= nullptr;
399 auto& trans
= *pendingRequest
;
403 pendingRequest
= nullptr;
408 SCMasterPort::recvRangeChange()
410 SC_REPORT_WARNING("SCMasterPort",
411 "received address range change but ignored it");
414 ExternalMaster::Port
*
415 SCMasterPortHandler::getExternalPort(const std::string
&name
,
416 ExternalMaster
&owner
,
417 const std::string
&port_data
)
419 // Create and register a new SystemC master port
420 auto* port
= new SCMasterPort(name
, port_data
, owner
, control
);
422 control
.registerMasterPort(port_data
, port
);
427 } // namespace Gem5SystemC