Show ship_masterport.h syntax highlighted
#ifndef __ship_masterport_h__
#define __ship_masterport_h__
#include "ship_serializable_if.h"
#include "ship_datatypes.h"
namespace tlm {
//---------------------------------------------------------------------------
/**
* This is the SHIP master port.
* Use target_addr parameter to configure the target address if
* connected to a router.
* Use mode parameter to configure operation mode of this SHIP port.
*/
//---------------------------------------------------------------------------
template <class T>
class shipMasterAPI
: public GenericMasterPort
{
public:
typedef GenericMasterPort PORT;
typedef typename PORT::transaction transaction;
typedef typename PORT::transactionHandle transactionHandle;
typedef typename PORT::accessHandle accessHandle;
typedef typename PORT::phase phase;
/// the operation mode of this SHIP port
gs_param<gs_uint32> mode;
/// the clock period of this SHIP port
gs_param<gs_uint32> clk_period;
SC_HAS_PROCESS(shipMasterAPI);
/**
* Create a SHIP master port. Use configuration framework
* to set parameters target_addr and mode.
*/
shipMasterAPI ( sc_module_name port_name )
: PORT(port_name),
mVector(NULL)
{
// DUST structure analysis
#ifdef DUST_ENABLE
DUST_MASTER_PORT("ShipMasterAPI", "SHIP");
#endif
SC_METHOD(react); // handle PVT protocol
sensitive << PORT::default_event();
dont_initialize();
SC_METHOD(ct_react); // this method handles CT quark update events
sensitive << mCTStartEvent;
dont_initialize();
mCmd.cmd = SHIP_NONE;
mVector = new std::vector<gs_uint8>();
GS_PARAM(mode, gs_uint32, SHIP_MODE_PV); // default mode is PV
GS_PARAM(clk_period, gs_uint32, 10); // default clock period is 10ns (not used in PV mode)
}
/// Send a SHIP object to a slave
/**
* The send method sends a SHIP object to a SHIP slave.
* Communication using this method is blocking, thus
* it will not return until the SHIP object has been
* completely delivered to the slave.
*
* @param obj The object to be send.
*/
void send( T& obj ) {
mah = PORT::create_transaction();
mVector->empty();
GSDataType data;
data.setData(*mVector);
unsigned int objbytes = obj.getSerialLength();
mCmd.cmd = SHIP_SEND;
mCmd.burstlength = objbytes;
mah->setMAddr(target_addr);
mah->setMBurstLength(objbytes);
mah->setMCmd(Generic_MCMD_WR);
if (mode==SHIP_MODE_PV) { // PV bypass mode
data.setPointer(static_cast<void*>(&obj));
mah->setMData(data); // pass SHIP object by pointer
GS_TRACE(name(), "send() calls PV Transact.");
PORT::Transact(mah);
mCmd.cmd = SHIP_NONE;
}
else { // PVT mode
// fill transaction container with transaction data
if (mode==SHIP_MODE_BA_P) { // BA performance mode
data.setPointer(static_cast<void*>(&obj));
mah->setMData(data); // pass SHIP object by pointer
}
else { // BA or CT mode
obj.serialize(data); // serialize SHIP object
mah->setMData(data); // pass SHIP object by value
}
// request phase
bool success=false;
while(!success) {
if (mode==SHIP_MODE_CT) {
GS_TRACE(name(), "send() starts write request with burstlength=%d, running in CT simulation mode.", objbytes);
PORT::Request.block(mah, SC_ZERO_TIME, MODE_CT);
}
else {
GS_TRACE(name(), "send() starts write request with burstlength=%d.", objbytes);
PORT::Request.block(mah, SC_ZERO_TIME);
}
mph = PORT::get_phase();
if (mph.state == GenericPhase::RequestAccepted) {
if (mph.getSimulationMode()==MODE_CT) {
GS_TRACE(name(), "send() write request has been accepted by the slave, running in CT simulation mode.");
}
else {
GS_TRACE(name(), "send() write request has been accepted by the slave.");
}
success = true;
} else {
char ch[1024];
sprintf(ch, "A write request was not acknowledged by the slave - got phase=%s (%d) - maybe a timeout occured. Sending request again.", mph.toString().c_str(), mph.state);
SC_REPORT_WARNING(name(), ch);
}
}
// data phase
if (mode==SHIP_MODE_CT) { // CT mode
sendDataCT();
}
else { // BA mode
PORT::SendData.block(mah, mph, SC_ZERO_TIME); // atomic BA data phase
}
mph = PORT::get_phase();
if (mph.state == GenericPhase::DataAccepted) {
GS_TRACE(name(), "send() write data has been accepted by the slave.");
} else {
char ch[1024];
sprintf(ch, "Master data was not acknowledged by the slave - got phase=%s (%d) - a severe error occured.", mph.toString().c_str(), mph.state);
SC_REPORT_ERROR(name(), ch);
}
mCmd.cmd = SHIP_NONE;
}
}
~shipMasterAPI() {
if (mVector != NULL)
delete mVector;
}
/// Request a SHIP object from a slave
/**
* The request method requests a SHIP object from a SHIP slave.
* Communication using this method is blocking, thus the request
* method will not return unless the SHIP object
* has been completely received.
* @param obj A reference to an SHIP object, into which
* the requested data will be copied.
*/
void request( T& obj ) {
sc_assert(mCmd.cmd == SHIP_NONE);
accessHandle mah = PORT::create_transaction();
mah->setMCmd(Generic_MCMD_RD);
mah->setMAddr(target_addr);
mCmd.cmd = SHIP_REQUEST;
mCmd.burstlength = 0;
if (mode==SHIP_MODE_PV) { // PV bypass mode
GS_TRACE(name(), "request() calls PV b_transact.");
PORT::Transact(mah);
// now lets look what we have received
GSDataType data;
data.set(mah->getMData());
sc_assert(data.isPointer());
T *robj = static_cast<T*>(data.getPointer());
obj = *robj; // copy received SHIP object to master
}
else { // PVT modes
bool success=false;
while(!success) {
if (mode==SHIP_MODE_CT) {
GS_TRACE(name(), "request() starts request phase, running in CT simulation mode.");
PORT::Request.block(mah, SC_ZERO_TIME, MODE_CT);
}
else {
GS_TRACE(name(), "request() starts request phase.");
PORT::Request.block(mah, SC_ZERO_TIME);
}
mph = PORT::get_phase();
if (mph.state == GenericPhase::RequestAccepted) {
mCmd.burstlength = mah->getSBurstLength();
if (mph.getSimulationMode()==MODE_CT) {
GS_TRACE(name(), "request() read request has been accepted by the slave, burstlength=%d, running in CT simulation mode.", mCmd.burstlength);
}
else {
GS_TRACE(name(), "request() read request has been accepted by the slave, burstlength=%d.", mCmd.burstlength);
}
success = true;
} else {
char ch[1024];
sprintf(ch, "A read request was not acknowledged by the slave - got phase=%s (%d) - maybe a timeout occured. Sending request again.", mph.toString().c_str(), mph.state);
SC_REPORT_WARNING(name(), ch);
}
}
// now wait for slave response (will be received by react method)
sc_core::wait(mResponseEvent);
// check the received data
GSDataType data;
data.set(mah->getMData());
if (data.isPointer()) { // slave uses BA performance mode and sent just a pointer
T *robj = static_cast<T*>(data.getPointer());
obj = *robj; // copy received SHIP object to master
mah->setMBurstLength(obj.getSerialLength()); // ack complete reception
}
// TODO: we assume here that we can accept one data quark per clock cycle
else { // slave sent a serialized SHIP object
if ((mph.getSimulationMode() == MODE_CT)) { // slave responses in CT mode
// notify ct_react method of that there is some work for it now
ct_react_wakeup = true;
mCTStartEvent.notify();
sc_core::wait(mCTFinishEvent); // wait for CT simulation to finish
}
obj.deserialize(data); // deserialize received data
}
if (data.isPointer() || mph.getSimulationMode()!=MODE_CT) { // BA atomic ack
mah->setMBurstLength(mah->getSBurstLength()); // ack all data quarks at once
PORT::AckResponse(mah, mph, sc_time(clk_period*mah->getSBurstLength()/mah->getSDataWidth(), SC_NS));
// block request method for the transfer delay
sc_core::wait(sc_time(clk_period*mah->getSBurstLength()/mah->getSDataWidth(), SC_NS));
}
GS_TRACE(name(), "request() received slave response OK.");
}
mCmd.cmd = SHIP_NONE;
}
/// Wrapper for bind operator
void operator() (tlm_port<b_if_type,if_type>& other) {
PORT::operator()(other);
}
/// Wrapper for bind operator
void operator() (tlm_multi_port<b_if_type,if_type>& other) {
PORT::operator()(other);
}
void operator() (tlm_port_forwarder_base<b_if_type,if_type>& other) {
PORT::operator()(other);
}
protected:
/**
* Play the PVT protocol with the slave
*/
void react() {
mah = PORT::get_transaction();
mph = PORT::get_phase();
PVTProcess();
}
void PVTProcess() {
switch (mph.state) {
case GenericPhase::ResponseValid: // slave sends response
{
mCmd.burstlength = mah->getSBurstLength();
GS_TRACE(name(), "react() received slave response (a SHIP object of %d bytes).", (gs_uint32)mah->getSBurstLength());
// notify request() method
mResponseEvent.notify();
}
break;
default:
break; // do nothing
}
}
/**
* Send data in CT simulation mode to the target.
*/
inline void sendDataCT() {
GS_TRACE(name(), "sendDataCT() starting data phase.");
mCTStartEvent.notify(SC_ZERO_TIME);
PORT::SendData.block(mah, mph, SC_ZERO_TIME, MODE_CT); // start CT data phase
}
/**
* Play the CT-protocol with the slave.
* This method is made dynamically sensitive to the quark update event
* by the send() and request() functions when they run in CT simulation mode.
*/
void ct_react() {
if (mCmd.cmd == SHIP_SEND) { // we are the transmitter
// send next data quark
if (mCmd.burstlength>mah->getSBurstLength()) {
mah->notifyTargetUpdate(clk_period, SC_NS); // send a data quark with the next rising clock edge
// wait for target acknowledge
next_trigger(mah->getInitiatorUpdateEvent());
}
else {
GS_TRACE(name(), "ct_react() sent last data quark.");
}
}
else if (mCmd.cmd == SHIP_REQUEST) { // we are the receiver
if (ct_react_wakeup) {
ct_react_wakeup=false;
}
else {
mah->notifyTargetUpdate(SC_ZERO_TIME); // acknowledge the received quark
mah->setMBurstLength(mah->getMBurstLength()+mah->getMDataWidth()); // increment number of received bytes
//GS_TRACE(name(), "ct_react() received data quark %d", (gs_uint32)mah->getMBurstLength());
if (mah->getSBurstLength()<=mah->getMBurstLength()) { // are we done?
GS_TRACE(name(), "ct_react() received last data quark. Sending AckResponse.");
PORT::AckResponse(mah, mph, clk_period, SC_NS, MODE_CT);
mCTFinishEvent.notify();
return;
}
}
// wait for next data quark
next_trigger(mah->getInitiatorUpdateEvent());
}
}
protected:
/// The current SHIP command
ship_command mCmd;
/// Internal notification
sc_event mResponseEvent;
/// Serialization buffer
std::vector<gs_uint8> *mVector;
/// Internal events for CT simulation
sc_event mCTStartEvent, mCTFinishEvent;
/// Wake-up indicator for ct_react method
bool ct_react_wakeup;
/// The current transcation container
accessHandle mah;
/// The current phase
phase mph;
};
} // namespace tlm
#endif
See more files for this project here