/*
 * Copyright (c) 2017,2019-2021 ARM Limited
 * All rights reserved.
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2009-2014 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
#define __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

#include <exception>
#include <iostream>
#include <string>
#include <unordered_map>

#include "base/addr_range.hh"
#include "base/addr_range_map.hh"
#include "base/callback.hh"
#include "mem/packet.hh"
#include "mem/qport.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/DataBlock.hh"
#include "mem/ruby/common/Histogram.hh"
#include "mem/ruby/common/MachineID.hh"
#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/protocol/AccessPermission.hh"
#include "mem/ruby/system/CacheRecorder.hh"
#include "params/RubyController.hh"
#include "sim/clocked_object.hh"

namespace gem5
{

namespace ruby
{

class Network;
class GPUCoalescer;
class DMASequencer;

// used to communicate that an in_port peeked the wrong message type
class RejectException: public std::exception
{
    virtual const char* what() const throw()
    { return "Port rejected message based on type"; }
};

class AbstractController : public ClockedObject, public Consumer
{
  public:
    PARAMS(RubyController);
    AbstractController(const Params &p);
    void init();

    NodeID getVersion() const { return m_machineID.getNum(); }
    MachineType getType() const { return m_machineID.getType(); }

    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }

    // return instance name
    void blockOnQueue(Addr, MessageBuffer*);
    bool isBlocked(Addr) const;
    void unblock(Addr);
    bool isBlocked(Addr);

    virtual MessageBuffer* getMandatoryQueue() const = 0;
    virtual MessageBuffer* getMemReqQueue() const = 0;
    virtual MessageBuffer* getMemRespQueue() const = 0;
    virtual AccessPermission getAccessPermission(const Addr &addr) = 0;

    virtual void print(std::ostream & out) const = 0;
    virtual void wakeup() = 0;
    virtual void resetStats() = 0;
    virtual void regStats();

    virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
    virtual Sequencer* getCPUSequencer() const = 0;
    virtual DMASequencer* getDMASequencer() const = 0;
    virtual GPUCoalescer* getGPUCoalescer() const = 0;

    // This latency is used by the sequencer when enqueueing requests.
    // Different latencies may be used depending on the request type.
    // This is the hit latency unless the top-level cache controller
    // introduces additional cycles in the response path.
    virtual Cycles mandatoryQueueLatency(const RubyRequestType& param_type)
    { return m_mandatory_queue_latency; }

    //! These functions are used by ruby system to read/write the data blocks
    //! that exist with in the controller.
    virtual bool functionalReadBuffers(PacketPtr&) = 0;
    virtual void functionalRead(const Addr &addr, PacketPtr)
    { panic("functionalRead(Addr,PacketPtr) not implemented"); }

    //! Functional read that reads only blocks not present in the mask.
    //! Return number of bytes read.
    virtual bool functionalReadBuffers(PacketPtr&, WriteMask &mask) = 0;
    virtual void functionalRead(const Addr &addr, PacketPtr pkt,
                               WriteMask &mask)
    { panic("functionalRead(Addr,PacketPtr,WriteMask) not implemented"); }

    void functionalMemoryRead(PacketPtr);
    //! The return value indicates the number of messages written with the
    //! data from the packet.
    virtual int functionalWriteBuffers(PacketPtr&) = 0;
    virtual int functionalWrite(const Addr &addr, PacketPtr) = 0;
    int functionalMemoryWrite(PacketPtr);

    //! Function for enqueuing a prefetch request
    virtual void enqueuePrefetch(const Addr &, const RubyRequestType&)
    { fatal("Prefetches not implemented!");}

    //! Notifies controller of a request coalesced at the sequencer.
    //! By default, it does nothing. Behavior is protocol-specific
    virtual void notifyCoalesced(const Addr& addr,
                                 const RubyRequestType& type,
                                 const RequestPtr& req,
                                 const DataBlock& data_blk,
                                 const bool& was_miss)
    { }

    //! Function for collating statistics from all the controllers of this
    //! particular type. This function should only be called from the
    //! version 0 of this controller type.
    virtual void collateStats()
    {fatal("collateStats() should be overridden!");}

    //! Initialize the message buffers.
    virtual void initNetQueues() = 0;

    /** A function used to return the port associated with this bus object. */
    Port &getPort(const std::string &if_name,
                  PortID idx=InvalidPortID);

    void recvTimingResp(PacketPtr pkt);
    Tick recvAtomic(PacketPtr pkt);

    const AddrRangeList &getAddrRanges() const { return addrRanges; }

  public:
    MachineID getMachineID() const { return m_machineID; }
    RequestorID getRequestorId() const { return m_id; }

    statistics::Histogram& getDelayHist() { return stats.delayHistogram; }
    statistics::Histogram& getDelayVCHist(uint32_t index)
    { return *(stats.delayVCHistogram[index]); }

    bool respondsTo(Addr addr)
    {
        for (auto &range: addrRanges)
            if (range.contains(addr)) return true;
        return false;
    }

    /**
     * Map an address to the correct MachineID
     *
     * This function querries the network for the NodeID of the
     * destination for a given request using its address and the type
     * of the destination. For example for a request with a given
     * address to a directory it will return the MachineID of the
     * authorative directory.
     *
     * @param the destination address
     * @param the type of the destination
     * @return the MachineID of the destination
     */
    MachineID mapAddressToMachine(Addr addr, MachineType mtype) const;

    /**
     * Maps an address to the correct dowstream MachineID (i.e. the component
     * in the next level of the cache hierarchy towards memory)
     *
     * This function uses the local list of possible destinations instead of
     * querying the network.
     *
     * @param the destination address
     * @param the type of the destination (optional)
     * @return the MachineID of the destination
     */
    MachineID mapAddressToDownstreamMachine(Addr addr,
                                    MachineType mtype = MachineType_NUM) const;

    const NetDest& allDownstreamDest() const { return downstreamDestinations; }

  protected:
    //! Profiles original cache requests including PUTs
    void profileRequest(const std::string &request);
    //! Profiles the delay associated with messages.
    void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);

    // Tracks outstanding transactions for latency profiling
    struct TransMapPair { unsigned transaction; unsigned state; Tick time; };
    std::unordered_map<Addr, TransMapPair> m_inTrans;
    std::unordered_map<Addr, TransMapPair> m_outTrans;

    /**
     * Profiles an event that initiates a protocol transactions for a specific
     * line (e.g. events triggered by incoming request messages).
     * A histogram with the latency of the transactions is generated for
     * all combinations of trigger event, initial state, and final state.
     *
     * @param addr address of the line
     * @param type event that started the transaction
     * @param initialState state of the line before the transaction
     */
    template<typename EventType, typename StateType>
    void incomingTransactionStart(Addr addr,
        EventType type, StateType initialState, bool retried)
    {
        assert(m_inTrans.find(addr) == m_inTrans.end());
        m_inTrans[addr] = {type, initialState, curTick()};
        if (retried)
          ++(*stats.inTransLatRetries[type]);
    }

    /**
     * Profiles an event that ends a transaction.
     *
     * @param addr address of the line with a outstanding transaction
     * @param finalState state of the line after the transaction
     */
    template<typename StateType>
    void incomingTransactionEnd(Addr addr, StateType finalState)
    {
        auto iter = m_inTrans.find(addr);
        assert(iter != m_inTrans.end());
        stats.inTransLatHist[iter->second.transaction]
                              [iter->second.state]
                              [(unsigned)finalState]->sample(
                                ticksToCycles(curTick() - iter->second.time));
        ++(*stats.inTransLatTotal[iter->second.transaction]);
       m_inTrans.erase(iter);
    }

    /**
     * Profiles an event that initiates a transaction in a peer controller
     * (e.g. an event that sends a request message)
     *
     * @param addr address of the line
     * @param type event that started the transaction
     */
    template<typename EventType>
    void outgoingTransactionStart(Addr addr, EventType type)
    {
        assert(m_outTrans.find(addr) == m_outTrans.end());
        m_outTrans[addr] = {type, 0, curTick()};
    }

    /**
     * Profiles the end of an outgoing transaction.
     * (e.g. receiving the response for a requests)
     *
     * @param addr address of the line with an outstanding transaction
     */
    void outgoingTransactionEnd(Addr addr, bool retried)
    {
        auto iter = m_outTrans.find(addr);
        assert(iter != m_outTrans.end());
        stats.outTransLatHist[iter->second.transaction]->sample(
            ticksToCycles(curTick() - iter->second.time));
        if (retried)
          ++(*stats.outTransLatHistRetries[iter->second.transaction]);
        m_outTrans.erase(iter);
    }

    void stallBuffer(MessageBuffer* buf, Addr addr);
    void wakeUpBuffer(MessageBuffer* buf, Addr addr);
    void wakeUpBuffers(Addr addr);
    void wakeUpAllBuffers(Addr addr);
    void wakeUpAllBuffers();
    bool serviceMemoryQueue();

  protected:
    const NodeID m_version;
    MachineID m_machineID;
    const NodeID m_clusterID;

    // RequestorID used by some components of gem5.
    const RequestorID m_id;

    Network *m_net_ptr;
    bool m_is_blocking;
    std::map<Addr, MessageBuffer*> m_block_map;

    typedef std::vector<MessageBuffer*> MsgVecType;
    typedef std::set<MessageBuffer*> MsgBufType;
    typedef std::map<Addr, MsgVecType* > WaitingBufType;
    WaitingBufType m_waiting_buffers;

    unsigned int m_in_ports;
    unsigned int m_cur_in_port;
    const int m_number_of_TBEs;
    const int m_transitions_per_cycle;
    const unsigned int m_buffer_size;
    Cycles m_recycle_latency;
    const Cycles m_mandatory_queue_latency;
    bool m_waiting_mem_retry;

    /**
     * Port that forwards requests and receives responses from the
     * memory controller.
     */
    class MemoryPort : public RequestPort
    {
      private:
        // Controller that operates this port.
        AbstractController *controller;

      public:
        MemoryPort(const std::string &_name, AbstractController *_controller,
                   PortID id = InvalidPortID);

      protected:
        // Function for receiving a timing response from the peer port.
        // Currently the pkt is handed to the coherence controller
        // associated with this port.
        bool recvTimingResp(PacketPtr pkt);

        void recvReqRetry();
    };

    /* Request port to the memory controller. */
    MemoryPort memoryPort;

    // State that is stored in packets sent to the memory controller.
    struct SenderState : public Packet::SenderState
    {
        // Id of the machine from which the request originated.
        MachineID id;

        SenderState(MachineID _id) : id(_id)
        {}
    };

  private:
    /** The address range to which the controller responds on the CPU side. */
    const AddrRangeList addrRanges;

    typedef std::unordered_map<MachineType, MachineID> AddrMapEntry;

    AddrRangeMap<AddrMapEntry, 3> downstreamAddrMap;

    NetDest downstreamDestinations;

  public:
    struct ControllerStats : public statistics::Group
    {
        ControllerStats(statistics::Group *parent);

        // Initialized by the SLICC compiler for all combinations of event and
        // states. Only histograms with samples will appear in the stats
        std::vector<std::vector<std::vector<statistics::Histogram*>>>
          inTransLatHist;
        std::vector<statistics::Scalar*> inTransLatRetries;
        std::vector<statistics::Scalar*> inTransLatTotal;

        // Initialized by the SLICC compiler for all events.
        // Only histograms with samples will appear in the stats.
        std::vector<statistics::Histogram*> outTransLatHist;
        std::vector<statistics::Scalar*> outTransLatHistRetries;

        //! Counter for the number of cycles when the transitions carried out
        //! were equal to the maximum allowed
        statistics::Scalar fullyBusyCycles;

        //! Histogram for profiling delay for the messages this controller
        //! cares for
        statistics::Histogram delayHistogram;
        std::vector<statistics::Histogram *> delayVCHistogram;
    } stats;

};

} // namespace ruby
} // namespace gem5

#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
