1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#ifndef __TLM_FIFO_H__
21#define __TLM_FIFO_H__
22
23//
24// This implements put, get and peek
25//
26// It also implements 0 and infinite size fifos - but the size
27// zero fifos aren't rendezvous like zero length fifos, they simply are both
28// full and empty at the same time.
29//
30// The size can be dynamically changed using the resize interface
31//
32// To get an infinite fifo use a -ve size in the constructor.
33// The absolute value of the size is taken as the starting size of the
34// actual physical buffer.
35//
36
37//#include <systemc>
38
39#include "tlm_core/tlm_1/tlm_req_rsp/tlm_1_interfaces/tlm_fifo_ifs.h"
40#include "tlm_core/tlm_1/tlm_req_rsp/tlm_channels/tlm_fifo/circular_buffer.h"
41
42namespace tlm {
43
44template <typename T>
45class tlm_fifo :
46  public virtual tlm_fifo_get_if<T>,
47  public virtual tlm_fifo_put_if<T>,
48  public sc_core::sc_prim_channel
49{
50public:
51
52    // constructors
53
54    explicit tlm_fifo( int size_ = 1 )
55      : sc_core::sc_prim_channel( sc_core::sc_gen_unique_name( "fifo" ) ) {
56
57      init( size_ );
58
59    }
60
61    explicit tlm_fifo( const char* name_, int size_ = 1 )
62      : sc_core::sc_prim_channel( name_ ) {
63
64      init( size_ );
65
66    }
67
68    // destructor
69
70    virtual ~tlm_fifo() {}
71
72    // tlm get interface
73
74    T get( tlm_tag<T> * = 0 );
75
76    bool nb_get( T& );
77    bool nb_can_get( tlm_tag<T> * = 0 ) const;
78    const sc_core::sc_event &ok_to_get( tlm_tag<T> * = 0 ) const {
79      return m_data_written_event;
80    }
81
82    // tlm peek interface
83
84    T peek( tlm_tag<T> * = 0 ) const;
85
86    bool nb_peek( T& ) const;
87    bool nb_can_peek( tlm_tag<T> * = 0 ) const;
88    const sc_core::sc_event &ok_to_peek( tlm_tag<T> * = 0 ) const {
89      return m_data_written_event;
90    }
91
92    // tlm put interface
93
94    void put( const T& );
95
96    bool nb_put( const T& );
97    bool nb_can_put( tlm_tag<T> * = 0 ) const;
98
99    const sc_core::sc_event& ok_to_put( tlm_tag<T> * = 0 ) const {
100      return m_data_read_event;
101    }
102
103    // resize if
104
105    void nb_expand( unsigned int n = 1 );
106    void nb_unbound( unsigned int n = 16 );
107
108    bool nb_reduce( unsigned int n = 1 );
109    bool nb_bound( unsigned int n );
110
111    // debug interface
112
113    bool nb_peek( T & , int n ) const;
114    bool nb_poke( const T & , int n = 0 );
115
116    int used() const {
117      return m_num_readable - m_num_read;
118    }
119
120    int size() const {
121      return m_size;
122    }
123
124    void debug() const {
125
126      if( is_empty() ) std::cout << "empty" << std::endl;
127      if( is_full() ) std::cout << "full" << std::endl;
128
129      std::cout << "size " << size() << " - " << used() << " used "
130                << std::endl;
131      std::cout << "readable " << m_num_readable
132                << std::endl;
133      std::cout << "written/read " << m_num_written << "/" << m_num_read
134                << std::endl;
135
136    }
137
138    // support functions
139
140    static const char* const kind_string;
141
142    const char* kind() const
143        { return kind_string; }
144
145
146protected:
147    sc_core::sc_event &read_event( tlm_tag<T> * = 0 ) {
148      return m_data_read_event;
149    }
150
151protected:
152
153    void update();
154
155    // support methods
156
157    void init( int );
158
159protected:
160
161    circular_buffer<T> buffer;
162
163    int m_size;                  // logical size of fifo
164
165    int m_num_readable;          // #samples readable
166    int m_num_read;          // #samples read during this delta cycle
167    int m_num_written;           // #samples written during this delta cycle
168    bool m_expand;               // has an expand occurred during this delta cycle ?
169    int m_num_read_no_notify;    // #samples read without notify during this delta cycle
170
171    sc_core::sc_event m_data_read_event;
172    sc_core::sc_event m_data_written_event;
173
174private:
175
176    // disabled
177    tlm_fifo( const tlm_fifo<T>& );
178    tlm_fifo& operator = ( const tlm_fifo<T>& );
179
180    //
181    // use nb_can_get() and nb_can_put() rather than the following two
182    // private functions
183    //
184
185    bool is_empty() const {
186      return used() == 0;
187    }
188
189    bool is_full() const {
190      //return size() == m_num_readable + m_num_written; // Old buggy code
191      if( size() < 0 )
192        return false;
193      else
194        return size() <= m_num_readable + m_num_written;
195    }
196
197};
198
199template <typename T>
200const char* const tlm_fifo<T>::kind_string = "tlm_fifo";
201
202
203/******************************************************************
204//
205// init and update
206//
207******************************************************************/
208
209template< typename T >
210inline
211void
212tlm_fifo<T>::init( int size_ ) {
213
214  if( size_ > 0 ) {
215    buffer.resize( size_ );
216  }
217
218  else if( size_ < 0 ) {
219    buffer.resize( -size_ );
220  }
221
222  else {
223    buffer.resize( 16 );
224  }
225
226  m_size = size_;
227  m_num_readable = 0;
228  m_num_read = 0;
229  m_num_written = 0;
230  m_expand = false;
231  m_num_read_no_notify = false;
232
233}
234
235template < typename T>
236inline
237void
238tlm_fifo<T>::update()
239{
240    if( m_num_read > m_num_read_no_notify || m_expand ) {
241  m_data_read_event.notify( sc_core::SC_ZERO_TIME );
242    }
243
244    if( m_num_written > 0 ) {
245  m_data_written_event.notify( sc_core::SC_ZERO_TIME );
246    }
247
248    m_expand = false;
249    m_num_read = 0;
250    m_num_written = 0;
251    m_num_readable = buffer.used();
252    m_num_read_no_notify = 0;
253
254}
255
256} // namespace tlm
257
258#include "tlm_core/tlm_1/tlm_req_rsp/tlm_channels/tlm_fifo/tlm_fifo_put_get.h"
259#include "tlm_core/tlm_1/tlm_req_rsp/tlm_channels/tlm_fifo/tlm_fifo_peek.h"
260#include "tlm_core/tlm_1/tlm_req_rsp/tlm_channels/tlm_fifo/tlm_fifo_resize.h"
261
262#endif
263
264