Andy Tomlin Posted March 20, 2023 Report Posted March 20, 2023 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 > >; Quote
David Black Posted March 20, 2023 Report Posted March 20, 2023 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. Quote
Andy Tomlin Posted March 21, 2023 Author Report Posted March 21, 2023 @David Black Thanks. I'll experiment with the options and fix the naming. I'll respond with how it goes. Quote
Recommended Posts
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.