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