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