TLM-2.0  2.0.4
Accellera TLM-2.0 proof-of-concept library
peq_with_cb_and_phase.h
Go to the documentation of this file.
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 // 12-Jan-2009 John Aynsley Bug fix. Phase argument to notify should be const
21 // 20-Mar-2009 John Aynsley Add cancel_all() method
22 
23 
24 #ifndef __PEQ_WITH_CB_AND_PHASE_H__
25 #define __PEQ_WITH_CB_AND_PHASE_H__
26 
27 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn
28 # define SC_INCLUDE_DYNAMIC_PROCESSES
29 #endif
30 
31 #include <vector>
32 #include <systemc>
33 #include <tlm>
34 
35 namespace tlm_utils {
36 
37 template <typename PAYLOAD>
39 {
40 public:
41  struct element
42  {
43  struct element *next;
44  PAYLOAD p;
47  element(PAYLOAD& p, sc_core::sc_time t, sc_dt::uint64 d): p(p),t(t),d(d) {}
48  element(){}
49  };
50 
54  unsigned int size;
55 
57  : nill(new element()),
58  empties(NULL),
59  list(nill),
60  size(0)
61  {
62  }
63 
65  reset();
66  while(empties){
67  struct element *e=empties->next;
68  delete empties;
69  empties=e;
70  }
71  delete nill;
72  }
73 
74  void reset() {
75  while(size) {
76  delete_top();
77  }
78  }
79 
80  void insert(const PAYLOAD& p, sc_core::sc_time t) {
81  if (!empties) {
82  empties=new struct element();
83  empties->next=NULL;
84  }
85 
86  struct element *e=empties;
87  empties=empties->next;
88  e->p=p;
89  e->t=t;
91 
92  struct element * ancestor=nill;
93  struct element * iterator=list;
94  while (iterator!=nill && iterator->t<=t){
95  ancestor=iterator;
96  iterator=iterator->next;
97  }
98  if (ancestor==nill){
99  e->next=list;
100  list=e;
101  }
102  else {
103  e->next=iterator;
104  ancestor->next=e;
105  }
106  size++;
107  }
108 
109  void delete_top(){
110  if (list != nill) {
111  struct element *e=list;
112  list=list->next;
113  e->next=empties;
114  empties=e;
115  size--;
116  }
117  }
118 
119  unsigned int get_size()
120  {
121  return size;
122  }
123 
124  PAYLOAD &top()
125  {
126  return list->p;
127  }
129  {
130  return list->t;
131  }
132 
134  {
135  return list->d;
136  }
137 
139  {
140  return list->next->t;
141  }
142 };
143 
144 //---------------------------------------------------------------------------
149 //---------------------------------------------------------------------------
150 template<typename OWNER,typename TYPES=tlm::tlm_base_protocol_types>
152  public sc_core::sc_object
153 {
154 
155  typedef typename TYPES::tlm_payload_type tlm_payload_type;
156  typedef typename TYPES::tlm_phase_type tlm_phase_type;
157  typedef std::pair<tlm_payload_type*, tlm_phase_type> PAYLOAD;
158  typedef void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&);
159 
160  class delta_list{
161  public:
162  delta_list(){
163  reset();
164  entries.resize(100);
165  }
166 
167  inline void insert(const PAYLOAD& p){
168  if (size==entries.size()){
169  entries.resize(entries.size()*2);
170  }
171  entries[size++]=p;
172  }
173 
174  inline PAYLOAD& get(){
175  return entries[out++];
176  }
177 
178  inline bool next(){
179  return out<size;
180  }
181 
182  inline void reset(){
183  size=0;
184  out=0;
185  }
186  public:
187  unsigned int size;
188  private:
189  std::vector<PAYLOAD> entries;
190  unsigned int out;
191  };
192 
193 public:
194 
195  peq_with_cb_and_phase(OWNER* _owner, cb _cb)
196  :sc_core::sc_object( sc_core::sc_gen_unique_name( "peq_with_cb_and_phase" ) )
197  ,m_owner(_owner)
198  ,m_cb(_cb)
199  {
201  opts.spawn_method();
202  opts.set_sensitivity(&m_e);
203  opts.dont_initialize();
204  sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
205  sc_core::sc_gen_unique_name("fec"), &opts);
206  }
207 
208  peq_with_cb_and_phase(const char* _name, OWNER* _owner,cb _cb)
209  : sc_core::sc_object( _name )
210  ,m_owner(_owner)
211  ,m_cb(_cb)
212  {
214  opts.spawn_method();
215  opts.set_sensitivity(&m_e);
216  opts.dont_initialize();
217  sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
218  sc_core::sc_gen_unique_name("fec"), &opts);
219  }
220 
222 
223  void notify (tlm_payload_type& t, const tlm_phase_type& p, const sc_core::sc_time& when){
224  //t.aquire();
225  if (when==sc_core::SC_ZERO_TIME) {
226  if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) //uneven delta cycle so delta delay is for even cylce
227  m_even_delta.insert(PAYLOAD(&t,p));
228  else
229  m_uneven_delta.insert(PAYLOAD(&t,p)); //even delta cycle so delta delay is for uneven delta
230  m_e.notify(sc_core::SC_ZERO_TIME);
231  }
232  else {
233  m_ppq.insert(PAYLOAD(&t,p), when + sc_core::sc_time_stamp() );
234  m_e.notify(when); // note, this will only over-right the "newest" event.
235  }
236  }
237 
238  void notify (tlm_payload_type& t, const tlm_phase_type& p){
239  m_immediate_yield.insert(PAYLOAD(&t,p));
240  m_e.notify(); // immediate notification
241  }
242 
243  // Cancel all events from the event queue
244  void cancel_all() {
245  m_ppq.reset();
246  m_uneven_delta.reset();
247  m_even_delta.reset();
248  m_immediate_yield.reset();
249  m_e.cancel();
250  }
251 
252 private:
253 
254  void fec(){
255  //immediate yield notifications
256  while(m_immediate_yield.next()) {PAYLOAD& tmp=m_immediate_yield.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
257  m_immediate_yield.reset();
258 
259  //delta notifications
260  if (sc_core::sc_delta_count() & (sc_dt::uint64) 0x1) {//uneven delta so put out all payloads for uneven delta
261  while (m_uneven_delta.next()) {PAYLOAD& tmp=m_uneven_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
262  m_uneven_delta.reset();
263  if (m_even_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
264  }
265  else {
266  while (m_even_delta.next()) {PAYLOAD& tmp=m_even_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
267  m_even_delta.reset();
268  if (m_uneven_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
269  }
270  if (!m_ppq.get_size()) return; //there were only delta notification
271 
272  //timed notifications
274  sc_core::sc_time top=m_ppq.top_time();
275 
276  while(m_ppq.get_size() && top==now) { // push all active ones into target
277  PAYLOAD& tmp=m_ppq.top();
278  (m_owner->*m_cb)(*tmp.first, tmp.second); //tmp.first->release();}
279  m_ppq.delete_top();
280  top=m_ppq.top_time();
281  }
282  if ( m_ppq.get_size()) {
283  m_e.notify( top - now) ;
284  }
285 
286  }
287 
288  OWNER* m_owner;
289  cb m_cb;
290 
292  delta_list m_uneven_delta;
293  delta_list m_even_delta;
294  delta_list m_immediate_yield;
295 
296  sc_core::sc_event m_e; // default event
297 };
298 
299 }
300 
301 #endif // __PEQ_WITH_CB_AND_PHASE_H__
SC_API const sc_time SC_ZERO_TIME
#define sc_bind
SC_API sc_dt::uint64 sc_delta_count()
uint64_t uint64
SC_API const sc_time & sc_time_stamp()
peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb)
sc_process_handle sc_spawn(T object, const char *name_p=0, const sc_spawn_options *opt_p=0)
element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d)
void notify(tlm_payload_type &t, const tlm_phase_type &p, const sc_core::sc_time &when)
SC_API const char * sc_gen_unique_name(const char *, bool preserve_first)
void insert(const PAYLOAD &p, sc_core::sc_time t)
class SC_API sc_object
void set_sensitivity(const sc_event *event)
void notify(tlm_payload_type &t, const tlm_phase_type &p)
peq_with_cb_and_phase(OWNER *_owner, cb _cb)