Jump to content

Creating Ready Valid Channel


Andy Tomlin

Recommended Posts

I'm trying to create a custom channel and am getting unexpected result. I started with the sc_fifo code and modified from that. The expectation is that ready/valid is a blocking protocol.

The reader enters the read function sets m_ready and execute the wait(m_channel_event)

The writer enters, sets m_valid and issue the request_update()

I was expecting that the call to request_update() would result in the other process being scheduled, however the writer continues through and can loop around overwriting the channel data. As the reader never ran, he never got the opportunity to deassert ready to slow down the writer.

Would appreciate some advice on correct way to handle.

I have removed some unnecessary items for brevity

template <class T>
class sc_rvbase
: public sc_rvbase_in_if<T>,
  public sc_rvbase_out_if<T>,
  public sc_prim_channel
{
public:
    // constructors
    explicit sc_rvbase( const char* name_)
      : sc_prim_channel( name_ ),
        m_channel_event( "channel_event" )
       { init( ); }

    // destructor
    virtual ~sc_rvbase() { }

    // interface methods
    virtual void register_port( sc_port_base&, const char* );

    // blocking read
    virtual void read( T& );
    virtual T read();

    // non-blocking read
    virtual bool nb_read( T& );

    // does the writer have data
    virtual bool is_valid() const
	{ return ( m_valid ); }

    // get the data written event (note for this interface the read and write events are the same)
    virtual const sc_event& data_written_event() const
	{ return m_channel_event; }

    // blocking write
    virtual void write( const T& );

    // non-blocking write
    virtual bool nb_write( const T& );

    // is the reader ready
    virtual bool is_ready() const
	{ return ( m_ready ); }

    // get the data read event (note for this interface the read and write events are the same)
    virtual const sc_event& data_read_event() const
	{ return m_channel_event; }

    // other methods
    operator T ()
	{ return read(); }

    sc_rvbase<T>& operator = ( const T& a )
        { write( a ); return *this; }

protected:
    virtual void update();
    // support methods
    void init( void );

    T    m_value;			// the data

    sc_port_base* m_reader;	// used for static design rule checking
    sc_port_base* m_writer;	// used for static design rule checking

    bool m_valid;   // can we read the value
    bool m_ready;		   // can we write the value

    sc_event m_channel_event;

private:

    // disabled
    sc_rvbase( const sc_rvbase<T>& );
    sc_rvbase& operator = ( const sc_rvbase<T>& );
};

// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

// blocking read
template <class T>
inline
void
sc_rvbase<T>::read( T& val_ )
{
    m_ready = true;
    if( is_valid() == false ) {
	    sc_core::wait( data_written_event() );
    } else {
        request_update();
    }
    val_ = m_value;
    m_ready = false;
}

template <class T>
inline
T
sc_rvbase<T>::read()
{
    T tmp;
    read( tmp );
    return tmp;
}

// non-blocking read
template <class T>
inline
bool
sc_rvbase<T>::nb_read( T& val_ )
{
    if( is_valid() == false ) {
	    return false;
    }
    m_ready = true;
    val_ = m_value;
    request_update();
    m_ready = false;
    return true;
}

// blocking write
template <class T>
inline
void
sc_rvbase<T>::write( const T& val_ )
{
    m_value = val_ ;
    m_valid = true;
    if( is_ready() == false ) {
	    sc_core::wait( data_read_event() );
    } else {
        request_update();        
    }
    m_valid = false;
}

// non-blocking write
template <class T>
inline
bool
sc_rvbase<T>::nb_write( const T& val_ )
{
    if( is_ready() == false ) {
	    return false;
    }
    m_value = val_ ;
    m_valid = true;
    request_update();
    m_valid = false;

    return true;
}

// override of virtual primative update, this is called by kernel
template <class T>
inline
void
sc_rvbase<T>::update()
{
    if( m_valid || m_ready ) {
	    m_channel_event.notify(SC_ZERO_TIME);
    }
}

// support methods
template <class T>
inline
void
sc_rvbase<T>::init( )
{
    m_reader = 0;
    m_writer = 0;

    m_valid = false;
    m_ready = false;
}


} // namespace sc_core

template <class T>
using sc_rv_out = sc_port<sc_rvbase_blocking_out_if< T > >;
template <class T>
using sc_rv_in = sc_port<sc_rvbase_blocking_in_if< T > >;

 

Link to comment
Share on other sites

request_update() is a non-blocking call. It simply registers a request to have your primitive channel's update() called at the end of the delta cycle. So, your code sets m_valid true, makes a request and immediately overwrites m_valid with false. You need to have a wait() statement in the write after the request. You would wait on an event or perhaps even just wait(SC_ZERO_TIME).

Observation: Please don't use the sc_ prefix for your identifiers. sc_ should be reserved for things that go in the SystemC library.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...