blob: 38095812540104bbaaf1996c7426dd824aabffb4 [file] [log] [blame]
/*
* 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;
}