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