TLM-2.0  2.0.3
Accellera TLM-2.0 proof-of-concept library
peq_with_cb_and_phase.h
Go to the documentation of this file.
1 /*****************************************************************************
2 
3  The following code is derived, directly or indirectly, from the SystemC
4  source code Copyright (c) 1996-2014 by all Contributors.
5  All Rights reserved.
6 
7  The contents of this file are subject to the restrictions and limitations
8  set forth in the SystemC Open Source License (the "License");
9  You may not use this file except in compliance with such restrictions and
10  limitations. You may obtain instructions on how to receive a copy of the
11  License at http://www.accellera.org/. Software distributed by Contributors
12  under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
13  ANY KIND, either express or implied. See the License for the specific
14  language governing rights and limitations under the License.
15 
16  *****************************************************************************/
17 
18 // 12-Jan-2009 John Aynsley Bug fix. Phase argument to notify should be const
19 // 20-Mar-2009 John Aynsley Add cancel_all() method
20 
21 
22 #ifndef __PEQ_WITH_CB_AND_PHASE_H__
23 #define __PEQ_WITH_CB_AND_PHASE_H__
24 
25 #ifndef SC_INCLUDE_DYNAMIC_PROCESSES // needed for sc_spawn
26 # define SC_INCLUDE_DYNAMIC_PROCESSES
27 #endif
28 
29 #include <vector>
30 #include <systemc>
31 #include <tlm>
32 
33 namespace tlm_utils {
34 
35 template <typename PAYLOAD>
37 {
38 public:
39  struct element
40  {
41  struct element *next;
42  PAYLOAD p;
45  element(PAYLOAD& p, sc_core::sc_time t, sc_dt::uint64 d): p(p),t(t),d(d) {}
46  element(){}
47  };
48 
52  unsigned int size;
53 
55  : nill(new element()),
56  empties(NULL),
57  list(nill),
58  size(0)
59  {
60  }
61 
63  reset();
64  while(empties){
65  struct element *e=empties->next;
66  delete empties;
67  empties=e;
68  }
69  delete nill;
70  }
71 
72  void reset() {
73  while(size) {
74  delete_top();
75  }
76  }
77 
78  void insert(const PAYLOAD& p, sc_core::sc_time t) {
79  if (!empties) {
80  empties=new struct element();
81  empties->next=NULL;
82  }
83 
84  struct element *e=empties;
86  e->p=p;
87  e->t=t;
89 
90  struct element * ancestor=nill;
91  struct element * iterator=list;
92  while (iterator!=nill && iterator->t<=t){
93  ancestor=iterator;
94  iterator=iterator->next;
95  }
96  if (ancestor==nill){
97  e->next=list;
98  list=e;
99  }
100  else {
101  e->next=iterator;
102  ancestor->next=e;
103  }
104  size++;
105  }
106 
107  void delete_top(){
108  if (list != nill) {
109  struct element *e=list;
110  list=list->next;
111  e->next=empties;
112  empties=e;
113  size--;
114  }
115  }
116 
117  unsigned int get_size()
118  {
119  return size;
120  }
121 
122  PAYLOAD &top()
123  {
124  return list->p;
125  }
127  {
128  return list->t;
129  }
130 
132  {
133  return list->d;
134  }
135 
137  {
138  return list->next->t;
139  }
140 };
141 
142 //---------------------------------------------------------------------------
147 //---------------------------------------------------------------------------
148 template<typename OWNER,typename TYPES=tlm::tlm_base_protocol_types>
150  public sc_core::sc_object
151 {
152 
153  typedef typename TYPES::tlm_payload_type tlm_payload_type;
154  typedef typename TYPES::tlm_phase_type tlm_phase_type;
155  typedef std::pair<tlm_payload_type*, tlm_phase_type> PAYLOAD;
156  typedef void (OWNER::*cb)(tlm_payload_type&, const tlm_phase_type&);
157 
158  class delta_list{
159  public:
160  delta_list(){
161  reset();
162  entries.resize(100);
163  }
164 
165  inline void insert(const PAYLOAD& p){
166  if (size==entries.size()){
167  entries.resize(entries.size()*2);
168  }
169  entries[size++]=p;
170  }
171 
172  inline PAYLOAD& get(){
173  return entries[out++];
174  }
175 
176  inline bool next(){
177  return out<size;
178  }
179 
180  inline void reset(){
181  size=0;
182  out=0;
183  }
184  public:
185  unsigned int size;
186  private:
187  std::vector<PAYLOAD> entries;
188  unsigned int out;
189  };
190 
191 public:
192 
193  peq_with_cb_and_phase(OWNER* _owner, cb _cb)
194  :sc_core::sc_object( sc_core::sc_gen_unique_name( "peq_with_cb_and_phase" ) )
195  ,m_owner(_owner)
196  ,m_cb(_cb)
197  {
199  opts.spawn_method();
200  opts.set_sensitivity(&m_e);
201  opts.dont_initialize();
202  sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
203  sc_core::sc_gen_unique_name("fec"), &opts);
204  }
205 
206  peq_with_cb_and_phase(const char* _name, OWNER* _owner,cb _cb)
207  : sc_core::sc_object( _name )
208  ,m_owner(_owner)
209  ,m_cb(_cb)
210  {
212  opts.spawn_method();
213  opts.set_sensitivity(&m_e);
214  opts.dont_initialize();
215  sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
216  sc_core::sc_gen_unique_name("fec"), &opts);
217  }
218 
220 
221  void notify (tlm_payload_type& t, const tlm_phase_type& p, const sc_core::sc_time& when){
222  //t.aquire();
223  if (when==sc_core::SC_ZERO_TIME) {
224  if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) //uneven delta cycle so delta delay is for even cylce
225  m_even_delta.insert(PAYLOAD(&t,p));
226  else
227  m_uneven_delta.insert(PAYLOAD(&t,p)); //even delta cycle so delta delay is for uneven delta
229  }
230  else {
231  m_ppq.insert(PAYLOAD(&t,p), when + sc_core::sc_time_stamp() );
232  m_e.notify(when); // note, this will only over-right the "newest" event.
233  }
234  }
235 
236  void notify (tlm_payload_type& t, const tlm_phase_type& p){
237  m_immediate_yield.insert(PAYLOAD(&t,p));
238  m_e.notify(); // immediate notification
239  }
240 
241  // Cancel all events from the event queue
242  void cancel_all() {
243  m_ppq.reset();
244  m_uneven_delta.reset();
245  m_even_delta.reset();
246  m_immediate_yield.reset();
247  m_e.cancel();
248  }
249 
250 private:
251 
252  void fec(){
253  //immediate yield notifications
254  while(m_immediate_yield.next()) {PAYLOAD& tmp=m_immediate_yield.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
255  m_immediate_yield.reset();
256 
257  //delta notifications
258  if (sc_core::sc_delta_count() & (sc_dt::uint64) 0x1) {//uneven delta so put out all payloads for uneven delta
259  while (m_uneven_delta.next()) {PAYLOAD& tmp=m_uneven_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
260  m_uneven_delta.reset();
261  if (m_even_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
262  }
263  else {
264  while (m_even_delta.next()) {PAYLOAD& tmp=m_even_delta.get(); (m_owner->*m_cb)(*tmp.first, tmp.second);} //tmp.first->release();}
265  m_even_delta.reset();
266  if (m_uneven_delta.size) m_e.notify(sc_core::SC_ZERO_TIME);
267  }
268  if (!m_ppq.get_size()) return; //there were only delta notification
269 
270  //timed notifications
272  sc_core::sc_time top=m_ppq.top_time();
273 
274  while(m_ppq.get_size() && top==now) { // push all active ones into target
275  PAYLOAD& tmp=m_ppq.top();
276  (m_owner->*m_cb)(*tmp.first, tmp.second); //tmp.first->release();}
277  m_ppq.delete_top();
278  top=m_ppq.top_time();
279  }
280  if ( m_ppq.get_size()) {
281  m_e.notify( top - now) ;
282  }
283 
284  }
285 
286  OWNER* m_owner;
287  cb m_cb;
288 
289  time_ordered_list<PAYLOAD> m_ppq;
290  delta_list m_uneven_delta;
291  delta_list m_even_delta;
292  delta_list m_immediate_yield;
293 
294  sc_core::sc_event m_e; // default event
295 };
296 
297 }
298 
299 #endif // __PEQ_WITH_CB_AND_PHASE_H__
#define sc_bind
uint64_t uint64
void set_sensitivity(const sc_event *event)
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)
const char * sc_gen_unique_name(const char *, bool preserve_first)
void insert(const PAYLOAD &p, sc_core::sc_time t)
sc_dt::uint64 sc_delta_count()
const sc_time SC_ZERO_TIME
void notify(tlm_payload_type &t, const tlm_phase_type &p)
void notify(tlm_payload_type &t, const tlm_phase_type &p, const sc_core::sc_time &when)
const sc_time & sc_time_stamp()
peq_with_cb_and_phase(OWNER *_owner, cb _cb)
element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d)