peq_with_cb_and_phase.h revision 13513
113511Sgabeblack@google.com/*****************************************************************************
213511Sgabeblack@google.com
313511Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
413511Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
513511Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
613511Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
713511Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
813511Sgabeblack@google.com  License.  You may obtain a copy of the License at
913511Sgabeblack@google.com
1013511Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1113511Sgabeblack@google.com
1213511Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1313511Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1413511Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1513511Sgabeblack@google.com  implied.  See the License for the specific language governing
1613511Sgabeblack@google.com  permissions and limitations under the License.
1713511Sgabeblack@google.com
1813511Sgabeblack@google.com *****************************************************************************/
1913511Sgabeblack@google.com
2013513Sgabeblack@google.com#ifndef __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
2113513Sgabeblack@google.com#define __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
2213511Sgabeblack@google.com
2313511Sgabeblack@google.com#include <systemc>
2413511Sgabeblack@google.com#include <tlm>
2513513Sgabeblack@google.com#include <vector>
2613511Sgabeblack@google.com
2713513Sgabeblack@google.comnamespace tlm_utils
2813513Sgabeblack@google.com{
2913511Sgabeblack@google.com
3013511Sgabeblack@google.comtemplate <typename PAYLOAD>
3113511Sgabeblack@google.comclass time_ordered_list
3213511Sgabeblack@google.com{
3313513Sgabeblack@google.com  public:
3413513Sgabeblack@google.com    struct element
3513513Sgabeblack@google.com    {
3613513Sgabeblack@google.com        struct element *next;
3713513Sgabeblack@google.com        PAYLOAD p;
3813513Sgabeblack@google.com        sc_core::sc_time t;
3913513Sgabeblack@google.com        sc_dt::uint64 d;
4013513Sgabeblack@google.com        element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
4113513Sgabeblack@google.com            p(p), t(t), d(d)
4213513Sgabeblack@google.com        {}
4313513Sgabeblack@google.com        element() {}
4413513Sgabeblack@google.com    };
4513511Sgabeblack@google.com
4613513Sgabeblack@google.com    element *nill;
4713513Sgabeblack@google.com    element *empties;
4813513Sgabeblack@google.com    element *list;
4913513Sgabeblack@google.com    unsigned int size;
5013511Sgabeblack@google.com
5113513Sgabeblack@google.com    time_ordered_list() : nill(new element()), empties(NULL),
5213513Sgabeblack@google.com                          list(nill), size(0)
5313513Sgabeblack@google.com    {}
5413511Sgabeblack@google.com
5513513Sgabeblack@google.com    ~time_ordered_list()
5613513Sgabeblack@google.com    {
5713513Sgabeblack@google.com        reset();
5813513Sgabeblack@google.com        while (empties) {
5913513Sgabeblack@google.com            struct element *e = empties->next;
6013513Sgabeblack@google.com            delete empties;
6113513Sgabeblack@google.com            empties = e;
6213513Sgabeblack@google.com        }
6313513Sgabeblack@google.com        delete nill;
6413511Sgabeblack@google.com    }
6513511Sgabeblack@google.com
6613513Sgabeblack@google.com    void
6713513Sgabeblack@google.com    reset()
6813513Sgabeblack@google.com    {
6913513Sgabeblack@google.com        while (size) {
7013513Sgabeblack@google.com            delete_top();
7113513Sgabeblack@google.com        }
7213513Sgabeblack@google.com    }
7313511Sgabeblack@google.com
7413513Sgabeblack@google.com    void
7513513Sgabeblack@google.com    insert(const PAYLOAD &p, sc_core::sc_time t)
7613513Sgabeblack@google.com    {
7713513Sgabeblack@google.com        if (!empties) {
7813513Sgabeblack@google.com            empties = new struct element();
7913513Sgabeblack@google.com            empties->next=NULL;
8013513Sgabeblack@google.com        }
8113513Sgabeblack@google.com
8213513Sgabeblack@google.com        struct element *e = empties;
8313513Sgabeblack@google.com        empties = empties->next;
8413513Sgabeblack@google.com        e->p = p;
8513513Sgabeblack@google.com        e->t = t;
8613513Sgabeblack@google.com        e->d = sc_core::sc_delta_count();
8713513Sgabeblack@google.com
8813513Sgabeblack@google.com        struct element *ancestor = nill;
8913513Sgabeblack@google.com        struct element *iterator = list;
9013513Sgabeblack@google.com        while (iterator != nill && iterator->t <= t) {
9113513Sgabeblack@google.com            ancestor = iterator;
9213513Sgabeblack@google.com            iterator = iterator->next;
9313513Sgabeblack@google.com        }
9413513Sgabeblack@google.com        if (ancestor == nill) {
9513513Sgabeblack@google.com            e->next = list;
9613513Sgabeblack@google.com            list = e;
9713513Sgabeblack@google.com        } else {
9813513Sgabeblack@google.com            e->next = iterator;
9913513Sgabeblack@google.com            ancestor->next = e;
10013513Sgabeblack@google.com        }
10113513Sgabeblack@google.com        size++;
10213511Sgabeblack@google.com    }
10313513Sgabeblack@google.com
10413513Sgabeblack@google.com    void
10513513Sgabeblack@google.com    delete_top()
10613513Sgabeblack@google.com    {
10713513Sgabeblack@google.com        if (list != nill) {
10813513Sgabeblack@google.com            struct element *e = list;
10913513Sgabeblack@google.com            list = list->next;
11013513Sgabeblack@google.com            e->next = empties;
11113513Sgabeblack@google.com            empties = e;
11213513Sgabeblack@google.com            size--;
11313513Sgabeblack@google.com        }
11413511Sgabeblack@google.com    }
11513511Sgabeblack@google.com
11613513Sgabeblack@google.com    unsigned int get_size() { return size; }
11713513Sgabeblack@google.com    PAYLOAD &top() { return list->p; }
11813513Sgabeblack@google.com    sc_core::sc_time top_time() { return list->t; }
11913513Sgabeblack@google.com    sc_dt::uint64 &top_delta() { return list->d; }
12013513Sgabeblack@google.com    sc_core::sc_time next_time() { return list->next->t; }
12113511Sgabeblack@google.com};
12213511Sgabeblack@google.com
12313511Sgabeblack@google.com//---------------------------------------------------------------------------
12413511Sgabeblack@google.com/**
12513511Sgabeblack@google.com * An event queue that can contain any number of pending
12613511Sgabeblack@google.com * notifications. Each notification have an associate payload.
12713511Sgabeblack@google.com */
12813511Sgabeblack@google.com//---------------------------------------------------------------------------
12913513Sgabeblack@google.comtemplate<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
13013513Sgabeblack@google.comclass peq_with_cb_and_phase : public sc_core::sc_object
13113511Sgabeblack@google.com{
13213513Sgabeblack@google.com    typedef typename TYPES::tlm_payload_type tlm_payload_type;
13313513Sgabeblack@google.com    typedef typename TYPES::tlm_phase_type tlm_phase_type;
13413513Sgabeblack@google.com    typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
13513513Sgabeblack@google.com    typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
13613511Sgabeblack@google.com
13713513Sgabeblack@google.com    class delta_list
13813513Sgabeblack@google.com    {
13913513Sgabeblack@google.com      public:
14013513Sgabeblack@google.com        delta_list()
14113513Sgabeblack@google.com        {
14213513Sgabeblack@google.com            reset();
14313513Sgabeblack@google.com            entries.resize(100);
14413513Sgabeblack@google.com        }
14513511Sgabeblack@google.com
14613513Sgabeblack@google.com        inline void
14713513Sgabeblack@google.com        insert(const PAYLOAD &p)
14813513Sgabeblack@google.com        {
14913513Sgabeblack@google.com            if (size==entries.size()) {
15013513Sgabeblack@google.com                entries.resize(entries.size() * 2);
15113513Sgabeblack@google.com            }
15213513Sgabeblack@google.com            entries[size++] = p;
15313513Sgabeblack@google.com        }
15413513Sgabeblack@google.com
15513513Sgabeblack@google.com        inline PAYLOAD &get() { return entries[out++]; }
15613513Sgabeblack@google.com        inline bool next() { return out < size; }
15713513Sgabeblack@google.com        inline void
15813513Sgabeblack@google.com        reset()
15913513Sgabeblack@google.com        {
16013513Sgabeblack@google.com            size=0;
16113513Sgabeblack@google.com            out=0;
16213513Sgabeblack@google.com        }
16313513Sgabeblack@google.com
16413513Sgabeblack@google.com      public:
16513513Sgabeblack@google.com        unsigned int size;
16613513Sgabeblack@google.com
16713513Sgabeblack@google.com      private:
16813513Sgabeblack@google.com        std::vector<PAYLOAD> entries;
16913513Sgabeblack@google.com        unsigned int out;
17013513Sgabeblack@google.com    };
17113513Sgabeblack@google.com
17213511Sgabeblack@google.com  public:
17313513Sgabeblack@google.com    peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
17413513Sgabeblack@google.com        sc_core::sc_object(sc_core::sc_gen_unique_name(
17513513Sgabeblack@google.com                    "peq_with_cb_and_phase")),
17613513Sgabeblack@google.com        m_owner(_owner), m_cb(_cb)
17713513Sgabeblack@google.com    {
17813513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
17913513Sgabeblack@google.com        opts.spawn_method();
18013513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
18113513Sgabeblack@google.com        opts.dont_initialize();
18213513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
18313513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
18413511Sgabeblack@google.com    }
18513511Sgabeblack@google.com
18613513Sgabeblack@google.com    peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
18713513Sgabeblack@google.com        sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
18813513Sgabeblack@google.com    {
18913513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
19013513Sgabeblack@google.com        opts.spawn_method();
19113513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
19213513Sgabeblack@google.com        opts.dont_initialize();
19313513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
19413513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
19513511Sgabeblack@google.com    }
19613511Sgabeblack@google.com
19713513Sgabeblack@google.com    ~peq_with_cb_and_phase() {}
19813513Sgabeblack@google.com
19913513Sgabeblack@google.com    void
20013513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p,
20113513Sgabeblack@google.com            const sc_core::sc_time &when)
20213513Sgabeblack@google.com    {
20313513Sgabeblack@google.com        if (when == sc_core::SC_ZERO_TIME) {
20413513Sgabeblack@google.com            if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
20513513Sgabeblack@google.com                // Uneven delta cycle so delta delay is for even cycle.
20613513Sgabeblack@google.com                m_even_delta.insert(PAYLOAD(&t,p));
20713513Sgabeblack@google.com            } else {
20813513Sgabeblack@google.com                // Even delta cycle so delta delay is for uneven delta.
20913513Sgabeblack@google.com                m_uneven_delta.insert(PAYLOAD(&t, p));
21013513Sgabeblack@google.com            }
21113513Sgabeblack@google.com            m_e.notify(sc_core::SC_ZERO_TIME);
21213513Sgabeblack@google.com        } else {
21313513Sgabeblack@google.com            m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
21413513Sgabeblack@google.com            // Note, this will only overwrite the "newest" event.
21513513Sgabeblack@google.com            m_e.notify(when);
21613513Sgabeblack@google.com        }
21713511Sgabeblack@google.com    }
21813511Sgabeblack@google.com
21913513Sgabeblack@google.com    void
22013513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p)
22113513Sgabeblack@google.com    {
22213513Sgabeblack@google.com        m_immediate_yield.insert(PAYLOAD(&t, p));
22313513Sgabeblack@google.com        m_e.notify(); // Immediate notification.
22413511Sgabeblack@google.com    }
22513511Sgabeblack@google.com
22613513Sgabeblack@google.com    // Cancel all events from the event queue.
22713513Sgabeblack@google.com    void
22813513Sgabeblack@google.com    cancel_all()
22913513Sgabeblack@google.com    {
23013513Sgabeblack@google.com        m_ppq.reset();
23113513Sgabeblack@google.com        m_uneven_delta.reset();
23213513Sgabeblack@google.com        m_even_delta.reset();
23313513Sgabeblack@google.com        m_immediate_yield.reset();
23413513Sgabeblack@google.com        m_e.cancel();
23513511Sgabeblack@google.com    }
23613511Sgabeblack@google.com
23713513Sgabeblack@google.com  private:
23813513Sgabeblack@google.com    void
23913513Sgabeblack@google.com    fec()
24013513Sgabeblack@google.com    {
24113513Sgabeblack@google.com        // Immediate yield notifications.
24213513Sgabeblack@google.com        while (m_immediate_yield.next()) {
24313513Sgabeblack@google.com            PAYLOAD &tmp = m_immediate_yield.get();
24413513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
24513513Sgabeblack@google.com        }
24613513Sgabeblack@google.com        m_immediate_yield.reset();
24713511Sgabeblack@google.com
24813513Sgabeblack@google.com        // Delta notifications.
24913513Sgabeblack@google.com        if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
25013513Sgabeblack@google.com            // Uneven delta so put out all payloads for uneven delta.
25113513Sgabeblack@google.com            while (m_uneven_delta.next()) {
25213513Sgabeblack@google.com                PAYLOAD &tmp = m_uneven_delta.get();
25313513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
25413513Sgabeblack@google.com            }
25513513Sgabeblack@google.com            m_uneven_delta.reset();
25613513Sgabeblack@google.com            if (m_even_delta.size)
25713513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
25813513Sgabeblack@google.com        } else {
25913513Sgabeblack@google.com            while (m_even_delta.next()) {
26013513Sgabeblack@google.com                PAYLOAD &tmp = m_even_delta.get();
26113513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
26213513Sgabeblack@google.com            }
26313513Sgabeblack@google.com            m_even_delta.reset();
26413513Sgabeblack@google.com            if (m_uneven_delta.size)
26513513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
26613513Sgabeblack@google.com        }
26713513Sgabeblack@google.com        if (!m_ppq.get_size())
26813513Sgabeblack@google.com            return; // There were only delta notification.
26913511Sgabeblack@google.com
27013513Sgabeblack@google.com        // Timed notifications.
27113513Sgabeblack@google.com        const sc_core::sc_time now = sc_core::sc_time_stamp();
27213513Sgabeblack@google.com        sc_core::sc_time top = m_ppq.top_time();
27313511Sgabeblack@google.com
27413513Sgabeblack@google.com        while (m_ppq.get_size() && top == now) {
27513513Sgabeblack@google.com            // Push all active ones into target.
27613513Sgabeblack@google.com            PAYLOAD &tmp = m_ppq.top();
27713513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
27813513Sgabeblack@google.com            m_ppq.delete_top();
27913513Sgabeblack@google.com            top = m_ppq.top_time();
28013513Sgabeblack@google.com        }
28113513Sgabeblack@google.com        if (m_ppq.get_size()) {
28213513Sgabeblack@google.com            m_e.notify(top - now);
28313513Sgabeblack@google.com        }
28413513Sgabeblack@google.com    }
28513513Sgabeblack@google.com
28613513Sgabeblack@google.com    OWNER *m_owner;
28713513Sgabeblack@google.com    cb m_cb;
28813513Sgabeblack@google.com
28913513Sgabeblack@google.com    time_ordered_list<PAYLOAD> m_ppq;
29013513Sgabeblack@google.com    delta_list m_uneven_delta;
29113513Sgabeblack@google.com    delta_list m_even_delta;
29213513Sgabeblack@google.com    delta_list m_immediate_yield;
29313513Sgabeblack@google.com
29413513Sgabeblack@google.com    sc_core::sc_event m_e; // Default event.
29513511Sgabeblack@google.com};
29613511Sgabeblack@google.com
29713513Sgabeblack@google.com} // namespace tlm_utils
29813511Sgabeblack@google.com
29913513Sgabeblack@google.com#endif /* __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ */
300