base.hh revision 4458
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 * Steve Reinhardt 30 * Ron Dreslinski 31 */ 32 33/** 34 * @file 35 * Declares a basic cache interface BaseCache. 36 */ 37 38#ifndef __BASE_CACHE_HH__ 39#define __BASE_CACHE_HH__ 40 41#include <vector> 42#include <string> 43#include <list> 44#include <inttypes.h> 45 46#include "base/misc.hh" 47#include "base/statistics.hh" 48#include "base/trace.hh" 49#include "mem/mem_object.hh" 50#include "mem/packet.hh" 51#include "mem/port.hh" 52#include "mem/request.hh" 53#include "sim/eventq.hh" 54 55/** 56 * Reasons for Caches to be Blocked. 57 */ 58enum BlockedCause{ 59 Blocked_NoMSHRs, 60 Blocked_NoTargets, 61 Blocked_NoWBBuffers, 62 Blocked_Coherence, 63 NUM_BLOCKED_CAUSES 64}; 65 66/** 67 * Reasons for cache to request a bus. 68 */ 69enum RequestCause{ 70 Request_MSHR, 71 Request_WB, 72 Request_Coherence, 73 Request_PF 74}; 75 76class MSHR; 77/** 78 * A basic cache interface. Implements some common functions for speed. 79 */ 80class BaseCache : public MemObject 81{ 82 class CachePort : public Port 83 { 84 public: 85 BaseCache *cache; 86 87 protected: 88 Event *responseEvent; 89 90 CachePort(const std::string &_name, BaseCache *_cache); 91 92 virtual void recvStatusChange(Status status); 93 94 virtual void getDeviceAddressRanges(AddrRangeList &resp, 95 AddrRangeList &snoop); 96 97 virtual int deviceBlockSize(); 98 99 bool recvRetryCommon(); 100 101 public: 102 void setOtherPort(CachePort *_otherPort) { otherPort = _otherPort; } 103 104 void setBlocked(); 105 106 void clearBlocked(); 107 108 bool checkFunctional(PacketPtr pkt); 109 110 void checkAndSendFunctional(PacketPtr pkt); 111 112 bool canDrain() { return drainList.empty() && transmitList.empty(); } 113 114 bool drainResponse(); 115 116 CachePort *otherPort; 117 118 bool blocked; 119 120 bool mustSendRetry; 121 122 bool waitingOnRetry; 123 124 /** 125 * Bit vector for the outstanding requests for the master interface. 126 */ 127 uint8_t requestCauses; 128 129 std::list<PacketPtr> drainList; 130 131 std::list<std::pair<Tick,PacketPtr> > transmitList; 132 133 bool isBusRequested() { return requestCauses != 0; } 134 135 // These need to be virtual since the Event objects depend on 136 // cache template parameters. 137 virtual void scheduleRequestEvent(Tick t) = 0; 138 139 void requestBus(RequestCause cause, Tick time) 140 { 141 if (!isBusRequested() && !waitingOnRetry) { 142 scheduleRequestEvent(time); 143 } 144 requestCauses |= (1 << cause); 145 } 146 147 void deassertBusRequest(RequestCause cause) 148 { 149 requestCauses &= ~(1 << cause); 150 } 151 152 void respond(PacketPtr pkt, Tick time); 153 }; 154 155 public: //Made public so coherence can get at it. 156 CachePort *cpuSidePort; 157 CachePort *memSidePort; 158 159 private: 160 /** 161 * Bit vector of the blocking reasons for the access path. 162 * @sa #BlockedCause 163 */ 164 uint8_t blocked; 165 166 /** 167 * Bit vector for the blocking reasons for the snoop path. 168 * @sa #BlockedCause 169 */ 170 uint8_t blockedSnoop; 171 172 protected: 173 174 /** Stores time the cache blocked for statistics. */ 175 Tick blockedCycle; 176 177 /** Block size of this cache */ 178 const int blkSize; 179 180 /** The number of misses to trigger an exit event. */ 181 Counter missCount; 182 183 /** The drain event. */ 184 Event *drainEvent; 185 186 public: 187 // Statistics 188 /** 189 * @addtogroup CacheStatistics 190 * @{ 191 */ 192 193 /** Number of hits per thread for each type of command. @sa Packet::Command */ 194 Stats::Vector<> hits[MemCmd::NUM_MEM_CMDS]; 195 /** Number of hits for demand accesses. */ 196 Stats::Formula demandHits; 197 /** Number of hit for all accesses. */ 198 Stats::Formula overallHits; 199 200 /** Number of misses per thread for each type of command. @sa Packet::Command */ 201 Stats::Vector<> misses[MemCmd::NUM_MEM_CMDS]; 202 /** Number of misses for demand accesses. */ 203 Stats::Formula demandMisses; 204 /** Number of misses for all accesses. */ 205 Stats::Formula overallMisses; 206 207 /** 208 * Total number of cycles per thread/command spent waiting for a miss. 209 * Used to calculate the average miss latency. 210 */ 211 Stats::Vector<> missLatency[MemCmd::NUM_MEM_CMDS]; 212 /** Total number of cycles spent waiting for demand misses. */ 213 Stats::Formula demandMissLatency; 214 /** Total number of cycles spent waiting for all misses. */ 215 Stats::Formula overallMissLatency; 216 217 /** The number of accesses per command and thread. */ 218 Stats::Formula accesses[MemCmd::NUM_MEM_CMDS]; 219 /** The number of demand accesses. */ 220 Stats::Formula demandAccesses; 221 /** The number of overall accesses. */ 222 Stats::Formula overallAccesses; 223 224 /** The miss rate per command and thread. */ 225 Stats::Formula missRate[MemCmd::NUM_MEM_CMDS]; 226 /** The miss rate of all demand accesses. */ 227 Stats::Formula demandMissRate; 228 /** The miss rate for all accesses. */ 229 Stats::Formula overallMissRate; 230 231 /** The average miss latency per command and thread. */ 232 Stats::Formula avgMissLatency[MemCmd::NUM_MEM_CMDS]; 233 /** The average miss latency for demand misses. */ 234 Stats::Formula demandAvgMissLatency; 235 /** The average miss latency for all misses. */ 236 Stats::Formula overallAvgMissLatency; 237 238 /** The total number of cycles blocked for each blocked cause. */ 239 Stats::Vector<> blocked_cycles; 240 /** The number of times this cache blocked for each blocked cause. */ 241 Stats::Vector<> blocked_causes; 242 243 /** The average number of cycles blocked for each blocked cause. */ 244 Stats::Formula avg_blocked; 245 246 /** The number of fast writes (WH64) performed. */ 247 Stats::Scalar<> fastWrites; 248 249 /** The number of cache copies performed. */ 250 Stats::Scalar<> cacheCopies; 251 252 /** 253 * @} 254 */ 255 256 /** 257 * Register stats for this object. 258 */ 259 virtual void regStats(); 260 261 public: 262 263 class Params 264 { 265 public: 266 /** List of address ranges of this cache. */ 267 std::vector<Range<Addr> > addrRange; 268 /** The hit latency for this cache. */ 269 int hitLatency; 270 /** The block size of this cache. */ 271 int blkSize; 272 /** 273 * The maximum number of misses this cache should handle before 274 * ending the simulation. 275 */ 276 Counter maxMisses; 277 278 /** 279 * Construct an instance of this parameter class. 280 */ 281 Params(std::vector<Range<Addr> > addr_range, 282 int hit_latency, int _blkSize, Counter max_misses) 283 : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize), 284 maxMisses(max_misses) 285 { 286 } 287 }; 288 289 /** 290 * Create and initialize a basic cache object. 291 * @param name The name of this cache. 292 * @param hier_params Pointer to the HierParams object for this hierarchy 293 * of this cache. 294 * @param params The parameter object for this BaseCache. 295 */ 296 BaseCache(const std::string &name, Params ¶ms); 297 298 ~BaseCache() 299 { 300 } 301 302 virtual void init(); 303 304 /** 305 * Query block size of a cache. 306 * @return The block size 307 */ 308 int getBlockSize() const 309 { 310 return blkSize; 311 } 312 313 /** 314 * Returns true if the cache is blocked for accesses. 315 */ 316 bool isBlocked() 317 { 318 return blocked != 0; 319 } 320 321 /** 322 * Returns true if the cache is blocked for snoops. 323 */ 324 bool isBlockedForSnoop() 325 { 326 return blockedSnoop != 0; 327 } 328 329 /** 330 * Marks the access path of the cache as blocked for the given cause. This 331 * also sets the blocked flag in the slave interface. 332 * @param cause The reason for the cache blocking. 333 */ 334 void setBlocked(BlockedCause cause) 335 { 336 uint8_t flag = 1 << cause; 337 if (blocked == 0) { 338 blocked_causes[cause]++; 339 blockedCycle = curTick; 340 } 341 int old_state = blocked; 342 if (!(blocked & flag)) { 343 //Wasn't already blocked for this cause 344 blocked |= flag; 345 DPRINTF(Cache,"Blocking for cause %s\n", cause); 346 if (!old_state) 347 cpuSidePort->setBlocked(); 348 } 349 } 350 351 /** 352 * Marks the snoop path of the cache as blocked for the given cause. This 353 * also sets the blocked flag in the master interface. 354 * @param cause The reason to block the snoop path. 355 */ 356 void setBlockedForSnoop(BlockedCause cause) 357 { 358 uint8_t flag = 1 << cause; 359 uint8_t old_state = blockedSnoop; 360 if (!(blockedSnoop & flag)) { 361 //Wasn't already blocked for this cause 362 blockedSnoop |= flag; 363 if (!old_state) 364 memSidePort->setBlocked(); 365 } 366 } 367 368 /** 369 * Marks the cache as unblocked for the given cause. This also clears the 370 * blocked flags in the appropriate interfaces. 371 * @param cause The newly unblocked cause. 372 * @warning Calling this function can cause a blocked request on the bus to 373 * access the cache. The cache must be in a state to handle that request. 374 */ 375 void clearBlocked(BlockedCause cause) 376 { 377 uint8_t flag = 1 << cause; 378 DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n", 379 cause, blocked); 380 if (blocked & flag) 381 { 382 blocked &= ~flag; 383 if (!isBlocked()) { 384 blocked_cycles[cause] += curTick - blockedCycle; 385 DPRINTF(Cache,"Unblocking from all causes\n"); 386 cpuSidePort->clearBlocked(); 387 } 388 } 389 if (blockedSnoop & flag) 390 { 391 blockedSnoop &= ~flag; 392 if (!isBlockedForSnoop()) { 393 memSidePort->clearBlocked(); 394 } 395 } 396 } 397 398 /** 399 * True if the memory-side bus should be requested. 400 * @return True if there are outstanding requests for the master bus. 401 */ 402 bool isMemSideBusRequested() 403 { 404 return memSidePort->isBusRequested(); 405 } 406 407 /** 408 * Request the master bus for the given cause and time. 409 * @param cause The reason for the request. 410 * @param time The time to make the request. 411 */ 412 void requestMemSideBus(RequestCause cause, Tick time) 413 { 414 memSidePort->requestBus(cause, time); 415 } 416 417 /** 418 * Clear the master bus request for the given cause. 419 * @param cause The request reason to clear. 420 */ 421 void deassertMemSideBusRequest(RequestCause cause) 422 { 423 memSidePort->deassertBusRequest(cause); 424 checkDrain(); 425 } 426 427 /** 428 * Send a response to the slave interface. 429 * @param pkt The request being responded to. 430 * @param time The time the response is ready. 431 */ 432 void respond(PacketPtr pkt, Tick time) 433 { 434 cpuSidePort->respond(pkt, time); 435 } 436 437 /** 438 * Suppliess the data if cache to cache transfers are enabled. 439 * @param pkt The bus transaction to fulfill. 440 */ 441 void respondToSnoop(PacketPtr pkt, Tick time) 442 { 443 memSidePort->respond(pkt, time); 444 } 445 446 virtual unsigned int drain(Event *de); 447 448 void checkDrain() 449 { 450 if (drainEvent && canDrain()) { 451 drainEvent->process(); 452 changeState(SimObject::Drained); 453 // Clear the drain event 454 drainEvent = NULL; 455 } 456 } 457 458 bool canDrain() 459 { 460 if (isMemSideBusRequested()) { 461 return false; 462 } else if (memSidePort && !memSidePort->canDrain()) { 463 return false; 464 } else if (cpuSidePort && !cpuSidePort->canDrain()) { 465 return false; 466 } 467 return true; 468 } 469 470 virtual bool inCache(Addr addr) = 0; 471 472 virtual bool inMissQueue(Addr addr) = 0; 473}; 474 475#endif //__BASE_CACHE_HH__ 476