Code Search for Developers
 
 
  

ship_slaveport.h from GreenSocs at Krugle


Show ship_slaveport.h syntax highlighted

#ifndef __ship_slaveport_h__
#define __ship_slaveport_h__

#include "ship_serializable_if.h"
#include "ship_datatypes.h"


namespace tlm {



//---------------------------------------------------------------------------
/**
 * This is the SHIP slave port.
 * Use base_addr and high_addr parameter to configure the  address range if
 * connected to a router.
 * Use mode parameter to configure operation mode of this port (default is SHIP_MODE_PV).
 */
//---------------------------------------------------------------------------
template <class T>
class shipSlaveAPI
: public GenericSlavePort,
  public tlm_b_if<GenericTransaction_P>
{     
public:
  typedef GenericSlavePort PORT;
  typedef typename PORT::transaction transaction;
  typedef typename PORT::transactionHandle transactionHandle;
  typedef typename PORT::accessHandle accessHandle;
  typedef typename PORT::phase phase;

  // configurable parameters
  gs_param<gs_uint32> mode;
  gs_param<gs_uint32> clk_period;


  SC_HAS_PROCESS(shipSlaveAPI);


  /**
   * Create a SHIP slave port. Use configuration framework
   * to set address raneg (base_addr, high_addr) and operation mode (mode).
   */
  shipSlaveAPI ( sc_module_name port_name ) : 
    PORT(port_name),    
    mReplyObj(NULL),
    mVector(NULL)
  {
    // DUST structure analysis
#ifdef DUST_ENABLE    
    DUST_SLAVE_PORT("ShipSlaveAPI", "SHIP");
#endif
    
    PORT::bind_b_if(*this); 

    SC_METHOD(react); // this method handles the 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;
    mCmd.burstlength = 0;

    mVector = new std::vector<gs_uint8>();

    GS_PARAM(mode, gs_uint32, SHIP_MODE_PV); // default is PV
    GS_PARAM(clk_period, gs_uint32, 10); // default clock period is 10ns (not used in PV mode)
  }

  
  /// Receive a SHIP object from a master 
  /**
   * The recv method copies the last received
   * SHIP object into a user SHIP object.
   * @param obj A reference to a SHIP object. The received
   *            object will be copied into this object.
   */
  void recv(T& obj) {
    if (mCmd.cmd != SHIP_SEND) {
      SC_REPORT_ERROR(name(), "recv() called, but not in RECV state");
      return;
    }

    if (mObj != NULL) { // PV mode
      // we received a pointer to the master's SHIP object, 
      // so do a direct copy
      obj = *mObj; // mObj has already been set by b_transact
      mTransactEvent.notify(); // notify b_transact
    }

    else { // PVT mode
      GSDataType data;
      data.set(mah->getMData());

      if (data.isPointer()) { // master uses BA performance mode
        obj = *(static_cast<T*>(data.getPointer()));
      }

      else { // received serialized SHIP object
        if (mph.getSimulationMode()==MODE_CT) { // 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 SHIP object from received byte array
      }

      if (mph.getSimulationMode()!=MODE_CT) { 
        mah->setSBurstLength(obj.getSerialLength()); // ack complete reception
        // acknowledge BA data phase after estimated transfer delay
        PORT::AckData(mah, mph, sc_time(clk_period*mah->getMBurstLength()/mah->getSDataWidth(), SC_NS));
        // block this method for the time this data transfer would take in a real system
        sc_core::wait(sc_time(clk_period*mah->getMBurstLength()/mah->getSDataWidth(), SC_NS));
      }
      
    }

    mCmd.cmd = SHIP_NONE; // idle again    

    GS_TRACE(name(), "recv() received a SHIP object.");
  }
  

  ~shipSlaveAPI() {
    if (mVector != NULL)
      delete mVector;
  }


  /**
   * Send data in CT simulation mode to the target.
   */
  inline void sendResponseCT() {
    mCTStartEvent.notify(SC_ZERO_TIME); 
    PORT::Response.block(mah, mph, SC_ZERO_TIME, MODE_CT); // start CT data phase
  }



  /// Send a SHIP object to a master in answer to a request
  /**
   * The reply method sends a SHIP object to a master 
   * in answer to a SHIP request.
   * @param obj The object to send to the master.
   */
  void reply(T& obj) {
    sc_assert(mRequestHandle != NULL);
    mCmd.burstlength = obj.getSerialLength();

    unsigned int objbytes = obj.getSerialLength()*8;

    if (mode == SHIP_MODE_PV) { // PV bypass mode 
      // create local copy of reply data, so that the master can access the data safely until the next request() invocation
      if (mReplyObj != NULL)
        delete mReplyObj;
      mReplyObj = new T(obj);

      mRequestHandle->setSBurstLength(objbytes); 
      GSDataType data;
      data.setPointer(mReplyObj);
      mRequestHandle->setSData(data);
      //GS_TRACE(name(), "reply() set data pointer to local SHIP object in transaction container.");
      mCmd.cmd = SHIP_NONE;
      mTransactEvent.notify(); // notify b_transact      
    }

    else { // PVT transaction
      // map SHIP object onto transaction container
      if (mph.getSimulationMode()==MODE_BA && mode==SHIP_MODE_BA_P) { // BA performance mode
        mah->getSData().setPointer(static_cast<void*>(&obj));
      }
      else { // use serialization
        mVector->empty();
        mah->getSData().setData(*mVector); // TODO: should be mah->setSData(*mVector), but that does a deepcopy, which is not necessary here
        obj.serialize(mah->getSData());
      }
      
      mah->setSBurstLength(objbytes);      
        
      // response phase
      if (mph.getSimulationMode()==MODE_CT) { // CT mode
        GS_TRACE(name(), "reply() sends response with data size %d, using CT simulation mode.", objbytes);
        sendResponseCT();
      }
      else { // BA mode
        GS_TRACE(name(), "reply() sends response with data size %d.", objbytes);
        PORT::Response.block(mah, SC_ZERO_TIME);
      }
      
      mph==PORT::get_phase();
      if (mph.state == GenericPhase::ResponseAccepted) {
        GS_TRACE(name(), "reply() response has been accepted by the master.", objbytes);
      } else {
        char ch[1024];
        sprintf(ch, "Slave response was not acknowledged by the master - got phase=%s (%d) - a severe error occured.", mph.toString().c_str(), mph.state);
        SC_REPORT_ERROR(name(), ch);
      }

      mCmd.cmd = SHIP_NONE;
    }
  }

  
  /// Wait for commands from a master
  /**
   * For each SHIP slave port, a SC_THREAD has to be implemented
   * which handles commands from the SHIP master connected
   * to this slave port. This can be performed by calling the
   * waitEvent method, which does not return unless a SHIP command
   * has been received. 
   * 
   * A typical implementation would look like this:
   * <pre>
   * ship_command comm;
   * while(1) {
   *   comm = slave_port->waitEvent();
   *   switch(comm.cmd) {
   *     case SHIP_SEND:
   *       // receive data using slave_port->recv(...)
   *       break;
   *     case SHIP_REQUEST:
   *       // send data using slave_port->reply(...)
   *       break;
   *     default:
   *       cout << "Unknown ship_command: " << comm.cmd << endl;
   *   }
   * }
   * </pre>
   * 
   * @return The return value is a ship_command-structure.
   * @see ship_command
   */
  ship_command waitEvent() {
    if (mCmd.cmd != SHIP_NONE) // return immediately if we are inside a transaction
      return mCmd;
    else {  
      do {  // wait for something to happen        
        sc_core::wait(mEvent); 
      } while(mCmd.cmd == SHIP_NONE);
      return mCmd;
    }
  }

  
  /**
   * Play the PVT protocol with the master.
   */
  void react() {
    mah = PORT::get_transaction();
    mph = PORT::get_phase();
    PVTProcess();
  }

  void PVTProcess() {
    switch (mph.state) {
    case GenericPhase::RequestValid: // master sends request
      {
        if (mCmd.cmd != SHIP_NONE) {
          SC_REPORT_ERROR(name(), "react() got request, but is already handling another transaction.");
        }
        else {
          PORT::AckRequest(mah, mph, SC_ZERO_TIME, mph.getSimulationMode()); // ack master request and simulation mode
          
          if (mah->getMCmd() == Generic_MCMD_WR) {
            mCmd.cmd = SHIP_SEND;
            mCmd.burstlength = mah->getMBurstLength();
            GS_TRACE(name(), "react() accepted write request, burstlength=%d. Now waiting for master data.", mCmd.burstlength);
            mObj = NULL; // indicate PVT mode transaction
          }
          else if (mah->getMCmd() == Generic_MCMD_RD) {
            GS_TRACE(name(), "react() accepted read request. Now waiting for slave to call reply().");
            mCmd.cmd = SHIP_REQUEST;
            mCmd.burstlength = 0;
            mObj = NULL; // indicate PVT mode transaction
            mEvent.notify();
          }
          else {
            SC_REPORT_WARNING(name(), "react() got unknown request. Ignoring.");
          }
        }
      }
      break;

    case GenericPhase::DataAccepted: // master acknowledges data (should this happen??)
      {
        SC_REPORT_ERROR(name(), "react() got DataAccepted. This should not happen!?");
      }
      break;

    case GenericPhase::DataValid: // master sends data
      {
        GS_TRACE(name(), "react() got DataValid. Now waiting for slave to call recv().");

        // notify waitEvent() method
        mEvent.notify();
      }
      break;


    case GenericPhase::ResponseAccepted: // master acknowledges response
      {
        GS_TRACE(name(), "react() got ResponseAccepted. SHIP transaction was finished OK.");
      }
      break;

    default:
      {
        GS_TRACE(name(), "react() got unknown phase [%s]", mph.toString().c_str());
        SC_REPORT_WARNING(name(), "react() got triggered with unexpected phase. Ignoring.");
      }
    }
  }


  /**
   * Play the CT-protocol with the master.
   * This method is made dynamically sensitive to the quark update event 
   * by the recv() and reply() functions when they run in CT simulation mode. 
   * TODO: here we assume an ideal slave accept delay of 1 cycle per data quark.
   * Note that quark size depends on sDataWidth.
   */
  void ct_react() {
    if (mCmd.cmd == SHIP_SEND) { // we are the receiver
      if (ct_react_wakeup) { 
        ct_react_wakeup=false;
      }
      else {
        mah->notifyInitiatorUpdate(SC_ZERO_TIME); // acknowledge the received quark
        mah->setSBurstLength(mah->getSBurstLength()+mah->getSDataWidth()); // increment number of received bytes
        //GS_TRACE(name(), "ct_react() received data quark %d", (gs_uint32)mah->getSBurstLength());
        if (mah->getSBurstLength()>=mah->getMBurstLength()) { // are we done?
          GS_TRACE(name(), "ct_react() received last data quark. Sending AckData.");
          PORT::AckData(mah, mph, clk_period, SC_NS, MODE_CT);
          mCTFinishEvent.notify();
          return;
        }        
      }
      // wait for next data quark 
      next_trigger(mah->getTargetUpdateEvent());
    }

    else if (mCmd.cmd == SHIP_REQUEST) { // we are the transmitter
      // send next data quark
      if (mCmd.burstlength>mah->getMBurstLength()) {
        mah->notifyInitiatorUpdate(clk_period, SC_NS); // send a data quark with the next rising clock edge
        // wait for target acknowledge
        next_trigger(mah->getTargetUpdateEvent());
      }
      else {
        GS_TRACE(name(), "ct_react() sent last data quark.");
      }
    }
  }


  /**
   * The tlm_b_if PV transaction implementation
   */
  virtual void b_transact(transactionHandle th) {
    sc_assert(mCmd.cmd == SHIP_NONE);

    if (th->getMCmd() == Generic_MCMD_WR) { // master sends data
      mObj = static_cast<T*>(th->getMData().getPointer());      
      mCmd.cmd = SHIP_SEND;
      mCmd.burstlength = mObj->getSerialLength();
      th->setSBurstLength(mCmd.burstlength); // ack burstlength
      
      GS_TRACE(name(), "b_transact() PV-received a SHIP object of size %d. Now waiting for slave to call recv().", (gs_uint32)th->getMBurstLength());

      // notify waitEvent method
      mEvent.notify();

      // wait for finalization of this request by the slave
      sc_core::wait(mTransactEvent);
    }

    else if (th->getMCmd() == Generic_MCMD_RD) { // master requests data
      mCmd.cmd = SHIP_REQUEST;
      mCmd.burstlength = th->getMBurstLength(); // should be 0

      // save transaction container for reply method
      mRequestHandle = th;

      GS_TRACE(name(), "b_transact() PV-received a SHIP request. Now waiting for slave to call request().");

      // notify waitEvent method
      mEvent.notify();

      // wait for finalization of this request by the slave
      sc_core::wait(mTransactEvent);
    }
  }


  void operator() (tlm_port_forwarder_base<b_if_type,if_type>& other) {
    PORT::operator()(other);
  }

  
protected:
  /// The current ship object
  T *mObj, *mReplyObj;
  /// State change event
  sc_event mEvent, mTransactEvent;
  /// The current state
  ship_command mCmd;
  /// Handle to the current transaction
  accessHandle mRequestHandle;
  /// 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

GreenSocs

To develop SystemC infrustructure, basic IP, patches and add on library code for eventual standerdization.\r\nThe GreenSocs project is made up of a number of contributions (sub projects). Please visit www.greensocs.com for more information.

Project homepage: http://sourceforge.net/projects/greensocs
Programming language(s): C,C++,Java,Perl,XML
License: other

  ship_datatypes.h
  ship_masterport.h
  ship_serializable_if.h
  ship_slaveport.h