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