eventq.hh revision 7005
14104Ssaidi@eecs.umich.edu/*
24104Ssaidi@eecs.umich.edu * Copyright (c) 2000-2005 The Regents of The University of Michigan
34104Ssaidi@eecs.umich.edu * All rights reserved.
44104Ssaidi@eecs.umich.edu *
54104Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
64104Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are
74104Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright
84104Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
94104Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
104104Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
114104Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution;
124104Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its
134104Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
144104Ssaidi@eecs.umich.edu * this software without specific prior written permission.
154104Ssaidi@eecs.umich.edu *
164104Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174104Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184104Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194104Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204104Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214104Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224104Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234104Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244104Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254104Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264104Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274104Ssaidi@eecs.umich.edu *
284104Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
294104Ssaidi@eecs.umich.edu *          Nathan Binkert
304104Ssaidi@eecs.umich.edu */
314104Ssaidi@eecs.umich.edu
324104Ssaidi@eecs.umich.edu/* @file
334104Ssaidi@eecs.umich.edu * EventQueue interfaces
344104Ssaidi@eecs.umich.edu */
354104Ssaidi@eecs.umich.edu
364104Ssaidi@eecs.umich.edu#ifndef __SIM_EVENTQ_HH__
374104Ssaidi@eecs.umich.edu#define __SIM_EVENTQ_HH__
384104Ssaidi@eecs.umich.edu
394104Ssaidi@eecs.umich.edu#include <algorithm>
408229Snate@binkert.org#include <cassert>
414104Ssaidi@eecs.umich.edu#include <climits>
427723SAli.Saidi@ARM.com#include <iosfwd>
434104Ssaidi@eecs.umich.edu#include <string>
444104Ssaidi@eecs.umich.edu
458232Snate@binkert.org#include "base/fast_alloc.hh"
464104Ssaidi@eecs.umich.edu#include "base/flags.hh"
474104Ssaidi@eecs.umich.edu#include "base/misc.hh"
488229Snate@binkert.org#include "base/trace.hh"
494104Ssaidi@eecs.umich.edu#include "base/types.hh"
504194Ssaidi@eecs.umich.edu#include "sim/serialize.hh"
514104Ssaidi@eecs.umich.edu
524104Ssaidi@eecs.umich.educlass EventQueue;       // forward declaration
534762Snate@binkert.org
544104Ssaidi@eecs.umich.eduextern EventQueue mainEventQueue;
554104Ssaidi@eecs.umich.edu
564104Ssaidi@eecs.umich.edu/*
574104Ssaidi@eecs.umich.edu * An item on an event queue.  The action caused by a given
584104Ssaidi@eecs.umich.edu * event is specified by deriving a subclass and overriding the
594104Ssaidi@eecs.umich.edu * process() member function.
604104Ssaidi@eecs.umich.edu *
615103Ssaidi@eecs.umich.edu * Caution, the order of members is chosen to maximize data packing.
625103Ssaidi@eecs.umich.edu */
635103Ssaidi@eecs.umich.educlass Event : public Serializable, public FastAlloc
644104Ssaidi@eecs.umich.edu{
654104Ssaidi@eecs.umich.edu    friend class EventQueue;
664104Ssaidi@eecs.umich.edu
674104Ssaidi@eecs.umich.edu  protected:
684104Ssaidi@eecs.umich.edu    typedef short FlagsType;
694104Ssaidi@eecs.umich.edu    typedef ::Flags<FlagsType> Flags;
704104Ssaidi@eecs.umich.edu
714104Ssaidi@eecs.umich.edu    static const FlagsType PublicRead    = 0x003f;
724104Ssaidi@eecs.umich.edu    static const FlagsType PublicWrite   = 0x001d;
734104Ssaidi@eecs.umich.edu    static const FlagsType Squashed      = 0x0001;
744104Ssaidi@eecs.umich.edu    static const FlagsType Scheduled     = 0x0002;
754104Ssaidi@eecs.umich.edu    static const FlagsType AutoDelete    = 0x0004;
764104Ssaidi@eecs.umich.edu    static const FlagsType AutoSerialize = 0x0008;
774104Ssaidi@eecs.umich.edu    static const FlagsType IsExitEvent   = 0x0010;
784104Ssaidi@eecs.umich.edu    static const FlagsType IsMainQueue   = 0x0020;
794104Ssaidi@eecs.umich.edu#ifdef EVENTQ_DEBUG
804104Ssaidi@eecs.umich.edu    static const FlagsType Initialized   = 0xf000;
814104Ssaidi@eecs.umich.edu#endif
824104Ssaidi@eecs.umich.edu
834104Ssaidi@eecs.umich.edu  private:
844104Ssaidi@eecs.umich.edu    // The event queue is now a linked list of linked lists.  The
854104Ssaidi@eecs.umich.edu    // 'nextBin' pointer is to find the bin, where a bin is defined as
864104Ssaidi@eecs.umich.edu    // when+priority.  All events in the same bin will be stored in a
874870Sstever@eecs.umich.edu    // second linked list (a stack) maintained by the 'nextInBin'
884104Ssaidi@eecs.umich.edu    // pointer.  The list will be accessed in LIFO order.  The end
894104Ssaidi@eecs.umich.edu    // result is that the insert/removal in 'nextBin' is
904104Ssaidi@eecs.umich.edu    // linear/constant, and the lookup/removal in 'nextInBin' is
914104Ssaidi@eecs.umich.edu    // constant/constant.  Hopefully this is a significant improvement
924104Ssaidi@eecs.umich.edu    // over the current fully linear insertion.
934104Ssaidi@eecs.umich.edu    Event *nextBin;
944104Ssaidi@eecs.umich.edu    Event *nextInBin;
954104Ssaidi@eecs.umich.edu
964104Ssaidi@eecs.umich.edu    static Event *insertBefore(Event *event, Event *curr);
976712Snate@binkert.org    static Event *removeItem(Event *event, Event *last);
986712Snate@binkert.org
994104Ssaidi@eecs.umich.edu    Tick _when;         //!< timestamp when event should be processed
1004104Ssaidi@eecs.umich.edu    short _priority;    //!< event priority
1014104Ssaidi@eecs.umich.edu    Flags flags;
1024104Ssaidi@eecs.umich.edu
1034104Ssaidi@eecs.umich.edu#ifndef NDEBUG
1046712Snate@binkert.org    /// Global counter to generate unique IDs for Event instances
1056712Snate@binkert.org    static Counter instanceCounter;
1066712Snate@binkert.org
1074104Ssaidi@eecs.umich.edu    /// This event's unique ID.  We can also use pointer values for
1084104Ssaidi@eecs.umich.edu    /// this but they're not consistent across runs making debugging
1094104Ssaidi@eecs.umich.edu    /// more difficult.  Thus we use a global counter value when
1104104Ssaidi@eecs.umich.edu    /// debugging.
1114104Ssaidi@eecs.umich.edu    Counter instance;
1124104Ssaidi@eecs.umich.edu
1134104Ssaidi@eecs.umich.edu    /// queue to which this event belongs (though it may or may not be
1144104Ssaidi@eecs.umich.edu    /// scheduled on this queue yet)
1154104Ssaidi@eecs.umich.edu    EventQueue *queue;
1164104Ssaidi@eecs.umich.edu#endif
1174104Ssaidi@eecs.umich.edu
1184104Ssaidi@eecs.umich.edu#ifdef EVENTQ_DEBUG
1194104Ssaidi@eecs.umich.edu    Tick whenCreated;   //!< time created
1204104Ssaidi@eecs.umich.edu    Tick whenScheduled; //!< time scheduled
1214104Ssaidi@eecs.umich.edu#endif
1224104Ssaidi@eecs.umich.edu
1235714Shsul@eecs.umich.edu    void
1244104Ssaidi@eecs.umich.edu    setWhen(Tick when, EventQueue *q)
1254104Ssaidi@eecs.umich.edu    {
1264104Ssaidi@eecs.umich.edu        _when = when;
1274104Ssaidi@eecs.umich.edu#ifndef NDEBUG
1284104Ssaidi@eecs.umich.edu        queue = q;
1294104Ssaidi@eecs.umich.edu#endif
1304104Ssaidi@eecs.umich.edu#ifdef EVENTQ_DEBUG
1314104Ssaidi@eecs.umich.edu        whenScheduled = curTick;
1324104Ssaidi@eecs.umich.edu#endif
1334104Ssaidi@eecs.umich.edu    }
1344104Ssaidi@eecs.umich.edu
1354104Ssaidi@eecs.umich.edu  protected:
1364104Ssaidi@eecs.umich.edu    /// Accessor for flags.
1374104Ssaidi@eecs.umich.edu    Flags
1384104Ssaidi@eecs.umich.edu    getFlags() const
1394104Ssaidi@eecs.umich.edu    {
1404104Ssaidi@eecs.umich.edu        return flags & PublicRead;
1414104Ssaidi@eecs.umich.edu    }
1424104Ssaidi@eecs.umich.edu
1434104Ssaidi@eecs.umich.edu    Flags
1444104Ssaidi@eecs.umich.edu    getFlags(Flags _flags) const
1454104Ssaidi@eecs.umich.edu    {
1464104Ssaidi@eecs.umich.edu        assert(flags.noneSet(~PublicRead));
1474104Ssaidi@eecs.umich.edu        return flags.isSet(_flags);
1484104Ssaidi@eecs.umich.edu    }
1494104Ssaidi@eecs.umich.edu
1504104Ssaidi@eecs.umich.edu    Flags
1514104Ssaidi@eecs.umich.edu    allFlags(Flags _flags) const
1524104Ssaidi@eecs.umich.edu    {
1534104Ssaidi@eecs.umich.edu        assert(_flags.noneSet(~PublicRead));
1544104Ssaidi@eecs.umich.edu        return flags.allSet(_flags);
1554104Ssaidi@eecs.umich.edu    }
1564104Ssaidi@eecs.umich.edu
1574104Ssaidi@eecs.umich.edu    /// Accessor for flags.
1584104Ssaidi@eecs.umich.edu    void
1594104Ssaidi@eecs.umich.edu    setFlags(Flags _flags)
1604104Ssaidi@eecs.umich.edu    {
1614104Ssaidi@eecs.umich.edu        assert(_flags.noneSet(~PublicWrite));
1624104Ssaidi@eecs.umich.edu        flags.set(_flags);
1634104Ssaidi@eecs.umich.edu    }
1644104Ssaidi@eecs.umich.edu
1654104Ssaidi@eecs.umich.edu    void
1664104Ssaidi@eecs.umich.edu    clearFlags(Flags _flags)
1674104Ssaidi@eecs.umich.edu    {
1684104Ssaidi@eecs.umich.edu        assert(_flags.noneSet(~PublicWrite));
1694104Ssaidi@eecs.umich.edu        flags.clear(_flags);
1704104Ssaidi@eecs.umich.edu    }
1714104Ssaidi@eecs.umich.edu
1724104Ssaidi@eecs.umich.edu    void
1734104Ssaidi@eecs.umich.edu    clearFlags()
1744104Ssaidi@eecs.umich.edu    {
1754104Ssaidi@eecs.umich.edu        flags.clear(PublicWrite);
1764104Ssaidi@eecs.umich.edu    }
1774104Ssaidi@eecs.umich.edu
1784104Ssaidi@eecs.umich.edu    // This function isn't really useful if TRACING_ON is not defined
1794104Ssaidi@eecs.umich.edu    virtual void trace(const char *action);     //!< trace event activity
1804870Sstever@eecs.umich.edu
1814104Ssaidi@eecs.umich.edu  public:
1824104Ssaidi@eecs.umich.edu    /// Event priorities, to provide tie-breakers for events scheduled
1834104Ssaidi@eecs.umich.edu    /// at the same cycle.  Most events are scheduled at the default
1844104Ssaidi@eecs.umich.edu    /// priority; these values are used to control events that need to
1854104Ssaidi@eecs.umich.edu    /// be ordered within a cycle.
1864104Ssaidi@eecs.umich.edu    enum Priority {
1874104Ssaidi@eecs.umich.edu        /// Minimum priority
1884104Ssaidi@eecs.umich.edu        Minimum_Pri             = SHRT_MIN,
1894104Ssaidi@eecs.umich.edu
1904104Ssaidi@eecs.umich.edu        /// If we enable tracing on a particular cycle, do that as the
1914104Ssaidi@eecs.umich.edu        /// very first thing so we don't miss any of the events on
1924104Ssaidi@eecs.umich.edu        /// that cycle (even if we enter the debugger).
1934104Ssaidi@eecs.umich.edu        Trace_Enable_Pri        = -101,
1944104Ssaidi@eecs.umich.edu
1954104Ssaidi@eecs.umich.edu        /// Breakpoints should happen before anything else (except
1964216Ssaidi@eecs.umich.edu        /// enabling trace output), so we don't miss any action when
1974216Ssaidi@eecs.umich.edu        /// debugging.
1984104Ssaidi@eecs.umich.edu        Debug_Break_Pri         = -100,
1994104Ssaidi@eecs.umich.edu
2004104Ssaidi@eecs.umich.edu        /// CPU switches schedule the new CPU's tick event for the
2014104Ssaidi@eecs.umich.edu        /// same cycle (after unscheduling the old CPU's tick event).
2026712Snate@binkert.org        /// The switch needs to come before any tick events to make
2034104Ssaidi@eecs.umich.edu        /// sure we don't tick both CPUs in the same cycle.
2044104Ssaidi@eecs.umich.edu        CPU_Switch_Pri          =   -31,
2054104Ssaidi@eecs.umich.edu
2064104Ssaidi@eecs.umich.edu        /// For some reason "delayed" inter-cluster writebacks are
2074216Ssaidi@eecs.umich.edu        /// scheduled before regular writebacks (which have default
2084216Ssaidi@eecs.umich.edu        /// priority).  Steve?
2094104Ssaidi@eecs.umich.edu        Delayed_Writeback_Pri   =   -1,
2104104Ssaidi@eecs.umich.edu
2114104Ssaidi@eecs.umich.edu        /// Default is zero for historical reasons.
2124104Ssaidi@eecs.umich.edu        Default_Pri             =    0,
2134104Ssaidi@eecs.umich.edu
2144216Ssaidi@eecs.umich.edu        /// Serailization needs to occur before tick events also, so
2154104Ssaidi@eecs.umich.edu        /// that a serialize/unserialize is identical to an on-line
2164104Ssaidi@eecs.umich.edu        /// CPU switch.
2174104Ssaidi@eecs.umich.edu        Serialize_Pri           =   32,
2184104Ssaidi@eecs.umich.edu
2194104Ssaidi@eecs.umich.edu        /// CPU ticks must come after other associated CPU events
2204104Ssaidi@eecs.umich.edu        /// (such as writebacks).
2214104Ssaidi@eecs.umich.edu        CPU_Tick_Pri            =   50,
2224104Ssaidi@eecs.umich.edu
2234104Ssaidi@eecs.umich.edu        /// Statistics events (dump, reset, etc.) come after
2244104Ssaidi@eecs.umich.edu        /// everything else, but before exit.
2254104Ssaidi@eecs.umich.edu        Stat_Event_Pri          =   90,
2264104Ssaidi@eecs.umich.edu
2274104Ssaidi@eecs.umich.edu        /// Progress events come at the end.
2284104Ssaidi@eecs.umich.edu        Progress_Event_Pri      =   95,
2294104Ssaidi@eecs.umich.edu
2304104Ssaidi@eecs.umich.edu        /// If we want to exit on this cycle, it's the very last thing
2314104Ssaidi@eecs.umich.edu        /// we do.
2324104Ssaidi@eecs.umich.edu        Sim_Exit_Pri            =  100,
2334104Ssaidi@eecs.umich.edu
2344104Ssaidi@eecs.umich.edu        /// Maximum priority
2354104Ssaidi@eecs.umich.edu        Maximum_Pri             = SHRT_MAX
2364104Ssaidi@eecs.umich.edu    };
2374104Ssaidi@eecs.umich.edu
2385714Shsul@eecs.umich.edu    /*
2394104Ssaidi@eecs.umich.edu     * Event constructor
2404104Ssaidi@eecs.umich.edu     * @param queue that the event gets scheduled on
2414104Ssaidi@eecs.umich.edu     */
2424104Ssaidi@eecs.umich.edu    Event(Priority p = Default_Pri)
2434104Ssaidi@eecs.umich.edu        : nextBin(NULL), nextInBin(NULL), _priority(p)
2444104Ssaidi@eecs.umich.edu    {
2454104Ssaidi@eecs.umich.edu#ifndef NDEBUG
2464216Ssaidi@eecs.umich.edu        instance = ++instanceCounter;
2474216Ssaidi@eecs.umich.edu        queue = NULL;
2484104Ssaidi@eecs.umich.edu#endif
2494104Ssaidi@eecs.umich.edu#ifdef EVENTQ_DEBUG
2504104Ssaidi@eecs.umich.edu        flags.set(Initialized);
2514104Ssaidi@eecs.umich.edu        whenCreated = curTick;
2524104Ssaidi@eecs.umich.edu        whenScheduled = 0;
2534216Ssaidi@eecs.umich.edu#endif
2544216Ssaidi@eecs.umich.edu    }
2554104Ssaidi@eecs.umich.edu
2564104Ssaidi@eecs.umich.edu    virtual ~Event();
2574104Ssaidi@eecs.umich.edu    virtual const std::string name() const;
2584104Ssaidi@eecs.umich.edu
2594104Ssaidi@eecs.umich.edu    /// Return a C string describing the event.  This string should
2604104Ssaidi@eecs.umich.edu    /// *not* be dynamically allocated; just a const char array
2614104Ssaidi@eecs.umich.edu    /// describing the event class.
2624104Ssaidi@eecs.umich.edu    virtual const char *description() const;
2634104Ssaidi@eecs.umich.edu
2644104Ssaidi@eecs.umich.edu    /// Dump the current event data
2654104Ssaidi@eecs.umich.edu    void dump() const;
2664104Ssaidi@eecs.umich.edu
2674104Ssaidi@eecs.umich.edu  public:
2684104Ssaidi@eecs.umich.edu    /*
2694216Ssaidi@eecs.umich.edu     * This member function is invoked when the event is processed
2704216Ssaidi@eecs.umich.edu     * (occurs).  There is no default implementation; each subclass
2714104Ssaidi@eecs.umich.edu     * must provide its own implementation.  The event is not
2724104Ssaidi@eecs.umich.edu     * automatically deleted after it is processed (to allow for
2734104Ssaidi@eecs.umich.edu     * statically allocated event objects).
2744104Ssaidi@eecs.umich.edu     *
2754104Ssaidi@eecs.umich.edu     * If the AutoDestroy flag is set, the object is deleted once it
2764104Ssaidi@eecs.umich.edu     * is processed.
2774104Ssaidi@eecs.umich.edu     */
2784194Ssaidi@eecs.umich.edu    virtual void process() = 0;
2795719Shsul@eecs.umich.edu
2804104Ssaidi@eecs.umich.edu    /// Determine if the current event is scheduled
2814130Ssaidi@eecs.umich.edu    bool scheduled() const { return flags.isSet(Scheduled); }
2824194Ssaidi@eecs.umich.edu
2834194Ssaidi@eecs.umich.edu    /// Squash the current event
2844216Ssaidi@eecs.umich.edu    void squash() { flags.set(Squashed); }
2854216Ssaidi@eecs.umich.edu
2864194Ssaidi@eecs.umich.edu    /// Check whether the event is squashed
2874194Ssaidi@eecs.umich.edu    bool squashed() const { return flags.isSet(Squashed); }
2884194Ssaidi@eecs.umich.edu
2894194Ssaidi@eecs.umich.edu    /// See if this is a SimExitEvent (without resorting to RTTI)
2904194Ssaidi@eecs.umich.edu    bool isExitEvent() const { return flags.isSet(IsExitEvent); }
2914194Ssaidi@eecs.umich.edu
2924194Ssaidi@eecs.umich.edu    /// Get the time that the event is scheduled
2934194Ssaidi@eecs.umich.edu    Tick when() const { return _when; }
2944194Ssaidi@eecs.umich.edu
2954194Ssaidi@eecs.umich.edu    /// Get the event priority
2964216Ssaidi@eecs.umich.edu    int priority() const { return _priority; }
2974194Ssaidi@eecs.umich.edu
2984194Ssaidi@eecs.umich.edu#ifndef SWIG
2994194Ssaidi@eecs.umich.edu    struct priority_compare
3004216Ssaidi@eecs.umich.edu        : public std::binary_function<Event *, Event *, bool>
3014194Ssaidi@eecs.umich.edu    {
3024194Ssaidi@eecs.umich.edu        bool
3034194Ssaidi@eecs.umich.edu        operator()(const Event *l, const Event *r) const
3044194Ssaidi@eecs.umich.edu        {
3054194Ssaidi@eecs.umich.edu            return l->when() >= r->when() || l->priority() >= r->priority();
3064104Ssaidi@eecs.umich.edu        }
3074104Ssaidi@eecs.umich.edu    };
3084104Ssaidi@eecs.umich.edu
3094104Ssaidi@eecs.umich.edu    virtual void serialize(std::ostream &os);
3104104Ssaidi@eecs.umich.edu    virtual void unserialize(Checkpoint *cp, const std::string &section);
3114104Ssaidi@eecs.umich.edu#endif
3124104Ssaidi@eecs.umich.edu};
3134104Ssaidi@eecs.umich.edu
3144104Ssaidi@eecs.umich.edu#ifndef SWIG
3154104Ssaidi@eecs.umich.eduinline bool
3164216Ssaidi@eecs.umich.eduoperator<(const Event &l, const Event &r)
3174216Ssaidi@eecs.umich.edu{
3184216Ssaidi@eecs.umich.edu    return l.when() < r.when() ||
3194104Ssaidi@eecs.umich.edu        (l.when() == r.when() && l.priority() < r.priority());
3204104Ssaidi@eecs.umich.edu}
3214104Ssaidi@eecs.umich.edu
3224104Ssaidi@eecs.umich.eduinline bool
3234104Ssaidi@eecs.umich.eduoperator>(const Event &l, const Event &r)
3244104Ssaidi@eecs.umich.edu{
3254104Ssaidi@eecs.umich.edu    return l.when() > r.when() ||
3264104Ssaidi@eecs.umich.edu        (l.when() == r.when() && l.priority() > r.priority());
3274104Ssaidi@eecs.umich.edu}
3288711Sandreas.hansson@arm.com
3298711Sandreas.hansson@arm.cominline bool
3304104Ssaidi@eecs.umich.eduoperator<=(const Event &l, const Event &r)
3318711Sandreas.hansson@arm.com{
3328711Sandreas.hansson@arm.com    return l.when() < r.when() ||
3338711Sandreas.hansson@arm.com        (l.when() == r.when() && l.priority() <= r.priority());
3348711Sandreas.hansson@arm.com}
3354104Ssaidi@eecs.umich.eduinline bool
3364104Ssaidi@eecs.umich.eduoperator>=(const Event &l, const Event &r)
3374104Ssaidi@eecs.umich.edu{
3384104Ssaidi@eecs.umich.edu    return l.when() > r.when() ||
3394104Ssaidi@eecs.umich.edu        (l.when() == r.when() && l.priority() >= r.priority());
3404104Ssaidi@eecs.umich.edu}
3414104Ssaidi@eecs.umich.edu
3424104Ssaidi@eecs.umich.eduinline bool
3434104Ssaidi@eecs.umich.eduoperator==(const Event &l, const Event &r)
3444104Ssaidi@eecs.umich.edu{
3454104Ssaidi@eecs.umich.edu    return l.when() == r.when() && l.priority() == r.priority();
3464104Ssaidi@eecs.umich.edu}
3474104Ssaidi@eecs.umich.edu
3484104Ssaidi@eecs.umich.eduinline bool
3494104Ssaidi@eecs.umich.eduoperator!=(const Event &l, const Event &r)
3504104Ssaidi@eecs.umich.edu{
3514104Ssaidi@eecs.umich.edu    return l.when() != r.when() || l.priority() != r.priority();
3524104Ssaidi@eecs.umich.edu}
3534104Ssaidi@eecs.umich.edu#endif
3544104Ssaidi@eecs.umich.edu
3554104Ssaidi@eecs.umich.edu/*
3564104Ssaidi@eecs.umich.edu * Queue of events sorted in time order
3574104Ssaidi@eecs.umich.edu */
3584104Ssaidi@eecs.umich.educlass EventQueue : public Serializable
3594104Ssaidi@eecs.umich.edu{
3604104Ssaidi@eecs.umich.edu  private:
3614104Ssaidi@eecs.umich.edu    std::string objName;
3624104Ssaidi@eecs.umich.edu    Event *head;
3634104Ssaidi@eecs.umich.edu
3644104Ssaidi@eecs.umich.edu    void insert(Event *event);
3654104Ssaidi@eecs.umich.edu    void remove(Event *event);
3664104Ssaidi@eecs.umich.edu
3674104Ssaidi@eecs.umich.edu  public:
3684104Ssaidi@eecs.umich.edu    EventQueue(const std::string &n)
3694104Ssaidi@eecs.umich.edu        : objName(n), head(NULL)
3704104Ssaidi@eecs.umich.edu    {}
3714104Ssaidi@eecs.umich.edu
3724104Ssaidi@eecs.umich.edu    virtual const std::string name() const { return objName; }
3734104Ssaidi@eecs.umich.edu
3744104Ssaidi@eecs.umich.edu    // schedule the given event on this queue
3754104Ssaidi@eecs.umich.edu    void schedule(Event *event, Tick when);
3764104Ssaidi@eecs.umich.edu    void deschedule(Event *event);
3774762Snate@binkert.org    void reschedule(Event *event, Tick when, bool always = false);
3784762Snate@binkert.org
3794104Ssaidi@eecs.umich.edu    Tick nextTick() const { return head->when(); }
3804762Snate@binkert.org    Event *serviceOne();
3814104Ssaidi@eecs.umich.edu
382    // process all events up to the given timestamp.  we inline a
383    // quick test to see if there are any events to process; if so,
384    // call the internal out-of-line version to process them all.
385    void
386    serviceEvents(Tick when)
387    {
388        while (!empty()) {
389            if (nextTick() > when)
390                break;
391
392            /**
393             * @todo this assert is a good bug catcher.  I need to
394             * make it true again.
395             */
396            //assert(head->when() >= when && "event scheduled in the past");
397            serviceOne();
398        }
399    }
400
401    // default: process all events up to 'now' (curTick)
402    void serviceEvents() { serviceEvents(curTick); }
403
404    // return true if no events are queued
405    bool empty() const { return head == NULL; }
406
407    void dump() const;
408
409    Tick nextEventTime() { return empty() ? curTick : head->when(); }
410
411    bool debugVerify() const;
412
413#ifndef SWIG
414    virtual void serialize(std::ostream &os);
415    virtual void unserialize(Checkpoint *cp, const std::string &section);
416#endif
417};
418
419#ifndef SWIG
420class EventManager
421{
422  protected:
423    /** A pointer to this object's event queue */
424    EventQueue *eventq;
425
426  public:
427    EventManager(EventManager &em) : eventq(em.queue()) {}
428    EventManager(EventManager *em) : eventq(em ? em->queue() : NULL) {}
429    EventManager(EventQueue *eq) : eventq(eq) {}
430
431    EventQueue *
432    queue() const
433    {
434        return eventq;
435    }
436
437    void
438    schedule(Event &event, Tick when)
439    {
440        eventq->schedule(&event, when);
441    }
442
443    void
444    deschedule(Event &event)
445    {
446        eventq->deschedule(&event);
447    }
448
449    void
450    reschedule(Event &event, Tick when, bool always = false)
451    {
452        eventq->reschedule(&event, when, always);
453    }
454
455    void
456    schedule(Event *event, Tick when)
457    {
458        eventq->schedule(event, when);
459    }
460
461    void
462    deschedule(Event *event)
463    {
464        eventq->deschedule(event);
465    }
466
467    void
468    reschedule(Event *event, Tick when, bool always = false)
469    {
470        eventq->reschedule(event, when, always);
471    }
472};
473
474inline void
475EventQueue::schedule(Event *event, Tick when)
476{
477    assert((UTick)when >= (UTick)curTick);
478    assert(!event->scheduled());
479#ifdef EVENTQ_DEBUG
480    assert((event->flags & Event::Initialized) == Event::Initialized);
481#endif
482
483    event->setWhen(when, this);
484    insert(event);
485    event->flags.set(Event::Scheduled);
486    if (this == &mainEventQueue)
487        event->flags.set(Event::IsMainQueue);
488    else
489        event->flags.clear(Event::IsMainQueue);
490
491    if (DTRACE(Event))
492        event->trace("scheduled");
493}
494
495inline void
496EventQueue::deschedule(Event *event)
497{
498    assert(event->scheduled());
499#ifdef EVENTQ_DEBUG
500    assert((event->flags & Event::Initialized) == Event::Initialized);
501#endif
502
503    remove(event);
504
505    event->flags.clear(Event::Squashed);
506    event->flags.clear(Event::Scheduled);
507
508    if (event->flags.isSet(Event::AutoDelete))
509        delete event;
510
511    if (DTRACE(Event))
512        event->trace("descheduled");
513}
514
515inline void
516EventQueue::reschedule(Event *event, Tick when, bool always)
517{
518    assert(when >= curTick);
519    assert(always || event->scheduled());
520#ifdef EVENTQ_DEBUG
521    assert((event->flags & Event::Initialized) == Event::Initialized);
522#endif
523
524    if (event->scheduled())
525        remove(event);
526
527    event->setWhen(when, this);
528    insert(event);
529    event->flags.clear(Event::Squashed);
530    event->flags.set(Event::Scheduled);
531    if (this == &mainEventQueue)
532        event->flags.set(Event::IsMainQueue);
533    else
534        event->flags.clear(Event::IsMainQueue);
535
536    if (DTRACE(Event))
537        event->trace("rescheduled");
538}
539
540template <class T, void (T::* F)()>
541void
542DelayFunction(EventQueue *eventq, Tick when, T *object)
543{
544    class DelayEvent : public Event
545    {
546      private:
547        T *object;
548
549      public:
550        DelayEvent(T *o)
551            : object(o)
552        { this->setFlags(AutoDelete); }
553        void process() { (object->*F)(); }
554        const char *description() const { return "delay"; }
555    };
556
557    eventq->schedule(new DelayEvent(object), when);
558}
559
560template <class T, void (T::* F)()>
561class EventWrapper : public Event
562{
563  private:
564    T *object;
565
566  public:
567    EventWrapper(T *obj, bool del = false, Priority p = Default_Pri)
568        : Event(p), object(obj)
569    {
570        if (del)
571            setFlags(AutoDelete);
572    }
573
574    void process() { (object->*F)(); }
575
576    const std::string
577    name() const
578    {
579        return object->name() + ".wrapped_event";
580    }
581
582    const char *description() const { return "EventWrapped"; }
583};
584#endif
585
586#endif // __SIM_EVENTQ_HH__
587