--- /dev/null
+/**************************************************************************
+ dol_fifo.h
+
+ DOL FIFO channel:
+ relative bloking (RB) and relative non-bloking (RN)
+ task transaction level (TTL) fifo channel
+
+ (c) 2006 by Alexander Maxiaguine <maxiagui@tik.ee.ethz.ch>
+
+ Computer Engineering and Networks Laboratory, TIK
+ Swiss Federal Institute of Technology, ETHZ Zurich
+ Switzerland
+
+**************************************************************************/
+
+/**************************************************************************
+ Change Log:
+
+ 14.03.06 -- creation
+
+**************************************************************************/
+
+#ifndef DOL_FIFO_H
+#define DOL_FIFO_H
+
+#include <typeinfo>
+#include "systemc.h"
+
+#include "dol_rp_ids.h"
+#include "dol_fifo_if.h"
+
+
+template <class T>
+class dol_fifo
+: public dol_fifo_write_if<T>,
+ public dol_fifo_read_if<T>,
+ public sc_prim_channel
+{
+public:
+
+ // constructors
+ explicit dol_fifo( int size ) : sc_prim_channel( sc_gen_unique_name( "dol_fifo" ) )
+ { init( size ); }
+
+ explicit dol_fifo( const char* name, int size) : sc_prim_channel( name)
+ { init( size ); }
+
+ // destructor
+ virtual ~dol_fifo()
+ { delete [] m_buf; }
+
+ virtual void register_port( sc_port_base&, const char* );
+
+ // ********* WRITE interface methods **************
+ // bloking (re)acquire free room in the channel
+ virtual void reAcquireRoom(int count);
+
+ // non-bloking (re)acquire free room in the channel
+ virtual bool tryReAcquireRoom(int count);
+
+ // store data into the acquired free room
+ virtual void store(int offset, T* data, int count);
+
+ // release the stored data to the channel (commit write)
+ virtual void releaseData(int count);
+
+ // ********* READ interface methods **************
+ // bloking (re)acquire data in the channel
+ virtual void reAcquireData(int count);
+
+ // non-bloking (re)acquire data in the channel
+ virtual bool tryReAcquireData(int count);
+
+ // load the acquired data into a vector
+ virtual void load(int offset, T* vector, int count);
+
+ // free up the room in the channel (commit read)
+ virtual void releaseRoom(int count);
+
+
+ // ***************************************
+ // helper methods (for debug, etc.)
+
+ bool in_deadlock() {
+ return reader_is_blocked && writer_is_blocked;
+ }
+
+ void trace( sc_trace_file* tf ) const;
+ virtual void print( ::std::ostream& = ::std::cout ) const;
+ virtual void dump( ::std::ostream& = ::std::cout ) const;
+
+
+ virtual const char* kind() const
+ { return "dol_fifo"; }
+
+
+protected:
+
+ virtual void update();
+ void init( int );
+
+
+protected:
+
+ int m_size; // buffer size
+ T* m_buf; // the buffer
+
+ // channel state variables
+ int m_rwin_head; // index of read window head (oldest full token)
+ int m_wwin_head; // index of write window head (oldest empty token)
+
+ int m_readable; // number of readable tokens (number of full tokens)
+ int m_acquired_room; // size of acquired room (write window)
+ int m_acquired_data; // size of acquired data (read window)
+
+ int m_released_data; // size of data (filled tokens) released during this delta cycle
+ int m_released_room; // size of room (emptied tokens) released during this delta cycle
+
+
+ // SC specific properties
+ sc_event m_data_released_event;
+ sc_event m_room_released_event;
+
+ sc_port_base* m_reader; // used for static design rule checking
+ sc_port_base* m_writer; // used for static design rule checking
+
+ // used to detect deadlocks
+ bool reader_is_blocked;
+ bool writer_is_blocked;
+
+private:
+
+ // disabled
+ dol_fifo( const dol_fifo<T>& );
+ dol_fifo& operator = ( const dol_fifo<T>& );
+};
+
+
+
+
+// ************ Implementation ************************************
+
+// *** WRITE interface methods ****
+
+// blocking (re)acquire free room of size COUNT in the channel
+template <class T>
+inline void dol_fifo<T>::reAcquireRoom( int count )
+{
+ while( m_size - m_readable < count ) {
+ if( m_size < count) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than total available buffer space \n --> This is a deadlock\n\n");
+ }
+
+ writer_is_blocked = true;
+ sc_core::wait( m_room_released_event );
+ writer_is_blocked = false;
+ }
+ m_acquired_room = count;
+}
+
+// non-bloking (re)acquire free room in the channel
+template <class T>
+inline bool dol_fifo<T>::tryReAcquireRoom( int count )
+{
+ if( m_size - m_readable < count ) {
+ if( m_size < count) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than the total available buffer space \n\n");
+ }
+ return false;
+ }
+ m_acquired_room = count;
+ return true;
+}
+
+// write COUNT data into the acquired free room starting from the position indicated by OFFSET
+template <class T>
+inline void dol_fifo<T>::store( int offset, T* data, int count )
+{
+ // sanity checks
+ if( m_acquired_room <= 0) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write without acquiring the room\n --> I ignore this action\n\n");
+ return;
+ }
+ if( offset > m_acquired_room - 1 ) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write beyond the acquired room: offset value may be too large\n --> I ignore this action\n\n");
+ return;
+ }
+ if( count > m_acquired_room - offset ) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write beyound the acquired room: data size may be too large\n --> I'm decreasing the data size\n\n");
+ count = m_acquired_room - offset;
+ }
+
+ int wi = ( m_wwin_head + offset ) % m_size;
+ for(int i=0; i<count; i++ ) {
+ m_buf[wi] = data[i];
+ wi = ( wi + 1 ) % m_size;
+ }
+}
+
+// release COUNT stored data to the channel (commit write)
+template <class T>
+inline void dol_fifo<T>::releaseData( int count )
+{
+ // sanity check
+ if( count > m_acquired_room ) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to release more room than was acquired\n --> I'm decreasing the size of released room\n\n");
+ count = m_acquired_room;
+ }
+
+ m_readable += count;
+ m_released_data += count;
+
+ m_acquired_room -= count;
+ m_wwin_head = ( m_wwin_head + count ) % m_size;
+
+ request_update();
+}
+
+
+// *** READ interface methods ****
+
+// bloking (re)acquire COUNT data in the channel
+template <class T>
+inline void dol_fifo<T>::reAcquireData( int count )
+{
+ while( m_readable < count ) {
+ if( m_size < count) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space\n --> This is a deadlock\n\n");
+ }
+
+ reader_is_blocked = true;
+ sc_core::wait( m_data_released_event );
+ reader_is_blocked = false;
+ }
+
+ m_acquired_data = count;
+}
+
+// non-bloking (re)acquire COUNT data in the channel
+template <class T>
+inline
+bool
+dol_fifo<T>::tryReAcquireData( int count ) {
+ if( m_readable < count ) {
+
+ if( m_size < count) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space \n\n");
+ }
+ return false;
+ }
+
+ m_acquired_data = count;
+ return true;
+}
+
+// load COUNT acquired data into a vector
+// from the read window starting at the position indicated by OFFSET
+template <class T>
+inline void dol_fifo<T>::load( int offset, T* vector, int count )
+{
+ // sanity checks
+ if( m_acquired_data <= 0) {
+
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to load without acquiring the data\n --> I ignore this action\n\n");
+ return;
+ }
+
+ if( offset > m_acquired_data - 1 ) {
+
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to read beyond the acquired data: offset value may be too large\n --> I ignore this action\n\n");
+ return;
+ }
+
+ if( count > m_acquired_data - offset ) {
+
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to read beyound the acquired data: data size may be too large\n --> I'm decreasing the data size\n\n");
+ count = m_acquired_data - offset;
+ }
+
+
+ int ri = ( m_rwin_head + offset ) % m_size;
+
+ for(int i=0; i<count; i++ ) {
+ vector[i] = m_buf[ri];
+ ri = ( ri + 1 ) % m_size;
+ }
+}
+
+// free up COUNT room in the channel (commit read)
+template <class T>
+inline void dol_fifo<T>::releaseRoom( int count )
+{
+ // sanity check
+ if( count > m_acquired_data ) {
+ SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to free up more room than was acquired\n --> I'm decreasing the size of released room\n\n");
+ count = m_acquired_data;
+ }
+
+ m_readable -= count;
+ m_released_room += count;
+
+ m_acquired_data -= count;
+ m_rwin_head = ( m_rwin_head + count ) % m_size;
+
+ request_update();
+}
+
+
+
+
+// *** Other methods ***
+
+
+template <class T>
+inline void dol_fifo<T>::update()
+{
+ if( m_released_room > 0 ) {
+ m_room_released_event.notify_delayed();
+ }
+
+ if( m_released_data > 0 ) {
+ m_data_released_event.notify_delayed();
+ }
+
+ m_released_room = 0;
+ m_released_data = 0;
+}
+
+
+template <class T>
+inline void dol_fifo<T>::init( int size )
+{
+ if( size <= 0 ) {
+ SC_REPORT_ERROR( SC_ID_INVALID_FIFO_SIZE_, 0 );
+ }
+
+ m_size = size;
+ m_buf = new T[m_size];
+
+ m_readable = 0;
+
+ m_acquired_room = 0;
+ m_acquired_data = 0;
+
+ m_rwin_head = 0;
+ m_wwin_head = 0;
+
+ m_released_data = 0;
+ m_released_room = 0;
+
+ m_reader = 0;
+ m_writer = 0;
+
+ reader_is_blocked = false;
+ writer_is_blocked = false;
+}
+
+
+template <class T>
+inline void dol_fifo<T>::register_port( sc_port_base& port_,
+ const char* if_typename_ )
+{
+ std::string nm( if_typename_ );
+ if( nm == typeid( dol_fifo_read_if<T> ).name() ) {
+ // only one reader can be connected
+ if( m_reader != 0 ) {
+ SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_READER_, 0 );
+ }
+ m_reader = &port_;
+ } else { // nm == typeid( dol_fifo_write_if<T> ).name()
+ // only one writer can be connected
+ if( m_writer != 0 ) {
+ SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_WRITER_, 0 );
+ }
+ m_writer = &port_;
+ }
+}
+
+
+
+template <class T>
+inline void dol_fifo<T>::trace( sc_trace_file* tf ) const
+{
+#ifdef DEBUG_SYSTEMC
+ char buf[32];
+ std::string nm = name();
+ for( int i = 0; i < m_size; ++ i ) {
+ sprintf( buf, "_%d", i );
+ sc_trace( tf, m_buf[i], nm + buf );
+ }
+#endif
+}
+
+
+template <class T>
+inline void dol_fifo<T>::print( ::std::ostream& os ) const
+{
+ if( m_readable ) {
+ for(int j=0, i = m_rwin_head; j<m_readable; j++) {
+// os << m_buf[i] << ::std::endl;
+ os << m_buf[i];
+ i = ( i + 1 ) % m_size;
+ }
+ }
+ os << ::std::endl;
+}
+
+template <class T>
+inline void dol_fifo<T>::dump( ::std::ostream& os ) const
+{
+ os << "name = " << name() << ::std::endl;
+ if( m_readable ) {
+ for(int j=0, i = m_rwin_head; j<m_readable; j++) {
+ os << "value[" << j << "] = " << m_buf[i] << ::std::endl;
+ i = ( i + 1 ) % m_size;
+
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+
+template <class T>
+inline ::std::ostream& operator << ( ::std::ostream& os, const dol_fifo<T>& a )
+{
+ a.print( os );
+ return os;
+}
+
+
+#endif