peq_with_cb_and_phase.h revision 13586
12SN/A/*****************************************************************************
21762SN/A
32SN/A  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
42SN/A  more contributor license agreements.  See the NOTICE file distributed
52SN/A  with this work for additional information regarding copyright ownership.
62SN/A  Accellera licenses this file to you under the Apache License, Version 2.0
72SN/A  (the "License"); you may not use this file except in compliance with the
82SN/A  License.  You may obtain a copy of the License at
92SN/A
102SN/A    http://www.apache.org/licenses/LICENSE-2.0
112SN/A
122SN/A  Unless required by applicable law or agreed to in writing, software
132SN/A  distributed under the License is distributed on an "AS IS" BASIS,
142SN/A  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152SN/A  implied.  See the License for the specific language governing
162SN/A  permissions and limitations under the License.
172SN/A
182SN/A *****************************************************************************/
192SN/A
202SN/A#ifndef __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
212SN/A#define __SYSTEMC_EXT_TLM_UTILS_PEQ_WITH_CB_AND_PHASE_H__
222SN/A
232SN/A#include <vector>
242SN/A
252SN/A#include "../core/sc_main.hh"
262SN/A#include "../core/sc_object.hh"
272665Ssaidi@eecs.umich.edu#include "../core/sc_spawn.hh"
282665Ssaidi@eecs.umich.edu#include "../core/sc_time.hh"
292665Ssaidi@eecs.umich.edu#include "../dt/int/sc_nbdefs.hh"
302665Ssaidi@eecs.umich.edu
312665Ssaidi@eecs.umich.edunamespace tlm_utils
322SN/A{
332SN/A
342SN/Atemplate <typename PAYLOAD>
352SN/Aclass time_ordered_list
367349SAli.Saidi@ARM.com{
3756SN/A  public:
381717SN/A    struct element
392518SN/A    {
4056SN/A        struct element *next;
414776Sgblack@eecs.umich.edu        PAYLOAD p;
426658Snate@binkert.org        sc_core::sc_time t;
434762Snate@binkert.org        sc_dt::uint64 d;
443065Sgblack@eecs.umich.edu        element(PAYLOAD &p, sc_core::sc_time t, sc_dt::uint64 d) :
452SN/A            p(p), t(t), d(d)
462973Sgblack@eecs.umich.edu        {}
472SN/A        element() {}
483506Ssaidi@eecs.umich.edu    };
494054Sbinkertn@umich.edu
504054Sbinkertn@umich.edu    element *nill;
515866Sksewell@umich.edu    element *empties;
525866Sksewell@umich.edu    element *list;
535866Sksewell@umich.edu    unsigned int size;
545866Sksewell@umich.edu
555866Sksewell@umich.edu    time_ordered_list() : nill(new element()), empties(NULL),
565866Sksewell@umich.edu                          list(nill), size(0)
575784Sgblack@eecs.umich.edu    {}
584054Sbinkertn@umich.edu
594776Sgblack@eecs.umich.edu    ~time_ordered_list()
604054Sbinkertn@umich.edu    {
614776Sgblack@eecs.umich.edu        reset();
625866Sksewell@umich.edu        while (empties) {
634054Sbinkertn@umich.edu            struct element *e = empties->next;
644776Sgblack@eecs.umich.edu            delete empties;
654054Sbinkertn@umich.edu            empties = e;
664776Sgblack@eecs.umich.edu        }
674776Sgblack@eecs.umich.edu        delete nill;
684054Sbinkertn@umich.edu    }
694776Sgblack@eecs.umich.edu
705715Shsul@eecs.umich.edu    void
714776Sgblack@eecs.umich.edu    reset()
724776Sgblack@eecs.umich.edu    {
734776Sgblack@eecs.umich.edu        while (size) {
747349SAli.Saidi@ARM.com            delete_top();
757349SAli.Saidi@ARM.com        }
767349SAli.Saidi@ARM.com    }
777349SAli.Saidi@ARM.com
784776Sgblack@eecs.umich.edu    void
794776Sgblack@eecs.umich.edu    insert(const PAYLOAD &p, sc_core::sc_time t)
805947Sgblack@eecs.umich.edu    {
815947Sgblack@eecs.umich.edu        if (!empties) {
825947Sgblack@eecs.umich.edu            empties = new struct element();
837349SAli.Saidi@ARM.com            empties->next=NULL;
847349SAli.Saidi@ARM.com        }
857349SAli.Saidi@ARM.com
865784Sgblack@eecs.umich.edu        struct element *e = empties;
874776Sgblack@eecs.umich.edu        empties = empties->next;
884776Sgblack@eecs.umich.edu        e->p = p;
897349SAli.Saidi@ARM.com        e->t = t;
904776Sgblack@eecs.umich.edu        e->d = sc_core::sc_delta_count();
914776Sgblack@eecs.umich.edu
925784Sgblack@eecs.umich.edu        struct element *ancestor = nill;
935784Sgblack@eecs.umich.edu        struct element *iterator = list;
945784Sgblack@eecs.umich.edu        while (iterator != nill && iterator->t <= t) {
955784Sgblack@eecs.umich.edu            ancestor = iterator;
965784Sgblack@eecs.umich.edu            iterator = iterator->next;
975784Sgblack@eecs.umich.edu        }
985784Sgblack@eecs.umich.edu        if (ancestor == nill) {
995784Sgblack@eecs.umich.edu            e->next = list;
1004776Sgblack@eecs.umich.edu            list = e;
1014776Sgblack@eecs.umich.edu        } else {
1024776Sgblack@eecs.umich.edu            e->next = iterator;
1034776Sgblack@eecs.umich.edu            ancestor->next = e;
1044776Sgblack@eecs.umich.edu        }
1057349SAli.Saidi@ARM.com        size++;
1064776Sgblack@eecs.umich.edu    }
1075784Sgblack@eecs.umich.edu
1085784Sgblack@eecs.umich.edu    void
1095784Sgblack@eecs.umich.edu    delete_top()
1105784Sgblack@eecs.umich.edu    {
1115784Sgblack@eecs.umich.edu        if (list != nill) {
1125784Sgblack@eecs.umich.edu            struct element *e = list;
1135784Sgblack@eecs.umich.edu            list = list->next;
1147600Sminkyu.jeong@arm.com            e->next = empties;
1157600Sminkyu.jeong@arm.com            empties = e;
1167600Sminkyu.jeong@arm.com            size--;
1177600Sminkyu.jeong@arm.com        }
1185784Sgblack@eecs.umich.edu    }
1195784Sgblack@eecs.umich.edu
1205784Sgblack@eecs.umich.edu    unsigned int get_size() { return size; }
1215784Sgblack@eecs.umich.edu    PAYLOAD &top() { return list->p; }
1225784Sgblack@eecs.umich.edu    sc_core::sc_time top_time() { return list->t; }
1235784Sgblack@eecs.umich.edu    sc_dt::uint64 &top_delta() { return list->d; }
1245784Sgblack@eecs.umich.edu    sc_core::sc_time next_time() { return list->next->t; }
1255784Sgblack@eecs.umich.edu};
1265784Sgblack@eecs.umich.edu
1275784Sgblack@eecs.umich.edu//---------------------------------------------------------------------------
1285784Sgblack@eecs.umich.edu/**
1295784Sgblack@eecs.umich.edu * An event queue that can contain any number of pending
1304776Sgblack@eecs.umich.edu * notifications. Each notification have an associate payload.
1314776Sgblack@eecs.umich.edu */
1324776Sgblack@eecs.umich.edu//---------------------------------------------------------------------------
1334776Sgblack@eecs.umich.edutemplate<typename OWNER, typename TYPES=tlm::tlm_base_protocol_types>
1344776Sgblack@eecs.umich.educlass peq_with_cb_and_phase : public sc_core::sc_object
1354776Sgblack@eecs.umich.edu{
1363506Ssaidi@eecs.umich.edu    typedef typename TYPES::tlm_payload_type tlm_payload_type;
1373506Ssaidi@eecs.umich.edu    typedef typename TYPES::tlm_phase_type tlm_phase_type;
1385784Sgblack@eecs.umich.edu    typedef std::pair<tlm_payload_type *, tlm_phase_type> PAYLOAD;
1395784Sgblack@eecs.umich.edu    typedef void (OWNER::*cb)(tlm_payload_type &, const tlm_phase_type &);
1405784Sgblack@eecs.umich.edu
1415784Sgblack@eecs.umich.edu    class delta_list
1425784Sgblack@eecs.umich.edu    {
1435784Sgblack@eecs.umich.edu      public:
1445784Sgblack@eecs.umich.edu        delta_list()
1455784Sgblack@eecs.umich.edu        {
1465784Sgblack@eecs.umich.edu            reset();
1475784Sgblack@eecs.umich.edu            entries.resize(100);
1485784Sgblack@eecs.umich.edu        }
1495784Sgblack@eecs.umich.edu
1505791Srstrong@cs.ucsd.edu        inline void
1515784Sgblack@eecs.umich.edu        insert(const PAYLOAD &p)
1525784Sgblack@eecs.umich.edu        {
1535791Srstrong@cs.ucsd.edu            if (size==entries.size()) {
1545784Sgblack@eecs.umich.edu                entries.resize(entries.size() * 2);
1555784Sgblack@eecs.umich.edu            }
1565784Sgblack@eecs.umich.edu            entries[size++] = p;
1575784Sgblack@eecs.umich.edu        }
1585784Sgblack@eecs.umich.edu
1595784Sgblack@eecs.umich.edu        inline PAYLOAD &get() { return entries[out++]; }
1605784Sgblack@eecs.umich.edu        inline bool next() { return out < size; }
1614776Sgblack@eecs.umich.edu        inline void
1624776Sgblack@eecs.umich.edu        reset()
1632SN/A        {
1642SN/A            size=0;
1654776Sgblack@eecs.umich.edu            out=0;
1662SN/A        }
1674776Sgblack@eecs.umich.edu
1684776Sgblack@eecs.umich.edu      public:
1693748Sgblack@eecs.umich.edu        unsigned int size;
1705034Smilesck@eecs.umich.edu
1714776Sgblack@eecs.umich.edu      private:
172        std::vector<PAYLOAD> entries;
173        unsigned int out;
174    };
175
176  public:
177    peq_with_cb_and_phase(OWNER *_owner, cb _cb) :
178        sc_core::sc_object(sc_core::sc_gen_unique_name(
179                    "peq_with_cb_and_phase")),
180        m_owner(_owner), m_cb(_cb)
181    {
182        sc_core::sc_spawn_options opts;
183        opts.spawn_method();
184        opts.set_sensitivity(&m_e);
185        opts.dont_initialize();
186        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
187                          sc_core::sc_gen_unique_name("fec"), &opts);
188    }
189
190    peq_with_cb_and_phase(const char *_name, OWNER *_owner, cb _cb) :
191        sc_core::sc_object(_name), m_owner(_owner), m_cb(_cb)
192    {
193        sc_core::sc_spawn_options opts;
194        opts.spawn_method();
195        opts.set_sensitivity(&m_e);
196        opts.dont_initialize();
197        sc_core::sc_spawn(sc_bind(&peq_with_cb_and_phase::fec, this),
198                          sc_core::sc_gen_unique_name("fec"), &opts);
199    }
200
201    ~peq_with_cb_and_phase() {}
202
203    void
204    notify(tlm_payload_type &t, const tlm_phase_type &p,
205            const sc_core::sc_time &when)
206    {
207        if (when == sc_core::SC_ZERO_TIME) {
208            if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
209                // Uneven delta cycle so delta delay is for even cycle.
210                m_even_delta.insert(PAYLOAD(&t,p));
211            } else {
212                // Even delta cycle so delta delay is for uneven delta.
213                m_uneven_delta.insert(PAYLOAD(&t, p));
214            }
215            m_e.notify(sc_core::SC_ZERO_TIME);
216        } else {
217            m_ppq.insert(PAYLOAD(&t, p), when + sc_core::sc_time_stamp());
218            // Note, this will only overwrite the "newest" event.
219            m_e.notify(when);
220        }
221    }
222
223    void
224    notify(tlm_payload_type &t, const tlm_phase_type &p)
225    {
226        m_immediate_yield.insert(PAYLOAD(&t, p));
227        m_e.notify(); // Immediate notification.
228    }
229
230    // Cancel all events from the event queue.
231    void
232    cancel_all()
233    {
234        m_ppq.reset();
235        m_uneven_delta.reset();
236        m_even_delta.reset();
237        m_immediate_yield.reset();
238        m_e.cancel();
239    }
240
241  private:
242    void
243    fec()
244    {
245        // Immediate yield notifications.
246        while (m_immediate_yield.next()) {
247            PAYLOAD &tmp = m_immediate_yield.get();
248            (m_owner->*m_cb)(*tmp.first, tmp.second);
249        }
250        m_immediate_yield.reset();
251
252        // Delta notifications.
253        if (sc_core::sc_delta_count() & (sc_dt::uint64)0x1) {
254            // Uneven delta so put out all payloads for uneven delta.
255            while (m_uneven_delta.next()) {
256                PAYLOAD &tmp = m_uneven_delta.get();
257                (m_owner->*m_cb)(*tmp.first, tmp.second);
258            }
259            m_uneven_delta.reset();
260            if (m_even_delta.size)
261                m_e.notify(sc_core::SC_ZERO_TIME);
262        } else {
263            while (m_even_delta.next()) {
264                PAYLOAD &tmp = m_even_delta.get();
265                (m_owner->*m_cb)(*tmp.first, tmp.second);
266            }
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