Matthias Jung, Janik Schlemminger and Robert Gernhardt were used as authors for all files which did not have an author/header.
171 lines
5.7 KiB
C++
171 lines
5.7 KiB
C++
/*
|
|
* Copyright (c) 2015, University of Kaiserslautern
|
|
* 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.
|
|
*
|
|
* Authors:
|
|
* Janik Schlemminger
|
|
* Robert Gernhardt
|
|
* Matthias Jung
|
|
*/
|
|
|
|
#ifndef REORDERBUFFER_H
|
|
#define REORDERBUFFER_H
|
|
|
|
#include <deque>
|
|
#include <systemc.h>
|
|
#include <set>
|
|
|
|
using namespace std;
|
|
using namespace tlm;
|
|
|
|
template<unsigned int BUSWIDTH = 128>
|
|
struct ReorderBuffer: public sc_module
|
|
{
|
|
public:
|
|
tlm_utils::simple_initiator_socket<ReorderBuffer,BUSWIDTH, tlm::tlm_base_protocol_types> iSocket;
|
|
tlm_utils::simple_target_socket<ReorderBuffer, BUSWIDTH, tlm::tlm_base_protocol_types> tSocket;
|
|
|
|
SC_CTOR(ReorderBuffer) :
|
|
payloadEventQueue(this, &ReorderBuffer::peqCallback), responseIsPendingInInitator(false)
|
|
{
|
|
iSocket.register_nb_transport_bw(this, &ReorderBuffer::nb_transport_bw);
|
|
tSocket.register_nb_transport_fw(this, &ReorderBuffer::nb_transport_fw);
|
|
}
|
|
|
|
private:
|
|
tlm_utils::peq_with_cb_and_phase<ReorderBuffer> payloadEventQueue;
|
|
deque<tlm_generic_payload*> pendingRequestsInOrder;
|
|
set<tlm_generic_payload*> receivedResponses;
|
|
|
|
bool responseIsPendingInInitator;
|
|
|
|
|
|
// Initiated by dram side
|
|
tlm_sync_enum nb_transport_bw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& bwDelay)
|
|
{
|
|
payloadEventQueue.notify(payload, phase, bwDelay);
|
|
return TLM_ACCEPTED;
|
|
}
|
|
|
|
// Initiated by initator side (players)
|
|
tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase,
|
|
sc_time& fwDelay)
|
|
{
|
|
if (phase == BEGIN_REQ)
|
|
{
|
|
payload.acquire();
|
|
}
|
|
else if (phase == END_RESP)
|
|
{
|
|
payload.release();
|
|
}
|
|
|
|
payloadEventQueue.notify(payload, phase, fwDelay);
|
|
return TLM_ACCEPTED;
|
|
}
|
|
|
|
void peqCallback(tlm_generic_payload& payload, const tlm_phase& phase)
|
|
{
|
|
//Phases initiated by initiator side
|
|
if (phase == BEGIN_REQ)
|
|
{
|
|
pendingRequestsInOrder.push_back(&payload);
|
|
sendToTarget(payload, phase, SC_ZERO_TIME );
|
|
}
|
|
|
|
else if (phase == END_RESP)
|
|
{
|
|
responseIsPendingInInitator = false;
|
|
pendingRequestsInOrder.pop_front();
|
|
receivedResponses.erase(&payload);
|
|
sendNextResponse();
|
|
}
|
|
|
|
//Phases initiated by dram side
|
|
else if (phase == END_REQ)
|
|
{
|
|
sendToInitiator(payload, phase, SC_ZERO_TIME);
|
|
}
|
|
else if (phase == BEGIN_RESP)
|
|
{
|
|
sendToTarget(payload, END_RESP, SC_ZERO_TIME);
|
|
receivedResponses.emplace(&payload);
|
|
sendNextResponse();
|
|
}
|
|
|
|
|
|
else
|
|
{
|
|
SC_REPORT_FATAL(0, "Payload event queue in arbiter was triggered with unknown phase");
|
|
}
|
|
}
|
|
|
|
void sendToTarget(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay)
|
|
{
|
|
tlm_phase TPhase = phase;
|
|
sc_time TDelay = delay;
|
|
iSocket->nb_transport_fw(payload, TPhase, TDelay);
|
|
}
|
|
|
|
void sendToInitiator(tlm_generic_payload& payload, const tlm_phase& phase, const sc_time& delay)
|
|
{
|
|
|
|
|
|
sc_assert(phase == END_REQ ||
|
|
(phase == BEGIN_RESP && pendingRequestsInOrder.front() == &payload && receivedResponses.count(&payload)));
|
|
|
|
tlm_phase TPhase = phase;
|
|
sc_time TDelay = delay;
|
|
tSocket->nb_transport_bw(payload, TPhase, TDelay);
|
|
}
|
|
|
|
void sendNextResponse()
|
|
{
|
|
//only send the next response when there response for the oldest pending request (requestsInOrder.front())
|
|
//has been received
|
|
if(!responseIsPendingInInitator && receivedResponses.count(pendingRequestsInOrder.front()))
|
|
{
|
|
tlm_generic_payload* payloadToSend = pendingRequestsInOrder.front();
|
|
responseIsPendingInInitator = true;
|
|
sendToInitiator(*payloadToSend,BEGIN_RESP,SC_ZERO_TIME);
|
|
}
|
|
// else if(!responseIsPendingInInitator && receivedResponses.size()>0 && !receivedResponses.count(pendingRequestsInOrder.front())>0)
|
|
// {
|
|
// cout << "cant send this response, because we are still waiting for response of oldest pending request. Elemts in buffer: " << receivedResponses.size() << endl;
|
|
// }
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif // REORDERBUFFER_H
|