dol: initial dol commit
[jump.git] / dol / src / dol / visitor / systemC / lib / dol_fifo.h
1 /**************************************************************************
2         dol_fifo.h
3  
4         DOL FIFO channel:   
5         relative bloking (RB) and relative non-bloking (RN) 
6         task transaction level (TTL) fifo channel 
7
8         (c) 2006 by Alexander Maxiaguine <maxiagui@tik.ee.ethz.ch>
9
10         Computer Engineering and Networks Laboratory, TIK
11         Swiss Federal Institute of Technology, ETHZ Zurich 
12         Switzerland
13
14 **************************************************************************/
15
16 /**************************************************************************
17         Change Log:
18
19         14.03.06 -- creation
20
21 **************************************************************************/
22
23 #ifndef DOL_FIFO_H
24 #define DOL_FIFO_H
25
26 #include <typeinfo>
27 #include "systemc.h"
28
29 #include "dol_rp_ids.h"
30 #include "dol_fifo_if.h"
31
32
33 template <class T>
34 class dol_fifo
35 : public dol_fifo_write_if<T>,
36   public dol_fifo_read_if<T>,
37   public sc_prim_channel
38 {
39 public:
40
41     // constructors
42     explicit dol_fifo( int size ) : sc_prim_channel( sc_gen_unique_name( "dol_fifo" ) )
43         { init( size ); }
44     
45     explicit dol_fifo( const char* name, int size) : sc_prim_channel( name)
46         { init( size ); }
47
48     // destructor
49     virtual ~dol_fifo()
50         { delete [] m_buf; }
51
52     virtual void register_port( sc_port_base&, const char* );
53
54     // ********* WRITE interface methods **************
55     // bloking (re)acquire free room in the channel
56     virtual void reAcquireRoom(int count);
57     
58     // non-bloking (re)acquire free room in the channel
59     virtual bool tryReAcquireRoom(int count);
60     
61     // store data into the acquired free room
62     virtual void store(int offset, T* data, int count);
63     
64     // release the stored data to the channel (commit write)
65     virtual void releaseData(int count);
66
67     // ********* READ interface methods **************
68     // bloking (re)acquire data in the channel
69     virtual void reAcquireData(int count);
70     
71     // non-bloking (re)acquire data in the channel
72     virtual bool tryReAcquireData(int count);
73     
74     // load the acquired data into a vector
75     virtual void load(int offset, T* vector, int count);
76     
77     // free up the room in the channel (commit read)
78     virtual void releaseRoom(int count);
79     
80     
81     // ***************************************
82     // helper methods (for debug, etc.)
83     
84     bool in_deadlock()  {
85         return reader_is_blocked && writer_is_blocked;
86     }
87     
88     void trace( sc_trace_file* tf ) const;
89     virtual void print( ::std::ostream& = ::std::cout ) const;
90     virtual void dump( ::std::ostream& = ::std::cout ) const;
91     
92     
93     virtual const char* kind() const
94         { return "dol_fifo"; }
95
96     
97 protected:
98     
99     virtual void update();
100     void init( int );
101
102     
103 protected:
104
105     int m_size;                 // buffer size
106     T*  m_buf;                  // the buffer
107
108     // channel state variables
109     int m_rwin_head;     // index of read window head (oldest full token)
110     int m_wwin_head;     // index of write window head (oldest empty token)
111     
112     int m_readable;      // number of readable tokens (number of full tokens)
113     int m_acquired_room; // size of acquired room (write window)
114     int m_acquired_data; // size of acquired data (read window)
115     
116     int m_released_data;  // size of data (filled tokens) released during this delta cycle
117     int m_released_room;  // size of room (emptied tokens) released during this delta cycle
118     
119
120     // SC specific properties
121     sc_event m_data_released_event;
122     sc_event m_room_released_event;
123     
124     sc_port_base* m_reader;     // used for static design rule checking
125     sc_port_base* m_writer;     // used for static design rule checking
126
127     // used to detect deadlocks
128     bool reader_is_blocked;
129     bool writer_is_blocked;
130     
131 private:
132     
133     // disabled
134     dol_fifo( const dol_fifo<T>& );
135     dol_fifo& operator = ( const dol_fifo<T>& );
136 };
137
138
139
140
141 // ************ Implementation ************************************
142
143 // *** WRITE interface methods ****
144
145 // blocking (re)acquire free room of size COUNT in the channel
146 template <class T>
147 inline void dol_fifo<T>::reAcquireRoom( int count )
148 {
149     while( m_size - m_readable < count   ) {
150         if( m_size < count) {
151             SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than total available buffer space \n  --> This is a deadlock\n\n");
152         }
153         
154         writer_is_blocked = true;
155         sc_core::wait( m_room_released_event );
156         writer_is_blocked = false;
157     }
158     m_acquired_room = count;
159 }
160
161 // non-bloking (re)acquire free room in the channel
162 template <class T>
163 inline bool dol_fifo<T>::tryReAcquireRoom( int count )
164 {
165     if( m_size - m_readable < count   ) {
166         if( m_size < count) {
167             SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Requested room is larger than the total available buffer space \n\n");
168         }
169         return false;
170     }
171     m_acquired_room = count;
172     return true;
173 }
174
175 // write COUNT data into the acquired free room starting from the position indicated by OFFSET
176 template <class T>
177 inline void dol_fifo<T>::store( int offset, T* data, int count )
178 {
179     // sanity checks
180     if( m_acquired_room <= 0) {
181         SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to write without acquiring the room\n  --> I ignore this action\n\n");
182         return;
183     }
184     if( offset >  m_acquired_room - 1 ) {
185         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");
186         return;
187     }
188     if( count >  m_acquired_room - offset ) {
189         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");
190         count =  m_acquired_room - offset;
191     }
192     
193     int wi = ( m_wwin_head + offset ) % m_size;
194     for(int i=0; i<count; i++ ) {
195         m_buf[wi] = data[i];
196         wi = ( wi + 1 ) % m_size;
197     }
198 }
199
200 // release COUNT stored data to the channel (commit write)
201 template <class T>
202 inline void dol_fifo<T>::releaseData( int count )
203 {
204     // sanity check
205     if( count > m_acquired_room ) {
206         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");
207         count = m_acquired_room;
208     }
209         
210     m_readable += count;
211     m_released_data += count;
212     
213     m_acquired_room -= count;
214     m_wwin_head = ( m_wwin_head + count ) % m_size;
215
216     request_update();
217 }
218
219
220 // *** READ interface methods ****
221
222 // bloking (re)acquire COUNT data in the channel
223 template <class T>
224 inline void dol_fifo<T>::reAcquireData( int count )
225 {
226     while( m_readable < count  ) {
227         if( m_size < count) {
228             SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space\n  --> This is a deadlock\n\n");
229         }
230         
231         reader_is_blocked = true;
232         sc_core::wait( m_data_released_event );
233         reader_is_blocked = false;
234     }
235     
236     m_acquired_data = count;
237 }
238
239 // non-bloking (re)acquire COUNT data in the channel
240 template <class T>
241 inline
242 bool
243 dol_fifo<T>::tryReAcquireData( int count ) {
244     if( m_readable < count  ) {
245         
246         if( m_size < count) {
247             SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Acquired data size is larger than total available buffer space \n\n");
248         }
249         return false;
250     }
251
252     m_acquired_data = count;
253     return true;
254 }
255
256 // load COUNT acquired data into a vector
257 // from the read window starting at the position indicated by OFFSET
258 template <class T>
259 inline void dol_fifo<T>::load( int offset, T* vector, int count )
260 {
261     // sanity checks
262     if( m_acquired_data <= 0) {
263         
264         SC_REPORT_WARNING(RP_ID_PARAMETER_PROBLEM, "Attempt to load without acquiring the data\n  --> I ignore this action\n\n");
265         return;
266     }
267     
268     if( offset >  m_acquired_data - 1 ) {
269         
270         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");
271         return;
272     }
273     
274     if( count >  m_acquired_data - offset ) {
275         
276         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");
277         count =  m_acquired_data - offset;
278         }
279     
280     
281     int ri = ( m_rwin_head + offset ) % m_size;
282     
283     for(int i=0; i<count; i++ ) {
284         vector[i] = m_buf[ri];
285         ri = ( ri + 1 ) % m_size;
286     }
287 }
288
289 // free up COUNT room in the channel (commit read)
290 template <class T>
291 inline void dol_fifo<T>::releaseRoom( int count ) 
292 {
293     // sanity check
294     if( count > m_acquired_data ) {
295         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");
296         count = m_acquired_data;
297     }
298         
299     m_readable -= count;
300     m_released_room += count;
301     
302     m_acquired_data -= count;
303     m_rwin_head = ( m_rwin_head + count ) % m_size;
304
305     request_update();
306 }
307
308
309
310
311 // *** Other methods *** 
312
313
314 template <class T>
315 inline void dol_fifo<T>::update()
316 {
317     if( m_released_room > 0 ) {
318         m_room_released_event.notify_delayed();
319     }
320     
321     if( m_released_data > 0 ) {
322         m_data_released_event.notify_delayed();
323     }
324
325     m_released_room = 0;
326     m_released_data = 0;
327 }
328
329
330 template <class T>
331 inline void dol_fifo<T>::init( int size )
332 {
333     if( size <= 0 ) {
334         SC_REPORT_ERROR( SC_ID_INVALID_FIFO_SIZE_, 0 );
335     }
336
337     m_size = size;
338     m_buf = new T[m_size];
339
340     m_readable = 0;
341         
342     m_acquired_room = 0;
343     m_acquired_data = 0;
344     
345     m_rwin_head = 0;
346     m_wwin_head = 0;
347     
348     m_released_data = 0;
349     m_released_room = 0;
350
351     m_reader = 0;
352     m_writer = 0;
353
354     reader_is_blocked = false;
355     writer_is_blocked = false;
356 }
357
358
359 template <class T>
360 inline void dol_fifo<T>::register_port( sc_port_base& port_,
361                                         const char* if_typename_ )
362 {
363     std::string nm( if_typename_ );
364     if( nm == typeid( dol_fifo_read_if<T> ).name() ) {
365         // only one reader can be connected
366         if( m_reader != 0 ) {
367             SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_READER_, 0 );
368         }
369         m_reader = &port_;
370     } else {  // nm == typeid( dol_fifo_write_if<T> ).name()
371         // only one writer can be connected
372         if( m_writer != 0 ) {
373             SC_REPORT_ERROR( SC_ID_MORE_THAN_ONE_FIFO_WRITER_, 0 );
374         }
375         m_writer = &port_;
376     }
377 }
378
379
380
381 template <class T>
382 inline void dol_fifo<T>::trace( sc_trace_file* tf ) const
383 {
384 #ifdef DEBUG_SYSTEMC
385     char buf[32];
386     std::string nm = name();
387     for( int i = 0; i < m_size; ++ i ) {
388         sprintf( buf, "_%d", i );
389         sc_trace( tf, m_buf[i], nm + buf );
390     }
391 #endif
392 }
393
394
395 template <class T>
396 inline void dol_fifo<T>::print( ::std::ostream& os ) const
397 {
398     if( m_readable ) {
399         for(int j=0, i = m_rwin_head; j<m_readable; j++) {
400 //            os << m_buf[i] << ::std::endl;
401             os << m_buf[i];
402             i = ( i + 1 ) % m_size;
403         }
404     }
405     os << ::std::endl;
406 }
407
408 template <class T>
409 inline void dol_fifo<T>::dump( ::std::ostream& os ) const
410 {
411     os << "name = " << name() << ::std::endl;
412     if( m_readable ) {
413         for(int j=0, i = m_rwin_head; j<m_readable; j++) {
414             os << "value[" << j << "] = " << m_buf[i] << ::std::endl;
415             i = ( i + 1 ) % m_size;
416             
417         }
418     }
419 }
420
421
422 // ----------------------------------------------------------------------------
423
424 template <class T>
425 inline ::std::ostream& operator << ( ::std::ostream& os, const dol_fifo<T>& a )
426 {
427     a.print( os );
428     return os;
429 }
430
431
432 #endif