simple_cache.hh revision 12339:1141f798a210
1/*
2 * Copyright (c) 2017 Jason Lowe-Power
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jason Lowe-Power
29 */
30
31#ifndef __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
32#define __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
33
34#include <unordered_map>
35
36#include "mem/mem_object.hh"
37#include "params/SimpleCache.hh"
38
39/**
40 * A very simple cache object. Has a fully-associative data store with random
41 * replacement.
42 * This cache is fully blocking (not non-blocking). Only a single request can
43 * be outstanding at a time.
44 * This cache is a writeback cache.
45 */
46class SimpleCache : public MemObject
47{
48  private:
49
50    /**
51     * Port on the CPU-side that receives requests.
52     * Mostly just forwards requests to the cache (owner)
53     */
54    class CPUSidePort : public SlavePort
55    {
56      private:
57        /// Since this is a vector port, need to know what number this one is
58        int id;
59
60        /// The object that owns this object (SimpleCache)
61        SimpleCache *owner;
62
63        /// True if the port needs to send a retry req.
64        bool needRetry;
65
66        /// If we tried to send a packet and it was blocked, store it here
67        PacketPtr blockedPacket;
68
69      public:
70        /**
71         * Constructor. Just calls the superclass constructor.
72         */
73        CPUSidePort(const std::string& name, int id, SimpleCache *owner) :
74            SlavePort(name, owner), id(id), owner(owner), needRetry(false),
75            blockedPacket(nullptr)
76        { }
77
78        /**
79         * Send a packet across this port. This is called by the owner and
80         * all of the flow control is hanled in this function.
81         * This is a convenience function for the SimpleCache to send pkts.
82         *
83         * @param packet to send.
84         */
85        void sendPacket(PacketPtr pkt);
86
87        /**
88         * Get a list of the non-overlapping address ranges the owner is
89         * responsible for. All slave ports must override this function
90         * and return a populated list with at least one item.
91         *
92         * @return a list of ranges responded to
93         */
94        AddrRangeList getAddrRanges() const override;
95
96        /**
97         * Send a retry to the peer port only if it is needed. This is called
98         * from the SimpleCache whenever it is unblocked.
99         */
100        void trySendRetry();
101
102      protected:
103        /**
104         * Receive an atomic request packet from the master port.
105         * No need to implement in this simple cache.
106         */
107        Tick recvAtomic(PacketPtr pkt) override
108        { panic("recvAtomic unimpl."); }
109
110        /**
111         * Receive a functional request packet from the master port.
112         * Performs a "debug" access updating/reading the data in place.
113         *
114         * @param packet the requestor sent.
115         */
116        void recvFunctional(PacketPtr pkt) override;
117
118        /**
119         * Receive a timing request from the master port.
120         *
121         * @param the packet that the requestor sent
122         * @return whether this object can consume to packet. If false, we
123         *         will call sendRetry() when we can try to receive this
124         *         request again.
125         */
126        bool recvTimingReq(PacketPtr pkt) override;
127
128        /**
129         * Called by the master port if sendTimingResp was called on this
130         * slave port (causing recvTimingResp to be called on the master
131         * port) and was unsuccesful.
132         */
133        void recvRespRetry() override;
134    };
135
136    /**
137     * Port on the memory-side that receives responses.
138     * Mostly just forwards requests to the cache (owner)
139     */
140    class MemSidePort : public MasterPort
141    {
142      private:
143        /// The object that owns this object (SimpleCache)
144        SimpleCache *owner;
145
146        /// If we tried to send a packet and it was blocked, store it here
147        PacketPtr blockedPacket;
148
149      public:
150        /**
151         * Constructor. Just calls the superclass constructor.
152         */
153        MemSidePort(const std::string& name, SimpleCache *owner) :
154            MasterPort(name, owner), owner(owner), blockedPacket(nullptr)
155        { }
156
157        /**
158         * Send a packet across this port. This is called by the owner and
159         * all of the flow control is hanled in this function.
160         * This is a convenience function for the SimpleCache to send pkts.
161         *
162         * @param packet to send.
163         */
164        void sendPacket(PacketPtr pkt);
165
166      protected:
167        /**
168         * Receive a timing response from the slave port.
169         */
170        bool recvTimingResp(PacketPtr pkt) override;
171
172        /**
173         * Called by the slave port if sendTimingReq was called on this
174         * master port (causing recvTimingReq to be called on the slave
175         * port) and was unsuccesful.
176         */
177        void recvReqRetry() override;
178
179        /**
180         * Called to receive an address range change from the peer slave
181         * port. The default implementation ignores the change and does
182         * nothing. Override this function in a derived class if the owner
183         * needs to be aware of the address ranges, e.g. in an
184         * interconnect component like a bus.
185         */
186        void recvRangeChange() override;
187    };
188
189    /**
190     * Handle the request from the CPU side. Called from the CPU port
191     * on a timing request.
192     *
193     * @param requesting packet
194     * @param id of the port to send the response
195     * @return true if we can handle the request this cycle, false if the
196     *         requestor needs to retry later
197     */
198    bool handleRequest(PacketPtr pkt, int port_id);
199
200    /**
201     * Handle the respone from the memory side. Called from the memory port
202     * on a timing response.
203     *
204     * @param responding packet
205     * @return true if we can handle the response this cycle, false if the
206     *         responder needs to retry later
207     */
208    bool handleResponse(PacketPtr pkt);
209
210    /**
211     * Send the packet to the CPU side.
212     * This function assumes the pkt is already a response packet and forwards
213     * it to the correct port. This function also unblocks this object and
214     * cleans up the whole request.
215     *
216     * @param the packet to send to the cpu side
217     */
218    void sendResponse(PacketPtr pkt);
219
220    /**
221     * Handle a packet functionally. Update the data on a write and get the
222     * data on a read. Called from CPU port on a recv functional.
223     *
224     * @param packet to functionally handle
225     */
226    void handleFunctional(PacketPtr pkt);
227
228    /**
229     * Access the cache for a timing access. This is called after the cache
230     * access latency has already elapsed.
231     */
232    void accessTiming(PacketPtr pkt);
233
234    /**
235     * This is where we actually update / read from the cache. This function
236     * is executed on both timing and functional accesses.
237     *
238     * @return true if a hit, false otherwise
239     */
240    bool accessFunctional(PacketPtr pkt);
241
242    /**
243     * Insert a block into the cache. If there is no room left in the cache,
244     * then this function evicts a random entry t make room for the new block.
245     *
246     * @param packet with the data (and address) to insert into the cache
247     */
248    void insert(PacketPtr pkt);
249
250    /**
251     * Return the address ranges this cache is responsible for. Just use the
252     * same as the next upper level of the hierarchy.
253     *
254     * @return the address ranges this cache is responsible for
255     */
256    AddrRangeList getAddrRanges() const;
257
258    /**
259     * Tell the CPU side to ask for our memory ranges.
260     */
261    void sendRangeChange() const;
262
263    /// Latency to check the cache. Number of cycles for both hit and miss
264    const Cycles latency;
265
266    /// The block size for the cache
267    const unsigned blockSize;
268
269    /// Number of blocks in the cache (size of cache / block size)
270    const unsigned capacity;
271
272    /// Instantiation of the CPU-side port
273    std::vector<CPUSidePort> cpuPorts;
274
275    /// Instantiation of the memory-side port
276    MemSidePort memPort;
277
278    /// True if this cache is currently blocked waiting for a response.
279    bool blocked;
280
281    /// Packet that we are currently handling. Used for upgrading to larger
282    /// cache line sizes
283    PacketPtr originalPacket;
284
285    /// The port to send the response when we recieve it back
286    int waitingPortId;
287
288    /// For tracking the miss latency
289    Tick missTime;
290
291    /// An incredibly simple cache storage. Maps block addresses to data
292    std::unordered_map<Addr, uint8_t*> cacheStore;
293
294    /// Cache statistics
295    Stats::Scalar hits;
296    Stats::Scalar misses;
297    Stats::Histogram missLatency;
298    Stats::Formula hitRatio;
299
300  public:
301
302    /** constructor
303     */
304    SimpleCache(SimpleCacheParams *params);
305
306    /**
307     * Get a master port with a given name and index. This is used at
308     * binding time and returns a reference to a protocol-agnostic
309     * base master port.
310     *
311     * @param if_name Port name
312     * @param idx Index in the case of a VectorPort
313     *
314     * @return A reference to the given port
315     */
316    virtual BaseMasterPort& getMasterPort(const std::string& if_name,
317                                          PortID idx = InvalidPortID) override;
318
319    /**
320     * Get a slave port with a given name and index. This is used at
321     * binding time and returns a reference to a protocol-agnostic
322     * base master port.
323     *
324     * @param if_name Port name
325     * @param idx Index in the case of a VectorPort
326     *
327     * @return A reference to the given port
328     */
329    virtual BaseSlavePort& getSlavePort(const std::string& if_name,
330                                        PortID idx = InvalidPortID) override;
331
332    /**
333     * Register the stats
334     */
335    void regStats() override;
336};
337
338
339#endif // __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__
340