tlm_to_gem5.cc revision 13846:af21c0a800fb
112904Sgabeblack@google.com/*
212904Sgabeblack@google.com * Copyright 2019 Google, Inc.
312904Sgabeblack@google.com *
412904Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
512904Sgabeblack@google.com * modification, are permitted provided that the following conditions are
612904Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
712904Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
812904Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
912904Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
1012904Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
1112904Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
1212904Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
1312904Sgabeblack@google.com * this software without specific prior written permission.
1412904Sgabeblack@google.com *
1512904Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612904Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712904Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812904Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912904Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012904Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112904Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212904Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312904Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412904Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512904Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612904Sgabeblack@google.com *
2712904Sgabeblack@google.com * Copyright (c) 2016, Dresden University of Technology (TU Dresden)
2812904Sgabeblack@google.com * 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 * Authors: Gabe Black
58 *          Christian Menard
59 */
60
61#include "systemc/tlm_bridge/tlm_to_gem5.hh"
62
63#include "params/TlmToGem5Bridge32.hh"
64#include "params/TlmToGem5Bridge64.hh"
65#include "sim/system.hh"
66#include "systemc/ext/core/sc_module_name.hh"
67#include "systemc/ext/core/sc_time.hh"
68
69namespace sc_gem5
70{
71
72template <unsigned int BITWIDTH>
73void
74TlmToGem5Bridge<BITWIDTH>::sendEndReq(tlm::tlm_generic_payload &trans)
75{
76    tlm::tlm_phase phase = tlm::END_REQ;
77    auto delay = sc_core::SC_ZERO_TIME;
78
79    auto status = socket->nb_transport_bw(trans, phase, delay);
80    panic_if(status != tlm::TLM_ACCEPTED,
81             "Unexpected status after sending END_REQ");
82}
83
84template <unsigned int BITWIDTH>
85void
86TlmToGem5Bridge<BITWIDTH>::sendBeginResp(tlm::tlm_generic_payload &trans,
87                                         sc_core::sc_time &delay)
88{
89    tlm::tlm_phase phase = tlm::BEGIN_RESP;
90
91    trans.set_response_status(tlm::TLM_OK_RESPONSE);
92
93    auto status = socket->nb_transport_bw(trans, phase, delay);
94
95    if (status == tlm::TLM_COMPLETED ||
96        (status == tlm::TLM_UPDATED && phase == tlm::END_RESP)) {
97        // transaction completed -> no need to wait for tlm::END_RESP
98        responseInProgress = false;
99    } else if (status == tlm::TLM_ACCEPTED) {
100        // we need to wait for tlm::END_RESP
101        responseInProgress = true;
102    } else {
103        panic("Unexpected status after sending BEGIN_RESP");
104    }
105}
106
107template <unsigned int BITWIDTH>
108void
109TlmToGem5Bridge<BITWIDTH>::handleBeginReq(tlm::tlm_generic_payload &trans)
110{
111    sc_assert(!waitForRetry);
112    sc_assert(pendingRequest == nullptr);
113    sc_assert(pendingPacket == nullptr);
114
115    trans.acquire();
116
117    PacketPtr pkt = nullptr;
118
119    Gem5SystemC::Gem5Extension *extension = nullptr;
120    trans.get_extension(extension);
121
122    // If there is an extension, this transaction was initiated by the gem5
123    // world and we can pipe through the original packet. Otherwise, we
124    // generate a new packet based on the transaction.
125    if (extension != nullptr) {
126        extension->setPipeThrough();
127        pkt = extension->getPacket();
128    } else {
129        pkt = generatePacket(trans);
130    }
131
132    auto tlmSenderState = new TlmSenderState(trans);
133    pkt->pushSenderState(tlmSenderState);
134
135    if (bmp.sendTimingReq(pkt)) { // port is free -> send END_REQ immediately
136        sendEndReq(trans);
137        trans.release();
138    } else { // port is blocked -> wait for retry before sending END_REQ
139        waitForRetry = true;
140        pendingRequest = &trans;
141        pendingPacket = pkt;
142    }
143}
144
145template <unsigned int BITWIDTH>
146void
147TlmToGem5Bridge<BITWIDTH>::handleEndResp(tlm::tlm_generic_payload &trans)
148{
149    sc_assert(responseInProgress);
150
151    responseInProgress = false;
152
153    checkTransaction(trans);
154
155    if (needToSendRetry) {
156        bmp.sendRetryResp();
157        needToSendRetry = false;
158    }
159}
160
161template <unsigned int BITWIDTH>
162PacketPtr
163TlmToGem5Bridge<BITWIDTH>::generatePacket(tlm::tlm_generic_payload &trans)
164{
165    MemCmd cmd;
166
167    switch (trans.get_command()) {
168        case tlm::TLM_READ_COMMAND:
169            cmd = MemCmd::ReadReq;
170            break;
171        case tlm::TLM_WRITE_COMMAND:
172            cmd = MemCmd::WriteReq;
173            break;
174        case tlm::TLM_IGNORE_COMMAND:
175            return nullptr;
176        default:
177            SC_REPORT_FATAL("TlmToGem5Bridge",
178                            "received transaction with unsupported command");
179    }
180
181    Request::Flags flags;
182    auto req = std::make_shared<Request>(
183        trans.get_address(), trans.get_data_length(), flags, masterId);
184
185    /*
186     * Allocate a new Packet. The packet will be deleted when it returns from
187     * the gem5 world as a response.
188     */
189    auto pkt = new Packet(req, cmd);
190    pkt->dataStatic(trans.get_data_ptr());
191
192    return pkt;
193}
194
195template <unsigned int BITWIDTH>
196void
197TlmToGem5Bridge<BITWIDTH>::destroyPacket(PacketPtr pkt)
198{
199    delete pkt;
200}
201
202template <unsigned int BITWIDTH>
203void
204TlmToGem5Bridge<BITWIDTH>::checkTransaction(tlm::tlm_generic_payload &trans)
205{
206    if (trans.is_response_error()) {
207        std::stringstream ss;
208        ss << "Transaction returned with error, response status = "
209           << trans.get_response_string();
210        SC_REPORT_ERROR("TLM-2", ss.str().c_str());
211    }
212}
213
214template <unsigned int BITWIDTH>
215void
216TlmToGem5Bridge<BITWIDTH>::invalidateDmi(const ::MemBackdoor &backdoor)
217{
218    socket->invalidate_direct_mem_ptr(
219            backdoor.range().start(), backdoor.range().end());
220}
221
222template <unsigned int BITWIDTH>
223void
224TlmToGem5Bridge<BITWIDTH>::peq_cb(tlm::tlm_generic_payload &trans,
225                                  const tlm::tlm_phase &phase)
226{
227    switch (phase) {
228        case tlm::BEGIN_REQ:
229            handleBeginReq(trans);
230            break;
231        case tlm::END_RESP:
232            handleEndResp(trans);
233            break;
234        default:
235            panic("unimplemented phase in callback");
236    }
237}
238
239template <unsigned int BITWIDTH>
240tlm::tlm_sync_enum
241TlmToGem5Bridge<BITWIDTH>::nb_transport_fw(
242        tlm::tlm_generic_payload &trans, tlm::tlm_phase &phase,
243        sc_core::sc_time &delay)
244{
245    unsigned len = trans.get_data_length();
246    unsigned char *byteEnable = trans.get_byte_enable_ptr();
247    unsigned width = trans.get_streaming_width();
248
249    // check the transaction attributes for unsupported features ...
250    if (byteEnable != 0) {
251        trans.set_response_status(tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE);
252        return tlm::TLM_COMPLETED;
253    }
254    if (width < len) { // is this a burst request?
255        trans.set_response_status(tlm::TLM_BURST_ERROR_RESPONSE);
256        return tlm::TLM_COMPLETED;
257    }
258
259    // ... and queue the valid transaction
260    trans.acquire();
261    peq.notify(trans, phase, delay);
262    return tlm::TLM_ACCEPTED;
263}
264
265template <unsigned int BITWIDTH>
266void
267TlmToGem5Bridge<BITWIDTH>::b_transport(tlm::tlm_generic_payload &trans,
268                                       sc_core::sc_time &t)
269{
270    Gem5SystemC::Gem5Extension *extension = nullptr;
271    trans.get_extension(extension);
272
273    PacketPtr pkt = nullptr;
274
275    // If there is an extension, this transaction was initiated by the gem5
276    // world and we can pipe through the original packet.
277    if (extension != nullptr) {
278        extension->setPipeThrough();
279        pkt = extension->getPacket();
280    } else {
281        pkt = generatePacket(trans);
282    }
283
284    MemBackdoorPtr backdoor = nullptr;
285    Tick ticks = bmp.sendAtomicBackdoor(pkt, backdoor);
286    if (backdoor)
287        trans.set_dmi_allowed(true);
288
289    // send an atomic request to gem5
290    panic_if(pkt->needsResponse() && !pkt->isResponse(),
291             "Packet sending failed!\n");
292
293    auto delay =
294      sc_core::sc_time((double)(ticks / SimClock::Int::ps), sc_core::SC_PS);
295
296    // update time
297    t += delay;
298
299    if (extension == nullptr)
300        destroyPacket(pkt);
301
302    trans.set_response_status(tlm::TLM_OK_RESPONSE);
303}
304
305template <unsigned int BITWIDTH>
306unsigned int
307TlmToGem5Bridge<BITWIDTH>::transport_dbg(tlm::tlm_generic_payload &trans)
308{
309    Gem5SystemC::Gem5Extension *extension = nullptr;
310    trans.get_extension(extension);
311
312    // If there is an extension, this transaction was initiated by the gem5
313    // world and we can pipe through the original packet.
314    if (extension != nullptr) {
315        extension->setPipeThrough();
316        bmp.sendFunctional(extension->getPacket());
317    } else {
318        auto pkt = generatePacket(trans);
319        if (pkt) {
320            bmp.sendFunctional(pkt);
321            destroyPacket(pkt);
322        }
323    }
324
325    return trans.get_data_length();
326}
327
328template <unsigned int BITWIDTH>
329bool
330TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr(tlm::tlm_generic_payload &trans,
331                                              tlm::tlm_dmi &dmi_data)
332{
333    Gem5SystemC::Gem5Extension *extension = nullptr;
334    trans.get_extension(extension);
335
336    PacketPtr pkt = nullptr;
337
338    // If there is an extension, this transaction was initiated by the gem5
339    // world and we can pipe through the original packet.
340    if (extension != nullptr) {
341        extension->setPipeThrough();
342        pkt = extension->getPacket();
343    } else {
344        pkt = generatePacket(trans);
345        pkt->req->setFlags(Request::NO_ACCESS);
346    }
347
348    MemBackdoorPtr backdoor = nullptr;
349    bmp.sendAtomicBackdoor(pkt, backdoor);
350    if (backdoor) {
351        trans.set_dmi_allowed(true);
352        dmi_data.set_dmi_ptr(backdoor->ptr());
353        dmi_data.set_start_address(backdoor->range().start());
354        dmi_data.set_end_address(backdoor->range().end());
355
356        typedef tlm::tlm_dmi::dmi_access_e access_t;
357        access_t access = tlm::tlm_dmi::DMI_ACCESS_NONE;
358        if (backdoor->readable())
359            access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_READ);
360        if (backdoor->writeable())
361            access = (access_t)(access | tlm::tlm_dmi::DMI_ACCESS_WRITE);
362        dmi_data.set_granted_access(access);
363
364        backdoor->addInvalidationCallback(
365            [this](const MemBackdoor &backdoor)
366            {
367                invalidateDmi(backdoor);
368            }
369        );
370    }
371
372    if (extension == nullptr)
373        destroyPacket(pkt);
374
375    trans.set_response_status(tlm::TLM_OK_RESPONSE);
376
377    return backdoor != nullptr;
378}
379
380template <unsigned int BITWIDTH>
381bool
382TlmToGem5Bridge<BITWIDTH>::recvTimingResp(PacketPtr pkt)
383{
384    // exclusion rule
385    // We need to Wait for END_RESP before sending next BEGIN_RESP
386    if (responseInProgress) {
387        sc_assert(!needToSendRetry);
388        needToSendRetry = true;
389        return false;
390    }
391
392    sc_assert(pkt->isResponse());
393
394    /*
395     * Pay for annotated transport delays.
396     *
397     * See recvTimingReq in sc_slave_port.cc for a detailed description.
398     */
399    auto delay = sc_core::sc_time::from_value(pkt->payloadDelay);
400    // reset the delays
401    pkt->payloadDelay = 0;
402    pkt->headerDelay = 0;
403
404    auto tlmSenderState = dynamic_cast<TlmSenderState*>(pkt->popSenderState());
405    sc_assert(tlmSenderState != nullptr);
406
407    auto &trans = tlmSenderState->trans;
408
409    Gem5SystemC::Gem5Extension *extension = nullptr;
410    trans.get_extension(extension);
411
412    // clean up
413    delete tlmSenderState;
414
415    // If there is an extension the packet was piped through and we must not
416    // delete it. The packet travels back with the transaction.
417    if (extension == nullptr)
418        destroyPacket(pkt);
419    else
420        sc_assert(extension->isPipeThrough());
421
422    sendBeginResp(trans, delay);
423    trans.release();
424
425    return true;
426}
427
428template <unsigned int BITWIDTH>
429void
430TlmToGem5Bridge<BITWIDTH>::recvReqRetry()
431{
432    sc_assert(waitForRetry);
433    sc_assert(pendingRequest != nullptr);
434    sc_assert(pendingPacket != nullptr);
435
436    if (bmp.sendTimingReq(pendingPacket)) {
437        waitForRetry = false;
438        pendingPacket = nullptr;
439
440        auto &trans = *pendingRequest;
441        sendEndReq(trans);
442        trans.release();
443
444        pendingRequest = nullptr;
445    }
446}
447
448template <unsigned int BITWIDTH>
449void
450TlmToGem5Bridge<BITWIDTH>::recvRangeChange()
451{
452    SC_REPORT_WARNING("TlmToGem5Bridge",
453                      "received address range change but ignored it");
454}
455
456template <unsigned int BITWIDTH>
457::Port &
458TlmToGem5Bridge<BITWIDTH>::gem5_getPort(const std::string &if_name, int idx)
459{
460    if (if_name == "gem5")
461        return bmp;
462    else if (if_name == "tlm")
463        return wrapper;
464
465    return sc_core::sc_module::gem5_getPort(if_name, idx);
466}
467
468template <unsigned int BITWIDTH>
469TlmToGem5Bridge<BITWIDTH>::TlmToGem5Bridge(
470        Params *params, const sc_core::sc_module_name &mn) :
471    TlmToGem5BridgeBase(mn), peq(this, &TlmToGem5Bridge<BITWIDTH>::peq_cb),
472    waitForRetry(false), pendingRequest(nullptr), pendingPacket(nullptr),
473    needToSendRetry(false), responseInProgress(false),
474    bmp(std::string(name()) + "master", *this), socket("tlm_socket"),
475    wrapper(socket, std::string(name()) + ".tlm", InvalidPortID),
476    system(params->system),
477    masterId(params->system->getGlobalMasterId(
478                std::string("[systemc].") + name()))
479{
480}
481
482template <unsigned int BITWIDTH>
483void
484TlmToGem5Bridge<BITWIDTH>::before_end_of_elaboration()
485{
486    /*
487     * Register the TLM non-blocking interface when using gem5 Timing mode and
488     * the TLM blocking interface when using the gem5 Atomic mode.
489     * Then the magic (TM) in simple_target_socket automatically transforms
490     * non-blocking in blocking transactions and vice versa.
491     *
492     * NOTE: The mode may change during execution.
493     */
494    if (system->isTimingMode()) {
495        SC_REPORT_INFO("TlmToGem5Bridge", "register non-blocking interface");
496        socket.register_nb_transport_fw(
497                this, &TlmToGem5Bridge<BITWIDTH>::nb_transport_fw);
498    } else if (system->isAtomicMode()) {
499        SC_REPORT_INFO("TlmToGem5Bridge", "register blocking interface");
500        socket.register_b_transport(
501                this, &TlmToGem5Bridge<BITWIDTH>::b_transport);
502        socket.register_get_direct_mem_ptr(
503                this, &TlmToGem5Bridge<BITWIDTH>::get_direct_mem_ptr);
504    } else {
505        panic("gem5 operates neither in Timing nor in Atomic mode");
506    }
507
508    socket.register_transport_dbg(
509            this, &TlmToGem5Bridge<BITWIDTH>::transport_dbg);
510
511    sc_core::sc_module::before_end_of_elaboration();
512}
513
514} // namespace sc_gem5
515
516sc_gem5::TlmToGem5Bridge<32> *
517TlmToGem5Bridge32Params::create()
518{
519    return new sc_gem5::TlmToGem5Bridge<32>(
520            this, sc_core::sc_module_name(name.c_str()));
521}
522
523sc_gem5::TlmToGem5Bridge<64> *
524TlmToGem5Bridge64Params::create()
525{
526    return new sc_gem5::TlmToGem5Bridge<64>(
527            this, sc_core::sc_module_name(name.c_str()));
528}
529