dol: initial dol commit
[jump.git] / dol / src / dol / visitor / systemC / lib / dol_fifo.h
diff --git a/dol/src/dol/visitor/systemC/lib/dol_fifo.h b/dol/src/dol/visitor/systemC/lib/dol_fifo.h
new file mode 100644 (file)
index 0000000..5646682
--- /dev/null
@@ -0,0 +1,432 @@
+/**************************************************************************
+       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