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