misc: Replaced master/slave terminology
[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(RequestorID _id, 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, _id);
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(_id, trans);
160 }
161
162 auto tlmSenderState = new TlmSenderState(trans);
163 pkt->pushSenderState(tlmSenderState);
164
165 // If the packet doesn't need a response, we should send BEGIN_RESP by
166 // ourselves.
167 bool needsResponse = pkt->needsResponse();
168 if (bmp.sendTimingReq(pkt)) { // port is free -> send END_REQ immediately
169 sendEndReq(trans);
170 if (!needsResponse) {
171 auto delay = sc_core::SC_ZERO_TIME;
172 sendBeginResp(trans, delay);
173 }
174 trans.release();
175 } else { // port is blocked -> wait for retry before sending END_REQ
176 waitForRetry = true;
177 pendingRequest = &trans;
178 pendingPacket = pkt;
179 }
180 }
181
182 template <unsigned int BITWIDTH>
183 void
184 TlmToGem5Bridge<BITWIDTH>::handleEndResp(tlm::tlm_generic_payload &trans)
185 {
186 sc_assert(responseInProgress);
187
188 responseInProgress = false;
189
190 checkTransaction(trans);
191
192 if (needToSendRetry) {
193 bmp.sendRetryResp();
194 needToSendRetry = false;
195 }
196 }
197
198 template <unsigned int BITWIDTH>
199 void
200 TlmToGem5Bridge<BITWIDTH>::destroyPacket(PacketPtr pkt)
201 {
202 delete pkt;
203 }
204
205 template <unsigned int BITWIDTH>
206 void
207 TlmToGem5Bridge<BITWIDTH>::checkTransaction(tlm::tlm_generic_payload &trans)
208 {
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());
214 }
215 }
216
217 template <unsigned int BITWIDTH>
218 void
219 TlmToGem5Bridge<BITWIDTH>::invalidateDmi(const ::MemBackdoor &backdoor)
220 {
221 socket->invalidate_direct_mem_ptr(
222 backdoor.range().start(), backdoor.range().end());
223 }
224
225 template <unsigned int BITWIDTH>
226 void
227 TlmToGem5Bridge<BITWIDTH>::peq_cb(tlm::tlm_generic_payload &trans,
228 const tlm::tlm_phase &phase)
229 {
230 switch (phase) {
231 case tlm::BEGIN_REQ:
232 handleBeginReq(trans);
233 break;
234 case tlm::END_RESP:
235 handleEndResp(trans);
236 break;
237 default:
238 panic("unimplemented phase in callback");
239 }
240 }
241
242 template <unsigned int BITWIDTH>
243 tlm::tlm_sync_enum
244 TlmToGem5Bridge<BITWIDTH>::nb_transport_fw(
245 tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
246 sc_core::sc_time &delay)
247 {
248 unsigned len = trans.get_data_length();
249 unsigned char *byteEnable = trans.get_byte_enable_ptr();
250 unsigned width = trans.get_streaming_width();
251
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;
256 }
257 if (width < len) { // is this a burst request?
258 trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
259 return tlm::TLM_COMPLETED;
260 }
261
262 // ... and queue the valid transaction
263 trans.acquire();
264 peq.notify(trans, phase, delay);
265 return tlm::TLM_ACCEPTED;
266 }
267
268 template <unsigned int BITWIDTH>
269 void
270 TlmToGem5Bridge<BITWIDTH>::b_transport(tlm::tlm_generic_payload &trans,
271 sc_core::sc_time &t)
272 {
273 Gem5SystemC::Gem5Extension *extension = nullptr;
274 trans.get_extension(extension);
275
276 PacketPtr pkt = nullptr;
277
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();
283 } else {
284 pkt = payload2packet(_id, trans);
285 }
286
287 MemBackdoorPtr backdoor = nullptr;
288 Tick ticks = bmp.sendAtomicBackdoor(pkt, backdoor);
289 if (backdoor)
290 trans.set_dmi_allowed(true);
291
292 // send an atomic request to gem5
293 panic_if(pkt->needsResponse() && !pkt->isResponse(),
294 "Packet sending failed!\n");
295
296 auto delay =
297 sc_core::sc_time((double)(ticks / SimClock::Int::ps), sc_core::SC_PS);
298
299 // update time
300 t += delay;
301
302 if (extension == nullptr)
303 destroyPacket(pkt);
304
305 trans.set_response_status(tlm::TLM_OK_RESPONSE);
306 }
307
308 template <unsigned int BITWIDTH>
309 unsigned int
310 TlmToGem5Bridge<BITWIDTH>::transport_dbg(tlm::tlm_generic_payload &trans)
311 {
312 Gem5SystemC::Gem5Extension *extension = nullptr;
313 trans.get_extension(extension);
314
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());
320 } else {
321 auto pkt = payload2packet(_id, trans);
322 if (pkt) {
323 bmp.sendFunctional(pkt);
324 destroyPacket(pkt);
325 }
326 }
327
328 return trans.get_data_length();
329 }
330
331 template <unsigned int BITWIDTH>
332 bool
333 TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
334 tlm::tlm_dmi &dmi_data)
335 {
336 Gem5SystemC::Gem5Extension *extension = nullptr;
337 trans.get_extension(extension);
338
339 PacketPtr pkt = nullptr;
340
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();
346 } else {
347 pkt = payload2packet(_id, trans);
348 pkt->req->setFlags(Request::NO_ACCESS);
349 }
350
351 MemBackdoorPtr backdoor = nullptr;
352 bmp.sendAtomicBackdoor(pkt, backdoor);
353 if (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());
358
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);
366
367 backdoor->addInvalidationCallback(
368 [this](const MemBackdoor &backdoor)
369 {
370 invalidateDmi(backdoor);
371 }
372 );
373 }
374
375 if (extension == nullptr)
376 destroyPacket(pkt);
377
378 trans.set_response_status(tlm::TLM_OK_RESPONSE);
379
380 return backdoor != nullptr;
381 }
382
383 template <unsigned int BITWIDTH>
384 bool
385 TlmToGem5Bridge<BITWIDTH>::recvTimingResp(PacketPtr pkt)
386 {
387 // exclusion rule
388 // We need to Wait for END_RESP before sending next BEGIN_RESP
389 if (responseInProgress) {
390 sc_assert(!needToSendRetry);
391 needToSendRetry = true;
392 return false;
393 }
394
395 sc_assert(pkt->isResponse());
396
397 /*
398 * Pay for annotated transport delays.
399 *
400 * See recvTimingReq in sc_slave_port.cc for a detailed description.
401 */
402 auto delay = sc_core::sc_time::from_value(pkt->payloadDelay);
403 // reset the delays
404 pkt->payloadDelay = 0;
405 pkt->headerDelay = 0;
406
407 auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState());
408 sc_assert(tlmSenderState != nullptr);
409
410 auto &trans = tlmSenderState->trans;
411
412 Gem5SystemC::Gem5Extension *extension = nullptr;
413 trans.get_extension(extension);
414
415 // clean up
416 delete tlmSenderState;
417
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)
421 destroyPacket(pkt);
422 else
423 sc_assert(extension->isPipeThrough());
424
425 sendBeginResp(trans, delay);
426 trans.release();
427
428 return true;
429 }
430
431 template <unsigned int BITWIDTH>
432 void
433 TlmToGem5Bridge<BITWIDTH>::recvReqRetry()
434 {
435 sc_assert(waitForRetry);
436 sc_assert(pendingRequest != nullptr);
437 sc_assert(pendingPacket != nullptr);
438
439 // If the packet doesn't need a response, we should send BEGIN_RESP by
440 // ourselves.
441 bool needsResponse = pendingPacket->needsResponse();
442 if (bmp.sendTimingReq(pendingPacket)) {
443 waitForRetry = false;
444 pendingPacket = nullptr;
445
446 auto &trans = *pendingRequest;
447 sendEndReq(trans);
448 if (!needsResponse) {
449 auto delay = sc_core::SC_ZERO_TIME;
450 sendBeginResp(trans, delay);
451 }
452 trans.release();
453
454 pendingRequest = nullptr;
455 }
456 }
457
458 template <unsigned int BITWIDTH>
459 void
460 TlmToGem5Bridge<BITWIDTH>::recvRangeChange()
461 {
462 SC_REPORT_WARNING("TlmToGem5Bridge",
463 "received address range change but ignored it");
464 }
465
466 template <unsigned int BITWIDTH>
467 ::Port &
468 TlmToGem5Bridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx)
469 {
470 if (if_name == "gem5")
471 return bmp;
472 else if (if_name == "tlm")
473 return wrapper;
474
475 return sc_core::sc_module::gem5_getPort(if_name, idx);
476 }
477
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()))
489 {
490 }
491
492 template <unsigned int BITWIDTH>
493 void
494 TlmToGem5Bridge<BITWIDTH>::before_end_of_elaboration()
495 {
496 /*
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.
501 *
502 * NOTE: The mode may change during execution.
503 */
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);
514 } else {
515 panic("gem5 operates neither in Timing nor in Atomic mode");
516 }
517
518 socket.register_transport_dbg(
519 this, &TlmToGem5Bridge<BITWIDTH>::transport_dbg);
520
521 sc_core::sc_module::before_end_of_elaboration();
522 }
523
524 } // namespace sc_gem5
525
526 sc_gem5::TlmToGem5Bridge<32> *
527 TlmToGem5Bridge32Params::create()
528 {
529 return new sc_gem5::TlmToGem5Bridge<32>(
530 this, sc_core::sc_module_name(name.c_str()));
531 }
532
533 sc_gem5::TlmToGem5Bridge<64> *
534 TlmToGem5Bridge64Params::create()
535 {
536 return new sc_gem5::TlmToGem5Bridge<64>(
537 this, sc_core::sc_module_name(name.c_str()));
538 }