misc: Replaced master/slave terminology
[gem5.git] / src / systemc / tlm_bridge / gem5_to_tlm.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) 2015, University of Kaiserslautern
28 * Copyright (c) 2016, Dresden University of Technology (TU Dresden)
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions are
33 * met:
34 *
35 * 1. Redistributions of source code must retain the above copyright notice,
36 * this list of conditions and the following disclaimer.
37 *
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 *
42 * 3. Neither the name of the copyright holder nor the names of its
43 * contributors may be used to endorse or promote products derived from
44 * this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
48 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
49 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
50 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
52 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
53 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
54 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
55 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
56 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59 #include "systemc/tlm_bridge/gem5_to_tlm.hh"
60
61 #include "params/Gem5ToTlmBridge32.hh"
62 #include "params/Gem5ToTlmBridge64.hh"
63 #include "sim/system.hh"
64 #include "systemc/tlm_bridge/sc_ext.hh"
65 #include "systemc/tlm_bridge/sc_mm.hh"
66
67 namespace sc_gem5
68 {
69
70 /**
71 * Instantiate a tlm memory manager that takes care about all the
72 * tlm transactions in the system.
73 */
74 Gem5SystemC::MemoryManager mm;
75
76 /**
77 * Convert a gem5 packet to a TLM payload by copying all the relevant
78 * information to new tlm payload.
79 */
80 tlm::tlm_generic_payload *
81 packet2payload(PacketPtr packet)
82 {
83 tlm::tlm_generic_payload *trans = mm.allocate();
84 trans->acquire();
85
86 trans->set_address(packet->getAddr());
87
88 /* Check if this transaction was allocated by mm */
89 sc_assert(trans->has_mm());
90
91 unsigned int size = packet->getSize();
92 unsigned char *data = packet->getPtr<unsigned char>();
93
94 trans->set_data_length(size);
95 trans->set_streaming_width(size);
96 trans->set_data_ptr(data);
97
98 if ((packet->req->getFlags() & Request::NO_ACCESS) != 0) {
99 /* Do nothing */
100 trans->set_command(tlm::TLM_IGNORE_COMMAND);
101 } else if (packet->isRead()) {
102 trans->set_command(tlm::TLM_READ_COMMAND);
103 } else if (packet->isWrite()) {
104 trans->set_command(tlm::TLM_WRITE_COMMAND);
105 } else {
106 trans->set_command(tlm::TLM_IGNORE_COMMAND);
107 }
108
109 // Attach the packet pointer to the TLM transaction to keep track.
110 auto *extension = new Gem5SystemC::Gem5Extension(packet);
111 trans->set_auto_extension(extension);
112
113 return trans;
114 }
115
116 template <unsigned int BITWIDTH>
117 void
118 Gem5ToTlmBridge<BITWIDTH>::pec(
119 tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
120 {
121 sc_core::sc_time delay;
122
123 if (phase == tlm::END_REQ ||
124 (&trans == blockingRequest && phase == tlm::BEGIN_RESP)) {
125 sc_assert(&trans == blockingRequest);
126 blockingRequest = nullptr;
127
128 // Did another request arrive while blocked, schedule a retry.
129 if (needToSendRequestRetry) {
130 needToSendRequestRetry = false;
131 bridgeResponsePort.sendRetryReq();
132 }
133 }
134 if (phase == tlm::BEGIN_RESP) {
135 auto &extension = Gem5SystemC::Gem5Extension::getExtension(trans);
136 auto packet = extension.getPacket();
137
138 sc_assert(!blockingResponse);
139
140 bool need_retry = false;
141
142 /*
143 * If the packet was piped through and needs a response, we don't need
144 * to touch the packet and can forward it directly as a response.
145 * Otherwise, we need to make a response and send the transformed
146 * packet.
147 */
148 if (extension.isPipeThrough()) {
149 if (packet->isResponse()) {
150 need_retry = !bridgeResponsePort.sendTimingResp(packet);
151 }
152 } else if (packet->needsResponse()) {
153 packet->makeResponse();
154 need_retry = !bridgeResponsePort.sendTimingResp(packet);
155 }
156
157 if (need_retry) {
158 blockingResponse = &trans;
159 } else {
160 if (phase == tlm::BEGIN_RESP) {
161 // Send END_RESP and we're finished:
162 tlm::tlm_phase fw_phase = tlm::END_RESP;
163 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
164 socket->nb_transport_fw(trans, fw_phase, delay);
165 // Release the transaction with all the extensions.
166 trans.release();
167 }
168 }
169 }
170 }
171
172 template <unsigned int BITWIDTH>
173 MemBackdoorPtr
174 Gem5ToTlmBridge<BITWIDTH>::getBackdoor(tlm::tlm_generic_payload &trans)
175 {
176 sc_dt::uint64 start = trans.get_address();
177 sc_dt::uint64 end = start + trans.get_data_length();
178
179 // Check for a back door we already know about.
180 AddrRange r(start, end);
181 auto it = backdoorMap.contains(r);
182 if (it != backdoorMap.end())
183 return it->second;
184
185 // If not, ask the target for one.
186 tlm::tlm_dmi dmi_data;
187 if (!socket->get_direct_mem_ptr(trans, dmi_data))
188 return nullptr;
189
190 // If the target gave us one, translate it to a gem5 MemBackdoor and
191 // store it in our cache.
192 AddrRange dmi_r(dmi_data.get_start_address(), dmi_data.get_end_address());
193 auto backdoor = new MemBackdoor(
194 dmi_r, dmi_data.get_dmi_ptr(), MemBackdoor::NoAccess);
195 backdoor->readable(dmi_data.is_read_allowed());
196 backdoor->writeable(dmi_data.is_write_allowed());
197
198 backdoorMap.insert(dmi_r, backdoor);
199
200 return backdoor;
201 }
202
203 // Similar to TLM's blocking transport (LT)
204 template <unsigned int BITWIDTH>
205 Tick
206 Gem5ToTlmBridge<BITWIDTH>::recvAtomic(PacketPtr packet)
207 {
208 panic_if(packet->cacheResponding(),
209 "Should not see packets where cache is responding");
210
211 // Prepare the transaction.
212 auto *trans = packet2payload(packet);
213
214 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
215
216 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
217 // Execute b_transport:
218 socket->b_transport(*trans, delay);
219 }
220
221 if (packet->needsResponse())
222 packet->makeResponse();
223
224 trans->release();
225
226 return delay.value();
227 }
228
229 template <unsigned int BITWIDTH>
230 Tick
231 Gem5ToTlmBridge<BITWIDTH>::recvAtomicBackdoor(
232 PacketPtr packet, MemBackdoorPtr &backdoor)
233 {
234 panic_if(packet->cacheResponding(),
235 "Should not see packets where cache is responding");
236
237 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
238
239 // Prepare the transaction.
240 auto *trans = packet2payload(packet);
241
242 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
243 // Execute b_transport:
244 socket->b_transport(*trans, delay);
245 // If the hint said we could use DMI, set that up.
246 if (trans->is_dmi_allowed())
247 backdoor = getBackdoor(*trans);
248 } else {
249 // There's no transaction to piggy back on, so just request the
250 // backdoor normally.
251 backdoor = getBackdoor(*trans);
252 }
253
254 if (packet->needsResponse())
255 packet->makeResponse();
256
257 trans->release();
258
259 return delay.value();
260 }
261
262 template <unsigned int BITWIDTH>
263 void
264 Gem5ToTlmBridge<BITWIDTH>::recvFunctionalSnoop(PacketPtr packet)
265 {
266 // Snooping should be implemented with tlm_dbg_transport.
267 SC_REPORT_FATAL("Gem5ToTlmBridge",
268 "unimplemented func.: recvFunctionalSnoop");
269 }
270
271 // Similar to TLM's non-blocking transport (AT).
272 template <unsigned int BITWIDTH>
273 bool
274 Gem5ToTlmBridge<BITWIDTH>::recvTimingReq(PacketPtr packet)
275 {
276 panic_if(packet->cacheResponding(),
277 "Should not see packets where cache is responding");
278
279 // We should never get a second request after noting that a retry is
280 // required.
281 sc_assert(!needToSendRequestRetry);
282
283 // Remember if a request comes in while we're blocked so that a retry
284 // can be sent to gem5.
285 if (blockingRequest) {
286 needToSendRequestRetry = true;
287 return false;
288 }
289
290 /*
291 * NOTE: normal tlm is blocking here. But in our case we return false
292 * and tell gem5 when a retry can be done. This is the main difference
293 * in the protocol:
294 * if (requestInProgress)
295 * {
296 * wait(endRequestEvent);
297 * }
298 * requestInProgress = trans;
299 */
300
301 // Prepare the transaction.
302 auto *trans = packet2payload(packet);
303
304 /*
305 * Pay for annotated transport delays.
306 *
307 * The header delay marks the point in time, when the packet first is seen
308 * by the transactor. This is the point in time when the transactor needs
309 * to send the BEGIN_REQ to the SystemC world.
310 *
311 * NOTE: We drop the payload delay here. Normally, the receiver would be
312 * responsible for handling the payload delay. In this case, however,
313 * the receiver is a SystemC module and has no notion of the gem5
314 * transport protocol and we cannot simply forward the
315 * payload delay to the receiving module. Instead, we expect the
316 * receiving SystemC module to model the payload delay by deferring
317 * the END_REQ. This could lead to incorrect delays, if the XBar
318 * payload delay is longer than the time the receiver needs to accept
319 * the request (time between BEGIN_REQ and END_REQ).
320 *
321 * TODO: We could detect the case described above by remembering the
322 * payload delay and comparing it to the time between BEGIN_REQ and
323 * END_REQ. Then, a warning should be printed.
324 */
325 auto delay = sc_core::sc_time::from_value(packet->payloadDelay);
326 // Reset the delays
327 packet->payloadDelay = 0;
328 packet->headerDelay = 0;
329
330 // Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC
331 // Standard Page 507 for a visualisation of the procedure.
332 tlm::tlm_phase phase = tlm::BEGIN_REQ;
333 tlm::tlm_sync_enum status;
334 status = socket->nb_transport_fw(*trans, phase, delay);
335 // Check returned value:
336 if (status == tlm::TLM_ACCEPTED) {
337 sc_assert(phase == tlm::BEGIN_REQ);
338 // Accepted but is now blocking until END_REQ (exclusion rule).
339 blockingRequest = trans;
340 } else if (status == tlm::TLM_UPDATED) {
341 // The Timing annotation must be honored:
342 sc_assert(phase == tlm::END_REQ || phase == tlm::BEGIN_RESP);
343 auto cb = [this, trans, phase]() { pec(*trans, phase); };
344 system->schedule(new EventFunctionWrapper(cb, "pec", true),
345 curTick() + delay.value());
346 } else if (status == tlm::TLM_COMPLETED) {
347 // Transaction is over nothing has do be done.
348 sc_assert(phase == tlm::END_RESP);
349 trans->release();
350 }
351
352 return true;
353 }
354
355 template <unsigned int BITWIDTH>
356 bool
357 Gem5ToTlmBridge<BITWIDTH>::recvTimingSnoopResp(PacketPtr packet)
358 {
359 // Snooping should be implemented with tlm_dbg_transport.
360 SC_REPORT_FATAL("Gem5ToTlmBridge",
361 "unimplemented func.: recvTimingSnoopResp");
362 return false;
363 }
364
365 template <unsigned int BITWIDTH>
366 bool
367 Gem5ToTlmBridge<BITWIDTH>::tryTiming(PacketPtr packet)
368 {
369 panic("tryTiming(PacketPtr) isn't implemented.");
370 }
371
372 template <unsigned int BITWIDTH>
373 void
374 Gem5ToTlmBridge<BITWIDTH>::recvRespRetry()
375 {
376 /* Retry a response */
377 sc_assert(blockingResponse);
378
379 tlm::tlm_generic_payload *trans = blockingResponse;
380 blockingResponse = nullptr;
381 PacketPtr packet =
382 Gem5SystemC::Gem5Extension::getExtension(trans).getPacket();
383
384 bool need_retry = !bridgeResponsePort.sendTimingResp(packet);
385
386 sc_assert(!need_retry);
387
388 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
389 tlm::tlm_phase phase = tlm::END_RESP;
390 socket->nb_transport_fw(*trans, phase, delay);
391 // Release transaction with all the extensions
392 trans->release();
393 }
394
395 // Similar to TLM's debug transport.
396 template <unsigned int BITWIDTH>
397 void
398 Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet)
399 {
400 // Prepare the transaction.
401 auto *trans = packet2payload(packet);
402
403 /* Execute Debug Transport: */
404 unsigned int bytes = socket->transport_dbg(*trans);
405 if (bytes != trans->get_data_length()) {
406 SC_REPORT_FATAL("Gem5ToTlmBridge",
407 "debug transport was not completed");
408 }
409
410 trans->release();
411 }
412
413 template <unsigned int BITWIDTH>
414 tlm::tlm_sync_enum
415 Gem5ToTlmBridge<BITWIDTH>::nb_transport_bw(tlm::tlm_generic_payload &trans,
416 tlm::tlm_phase &phase, sc_core::sc_time &delay)
417 {
418 auto cb = [this, &trans, phase]() { pec(trans, phase); };
419 system->schedule(new EventFunctionWrapper(cb, "pec", true),
420 curTick() + delay.value());
421 return tlm::TLM_ACCEPTED;
422 }
423
424 template <unsigned int BITWIDTH>
425 void
426 Gem5ToTlmBridge<BITWIDTH>::invalidate_direct_mem_ptr(
427 sc_dt::uint64 start_range, sc_dt::uint64 end_range)
428 {
429 AddrRange r(start_range, end_range);
430
431 for (;;) {
432 auto it = backdoorMap.intersects(r);
433 if (it == backdoorMap.end())
434 break;
435
436 it->second->invalidate();
437 delete it->second;
438 backdoorMap.erase(it);
439 };
440 }
441
442 template <unsigned int BITWIDTH>
443 Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge(
444 Params *params, const sc_core::sc_module_name &mn) :
445 Gem5ToTlmBridgeBase(mn),
446 bridgeResponsePort(std::string(name()) + ".gem5", *this),
447 socket("tlm_socket"),
448 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID),
449 system(params->system), blockingRequest(nullptr),
450 needToSendRequestRetry(false), blockingResponse(nullptr),
451 addrRanges(params->addr_ranges.begin(), params->addr_ranges.end())
452 {
453 }
454
455 template <unsigned int BITWIDTH>
456 ::Port &
457 Gem5ToTlmBridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx)
458 {
459 if (if_name == "gem5")
460 return bridgeResponsePort;
461 else if (if_name == "tlm")
462 return wrapper;
463
464 return sc_core::sc_module::gem5_getPort(if_name, idx);
465 }
466
467 template <unsigned int BITWIDTH>
468 void
469 Gem5ToTlmBridge<BITWIDTH>::before_end_of_elaboration()
470 {
471 bridgeResponsePort.sendRangeChange();
472
473 socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw);
474 socket.register_invalidate_direct_mem_ptr(
475 this, &Gem5ToTlmBridge::invalidate_direct_mem_ptr);
476 sc_core::sc_module::before_end_of_elaboration();
477 }
478
479 } // namespace sc_gem5
480
481 sc_gem5::Gem5ToTlmBridge<32> *
482 Gem5ToTlmBridge32Params::create()
483 {
484 return new sc_gem5::Gem5ToTlmBridge<32>(
485 this, sc_core::sc_module_name(name.c_str()));
486 }
487
488 sc_gem5::Gem5ToTlmBridge<64> *
489 Gem5ToTlmBridge64Params::create()
490 {
491 return new sc_gem5::Gem5ToTlmBridge<64>(
492 this, sc_core::sc_module_name(name.c_str()));
493 }