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
2313513Sgabeblack@google.com#include <vector>
2413511Sgabeblack@google.com
2513586Sgabeblack@google.com#include "../core/sc_main.hh"
2613586Sgabeblack@google.com#include "../core/sc_object.hh"
2713586Sgabeblack@google.com#include "../core/sc_spawn.hh"
2813586Sgabeblack@google.com#include "../core/sc_time.hh"
2913586Sgabeblack@google.com#include "../dt/int/sc_nbdefs.hh"
3013743Sgabeblack@google.com#include "../tlm_core/2/interfaces/fw_bw_ifs.hh"
3113586Sgabeblack@google.com
3213513Sgabeblack@google.comnamespace tlm_utils
3313513Sgabeblack@google.com{
3413511Sgabeblack@google.com
3513511Sgabeblack@google.comtemplate <typename PAYLOAD>
3613511Sgabeblack@google.comclass time_ordered_list
3713511Sgabeblack@google.com{
3813513Sgabeblack@google.com  public:
3913513Sgabeblack@google.com    struct element
4013513Sgabeblack@google.com    {
4113513Sgabeblack@google.com        struct element *next;
4213513Sgabeblack@google.com        PAYLOAD p;
4313513Sgabeblack@google.com        sc_core::sc_time t;
4413513Sgabeblack@google.com        sc_dt::uint64 d;
4513513Sgabeblack@google.com        element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
4613513Sgabeblack@google.com            p(p), t(t), d(d)
4713513Sgabeblack@google.com        {}
4813513Sgabeblack@google.com        element() {}
4913513Sgabeblack@google.com    };
5013511Sgabeblack@google.com
5113513Sgabeblack@google.com    element *nill;
5213513Sgabeblack@google.com    element *empties;
5313513Sgabeblack@google.com    element *list;
5413513Sgabeblack@google.com    unsigned int size;
5513511Sgabeblack@google.com
5613513Sgabeblack@google.com    time_ordered_list() : nill(new element()), empties(NULL),
5713513Sgabeblack@google.com                          list(nill), size(0)
5813513Sgabeblack@google.com    {}
5913511Sgabeblack@google.com
6013513Sgabeblack@google.com    ~time_ordered_list()
6113513Sgabeblack@google.com    {
6213513Sgabeblack@google.com        reset();
6313513Sgabeblack@google.com        while (empties) {
6413513Sgabeblack@google.com            struct element *e = empties->next;
6513513Sgabeblack@google.com            delete empties;
6613513Sgabeblack@google.com            empties = e;
6713513Sgabeblack@google.com        }
6813513Sgabeblack@google.com        delete nill;
6913511Sgabeblack@google.com    }
7013511Sgabeblack@google.com
7113513Sgabeblack@google.com    void
7213513Sgabeblack@google.com    reset()
7313513Sgabeblack@google.com    {
7413513Sgabeblack@google.com        while (size) {
7513513Sgabeblack@google.com            delete_top();
7613513Sgabeblack@google.com        }
7713513Sgabeblack@google.com    }
7813511Sgabeblack@google.com
7913513Sgabeblack@google.com    void
8013513Sgabeblack@google.com    insert(const PAYLOAD &p, sc_core::sc_time t)
8113513Sgabeblack@google.com    {
8213513Sgabeblack@google.com        if (!empties) {
8313513Sgabeblack@google.com            empties = new struct element();
8413513Sgabeblack@google.com            empties->next=NULL;
8513513Sgabeblack@google.com        }
8613513Sgabeblack@google.com
8713513Sgabeblack@google.com        struct element *e = empties;
8813513Sgabeblack@google.com        empties = empties->next;
8913513Sgabeblack@google.com        e->p = p;
9013513Sgabeblack@google.com        e->t = t;
9113513Sgabeblack@google.com        e->d = sc_core::sc_delta_count();
9213513Sgabeblack@google.com
9313513Sgabeblack@google.com        struct element *ancestor = nill;
9413513Sgabeblack@google.com        struct element *iterator = list;
9513513Sgabeblack@google.com        while (iterator != nill && iterator->t <= t) {
9613513Sgabeblack@google.com            ancestor = iterator;
9713513Sgabeblack@google.com            iterator = iterator->next;
9813513Sgabeblack@google.com        }
9913513Sgabeblack@google.com        if (ancestor == nill) {
10013513Sgabeblack@google.com            e->next = list;
10113513Sgabeblack@google.com            list = e;
10213513Sgabeblack@google.com        } else {
10313513Sgabeblack@google.com            e->next = iterator;
10413513Sgabeblack@google.com            ancestor->next = e;
10513513Sgabeblack@google.com        }
10613513Sgabeblack@google.com        size++;
10713511Sgabeblack@google.com    }
10813513Sgabeblack@google.com
10913513Sgabeblack@google.com    void
11013513Sgabeblack@google.com    delete_top()
11113513Sgabeblack@google.com    {
11213513Sgabeblack@google.com        if (list != nill) {
11313513Sgabeblack@google.com            struct element *e = list;
11413513Sgabeblack@google.com            list = list->next;
11513513Sgabeblack@google.com            e->next = empties;
11613513Sgabeblack@google.com            empties = e;
11713513Sgabeblack@google.com            size--;
11813513Sgabeblack@google.com        }
11913511Sgabeblack@google.com    }
12013511Sgabeblack@google.com
12113513Sgabeblack@google.com    unsigned int get_size() { return size; }
12213513Sgabeblack@google.com    PAYLOAD &top() { return list->p; }
12313513Sgabeblack@google.com    sc_core::sc_time top_time() { return list->t; }
12413513Sgabeblack@google.com    sc_dt::uint64 &top_delta() { return list->d; }
12513513Sgabeblack@google.com    sc_core::sc_time next_time() { return list->next->t; }
12613511Sgabeblack@google.com};
12713511Sgabeblack@google.com
12813511Sgabeblack@google.com//---------------------------------------------------------------------------
12913511Sgabeblack@google.com/**
13013511Sgabeblack@google.com * An event queue that can contain any number of pending
13113511Sgabeblack@google.com * notifications. Each notification have an associate payload.
13213511Sgabeblack@google.com */
13313511Sgabeblack@google.com//---------------------------------------------------------------------------
13413513Sgabeblack@google.comtemplate<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
13513513Sgabeblack@google.comclass peq_with_cb_and_phase : public sc_core::sc_object
13613511Sgabeblack@google.com{
13713513Sgabeblack@google.com    typedef typename TYPES::tlm_payload_type tlm_payload_type;
13813513Sgabeblack@google.com    typedef typename TYPES::tlm_phase_type tlm_phase_type;
13913513Sgabeblack@google.com    typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
14013513Sgabeblack@google.com    typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
14113511Sgabeblack@google.com
14213513Sgabeblack@google.com    class delta_list
14313513Sgabeblack@google.com    {
14413513Sgabeblack@google.com      public:
14513513Sgabeblack@google.com        delta_list()
14613513Sgabeblack@google.com        {
14713513Sgabeblack@google.com            reset();
14813513Sgabeblack@google.com            entries.resize(100);
14913513Sgabeblack@google.com        }
15013511Sgabeblack@google.com
15113513Sgabeblack@google.com        inline void
15213513Sgabeblack@google.com        insert(const PAYLOAD &p)
15313513Sgabeblack@google.com        {
15413513Sgabeblack@google.com            if (size==entries.size()) {
15513513Sgabeblack@google.com                entries.resize(entries.size() * 2);
15613513Sgabeblack@google.com            }
15713513Sgabeblack@google.com            entries[size++] = p;
15813513Sgabeblack@google.com        }
15913513Sgabeblack@google.com
16013513Sgabeblack@google.com        inline PAYLOAD &get() { return entries[out++]; }
16113513Sgabeblack@google.com        inline bool next() { return out < size; }
16213513Sgabeblack@google.com        inline void
16313513Sgabeblack@google.com        reset()
16413513Sgabeblack@google.com        {
16513513Sgabeblack@google.com            size=0;
16613513Sgabeblack@google.com            out=0;
16713513Sgabeblack@google.com        }
16813513Sgabeblack@google.com
16913513Sgabeblack@google.com      public:
17013513Sgabeblack@google.com        unsigned int size;
17113513Sgabeblack@google.com
17213513Sgabeblack@google.com      private:
17313513Sgabeblack@google.com        std::vector<PAYLOAD> entries;
17413513Sgabeblack@google.com        unsigned int out;
17513513Sgabeblack@google.com    };
17613513Sgabeblack@google.com
17713511Sgabeblack@google.com  public:
17813513Sgabeblack@google.com    peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
17913513Sgabeblack@google.com        sc_core::sc_object(sc_core::sc_gen_unique_name(
18013513Sgabeblack@google.com                    "peq_with_cb_and_phase")),
18113513Sgabeblack@google.com        m_owner(_owner), m_cb(_cb)
18213513Sgabeblack@google.com    {
18313513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
18413513Sgabeblack@google.com        opts.spawn_method();
18513513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
18613513Sgabeblack@google.com        opts.dont_initialize();
18713513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
18813513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
18913511Sgabeblack@google.com    }
19013511Sgabeblack@google.com
19113513Sgabeblack@google.com    peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
19213513Sgabeblack@google.com        sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
19313513Sgabeblack@google.com    {
19413513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
19513513Sgabeblack@google.com        opts.spawn_method();
19613513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
19713513Sgabeblack@google.com        opts.dont_initialize();
19813513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
19913513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
20013511Sgabeblack@google.com    }
20113511Sgabeblack@google.com
20213513Sgabeblack@google.com    ~peq_with_cb_and_phase() {}
20313513Sgabeblack@google.com
20413513Sgabeblack@google.com    void
20513513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p,
20613513Sgabeblack@google.com            const sc_core::sc_time &when)
20713513Sgabeblack@google.com    {
20813513Sgabeblack@google.com        if (when == sc_core::SC_ZERO_TIME) {
20913513Sgabeblack@google.com            if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
21013513Sgabeblack@google.com                // Uneven delta cycle so delta delay is for even cycle.
21113513Sgabeblack@google.com                m_even_delta.insert(PAYLOAD(&t,p));
21213513Sgabeblack@google.com            } else {
21313513Sgabeblack@google.com                // Even delta cycle so delta delay is for uneven delta.
21413513Sgabeblack@google.com                m_uneven_delta.insert(PAYLOAD(&t, p));
21513513Sgabeblack@google.com            }
21613513Sgabeblack@google.com            m_e.notify(sc_core::SC_ZERO_TIME);
21713513Sgabeblack@google.com        } else {
21813513Sgabeblack@google.com            m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
21913513Sgabeblack@google.com            // Note, this will only overwrite the "newest" event.
22013513Sgabeblack@google.com            m_e.notify(when);
22113513Sgabeblack@google.com        }
22213511Sgabeblack@google.com    }
22313511Sgabeblack@google.com
22413513Sgabeblack@google.com    void
22513513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p)
22613513Sgabeblack@google.com    {
22713513Sgabeblack@google.com        m_immediate_yield.insert(PAYLOAD(&t, p));
22813513Sgabeblack@google.com        m_e.notify(); // Immediate notification.
22913511Sgabeblack@google.com    }
23013511Sgabeblack@google.com
23113513Sgabeblack@google.com    // Cancel all events from the event queue.
23213513Sgabeblack@google.com    void
23313513Sgabeblack@google.com    cancel_all()
23413513Sgabeblack@google.com    {
23513513Sgabeblack@google.com        m_ppq.reset();
23613513Sgabeblack@google.com        m_uneven_delta.reset();
23713513Sgabeblack@google.com        m_even_delta.reset();
23813513Sgabeblack@google.com        m_immediate_yield.reset();
23913513Sgabeblack@google.com        m_e.cancel();
24013511Sgabeblack@google.com    }
24113511Sgabeblack@google.com
24213513Sgabeblack@google.com  private:
24313513Sgabeblack@google.com    void
24413513Sgabeblack@google.com    fec()
24513513Sgabeblack@google.com    {
24613513Sgabeblack@google.com        // Immediate yield notifications.
24713513Sgabeblack@google.com        while (m_immediate_yield.next()) {
24813513Sgabeblack@google.com            PAYLOAD &tmp = m_immediate_yield.get();
24913513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
25013513Sgabeblack@google.com        }
25113513Sgabeblack@google.com        m_immediate_yield.reset();
25213511Sgabeblack@google.com
25313513Sgabeblack@google.com        // Delta notifications.
25413513Sgabeblack@google.com        if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
25513513Sgabeblack@google.com            // Uneven delta so put out all payloads for uneven delta.
25613513Sgabeblack@google.com            while (m_uneven_delta.next()) {
25713513Sgabeblack@google.com                PAYLOAD &tmp = m_uneven_delta.get();
25813513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
25913513Sgabeblack@google.com            }
26013513Sgabeblack@google.com            m_uneven_delta.reset();
26113513Sgabeblack@google.com            if (m_even_delta.size)
26213513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
26313513Sgabeblack@google.com        } else {
26413513Sgabeblack@google.com            while (m_even_delta.next()) {
26513513Sgabeblack@google.com                PAYLOAD &tmp = m_even_delta.get();
26613513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
26713513Sgabeblack@google.com            }
26813513Sgabeblack@google.com            m_even_delta.reset();
26913513Sgabeblack@google.com            if (m_uneven_delta.size)
27013513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
27113513Sgabeblack@google.com        }
27213513Sgabeblack@google.com        if (!m_ppq.get_size())
27313513Sgabeblack@google.com            return; // There were only delta notification.
27413511Sgabeblack@google.com
27513513Sgabeblack@google.com        // Timed notifications.
27613513Sgabeblack@google.com        const sc_core::sc_time now = sc_core::sc_time_stamp();
27713513Sgabeblack@google.com        sc_core::sc_time top = m_ppq.top_time();
27813511Sgabeblack@google.com
27913513Sgabeblack@google.com        while (m_ppq.get_size() && top == now) {
28013513Sgabeblack@google.com            // Push all active ones into target.
28113513Sgabeblack@google.com            PAYLOAD &tmp = m_ppq.top();
28213513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
28313513Sgabeblack@google.com            m_ppq.delete_top();
28413513Sgabeblack@google.com            top = m_ppq.top_time();
28513513Sgabeblack@google.com        }
28613513Sgabeblack@google.com        if (m_ppq.get_size()) {
28713513Sgabeblack@google.com            m_e.notify(top - now);
28813513Sgabeblack@google.com        }
28913513Sgabeblack@google.com    }
29013513Sgabeblack@google.com
29113513Sgabeblack@google.com    OWNER *m_owner;
29213513Sgabeblack@google.com    cb m_cb;
29313513Sgabeblack@google.com
29413513Sgabeblack@google.com    time_ordered_list<PAYLOAD> m_ppq;
29513513Sgabeblack@google.com    delta_list m_uneven_delta;
29613513Sgabeblack@google.com    delta_list m_even_delta;
29713513Sgabeblack@google.com    delta_list m_immediate_yield;
29813513Sgabeblack@google.com
29913513Sgabeblack@google.com    sc_core::sc_event m_e; // Default event.
30013511Sgabeblack@google.com};
30113511Sgabeblack@google.com
30213513Sgabeblack@google.com} // namespace tlm_utils
30313511Sgabeblack@google.com
30413513Sgabeblack@google.com#endif /* __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ */
305