1/*
2 * Copyright (c) 2016, Dresden University of Technology (TU Dresden)
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 *    contributors may be used to endorse or promote products derived from
18 *    this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Authors: Christian Menard
33 */
34
35#include "base/random.hh"
36#include "traffic_generator.hh"
37
38TrafficGenerator::TrafficGenerator(sc_core::sc_module_name name)
39  : sc_core::sc_module(name),
40    requestInProgress(0),
41    peq(this, &TrafficGenerator::peq_cb)
42{
43    socket.register_nb_transport_bw(this, &TrafficGenerator::nb_transport_bw);
44    SC_THREAD(process);
45}
46
47void
48TrafficGenerator::process()
49{
50    auto rnd = Random(time(NULL));
51
52    unsigned const memSize = (1 << 10); // 512 MB
53
54    while (true) {
55
56        wait(sc_core::sc_time((double)rnd.random(1,100), sc_core::SC_NS));
57
58        auto trans = mm.allocate();
59        trans->acquire();
60
61        std::string cmdStr;
62        if (rnd.random(0,1)) // Generate a write request?
63        {
64            cmdStr = "write";
65            trans->set_command(tlm::TLM_WRITE_COMMAND);
66            dataBuffer = rnd.random(0,0xffff);
67        } else {
68            cmdStr = "read";
69            trans->set_command(tlm::TLM_READ_COMMAND);
70        }
71
72        trans->set_data_ptr(reinterpret_cast<unsigned char*>(&dataBuffer));
73        trans->set_address(rnd.random(0, (int)(memSize-1)));
74        trans->set_data_length(4);
75        trans->set_streaming_width(4);
76        trans->set_byte_enable_ptr(0);
77        trans->set_dmi_allowed(0);
78        trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
79
80        // honor the BEGIN_REQ/END_REQ exclusion rule
81        if (requestInProgress)
82            sc_core::wait(endRequestEvent);
83
84        std::stringstream ss;
85        ss << "Send " << cmdStr << " request @0x" << std::hex
86           << trans->get_address();
87        SC_REPORT_INFO("Traffic Generator", ss.str().c_str());
88
89        // send the request
90        requestInProgress = trans;
91        tlm::tlm_phase phase = tlm::BEGIN_REQ;
92        auto delay = sc_core::SC_ZERO_TIME;
93
94        auto status = socket->nb_transport_fw(*trans, phase, delay);
95
96        // Check status
97        if (status == tlm::TLM_UPDATED) {
98            peq.notify(*trans, phase, delay);
99        } else if (status == tlm::TLM_COMPLETED) {
100            requestInProgress = 0;
101            checkTransaction(*trans);
102            SC_REPORT_INFO("Traffic Generator", "request completed");
103            trans->release();
104        }
105    }
106}
107
108void
109TrafficGenerator::peq_cb(tlm::tlm_generic_payload& trans,
110                         const tlm::tlm_phase& phase)
111{
112    if (phase == tlm::END_REQ ||
113        (&trans == requestInProgress && phase == tlm::BEGIN_RESP)) {
114        // The end of the BEGIN_REQ phase
115        requestInProgress = 0;
116        endRequestEvent.notify();
117    } else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP)
118        SC_REPORT_FATAL("TLM-2",
119                        "Illegal transaction phase received by initiator");
120
121    if (phase == tlm::BEGIN_RESP) {
122        checkTransaction(trans);
123        SC_REPORT_INFO("Traffic Generator", "received response");
124
125        // Send end response
126        tlm::tlm_phase fw_phase = tlm::END_RESP;
127
128        // stress the retry mechanism by deferring the response
129        auto delay = sc_core::sc_time(5.0, sc_core::SC_NS);
130        socket->nb_transport_fw(trans, fw_phase, delay);
131        trans.release();
132    }
133}
134
135void
136TrafficGenerator::checkTransaction(tlm::tlm_generic_payload& trans)
137{
138    if (trans.is_response_error()) {
139        std::stringstream ss;
140        ss << "Transaction returned with error, response status = %s"
141           << trans.get_response_string();
142        SC_REPORT_ERROR("TLM-2", ss.str().c_str());
143    }
144}
145
146tlm::tlm_sync_enum
147TrafficGenerator::nb_transport_bw(tlm::tlm_generic_payload& trans,
148                                  tlm::tlm_phase& phase,
149                                  sc_core::sc_time& delay)
150{
151    trans.acquire();
152    peq.notify(trans, phase, delay);
153    return tlm::TLM_ACCEPTED;
154}
155