Show simpleBusProtocol.h syntax highlighted
/*
Copyright (c) 2006 : Technical University of Braunschweig, Germany
All rights reserved.
Authors: Robert Guenzel, Wolfgang Klingauf, TU Braunschweig, E.I.S.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer. 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. Neither the name of
the Technical University of Braunschweig, Germany 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
OWNER 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.
*/
#ifndef __simpleBusProtocol_h__
#define __simpleBusProtocol_h__
#define VERBOSE
#include <systemc.h>
#include "gstlm/tlm.h"
#include "protocol/generic.h"
#include "router/genericProtocol_if.h"
#include "router/genericScheduler_if.h"
using namespace tlm;
//--------------------------------------------------------------------------
/**
* A simple bus protocol implementation.
* The bus processes transactions consecutively. The arbitration
* is clock-synchronous. Thus, incoming requests are always processed
* with the next positive edge of the clock. Requests are
* granted immediately when the bus is idle, else they will have to wait
* until the bus is available again.
*/
//--------------------------------------------------------------------------
template <class TRANSACTION,
class PHASE,
class TRANSACTION_P = boost::shared_ptr<TRANSACTION>,
class PHASE_P = PHASE, //PHASE_P = boost::shared_ptr<PHASE>,
class TRANSACTION_PHASE = tlm::unevenpair<TRANSACTION_P,PHASE_P>,
class INITPORT = initiator_multi_port<TRANSACTION,GenericRouterAccess,PHASE>,
class TARGETPORT = target_multi_port<TRANSACTION,GenericRouterAccess,PHASE>,
class ADDRESSMAP = SimpleAddressMap<MAddr,INITPORT,TRANSACTION,PHASE>
>
class SimpleBusProtocol
: public GenericProtocol_if<TRANSACTION, PHASE>,
public sc_module
{
typedef sc_export<payload_event_queue_if<tlm::unevenpair<boost::shared_ptr<TRANSACTION>,PHASE > > > * SourcePort;
typedef sc_export<payload_event_queue_if<tlm::unevenpair<boost::shared_ptr<TRANSACTION>,PHASE > > > * DestinationPort;
public:
/// the port to the router
sc_port<GenericRouter_if<INITPORT, TARGETPORT> > router_port;
/// the port to the scheduler
sc_port<GenericScheduler_if<TRANSACTION, PHASE> > scheduler_port;
SC_HAS_PROCESS(SimpleBusProtocol);
//--------------------------------------------------------------------------
/**
* Constructor.
*/
//--------------------------------------------------------------------------
SimpleBusProtocol(sc_module_name name_, sc_time clkPeriod) :
sc_module(name_),
router_port("router_port"),
scheduler_port("scheduler_port"),
m_clkPeriod(clkPeriod),
m_idle(true)
{
GS_TRACE(name(), "I am a simple bus protocol.");
// DUST structure analysis
#ifdef DUST_ENABLE
DUST_PROTOCOL("SimpleBusProtocl");
#endif
}
//--------------------------------------------------------------------------
/**
* A master accesses the channel
*/
//--------------------------------------------------------------------------
virtual bool registerMasterAccess(TRANSACTION_PHASE& transaction)
{
GenericPhase p = transaction.second;
GenericRouterAccess &t = dynamic_cast<GenericRouterAccess&>(*(transaction.first));
if (p.isRequestValid()) {
// this is a new request, so let's schedule it for execution
scheduler_port->enqueue(transaction);
// process the request at the next posedge clk
GS_TRACE(name(), "got RequestValid atom from master id=0x%x --> requesting its execution for the next posedge clk from the scheduler.", (unsigned)t.get_mID());
startMasterAccessProcessingEvent.notify(m_clkPeriod);
return true;
}
else {
// this is a master who is in the data handshake phase, so forward the data to the slave
DestinationPort destination = ( *router_port->getInitPort() ).connected_in_ports[router_port->decodeAddress(t.get_mAddr())];
(*destination)->notify(transaction);
GS_TRACE(name(), "got %s atom from master id=0x%x", p.toString().c_str(), (unsigned)t.get_mID());
return true;
}
}
//--------------------------------------------------------------------------
/**
* A master's request is to be processed now.
*/
//--------------------------------------------------------------------------
virtual bool processMasterAccess()
{
// if bus is idle, check for new request
if (m_idle && scheduler_port->isPending()) {
// get next pending request from scheduler...
TRANSACTION_PHASE transaction = scheduler_port->dequeue();
GenericRouterAccess &t = dynamic_cast<GenericRouterAccess&>(*(transaction.first));
// ...and forward it to the slave
DestinationPort destination = ( *router_port->getInitPort() ).connected_in_ports[router_port->decodeAddress(t.get_mAddr())];
(*destination)->notify(transaction);
GS_TRACE(name(), "notified RequestValid from master id=0x%x", (unsigned)t.get_mID());
m_idle =false;
return true;
}
return false;
}
//--------------------------------------------------------------------------
/**
* A slave accesses the channel
*/
//--------------------------------------------------------------------------
virtual bool registerSlaveAccess(TRANSACTION_PHASE& transaction)
{
GenericRouterAccess &t = dynamic_cast<GenericRouterAccess&>(*(transaction.first));
GenericPhase p =transaction.second;
SourcePort source =( *router_port->getTargetPort() ).connected_in_ports[m_masterMap[t.get_mID()]];
(*source)->notify(transaction); // immideately forward the ack
switch(p.state) {
case GenericPhase::DataAccepted:
GS_TRACE(name(), "got DataAccepted atom from slave at address=0x%x", (unsigned)t.get_mAddr());
m_idle =true; // transaction finished
startMasterAccessProcessingEvent.notify(m_clkPeriod); // handle next request
break;
case GenericPhase::DataError:
GS_TRACE(name(), "got DataError atom from slave at address=0x%x", (unsigned)t.get_mAddr());
m_idle =true; // transaction finished
startMasterAccessProcessingEvent.notify(m_clkPeriod); // handle next request
break;
case GenericPhase::ResponseValid:
GS_TRACE(name(), "got ResponseValid atom from slave at address=0x%x", (unsigned)t.get_mAddr());
m_idle =true;
startMasterAccessProcessingEvent.notify(m_clkPeriod); // handle next request
break;
case GenericPhase::RequestError:
GS_TRACE(name(), "got RequestError atom from slave at address=0x%x", (unsigned)t.get_mAddr());
m_idle =true;
startMasterAccessProcessingEvent.notify(m_clkPeriod); // handle next request
break;
default:
GS_TRACE(name(), "got %s atom from slave at address=0x%x", p.toString().c_str(), (unsigned)t.get_mAddr());
}
return true;
}
//--------------------------------------------------------------------------
/**
* A slave's request should be processed now.
*/
//--------------------------------------------------------------------------
virtual bool processSlaveAccess()
{
// this method can be used for implementing advanced protocol functions,
// e.g. timeout handling
return true;
}
//--------------------------------------------------------------------------
/**
* Make the router's processMasterAccess function sensitive to our event.
*/
//--------------------------------------------------------------------------
void assignProcessMasterAccessSensitivity(sc_process_b* pMethod)
{
GS_TRACE(name(), "assignProcessMasterAccessSensitivity triggered.");
// register our startMasterAccessProcessing event_queue with the router's processMasterAccess callback
sc_sensitive::make_static_sensitivity(pMethod, startMasterAccessProcessingEvent);
}
//--------------------------------------------------------------------------
/**
* Make the router's processSlaveAccess function sensitive to our event.
*/
//--------------------------------------------------------------------------
void assignProcessSlaveAccessSensitivity(sc_process_b* pMethod)
{
GS_TRACE(name(), "assignProcessMasterSlaveSensitivity triggered.");
// register our startSlaveAccessProcessing event with the router's processMasterAccess callback
sc_sensitive::make_static_sensitivity(pMethod, startSlaveAccessProcessingEvent);
}
//--------------------------------------------------------------------------
/**
* After end of elaboration, scan the init and target ports
* and generate an master to port-num map.
*/
//--------------------------------------------------------------------------
void end_of_elaboration(){
GS_TRACE(name(), "protocol configuration:");
// create the master <=> port-num map
for (unsigned int i=0; i<router_port->getTargetPort()->connected_in_ports.size(); i++) {
GS_TRACE(name(), "At port %d there is the master with id=0x%x",
i, ((unsigned int)(router_port->getTargetPort()->connected_in_ports[i])));
// create (port pointer <=> master number) pairs
m_masterMap[((unsigned int)(router_port->getTargetPort()->connected_in_ports[i]))]=i;
}
// announce the master map to the scheduler
scheduler_port->setMasterMap(&m_masterMap);
}
private:
sc_event_queue startMasterAccessProcessingEvent;
sc_event startSlaveAccessProcessingEvent;
/**
* \brief master <=> port-num map.
* This map is needed by the protocol to identify the master destination port of a slave's reply.
*/
std::map<unsigned int, unsigned int> m_masterMap;
/// clock period duration
sc_time m_clkPeriod;
/// bus state
bool m_idle;
};
#endif
See more files for this project here