|  | /* | 
|  | * Copyright (c) 2013-2014 ARM Limited | 
|  | * All rights reserved | 
|  | * | 
|  | * The license below extends only to copyright in the software and shall | 
|  | * not be construed as granting a license to any other intellectual | 
|  | * property including but not limited to intellectual property relating | 
|  | * to a hardware implementation of the functionality of the software | 
|  | * licensed hereunder.  You may use the software subject to the license | 
|  | * terms below provided that you ensure that this notice is replicated | 
|  | * unmodified and in its entirety in all distributions of the software, | 
|  | * modified or unmodified, in source code or in binary form. | 
|  | * | 
|  | * 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 | 
|  | * | 
|  | * Classes for buffer, queue and FIFO behaviour. | 
|  | */ | 
|  |  | 
|  | #ifndef __CPU_MINOR_BUFFERS_HH__ | 
|  | #define __CPU_MINOR_BUFFERS_HH__ | 
|  |  | 
|  | #include <iostream> | 
|  | #include <queue> | 
|  | #include <sstream> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/logging.hh" | 
|  | #include "base/named.hh" | 
|  | #include "base/types.hh" | 
|  | #include "cpu/activity.hh" | 
|  | #include "cpu/minor/trace.hh" | 
|  | #include "cpu/timebuf.hh" | 
|  |  | 
|  | namespace gem5 | 
|  | { | 
|  |  | 
|  | GEM5_DEPRECATED_NAMESPACE(Minor, minor); | 
|  | namespace minor | 
|  | { | 
|  |  | 
|  | /** Interface class for data with reporting/tracing facilities.  This | 
|  | *  interface doesn't actually have to be used as other classes which need | 
|  | *  this interface uses templating rather than inheritance but it's provided | 
|  | *  here to document the interface needed by those classes. */ | 
|  | class ReportIF | 
|  | { | 
|  | public: | 
|  | /** Print the data in a format suitable to be the value in "name=value" | 
|  | *  trace lines */ | 
|  | virtual void reportData(std::ostream &os) const = 0; | 
|  |  | 
|  | virtual ~ReportIF() { } | 
|  | }; | 
|  |  | 
|  | /** Interface class for data with 'bubble' values.  This interface doesn't | 
|  | *  actually have to be used as other classes which need this interface uses | 
|  | *  templating rather than inheritance but it's provided here to document | 
|  | *  the interface needed by those classes. */ | 
|  | class BubbleIF | 
|  | { | 
|  | public: | 
|  | virtual bool isBubble() const = 0; | 
|  | }; | 
|  |  | 
|  | /** ...ReportTraits are trait classes with the same functionality as | 
|  | *  ReportIF, but with elements explicitly passed into the report... | 
|  | *  functions. */ | 
|  |  | 
|  | /** Allow a template using ReportTraits to call report... functions of | 
|  | *  ReportIF-bearing elements themselves */ | 
|  | template <typename ElemType> /* ElemType should implement ReportIF */ | 
|  | class ReportTraitsAdaptor | 
|  | { | 
|  | public: | 
|  | static void | 
|  | reportData(std::ostream &os, const ElemType &elem) | 
|  | { elem.reportData(os); } | 
|  | }; | 
|  |  | 
|  | /** A similar adaptor but for elements held by pointer | 
|  | *  ElemType should implement ReportIF */ | 
|  | template <typename PtrType> | 
|  | class ReportTraitsPtrAdaptor | 
|  | { | 
|  | public: | 
|  | static void | 
|  | reportData(std::ostream &os, const PtrType &elem) | 
|  | { elem->reportData(os); } | 
|  | }; | 
|  |  | 
|  | /** ... BubbleTraits are trait classes to add BubbleIF interface | 
|  | *  functionality to templates which process elements which don't necessarily | 
|  | *  implement BubbleIF themselves */ | 
|  |  | 
|  | /** Default behaviour, no bubbles */ | 
|  | template <typename ElemType> | 
|  | class NoBubbleTraits | 
|  | { | 
|  | public: | 
|  | static bool isBubble(const ElemType &) { return false; } | 
|  | static ElemType | 
|  | bubble() | 
|  | { | 
|  | panic("bubble called but no bubble interface"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** Pass on call to the element */ | 
|  | template <typename ElemType> | 
|  | class BubbleTraitsAdaptor | 
|  | { | 
|  | public: | 
|  | static bool isBubble(const ElemType &elem) | 
|  | { return elem.isBubble(); } | 
|  |  | 
|  | static ElemType bubble() { return ElemType::bubble(); } | 
|  | }; | 
|  |  | 
|  | /** Pass on call to the element where the element is a pointer */ | 
|  | template <typename PtrType, typename ElemType> | 
|  | class BubbleTraitsPtrAdaptor | 
|  | { | 
|  | public: | 
|  | static bool isBubble(const PtrType &elem) | 
|  | { return elem->isBubble(); } | 
|  |  | 
|  | static PtrType bubble() { return ElemType::bubble(); } | 
|  | }; | 
|  |  | 
|  | /** TimeBuffer with MinorTrace and Named interfaces */ | 
|  | template <typename ElemType, | 
|  | typename ReportTraits = ReportTraitsAdaptor<ElemType>, | 
|  | typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > | 
|  | class MinorBuffer : public Named, public TimeBuffer<ElemType> | 
|  | { | 
|  | protected: | 
|  | /** The range of elements that should appear in trace lines */ | 
|  | int reportLeft, reportRight; | 
|  |  | 
|  | /** Name to use for the data in a MinorTrace line */ | 
|  | std::string dataName; | 
|  |  | 
|  | public: | 
|  | MinorBuffer(const std::string &name, | 
|  | const std::string &data_name, | 
|  | int num_past, int num_future, | 
|  | int report_left = -1, int report_right = -1) : | 
|  | Named(name), TimeBuffer<ElemType>(num_past, num_future), | 
|  | reportLeft(report_left), reportRight(report_right), | 
|  | dataName(data_name) | 
|  | { } | 
|  |  | 
|  | public: | 
|  | /* Is this buffer full of only bubbles */ | 
|  | bool | 
|  | empty() const | 
|  | { | 
|  | bool ret = true; | 
|  |  | 
|  | for (int i = -this->past; i <= this->future; i++) { | 
|  | if (!BubbleTraits::isBubble((*this)[i])) | 
|  | ret = false; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /** Report buffer states from 'slot' 'from' to 'to'.  For example 0,-1 | 
|  | * will produce two slices with current (just assigned) and last (one | 
|  | * advance() old) slices with the current (0) one on the left. | 
|  | * Reverse the numbers to change the order of slices */ | 
|  | void | 
|  | minorTrace() const | 
|  | { | 
|  | std::ostringstream data; | 
|  |  | 
|  | int step = (reportLeft > reportRight ? -1 : 1); | 
|  | int end = reportRight + step; | 
|  | int i = reportLeft; | 
|  |  | 
|  | while (i != end) { | 
|  | const ElemType &datum = (*this)[i]; | 
|  |  | 
|  | ReportTraits::reportData(data, datum); | 
|  | i += step; | 
|  | if (i != end) | 
|  | data << ','; | 
|  | } | 
|  |  | 
|  | minor::minorTrace("%s=%s\n", dataName, data.str()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** Wraps a MinorBuffer with Input/Output interfaces to ensure that units | 
|  | *  within the model can only see the right end of buffers between them. */ | 
|  | template <typename Data> | 
|  | class Latch | 
|  | { | 
|  | public: | 
|  | typedef MinorBuffer<Data> Buffer; | 
|  |  | 
|  | protected: | 
|  | /** Delays, in cycles, writing data into the latch and seeing it on the | 
|  | *  latched wires */ | 
|  | Cycles delay; | 
|  |  | 
|  | Buffer buffer; | 
|  |  | 
|  | public: | 
|  | /** forward/backwardDelay specify the delay from input to output in each | 
|  | *  direction.  These arguments *must* be >= 1 */ | 
|  | Latch(const std::string &name, | 
|  | const std::string &data_name, | 
|  | Cycles delay_ = Cycles(1), | 
|  | bool report_backwards = false) : | 
|  | delay(delay_), | 
|  | buffer(name, data_name, delay_, 0, (report_backwards ? -delay_ : 0), | 
|  | (report_backwards ? 0 : -delay_)) | 
|  | { } | 
|  |  | 
|  | public: | 
|  | /** Encapsulate wires on either input or output of the latch. | 
|  | *  forward/backward correspond to data direction relative to the | 
|  | *  pipeline.  Latched and Immediate specify delay for backward data. | 
|  | *  Immediate data is available to earlier stages *during* the cycle it | 
|  | *  is written */ | 
|  | class Input | 
|  | { | 
|  | public: | 
|  | typename Buffer::wire inputWire; | 
|  |  | 
|  | public: | 
|  | Input(typename Buffer::wire input_wire) : | 
|  | inputWire(input_wire) | 
|  | { } | 
|  | }; | 
|  |  | 
|  | class Output | 
|  | { | 
|  | public: | 
|  | typename Buffer::wire outputWire; | 
|  |  | 
|  | public: | 
|  | Output(typename Buffer::wire output_wire) : | 
|  | outputWire(output_wire) | 
|  | { } | 
|  | }; | 
|  |  | 
|  | bool empty() const { return buffer.empty(); } | 
|  |  | 
|  | /** An interface to just the input of the buffer */ | 
|  | Input input() { return Input(buffer.getWire(0)); } | 
|  |  | 
|  | /** An interface to just the output of the buffer */ | 
|  | Output output() { return Output(buffer.getWire(-delay)); } | 
|  |  | 
|  | void minorTrace() const { buffer.minorTrace(); } | 
|  |  | 
|  | void evaluate() { buffer.advance(); } | 
|  | }; | 
|  |  | 
|  | /** A pipeline simulating class that will stall (not advance when advance() | 
|  | *  is called) if a non-bubble value lies at the far end of the pipeline. | 
|  | *  The user can clear the stall before calling advance to unstall the | 
|  | *  pipeline. */ | 
|  | template <typename ElemType, | 
|  | typename ReportTraits, | 
|  | typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > | 
|  | class SelfStallingPipeline : public MinorBuffer<ElemType, ReportTraits> | 
|  | { | 
|  | protected: | 
|  | /** Wire at the input end of the pipeline (for convenience) */ | 
|  | typename TimeBuffer<ElemType>::wire pushWire; | 
|  | /** Wire at the output end of the pipeline (for convenience) */ | 
|  | typename TimeBuffer<ElemType>::wire popWire; | 
|  |  | 
|  | public: | 
|  | /** If true, advance will not advance the pipeline */ | 
|  | bool stalled; | 
|  |  | 
|  | /** The number of slots with non-bubbles in them */ | 
|  | unsigned int occupancy; | 
|  |  | 
|  | public: | 
|  | SelfStallingPipeline(const std::string &name, | 
|  | const std::string &data_name, | 
|  | unsigned depth) : | 
|  | MinorBuffer<ElemType, ReportTraits> | 
|  | (name, data_name, depth, 0, -1, -depth), | 
|  | pushWire(this->getWire(0)), | 
|  | popWire(this->getWire(-depth)), | 
|  | stalled(false), | 
|  | occupancy(0) | 
|  | { | 
|  | assert(depth > 0); | 
|  |  | 
|  | /* Write explicit bubbles to get around the case where the default | 
|  | *  constructor for the element type isn't good enough */ | 
|  | for (unsigned i = 0; i <= depth; i++) | 
|  | (*this)[-i] = BubbleTraits::bubble(); | 
|  | } | 
|  |  | 
|  | public: | 
|  | /** Write an element to the back of the pipeline.  This doesn't cause | 
|  | *  the pipeline to advance until advance is called.  Pushing twice | 
|  | *  without advance-ing will just cause an overwrite of the last push's | 
|  | *  data. */ | 
|  | void push(ElemType &elem) | 
|  | { | 
|  | assert(!alreadyPushed()); | 
|  | *pushWire = elem; | 
|  | if (!BubbleTraits::isBubble(elem)) | 
|  | occupancy++; | 
|  | } | 
|  |  | 
|  | /** Peek at the end element of the pipe */ | 
|  | ElemType &front() { return *popWire; } | 
|  |  | 
|  | const ElemType &front() const { return *popWire; } | 
|  |  | 
|  | /** Have we already pushed onto this pipe without advancing */ | 
|  | bool alreadyPushed() { return !BubbleTraits::isBubble(*pushWire); } | 
|  |  | 
|  | /** There's data (not a bubble) at the end of the pipe */ | 
|  | bool isPopable() { return !BubbleTraits::isBubble(front()); } | 
|  |  | 
|  | /** Try to advance the pipeline.  If we're stalled, don't advance.  If | 
|  | *  we're not stalled, advance then check to see if we become stalled | 
|  | *  (a non-bubble at the end of the pipe) */ | 
|  | void | 
|  | advance() | 
|  | { | 
|  | bool data_at_end = isPopable(); | 
|  |  | 
|  | if (!stalled) { | 
|  | TimeBuffer<ElemType>::advance(); | 
|  | /* If there was data at the end of the pipe that has now been | 
|  | *  advanced out of the pipe, we've lost data */ | 
|  | if (data_at_end) | 
|  | occupancy--; | 
|  | /* Is there data at the end of the pipe now? */ | 
|  | stalled = isPopable(); | 
|  | /* Insert a bubble into the empty input slot to make sure that | 
|  | *  element is correct in the case where the default constructor | 
|  | *  for ElemType doesn't produce a bubble */ | 
|  | ElemType bubble = BubbleTraits::bubble(); | 
|  | *pushWire = bubble; | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** Base class for space reservation requestable objects */ | 
|  | class Reservable | 
|  | { | 
|  | public: | 
|  | /** Can a slot be reserved? */ | 
|  | virtual bool canReserve() const = 0; | 
|  |  | 
|  | /** Reserve a slot in whatever structure this is attached to */ | 
|  | virtual void reserve() = 0; | 
|  |  | 
|  | /** Free a reserved slot */ | 
|  | virtual void freeReservation() = 0; | 
|  |  | 
|  | virtual ~Reservable() {}; | 
|  | }; | 
|  |  | 
|  | /** Wrapper for a queue type to act as a pipeline stage input queue. | 
|  | *  Handles capacity management, bubble value suppression and provides | 
|  | *  reporting. | 
|  | * | 
|  | *  In an ideal world, ElemType would be derived from ReportIF and BubbleIF, | 
|  | *  but here we use traits and allow the Adaptors ReportTraitsAdaptor and | 
|  | *  BubbleTraitsAdaptor to work on data which *does* directly implement | 
|  | *  those interfaces. */ | 
|  | template <typename ElemType, | 
|  | typename ReportTraits = ReportTraitsAdaptor<ElemType>, | 
|  | typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > | 
|  | class Queue : public Named, public Reservable | 
|  | { | 
|  | private: | 
|  | std::deque<ElemType> queue; | 
|  |  | 
|  | /** Number of slots currently reserved for future (reservation | 
|  | *  respecting) pushes */ | 
|  | unsigned int numReservedSlots; | 
|  |  | 
|  | /** Need this here as queues usually don't have a limited capacity */ | 
|  | unsigned int capacity; | 
|  |  | 
|  | /** Name to use for the data in MinorTrace */ | 
|  | std::string dataName; | 
|  |  | 
|  | public: | 
|  | Queue(const std::string &name, const std::string &data_name, | 
|  | unsigned int capacity_) : | 
|  | Named(name), | 
|  | numReservedSlots(0), | 
|  | capacity(capacity_), | 
|  | dataName(data_name) | 
|  | { } | 
|  |  | 
|  | public: | 
|  | /** Push an element into the buffer if it isn't a bubble.  Bubbles are | 
|  | *  just discarded.  It is assummed that any push into a queue with | 
|  | *  reserved space intends to take that space */ | 
|  | void | 
|  | push(ElemType &data) | 
|  | { | 
|  | if (!BubbleTraits::isBubble(data)) { | 
|  | freeReservation(); | 
|  | queue.push_back(data); | 
|  |  | 
|  | if (queue.size() > capacity) { | 
|  | warn("%s: No space to push data into queue of capacity" | 
|  | " %u, pushing anyway\n", name(), capacity); | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Clear all allocated space.  Be careful how this is used */ | 
|  | void clearReservedSpace() { numReservedSlots = 0; } | 
|  |  | 
|  | /** Clear a single reserved slot */ | 
|  | void freeReservation() | 
|  | { | 
|  | if (numReservedSlots != 0) | 
|  | numReservedSlots--; | 
|  | } | 
|  |  | 
|  | /** Reserve space in the queue for future pushes.  Enquiries about space | 
|  | *  in the queue using unreservedRemainingSpace will only tell about | 
|  | *  space which is not full and not reserved. */ | 
|  | void | 
|  | reserve() | 
|  | { | 
|  | /* Check reservable space */ | 
|  | if (unreservedRemainingSpace() == 0) | 
|  | warn("%s: No space is reservable in queue", name()); | 
|  |  | 
|  | numReservedSlots++; | 
|  | } | 
|  |  | 
|  | bool canReserve() const { return unreservedRemainingSpace() != 0; } | 
|  |  | 
|  | /** Number of slots available in an empty buffer */ | 
|  | unsigned int totalSpace() const { return capacity; } | 
|  |  | 
|  | /** Number of slots already occupied in this buffer */ | 
|  | unsigned int occupiedSpace() const { return queue.size(); } | 
|  |  | 
|  | /** Number of slots which are reserved. */ | 
|  | unsigned int reservedSpace() const { return numReservedSlots; } | 
|  |  | 
|  | /** Number of slots yet to fill in this buffer.  This doesn't include | 
|  | *  reservation. */ | 
|  | unsigned int | 
|  | remainingSpace() const | 
|  | { | 
|  | int ret = capacity - queue.size(); | 
|  |  | 
|  | return (ret < 0 ? 0 : ret); | 
|  | } | 
|  |  | 
|  | /** Like remainingSpace but does not count reserved spaces */ | 
|  | unsigned int | 
|  | unreservedRemainingSpace() const | 
|  | { | 
|  | int ret = capacity - (queue.size() + numReservedSlots); | 
|  |  | 
|  | return (ret < 0 ? 0 : ret); | 
|  | } | 
|  |  | 
|  | /** Head value.  Like std::queue::front */ | 
|  | ElemType &front() { return queue.front(); } | 
|  |  | 
|  | const ElemType &front() const { return queue.front(); } | 
|  |  | 
|  | /** Pop the head item.  Like std::queue::pop */ | 
|  | void pop() { queue.pop_front(); } | 
|  |  | 
|  | /** Is the queue empty? */ | 
|  | bool empty() const { return queue.empty(); } | 
|  |  | 
|  | void | 
|  | minorTrace() const | 
|  | { | 
|  | std::ostringstream data; | 
|  | /* If we become over-full, totalSpace() can actually be smaller than | 
|  | * occupiedSpace().  Handle this */ | 
|  | unsigned int num_total = (occupiedSpace() > totalSpace() ? | 
|  | occupiedSpace() : totalSpace()); | 
|  |  | 
|  | unsigned int num_reserved = reservedSpace(); | 
|  | unsigned int num_occupied = occupiedSpace(); | 
|  |  | 
|  | int num_printed = 1; | 
|  | /* Bodge to rotate queue to report elements */ | 
|  | while (num_printed <= num_occupied) { | 
|  | ReportTraits::reportData(data, queue[num_printed - 1]); | 
|  | num_printed++; | 
|  |  | 
|  | if (num_printed <= num_total) | 
|  | data << ','; | 
|  | } | 
|  |  | 
|  | int num_printed_reserved = 1; | 
|  | /* Show reserved slots */ | 
|  | while (num_printed_reserved <= num_reserved && | 
|  | num_printed <= num_total) | 
|  | { | 
|  | data << 'R'; | 
|  | num_printed_reserved++; | 
|  | num_printed++; | 
|  |  | 
|  | if (num_printed <= num_total) | 
|  | data << ','; | 
|  | } | 
|  |  | 
|  | /* And finally pad with empty slots (if there are any) */ | 
|  | while (num_printed <= num_total) { | 
|  | num_printed++; | 
|  |  | 
|  | if (num_printed <= num_total) | 
|  | data << ','; | 
|  | } | 
|  |  | 
|  | minor::minorTrace("%s=%s\n", dataName, data.str()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /** Like a Queue but with a restricted interface and a setTail function | 
|  | *  which, when the queue is empty, just takes a reference to the pushed | 
|  | *  item as the single element.  Calling pushTail will push that element | 
|  | *  onto the queue. | 
|  | * | 
|  | *  The purpose of this class is to allow the faster operation of queues of | 
|  | *  items which usually don't get deeper than one item and for which the copy | 
|  | *  associated with a push is expensive enough to want to avoid | 
|  | * | 
|  | *  The intended use case is the input buffer for pipeline stages, hence the | 
|  | *  class name */ | 
|  | template <typename ElemType, | 
|  | typename ReportTraits = ReportTraitsAdaptor<ElemType>, | 
|  | typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > | 
|  | class InputBuffer : public Reservable | 
|  | { | 
|  | protected: | 
|  | /** Underlying queue */ | 
|  | mutable Queue<ElemType, ReportTraits, BubbleTraits> queue; | 
|  |  | 
|  | /** Pointer to the single element (if not NULL) */ | 
|  | mutable ElemType *elementPtr; | 
|  |  | 
|  | public: | 
|  | InputBuffer(const std::string &name, const std::string &data_name, | 
|  | unsigned int capacity_) : | 
|  | queue(name, data_name, capacity_), | 
|  | elementPtr(NULL) | 
|  | { } | 
|  |  | 
|  | public: | 
|  | /** Set the tail of the queue, this is like push but needs | 
|  | *  to be followed by pushTail for the new tail to make its | 
|  | *  way into the queue proper */ | 
|  | void | 
|  | setTail(ElemType &new_element) | 
|  | { | 
|  | assert(!elementPtr); | 
|  | if (!BubbleTraits::isBubble(new_element)) { | 
|  | if (queue.empty()) | 
|  | elementPtr = &new_element; | 
|  | else | 
|  | queue.push(new_element); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** No single element or queue entries */ | 
|  | bool empty() const { return !elementPtr && queue.empty(); } | 
|  |  | 
|  | /** Return the element, or the front of the queue */ | 
|  | const ElemType &front() const | 
|  | { return (elementPtr ? *elementPtr : queue.front()); } | 
|  |  | 
|  | ElemType &front() | 
|  | { return (elementPtr ? *elementPtr : queue.front()); } | 
|  |  | 
|  | /** Pop either the head, or if none, the head of the queue */ | 
|  | void | 
|  | pop() | 
|  | { | 
|  | if (elementPtr) { | 
|  | /* A popped element was expected to be pushed into queue | 
|  | *  and so take a reserved space */ | 
|  | elementPtr = NULL; | 
|  | queue.freeReservation(); | 
|  | } else { | 
|  | queue.pop(); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** Push the single element (if any) into the queue proper.  If the | 
|  | *  element's reference points to a transient object, remember to | 
|  | *  always do this before the end of that object's life */ | 
|  | void | 
|  | pushTail() const | 
|  | { | 
|  | if (elementPtr) | 
|  | queue.push(*elementPtr); | 
|  | elementPtr = NULL; | 
|  | } | 
|  |  | 
|  | /** Report elements */ | 
|  | void | 
|  | minorTrace() const | 
|  | { | 
|  | pushTail(); | 
|  | queue.minorTrace(); | 
|  | } | 
|  |  | 
|  | /** Reservable interface, passed on to queue */ | 
|  | bool canReserve() const { return queue.canReserve(); } | 
|  | void reserve() { queue.reserve(); } | 
|  | void freeReservation() { queue.freeReservation(); } | 
|  |  | 
|  | /** Like remainingSpace but does not count reserved spaces */ | 
|  | unsigned int | 
|  | unreservedRemainingSpace() | 
|  | { | 
|  | pushTail(); | 
|  | return queue.unreservedRemainingSpace(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // namespace minor | 
|  | } // namespace gem5 | 
|  |  | 
|  | #endif /* __CPU_MINOR_BUFFERS_HH__ */ |