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