peq_with_cb_and_phase.h (13513:bbf275465d3d) peq_with_cb_and_phase.h (13586:008fe87c1ad4)
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 __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
21#define __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
22
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 __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
21#define __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
22
23#include <systemc>
24#include <tlm>
25#include <vector>
26
23#include <vector>
24
25#include "../core/sc_main.hh"
26#include "../core/sc_object.hh"
27#include "../core/sc_spawn.hh"
28#include "../core/sc_time.hh"
29#include "../dt/int/sc_nbdefs.hh"
30
27namespace tlm_utils
28{
29
30template <typename PAYLOAD>
31class time_ordered_list
32{
33 public:
34 struct element
35 {
36 struct element *next;
37 PAYLOAD p;
38 sc_core::sc_time t;
39 sc_dt::uint64 d;
40 element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
41 p(p), t(t), d(d)
42 {}
43 element() {}
44 };
45
46 element *nill;
47 element *empties;
48 element *list;
49 unsigned int size;
50
51 time_ordered_list() : nill(new element()), empties(NULL),
52 list(nill), size(0)
53 {}
54
55 ~time_ordered_list()
56 {
57 reset();
58 while (empties) {
59 struct element *e = empties->next;
60 delete empties;
61 empties = e;
62 }
63 delete nill;
64 }
65
66 void
67 reset()
68 {
69 while (size) {
70 delete_top();
71 }
72 }
73
74 void
75 insert(const PAYLOAD &p, sc_core::sc_time t)
76 {
77 if (!empties) {
78 empties = new struct element();
79 empties->next=NULL;
80 }
81
82 struct element *e = empties;
83 empties = empties->next;
84 e->p = p;
85 e->t = t;
86 e->d = sc_core::sc_delta_count();
87
88 struct element *ancestor = nill;
89 struct element *iterator = list;
90 while (iterator != nill && iterator->t <= t) {
91 ancestor = iterator;
92 iterator = iterator->next;
93 }
94 if (ancestor == nill) {
95 e->next = list;
96 list = e;
97 } else {
98 e->next = iterator;
99 ancestor->next = e;
100 }
101 size++;
102 }
103
104 void
105 delete_top()
106 {
107 if (list != nill) {
108 struct element *e = list;
109 list = list->next;
110 e->next = empties;
111 empties = e;
112 size--;
113 }
114 }
115
116 unsigned int get_size() { return size; }
117 PAYLOAD &top() { return list->p; }
118 sc_core::sc_time top_time() { return list->t; }
119 sc_dt::uint64 &top_delta() { return list->d; }
120 sc_core::sc_time next_time() { return list->next->t; }
121};
122
123//---------------------------------------------------------------------------
124/**
125 * An event queue that can contain any number of pending
126 * notifications. Each notification have an associate payload.
127 */
128//---------------------------------------------------------------------------
129template<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
130class peq_with_cb_and_phase : public sc_core::sc_object
131{
132 typedef typename TYPES::tlm_payload_type tlm_payload_type;
133 typedef typename TYPES::tlm_phase_type tlm_phase_type;
134 typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
135 typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
136
137 class delta_list
138 {
139 public:
140 delta_list()
141 {
142 reset();
143 entries.resize(100);
144 }
145
146 inline void
147 insert(const PAYLOAD &p)
148 {
149 if (size==entries.size()) {
150 entries.resize(entries.size() * 2);
151 }
152 entries[size++] = p;
153 }
154
155 inline PAYLOAD &get() { return entries[out++]; }
156 inline bool next() { return out < size; }
157 inline void
158 reset()
159 {
160 size=0;
161 out=0;
162 }
163
164 public:
165 unsigned int size;
166
167 private:
168 std::vector<PAYLOAD> entries;
169 unsigned int out;
170 };
171
172 public:
173 peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
174 sc_core::sc_object(sc_core::sc_gen_unique_name(
175 "peq_with_cb_and_phase")),
176 m_owner(_owner), m_cb(_cb)
177 {
178 sc_core::sc_spawn_options opts;
179 opts.spawn_method();
180 opts.set_sensitivity(&m_e);
181 opts.dont_initialize();
182 sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
183 sc_core::sc_gen_unique_name("fec"), &opts);
184 }
185
186 peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
187 sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
188 {
189 sc_core::sc_spawn_options opts;
190 opts.spawn_method();
191 opts.set_sensitivity(&m_e);
192 opts.dont_initialize();
193 sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
194 sc_core::sc_gen_unique_name("fec"), &opts);
195 }
196
197 ~peq_with_cb_and_phase() {}
198
199 void
200 notify(tlm_payload_type &t, const tlm_phase_type &p,
201 const sc_core::sc_time &when)
202 {
203 if (when == sc_core::SC_ZERO_TIME) {
204 if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
205 // Uneven delta cycle so delta delay is for even cycle.
206 m_even_delta.insert(PAYLOAD(&t,p));
207 } else {
208 // Even delta cycle so delta delay is for uneven delta.
209 m_uneven_delta.insert(PAYLOAD(&t, p));
210 }
211 m_e.notify(sc_core::SC_ZERO_TIME);
212 } else {
213 m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
214 // Note, this will only overwrite the "newest" event.
215 m_e.notify(when);
216 }
217 }
218
219 void
220 notify(tlm_payload_type &t, const tlm_phase_type &p)
221 {
222 m_immediate_yield.insert(PAYLOAD(&t, p));
223 m_e.notify(); // Immediate notification.
224 }
225
226 // Cancel all events from the event queue.
227 void
228 cancel_all()
229 {
230 m_ppq.reset();
231 m_uneven_delta.reset();
232 m_even_delta.reset();
233 m_immediate_yield.reset();
234 m_e.cancel();
235 }
236
237 private:
238 void
239 fec()
240 {
241 // Immediate yield notifications.
242 while (m_immediate_yield.next()) {
243 PAYLOAD &tmp = m_immediate_yield.get();
244 (m_owner->*m_cb)(*tmp.first, tmp.second);
245 }
246 m_immediate_yield.reset();
247
248 // Delta notifications.
249 if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
250 // Uneven delta so put out all payloads for uneven delta.
251 while (m_uneven_delta.next()) {
252 PAYLOAD &tmp = m_uneven_delta.get();
253 (m_owner->*m_cb)(*tmp.first, tmp.second);
254 }
255 m_uneven_delta.reset();
256 if (m_even_delta.size)
257 m_e.notify(sc_core::SC_ZERO_TIME);
258 } else {
259 while (m_even_delta.next()) {
260 PAYLOAD &tmp = m_even_delta.get();
261 (m_owner->*m_cb)(*tmp.first, tmp.second);
262 }
263 m_even_delta.reset();
264 if (m_uneven_delta.size)
265 m_e.notify(sc_core::SC_ZERO_TIME);
266 }
267 if (!m_ppq.get_size())
268 return; // There were only delta notification.
269
270 // Timed notifications.
271 const sc_core::sc_time now = sc_core::sc_time_stamp();
272 sc_core::sc_time top = m_ppq.top_time();
273
274 while (m_ppq.get_size() && top == now) {
275 // Push all active ones into target.
276 PAYLOAD &tmp = m_ppq.top();
277 (m_owner->*m_cb)(*tmp.first, tmp.second);
278 m_ppq.delete_top();
279 top = m_ppq.top_time();
280 }
281 if (m_ppq.get_size()) {
282 m_e.notify(top - now);
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} // namespace tlm_utils
298
299#endif /* __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ */
31namespace tlm_utils
32{
33
34template <typename PAYLOAD>
35class time_ordered_list
36{
37 public:
38 struct element
39 {
40 struct element *next;
41 PAYLOAD p;
42 sc_core::sc_time t;
43 sc_dt::uint64 d;
44 element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
45 p(p), t(t), d(d)
46 {}
47 element() {}
48 };
49
50 element *nill;
51 element *empties;
52 element *list;
53 unsigned int size;
54
55 time_ordered_list() : nill(new element()), empties(NULL),
56 list(nill), size(0)
57 {}
58
59 ~time_ordered_list()
60 {
61 reset();
62 while (empties) {
63 struct element *e = empties->next;
64 delete empties;
65 empties = e;
66 }
67 delete nill;
68 }
69
70 void
71 reset()
72 {
73 while (size) {
74 delete_top();
75 }
76 }
77
78 void
79 insert(const PAYLOAD &p, sc_core::sc_time t)
80 {
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;
90 e->d = sc_core::sc_delta_count();
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 } else {
102 e->next = iterator;
103 ancestor->next = e;
104 }
105 size++;
106 }
107
108 void
109 delete_top()
110 {
111 if (list != nill) {
112 struct element *e = list;
113 list = list->next;
114 e->next = empties;
115 empties = e;
116 size--;
117 }
118 }
119
120 unsigned int get_size() { return size; }
121 PAYLOAD &top() { return list->p; }
122 sc_core::sc_time top_time() { return list->t; }
123 sc_dt::uint64 &top_delta() { return list->d; }
124 sc_core::sc_time next_time() { return list->next->t; }
125};
126
127//---------------------------------------------------------------------------
128/**
129 * An event queue that can contain any number of pending
130 * notifications. Each notification have an associate payload.
131 */
132//---------------------------------------------------------------------------
133template<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
134class peq_with_cb_and_phase : public sc_core::sc_object
135{
136 typedef typename TYPES::tlm_payload_type tlm_payload_type;
137 typedef typename TYPES::tlm_phase_type tlm_phase_type;
138 typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
139 typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
140
141 class delta_list
142 {
143 public:
144 delta_list()
145 {
146 reset();
147 entries.resize(100);
148 }
149
150 inline void
151 insert(const PAYLOAD &p)
152 {
153 if (size==entries.size()) {
154 entries.resize(entries.size() * 2);
155 }
156 entries[size++] = p;
157 }
158
159 inline PAYLOAD &get() { return entries[out++]; }
160 inline bool next() { return out < size; }
161 inline void
162 reset()
163 {
164 size=0;
165 out=0;
166 }
167
168 public:
169 unsigned int size;
170
171 private:
172 std::vector<PAYLOAD> entries;
173 unsigned int out;
174 };
175
176 public:
177 peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
178 sc_core::sc_object(sc_core::sc_gen_unique_name(
179 "peq_with_cb_and_phase")),
180 m_owner(_owner), m_cb(_cb)
181 {
182 sc_core::sc_spawn_options opts;
183 opts.spawn_method();
184 opts.set_sensitivity(&m_e);
185 opts.dont_initialize();
186 sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
187 sc_core::sc_gen_unique_name("fec"), &opts);
188 }
189
190 peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
191 sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
192 {
193 sc_core::sc_spawn_options opts;
194 opts.spawn_method();
195 opts.set_sensitivity(&m_e);
196 opts.dont_initialize();
197 sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
198 sc_core::sc_gen_unique_name("fec"), &opts);
199 }
200
201 ~peq_with_cb_and_phase() {}
202
203 void
204 notify(tlm_payload_type &t, const tlm_phase_type &p,
205 const sc_core::sc_time &when)
206 {
207 if (when == sc_core::SC_ZERO_TIME) {
208 if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
209 // Uneven delta cycle so delta delay is for even cycle.
210 m_even_delta.insert(PAYLOAD(&t,p));
211 } else {
212 // Even delta cycle so delta delay is for uneven delta.
213 m_uneven_delta.insert(PAYLOAD(&t, p));
214 }
215 m_e.notify(sc_core::SC_ZERO_TIME);
216 } else {
217 m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
218 // Note, this will only overwrite the "newest" event.
219 m_e.notify(when);
220 }
221 }
222
223 void
224 notify(tlm_payload_type &t, const tlm_phase_type &p)
225 {
226 m_immediate_yield.insert(PAYLOAD(&t, p));
227 m_e.notify(); // Immediate notification.
228 }
229
230 // Cancel all events from the event queue.
231 void
232 cancel_all()
233 {
234 m_ppq.reset();
235 m_uneven_delta.reset();
236 m_even_delta.reset();
237 m_immediate_yield.reset();
238 m_e.cancel();
239 }
240
241 private:
242 void
243 fec()
244 {
245 // Immediate yield notifications.
246 while (m_immediate_yield.next()) {
247 PAYLOAD &tmp = m_immediate_yield.get();
248 (m_owner->*m_cb)(*tmp.first, tmp.second);
249 }
250 m_immediate_yield.reset();
251
252 // Delta notifications.
253 if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
254 // Uneven delta so put out all payloads for uneven delta.
255 while (m_uneven_delta.next()) {
256 PAYLOAD &tmp = m_uneven_delta.get();
257 (m_owner->*m_cb)(*tmp.first, tmp.second);
258 }
259 m_uneven_delta.reset();
260 if (m_even_delta.size)
261 m_e.notify(sc_core::SC_ZERO_TIME);
262 } else {
263 while (m_even_delta.next()) {
264 PAYLOAD &tmp = m_even_delta.get();
265 (m_owner->*m_cb)(*tmp.first, tmp.second);
266 }
267 m_even_delta.reset();
268 if (m_uneven_delta.size)
269 m_e.notify(sc_core::SC_ZERO_TIME);
270 }
271 if (!m_ppq.get_size())
272 return; // There were only delta notification.
273
274 // Timed notifications.
275 const sc_core::sc_time now = sc_core::sc_time_stamp();
276 sc_core::sc_time top = m_ppq.top_time();
277
278 while (m_ppq.get_size() && top == now) {
279 // Push all active ones into target.
280 PAYLOAD &tmp = m_ppq.top();
281 (m_owner->*m_cb)(*tmp.first, tmp.second);
282 m_ppq.delete_top();
283 top = m_ppq.top_time();
284 }
285 if (m_ppq.get_size()) {
286 m_e.notify(top - now);
287 }
288 }
289
290 OWNER *m_owner;
291 cb m_cb;
292
293 time_ordered_list<PAYLOAD> m_ppq;
294 delta_list m_uneven_delta;
295 delta_list m_even_delta;
296 delta_list m_immediate_yield;
297
298 sc_core::sc_event m_e; // Default event.
299};
300
301} // namespace tlm_utils
302
303#endif /* __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ */