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