| /* |
| * Copyright (c) 2016, Dresden University of Technology (TU Dresden) |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
| * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER |
| * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "base/random.hh" |
| #include "traffic_generator.hh" |
| |
| TrafficGenerator::TrafficGenerator(sc_core::sc_module_name name) |
| : sc_core::sc_module(name), |
| requestInProgress(0), |
| peq(this, &TrafficGenerator::peq_cb) |
| { |
| socket.register_nb_transport_bw(this, &TrafficGenerator::nb_transport_bw); |
| SC_THREAD(process); |
| } |
| |
| void |
| TrafficGenerator::process() |
| { |
| auto rnd = Random(time(NULL)); |
| |
| unsigned const memSize = (1 << 10); // 512 MB |
| |
| while (true) { |
| |
| wait(sc_core::sc_time((double)rnd.random(1,100), sc_core::SC_NS)); |
| |
| auto trans = mm.allocate(); |
| trans->acquire(); |
| |
| std::string cmdStr; |
| if (rnd.random(0,1)) // Generate a write request? |
| { |
| cmdStr = "write"; |
| trans->set_command(tlm::TLM_WRITE_COMMAND); |
| dataBuffer = rnd.random(0,0xffff); |
| } else { |
| cmdStr = "read"; |
| trans->set_command(tlm::TLM_READ_COMMAND); |
| } |
| |
| trans->set_data_ptr(reinterpret_cast<unsigned char*>(&dataBuffer)); |
| trans->set_address(rnd.random(0, (int)(memSize-1))); |
| trans->set_data_length(4); |
| trans->set_streaming_width(4); |
| trans->set_byte_enable_ptr(0); |
| trans->set_dmi_allowed(0); |
| trans->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); |
| |
| // honor the BEGIN_REQ/END_REQ exclusion rule |
| if (requestInProgress) |
| sc_core::wait(endRequestEvent); |
| |
| std::stringstream ss; |
| ss << "Send " << cmdStr << " request @0x" << std::hex |
| << trans->get_address(); |
| SC_REPORT_INFO("Traffic Generator", ss.str().c_str()); |
| |
| // send the request |
| requestInProgress = trans; |
| tlm::tlm_phase phase = tlm::BEGIN_REQ; |
| auto delay = sc_core::SC_ZERO_TIME; |
| |
| auto status = socket->nb_transport_fw(*trans, phase, delay); |
| |
| // Check status |
| if (status == tlm::TLM_UPDATED) { |
| peq.notify(*trans, phase, delay); |
| } else if (status == tlm::TLM_COMPLETED) { |
| requestInProgress = 0; |
| checkTransaction(*trans); |
| SC_REPORT_INFO("Traffic Generator", "request completed"); |
| trans->release(); |
| } |
| } |
| } |
| |
| void |
| TrafficGenerator::peq_cb(tlm::tlm_generic_payload& trans, |
| const tlm::tlm_phase& phase) |
| { |
| if (phase == tlm::END_REQ || |
| (&trans == requestInProgress && phase == tlm::BEGIN_RESP)) { |
| // The end of the BEGIN_REQ phase |
| requestInProgress = 0; |
| endRequestEvent.notify(); |
| } else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP) |
| SC_REPORT_FATAL("TLM-2", |
| "Illegal transaction phase received by initiator"); |
| |
| if (phase == tlm::BEGIN_RESP) { |
| checkTransaction(trans); |
| SC_REPORT_INFO("Traffic Generator", "received response"); |
| |
| // Send end response |
| tlm::tlm_phase fw_phase = tlm::END_RESP; |
| |
| // stress the retry mechanism by deferring the response |
| auto delay = sc_core::sc_time(5.0, sc_core::SC_NS); |
| socket->nb_transport_fw(trans, fw_phase, delay); |
| trans.release(); |
| } |
| } |
| |
| void |
| TrafficGenerator::checkTransaction(tlm::tlm_generic_payload& trans) |
| { |
| if (trans.is_response_error()) { |
| std::stringstream ss; |
| ss << "Transaction returned with error, response status = %s" |
| << trans.get_response_string(); |
| SC_REPORT_ERROR("TLM-2", ss.str().c_str()); |
| } |
| } |
| |
| tlm::tlm_sync_enum |
| TrafficGenerator::nb_transport_bw(tlm::tlm_generic_payload& trans, |
| tlm::tlm_phase& phase, |
| sc_core::sc_time& delay) |
| { |
| trans.acquire(); |
| peq.notify(trans, phase, delay); |
| return tlm::TLM_ACCEPTED; |
| } |