gem5_to_tlm.cc revision 13823
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
84 */
85void
86packet2payload(PacketPtr packet, tlm::tlm_generic_payload &trans)
87{
88    trans.set_address(packet->getAddr());
89
90    /* Check if this transaction was allocated by mm */
91    sc_assert(trans.has_mm());
92
93    unsigned int size = packet->getSize();
94    unsigned char *data = packet->getPtr<unsigned char>();
95
96    trans.set_data_length(size);
97    trans.set_streaming_width(size);
98    trans.set_data_ptr(data);
99
100    if (packet->isRead()) {
101        trans.set_command(tlm::TLM_READ_COMMAND);
102    } else if (packet->isInvalidate()) {
103        /* Do nothing */
104    } else if (packet->isWrite()) {
105        trans.set_command(tlm::TLM_WRITE_COMMAND);
106    } else {
107        SC_REPORT_FATAL("Gem5ToTlmBridge", "No R/W packet");
108    }
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
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
177    panic_if(!(packet->isRead() || packet->isWrite()),
178             "Should only see read and writes at TLM memory\n");
179
180    sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
181
182    // Prepare the transaction.
183    tlm::tlm_generic_payload *trans = mm.allocate();
184    trans->acquire();
185    packet2payload(packet, *trans);
186
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);
190
191    // Execute b_transport:
192    if (packet->cmd == MemCmd::SwapReq) {
193        SC_REPORT_FATAL("Gem5ToTlmBridge", "SwapReq not supported");
194    } else if (packet->isRead()) {
195        socket->b_transport(*trans, delay);
196    } else if (packet->isInvalidate()) {
197        // do nothing
198    } else if (packet->isWrite()) {
199        socket->b_transport(*trans, delay);
200    } else {
201        SC_REPORT_FATAL("Gem5ToTlmBridge", "Typo of request not supported");
202    }
203
204    if (packet->needsResponse()) {
205        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.
257    tlm::tlm_generic_payload *trans = mm.allocate();
258    trans->acquire();
259    packet2payload(packet, *trans);
260
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.
365    tlm::tlm_generic_payload *trans = mm.allocate();
366    trans->acquire();
367    packet2payload(packet, *trans);
368
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>
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);
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}
445