111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2014-2015 Advanced Micro Devices, Inc.
311308Santhony.gutierrez@amd.com * All rights reserved.
411308Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * For use for simulation and test purposes only
611308Santhony.gutierrez@amd.com *
711308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
811308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are met:
911308Santhony.gutierrez@amd.com *
1011308Santhony.gutierrez@amd.com * 1. Redistributions of source code must retain the above copyright notice,
1111308Santhony.gutierrez@amd.com * this list of conditions and the following disclaimer.
1211308Santhony.gutierrez@amd.com *
1311308Santhony.gutierrez@amd.com * 2. Redistributions in binary form must reproduce the above copyright notice,
1411308Santhony.gutierrez@amd.com * this list of conditions and the following disclaimer in the documentation
1511308Santhony.gutierrez@amd.com * and/or other materials provided with the distribution.
1611308Santhony.gutierrez@amd.com *
1712697Santhony.gutierrez@amd.com * 3. Neither the name of the copyright holder nor the names of its
1812697Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from this
1912697Santhony.gutierrez@amd.com * software without specific prior written permission.
2011308Santhony.gutierrez@amd.com *
2111308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2211308Santhony.gutierrez@amd.com * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2311308Santhony.gutierrez@amd.com * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2411308Santhony.gutierrez@amd.com * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2511308Santhony.gutierrez@amd.com * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2611308Santhony.gutierrez@amd.com * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2711308Santhony.gutierrez@amd.com * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2811308Santhony.gutierrez@amd.com * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2911308Santhony.gutierrez@amd.com * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3011308Santhony.gutierrez@amd.com * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3111308Santhony.gutierrez@amd.com * POSSIBILITY OF SUCH DAMAGE.
3211308Santhony.gutierrez@amd.com *
3312697Santhony.gutierrez@amd.com * Authors: John Kalamatianos,
3412697Santhony.gutierrez@amd.com *          Joe Gross
3511308Santhony.gutierrez@amd.com */
3611308Santhony.gutierrez@amd.com
3711308Santhony.gutierrez@amd.com#ifndef __LDS_STATE_HH__
3811308Santhony.gutierrez@amd.com#define __LDS_STATE_HH__
3911308Santhony.gutierrez@amd.com
4011308Santhony.gutierrez@amd.com#include <array>
4111308Santhony.gutierrez@amd.com#include <queue>
4211308Santhony.gutierrez@amd.com#include <string>
4311308Santhony.gutierrez@amd.com#include <unordered_map>
4411308Santhony.gutierrez@amd.com#include <utility>
4511308Santhony.gutierrez@amd.com#include <vector>
4611308Santhony.gutierrez@amd.com
4711308Santhony.gutierrez@amd.com#include "enums/MemType.hh"
4811308Santhony.gutierrez@amd.com#include "gpu-compute/misc.hh"
4911308Santhony.gutierrez@amd.com#include "mem/port.hh"
5011308Santhony.gutierrez@amd.com#include "params/LdsState.hh"
5113892Sgabeblack@google.com#include "sim/clocked_object.hh"
5211308Santhony.gutierrez@amd.com
5311308Santhony.gutierrez@amd.comclass ComputeUnit;
5411308Santhony.gutierrez@amd.com
5511308Santhony.gutierrez@amd.com/**
5611308Santhony.gutierrez@amd.com * this represents a slice of the overall LDS, intended to be associated with an
5711308Santhony.gutierrez@amd.com * individual workgroup
5811308Santhony.gutierrez@amd.com */
5911308Santhony.gutierrez@amd.comclass LdsChunk
6011308Santhony.gutierrez@amd.com{
6111308Santhony.gutierrez@amd.com  public:
6211308Santhony.gutierrez@amd.com    LdsChunk(const uint32_t x_size):
6311308Santhony.gutierrez@amd.com        chunk(x_size)
6411308Santhony.gutierrez@amd.com    {
6511308Santhony.gutierrez@amd.com    }
6611308Santhony.gutierrez@amd.com
6711308Santhony.gutierrez@amd.com    LdsChunk() {}
6811308Santhony.gutierrez@amd.com
6911308Santhony.gutierrez@amd.com    /**
7011308Santhony.gutierrez@amd.com     * a read operation
7111308Santhony.gutierrez@amd.com     */
7211308Santhony.gutierrez@amd.com    template<class T>
7311308Santhony.gutierrez@amd.com    T
7411308Santhony.gutierrez@amd.com    read(const uint32_t index)
7511308Santhony.gutierrez@amd.com    {
7611308Santhony.gutierrez@amd.com        fatal_if(!chunk.size(), "cannot read from an LDS chunk of size 0");
7711308Santhony.gutierrez@amd.com        fatal_if(index >= chunk.size(), "out-of-bounds access to an LDS chunk");
7811308Santhony.gutierrez@amd.com        T *p0 = (T *) (&(chunk.at(index)));
7911308Santhony.gutierrez@amd.com        return *p0;
8011308Santhony.gutierrez@amd.com    }
8111308Santhony.gutierrez@amd.com
8211308Santhony.gutierrez@amd.com    /**
8311308Santhony.gutierrez@amd.com     * a write operation
8411308Santhony.gutierrez@amd.com     */
8511308Santhony.gutierrez@amd.com    template<class T>
8611308Santhony.gutierrez@amd.com    void
8711308Santhony.gutierrez@amd.com    write(const uint32_t index, const T value)
8811308Santhony.gutierrez@amd.com    {
8911308Santhony.gutierrez@amd.com        fatal_if(!chunk.size(), "cannot write to an LDS chunk of size 0");
9011308Santhony.gutierrez@amd.com        fatal_if(index >= chunk.size(), "out-of-bounds access to an LDS chunk");
9111308Santhony.gutierrez@amd.com        T *p0 = (T *) (&(chunk.at(index)));
9211308Santhony.gutierrez@amd.com        *p0 = value;
9311308Santhony.gutierrez@amd.com    }
9411308Santhony.gutierrez@amd.com
9511308Santhony.gutierrez@amd.com    /**
9611308Santhony.gutierrez@amd.com     * get the size of this chunk
9711308Santhony.gutierrez@amd.com     */
9811308Santhony.gutierrez@amd.com    std::vector<uint8_t>::size_type
9911308Santhony.gutierrez@amd.com    size() const
10011308Santhony.gutierrez@amd.com    {
10111308Santhony.gutierrez@amd.com        return chunk.size();
10211308Santhony.gutierrez@amd.com    }
10311308Santhony.gutierrez@amd.com
10411308Santhony.gutierrez@amd.com  protected:
10511308Santhony.gutierrez@amd.com    // the actual data store for this slice of the LDS
10611308Santhony.gutierrez@amd.com    std::vector<uint8_t> chunk;
10711308Santhony.gutierrez@amd.com};
10811308Santhony.gutierrez@amd.com
10911308Santhony.gutierrez@amd.com// Local Data Share (LDS) State per Wavefront (contents of the LDS region
11011308Santhony.gutierrez@amd.com// allocated to the WorkGroup of this Wavefront)
11113892Sgabeblack@google.comclass LdsState: public ClockedObject
11211308Santhony.gutierrez@amd.com{
11311308Santhony.gutierrez@amd.com  protected:
11411308Santhony.gutierrez@amd.com
11511308Santhony.gutierrez@amd.com    /**
11611308Santhony.gutierrez@amd.com     * an event to allow event-driven execution
11711308Santhony.gutierrez@amd.com     */
11811308Santhony.gutierrez@amd.com    class TickEvent: public Event
11911308Santhony.gutierrez@amd.com    {
12011308Santhony.gutierrez@amd.com      protected:
12111308Santhony.gutierrez@amd.com
12211308Santhony.gutierrez@amd.com        LdsState *ldsState = nullptr;
12311308Santhony.gutierrez@amd.com
12411308Santhony.gutierrez@amd.com        Tick nextTick = 0;
12511308Santhony.gutierrez@amd.com
12611308Santhony.gutierrez@amd.com      public:
12711308Santhony.gutierrez@amd.com
12811308Santhony.gutierrez@amd.com        TickEvent(LdsState *_ldsState) :
12911308Santhony.gutierrez@amd.com            ldsState(_ldsState)
13011308Santhony.gutierrez@amd.com        {
13111308Santhony.gutierrez@amd.com        }
13211308Santhony.gutierrez@amd.com
13311308Santhony.gutierrez@amd.com        virtual void
13411308Santhony.gutierrez@amd.com        process();
13511308Santhony.gutierrez@amd.com
13611308Santhony.gutierrez@amd.com        void
13711308Santhony.gutierrez@amd.com        schedule(Tick when)
13811308Santhony.gutierrez@amd.com        {
13911308Santhony.gutierrez@amd.com            mainEventQueue[0]->schedule(this, when);
14011308Santhony.gutierrez@amd.com        }
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.com        void
14311308Santhony.gutierrez@amd.com        deschedule()
14411308Santhony.gutierrez@amd.com        {
14511308Santhony.gutierrez@amd.com            mainEventQueue[0]->deschedule(this);
14611308Santhony.gutierrez@amd.com        }
14711308Santhony.gutierrez@amd.com    };
14811308Santhony.gutierrez@amd.com
14911308Santhony.gutierrez@amd.com    /**
15011308Santhony.gutierrez@amd.com     * CuSidePort is the LDS Port closer to the CU side
15111308Santhony.gutierrez@amd.com     */
15211308Santhony.gutierrez@amd.com    class CuSidePort: public SlavePort
15311308Santhony.gutierrez@amd.com    {
15411308Santhony.gutierrez@amd.com      public:
15511308Santhony.gutierrez@amd.com        CuSidePort(const std::string &_name, LdsState *_ownerLds) :
15611308Santhony.gutierrez@amd.com                SlavePort(_name, _ownerLds), ownerLds(_ownerLds)
15711308Santhony.gutierrez@amd.com        {
15811308Santhony.gutierrez@amd.com        }
15911308Santhony.gutierrez@amd.com
16011308Santhony.gutierrez@amd.com      protected:
16111308Santhony.gutierrez@amd.com        LdsState *ownerLds;
16211308Santhony.gutierrez@amd.com
16311308Santhony.gutierrez@amd.com        virtual bool
16411308Santhony.gutierrez@amd.com        recvTimingReq(PacketPtr pkt);
16511308Santhony.gutierrez@amd.com
16611308Santhony.gutierrez@amd.com        virtual Tick
16711308Santhony.gutierrez@amd.com        recvAtomic(PacketPtr pkt)
16811308Santhony.gutierrez@amd.com        {
16911308Santhony.gutierrez@amd.com          return 0;
17011308Santhony.gutierrez@amd.com        }
17111308Santhony.gutierrez@amd.com
17211308Santhony.gutierrez@amd.com        virtual void
17311308Santhony.gutierrez@amd.com        recvFunctional(PacketPtr pkt);
17411308Santhony.gutierrez@amd.com
17511308Santhony.gutierrez@amd.com        virtual void
17611308Santhony.gutierrez@amd.com        recvRangeChange()
17711308Santhony.gutierrez@amd.com        {
17811308Santhony.gutierrez@amd.com        }
17911308Santhony.gutierrez@amd.com
18011308Santhony.gutierrez@amd.com        virtual void
18111308Santhony.gutierrez@amd.com        recvRetry();
18211308Santhony.gutierrez@amd.com
18311308Santhony.gutierrez@amd.com        virtual void
18411308Santhony.gutierrez@amd.com        recvRespRetry();
18511308Santhony.gutierrez@amd.com
18611308Santhony.gutierrez@amd.com        virtual AddrRangeList
18711308Santhony.gutierrez@amd.com        getAddrRanges() const
18811308Santhony.gutierrez@amd.com        {
18911308Santhony.gutierrez@amd.com          AddrRangeList ranges;
19011308Santhony.gutierrez@amd.com          ranges.push_back(ownerLds->getAddrRange());
19111308Santhony.gutierrez@amd.com          return ranges;
19211308Santhony.gutierrez@amd.com        }
19311308Santhony.gutierrez@amd.com
19411308Santhony.gutierrez@amd.com        template<typename T>
19511308Santhony.gutierrez@amd.com        void
19611308Santhony.gutierrez@amd.com        loadData(PacketPtr packet);
19711308Santhony.gutierrez@amd.com
19811308Santhony.gutierrez@amd.com        template<typename T>
19911308Santhony.gutierrez@amd.com        void
20011308Santhony.gutierrez@amd.com        storeData(PacketPtr packet);
20111308Santhony.gutierrez@amd.com
20211308Santhony.gutierrez@amd.com        template<typename T>
20311308Santhony.gutierrez@amd.com        void
20411308Santhony.gutierrez@amd.com        atomicOperation(PacketPtr packet);
20511308Santhony.gutierrez@amd.com    };
20611308Santhony.gutierrez@amd.com
20711308Santhony.gutierrez@amd.com  protected:
20811308Santhony.gutierrez@amd.com
20911308Santhony.gutierrez@amd.com    // the lds reference counter
21011308Santhony.gutierrez@amd.com    // The key is the workgroup ID and dispatch ID
21111308Santhony.gutierrez@amd.com    // The value is the number of wavefronts that reference this LDS, as
21211308Santhony.gutierrez@amd.com    // wavefronts are launched, the counter goes up for that workgroup and when
21311308Santhony.gutierrez@amd.com    // they return it decreases, once it reaches 0 then this chunk of the LDS is
21411308Santhony.gutierrez@amd.com    // returned to the available pool. However,it is deallocated on the 1->0
21511308Santhony.gutierrez@amd.com    // transition, not whenever the counter is 0 as it always starts with 0 when
21611308Santhony.gutierrez@amd.com    // the workgroup asks for space
21711308Santhony.gutierrez@amd.com    std::unordered_map<uint32_t,
21811308Santhony.gutierrez@amd.com                       std::unordered_map<uint32_t, int32_t>> refCounter;
21911308Santhony.gutierrez@amd.com
22011308Santhony.gutierrez@amd.com    // the map that allows workgroups to access their own chunk of the LDS
22111308Santhony.gutierrez@amd.com    std::unordered_map<uint32_t,
22211308Santhony.gutierrez@amd.com                       std::unordered_map<uint32_t, LdsChunk>> chunkMap;
22311308Santhony.gutierrez@amd.com
22411308Santhony.gutierrez@amd.com    // an event to allow the LDS to wake up at a specified time
22511308Santhony.gutierrez@amd.com    TickEvent tickEvent;
22611308Santhony.gutierrez@amd.com
22711308Santhony.gutierrez@amd.com    // the queue of packets that are going back to the CU after a
22811308Santhony.gutierrez@amd.com    // read/write/atomic op
22911308Santhony.gutierrez@amd.com    // TODO need to make this have a maximum size to create flow control
23011308Santhony.gutierrez@amd.com    std::queue<std::pair<Tick, PacketPtr>> returnQueue;
23111308Santhony.gutierrez@amd.com
23211308Santhony.gutierrez@amd.com    // whether or not there are pending responses
23311308Santhony.gutierrez@amd.com    bool retryResp = false;
23411308Santhony.gutierrez@amd.com
23511308Santhony.gutierrez@amd.com    bool
23611308Santhony.gutierrez@amd.com    process();
23711308Santhony.gutierrez@amd.com
23811308Santhony.gutierrez@amd.com    GPUDynInstPtr
23911308Santhony.gutierrez@amd.com    getDynInstr(PacketPtr packet);
24011308Santhony.gutierrez@amd.com
24111308Santhony.gutierrez@amd.com    bool
24211308Santhony.gutierrez@amd.com    processPacket(PacketPtr packet);
24311308Santhony.gutierrez@amd.com
24411308Santhony.gutierrez@amd.com    unsigned
24511308Santhony.gutierrez@amd.com    countBankConflicts(PacketPtr packet, unsigned *bankAccesses);
24611308Santhony.gutierrez@amd.com
24711308Santhony.gutierrez@amd.com    unsigned
24811308Santhony.gutierrez@amd.com    countBankConflicts(GPUDynInstPtr gpuDynInst,
24911308Santhony.gutierrez@amd.com                       unsigned *numBankAccesses);
25011308Santhony.gutierrez@amd.com
25111308Santhony.gutierrez@amd.com  public:
25211308Santhony.gutierrez@amd.com    typedef LdsStateParams Params;
25311308Santhony.gutierrez@amd.com
25411308Santhony.gutierrez@amd.com    LdsState(const Params *params);
25511308Santhony.gutierrez@amd.com
25611308Santhony.gutierrez@amd.com    // prevent copy construction
25711308Santhony.gutierrez@amd.com    LdsState(const LdsState&) = delete;
25811308Santhony.gutierrez@amd.com
25911308Santhony.gutierrez@amd.com    ~LdsState()
26011308Santhony.gutierrez@amd.com    {
26111308Santhony.gutierrez@amd.com        parent = nullptr;
26211308Santhony.gutierrez@amd.com    }
26311308Santhony.gutierrez@amd.com
26411308Santhony.gutierrez@amd.com    const Params *
26511308Santhony.gutierrez@amd.com    params() const
26611308Santhony.gutierrez@amd.com    {
26711308Santhony.gutierrez@amd.com        return dynamic_cast<const Params *>(_params);
26811308Santhony.gutierrez@amd.com    }
26911308Santhony.gutierrez@amd.com
27011308Santhony.gutierrez@amd.com    bool
27111308Santhony.gutierrez@amd.com    isRetryResp() const
27211308Santhony.gutierrez@amd.com    {
27311308Santhony.gutierrez@amd.com        return retryResp;
27411308Santhony.gutierrez@amd.com    }
27511308Santhony.gutierrez@amd.com
27611308Santhony.gutierrez@amd.com    void
27711308Santhony.gutierrez@amd.com    setRetryResp(const bool value)
27811308Santhony.gutierrez@amd.com    {
27911308Santhony.gutierrez@amd.com        retryResp = value;
28011308Santhony.gutierrez@amd.com    }
28111308Santhony.gutierrez@amd.com
28211308Santhony.gutierrez@amd.com    // prevent assignment
28311308Santhony.gutierrez@amd.com    LdsState &
28411308Santhony.gutierrez@amd.com    operator=(const LdsState &) = delete;
28511308Santhony.gutierrez@amd.com
28611308Santhony.gutierrez@amd.com    /**
28711308Santhony.gutierrez@amd.com     * use the dynamic wave id to create or just increase the reference count
28811308Santhony.gutierrez@amd.com     */
28911308Santhony.gutierrez@amd.com    int
29011308Santhony.gutierrez@amd.com    increaseRefCounter(const uint32_t dispatchId, const uint32_t wgId)
29111308Santhony.gutierrez@amd.com    {
29211308Santhony.gutierrez@amd.com        int refCount = getRefCounter(dispatchId, wgId);
29311308Santhony.gutierrez@amd.com        fatal_if(refCount < 0,
29411308Santhony.gutierrez@amd.com                 "reference count should not be below zero");
29511308Santhony.gutierrez@amd.com        return ++refCounter[dispatchId][wgId];
29611308Santhony.gutierrez@amd.com    }
29711308Santhony.gutierrez@amd.com
29811308Santhony.gutierrez@amd.com    /**
29911308Santhony.gutierrez@amd.com     * decrease the reference count after making sure it is in the list
30011308Santhony.gutierrez@amd.com     * give back this chunk if the ref counter has reached 0
30111308Santhony.gutierrez@amd.com     */
30211308Santhony.gutierrez@amd.com    int
30311308Santhony.gutierrez@amd.com    decreaseRefCounter(const uint32_t dispatchId, const uint32_t wgId)
30411308Santhony.gutierrez@amd.com    {
30511308Santhony.gutierrez@amd.com      int refCount = getRefCounter(dispatchId, wgId);
30611308Santhony.gutierrez@amd.com
30711308Santhony.gutierrez@amd.com      fatal_if(refCount <= 0,
30811308Santhony.gutierrez@amd.com              "reference count should not be below zero or at zero to"
30911308Santhony.gutierrez@amd.com              "decrement");
31011308Santhony.gutierrez@amd.com
31111308Santhony.gutierrez@amd.com      refCounter[dispatchId][wgId]--;
31211308Santhony.gutierrez@amd.com
31311308Santhony.gutierrez@amd.com      if (refCounter[dispatchId][wgId] == 0) {
31411308Santhony.gutierrez@amd.com        releaseSpace(dispatchId, wgId);
31511308Santhony.gutierrez@amd.com        return 0;
31611308Santhony.gutierrez@amd.com      } else {
31711308Santhony.gutierrez@amd.com        return refCounter[dispatchId][wgId];
31811308Santhony.gutierrez@amd.com      }
31911308Santhony.gutierrez@amd.com    }
32011308Santhony.gutierrez@amd.com
32111308Santhony.gutierrez@amd.com    /**
32211308Santhony.gutierrez@amd.com     * return the current reference count for this workgroup id
32311308Santhony.gutierrez@amd.com     */
32411308Santhony.gutierrez@amd.com    int
32511308Santhony.gutierrez@amd.com    getRefCounter(const uint32_t dispatchId, const uint32_t wgId) const
32611308Santhony.gutierrez@amd.com    {
32711308Santhony.gutierrez@amd.com      auto dispatchIter = chunkMap.find(dispatchId);
32811308Santhony.gutierrez@amd.com      fatal_if(dispatchIter == chunkMap.end(),
32911308Santhony.gutierrez@amd.com               "could not locate this dispatch id [%d]", dispatchId);
33011308Santhony.gutierrez@amd.com
33111308Santhony.gutierrez@amd.com      auto workgroup = dispatchIter->second.find(wgId);
33211308Santhony.gutierrez@amd.com      fatal_if(workgroup == dispatchIter->second.end(),
33311308Santhony.gutierrez@amd.com               "could not find this workgroup id within this dispatch id"
33411308Santhony.gutierrez@amd.com               " did[%d] wgid[%d]", dispatchId, wgId);
33511308Santhony.gutierrez@amd.com
33611308Santhony.gutierrez@amd.com      auto refCountIter = refCounter.find(dispatchId);
33711308Santhony.gutierrez@amd.com      if (refCountIter == refCounter.end()) {
33811308Santhony.gutierrez@amd.com        fatal("could not locate this dispatch id [%d]", dispatchId);
33911308Santhony.gutierrez@amd.com      } else {
34011308Santhony.gutierrez@amd.com        auto workgroup = refCountIter->second.find(wgId);
34111308Santhony.gutierrez@amd.com        if (workgroup == refCountIter->second.end()) {
34211308Santhony.gutierrez@amd.com          fatal("could not find this workgroup id within this dispatch id"
34311308Santhony.gutierrez@amd.com                  " did[%d] wgid[%d]", dispatchId, wgId);
34411308Santhony.gutierrez@amd.com        } else {
34511308Santhony.gutierrez@amd.com          return refCounter.at(dispatchId).at(wgId);
34611308Santhony.gutierrez@amd.com        }
34711308Santhony.gutierrez@amd.com      }
34811308Santhony.gutierrez@amd.com
34911308Santhony.gutierrez@amd.com      fatal("should not reach this point");
35011308Santhony.gutierrez@amd.com      return 0;
35111308Santhony.gutierrez@amd.com    }
35211308Santhony.gutierrez@amd.com
35311308Santhony.gutierrez@amd.com    /**
35411308Santhony.gutierrez@amd.com     * assign a parent and request this amount of space be set aside
35511308Santhony.gutierrez@amd.com     * for this wgid
35611308Santhony.gutierrez@amd.com     */
35711308Santhony.gutierrez@amd.com    LdsChunk *
35811308Santhony.gutierrez@amd.com    reserveSpace(const uint32_t dispatchId, const uint32_t wgId,
35911308Santhony.gutierrez@amd.com            const uint32_t size)
36011308Santhony.gutierrez@amd.com    {
36111308Santhony.gutierrez@amd.com        if (chunkMap.find(dispatchId) != chunkMap.end()) {
36211308Santhony.gutierrez@amd.com            fatal_if(
36311308Santhony.gutierrez@amd.com                chunkMap[dispatchId].find(wgId) != chunkMap[dispatchId].end(),
36411308Santhony.gutierrez@amd.com                "duplicate workgroup ID asking for space in the LDS "
36511308Santhony.gutierrez@amd.com                "did[%d] wgid[%d]", dispatchId, wgId);
36611308Santhony.gutierrez@amd.com        }
36711308Santhony.gutierrez@amd.com
36811308Santhony.gutierrez@amd.com        fatal_if(bytesAllocated + size > maximumSize,
36911308Santhony.gutierrez@amd.com                 "request would ask for more space than is available");
37011308Santhony.gutierrez@amd.com
37111308Santhony.gutierrez@amd.com        bytesAllocated += size;
37211308Santhony.gutierrez@amd.com
37311308Santhony.gutierrez@amd.com        chunkMap[dispatchId].emplace(wgId, LdsChunk(size));
37411308Santhony.gutierrez@amd.com        // make an entry for this workgroup
37511308Santhony.gutierrez@amd.com        refCounter[dispatchId][wgId] = 0;
37611308Santhony.gutierrez@amd.com
37711308Santhony.gutierrez@amd.com        return &chunkMap[dispatchId][wgId];
37811308Santhony.gutierrez@amd.com    }
37911308Santhony.gutierrez@amd.com
38011308Santhony.gutierrez@amd.com    bool
38111308Santhony.gutierrez@amd.com    returnQueuePush(std::pair<Tick, PacketPtr> thePair);
38211308Santhony.gutierrez@amd.com
38311308Santhony.gutierrez@amd.com    Tick
38411308Santhony.gutierrez@amd.com    earliestReturnTime() const
38511308Santhony.gutierrez@amd.com    {
38611308Santhony.gutierrez@amd.com        // TODO set to max(lastCommand+1, curTick())
38711308Santhony.gutierrez@amd.com        return returnQueue.empty() ? curTick() : returnQueue.back().first;
38811308Santhony.gutierrez@amd.com    }
38911308Santhony.gutierrez@amd.com
39011308Santhony.gutierrez@amd.com    void
39111308Santhony.gutierrez@amd.com    setParent(ComputeUnit *x_parent);
39211308Santhony.gutierrez@amd.com
39311308Santhony.gutierrez@amd.com    // accessors
39411308Santhony.gutierrez@amd.com    ComputeUnit *
39511308Santhony.gutierrez@amd.com    getParent() const
39611308Santhony.gutierrez@amd.com    {
39711308Santhony.gutierrez@amd.com        return parent;
39811308Santhony.gutierrez@amd.com    }
39911308Santhony.gutierrez@amd.com
40011308Santhony.gutierrez@amd.com    std::string
40111308Santhony.gutierrez@amd.com    getName()
40211308Santhony.gutierrez@amd.com    {
40311308Santhony.gutierrez@amd.com        return _name;
40411308Santhony.gutierrez@amd.com    }
40511308Santhony.gutierrez@amd.com
40611308Santhony.gutierrez@amd.com    int
40711308Santhony.gutierrez@amd.com    getBanks() const
40811308Santhony.gutierrez@amd.com    {
40911308Santhony.gutierrez@amd.com        return banks;
41011308Santhony.gutierrez@amd.com    }
41111308Santhony.gutierrez@amd.com
41211308Santhony.gutierrez@amd.com    ComputeUnit *
41311308Santhony.gutierrez@amd.com    getComputeUnit() const
41411308Santhony.gutierrez@amd.com    {
41511308Santhony.gutierrez@amd.com        return parent;
41611308Santhony.gutierrez@amd.com    }
41711308Santhony.gutierrez@amd.com
41811308Santhony.gutierrez@amd.com    int
41911308Santhony.gutierrez@amd.com    getBankConflictPenalty() const
42011308Santhony.gutierrez@amd.com    {
42111308Santhony.gutierrez@amd.com        return bankConflictPenalty;
42211308Santhony.gutierrez@amd.com    }
42311308Santhony.gutierrez@amd.com
42411308Santhony.gutierrez@amd.com    /**
42511308Santhony.gutierrez@amd.com     * get the allocated size for this workgroup
42611308Santhony.gutierrez@amd.com     */
42711308Santhony.gutierrez@amd.com    std::size_t
42811308Santhony.gutierrez@amd.com    ldsSize(const uint32_t x_wgId)
42911308Santhony.gutierrez@amd.com    {
43011308Santhony.gutierrez@amd.com        return chunkMap[x_wgId].size();
43111308Santhony.gutierrez@amd.com    }
43211308Santhony.gutierrez@amd.com
43311308Santhony.gutierrez@amd.com    AddrRange
43411308Santhony.gutierrez@amd.com    getAddrRange() const
43511308Santhony.gutierrez@amd.com    {
43611308Santhony.gutierrez@amd.com        return range;
43711308Santhony.gutierrez@amd.com    }
43811308Santhony.gutierrez@amd.com
43913784Sgabeblack@google.com    Port &
44013784Sgabeblack@google.com    getPort(const std::string &if_name, PortID idx)
44111308Santhony.gutierrez@amd.com    {
44211308Santhony.gutierrez@amd.com        if (if_name == "cuPort") {
44311308Santhony.gutierrez@amd.com            // TODO need to set name dynamically at this point?
44411308Santhony.gutierrez@amd.com            return cuPort;
44511308Santhony.gutierrez@amd.com        } else {
44611308Santhony.gutierrez@amd.com            fatal("cannot resolve the port name " + if_name);
44711308Santhony.gutierrez@amd.com        }
44811308Santhony.gutierrez@amd.com    }
44911308Santhony.gutierrez@amd.com
45011308Santhony.gutierrez@amd.com    /**
45111308Santhony.gutierrez@amd.com     * can this much space be reserved for a workgroup?
45211308Santhony.gutierrez@amd.com     */
45311308Santhony.gutierrez@amd.com    bool
45411308Santhony.gutierrez@amd.com    canReserve(uint32_t x_size) const
45511308Santhony.gutierrez@amd.com    {
45611308Santhony.gutierrez@amd.com      return bytesAllocated + x_size <= maximumSize;
45711308Santhony.gutierrez@amd.com    }
45811308Santhony.gutierrez@amd.com
45911308Santhony.gutierrez@amd.com  private:
46011308Santhony.gutierrez@amd.com    /**
46111308Santhony.gutierrez@amd.com     * give back the space
46211308Santhony.gutierrez@amd.com     */
46311308Santhony.gutierrez@amd.com    bool
46411308Santhony.gutierrez@amd.com    releaseSpace(const uint32_t x_dispatchId, const uint32_t x_wgId)
46511308Santhony.gutierrez@amd.com    {
46611308Santhony.gutierrez@amd.com        auto dispatchIter = chunkMap.find(x_dispatchId);
46711308Santhony.gutierrez@amd.com
46811308Santhony.gutierrez@amd.com        if (dispatchIter == chunkMap.end()) {
46911308Santhony.gutierrez@amd.com          fatal("dispatch id not found [%d]", x_dispatchId);
47011308Santhony.gutierrez@amd.com        } else {
47111308Santhony.gutierrez@amd.com          auto workgroupIter = dispatchIter->second.find(x_wgId);
47211308Santhony.gutierrez@amd.com          if (workgroupIter == dispatchIter->second.end()) {
47311308Santhony.gutierrez@amd.com            fatal("workgroup id [%d] not found in dispatch id [%d]",
47411308Santhony.gutierrez@amd.com                    x_wgId, x_dispatchId);
47511308Santhony.gutierrez@amd.com          }
47611308Santhony.gutierrez@amd.com        }
47711308Santhony.gutierrez@amd.com
47811308Santhony.gutierrez@amd.com        fatal_if(bytesAllocated < chunkMap[x_dispatchId][x_wgId].size(),
47911308Santhony.gutierrez@amd.com                 "releasing more space than was allocated");
48011308Santhony.gutierrez@amd.com
48111308Santhony.gutierrez@amd.com        bytesAllocated -= chunkMap[x_dispatchId][x_wgId].size();
48211308Santhony.gutierrez@amd.com        chunkMap[x_dispatchId].erase(chunkMap[x_dispatchId].find(x_wgId));
48311308Santhony.gutierrez@amd.com        return true;
48411308Santhony.gutierrez@amd.com    }
48511308Santhony.gutierrez@amd.com
48611308Santhony.gutierrez@amd.com    // the port that connects this LDS to its owner CU
48711308Santhony.gutierrez@amd.com    CuSidePort cuPort;
48811308Santhony.gutierrez@amd.com
48911308Santhony.gutierrez@amd.com    ComputeUnit* parent = nullptr;
49011308Santhony.gutierrez@amd.com
49111308Santhony.gutierrez@amd.com    std::string _name;
49211308Santhony.gutierrez@amd.com
49311308Santhony.gutierrez@amd.com    // the number of bytes currently reserved by all workgroups
49411308Santhony.gutierrez@amd.com    int bytesAllocated = 0;
49511308Santhony.gutierrez@amd.com
49611308Santhony.gutierrez@amd.com    // the size of the LDS, the most bytes available
49711308Santhony.gutierrez@amd.com    int maximumSize;
49811308Santhony.gutierrez@amd.com
49911308Santhony.gutierrez@amd.com    // Address range of this memory
50011308Santhony.gutierrez@amd.com    AddrRange range;
50111308Santhony.gutierrez@amd.com
50211308Santhony.gutierrez@amd.com    // the penalty, in cycles, for each LDS bank conflict
50311308Santhony.gutierrez@amd.com    int bankConflictPenalty = 0;
50411308Santhony.gutierrez@amd.com
50511308Santhony.gutierrez@amd.com    // the number of banks in the LDS underlying data store
50611308Santhony.gutierrez@amd.com    int banks = 0;
50711308Santhony.gutierrez@amd.com};
50811308Santhony.gutierrez@amd.com
50911308Santhony.gutierrez@amd.com#endif // __LDS_STATE_HH__
510