| /* |
| * Copyright (c) 2000-2004 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. |
| */ |
| |
| /* @file |
| * EventQueue interfaces |
| */ |
| |
| #ifndef __SIM_EVENTQ_HH__ |
| #define __SIM_EVENTQ_HH__ |
| |
| #include <assert.h> |
| |
| #include <algorithm> |
| #include <map> |
| #include <string> |
| #include <vector> |
| |
| #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<Event *, Event *, bool> |
| { |
| 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 <class T, void (T::* F)()> |
| 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 T, void (T::* F)()> |
| 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; |
| |
| 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__ |