buffers.hh revision 10259
110259SAndrew.Bardsley@arm.com/* 210259SAndrew.Bardsley@arm.com * Copyright (c) 2013-2014 ARM Limited 310259SAndrew.Bardsley@arm.com * All rights reserved 410259SAndrew.Bardsley@arm.com * 510259SAndrew.Bardsley@arm.com * The license below extends only to copyright in the software and shall 610259SAndrew.Bardsley@arm.com * not be construed as granting a license to any other intellectual 710259SAndrew.Bardsley@arm.com * property including but not limited to intellectual property relating 810259SAndrew.Bardsley@arm.com * to a hardware implementation of the functionality of the software 910259SAndrew.Bardsley@arm.com * licensed hereunder. You may use the software subject to the license 1010259SAndrew.Bardsley@arm.com * terms below provided that you ensure that this notice is replicated 1110259SAndrew.Bardsley@arm.com * unmodified and in its entirety in all distributions of the software, 1210259SAndrew.Bardsley@arm.com * modified or unmodified, in source code or in binary form. 1310259SAndrew.Bardsley@arm.com * 1410259SAndrew.Bardsley@arm.com * Redistribution and use in source and binary forms, with or without 1510259SAndrew.Bardsley@arm.com * modification, are permitted provided that the following conditions are 1610259SAndrew.Bardsley@arm.com * met: redistributions of source code must retain the above copyright 1710259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer; 1810259SAndrew.Bardsley@arm.com * redistributions in binary form must reproduce the above copyright 1910259SAndrew.Bardsley@arm.com * notice, this list of conditions and the following disclaimer in the 2010259SAndrew.Bardsley@arm.com * documentation and/or other materials provided with the distribution; 2110259SAndrew.Bardsley@arm.com * neither the name of the copyright holders nor the names of its 2210259SAndrew.Bardsley@arm.com * contributors may be used to endorse or promote products derived from 2310259SAndrew.Bardsley@arm.com * this software without specific prior written permission. 2410259SAndrew.Bardsley@arm.com * 2510259SAndrew.Bardsley@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610259SAndrew.Bardsley@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710259SAndrew.Bardsley@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810259SAndrew.Bardsley@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910259SAndrew.Bardsley@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010259SAndrew.Bardsley@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110259SAndrew.Bardsley@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210259SAndrew.Bardsley@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310259SAndrew.Bardsley@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410259SAndrew.Bardsley@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510259SAndrew.Bardsley@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610259SAndrew.Bardsley@arm.com * 3710259SAndrew.Bardsley@arm.com * Authors: Andrew Bardsley 3810259SAndrew.Bardsley@arm.com */ 3910259SAndrew.Bardsley@arm.com 4010259SAndrew.Bardsley@arm.com/** 4110259SAndrew.Bardsley@arm.com * @file 4210259SAndrew.Bardsley@arm.com * 4310259SAndrew.Bardsley@arm.com * Classes for buffer, queue and FIFO behaviour. 4410259SAndrew.Bardsley@arm.com */ 4510259SAndrew.Bardsley@arm.com 4610259SAndrew.Bardsley@arm.com#ifndef __CPU_MINOR_BUFFERS_HH__ 4710259SAndrew.Bardsley@arm.com#define __CPU_MINOR_BUFFERS_HH__ 4810259SAndrew.Bardsley@arm.com 4910259SAndrew.Bardsley@arm.com#include <iostream> 5010259SAndrew.Bardsley@arm.com#include <queue> 5110259SAndrew.Bardsley@arm.com#include <sstream> 5210259SAndrew.Bardsley@arm.com 5310259SAndrew.Bardsley@arm.com#include "cpu/minor/trace.hh" 5410259SAndrew.Bardsley@arm.com#include "cpu/activity.hh" 5510259SAndrew.Bardsley@arm.com#include "cpu/timebuf.hh" 5610259SAndrew.Bardsley@arm.com 5710259SAndrew.Bardsley@arm.comnamespace Minor 5810259SAndrew.Bardsley@arm.com{ 5910259SAndrew.Bardsley@arm.com 6010259SAndrew.Bardsley@arm.com/** Interface class for data with reporting/tracing facilities. This 6110259SAndrew.Bardsley@arm.com * interface doesn't actually have to be used as other classes which need 6210259SAndrew.Bardsley@arm.com * this interface uses templating rather than inheritance but it's provided 6310259SAndrew.Bardsley@arm.com * here to document the interface needed by those classes. */ 6410259SAndrew.Bardsley@arm.comclass ReportIF 6510259SAndrew.Bardsley@arm.com{ 6610259SAndrew.Bardsley@arm.com public: 6710259SAndrew.Bardsley@arm.com /** Print the data in a format suitable to be the value in "name=value" 6810259SAndrew.Bardsley@arm.com * trace lines */ 6910259SAndrew.Bardsley@arm.com virtual void reportData(std::ostream &os) const = 0; 7010259SAndrew.Bardsley@arm.com 7110259SAndrew.Bardsley@arm.com virtual ~ReportIF() { } 7210259SAndrew.Bardsley@arm.com}; 7310259SAndrew.Bardsley@arm.com 7410259SAndrew.Bardsley@arm.com/** Interface class for data with 'bubble' values. This interface doesn't 7510259SAndrew.Bardsley@arm.com * actually have to be used as other classes which need this interface uses 7610259SAndrew.Bardsley@arm.com * templating rather than inheritance but it's provided here to document 7710259SAndrew.Bardsley@arm.com * the interface needed by those classes. */ 7810259SAndrew.Bardsley@arm.comclass BubbleIF 7910259SAndrew.Bardsley@arm.com{ 8010259SAndrew.Bardsley@arm.com public: 8110259SAndrew.Bardsley@arm.com virtual bool isBubble() const = 0; 8210259SAndrew.Bardsley@arm.com}; 8310259SAndrew.Bardsley@arm.com 8410259SAndrew.Bardsley@arm.com/** ...ReportTraits are trait classes with the same functionality as 8510259SAndrew.Bardsley@arm.com * ReportIF, but with elements explicitly passed into the report... 8610259SAndrew.Bardsley@arm.com * functions. */ 8710259SAndrew.Bardsley@arm.com 8810259SAndrew.Bardsley@arm.com/** Allow a template using ReportTraits to call report... functions of 8910259SAndrew.Bardsley@arm.com * ReportIF-bearing elements themselves */ 9010259SAndrew.Bardsley@arm.comtemplate <typename ElemType> /* ElemType should implement ReportIF */ 9110259SAndrew.Bardsley@arm.comclass ReportTraitsAdaptor 9210259SAndrew.Bardsley@arm.com{ 9310259SAndrew.Bardsley@arm.com public: 9410259SAndrew.Bardsley@arm.com static void 9510259SAndrew.Bardsley@arm.com reportData(std::ostream &os, const ElemType &elem) 9610259SAndrew.Bardsley@arm.com { elem.reportData(os); } 9710259SAndrew.Bardsley@arm.com}; 9810259SAndrew.Bardsley@arm.com 9910259SAndrew.Bardsley@arm.com/** A similar adaptor but for elements held by pointer 10010259SAndrew.Bardsley@arm.com * ElemType should implement ReportIF */ 10110259SAndrew.Bardsley@arm.comtemplate <typename PtrType> 10210259SAndrew.Bardsley@arm.comclass ReportTraitsPtrAdaptor 10310259SAndrew.Bardsley@arm.com{ 10410259SAndrew.Bardsley@arm.com public: 10510259SAndrew.Bardsley@arm.com static void 10610259SAndrew.Bardsley@arm.com reportData(std::ostream &os, const PtrType &elem) 10710259SAndrew.Bardsley@arm.com { elem->reportData(os); } 10810259SAndrew.Bardsley@arm.com}; 10910259SAndrew.Bardsley@arm.com 11010259SAndrew.Bardsley@arm.com/** ... BubbleTraits are trait classes to add BubbleIF interface 11110259SAndrew.Bardsley@arm.com * functionality to templates which process elements which don't necessarily 11210259SAndrew.Bardsley@arm.com * implement BubbleIF themselves */ 11310259SAndrew.Bardsley@arm.com 11410259SAndrew.Bardsley@arm.com/** Default behaviour, no bubbles */ 11510259SAndrew.Bardsley@arm.comtemplate <typename ElemType> 11610259SAndrew.Bardsley@arm.comclass NoBubbleTraits 11710259SAndrew.Bardsley@arm.com{ 11810259SAndrew.Bardsley@arm.com public: 11910259SAndrew.Bardsley@arm.com static bool isBubble(const ElemType &) { return false; } 12010259SAndrew.Bardsley@arm.com static ElemType bubble() { assert(false); } 12110259SAndrew.Bardsley@arm.com}; 12210259SAndrew.Bardsley@arm.com 12310259SAndrew.Bardsley@arm.com/** Pass on call to the element */ 12410259SAndrew.Bardsley@arm.comtemplate <typename ElemType> 12510259SAndrew.Bardsley@arm.comclass BubbleTraitsAdaptor 12610259SAndrew.Bardsley@arm.com{ 12710259SAndrew.Bardsley@arm.com public: 12810259SAndrew.Bardsley@arm.com static bool isBubble(const ElemType &elem) 12910259SAndrew.Bardsley@arm.com { return elem.isBubble(); } 13010259SAndrew.Bardsley@arm.com 13110259SAndrew.Bardsley@arm.com static ElemType bubble() { return ElemType::bubble(); } 13210259SAndrew.Bardsley@arm.com}; 13310259SAndrew.Bardsley@arm.com 13410259SAndrew.Bardsley@arm.com/** Pass on call to the element where the element is a pointer */ 13510259SAndrew.Bardsley@arm.comtemplate <typename PtrType, typename ElemType> 13610259SAndrew.Bardsley@arm.comclass BubbleTraitsPtrAdaptor 13710259SAndrew.Bardsley@arm.com{ 13810259SAndrew.Bardsley@arm.com public: 13910259SAndrew.Bardsley@arm.com static bool isBubble(const PtrType &elem) 14010259SAndrew.Bardsley@arm.com { return elem->isBubble(); } 14110259SAndrew.Bardsley@arm.com 14210259SAndrew.Bardsley@arm.com static PtrType bubble() { return ElemType::bubble(); } 14310259SAndrew.Bardsley@arm.com}; 14410259SAndrew.Bardsley@arm.com 14510259SAndrew.Bardsley@arm.com/** TimeBuffer with MinorTrace and Named interfaces */ 14610259SAndrew.Bardsley@arm.comtemplate <typename ElemType, 14710259SAndrew.Bardsley@arm.com typename ReportTraits = ReportTraitsAdaptor<ElemType>, 14810259SAndrew.Bardsley@arm.com typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > 14910259SAndrew.Bardsley@arm.comclass MinorBuffer : public Named, public TimeBuffer<ElemType> 15010259SAndrew.Bardsley@arm.com{ 15110259SAndrew.Bardsley@arm.com protected: 15210259SAndrew.Bardsley@arm.com /** The range of elements that should appear in trace lines */ 15310259SAndrew.Bardsley@arm.com int reportLeft, reportRight; 15410259SAndrew.Bardsley@arm.com 15510259SAndrew.Bardsley@arm.com /** Name to use for the data in a MinorTrace line */ 15610259SAndrew.Bardsley@arm.com std::string dataName; 15710259SAndrew.Bardsley@arm.com 15810259SAndrew.Bardsley@arm.com public: 15910259SAndrew.Bardsley@arm.com MinorBuffer(const std::string &name, 16010259SAndrew.Bardsley@arm.com const std::string &data_name, 16110259SAndrew.Bardsley@arm.com int num_past, int num_future, 16210259SAndrew.Bardsley@arm.com int report_left = -1, int report_right = -1) : 16310259SAndrew.Bardsley@arm.com Named(name), TimeBuffer<ElemType>(num_past, num_future), 16410259SAndrew.Bardsley@arm.com reportLeft(report_left), reportRight(report_right), 16510259SAndrew.Bardsley@arm.com dataName(data_name) 16610259SAndrew.Bardsley@arm.com { } 16710259SAndrew.Bardsley@arm.com 16810259SAndrew.Bardsley@arm.com public: 16910259SAndrew.Bardsley@arm.com /* Is this buffer full of only bubbles */ 17010259SAndrew.Bardsley@arm.com bool 17110259SAndrew.Bardsley@arm.com empty() const 17210259SAndrew.Bardsley@arm.com { 17310259SAndrew.Bardsley@arm.com bool ret = true; 17410259SAndrew.Bardsley@arm.com 17510259SAndrew.Bardsley@arm.com for (int i = -this->past; i <= this->future; i++) { 17610259SAndrew.Bardsley@arm.com if (!BubbleTraits::isBubble((*this)[i])) 17710259SAndrew.Bardsley@arm.com ret = false; 17810259SAndrew.Bardsley@arm.com } 17910259SAndrew.Bardsley@arm.com 18010259SAndrew.Bardsley@arm.com return ret; 18110259SAndrew.Bardsley@arm.com } 18210259SAndrew.Bardsley@arm.com 18310259SAndrew.Bardsley@arm.com /** Report buffer states from 'slot' 'from' to 'to'. For example 0,-1 18410259SAndrew.Bardsley@arm.com * will produce two slices with current (just assigned) and last (one 18510259SAndrew.Bardsley@arm.com * advance() old) slices with the current (0) one on the left. 18610259SAndrew.Bardsley@arm.com * Reverse the numbers to change the order of slices */ 18710259SAndrew.Bardsley@arm.com void 18810259SAndrew.Bardsley@arm.com minorTrace() const 18910259SAndrew.Bardsley@arm.com { 19010259SAndrew.Bardsley@arm.com std::ostringstream data; 19110259SAndrew.Bardsley@arm.com 19210259SAndrew.Bardsley@arm.com int step = (reportLeft > reportRight ? -1 : 1); 19310259SAndrew.Bardsley@arm.com int end = reportRight + step; 19410259SAndrew.Bardsley@arm.com int i = reportLeft; 19510259SAndrew.Bardsley@arm.com 19610259SAndrew.Bardsley@arm.com while (i != end) { 19710259SAndrew.Bardsley@arm.com const ElemType &datum = (*this)[i]; 19810259SAndrew.Bardsley@arm.com 19910259SAndrew.Bardsley@arm.com ReportTraits::reportData(data, datum); 20010259SAndrew.Bardsley@arm.com i += step; 20110259SAndrew.Bardsley@arm.com if (i != end) 20210259SAndrew.Bardsley@arm.com data << ','; 20310259SAndrew.Bardsley@arm.com } 20410259SAndrew.Bardsley@arm.com 20510259SAndrew.Bardsley@arm.com MINORTRACE("%s=%s\n", dataName, data.str()); 20610259SAndrew.Bardsley@arm.com } 20710259SAndrew.Bardsley@arm.com}; 20810259SAndrew.Bardsley@arm.com 20910259SAndrew.Bardsley@arm.com/** Wraps a MinorBuffer with Input/Output interfaces to ensure that units 21010259SAndrew.Bardsley@arm.com * within the model can only see the right end of buffers between them. */ 21110259SAndrew.Bardsley@arm.comtemplate <typename Data> 21210259SAndrew.Bardsley@arm.comclass Latch 21310259SAndrew.Bardsley@arm.com{ 21410259SAndrew.Bardsley@arm.com public: 21510259SAndrew.Bardsley@arm.com typedef MinorBuffer<Data> Buffer; 21610259SAndrew.Bardsley@arm.com 21710259SAndrew.Bardsley@arm.com protected: 21810259SAndrew.Bardsley@arm.com /** Delays, in cycles, writing data into the latch and seeing it on the 21910259SAndrew.Bardsley@arm.com * latched wires */ 22010259SAndrew.Bardsley@arm.com Cycles delay; 22110259SAndrew.Bardsley@arm.com 22210259SAndrew.Bardsley@arm.com Buffer buffer; 22310259SAndrew.Bardsley@arm.com 22410259SAndrew.Bardsley@arm.com public: 22510259SAndrew.Bardsley@arm.com /** forward/backwardDelay specify the delay from input to output in each 22610259SAndrew.Bardsley@arm.com * direction. These arguments *must* be >= 1 */ 22710259SAndrew.Bardsley@arm.com Latch(const std::string &name, 22810259SAndrew.Bardsley@arm.com const std::string &data_name, 22910259SAndrew.Bardsley@arm.com Cycles delay_ = Cycles(1), 23010259SAndrew.Bardsley@arm.com bool report_backwards = false) : 23110259SAndrew.Bardsley@arm.com delay(delay_), 23210259SAndrew.Bardsley@arm.com buffer(name, data_name, delay_, 0, (report_backwards ? -delay_ : 0), 23310259SAndrew.Bardsley@arm.com (report_backwards ? 0 : -delay_)) 23410259SAndrew.Bardsley@arm.com { } 23510259SAndrew.Bardsley@arm.com 23610259SAndrew.Bardsley@arm.com public: 23710259SAndrew.Bardsley@arm.com /** Encapsulate wires on either input or output of the latch. 23810259SAndrew.Bardsley@arm.com * forward/backward correspond to data direction relative to the 23910259SAndrew.Bardsley@arm.com * pipeline. Latched and Immediate specify delay for backward data. 24010259SAndrew.Bardsley@arm.com * Immediate data is available to earlier stages *during* the cycle it 24110259SAndrew.Bardsley@arm.com * is written */ 24210259SAndrew.Bardsley@arm.com class Input 24310259SAndrew.Bardsley@arm.com { 24410259SAndrew.Bardsley@arm.com public: 24510259SAndrew.Bardsley@arm.com typename Buffer::wire inputWire; 24610259SAndrew.Bardsley@arm.com 24710259SAndrew.Bardsley@arm.com public: 24810259SAndrew.Bardsley@arm.com Input(typename Buffer::wire input_wire) : 24910259SAndrew.Bardsley@arm.com inputWire(input_wire) 25010259SAndrew.Bardsley@arm.com { } 25110259SAndrew.Bardsley@arm.com }; 25210259SAndrew.Bardsley@arm.com 25310259SAndrew.Bardsley@arm.com class Output 25410259SAndrew.Bardsley@arm.com { 25510259SAndrew.Bardsley@arm.com public: 25610259SAndrew.Bardsley@arm.com typename Buffer::wire outputWire; 25710259SAndrew.Bardsley@arm.com 25810259SAndrew.Bardsley@arm.com public: 25910259SAndrew.Bardsley@arm.com Output(typename Buffer::wire output_wire) : 26010259SAndrew.Bardsley@arm.com outputWire(output_wire) 26110259SAndrew.Bardsley@arm.com { } 26210259SAndrew.Bardsley@arm.com }; 26310259SAndrew.Bardsley@arm.com 26410259SAndrew.Bardsley@arm.com bool empty() const { return buffer.empty(); } 26510259SAndrew.Bardsley@arm.com 26610259SAndrew.Bardsley@arm.com /** An interface to just the input of the buffer */ 26710259SAndrew.Bardsley@arm.com Input input() { return Input(buffer.getWire(0)); } 26810259SAndrew.Bardsley@arm.com 26910259SAndrew.Bardsley@arm.com /** An interface to just the output of the buffer */ 27010259SAndrew.Bardsley@arm.com Output output() { return Output(buffer.getWire(-delay)); } 27110259SAndrew.Bardsley@arm.com 27210259SAndrew.Bardsley@arm.com void minorTrace() const { buffer.minorTrace(); } 27310259SAndrew.Bardsley@arm.com 27410259SAndrew.Bardsley@arm.com void evaluate() { buffer.advance(); } 27510259SAndrew.Bardsley@arm.com}; 27610259SAndrew.Bardsley@arm.com 27710259SAndrew.Bardsley@arm.com/** A pipeline simulating class that will stall (not advance when advance() 27810259SAndrew.Bardsley@arm.com * is called) if a non-bubble value lies at the far end of the pipeline. 27910259SAndrew.Bardsley@arm.com * The user can clear the stall before calling advance to unstall the 28010259SAndrew.Bardsley@arm.com * pipeline. */ 28110259SAndrew.Bardsley@arm.comtemplate <typename ElemType, 28210259SAndrew.Bardsley@arm.com typename ReportTraits, 28310259SAndrew.Bardsley@arm.com typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > 28410259SAndrew.Bardsley@arm.comclass SelfStallingPipeline : public MinorBuffer<ElemType, ReportTraits> 28510259SAndrew.Bardsley@arm.com{ 28610259SAndrew.Bardsley@arm.com protected: 28710259SAndrew.Bardsley@arm.com /** Wire at the input end of the pipeline (for convenience) */ 28810259SAndrew.Bardsley@arm.com typename TimeBuffer<ElemType>::wire pushWire; 28910259SAndrew.Bardsley@arm.com /** Wire at the output end of the pipeline (for convenience) */ 29010259SAndrew.Bardsley@arm.com typename TimeBuffer<ElemType>::wire popWire; 29110259SAndrew.Bardsley@arm.com 29210259SAndrew.Bardsley@arm.com public: 29310259SAndrew.Bardsley@arm.com /** If true, advance will not advance the pipeline */ 29410259SAndrew.Bardsley@arm.com bool stalled; 29510259SAndrew.Bardsley@arm.com 29610259SAndrew.Bardsley@arm.com /** The number of slots with non-bubbles in them */ 29710259SAndrew.Bardsley@arm.com unsigned int occupancy; 29810259SAndrew.Bardsley@arm.com 29910259SAndrew.Bardsley@arm.com public: 30010259SAndrew.Bardsley@arm.com SelfStallingPipeline(const std::string &name, 30110259SAndrew.Bardsley@arm.com const std::string &data_name, 30210259SAndrew.Bardsley@arm.com unsigned depth) : 30310259SAndrew.Bardsley@arm.com MinorBuffer<ElemType, ReportTraits> 30410259SAndrew.Bardsley@arm.com (name, data_name, depth, 0, -1, -depth), 30510259SAndrew.Bardsley@arm.com pushWire(this->getWire(0)), 30610259SAndrew.Bardsley@arm.com popWire(this->getWire(-depth)), 30710259SAndrew.Bardsley@arm.com stalled(false), 30810259SAndrew.Bardsley@arm.com occupancy(0) 30910259SAndrew.Bardsley@arm.com { 31010259SAndrew.Bardsley@arm.com assert(depth > 0); 31110259SAndrew.Bardsley@arm.com 31210259SAndrew.Bardsley@arm.com /* Write explicit bubbles to get around the case where the default 31310259SAndrew.Bardsley@arm.com * constructor for the element type isn't good enough */ 31410259SAndrew.Bardsley@arm.com for (unsigned i = 0; i <= depth; i++) 31510259SAndrew.Bardsley@arm.com (*this)[-i] = BubbleTraits::bubble(); 31610259SAndrew.Bardsley@arm.com } 31710259SAndrew.Bardsley@arm.com 31810259SAndrew.Bardsley@arm.com public: 31910259SAndrew.Bardsley@arm.com /** Write an element to the back of the pipeline. This doesn't cause 32010259SAndrew.Bardsley@arm.com * the pipeline to advance until advance is called. Pushing twice 32110259SAndrew.Bardsley@arm.com * without advance-ing will just cause an overwrite of the last push's 32210259SAndrew.Bardsley@arm.com * data. */ 32310259SAndrew.Bardsley@arm.com void push(ElemType &elem) 32410259SAndrew.Bardsley@arm.com { 32510259SAndrew.Bardsley@arm.com assert(!alreadyPushed()); 32610259SAndrew.Bardsley@arm.com *pushWire = elem; 32710259SAndrew.Bardsley@arm.com if (!BubbleTraits::isBubble(elem)) 32810259SAndrew.Bardsley@arm.com occupancy++; 32910259SAndrew.Bardsley@arm.com } 33010259SAndrew.Bardsley@arm.com 33110259SAndrew.Bardsley@arm.com /** Peek at the end element of the pipe */ 33210259SAndrew.Bardsley@arm.com ElemType &front() { return *popWire; } 33310259SAndrew.Bardsley@arm.com 33410259SAndrew.Bardsley@arm.com const ElemType &front() const { return *popWire; } 33510259SAndrew.Bardsley@arm.com 33610259SAndrew.Bardsley@arm.com /** Have we already pushed onto this pipe without advancing */ 33710259SAndrew.Bardsley@arm.com bool alreadyPushed() { return !BubbleTraits::isBubble(*pushWire); } 33810259SAndrew.Bardsley@arm.com 33910259SAndrew.Bardsley@arm.com /** There's data (not a bubble) at the end of the pipe */ 34010259SAndrew.Bardsley@arm.com bool isPopable() { return !BubbleTraits::isBubble(front()); } 34110259SAndrew.Bardsley@arm.com 34210259SAndrew.Bardsley@arm.com /** Try to advance the pipeline. If we're stalled, don't advance. If 34310259SAndrew.Bardsley@arm.com * we're not stalled, advance then check to see if we become stalled 34410259SAndrew.Bardsley@arm.com * (a non-bubble at the end of the pipe) */ 34510259SAndrew.Bardsley@arm.com void 34610259SAndrew.Bardsley@arm.com advance() 34710259SAndrew.Bardsley@arm.com { 34810259SAndrew.Bardsley@arm.com bool data_at_end = isPopable(); 34910259SAndrew.Bardsley@arm.com 35010259SAndrew.Bardsley@arm.com if (!stalled) { 35110259SAndrew.Bardsley@arm.com TimeBuffer<ElemType>::advance(); 35210259SAndrew.Bardsley@arm.com /* If there was data at the end of the pipe that has now been 35310259SAndrew.Bardsley@arm.com * advanced out of the pipe, we've lost data */ 35410259SAndrew.Bardsley@arm.com if (data_at_end) 35510259SAndrew.Bardsley@arm.com occupancy--; 35610259SAndrew.Bardsley@arm.com /* Is there data at the end of the pipe now? */ 35710259SAndrew.Bardsley@arm.com stalled = isPopable(); 35810259SAndrew.Bardsley@arm.com /* Insert a bubble into the empty input slot to make sure that 35910259SAndrew.Bardsley@arm.com * element is correct in the case where the default constructor 36010259SAndrew.Bardsley@arm.com * for ElemType doesn't produce a bubble */ 36110259SAndrew.Bardsley@arm.com ElemType bubble = BubbleTraits::bubble(); 36210259SAndrew.Bardsley@arm.com *pushWire = bubble; 36310259SAndrew.Bardsley@arm.com } 36410259SAndrew.Bardsley@arm.com } 36510259SAndrew.Bardsley@arm.com}; 36610259SAndrew.Bardsley@arm.com 36710259SAndrew.Bardsley@arm.com/** Base class for space reservation requestable objects */ 36810259SAndrew.Bardsley@arm.comclass Reservable 36910259SAndrew.Bardsley@arm.com{ 37010259SAndrew.Bardsley@arm.com public: 37110259SAndrew.Bardsley@arm.com /** Can a slot be reserved? */ 37210259SAndrew.Bardsley@arm.com virtual bool canReserve() const = 0; 37310259SAndrew.Bardsley@arm.com 37410259SAndrew.Bardsley@arm.com /** Reserve a slot in whatever structure this is attached to */ 37510259SAndrew.Bardsley@arm.com virtual void reserve() = 0; 37610259SAndrew.Bardsley@arm.com 37710259SAndrew.Bardsley@arm.com /** Free a reserved slot */ 37810259SAndrew.Bardsley@arm.com virtual void freeReservation() = 0; 37910259SAndrew.Bardsley@arm.com}; 38010259SAndrew.Bardsley@arm.com 38110259SAndrew.Bardsley@arm.com/** Wrapper for a queue type to act as a pipeline stage input queue. 38210259SAndrew.Bardsley@arm.com * Handles capacity management, bubble value suppression and provides 38310259SAndrew.Bardsley@arm.com * reporting. 38410259SAndrew.Bardsley@arm.com * 38510259SAndrew.Bardsley@arm.com * In an ideal world, ElemType would be derived from ReportIF and BubbleIF, 38610259SAndrew.Bardsley@arm.com * but here we use traits and allow the Adaptors ReportTraitsAdaptor and 38710259SAndrew.Bardsley@arm.com * BubbleTraitsAdaptor to work on data which *does* directly implement 38810259SAndrew.Bardsley@arm.com * those interfaces. */ 38910259SAndrew.Bardsley@arm.comtemplate <typename ElemType, 39010259SAndrew.Bardsley@arm.com typename ReportTraits = ReportTraitsAdaptor<ElemType>, 39110259SAndrew.Bardsley@arm.com typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > 39210259SAndrew.Bardsley@arm.comclass Queue : public Named, public Reservable 39310259SAndrew.Bardsley@arm.com{ 39410259SAndrew.Bardsley@arm.com private: 39510259SAndrew.Bardsley@arm.com std::deque<ElemType> queue; 39610259SAndrew.Bardsley@arm.com 39710259SAndrew.Bardsley@arm.com /** Number of slots currently reserved for future (reservation 39810259SAndrew.Bardsley@arm.com * respecting) pushes */ 39910259SAndrew.Bardsley@arm.com unsigned int numReservedSlots; 40010259SAndrew.Bardsley@arm.com 40110259SAndrew.Bardsley@arm.com /** Need this here as queues usually don't have a limited capacity */ 40210259SAndrew.Bardsley@arm.com unsigned int capacity; 40310259SAndrew.Bardsley@arm.com 40410259SAndrew.Bardsley@arm.com /** Name to use for the data in MinorTrace */ 40510259SAndrew.Bardsley@arm.com std::string dataName; 40610259SAndrew.Bardsley@arm.com 40710259SAndrew.Bardsley@arm.com public: 40810259SAndrew.Bardsley@arm.com Queue(const std::string &name, const std::string &data_name, 40910259SAndrew.Bardsley@arm.com unsigned int capacity_) : 41010259SAndrew.Bardsley@arm.com Named(name), 41110259SAndrew.Bardsley@arm.com numReservedSlots(0), 41210259SAndrew.Bardsley@arm.com capacity(capacity_), 41310259SAndrew.Bardsley@arm.com dataName(data_name) 41410259SAndrew.Bardsley@arm.com { } 41510259SAndrew.Bardsley@arm.com 41610259SAndrew.Bardsley@arm.com virtual ~Queue() { } 41710259SAndrew.Bardsley@arm.com 41810259SAndrew.Bardsley@arm.com public: 41910259SAndrew.Bardsley@arm.com /** Push an element into the buffer if it isn't a bubble. Bubbles are 42010259SAndrew.Bardsley@arm.com * just discarded. It is assummed that any push into a queue with 42110259SAndrew.Bardsley@arm.com * reserved space intends to take that space */ 42210259SAndrew.Bardsley@arm.com void 42310259SAndrew.Bardsley@arm.com push(ElemType &data) 42410259SAndrew.Bardsley@arm.com { 42510259SAndrew.Bardsley@arm.com if (!BubbleTraits::isBubble(data)) { 42610259SAndrew.Bardsley@arm.com freeReservation(); 42710259SAndrew.Bardsley@arm.com queue.push_back(data); 42810259SAndrew.Bardsley@arm.com 42910259SAndrew.Bardsley@arm.com if (queue.size() > capacity) { 43010259SAndrew.Bardsley@arm.com warn("%s: No space to push data into queue of capacity" 43110259SAndrew.Bardsley@arm.com " %u, pushing anyway\n", name(), capacity); 43210259SAndrew.Bardsley@arm.com } 43310259SAndrew.Bardsley@arm.com 43410259SAndrew.Bardsley@arm.com } 43510259SAndrew.Bardsley@arm.com } 43610259SAndrew.Bardsley@arm.com 43710259SAndrew.Bardsley@arm.com /** Clear all allocated space. Be careful how this is used */ 43810259SAndrew.Bardsley@arm.com void clearReservedSpace() { numReservedSlots = 0; } 43910259SAndrew.Bardsley@arm.com 44010259SAndrew.Bardsley@arm.com /** Clear a single reserved slot */ 44110259SAndrew.Bardsley@arm.com void freeReservation() 44210259SAndrew.Bardsley@arm.com { 44310259SAndrew.Bardsley@arm.com if (numReservedSlots != 0) 44410259SAndrew.Bardsley@arm.com numReservedSlots--; 44510259SAndrew.Bardsley@arm.com } 44610259SAndrew.Bardsley@arm.com 44710259SAndrew.Bardsley@arm.com /** Reserve space in the queue for future pushes. Enquiries about space 44810259SAndrew.Bardsley@arm.com * in the queue using unreservedRemainingSpace will only tell about 44910259SAndrew.Bardsley@arm.com * space which is not full and not reserved. */ 45010259SAndrew.Bardsley@arm.com void 45110259SAndrew.Bardsley@arm.com reserve() 45210259SAndrew.Bardsley@arm.com { 45310259SAndrew.Bardsley@arm.com /* Check reservable space */ 45410259SAndrew.Bardsley@arm.com if (unreservedRemainingSpace() == 0) 45510259SAndrew.Bardsley@arm.com warn("%s: No space is reservable in queue", name()); 45610259SAndrew.Bardsley@arm.com 45710259SAndrew.Bardsley@arm.com numReservedSlots++; 45810259SAndrew.Bardsley@arm.com } 45910259SAndrew.Bardsley@arm.com 46010259SAndrew.Bardsley@arm.com bool canReserve() const { return unreservedRemainingSpace() != 0; } 46110259SAndrew.Bardsley@arm.com 46210259SAndrew.Bardsley@arm.com /** Number of slots available in an empty buffer */ 46310259SAndrew.Bardsley@arm.com unsigned int totalSpace() const { return capacity; } 46410259SAndrew.Bardsley@arm.com 46510259SAndrew.Bardsley@arm.com /** Number of slots already occupied in this buffer */ 46610259SAndrew.Bardsley@arm.com unsigned int occupiedSpace() const { return queue.size(); } 46710259SAndrew.Bardsley@arm.com 46810259SAndrew.Bardsley@arm.com /** Number of slots which are reserved. */ 46910259SAndrew.Bardsley@arm.com unsigned int reservedSpace() const { return numReservedSlots; } 47010259SAndrew.Bardsley@arm.com 47110259SAndrew.Bardsley@arm.com /** Number of slots yet to fill in this buffer. This doesn't include 47210259SAndrew.Bardsley@arm.com * reservation. */ 47310259SAndrew.Bardsley@arm.com unsigned int 47410259SAndrew.Bardsley@arm.com remainingSpace() const 47510259SAndrew.Bardsley@arm.com { 47610259SAndrew.Bardsley@arm.com int ret = capacity - queue.size(); 47710259SAndrew.Bardsley@arm.com 47810259SAndrew.Bardsley@arm.com return (ret < 0 ? 0 : ret); 47910259SAndrew.Bardsley@arm.com } 48010259SAndrew.Bardsley@arm.com 48110259SAndrew.Bardsley@arm.com /** Like remainingSpace but does not count reserved spaces */ 48210259SAndrew.Bardsley@arm.com unsigned int 48310259SAndrew.Bardsley@arm.com unreservedRemainingSpace() const 48410259SAndrew.Bardsley@arm.com { 48510259SAndrew.Bardsley@arm.com int ret = capacity - (queue.size() + numReservedSlots); 48610259SAndrew.Bardsley@arm.com 48710259SAndrew.Bardsley@arm.com return (ret < 0 ? 0 : ret); 48810259SAndrew.Bardsley@arm.com } 48910259SAndrew.Bardsley@arm.com 49010259SAndrew.Bardsley@arm.com /** Head value. Like std::queue::front */ 49110259SAndrew.Bardsley@arm.com ElemType &front() { return queue.front(); } 49210259SAndrew.Bardsley@arm.com 49310259SAndrew.Bardsley@arm.com const ElemType &front() const { return queue.front(); } 49410259SAndrew.Bardsley@arm.com 49510259SAndrew.Bardsley@arm.com /** Pop the head item. Like std::queue::pop */ 49610259SAndrew.Bardsley@arm.com void pop() { queue.pop_front(); } 49710259SAndrew.Bardsley@arm.com 49810259SAndrew.Bardsley@arm.com /** Is the queue empty? */ 49910259SAndrew.Bardsley@arm.com bool empty() const { return queue.empty(); } 50010259SAndrew.Bardsley@arm.com 50110259SAndrew.Bardsley@arm.com void 50210259SAndrew.Bardsley@arm.com minorTrace() const 50310259SAndrew.Bardsley@arm.com { 50410259SAndrew.Bardsley@arm.com std::ostringstream data; 50510259SAndrew.Bardsley@arm.com /* If we become over-full, totalSpace() can actually be smaller than 50610259SAndrew.Bardsley@arm.com * occupiedSpace(). Handle this */ 50710259SAndrew.Bardsley@arm.com unsigned int num_total = (occupiedSpace() > totalSpace() ? 50810259SAndrew.Bardsley@arm.com occupiedSpace() : totalSpace()); 50910259SAndrew.Bardsley@arm.com 51010259SAndrew.Bardsley@arm.com unsigned int num_reserved = reservedSpace(); 51110259SAndrew.Bardsley@arm.com unsigned int num_occupied = occupiedSpace(); 51210259SAndrew.Bardsley@arm.com 51310259SAndrew.Bardsley@arm.com int num_printed = 1; 51410259SAndrew.Bardsley@arm.com /* Bodge to rotate queue to report elements */ 51510259SAndrew.Bardsley@arm.com while (num_printed <= num_occupied) { 51610259SAndrew.Bardsley@arm.com ReportTraits::reportData(data, queue[num_printed - 1]); 51710259SAndrew.Bardsley@arm.com num_printed++; 51810259SAndrew.Bardsley@arm.com 51910259SAndrew.Bardsley@arm.com if (num_printed <= num_total) 52010259SAndrew.Bardsley@arm.com data << ','; 52110259SAndrew.Bardsley@arm.com } 52210259SAndrew.Bardsley@arm.com 52310259SAndrew.Bardsley@arm.com int num_printed_reserved = 1; 52410259SAndrew.Bardsley@arm.com /* Show reserved slots */ 52510259SAndrew.Bardsley@arm.com while (num_printed_reserved <= num_reserved && 52610259SAndrew.Bardsley@arm.com num_printed <= num_total) 52710259SAndrew.Bardsley@arm.com { 52810259SAndrew.Bardsley@arm.com data << 'R'; 52910259SAndrew.Bardsley@arm.com num_printed_reserved++; 53010259SAndrew.Bardsley@arm.com num_printed++; 53110259SAndrew.Bardsley@arm.com 53210259SAndrew.Bardsley@arm.com if (num_printed <= num_total) 53310259SAndrew.Bardsley@arm.com data << ','; 53410259SAndrew.Bardsley@arm.com } 53510259SAndrew.Bardsley@arm.com 53610259SAndrew.Bardsley@arm.com /* And finally pad with empty slots (if there are any) */ 53710259SAndrew.Bardsley@arm.com while (num_printed <= num_total) { 53810259SAndrew.Bardsley@arm.com num_printed++; 53910259SAndrew.Bardsley@arm.com 54010259SAndrew.Bardsley@arm.com if (num_printed <= num_total) 54110259SAndrew.Bardsley@arm.com data << ','; 54210259SAndrew.Bardsley@arm.com } 54310259SAndrew.Bardsley@arm.com 54410259SAndrew.Bardsley@arm.com MINORTRACE("%s=%s\n", dataName, data.str()); 54510259SAndrew.Bardsley@arm.com } 54610259SAndrew.Bardsley@arm.com}; 54710259SAndrew.Bardsley@arm.com 54810259SAndrew.Bardsley@arm.com/** Like a Queue but with a restricted interface and a setTail function 54910259SAndrew.Bardsley@arm.com * which, when the queue is empty, just takes a reference to the pushed 55010259SAndrew.Bardsley@arm.com * item as the single element. Calling pushTail will push that element 55110259SAndrew.Bardsley@arm.com * onto the queue. 55210259SAndrew.Bardsley@arm.com * 55310259SAndrew.Bardsley@arm.com * The purpose of this class is to allow the faster operation of queues of 55410259SAndrew.Bardsley@arm.com * items which usually don't get deeper than one item and for which the copy 55510259SAndrew.Bardsley@arm.com * associated with a push is expensive enough to want to avoid 55610259SAndrew.Bardsley@arm.com * 55710259SAndrew.Bardsley@arm.com * The intended use case is the input buffer for pipeline stages, hence the 55810259SAndrew.Bardsley@arm.com * class name */ 55910259SAndrew.Bardsley@arm.comtemplate <typename ElemType, 56010259SAndrew.Bardsley@arm.com typename ReportTraits = ReportTraitsAdaptor<ElemType>, 56110259SAndrew.Bardsley@arm.com typename BubbleTraits = BubbleTraitsAdaptor<ElemType> > 56210259SAndrew.Bardsley@arm.comclass InputBuffer : public Reservable 56310259SAndrew.Bardsley@arm.com{ 56410259SAndrew.Bardsley@arm.com protected: 56510259SAndrew.Bardsley@arm.com /** Underlying queue */ 56610259SAndrew.Bardsley@arm.com mutable Queue<ElemType, ReportTraits, BubbleTraits> queue; 56710259SAndrew.Bardsley@arm.com 56810259SAndrew.Bardsley@arm.com /** Pointer to the single element (if not NULL) */ 56910259SAndrew.Bardsley@arm.com mutable ElemType *elementPtr; 57010259SAndrew.Bardsley@arm.com 57110259SAndrew.Bardsley@arm.com public: 57210259SAndrew.Bardsley@arm.com InputBuffer(const std::string &name, const std::string &data_name, 57310259SAndrew.Bardsley@arm.com unsigned int capacity_) : 57410259SAndrew.Bardsley@arm.com queue(name, data_name, capacity_), 57510259SAndrew.Bardsley@arm.com elementPtr(NULL) 57610259SAndrew.Bardsley@arm.com { } 57710259SAndrew.Bardsley@arm.com 57810259SAndrew.Bardsley@arm.com public: 57910259SAndrew.Bardsley@arm.com /** Set the tail of the queue, this is like push but needs 58010259SAndrew.Bardsley@arm.com * to be followed by pushTail for the new tail to make its 58110259SAndrew.Bardsley@arm.com * way into the queue proper */ 58210259SAndrew.Bardsley@arm.com void 58310259SAndrew.Bardsley@arm.com setTail(ElemType &new_element) 58410259SAndrew.Bardsley@arm.com { 58510259SAndrew.Bardsley@arm.com assert(!elementPtr); 58610259SAndrew.Bardsley@arm.com if (!BubbleTraits::isBubble(new_element)) { 58710259SAndrew.Bardsley@arm.com if (queue.empty()) 58810259SAndrew.Bardsley@arm.com elementPtr = &new_element; 58910259SAndrew.Bardsley@arm.com else 59010259SAndrew.Bardsley@arm.com queue.push(new_element); 59110259SAndrew.Bardsley@arm.com } 59210259SAndrew.Bardsley@arm.com } 59310259SAndrew.Bardsley@arm.com 59410259SAndrew.Bardsley@arm.com /** No single element or queue entries */ 59510259SAndrew.Bardsley@arm.com bool empty() const { return !elementPtr && queue.empty(); } 59610259SAndrew.Bardsley@arm.com 59710259SAndrew.Bardsley@arm.com /** Return the element, or the front of the queue */ 59810259SAndrew.Bardsley@arm.com const ElemType &front() const 59910259SAndrew.Bardsley@arm.com { return (elementPtr ? *elementPtr : queue.front()); } 60010259SAndrew.Bardsley@arm.com 60110259SAndrew.Bardsley@arm.com ElemType &front() 60210259SAndrew.Bardsley@arm.com { return (elementPtr ? *elementPtr : queue.front()); } 60310259SAndrew.Bardsley@arm.com 60410259SAndrew.Bardsley@arm.com /** Pop either the head, or if none, the head of the queue */ 60510259SAndrew.Bardsley@arm.com void 60610259SAndrew.Bardsley@arm.com pop() 60710259SAndrew.Bardsley@arm.com { 60810259SAndrew.Bardsley@arm.com if (elementPtr) { 60910259SAndrew.Bardsley@arm.com /* A popped element was expected to be pushed into queue 61010259SAndrew.Bardsley@arm.com * and so take a reserved space */ 61110259SAndrew.Bardsley@arm.com elementPtr = NULL; 61210259SAndrew.Bardsley@arm.com queue.freeReservation(); 61310259SAndrew.Bardsley@arm.com } else { 61410259SAndrew.Bardsley@arm.com queue.pop(); 61510259SAndrew.Bardsley@arm.com } 61610259SAndrew.Bardsley@arm.com } 61710259SAndrew.Bardsley@arm.com 61810259SAndrew.Bardsley@arm.com /** Push the single element (if any) into the queue proper. If the 61910259SAndrew.Bardsley@arm.com * element's reference points to a transient object, remember to 62010259SAndrew.Bardsley@arm.com * always do this before the end of that object's life */ 62110259SAndrew.Bardsley@arm.com void 62210259SAndrew.Bardsley@arm.com pushTail() const 62310259SAndrew.Bardsley@arm.com { 62410259SAndrew.Bardsley@arm.com if (elementPtr) 62510259SAndrew.Bardsley@arm.com queue.push(*elementPtr); 62610259SAndrew.Bardsley@arm.com elementPtr = NULL; 62710259SAndrew.Bardsley@arm.com } 62810259SAndrew.Bardsley@arm.com 62910259SAndrew.Bardsley@arm.com /** Report elements */ 63010259SAndrew.Bardsley@arm.com void 63110259SAndrew.Bardsley@arm.com minorTrace() const 63210259SAndrew.Bardsley@arm.com { 63310259SAndrew.Bardsley@arm.com pushTail(); 63410259SAndrew.Bardsley@arm.com queue.minorTrace(); 63510259SAndrew.Bardsley@arm.com } 63610259SAndrew.Bardsley@arm.com 63710259SAndrew.Bardsley@arm.com /** Reservable interface, passed on to queue */ 63810259SAndrew.Bardsley@arm.com bool canReserve() const { return queue.canReserve(); } 63910259SAndrew.Bardsley@arm.com void reserve() { queue.reserve(); } 64010259SAndrew.Bardsley@arm.com void freeReservation() { queue.freeReservation(); } 64110259SAndrew.Bardsley@arm.com 64210259SAndrew.Bardsley@arm.com /** Like remainingSpace but does not count reserved spaces */ 64310259SAndrew.Bardsley@arm.com unsigned int 64410259SAndrew.Bardsley@arm.com unreservedRemainingSpace() 64510259SAndrew.Bardsley@arm.com { 64610259SAndrew.Bardsley@arm.com pushTail(); 64710259SAndrew.Bardsley@arm.com return queue.unreservedRemainingSpace(); 64810259SAndrew.Bardsley@arm.com } 64910259SAndrew.Bardsley@arm.com}; 65010259SAndrew.Bardsley@arm.com 65110259SAndrew.Bardsley@arm.com} 65210259SAndrew.Bardsley@arm.com 65310259SAndrew.Bardsley@arm.com#endif /* __CPU_MINOR_BUFFERS_HH__ */ 654