112339Sjason@lowepower.com/*
212339Sjason@lowepower.com * Copyright (c) 2017 Jason Lowe-Power
312339Sjason@lowepower.com * All rights reserved.
412339Sjason@lowepower.com *
512339Sjason@lowepower.com * Redistribution and use in source and binary forms, with or without
612339Sjason@lowepower.com * modification, are permitted provided that the following conditions are
712339Sjason@lowepower.com * met: redistributions of source code must retain the above copyright
812339Sjason@lowepower.com * notice, this list of conditions and the following disclaimer;
912339Sjason@lowepower.com * redistributions in binary form must reproduce the above copyright
1012339Sjason@lowepower.com * notice, this list of conditions and the following disclaimer in the
1112339Sjason@lowepower.com * documentation and/or other materials provided with the distribution;
1212339Sjason@lowepower.com * neither the name of the copyright holders nor the names of its
1312339Sjason@lowepower.com * contributors may be used to endorse or promote products derived from
1412339Sjason@lowepower.com * this software without specific prior written permission.
1512339Sjason@lowepower.com *
1612339Sjason@lowepower.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712339Sjason@lowepower.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812339Sjason@lowepower.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912339Sjason@lowepower.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012339Sjason@lowepower.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112339Sjason@lowepower.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212339Sjason@lowepower.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312339Sjason@lowepower.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412339Sjason@lowepower.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512339Sjason@lowepower.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612339Sjason@lowepower.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712339Sjason@lowepower.com *
2812339Sjason@lowepower.com * Authors: Jason Lowe-Power
2912339Sjason@lowepower.com */
3012339Sjason@lowepower.com
3112339Sjason@lowepower.com#ifndef __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
3212339Sjason@lowepower.com#define __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
3312339Sjason@lowepower.com
3412339Sjason@lowepower.com#include <unordered_map>
3512339Sjason@lowepower.com
3614252Sgabeblack@google.com#include "base/statistics.hh"
3714252Sgabeblack@google.com#include "mem/port.hh"
3812339Sjason@lowepower.com#include "params/SimpleCache.hh"
3914252Sgabeblack@google.com#include "sim/clocked_object.hh"
4012339Sjason@lowepower.com
4112339Sjason@lowepower.com/**
4212339Sjason@lowepower.com * A very simple cache object. Has a fully-associative data store with random
4312339Sjason@lowepower.com * replacement.
4412339Sjason@lowepower.com * This cache is fully blocking (not non-blocking). Only a single request can
4512339Sjason@lowepower.com * be outstanding at a time.
4612339Sjason@lowepower.com * This cache is a writeback cache.
4712339Sjason@lowepower.com */
4814252Sgabeblack@google.comclass SimpleCache : public ClockedObject
4912339Sjason@lowepower.com{
5012339Sjason@lowepower.com  private:
5112339Sjason@lowepower.com
5212339Sjason@lowepower.com    /**
5312339Sjason@lowepower.com     * Port on the CPU-side that receives requests.
5412339Sjason@lowepower.com     * Mostly just forwards requests to the cache (owner)
5512339Sjason@lowepower.com     */
5612339Sjason@lowepower.com    class CPUSidePort : public SlavePort
5712339Sjason@lowepower.com    {
5812339Sjason@lowepower.com      private:
5912339Sjason@lowepower.com        /// Since this is a vector port, need to know what number this one is
6012339Sjason@lowepower.com        int id;
6112339Sjason@lowepower.com
6212339Sjason@lowepower.com        /// The object that owns this object (SimpleCache)
6312339Sjason@lowepower.com        SimpleCache *owner;
6412339Sjason@lowepower.com
6512339Sjason@lowepower.com        /// True if the port needs to send a retry req.
6612339Sjason@lowepower.com        bool needRetry;
6712339Sjason@lowepower.com
6812339Sjason@lowepower.com        /// If we tried to send a packet and it was blocked, store it here
6912339Sjason@lowepower.com        PacketPtr blockedPacket;
7012339Sjason@lowepower.com
7112339Sjason@lowepower.com      public:
7212339Sjason@lowepower.com        /**
7312339Sjason@lowepower.com         * Constructor. Just calls the superclass constructor.
7412339Sjason@lowepower.com         */
7512339Sjason@lowepower.com        CPUSidePort(const std::string& name, int id, SimpleCache *owner) :
7612339Sjason@lowepower.com            SlavePort(name, owner), id(id), owner(owner), needRetry(false),
7712339Sjason@lowepower.com            blockedPacket(nullptr)
7812339Sjason@lowepower.com        { }
7912339Sjason@lowepower.com
8012339Sjason@lowepower.com        /**
8112339Sjason@lowepower.com         * Send a packet across this port. This is called by the owner and
8212339Sjason@lowepower.com         * all of the flow control is hanled in this function.
8312339Sjason@lowepower.com         * This is a convenience function for the SimpleCache to send pkts.
8412339Sjason@lowepower.com         *
8512339Sjason@lowepower.com         * @param packet to send.
8612339Sjason@lowepower.com         */
8712339Sjason@lowepower.com        void sendPacket(PacketPtr pkt);
8812339Sjason@lowepower.com
8912339Sjason@lowepower.com        /**
9012339Sjason@lowepower.com         * Get a list of the non-overlapping address ranges the owner is
9112339Sjason@lowepower.com         * responsible for. All slave ports must override this function
9212339Sjason@lowepower.com         * and return a populated list with at least one item.
9312339Sjason@lowepower.com         *
9412339Sjason@lowepower.com         * @return a list of ranges responded to
9512339Sjason@lowepower.com         */
9612339Sjason@lowepower.com        AddrRangeList getAddrRanges() const override;
9712339Sjason@lowepower.com
9812339Sjason@lowepower.com        /**
9912339Sjason@lowepower.com         * Send a retry to the peer port only if it is needed. This is called
10012339Sjason@lowepower.com         * from the SimpleCache whenever it is unblocked.
10112339Sjason@lowepower.com         */
10212339Sjason@lowepower.com        void trySendRetry();
10312339Sjason@lowepower.com
10412339Sjason@lowepower.com      protected:
10512339Sjason@lowepower.com        /**
10612339Sjason@lowepower.com         * Receive an atomic request packet from the master port.
10712339Sjason@lowepower.com         * No need to implement in this simple cache.
10812339Sjason@lowepower.com         */
10912339Sjason@lowepower.com        Tick recvAtomic(PacketPtr pkt) override
11012339Sjason@lowepower.com        { panic("recvAtomic unimpl."); }
11112339Sjason@lowepower.com
11212339Sjason@lowepower.com        /**
11312339Sjason@lowepower.com         * Receive a functional request packet from the master port.
11412339Sjason@lowepower.com         * Performs a "debug" access updating/reading the data in place.
11512339Sjason@lowepower.com         *
11612339Sjason@lowepower.com         * @param packet the requestor sent.
11712339Sjason@lowepower.com         */
11812339Sjason@lowepower.com        void recvFunctional(PacketPtr pkt) override;
11912339Sjason@lowepower.com
12012339Sjason@lowepower.com        /**
12112339Sjason@lowepower.com         * Receive a timing request from the master port.
12212339Sjason@lowepower.com         *
12312339Sjason@lowepower.com         * @param the packet that the requestor sent
12412339Sjason@lowepower.com         * @return whether this object can consume to packet. If false, we
12512339Sjason@lowepower.com         *         will call sendRetry() when we can try to receive this
12612339Sjason@lowepower.com         *         request again.
12712339Sjason@lowepower.com         */
12812339Sjason@lowepower.com        bool recvTimingReq(PacketPtr pkt) override;
12912339Sjason@lowepower.com
13012339Sjason@lowepower.com        /**
13112339Sjason@lowepower.com         * Called by the master port if sendTimingResp was called on this
13212339Sjason@lowepower.com         * slave port (causing recvTimingResp to be called on the master
13312339Sjason@lowepower.com         * port) and was unsuccesful.
13412339Sjason@lowepower.com         */
13512339Sjason@lowepower.com        void recvRespRetry() override;
13612339Sjason@lowepower.com    };
13712339Sjason@lowepower.com
13812339Sjason@lowepower.com    /**
13912339Sjason@lowepower.com     * Port on the memory-side that receives responses.
14012339Sjason@lowepower.com     * Mostly just forwards requests to the cache (owner)
14112339Sjason@lowepower.com     */
14212339Sjason@lowepower.com    class MemSidePort : public MasterPort
14312339Sjason@lowepower.com    {
14412339Sjason@lowepower.com      private:
14512339Sjason@lowepower.com        /// The object that owns this object (SimpleCache)
14612339Sjason@lowepower.com        SimpleCache *owner;
14712339Sjason@lowepower.com
14812339Sjason@lowepower.com        /// If we tried to send a packet and it was blocked, store it here
14912339Sjason@lowepower.com        PacketPtr blockedPacket;
15012339Sjason@lowepower.com
15112339Sjason@lowepower.com      public:
15212339Sjason@lowepower.com        /**
15312339Sjason@lowepower.com         * Constructor. Just calls the superclass constructor.
15412339Sjason@lowepower.com         */
15512339Sjason@lowepower.com        MemSidePort(const std::string& name, SimpleCache *owner) :
15612339Sjason@lowepower.com            MasterPort(name, owner), owner(owner), blockedPacket(nullptr)
15712339Sjason@lowepower.com        { }
15812339Sjason@lowepower.com
15912339Sjason@lowepower.com        /**
16012339Sjason@lowepower.com         * Send a packet across this port. This is called by the owner and
16112339Sjason@lowepower.com         * all of the flow control is hanled in this function.
16212339Sjason@lowepower.com         * This is a convenience function for the SimpleCache to send pkts.
16312339Sjason@lowepower.com         *
16412339Sjason@lowepower.com         * @param packet to send.
16512339Sjason@lowepower.com         */
16612339Sjason@lowepower.com        void sendPacket(PacketPtr pkt);
16712339Sjason@lowepower.com
16812339Sjason@lowepower.com      protected:
16912339Sjason@lowepower.com        /**
17012339Sjason@lowepower.com         * Receive a timing response from the slave port.
17112339Sjason@lowepower.com         */
17212339Sjason@lowepower.com        bool recvTimingResp(PacketPtr pkt) override;
17312339Sjason@lowepower.com
17412339Sjason@lowepower.com        /**
17512339Sjason@lowepower.com         * Called by the slave port if sendTimingReq was called on this
17612339Sjason@lowepower.com         * master port (causing recvTimingReq to be called on the slave
17712339Sjason@lowepower.com         * port) and was unsuccesful.
17812339Sjason@lowepower.com         */
17912339Sjason@lowepower.com        void recvReqRetry() override;
18012339Sjason@lowepower.com
18112339Sjason@lowepower.com        /**
18212339Sjason@lowepower.com         * Called to receive an address range change from the peer slave
18312339Sjason@lowepower.com         * port. The default implementation ignores the change and does
18412339Sjason@lowepower.com         * nothing. Override this function in a derived class if the owner
18512339Sjason@lowepower.com         * needs to be aware of the address ranges, e.g. in an
18612339Sjason@lowepower.com         * interconnect component like a bus.
18712339Sjason@lowepower.com         */
18812339Sjason@lowepower.com        void recvRangeChange() override;
18912339Sjason@lowepower.com    };
19012339Sjason@lowepower.com
19112339Sjason@lowepower.com    /**
19212339Sjason@lowepower.com     * Handle the request from the CPU side. Called from the CPU port
19312339Sjason@lowepower.com     * on a timing request.
19412339Sjason@lowepower.com     *
19512339Sjason@lowepower.com     * @param requesting packet
19612339Sjason@lowepower.com     * @param id of the port to send the response
19712339Sjason@lowepower.com     * @return true if we can handle the request this cycle, false if the
19812339Sjason@lowepower.com     *         requestor needs to retry later
19912339Sjason@lowepower.com     */
20012339Sjason@lowepower.com    bool handleRequest(PacketPtr pkt, int port_id);
20112339Sjason@lowepower.com
20212339Sjason@lowepower.com    /**
20312339Sjason@lowepower.com     * Handle the respone from the memory side. Called from the memory port
20412339Sjason@lowepower.com     * on a timing response.
20512339Sjason@lowepower.com     *
20612339Sjason@lowepower.com     * @param responding packet
20712339Sjason@lowepower.com     * @return true if we can handle the response this cycle, false if the
20812339Sjason@lowepower.com     *         responder needs to retry later
20912339Sjason@lowepower.com     */
21012339Sjason@lowepower.com    bool handleResponse(PacketPtr pkt);
21112339Sjason@lowepower.com
21212339Sjason@lowepower.com    /**
21312339Sjason@lowepower.com     * Send the packet to the CPU side.
21412339Sjason@lowepower.com     * This function assumes the pkt is already a response packet and forwards
21512339Sjason@lowepower.com     * it to the correct port. This function also unblocks this object and
21612339Sjason@lowepower.com     * cleans up the whole request.
21712339Sjason@lowepower.com     *
21812339Sjason@lowepower.com     * @param the packet to send to the cpu side
21912339Sjason@lowepower.com     */
22012339Sjason@lowepower.com    void sendResponse(PacketPtr pkt);
22112339Sjason@lowepower.com
22212339Sjason@lowepower.com    /**
22312339Sjason@lowepower.com     * Handle a packet functionally. Update the data on a write and get the
22412339Sjason@lowepower.com     * data on a read. Called from CPU port on a recv functional.
22512339Sjason@lowepower.com     *
22612339Sjason@lowepower.com     * @param packet to functionally handle
22712339Sjason@lowepower.com     */
22812339Sjason@lowepower.com    void handleFunctional(PacketPtr pkt);
22912339Sjason@lowepower.com
23012339Sjason@lowepower.com    /**
23112339Sjason@lowepower.com     * Access the cache for a timing access. This is called after the cache
23212339Sjason@lowepower.com     * access latency has already elapsed.
23312339Sjason@lowepower.com     */
23412339Sjason@lowepower.com    void accessTiming(PacketPtr pkt);
23512339Sjason@lowepower.com
23612339Sjason@lowepower.com    /**
23712339Sjason@lowepower.com     * This is where we actually update / read from the cache. This function
23812339Sjason@lowepower.com     * is executed on both timing and functional accesses.
23912339Sjason@lowepower.com     *
24012339Sjason@lowepower.com     * @return true if a hit, false otherwise
24112339Sjason@lowepower.com     */
24212339Sjason@lowepower.com    bool accessFunctional(PacketPtr pkt);
24312339Sjason@lowepower.com
24412339Sjason@lowepower.com    /**
24512339Sjason@lowepower.com     * Insert a block into the cache. If there is no room left in the cache,
24612339Sjason@lowepower.com     * then this function evicts a random entry t make room for the new block.
24712339Sjason@lowepower.com     *
24812339Sjason@lowepower.com     * @param packet with the data (and address) to insert into the cache
24912339Sjason@lowepower.com     */
25012339Sjason@lowepower.com    void insert(PacketPtr pkt);
25112339Sjason@lowepower.com
25212339Sjason@lowepower.com    /**
25312339Sjason@lowepower.com     * Return the address ranges this cache is responsible for. Just use the
25412339Sjason@lowepower.com     * same as the next upper level of the hierarchy.
25512339Sjason@lowepower.com     *
25612339Sjason@lowepower.com     * @return the address ranges this cache is responsible for
25712339Sjason@lowepower.com     */
25812339Sjason@lowepower.com    AddrRangeList getAddrRanges() const;
25912339Sjason@lowepower.com
26012339Sjason@lowepower.com    /**
26112339Sjason@lowepower.com     * Tell the CPU side to ask for our memory ranges.
26212339Sjason@lowepower.com     */
26312339Sjason@lowepower.com    void sendRangeChange() const;
26412339Sjason@lowepower.com
26512339Sjason@lowepower.com    /// Latency to check the cache. Number of cycles for both hit and miss
26612339Sjason@lowepower.com    const Cycles latency;
26712339Sjason@lowepower.com
26812339Sjason@lowepower.com    /// The block size for the cache
26912339Sjason@lowepower.com    const unsigned blockSize;
27012339Sjason@lowepower.com
27112339Sjason@lowepower.com    /// Number of blocks in the cache (size of cache / block size)
27212339Sjason@lowepower.com    const unsigned capacity;
27312339Sjason@lowepower.com
27412339Sjason@lowepower.com    /// Instantiation of the CPU-side port
27512339Sjason@lowepower.com    std::vector<CPUSidePort> cpuPorts;
27612339Sjason@lowepower.com
27712339Sjason@lowepower.com    /// Instantiation of the memory-side port
27812339Sjason@lowepower.com    MemSidePort memPort;
27912339Sjason@lowepower.com
28012339Sjason@lowepower.com    /// True if this cache is currently blocked waiting for a response.
28112339Sjason@lowepower.com    bool blocked;
28212339Sjason@lowepower.com
28312339Sjason@lowepower.com    /// Packet that we are currently handling. Used for upgrading to larger
28412339Sjason@lowepower.com    /// cache line sizes
28512339Sjason@lowepower.com    PacketPtr originalPacket;
28612339Sjason@lowepower.com
28712339Sjason@lowepower.com    /// The port to send the response when we recieve it back
28812339Sjason@lowepower.com    int waitingPortId;
28912339Sjason@lowepower.com
29012339Sjason@lowepower.com    /// For tracking the miss latency
29112339Sjason@lowepower.com    Tick missTime;
29212339Sjason@lowepower.com
29312339Sjason@lowepower.com    /// An incredibly simple cache storage. Maps block addresses to data
29412339Sjason@lowepower.com    std::unordered_map<Addr, uint8_t*> cacheStore;
29512339Sjason@lowepower.com
29612339Sjason@lowepower.com    /// Cache statistics
29712339Sjason@lowepower.com    Stats::Scalar hits;
29812339Sjason@lowepower.com    Stats::Scalar misses;
29912339Sjason@lowepower.com    Stats::Histogram missLatency;
30012339Sjason@lowepower.com    Stats::Formula hitRatio;
30112339Sjason@lowepower.com
30212339Sjason@lowepower.com  public:
30312339Sjason@lowepower.com
30412339Sjason@lowepower.com    /** constructor
30512339Sjason@lowepower.com     */
30612339Sjason@lowepower.com    SimpleCache(SimpleCacheParams *params);
30712339Sjason@lowepower.com
30812339Sjason@lowepower.com    /**
30913784Sgabeblack@google.com     * Get a port with a given name and index. This is used at
31012339Sjason@lowepower.com     * binding time and returns a reference to a protocol-agnostic
31113784Sgabeblack@google.com     * port.
31212339Sjason@lowepower.com     *
31312339Sjason@lowepower.com     * @param if_name Port name
31412339Sjason@lowepower.com     * @param idx Index in the case of a VectorPort
31512339Sjason@lowepower.com     *
31612339Sjason@lowepower.com     * @return A reference to the given port
31712339Sjason@lowepower.com     */
31813784Sgabeblack@google.com    Port &getPort(const std::string &if_name,
31913784Sgabeblack@google.com                  PortID idx=InvalidPortID) override;
32012339Sjason@lowepower.com
32112339Sjason@lowepower.com    /**
32212339Sjason@lowepower.com     * Register the stats
32312339Sjason@lowepower.com     */
32412339Sjason@lowepower.com    void regStats() override;
32512339Sjason@lowepower.com};
32612339Sjason@lowepower.com
32712339Sjason@lowepower.com
32812339Sjason@lowepower.com#endif // __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
329