/* * Copyright (c) 2000-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Steve Reinhardt * Nathan Binkert */ /* @file * EventQueue interfaces */ #ifndef __SIM_EVENTQ_HH__ #define __SIM_EVENTQ_HH__ #include #include #include #include #include #include "sim/host.hh" // for Tick #include "base/fast_alloc.hh" #include "base/trace.hh" #include "sim/serialize.hh" class EventQueue; // forward declaration ////////////////////// // // Main Event Queue // // Events on this queue are processed at the *beginning* of each // cycle, before the pipeline simulation is performed. // // defined in eventq.cc // ////////////////////// extern EventQueue mainEventQueue; /* * An item on an event queue. The action caused by a given * event is specified by deriving a subclass and overriding the * process() member function. */ class Event : public Serializable, public FastAlloc { friend class EventQueue; private: /// queue to which this event belongs (though it may or may not be /// scheduled on this queue yet) EventQueue *queue; Event *next; Tick _when; //!< timestamp when event should be processed int _priority; //!< event priority char _flags; protected: enum Flags { None = 0x0, Squashed = 0x1, Scheduled = 0x2, AutoDelete = 0x4, AutoSerialize = 0x8 }; bool getFlags(Flags f) const { return (_flags & f) == f; } void setFlags(Flags f) { _flags |= f; } void clearFlags(Flags f) { _flags &= ~f; } protected: EventQueue *theQueue() const { return queue; } #if TRACING_ON Tick when_created; //!< Keep track of creation time For debugging Tick when_scheduled; //!< Keep track of creation time For debugging virtual void trace(const char *action); //!< trace event activity #else void trace(const char *) {} #endif unsigned annotated_value; public: /// Event priorities, to provide tie-breakers for events scheduled /// at the same cycle. Most events are scheduled at the default /// priority; these values are used to control events that need to /// be ordered within a cycle. enum Priority { /// Breakpoints should happen before anything else, so we /// don't miss any action when debugging. Debug_Break_Pri = -100, /// For some reason "delayed" inter-cluster writebacks are /// scheduled before regular writebacks (which have default /// priority). Steve? Delayed_Writeback_Pri = -1, /// Default is zero for historical reasons. Default_Pri = 0, /// CPU switches schedule the new CPU's tick event for the /// same cycle (after unscheduling the old CPU's tick event). /// The switch needs to come before any tick events to make /// sure we don't tick both CPUs in the same cycle. CPU_Switch_Pri = 31, /// Serailization needs to occur before tick events also, so /// that a serialize/unserialize is identical to an on-line /// CPU switch. Serialize_Pri = 32, /// CPU ticks must come after other associated CPU events /// (such as writebacks). CPU_Tick_Pri = 50, /// Statistics events (dump, reset, etc.) come after /// everything else, but before exit. Stat_Event_Pri = 90, /// If we want to exit on this cycle, it's the very last thing /// we do. Sim_Exit_Pri = 100 }; /* * Event constructor * @param queue that the event gets scheduled on */ Event(EventQueue *q, Priority p = Default_Pri) : queue(q), next(NULL), _priority(p), _flags(None), #if TRACING_ON when_created(curTick), when_scheduled(0), #endif annotated_value(0) { } ~Event() {} virtual const std::string name() const { return csprintf("Event_%x", (uintptr_t)this); } /// Determine if the current event is scheduled bool scheduled() const { return getFlags(Scheduled); } /// Schedule the event with the current priority or default priority void schedule(Tick t); /// Reschedule the event with the current priority void reschedule(Tick t); /// Remove the event from the current schedule void deschedule(); /// Return a C string describing the event. This string should /// *not* be dynamically allocated; just a const char array /// describing the event class. virtual const char *description(); /// Dump the current event data void dump(); /* * This member function is invoked when the event is processed * (occurs). There is no default implementation; each subclass * must provide its own implementation. The event is not * automatically deleted after it is processed (to allow for * statically allocated event objects). * * If the AutoDestroy flag is set, the object is deleted once it * is processed. */ virtual void process() = 0; void annotate(unsigned value) { annotated_value = value; }; unsigned annotation() { return annotated_value; } /// Squash the current event void squash() { setFlags(Squashed); } /// Check whether the event is squashed bool squashed() { return getFlags(Squashed); } /// Get the time that the event is scheduled Tick when() const { return _when; } /// Get the event priority int priority() const { return _priority; } struct priority_compare : public std::binary_function { bool operator()(const Event *l, const Event *r) const { return l->when() >= r->when() || l->priority() >= r->priority(); } }; virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); }; template void DelayFunction(Tick when, T *object) { class DelayEvent : public Event { private: T *object; public: DelayEvent(Tick when, T *o) : Event(&mainEventQueue), object(o) { setFlags(this->AutoDestroy); schedule(when); } void process() { (object->*F)(); } const char *description() { return "delay"; } }; new DelayEvent(when, object); } template class EventWrapper : public Event { private: T *object; public: EventWrapper(T *obj, bool del = false, EventQueue *q = &mainEventQueue, Priority p = Default_Pri) : Event(q, p), object(obj) { if (del) setFlags(AutoDelete); } void process() { (object->*F)(); } }; /* * Queue of events sorted in time order */ class EventQueue : public Serializable { protected: std::string objName; private: Event *head; void insert(Event *event); void remove(Event *event); public: // constructor EventQueue(const std::string &n) : objName(n), head(NULL) {} virtual const std::string name() const { return objName; } // schedule the given event on this queue void schedule(Event *ev); void deschedule(Event *ev); void reschedule(Event *ev); Tick nextTick() { return head->when(); } void serviceOne(); // process all events up to the given timestamp. we inline a // quick test to see if there are any events to process; if so, // call the internal out-of-line version to process them all. void serviceEvents(Tick when) { while (!empty()) { if (nextTick() > when) break; /** * @todo this assert is a good bug catcher. I need to * make it true again. */ //assert(head->when() >= when && "event scheduled in the past"); serviceOne(); } } // default: process all events up to 'now' (curTick) void serviceEvents() { serviceEvents(curTick); } // return true if no events are queued bool empty() { return head == NULL; } void dump(); Tick nextEventTime() { return empty() ? curTick : head->when(); } virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); }; ////////////////////// // // inline functions // // can't put these inside declaration due to circular dependence // between Event and EventQueue classes. // ////////////////////// // schedule at specified time (place on event queue specified via // constructor) inline void Event::schedule(Tick t) { assert(!scheduled()); assert(t >= curTick); setFlags(Scheduled); #if TRACING_ON when_scheduled = curTick; #endif _when = t; queue->schedule(this); } inline void Event::deschedule() { assert(scheduled()); clearFlags(Squashed); clearFlags(Scheduled); queue->deschedule(this); } inline void Event::reschedule(Tick t) { assert(scheduled()); clearFlags(Squashed); #if TRACING_ON when_scheduled = curTick; #endif _when = t; queue->reschedule(this); } inline void EventQueue::schedule(Event *event) { insert(event); if (DTRACE(Event)) event->trace("scheduled"); } inline void EventQueue::deschedule(Event *event) { remove(event); if (DTRACE(Event)) event->trace("descheduled"); } inline void EventQueue::reschedule(Event *event) { remove(event); insert(event); if (DTRACE(Event)) event->trace("rescheduled"); } #endif // __SIM_EVENTQ_HH__