gem5_to_tlm.cc (13823:040971e0f728) gem5_to_tlm.cc (13846:af21c0a800fb)
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 * Authors: Gabe Black
59 * Matthias Jung
60 * Abdul Mutaal Ahmad
61 * Christian Menard
62 */
63
64#include "systemc/tlm_bridge/gem5_to_tlm.hh"
65
66#include "params/Gem5ToTlmBridge32.hh"
67#include "params/Gem5ToTlmBridge64.hh"
68#include "sim/system.hh"
69#include "systemc/tlm_bridge/sc_ext.hh"
70#include "systemc/tlm_bridge/sc_mm.hh"
71
72namespace sc_gem5
73{
74
75/**
76 * Instantiate a tlm memory manager that takes care about all the
77 * tlm transactions in the system.
78 */
79Gem5SystemC::MemoryManager mm;
80
81/**
82 * Convert a gem5 packet to a TLM payload by copying all the relevant
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 * Authors: Gabe Black
59 * Matthias Jung
60 * Abdul Mutaal Ahmad
61 * Christian Menard
62 */
63
64#include "systemc/tlm_bridge/gem5_to_tlm.hh"
65
66#include "params/Gem5ToTlmBridge32.hh"
67#include "params/Gem5ToTlmBridge64.hh"
68#include "sim/system.hh"
69#include "systemc/tlm_bridge/sc_ext.hh"
70#include "systemc/tlm_bridge/sc_mm.hh"
71
72namespace sc_gem5
73{
74
75/**
76 * Instantiate a tlm memory manager that takes care about all the
77 * tlm transactions in the system.
78 */
79Gem5SystemC::MemoryManager mm;
80
81/**
82 * Convert a gem5 packet to a TLM payload by copying all the relevant
83 * information to a previously allocated tlm payload
83 * information to new tlm payload.
84 */
84 */
85void
86packet2payload(PacketPtr packet, tlm::tlm_generic_payload &trans)
85tlm::tlm_generic_payload *
86packet2payload(PacketPtr packet)
87{
87{
88 trans.set_address(packet->getAddr());
88 tlm::tlm_generic_payload *trans = mm.allocate();
89 trans->acquire();
89
90
91 trans->set_address(packet->getAddr());
92
90 /* Check if this transaction was allocated by mm */
93 /* Check if this transaction was allocated by mm */
91 sc_assert(trans.has_mm());
94 sc_assert(trans->has_mm());
92
93 unsigned int size = packet->getSize();
94 unsigned char *data = packet->getPtr<unsigned char>();
95
95
96 unsigned int size = packet->getSize();
97 unsigned char *data = packet->getPtr<unsigned char>();
98
96 trans.set_data_length(size);
97 trans.set_streaming_width(size);
98 trans.set_data_ptr(data);
99 trans->set_data_length(size);
100 trans->set_streaming_width(size);
101 trans->set_data_ptr(data);
99
102
100 if (packet->isRead()) {
101 trans.set_command(tlm::TLM_READ_COMMAND);
103 if ((packet->req->getFlags() & Request::NO_ACCESS) != 0) {
104 /* Do nothing */
105 trans->set_command(tlm::TLM_IGNORE_COMMAND);
106 } else if (packet->isRead()) {
107 trans->set_command(tlm::TLM_READ_COMMAND);
102 } else if (packet->isInvalidate()) {
103 /* Do nothing */
108 } else if (packet->isInvalidate()) {
109 /* Do nothing */
110 trans->set_command(tlm::TLM_IGNORE_COMMAND);
104 } else if (packet->isWrite()) {
111 } else if (packet->isWrite()) {
105 trans.set_command(tlm::TLM_WRITE_COMMAND);
112 trans->set_command(tlm::TLM_WRITE_COMMAND);
106 } else {
107 SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet");
108 }
113 } else {
114 SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet");
115 }
116
117 // Attach the packet pointer to the TLM transaction to keep track.
118 auto *extension = new Gem5SystemC::Gem5Extension(packet);
119 trans->set_auto_extension(extension);
120
121 return trans;
109}
110
111template <unsigned int BITWIDTH>
112void
113Gem5ToTlmBridge<BITWIDTH>::pec(
114 Gem5SystemC::PayloadEvent<Gem5ToTlmBridge<BITWIDTH>> *pe,
115 tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
116{
117 sc_core::sc_time delay;
118
119 if (phase == tlm::END_REQ ||
120 (&trans == blockingRequest && phase == tlm::BEGIN_RESP)) {
121 sc_assert(&trans == blockingRequest);
122 blockingRequest = nullptr;
123
124 // Did another request arrive while blocked, schedule a retry.
125 if (needToSendRequestRetry) {
126 needToSendRequestRetry = false;
127 bsp.sendRetryReq();
128 }
129 }
130 if (phase == tlm::BEGIN_RESP) {
131 auto &extension = Gem5SystemC::Gem5Extension::getExtension(trans);
132 auto packet = extension.getPacket();
133
134 sc_assert(!blockingResponse);
135
136 bool need_retry = false;
137
138 /*
139 * If the packet was piped through and needs a response, we don't need
140 * to touch the packet and can forward it directly as a response.
141 * Otherwise, we need to make a response and send the transformed
142 * packet.
143 */
144 if (extension.isPipeThrough()) {
145 if (packet->isResponse()) {
146 need_retry = !bsp.sendTimingResp(packet);
147 }
148 } else if (packet->needsResponse()) {
149 packet->makeResponse();
150 need_retry = !bsp.sendTimingResp(packet);
151 }
152
153 if (need_retry) {
154 blockingResponse = &trans;
155 } else {
156 if (phase == tlm::BEGIN_RESP) {
157 // Send END_RESP and we're finished:
158 tlm::tlm_phase fw_phase = tlm::END_RESP;
159 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
160 socket->nb_transport_fw(trans, fw_phase, delay);
161 // Release the transaction with all the extensions.
162 trans.release();
163 }
164 }
165 }
166 delete pe;
167}
168
122}
123
124template <unsigned int BITWIDTH>
125void
126Gem5ToTlmBridge<BITWIDTH>::pec(
127 Gem5SystemC::PayloadEvent<Gem5ToTlmBridge<BITWIDTH>> *pe,
128 tlm::tlm_generic_payload &trans, const tlm::tlm_phase &phase)
129{
130 sc_core::sc_time delay;
131
132 if (phase == tlm::END_REQ ||
133 (&trans == blockingRequest && phase == tlm::BEGIN_RESP)) {
134 sc_assert(&trans == blockingRequest);
135 blockingRequest = nullptr;
136
137 // Did another request arrive while blocked, schedule a retry.
138 if (needToSendRequestRetry) {
139 needToSendRequestRetry = false;
140 bsp.sendRetryReq();
141 }
142 }
143 if (phase == tlm::BEGIN_RESP) {
144 auto &extension = Gem5SystemC::Gem5Extension::getExtension(trans);
145 auto packet = extension.getPacket();
146
147 sc_assert(!blockingResponse);
148
149 bool need_retry = false;
150
151 /*
152 * If the packet was piped through and needs a response, we don't need
153 * to touch the packet and can forward it directly as a response.
154 * Otherwise, we need to make a response and send the transformed
155 * packet.
156 */
157 if (extension.isPipeThrough()) {
158 if (packet->isResponse()) {
159 need_retry = !bsp.sendTimingResp(packet);
160 }
161 } else if (packet->needsResponse()) {
162 packet->makeResponse();
163 need_retry = !bsp.sendTimingResp(packet);
164 }
165
166 if (need_retry) {
167 blockingResponse = &trans;
168 } else {
169 if (phase == tlm::BEGIN_RESP) {
170 // Send END_RESP and we're finished:
171 tlm::tlm_phase fw_phase = tlm::END_RESP;
172 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
173 socket->nb_transport_fw(trans, fw_phase, delay);
174 // Release the transaction with all the extensions.
175 trans.release();
176 }
177 }
178 }
179 delete pe;
180}
181
182template <unsigned int BITWIDTH>
183MemBackdoorPtr
184Gem5ToTlmBridge<BITWIDTH>::getBackdoor(tlm::tlm_generic_payload &trans)
185{
186 sc_dt::uint64 start = trans.get_address();
187 sc_dt::uint64 end = start + trans.get_data_length();
188
189 // Check for a back door we already know about.
190 AddrRange r(start, end);
191 auto it = backdoorMap.contains(r);
192 if (it != backdoorMap.end())
193 return it->second;
194
195 // If not, ask the target for one.
196 tlm::tlm_dmi dmi_data;
197 if (!socket->get_direct_mem_ptr(trans, dmi_data))
198 return nullptr;
199
200 // If the target gave us one, translate it to a gem5 MemBackdoor and
201 // store it in our cache.
202 AddrRange dmi_r(dmi_data.get_start_address(), dmi_data.get_end_address());
203 auto backdoor = new MemBackdoor(
204 dmi_r, dmi_data.get_dmi_ptr(), MemBackdoor::NoAccess);
205 backdoor->readable(dmi_data.is_read_allowed());
206 backdoor->writeable(dmi_data.is_write_allowed());
207
208 backdoorMap.insert(dmi_r, backdoor);
209
210 return backdoor;
211}
212
169// Similar to TLM's blocking transport (LT)
170template <unsigned int BITWIDTH>
171Tick
172Gem5ToTlmBridge<BITWIDTH>::recvAtomic(PacketPtr packet)
173{
174 panic_if(packet->cacheResponding(),
175 "Should not see packets where cache is responding");
176
213// Similar to TLM's blocking transport (LT)
214template <unsigned int BITWIDTH>
215Tick
216Gem5ToTlmBridge<BITWIDTH>::recvAtomic(PacketPtr packet)
217{
218 panic_if(packet->cacheResponding(),
219 "Should not see packets where cache is responding");
220
177 panic_if(!(packet->isRead() || packet->isWrite()),
178 "Should only see read and writes at TLM memory\n");
221 // Prepare the transaction.
222 auto *trans = packet2payload(packet);
179
180 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
181
223
224 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
225
182 // Prepare the transaction.
183 tlm::tlm_generic_payload *trans = mm.allocate();
184 trans->acquire();
185 packet2payload(packet, *trans);
226 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
227 // Execute b_transport:
228 socket->b_transport(*trans, delay);
229 }
186
230
187 // Attach the packet pointer to the TLM transaction to keep track.
188 auto *extension = new Gem5SystemC::Gem5Extension(packet);
189 trans->set_auto_extension(extension);
231 if (packet->needsResponse())
232 packet->makeResponse();
190
233
191 // Execute b_transport:
192 if (packet->cmd == MemCmd::SwapReq) {
193 SC_REPORT_FATAL("Gem5ToTlmBridge", "SwapReq not supported");
194 } else if (packet->isRead()) {
234 trans->release();
235
236 return delay.value();
237}
238
239template <unsigned int BITWIDTH>
240Tick
241Gem5ToTlmBridge<BITWIDTH>::recvAtomicBackdoor(
242 PacketPtr packet, MemBackdoorPtr &backdoor)
243{
244 panic_if(packet->cacheResponding(),
245 "Should not see packets where cache is responding");
246
247 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
248
249 // Prepare the transaction.
250 auto *trans = packet2payload(packet);
251
252 if (trans->get_command() != tlm::TLM_IGNORE_COMMAND) {
253 // Execute b_transport:
195 socket->b_transport(*trans, delay);
254 socket->b_transport(*trans, delay);
196 } else if (packet->isInvalidate()) {
197 // do nothing
198 } else if (packet->isWrite()) {
199 socket->b_transport(*trans, delay);
255 // If the hint said we could use DMI, set that up.
256 if (trans->is_dmi_allowed())
257 backdoor = getBackdoor(*trans);
200 } else {
258 } else {
201 SC_REPORT_FATAL("Gem5ToTlmBridge", "Typo of request not supported");
259 // There's no transaction to piggy back on, so just request the
260 // backdoor normally.
261 backdoor = getBackdoor(*trans);
202 }
203
262 }
263
204 if (packet->needsResponse()) {
264 if (packet->needsResponse())
205 packet->makeResponse();
265 packet->makeResponse();
206 }
207
208 trans->release();
209
210 return delay.value();
211}
212
213template <unsigned int BITWIDTH>
214void
215Gem5ToTlmBridge<BITWIDTH>::recvFunctionalSnoop(PacketPtr packet)
216{
217 // Snooping should be implemented with tlm_dbg_transport.
218 SC_REPORT_FATAL("Gem5ToTlmBridge",
219 "unimplemented func.: recvFunctionalSnoop");
220}
221
222// Similar to TLM's non-blocking transport (AT).
223template <unsigned int BITWIDTH>
224bool
225Gem5ToTlmBridge<BITWIDTH>::recvTimingReq(PacketPtr packet)
226{
227 panic_if(packet->cacheResponding(),
228 "Should not see packets where cache is responding");
229
230 panic_if(!(packet->isRead() || packet->isWrite()),
231 "Should only see read and writes at TLM memory\n");
232
233
234 // We should never get a second request after noting that a retry is
235 // required.
236 sc_assert(!needToSendRequestRetry);
237
238 // Remember if a request comes in while we're blocked so that a retry
239 // can be sent to gem5.
240 if (blockingRequest) {
241 needToSendRequestRetry = true;
242 return false;
243 }
244
245 /*
246 * NOTE: normal tlm is blocking here. But in our case we return false
247 * and tell gem5 when a retry can be done. This is the main difference
248 * in the protocol:
249 * if (requestInProgress)
250 * {
251 * wait(endRequestEvent);
252 * }
253 * requestInProgress = trans;
254 */
255
256 // Prepare the transaction.
266
267 trans->release();
268
269 return delay.value();
270}
271
272template <unsigned int BITWIDTH>
273void
274Gem5ToTlmBridge<BITWIDTH>::recvFunctionalSnoop(PacketPtr packet)
275{
276 // Snooping should be implemented with tlm_dbg_transport.
277 SC_REPORT_FATAL("Gem5ToTlmBridge",
278 "unimplemented func.: recvFunctionalSnoop");
279}
280
281// Similar to TLM's non-blocking transport (AT).
282template <unsigned int BITWIDTH>
283bool
284Gem5ToTlmBridge<BITWIDTH>::recvTimingReq(PacketPtr packet)
285{
286 panic_if(packet->cacheResponding(),
287 "Should not see packets where cache is responding");
288
289 panic_if(!(packet->isRead() || packet->isWrite()),
290 "Should only see read and writes at TLM memory\n");
291
292
293 // We should never get a second request after noting that a retry is
294 // required.
295 sc_assert(!needToSendRequestRetry);
296
297 // Remember if a request comes in while we're blocked so that a retry
298 // can be sent to gem5.
299 if (blockingRequest) {
300 needToSendRequestRetry = true;
301 return false;
302 }
303
304 /*
305 * NOTE: normal tlm is blocking here. But in our case we return false
306 * and tell gem5 when a retry can be done. This is the main difference
307 * in the protocol:
308 * if (requestInProgress)
309 * {
310 * wait(endRequestEvent);
311 * }
312 * requestInProgress = trans;
313 */
314
315 // Prepare the transaction.
257 tlm::tlm_generic_payload *trans = mm.allocate();
258 trans->acquire();
259 packet2payload(packet, *trans);
316 auto *trans = packet2payload(packet);
260
317
261 // Attach the packet pointer to the TLM transaction to keep track.
262 auto *extension = new Gem5SystemC::Gem5Extension(packet);
263 trans->set_auto_extension(extension);
264
265 /*
266 * Pay for annotated transport delays.
267 *
268 * The header delay marks the point in time, when the packet first is seen
269 * by the transactor. This is the point in time when the transactor needs
270 * to send the BEGIN_REQ to the SystemC world.
271 *
272 * NOTE: We drop the payload delay here. Normally, the receiver would be
273 * responsible for handling the payload delay. In this case, however,
274 * the receiver is a SystemC module and has no notion of the gem5
275 * transport protocol and we cannot simply forward the
276 * payload delay to the receiving module. Instead, we expect the
277 * receiving SystemC module to model the payload delay by deferring
278 * the END_REQ. This could lead to incorrect delays, if the XBar
279 * payload delay is longer than the time the receiver needs to accept
280 * the request (time between BEGIN_REQ and END_REQ).
281 *
282 * TODO: We could detect the case described above by remembering the
283 * payload delay and comparing it to the time between BEGIN_REQ and
284 * END_REQ. Then, a warning should be printed.
285 */
286 auto delay = sc_core::sc_time::from_value(packet->payloadDelay);
287 // Reset the delays
288 packet->payloadDelay = 0;
289 packet->headerDelay = 0;
290
291 // Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC
292 // Standard Page 507 for a visualisation of the procedure.
293 tlm::tlm_phase phase = tlm::BEGIN_REQ;
294 tlm::tlm_sync_enum status;
295 status = socket->nb_transport_fw(*trans, phase, delay);
296 // Check returned value:
297 if (status == tlm::TLM_ACCEPTED) {
298 sc_assert(phase == tlm::BEGIN_REQ);
299 // Accepted but is now blocking until END_REQ (exclusion rule).
300 blockingRequest = trans;
301 } else if (status == tlm::TLM_UPDATED) {
302 // The Timing annotation must be honored:
303 sc_assert(phase == tlm::END_REQ || phase == tlm::BEGIN_RESP);
304
305 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>(
306 *this, &Gem5ToTlmBridge::pec, "PEQ");
307 Tick nextEventTick = curTick() + delay.value();
308 system->wakeupEventQueue(nextEventTick);
309 system->schedule(pe, nextEventTick);
310 } else if (status == tlm::TLM_COMPLETED) {
311 // Transaction is over nothing has do be done.
312 sc_assert(phase == tlm::END_RESP);
313 trans->release();
314 }
315
316 return true;
317}
318
319template <unsigned int BITWIDTH>
320bool
321Gem5ToTlmBridge<BITWIDTH>::recvTimingSnoopResp(PacketPtr packet)
322{
323 // Snooping should be implemented with tlm_dbg_transport.
324 SC_REPORT_FATAL("Gem5ToTlmBridge",
325 "unimplemented func.: recvTimingSnoopResp");
326 return false;
327}
328
329template <unsigned int BITWIDTH>
330bool
331Gem5ToTlmBridge<BITWIDTH>::tryTiming(PacketPtr packet)
332{
333 panic("tryTiming(PacketPtr) isn't implemented.");
334}
335
336template <unsigned int BITWIDTH>
337void
338Gem5ToTlmBridge<BITWIDTH>::recvRespRetry()
339{
340 /* Retry a response */
341 sc_assert(blockingResponse);
342
343 tlm::tlm_generic_payload *trans = blockingResponse;
344 blockingResponse = nullptr;
345 PacketPtr packet =
346 Gem5SystemC::Gem5Extension::getExtension(trans).getPacket();
347
348 bool need_retry = !bsp.sendTimingResp(packet);
349
350 sc_assert(!need_retry);
351
352 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
353 tlm::tlm_phase phase = tlm::END_RESP;
354 socket->nb_transport_fw(*trans, phase, delay);
355 // Release transaction with all the extensions
356 trans->release();
357}
358
359// Similar to TLM's debug transport.
360template <unsigned int BITWIDTH>
361void
362Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet)
363{
364 // Prepare the transaction.
318 /*
319 * Pay for annotated transport delays.
320 *
321 * The header delay marks the point in time, when the packet first is seen
322 * by the transactor. This is the point in time when the transactor needs
323 * to send the BEGIN_REQ to the SystemC world.
324 *
325 * NOTE: We drop the payload delay here. Normally, the receiver would be
326 * responsible for handling the payload delay. In this case, however,
327 * the receiver is a SystemC module and has no notion of the gem5
328 * transport protocol and we cannot simply forward the
329 * payload delay to the receiving module. Instead, we expect the
330 * receiving SystemC module to model the payload delay by deferring
331 * the END_REQ. This could lead to incorrect delays, if the XBar
332 * payload delay is longer than the time the receiver needs to accept
333 * the request (time between BEGIN_REQ and END_REQ).
334 *
335 * TODO: We could detect the case described above by remembering the
336 * payload delay and comparing it to the time between BEGIN_REQ and
337 * END_REQ. Then, a warning should be printed.
338 */
339 auto delay = sc_core::sc_time::from_value(packet->payloadDelay);
340 // Reset the delays
341 packet->payloadDelay = 0;
342 packet->headerDelay = 0;
343
344 // Starting TLM non-blocking sequence (AT) Refer to IEEE1666-2011 SystemC
345 // Standard Page 507 for a visualisation of the procedure.
346 tlm::tlm_phase phase = tlm::BEGIN_REQ;
347 tlm::tlm_sync_enum status;
348 status = socket->nb_transport_fw(*trans, phase, delay);
349 // Check returned value:
350 if (status == tlm::TLM_ACCEPTED) {
351 sc_assert(phase == tlm::BEGIN_REQ);
352 // Accepted but is now blocking until END_REQ (exclusion rule).
353 blockingRequest = trans;
354 } else if (status == tlm::TLM_UPDATED) {
355 // The Timing annotation must be honored:
356 sc_assert(phase == tlm::END_REQ || phase == tlm::BEGIN_RESP);
357
358 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>(
359 *this, &Gem5ToTlmBridge::pec, "PEQ");
360 Tick nextEventTick = curTick() + delay.value();
361 system->wakeupEventQueue(nextEventTick);
362 system->schedule(pe, nextEventTick);
363 } else if (status == tlm::TLM_COMPLETED) {
364 // Transaction is over nothing has do be done.
365 sc_assert(phase == tlm::END_RESP);
366 trans->release();
367 }
368
369 return true;
370}
371
372template <unsigned int BITWIDTH>
373bool
374Gem5ToTlmBridge<BITWIDTH>::recvTimingSnoopResp(PacketPtr packet)
375{
376 // Snooping should be implemented with tlm_dbg_transport.
377 SC_REPORT_FATAL("Gem5ToTlmBridge",
378 "unimplemented func.: recvTimingSnoopResp");
379 return false;
380}
381
382template <unsigned int BITWIDTH>
383bool
384Gem5ToTlmBridge<BITWIDTH>::tryTiming(PacketPtr packet)
385{
386 panic("tryTiming(PacketPtr) isn't implemented.");
387}
388
389template <unsigned int BITWIDTH>
390void
391Gem5ToTlmBridge<BITWIDTH>::recvRespRetry()
392{
393 /* Retry a response */
394 sc_assert(blockingResponse);
395
396 tlm::tlm_generic_payload *trans = blockingResponse;
397 blockingResponse = nullptr;
398 PacketPtr packet =
399 Gem5SystemC::Gem5Extension::getExtension(trans).getPacket();
400
401 bool need_retry = !bsp.sendTimingResp(packet);
402
403 sc_assert(!need_retry);
404
405 sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
406 tlm::tlm_phase phase = tlm::END_RESP;
407 socket->nb_transport_fw(*trans, phase, delay);
408 // Release transaction with all the extensions
409 trans->release();
410}
411
412// Similar to TLM's debug transport.
413template <unsigned int BITWIDTH>
414void
415Gem5ToTlmBridge<BITWIDTH>::recvFunctional(PacketPtr packet)
416{
417 // Prepare the transaction.
365 tlm::tlm_generic_payload *trans = mm.allocate();
366 trans->acquire();
367 packet2payload(packet, *trans);
418 auto *trans = packet2payload(packet);
368
419
369 // Attach the packet pointer to the TLM transaction to keep track.
370 auto *extension = new Gem5SystemC::Gem5Extension(packet);
371 trans->set_auto_extension(extension);
372
373 /* Execute Debug Transport: */
374 unsigned int bytes = socket->transport_dbg(*trans);
375 if (bytes != trans->get_data_length()) {
376 SC_REPORT_FATAL("Gem5ToTlmBridge",
377 "debug transport was not completed");
378 }
379
380 trans->release();
381}
382
383template <unsigned int BITWIDTH>
384tlm::tlm_sync_enum
385Gem5ToTlmBridge<BITWIDTH>::nb_transport_bw(tlm::tlm_generic_payload &trans,
386 tlm::tlm_phase &phase, sc_core::sc_time &delay)
387{
388 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>(
389 *this, &Gem5ToTlmBridge::pec, "PE");
390 Tick nextEventTick = curTick() + delay.value();
391 system->wakeupEventQueue(nextEventTick);
392 system->schedule(pe, nextEventTick);
393 return tlm::TLM_ACCEPTED;
394}
395
396template <unsigned int BITWIDTH>
420 /* Execute Debug Transport: */
421 unsigned int bytes = socket->transport_dbg(*trans);
422 if (bytes != trans->get_data_length()) {
423 SC_REPORT_FATAL("Gem5ToTlmBridge",
424 "debug transport was not completed");
425 }
426
427 trans->release();
428}
429
430template <unsigned int BITWIDTH>
431tlm::tlm_sync_enum
432Gem5ToTlmBridge<BITWIDTH>::nb_transport_bw(tlm::tlm_generic_payload &trans,
433 tlm::tlm_phase &phase, sc_core::sc_time &delay)
434{
435 auto *pe = new Gem5SystemC::PayloadEvent<Gem5ToTlmBridge>(
436 *this, &Gem5ToTlmBridge::pec, "PE");
437 Tick nextEventTick = curTick() + delay.value();
438 system->wakeupEventQueue(nextEventTick);
439 system->schedule(pe, nextEventTick);
440 return tlm::TLM_ACCEPTED;
441}
442
443template <unsigned int BITWIDTH>
444void
445Gem5ToTlmBridge<BITWIDTH>::invalidate_direct_mem_ptr(
446 sc_dt::uint64 start_range, sc_dt::uint64 end_range)
447{
448 AddrRange r(start_range, end_range);
449
450 for (;;) {
451 auto it = backdoorMap.intersects(r);
452 if (it == backdoorMap.end())
453 break;
454
455 it->second->invalidate();
456 delete it->second;
457 backdoorMap.erase(it);
458 };
459}
460
461template <unsigned int BITWIDTH>
397Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge(
398 Params *params, const sc_core::sc_module_name &mn) :
399 Gem5ToTlmBridgeBase(mn), bsp(std::string(name()) + ".gem5", *this),
400 socket("tlm_socket"),
401 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID),
402 system(params->system), blockingRequest(nullptr),
403 needToSendRequestRetry(false), blockingResponse(nullptr),
404 addrRanges(params->addr_ranges.begin(), params->addr_ranges.end())
405{
406}
407
408template <unsigned int BITWIDTH>
409::Port &
410Gem5ToTlmBridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx)
411{
412 if (if_name == "gem5")
413 return bsp;
414 else if (if_name == "tlm")
415 return wrapper;
416
417 return sc_core::sc_module::gem5_getPort(if_name, idx);
418}
419
420template <unsigned int BITWIDTH>
421void
422Gem5ToTlmBridge<BITWIDTH>::before_end_of_elaboration()
423{
424 bsp.sendRangeChange();
425
426 socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw);
462Gem5ToTlmBridge<BITWIDTH>::Gem5ToTlmBridge(
463 Params *params, const sc_core::sc_module_name &mn) :
464 Gem5ToTlmBridgeBase(mn), bsp(std::string(name()) + ".gem5", *this),
465 socket("tlm_socket"),
466 wrapper(socket, std::string(name()) + ".tlm", InvalidPortID),
467 system(params->system), blockingRequest(nullptr),
468 needToSendRequestRetry(false), blockingResponse(nullptr),
469 addrRanges(params->addr_ranges.begin(), params->addr_ranges.end())
470{
471}
472
473template <unsigned int BITWIDTH>
474::Port &
475Gem5ToTlmBridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx)
476{
477 if (if_name == "gem5")
478 return bsp;
479 else if (if_name == "tlm")
480 return wrapper;
481
482 return sc_core::sc_module::gem5_getPort(if_name, idx);
483}
484
485template <unsigned int BITWIDTH>
486void
487Gem5ToTlmBridge<BITWIDTH>::before_end_of_elaboration()
488{
489 bsp.sendRangeChange();
490
491 socket.register_nb_transport_bw(this, &Gem5ToTlmBridge::nb_transport_bw);
492 socket.register_invalidate_direct_mem_ptr(
493 this, &Gem5ToTlmBridge::invalidate_direct_mem_ptr);
427 sc_core::sc_module::before_end_of_elaboration();
428}
429
430} // namespace sc_gem5
431
432sc_gem5::Gem5ToTlmBridge<32> *
433Gem5ToTlmBridge32Params::create()
434{
435 return new sc_gem5::Gem5ToTlmBridge<32>(
436 this, sc_core::sc_module_name(name.c_str()));
437}
438
439sc_gem5::Gem5ToTlmBridge<64> *
440Gem5ToTlmBridge64Params::create()
441{
442 return new sc_gem5::Gem5ToTlmBridge<64>(
443 this, sc_core::sc_module_name(name.c_str()));
444}
494 sc_core::sc_module::before_end_of_elaboration();
495}
496
497} // namespace sc_gem5
498
499sc_gem5::Gem5ToTlmBridge<32> *
500Gem5ToTlmBridge32Params::create()
501{
502 return new sc_gem5::Gem5ToTlmBridge<32>(
503 this, sc_core::sc_module_name(name.c_str()));
504}
505
506sc_gem5::Gem5ToTlmBridge<64> *
507Gem5ToTlmBridge64Params::create()
508{
509 return new sc_gem5::Gem5ToTlmBridge<64>(
510 this, sc_core::sc_module_name(name.c_str()));
511}