peq_with_cb_and_phase.h revision 13586
17584SAli.Saidi@arm.com/***************************************************************************** 29958Smatt.evans@arm.com 37584SAli.Saidi@arm.com Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 47584SAli.Saidi@arm.com more contributor license agreements. See the NOTICE file distributed 57584SAli.Saidi@arm.com with this work for additional information regarding copyright ownership. 67584SAli.Saidi@arm.com Accellera licenses this file to you under the Apache License, Version 2.0 77584SAli.Saidi@arm.com (the "License"); you may not use this file except in compliance with the 87584SAli.Saidi@arm.com License. You may obtain a copy of the License at 97584SAli.Saidi@arm.com 107584SAli.Saidi@arm.com http://www.apache.org/licenses/LICENSE-2.0 117584SAli.Saidi@arm.com 127584SAli.Saidi@arm.com Unless required by applicable law or agreed to in writing, software 137584SAli.Saidi@arm.com distributed under the License is distributed on an "AS IS" BASIS, 147584SAli.Saidi@arm.com WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 157584SAli.Saidi@arm.com implied. See the License for the specific language governing 167584SAli.Saidi@arm.com permissions and limitations under the License. 177584SAli.Saidi@arm.com 187584SAli.Saidi@arm.com *****************************************************************************/ 197584SAli.Saidi@arm.com 207584SAli.Saidi@arm.com#ifndef __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ 217584SAli.Saidi@arm.com#define __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ 227584SAli.Saidi@arm.com 237584SAli.Saidi@arm.com#include <vector> 247584SAli.Saidi@arm.com 257584SAli.Saidi@arm.com#include "../core/sc_main.hh" 267584SAli.Saidi@arm.com#include "../core/sc_object.hh" 277584SAli.Saidi@arm.com#include "../core/sc_spawn.hh" 287584SAli.Saidi@arm.com#include "../core/sc_time.hh" 297584SAli.Saidi@arm.com#include "../dt/int/sc_nbdefs.hh" 307584SAli.Saidi@arm.com 317584SAli.Saidi@arm.comnamespace tlm_utils 327584SAli.Saidi@arm.com{ 337584SAli.Saidi@arm.com 347584SAli.Saidi@arm.comtemplate <typename PAYLOAD> 357584SAli.Saidi@arm.comclass time_ordered_list 367584SAli.Saidi@arm.com{ 377584SAli.Saidi@arm.com public: 387584SAli.Saidi@arm.com struct element 397584SAli.Saidi@arm.com { 407584SAli.Saidi@arm.com struct element *next; 419958Smatt.evans@arm.com PAYLOAD p; 427584SAli.Saidi@arm.com sc_core::sc_time t; 437584SAli.Saidi@arm.com sc_dt::uint64 d; 447584SAli.Saidi@arm.com element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) : 457584SAli.Saidi@arm.com p(p), t(t), d(d) 467584SAli.Saidi@arm.com {} 479958Smatt.evans@arm.com element() {} 487584SAli.Saidi@arm.com }; 497584SAli.Saidi@arm.com 507584SAli.Saidi@arm.com element *nill; 517584SAli.Saidi@arm.com element *empties; 527584SAli.Saidi@arm.com element *list; 537584SAli.Saidi@arm.com unsigned int size; 547584SAli.Saidi@arm.com 557584SAli.Saidi@arm.com time_ordered_list() : nill(new element()), empties(NULL), 567584SAli.Saidi@arm.com list(nill), size(0) 577584SAli.Saidi@arm.com {} 587584SAli.Saidi@arm.com 598524SAli.Saidi@ARM.com ~time_ordered_list() 608524SAli.Saidi@ARM.com { 618524SAli.Saidi@ARM.com reset(); 628524SAli.Saidi@ARM.com while (empties) { 638524SAli.Saidi@ARM.com struct element *e = empties->next; 647584SAli.Saidi@arm.com delete empties; 657584SAli.Saidi@arm.com empties = e; 667584SAli.Saidi@arm.com } 679004Skoansin.tan@gmail.com delete nill; 687584SAli.Saidi@arm.com } 697584SAli.Saidi@arm.com 708060SAli.Saidi@ARM.com void 718060SAli.Saidi@ARM.com reset() 729004Skoansin.tan@gmail.com { 738060SAli.Saidi@ARM.com while (size) { 748060SAli.Saidi@ARM.com delete_top(); 757584SAli.Saidi@arm.com } 767584SAli.Saidi@arm.com } 777584SAli.Saidi@arm.com 787950SAli.Saidi@ARM.com void 797950SAli.Saidi@ARM.com insert(const PAYLOAD &p, sc_core::sc_time t) 807950SAli.Saidi@ARM.com { 817950SAli.Saidi@ARM.com if (!empties) { 827950SAli.Saidi@ARM.com empties = new struct element(); 837950SAli.Saidi@ARM.com empties->next=NULL; 847950SAli.Saidi@ARM.com } 857950SAli.Saidi@ARM.com 867950SAli.Saidi@ARM.com struct element *e = empties; 877950SAli.Saidi@ARM.com empties = empties->next; 887950SAli.Saidi@ARM.com e->p = p; 897950SAli.Saidi@ARM.com e->t = t; 907950SAli.Saidi@ARM.com e->d = sc_core::sc_delta_count(); 917950SAli.Saidi@ARM.com 927950SAli.Saidi@ARM.com struct element *ancestor = nill; 937950SAli.Saidi@ARM.com struct element *iterator = list; 947950SAli.Saidi@ARM.com while (iterator != nill && iterator->t <= t) { 957950SAli.Saidi@ARM.com ancestor = iterator; 967950SAli.Saidi@ARM.com iterator = iterator->next; 977950SAli.Saidi@ARM.com } 987950SAli.Saidi@ARM.com if (ancestor == nill) { 998281SAli.Saidi@ARM.com e->next = list; 1008281SAli.Saidi@ARM.com list = e; 1018281SAli.Saidi@ARM.com } else { 1028299Schander.sudanthi@arm.com e->next = iterator; 1038299Schander.sudanthi@arm.com ancestor->next = e; 1048299Schander.sudanthi@arm.com } 1058870SAli.Saidi@ARM.com size++; 1068870SAli.Saidi@ARM.com } 1078988SAli.Saidi@ARM.com 1089958Smatt.evans@arm.com void 1099958Smatt.evans@arm.com delete_top() 1109958Smatt.evans@arm.com { 1119958Smatt.evans@arm.com if (list != nill) { 1129958Smatt.evans@arm.com struct element *e = list; 1139958Smatt.evans@arm.com list = list->next; 1149958Smatt.evans@arm.com e->next = empties; 1159958Smatt.evans@arm.com empties = e; 1167584SAli.Saidi@arm.com size--; 1178299Schander.sudanthi@arm.com } 1188299Schander.sudanthi@arm.com } 1199958Smatt.evans@arm.com 1207584SAli.Saidi@arm.com unsigned int get_size() { return size; } 1217584SAli.Saidi@arm.com PAYLOAD &top() { return list->p; } 1227584SAli.Saidi@arm.com sc_core::sc_time top_time() { return list->t; } 1237584SAli.Saidi@arm.com sc_dt::uint64 &top_delta() { return list->d; } 1247584SAli.Saidi@arm.com sc_core::sc_time next_time() { return list->next->t; } 1257584SAli.Saidi@arm.com}; 1267584SAli.Saidi@arm.com 1277584SAli.Saidi@arm.com//--------------------------------------------------------------------------- 1287584SAli.Saidi@arm.com/** 1297584SAli.Saidi@arm.com * An event queue that can contain any number of pending 1307584SAli.Saidi@arm.com * notifications. Each notification have an associate payload. 1317584SAli.Saidi@arm.com */ 1327584SAli.Saidi@arm.com//--------------------------------------------------------------------------- 1337584SAli.Saidi@arm.comtemplate<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types> 1347584SAli.Saidi@arm.comclass peq_with_cb_and_phase : public sc_core::sc_object 1357950SAli.Saidi@ARM.com{ 1367950SAli.Saidi@ARM.com typedef typename TYPES::tlm_payload_type tlm_payload_type; 1377950SAli.Saidi@ARM.com typedef typename TYPES::tlm_phase_type tlm_phase_type; 1387950SAli.Saidi@ARM.com typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD; 1397950SAli.Saidi@ARM.com typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &); 1407950SAli.Saidi@ARM.com 1417950SAli.Saidi@ARM.com class delta_list 1427950SAli.Saidi@ARM.com { 1437950SAli.Saidi@ARM.com public: 1447584SAli.Saidi@arm.com delta_list() 1458281SAli.Saidi@ARM.com { 1468281SAli.Saidi@ARM.com reset(); 1478281SAli.Saidi@ARM.com entries.resize(100); 1488524SAli.Saidi@ARM.com } 1498524SAli.Saidi@ARM.com 1508524SAli.Saidi@ARM.com inline void 1519958Smatt.evans@arm.com insert(const PAYLOAD &p) 1529958Smatt.evans@arm.com { 1539958Smatt.evans@arm.com if (size==entries.size()) { 1549958Smatt.evans@arm.com entries.resize(entries.size() * 2); 1559958Smatt.evans@arm.com } 1569958Smatt.evans@arm.com entries[size++] = p; 1579958Smatt.evans@arm.com } 1589958Smatt.evans@arm.com 1599958Smatt.evans@arm.com inline PAYLOAD &get() { return entries[out++]; } 1609958Smatt.evans@arm.com inline bool next() { return out < size; } 1619958Smatt.evans@arm.com inline void 1629958Smatt.evans@arm.com reset() 1639958Smatt.evans@arm.com { 1649958Smatt.evans@arm.com size=0; 1659958Smatt.evans@arm.com out=0; 1669958Smatt.evans@arm.com } 1679958Smatt.evans@arm.com 1689958Smatt.evans@arm.com public: 1699958Smatt.evans@arm.com unsigned int size; 1709958Smatt.evans@arm.com 1719958Smatt.evans@arm.com private: 1729958Smatt.evans@arm.com std::vector<PAYLOAD> entries; 1739958Smatt.evans@arm.com unsigned int out; 1749958Smatt.evans@arm.com }; 1759958Smatt.evans@arm.com 1769958Smatt.evans@arm.com public: 1779958Smatt.evans@arm.com peq_with_cb_and_phase(OWNER *_owner, cb _cb) : 1789958Smatt.evans@arm.com sc_core::sc_object(sc_core::sc_gen_unique_name( 1799958Smatt.evans@arm.com "peq_with_cb_and_phase")), 1809958Smatt.evans@arm.com m_owner(_owner), m_cb(_cb) 1819958Smatt.evans@arm.com { 1829958Smatt.evans@arm.com sc_core::sc_spawn_options opts; 1839958Smatt.evans@arm.com opts.spawn_method(); 1849958Smatt.evans@arm.com opts.set_sensitivity(&m_e); 1859958Smatt.evans@arm.com opts.dont_initialize(); 1869958Smatt.evans@arm.com sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this), 1879958Smatt.evans@arm.com sc_core::sc_gen_unique_name("fec"), &opts); 1889958Smatt.evans@arm.com } 1899958Smatt.evans@arm.com 1909958Smatt.evans@arm.com peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) : 1919958Smatt.evans@arm.com sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb) 1929958Smatt.evans@arm.com { 1939958Smatt.evans@arm.com sc_core::sc_spawn_options opts; 1949958Smatt.evans@arm.com opts.spawn_method(); 1959958Smatt.evans@arm.com opts.set_sensitivity(&m_e); 1969958Smatt.evans@arm.com opts.dont_initialize(); 1979958Smatt.evans@arm.com sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this), 1989958Smatt.evans@arm.com sc_core::sc_gen_unique_name("fec"), &opts); 1999958Smatt.evans@arm.com } 2009958Smatt.evans@arm.com 2019958Smatt.evans@arm.com ~peq_with_cb_and_phase() {} 2029958Smatt.evans@arm.com 2039958Smatt.evans@arm.com void 2049958Smatt.evans@arm.com notify(tlm_payload_type &t, const tlm_phase_type &p, 2059958Smatt.evans@arm.com const sc_core::sc_time &when) 2069958Smatt.evans@arm.com { 2079958Smatt.evans@arm.com if (when == sc_core::SC_ZERO_TIME) { 2089958Smatt.evans@arm.com if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) { 2099958Smatt.evans@arm.com // Uneven delta cycle so delta delay is for even cycle. 2109958Smatt.evans@arm.com m_even_delta.insert(PAYLOAD(&t,p)); 2119958Smatt.evans@arm.com } else { 2129958Smatt.evans@arm.com // Even delta cycle so delta delay is for uneven delta. 2139958Smatt.evans@arm.com m_uneven_delta.insert(PAYLOAD(&t, p)); 2149958Smatt.evans@arm.com } 2159958Smatt.evans@arm.com m_e.notify(sc_core::SC_ZERO_TIME); 2169958Smatt.evans@arm.com } else { 2179958Smatt.evans@arm.com m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp()); 2189958Smatt.evans@arm.com // Note, this will only overwrite the "newest" event. 2199958Smatt.evans@arm.com m_e.notify(when); 2209958Smatt.evans@arm.com } 2219958Smatt.evans@arm.com } 2229958Smatt.evans@arm.com 2239958Smatt.evans@arm.com void 2249958Smatt.evans@arm.com notify(tlm_payload_type &t, const tlm_phase_type &p) 2259958Smatt.evans@arm.com { 2269958Smatt.evans@arm.com m_immediate_yield.insert(PAYLOAD(&t, p)); 2279958Smatt.evans@arm.com m_e.notify(); // Immediate notification. 2289958Smatt.evans@arm.com } 2299958Smatt.evans@arm.com 2309958Smatt.evans@arm.com // Cancel all events from the event queue. 2319958Smatt.evans@arm.com void 2329958Smatt.evans@arm.com cancel_all() 2339958Smatt.evans@arm.com { 2349958Smatt.evans@arm.com m_ppq.reset(); 2359958Smatt.evans@arm.com m_uneven_delta.reset(); 2369958Smatt.evans@arm.com m_even_delta.reset(); 2379958Smatt.evans@arm.com m_immediate_yield.reset(); 2389958Smatt.evans@arm.com m_e.cancel(); 2399958Smatt.evans@arm.com } 2409958Smatt.evans@arm.com 2417584SAli.Saidi@arm.com private: 2429958Smatt.evans@arm.com void 2439958Smatt.evans@arm.com fec() 2447584SAli.Saidi@arm.com { 2457584SAli.Saidi@arm.com // Immediate yield notifications. 2467584SAli.Saidi@arm.com while (m_immediate_yield.next()) { 2477584SAli.Saidi@arm.com PAYLOAD &tmp = m_immediate_yield.get(); 2487584SAli.Saidi@arm.com (m_owner->*m_cb)(*tmp.first, tmp.second); 2497584SAli.Saidi@arm.com } 2507584SAli.Saidi@arm.com m_immediate_yield.reset(); 25110905Sandreas.sandberg@arm.com 2527584SAli.Saidi@arm.com // Delta notifications. 2538281SAli.Saidi@ARM.com if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) { 2547584SAli.Saidi@arm.com // Uneven delta so put out all payloads for uneven delta. 2557584SAli.Saidi@arm.com while (m_uneven_delta.next()) { 2567584SAli.Saidi@arm.com PAYLOAD &tmp = m_uneven_delta.get(); 25710905Sandreas.sandberg@arm.com (m_owner->*m_cb)(*tmp.first, tmp.second); 2587584SAli.Saidi@arm.com } 2598281SAli.Saidi@ARM.com m_uneven_delta.reset(); 2607584SAli.Saidi@arm.com if (m_even_delta.size) 2617584SAli.Saidi@arm.com m_e.notify(sc_core::SC_ZERO_TIME); 2627584SAli.Saidi@arm.com } else { 2637584SAli.Saidi@arm.com while (m_even_delta.next()) { 2647584SAli.Saidi@arm.com PAYLOAD &tmp = m_even_delta.get(); 2657584SAli.Saidi@arm.com (m_owner->*m_cb)(*tmp.first, tmp.second); 2667584SAli.Saidi@arm.com } 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__ */ 304