peq_with_cb_and_phase.h revision 13586
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"
3013586Sgabeblack@google.com
3113513Sgabeblack@google.comnamespace tlm_utils
3213513Sgabeblack@google.com{
3313511Sgabeblack@google.com
3413511Sgabeblack@google.comtemplate <typename PAYLOAD>
3513511Sgabeblack@google.comclass time_ordered_list
3613511Sgabeblack@google.com{
3713513Sgabeblack@google.com  public:
3813513Sgabeblack@google.com    struct element
3913513Sgabeblack@google.com    {
4013513Sgabeblack@google.com        struct element *next;
4113513Sgabeblack@google.com        PAYLOAD p;
4213513Sgabeblack@google.com        sc_core::sc_time t;
4313513Sgabeblack@google.com        sc_dt::uint64 d;
4413513Sgabeblack@google.com        element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
4513513Sgabeblack@google.com            p(p), t(t), d(d)
4613513Sgabeblack@google.com        {}
4713513Sgabeblack@google.com        element() {}
4813513Sgabeblack@google.com    };
4913511Sgabeblack@google.com
5013513Sgabeblack@google.com    element *nill;
5113513Sgabeblack@google.com    element *empties;
5213513Sgabeblack@google.com    element *list;
5313513Sgabeblack@google.com    unsigned int size;
5413511Sgabeblack@google.com
5513513Sgabeblack@google.com    time_ordered_list() : nill(new element()), empties(NULL),
5613513Sgabeblack@google.com                          list(nill), size(0)
5713513Sgabeblack@google.com    {}
5813511Sgabeblack@google.com
5913513Sgabeblack@google.com    ~time_ordered_list()
6013513Sgabeblack@google.com    {
6113513Sgabeblack@google.com        reset();
6213513Sgabeblack@google.com        while (empties) {
6313513Sgabeblack@google.com            struct element *e = empties->next;
6413513Sgabeblack@google.com            delete empties;
6513513Sgabeblack@google.com            empties = e;
6613513Sgabeblack@google.com        }
6713513Sgabeblack@google.com        delete nill;
6813511Sgabeblack@google.com    }
6913511Sgabeblack@google.com
7013513Sgabeblack@google.com    void
7113513Sgabeblack@google.com    reset()
7213513Sgabeblack@google.com    {
7313513Sgabeblack@google.com        while (size) {
7413513Sgabeblack@google.com            delete_top();
7513513Sgabeblack@google.com        }
7613513Sgabeblack@google.com    }
7713511Sgabeblack@google.com
7813513Sgabeblack@google.com    void
7913513Sgabeblack@google.com    insert(const PAYLOAD &p, sc_core::sc_time t)
8013513Sgabeblack@google.com    {
8113513Sgabeblack@google.com        if (!empties) {
8213513Sgabeblack@google.com            empties = new struct element();
8313513Sgabeblack@google.com            empties->next=NULL;
8413513Sgabeblack@google.com        }
8513513Sgabeblack@google.com
8613513Sgabeblack@google.com        struct element *e = empties;
8713513Sgabeblack@google.com        empties = empties->next;
8813513Sgabeblack@google.com        e->p = p;
8913513Sgabeblack@google.com        e->t = t;
9013513Sgabeblack@google.com        e->d = sc_core::sc_delta_count();
9113513Sgabeblack@google.com
9213513Sgabeblack@google.com        struct element *ancestor = nill;
9313513Sgabeblack@google.com        struct element *iterator = list;
9413513Sgabeblack@google.com        while (iterator != nill && iterator->t <= t) {
9513513Sgabeblack@google.com            ancestor = iterator;
9613513Sgabeblack@google.com            iterator = iterator->next;
9713513Sgabeblack@google.com        }
9813513Sgabeblack@google.com        if (ancestor == nill) {
9913513Sgabeblack@google.com            e->next = list;
10013513Sgabeblack@google.com            list = e;
10113513Sgabeblack@google.com        } else {
10213513Sgabeblack@google.com            e->next = iterator;
10313513Sgabeblack@google.com            ancestor->next = e;
10413513Sgabeblack@google.com        }
10513513Sgabeblack@google.com        size++;
10613511Sgabeblack@google.com    }
10713513Sgabeblack@google.com
10813513Sgabeblack@google.com    void
10913513Sgabeblack@google.com    delete_top()
11013513Sgabeblack@google.com    {
11113513Sgabeblack@google.com        if (list != nill) {
11213513Sgabeblack@google.com            struct element *e = list;
11313513Sgabeblack@google.com            list = list->next;
11413513Sgabeblack@google.com            e->next = empties;
11513513Sgabeblack@google.com            empties = e;
11613513Sgabeblack@google.com            size--;
11713513Sgabeblack@google.com        }
11813511Sgabeblack@google.com    }
11913511Sgabeblack@google.com
12013513Sgabeblack@google.com    unsigned int get_size() { return size; }
12113513Sgabeblack@google.com    PAYLOAD &top() { return list->p; }
12213513Sgabeblack@google.com    sc_core::sc_time top_time() { return list->t; }
12313513Sgabeblack@google.com    sc_dt::uint64 &top_delta() { return list->d; }
12413513Sgabeblack@google.com    sc_core::sc_time next_time() { return list->next->t; }
12513511Sgabeblack@google.com};
12613511Sgabeblack@google.com
12713511Sgabeblack@google.com//---------------------------------------------------------------------------
12813511Sgabeblack@google.com/**
12913511Sgabeblack@google.com * An event queue that can contain any number of pending
13013511Sgabeblack@google.com * notifications. Each notification have an associate payload.
13113511Sgabeblack@google.com */
13213511Sgabeblack@google.com//---------------------------------------------------------------------------
13313513Sgabeblack@google.comtemplate<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
13413513Sgabeblack@google.comclass peq_with_cb_and_phase : public sc_core::sc_object
13513511Sgabeblack@google.com{
13613513Sgabeblack@google.com    typedef typename TYPES::tlm_payload_type tlm_payload_type;
13713513Sgabeblack@google.com    typedef typename TYPES::tlm_phase_type tlm_phase_type;
13813513Sgabeblack@google.com    typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
13913513Sgabeblack@google.com    typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
14013511Sgabeblack@google.com
14113513Sgabeblack@google.com    class delta_list
14213513Sgabeblack@google.com    {
14313513Sgabeblack@google.com      public:
14413513Sgabeblack@google.com        delta_list()
14513513Sgabeblack@google.com        {
14613513Sgabeblack@google.com            reset();
14713513Sgabeblack@google.com            entries.resize(100);
14813513Sgabeblack@google.com        }
14913511Sgabeblack@google.com
15013513Sgabeblack@google.com        inline void
15113513Sgabeblack@google.com        insert(const PAYLOAD &p)
15213513Sgabeblack@google.com        {
15313513Sgabeblack@google.com            if (size==entries.size()) {
15413513Sgabeblack@google.com                entries.resize(entries.size() * 2);
15513513Sgabeblack@google.com            }
15613513Sgabeblack@google.com            entries[size++] = p;
15713513Sgabeblack@google.com        }
15813513Sgabeblack@google.com
15913513Sgabeblack@google.com        inline PAYLOAD &get() { return entries[out++]; }
16013513Sgabeblack@google.com        inline bool next() { return out < size; }
16113513Sgabeblack@google.com        inline void
16213513Sgabeblack@google.com        reset()
16313513Sgabeblack@google.com        {
16413513Sgabeblack@google.com            size=0;
16513513Sgabeblack@google.com            out=0;
16613513Sgabeblack@google.com        }
16713513Sgabeblack@google.com
16813513Sgabeblack@google.com      public:
16913513Sgabeblack@google.com        unsigned int size;
17013513Sgabeblack@google.com
17113513Sgabeblack@google.com      private:
17213513Sgabeblack@google.com        std::vector<PAYLOAD> entries;
17313513Sgabeblack@google.com        unsigned int out;
17413513Sgabeblack@google.com    };
17513513Sgabeblack@google.com
17613511Sgabeblack@google.com  public:
17713513Sgabeblack@google.com    peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
17813513Sgabeblack@google.com        sc_core::sc_object(sc_core::sc_gen_unique_name(
17913513Sgabeblack@google.com                    "peq_with_cb_and_phase")),
18013513Sgabeblack@google.com        m_owner(_owner), m_cb(_cb)
18113513Sgabeblack@google.com    {
18213513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
18313513Sgabeblack@google.com        opts.spawn_method();
18413513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
18513513Sgabeblack@google.com        opts.dont_initialize();
18613513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
18713513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
18813511Sgabeblack@google.com    }
18913511Sgabeblack@google.com
19013513Sgabeblack@google.com    peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
19113513Sgabeblack@google.com        sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
19213513Sgabeblack@google.com    {
19313513Sgabeblack@google.com        sc_core::sc_spawn_options opts;
19413513Sgabeblack@google.com        opts.spawn_method();
19513513Sgabeblack@google.com        opts.set_sensitivity(&m_e);
19613513Sgabeblack@google.com        opts.dont_initialize();
19713513Sgabeblack@google.com        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
19813513Sgabeblack@google.com                          sc_core::sc_gen_unique_name("fec"), &opts);
19913511Sgabeblack@google.com    }
20013511Sgabeblack@google.com
20113513Sgabeblack@google.com    ~peq_with_cb_and_phase() {}
20213513Sgabeblack@google.com
20313513Sgabeblack@google.com    void
20413513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p,
20513513Sgabeblack@google.com            const sc_core::sc_time &when)
20613513Sgabeblack@google.com    {
20713513Sgabeblack@google.com        if (when == sc_core::SC_ZERO_TIME) {
20813513Sgabeblack@google.com            if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
20913513Sgabeblack@google.com                // Uneven delta cycle so delta delay is for even cycle.
21013513Sgabeblack@google.com                m_even_delta.insert(PAYLOAD(&t,p));
21113513Sgabeblack@google.com            } else {
21213513Sgabeblack@google.com                // Even delta cycle so delta delay is for uneven delta.
21313513Sgabeblack@google.com                m_uneven_delta.insert(PAYLOAD(&t, p));
21413513Sgabeblack@google.com            }
21513513Sgabeblack@google.com            m_e.notify(sc_core::SC_ZERO_TIME);
21613513Sgabeblack@google.com        } else {
21713513Sgabeblack@google.com            m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
21813513Sgabeblack@google.com            // Note, this will only overwrite the "newest" event.
21913513Sgabeblack@google.com            m_e.notify(when);
22013513Sgabeblack@google.com        }
22113511Sgabeblack@google.com    }
22213511Sgabeblack@google.com
22313513Sgabeblack@google.com    void
22413513Sgabeblack@google.com    notify(tlm_payload_type &t, const tlm_phase_type &p)
22513513Sgabeblack@google.com    {
22613513Sgabeblack@google.com        m_immediate_yield.insert(PAYLOAD(&t, p));
22713513Sgabeblack@google.com        m_e.notify(); // Immediate notification.
22813511Sgabeblack@google.com    }
22913511Sgabeblack@google.com
23013513Sgabeblack@google.com    // Cancel all events from the event queue.
23113513Sgabeblack@google.com    void
23213513Sgabeblack@google.com    cancel_all()
23313513Sgabeblack@google.com    {
23413513Sgabeblack@google.com        m_ppq.reset();
23513513Sgabeblack@google.com        m_uneven_delta.reset();
23613513Sgabeblack@google.com        m_even_delta.reset();
23713513Sgabeblack@google.com        m_immediate_yield.reset();
23813513Sgabeblack@google.com        m_e.cancel();
23913511Sgabeblack@google.com    }
24013511Sgabeblack@google.com
24113513Sgabeblack@google.com  private:
24213513Sgabeblack@google.com    void
24313513Sgabeblack@google.com    fec()
24413513Sgabeblack@google.com    {
24513513Sgabeblack@google.com        // Immediate yield notifications.
24613513Sgabeblack@google.com        while (m_immediate_yield.next()) {
24713513Sgabeblack@google.com            PAYLOAD &tmp = m_immediate_yield.get();
24813513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
24913513Sgabeblack@google.com        }
25013513Sgabeblack@google.com        m_immediate_yield.reset();
25113511Sgabeblack@google.com
25213513Sgabeblack@google.com        // Delta notifications.
25313513Sgabeblack@google.com        if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
25413513Sgabeblack@google.com            // Uneven delta so put out all payloads for uneven delta.
25513513Sgabeblack@google.com            while (m_uneven_delta.next()) {
25613513Sgabeblack@google.com                PAYLOAD &tmp = m_uneven_delta.get();
25713513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
25813513Sgabeblack@google.com            }
25913513Sgabeblack@google.com            m_uneven_delta.reset();
26013513Sgabeblack@google.com            if (m_even_delta.size)
26113513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
26213513Sgabeblack@google.com        } else {
26313513Sgabeblack@google.com            while (m_even_delta.next()) {
26413513Sgabeblack@google.com                PAYLOAD &tmp = m_even_delta.get();
26513513Sgabeblack@google.com                (m_owner->*m_cb)(*tmp.first, tmp.second);
26613513Sgabeblack@google.com            }
26713513Sgabeblack@google.com            m_even_delta.reset();
26813513Sgabeblack@google.com            if (m_uneven_delta.size)
26913513Sgabeblack@google.com                m_e.notify(sc_core::SC_ZERO_TIME);
27013513Sgabeblack@google.com        }
27113513Sgabeblack@google.com        if (!m_ppq.get_size())
27213513Sgabeblack@google.com            return; // There were only delta notification.
27313511Sgabeblack@google.com
27413513Sgabeblack@google.com        // Timed notifications.
27513513Sgabeblack@google.com        const sc_core::sc_time now = sc_core::sc_time_stamp();
27613513Sgabeblack@google.com        sc_core::sc_time top = m_ppq.top_time();
27713511Sgabeblack@google.com
27813513Sgabeblack@google.com        while (m_ppq.get_size() && top == now) {
27913513Sgabeblack@google.com            // Push all active ones into target.
28013513Sgabeblack@google.com            PAYLOAD &tmp = m_ppq.top();
28113513Sgabeblack@google.com            (m_owner->*m_cb)(*tmp.first, tmp.second);
28213513Sgabeblack@google.com            m_ppq.delete_top();
28313513Sgabeblack@google.com            top = m_ppq.top_time();
28413513Sgabeblack@google.com        }
28513513Sgabeblack@google.com        if (m_ppq.get_size()) {
28613513Sgabeblack@google.com            m_e.notify(top - now);
28713513Sgabeblack@google.com        }
28813513Sgabeblack@google.com    }
28913513Sgabeblack@google.com
29013513Sgabeblack@google.com    OWNER *m_owner;
29113513Sgabeblack@google.com    cb m_cb;
29213513Sgabeblack@google.com
29313513Sgabeblack@google.com    time_ordered_list<PAYLOAD> m_ppq;
29413513Sgabeblack@google.com    delta_list m_uneven_delta;
29513513Sgabeblack@google.com    delta_list m_even_delta;
29613513Sgabeblack@google.com    delta_list m_immediate_yield;
29713513Sgabeblack@google.com
29813513Sgabeblack@google.com    sc_core::sc_event m_e; // Default event.
29913511Sgabeblack@google.com};
30013511Sgabeblack@google.com
30113513Sgabeblack@google.com} // namespace tlm_utils
30213511Sgabeblack@google.com
30313513Sgabeblack@google.com#endif /* __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__ */
304