base.hh revision 3170
1/*
2 * Copyright (c) 2003-2005 The Regents of The University of Michigan
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: Erik Hallnor
29 */
30
31/**
32 * @file
33 * Declares a basic cache interface BaseCache.
34 */
35
36#ifndef __BASE_CACHE_HH__
37#define __BASE_CACHE_HH__
38
39#include <vector>
40#include <string>
41#include <list>
42#include <inttypes.h>
43
44#include "base/misc.hh"
45#include "base/statistics.hh"
46#include "base/trace.hh"
47#include "mem/mem_object.hh"
48#include "mem/packet.hh"
49#include "mem/port.hh"
50#include "mem/request.hh"
51#include "sim/eventq.hh"
52
53/**
54 * Reasons for Caches to be Blocked.
55 */
56enum BlockedCause{
57    Blocked_NoMSHRs,
58    Blocked_NoTargets,
59    Blocked_NoWBBuffers,
60    Blocked_Coherence,
61    Blocked_Copy,
62    NUM_BLOCKED_CAUSES
63};
64
65/**
66 * Reasons for cache to request a bus.
67 */
68enum RequestCause{
69    Request_MSHR,
70    Request_WB,
71    Request_Coherence,
72    Request_PF
73};
74
75/**
76 * A basic cache interface. Implements some common functions for speed.
77 */
78class BaseCache : public MemObject
79{
80    class CachePort : public Port
81    {
82      public:
83        BaseCache *cache;
84
85        CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
86
87      protected:
88        virtual bool recvTiming(Packet *pkt);
89
90        virtual Tick recvAtomic(Packet *pkt);
91
92        virtual void recvFunctional(Packet *pkt);
93
94        virtual void recvStatusChange(Status status);
95
96        virtual void getDeviceAddressRanges(AddrRangeList &resp,
97                                            AddrRangeList &snoop);
98
99        virtual int deviceBlockSize();
100
101        virtual void recvRetry();
102
103      public:
104        void setBlocked();
105
106        void clearBlocked();
107
108        bool blocked;
109
110        bool mustSendRetry;
111
112        bool isCpuSide;
113
114        std::list<Packet *> drainList;
115    };
116
117    struct CacheEvent : public Event
118    {
119        CachePort *cachePort;
120        Packet *pkt;
121
122        CacheEvent(CachePort *_cachePort);
123        CacheEvent(CachePort *_cachePort, Packet *_pkt);
124        void process();
125        const char *description();
126    };
127
128  protected:
129    CachePort *cpuSidePort;
130    CachePort *memSidePort;
131
132    bool snoopRangesSent;
133
134  public:
135    virtual Port *getPort(const std::string &if_name, int idx = -1);
136
137  private:
138    //To be defined in cache_impl.hh not in base class
139    virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
140    {
141        fatal("No implementation");
142    }
143
144    virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide)
145    {
146        fatal("No implementation");
147    }
148
149    virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide)
150    {
151        fatal("No implementation");
152    }
153
154    void recvStatusChange(Port::Status status, bool isCpuSide)
155    {
156        if (status == Port::RangeChange){
157            if (!isCpuSide) {
158                cpuSidePort->sendStatusChange(Port::RangeChange);
159                if (topLevelCache && !snoopRangesSent) {
160                    snoopRangesSent = true;
161                    memSidePort->sendStatusChange(Port::RangeChange);
162                }
163            }
164            else {
165                memSidePort->sendStatusChange(Port::RangeChange);
166            }
167        }
168        else if (status == Port::SnoopSquash) {
169            assert(snoopPhase2);
170            snoopPhase2 = false;
171        }
172    }
173
174    virtual Packet *getPacket()
175    {
176        fatal("No implementation");
177    }
178
179    virtual Packet *getCoherencePacket()
180    {
181        fatal("No implementation");
182    }
183
184    virtual void sendResult(Packet* &pkt, bool success)
185    {
186
187        fatal("No implementation");
188    }
189
190    /**
191     * Bit vector of the blocking reasons for the access path.
192     * @sa #BlockedCause
193     */
194    uint8_t blocked;
195
196    /**
197     * Bit vector for the blocking reasons for the snoop path.
198     * @sa #BlockedCause
199     */
200    uint8_t blockedSnoop;
201
202    /**
203     * Bit vector for the outstanding requests for the master interface.
204     */
205    uint8_t masterRequests;
206
207    /**
208     * Bit vector for the outstanding requests for the slave interface.
209     */
210    uint8_t slaveRequests;
211
212  protected:
213
214    /** True if this cache is connected to the CPU. */
215    bool topLevelCache;
216
217
218    /** True if we are now in phase 2 of the snoop process. */
219    bool snoopPhase2;
220
221    /** Stores time the cache blocked for statistics. */
222    Tick blockedCycle;
223
224    /** Block size of this cache */
225    const int blkSize;
226
227    /** The number of misses to trigger an exit event. */
228    Counter missCount;
229
230  public:
231    // Statistics
232    /**
233     * @addtogroup CacheStatistics
234     * @{
235     */
236
237    /** Number of hits per thread for each type of command. @sa Packet::Command */
238    Stats::Vector<> hits[NUM_MEM_CMDS];
239    /** Number of hits for demand accesses. */
240    Stats::Formula demandHits;
241    /** Number of hit for all accesses. */
242    Stats::Formula overallHits;
243
244    /** Number of misses per thread for each type of command. @sa Packet::Command */
245    Stats::Vector<> misses[NUM_MEM_CMDS];
246    /** Number of misses for demand accesses. */
247    Stats::Formula demandMisses;
248    /** Number of misses for all accesses. */
249    Stats::Formula overallMisses;
250
251    /**
252     * Total number of cycles per thread/command spent waiting for a miss.
253     * Used to calculate the average miss latency.
254     */
255    Stats::Vector<> missLatency[NUM_MEM_CMDS];
256    /** Total number of cycles spent waiting for demand misses. */
257    Stats::Formula demandMissLatency;
258    /** Total number of cycles spent waiting for all misses. */
259    Stats::Formula overallMissLatency;
260
261    /** The number of accesses per command and thread. */
262    Stats::Formula accesses[NUM_MEM_CMDS];
263    /** The number of demand accesses. */
264    Stats::Formula demandAccesses;
265    /** The number of overall accesses. */
266    Stats::Formula overallAccesses;
267
268    /** The miss rate per command and thread. */
269    Stats::Formula missRate[NUM_MEM_CMDS];
270    /** The miss rate of all demand accesses. */
271    Stats::Formula demandMissRate;
272    /** The miss rate for all accesses. */
273    Stats::Formula overallMissRate;
274
275    /** The average miss latency per command and thread. */
276    Stats::Formula avgMissLatency[NUM_MEM_CMDS];
277    /** The average miss latency for demand misses. */
278    Stats::Formula demandAvgMissLatency;
279    /** The average miss latency for all misses. */
280    Stats::Formula overallAvgMissLatency;
281
282    /** The total number of cycles blocked for each blocked cause. */
283    Stats::Vector<> blocked_cycles;
284    /** The number of times this cache blocked for each blocked cause. */
285    Stats::Vector<> blocked_causes;
286
287    /** The average number of cycles blocked for each blocked cause. */
288    Stats::Formula avg_blocked;
289
290    /** The number of fast writes (WH64) performed. */
291    Stats::Scalar<> fastWrites;
292
293    /** The number of cache copies performed. */
294    Stats::Scalar<> cacheCopies;
295
296    /**
297     * @}
298     */
299
300    /**
301     * Register stats for this object.
302     */
303    virtual void regStats();
304
305  public:
306
307    class Params
308    {
309      public:
310        /** List of address ranges of this cache. */
311        std::vector<Range<Addr> > addrRange;
312        /** The hit latency for this cache. */
313        int hitLatency;
314        /** The block size of this cache. */
315        int blkSize;
316        /**
317         * The maximum number of misses this cache should handle before
318         * ending the simulation.
319         */
320        Counter maxMisses;
321
322        /**
323         * Construct an instance of this parameter class.
324         */
325        Params(std::vector<Range<Addr> > addr_range,
326               int hit_latency, int _blkSize, Counter max_misses)
327            : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
328              maxMisses(max_misses)
329        {
330        }
331    };
332
333    /**
334     * Create and initialize a basic cache object.
335     * @param name The name of this cache.
336     * @param hier_params Pointer to the HierParams object for this hierarchy
337     * of this cache.
338     * @param params The parameter object for this BaseCache.
339     */
340    BaseCache(const std::string &name, Params &params)
341        : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
342          slaveRequests(0), topLevelCache(false),  blkSize(params.blkSize),
343          missCount(params.maxMisses)
344    {
345        //Start ports at null if more than one is created we should panic
346        cpuSidePort = NULL;
347        memSidePort = NULL;
348        snoopRangesSent = false;
349    }
350
351    virtual void init();
352
353    /**
354     * Query block size of a cache.
355     * @return  The block size
356     */
357    int getBlockSize() const
358    {
359        return blkSize;
360    }
361
362    /**
363     * Returns true if this cache is connect to the CPU.
364     * @return True if this is a L1 cache.
365     */
366    bool isTopLevel()
367    {
368        return topLevelCache;
369    }
370
371    /**
372     * Returns true if the cache is blocked for accesses.
373     */
374    bool isBlocked()
375    {
376        return blocked != 0;
377    }
378
379    /**
380     * Returns true if the cache is blocked for snoops.
381     */
382    bool isBlockedForSnoop()
383    {
384        return blockedSnoop != 0;
385    }
386
387    /**
388     * Marks the access path of the cache as blocked for the given cause. This
389     * also sets the blocked flag in the slave interface.
390     * @param cause The reason for the cache blocking.
391     */
392    void setBlocked(BlockedCause cause)
393    {
394        uint8_t flag = 1 << cause;
395        if (blocked == 0) {
396            blocked_causes[cause]++;
397            blockedCycle = curTick;
398        }
399        if (!(blocked & flag)) {
400            //Wasn't already blocked for this cause
401            blocked |= flag;
402            DPRINTF(Cache,"Blocking for cause %s\n", cause);
403            cpuSidePort->setBlocked();
404        }
405    }
406
407    /**
408     * Marks the snoop path of the cache as blocked for the given cause. This
409     * also sets the blocked flag in the master interface.
410     * @param cause The reason to block the snoop path.
411     */
412    void setBlockedForSnoop(BlockedCause cause)
413    {
414        uint8_t flag = 1 << cause;
415        if (!(blocked & flag)) {
416            //Wasn't already blocked for this cause
417            blockedSnoop |= flag;
418            memSidePort->setBlocked();
419        }
420    }
421
422    /**
423     * Marks the cache as unblocked for the given cause. This also clears the
424     * blocked flags in the appropriate interfaces.
425     * @param cause The newly unblocked cause.
426     * @warning Calling this function can cause a blocked request on the bus to
427     * access the cache. The cache must be in a state to handle that request.
428     */
429    void clearBlocked(BlockedCause cause)
430    {
431        uint8_t flag = 1 << cause;
432        DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
433                cause, blocked);
434        if (blocked & flag)
435        {
436            blocked &= ~flag;
437            if (!isBlocked()) {
438                blocked_cycles[cause] += curTick - blockedCycle;
439                DPRINTF(Cache,"Unblocking from all causes\n");
440                cpuSidePort->clearBlocked();
441            }
442        }
443        if (blockedSnoop & flag)
444        {
445            blockedSnoop &= ~flag;
446            if (!isBlockedForSnoop()) {
447                memSidePort->clearBlocked();
448            }
449        }
450    }
451
452    /**
453     * True if the master bus should be requested.
454     * @return True if there are outstanding requests for the master bus.
455     */
456    bool doMasterRequest()
457    {
458        return masterRequests != 0;
459    }
460
461    /**
462     * Request the master bus for the given cause and time.
463     * @param cause The reason for the request.
464     * @param time The time to make the request.
465     */
466    void setMasterRequest(RequestCause cause, Tick time)
467    {
468        if (!doMasterRequest())
469        {
470            BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort);
471            reqCpu->schedule(time);
472        }
473        uint8_t flag = 1<<cause;
474        masterRequests |= flag;
475    }
476
477    /**
478     * Clear the master bus request for the given cause.
479     * @param cause The request reason to clear.
480     */
481    void clearMasterRequest(RequestCause cause)
482    {
483        uint8_t flag = 1<<cause;
484        masterRequests &= ~flag;
485    }
486
487    /**
488     * Return true if the slave bus should be requested.
489     * @return True if there are outstanding requests for the slave bus.
490     */
491    bool doSlaveRequest()
492    {
493        return slaveRequests != 0;
494    }
495
496    /**
497     * Request the slave bus for the given reason and time.
498     * @param cause The reason for the request.
499     * @param time The time to make the request.
500     */
501    void setSlaveRequest(RequestCause cause, Tick time)
502    {
503        uint8_t flag = 1<<cause;
504        slaveRequests |= flag;
505        assert("Implement\n" && 0);
506//	si->pktuest(time);
507    }
508
509    /**
510     * Clear the slave bus request for the given reason.
511     * @param cause The request reason to clear.
512     */
513    void clearSlaveRequest(RequestCause cause)
514    {
515        uint8_t flag = 1<<cause;
516        slaveRequests &= ~flag;
517    }
518
519    /**
520     * Send a response to the slave interface.
521     * @param pkt The request being responded to.
522     * @param time The time the response is ready.
523     */
524    void respond(Packet *pkt, Tick time)
525    {
526        CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
527        reqCpu->schedule(time);
528    }
529
530    /**
531     * Send a reponse to the slave interface and calculate miss latency.
532     * @param pkt The request to respond to.
533     * @param time The time the response is ready.
534     */
535    void respondToMiss(Packet *pkt, Tick time)
536    {
537        if (!pkt->req->isUncacheable()) {
538            missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += time - pkt->time;
539        }
540        CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
541        reqCpu->schedule(time);
542    }
543
544    /**
545     * Suppliess the data if cache to cache transfers are enabled.
546     * @param pkt The bus transaction to fulfill.
547     */
548    void respondToSnoop(Packet *pkt, Tick time)
549    {
550//        assert("Implement\n" && 0);
551//	mi->respond(pkt,curTick + hitLatency);
552        CacheEvent *reqMem = new CacheEvent(memSidePort, pkt);
553        reqMem->schedule(time);
554    }
555
556    /**
557     * Notification from master interface that a address range changed. Nothing
558     * to do for a cache.
559     */
560    void rangeChange() {}
561
562    void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
563    {
564        if (isCpuSide)
565        {
566            AddrRangeList dummy;
567            memSidePort->getPeerAddressRanges(resp, dummy);
568        }
569        else
570        {
571            //This is where snoops get updated
572            AddrRangeList dummy;
573            if (!topLevelCache)
574            {
575                cpuSidePort->getPeerAddressRanges(dummy, snoop);
576            }
577            else
578            {
579                snoop.push_back(RangeSize(0,-1));
580            }
581
582            return;
583        }
584    }
585};
586
587#endif //__BASE_CACHE_HH__
588