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__ */
|