2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Erik Hallnor
33 * Definitions of the Indirect Index Cache tagstore.
41 #include "base/intmath.hh"
42 #include "base/trace.hh"
43 #include "debug/Cache.hh"
44 #include "debug/IIC.hh"
45 #include "debug/IICMore.hh"
46 #include "mem/cache/tags/iic.hh"
47 #include "mem/cache/base.hh"
48 #include "sim/core.hh"
52 /** Track the number of accesses to each cache set. */
55 IIC::IIC(IIC::Params
¶ms
) :
56 hashSets(params
.numSets
), blkSize(params
.blkSize
), assoc(params
.assoc
),
57 hitLatency(params
.hitLatency
), subSize(params
.subblockSize
),
58 numSub(blkSize
/subSize
),
59 trivialSize((floorLog2(params
.size
/subSize
)*numSub
)/8),
60 tagShift(floorLog2(blkSize
)), blkMask(blkSize
- 1),
61 subShift(floorLog2(subSize
)), subMask(numSub
- 1),
62 hashDelay(params
.hashDelay
),
63 numTags(hashSets
* assoc
+ params
.size
/blkSize
-1),
64 numSecondary(params
.size
/blkSize
),
66 primaryBound(hashSets
* assoc
)
69 if (blkSize
< 4 || !isPowerOf2(blkSize
)) {
70 fatal("Block size must be at least 4 and a power of 2");
72 if (hashSets
<= 0 || !isPowerOf2(hashSets
)) {
73 fatal("# of hashsets must be non-zero and a power of 2");
76 fatal("associativity must be greater than zero");
78 if (hitLatency
<= 0) {
79 fatal("access latency must be greater than zero");
81 if (numSub
*subSize
!= blkSize
) {
82 fatal("blocksize must be evenly divisible by subblock size");
86 freeSecond
= numSecondary
;
89 warmupBound
= params
.size
/blkSize
;
90 numBlocks
= params
.size
/subSize
;
92 // Replacement Policy Initialization
98 // allocate data reference counters
99 dataReferenceCount
= new int[numBlocks
];
100 memset(dataReferenceCount
, 0, numBlocks
*sizeof(int));
102 // Allocate storage for both internal data and block fast access data.
103 // We allocate it as one large chunk to reduce overhead and to make
105 unsigned data_index
= 0;
106 dataStore
= new uint8_t[(numBlocks
+ numTags
) * blkSize
];
107 dataBlks
= new uint8_t*[numBlocks
];
108 for (unsigned i
= 0; i
< numBlocks
; ++i
) {
109 dataBlks
[i
] = &dataStore
[data_index
];
111 data_index
+= subSize
;
114 assert(data_index
== numBlocks
* subSize
);
116 // allocate and init tag store
117 tagStore
= new IICTag
[numTags
];
119 unsigned blkIndex
= 0;
120 // allocate and init sets
121 sets
= new IICSet
[hashSets
];
122 for (unsigned i
= 0; i
< hashSets
; ++i
) {
123 sets
[i
].assoc
= assoc
;
124 sets
[i
].tags
= new IICTag
*[assoc
];
125 sets
[i
].chain_ptr
= tagNull
;
127 for (unsigned j
= 0; j
< assoc
; ++j
) {
128 IICTag
*tag
= &tagStore
[blkIndex
++];
129 tag
->chain_ptr
= tagNull
;
130 tag
->data_ptr
.resize(numSub
);
132 tag
->trivialData
= new uint8_t[trivialSize
];
134 sets
[i
].tags
[j
] = tag
;
136 tag
->data
= &dataStore
[data_index
];
137 data_index
+= blkSize
;
141 assert(blkIndex
== primaryBound
);
143 for (unsigned i
= primaryBound
; i
< tagNull
; i
++) {
144 tagStore
[i
].chain_ptr
= i
+1;
145 //setup data ptrs to subblocks
146 tagStore
[i
].data_ptr
.resize(numSub
);
147 tagStore
[i
].size
= blkSize
;
148 tagStore
[i
].trivialData
= new uint8_t[trivialSize
];
149 tagStore
[i
].numData
= 0;
151 tagStore
[i
].data
= &dataStore
[data_index
];
152 data_index
+= blkSize
;
154 freelist
= primaryBound
;
159 delete [] dataReferenceCount
;
165 /* register cache stats */
167 IIC::regStats(const string
&name
)
169 using namespace Stats
;
171 BaseTags::regStats(name
);
173 hitHashDepth
.init(0, 20, 1);
174 missHashDepth
.init(0, 20, 1);
175 setAccess
.init(0, hashSets
, 1);
177 /** IIC Statistics */
179 .name(name
+ ".hit_hash_depth_dist")
180 .desc("Dist. of Hash lookup depths")
185 .name(name
+ ".miss_hash_depth_dist")
186 .desc("Dist. of Hash lookup depths")
190 repl
->regStatsWithSuffix(name
);
194 .name(name
+ ".set_access_dist")
195 .desc("Dist. of Accesses across sets")
200 .name(name
+ ".miss_depth_total")
201 .desc("Total of miss depths")
205 .name(name
+ ".hash_miss")
206 .desc("Total of misses in hash table")
210 .name(name
+ ".hit_depth_total")
211 .desc("Total of hit depths")
215 .name(name
+ ".hash_hit")
216 .desc("Total of hites in hash table")
222 IIC::accessBlock(Addr addr
, int &lat
, int context_src
)
224 Addr tag
= extractTag(addr
);
225 unsigned set
= hash(addr
);
228 unsigned long chain_ptr
= tagNull
;
231 setAccess
.sample(set
);
233 IICTag
*tag_ptr
= sets
[set
].findTag(tag
, chain_ptr
);
235 if (tag_ptr
== NULL
&& chain_ptr
!= tagNull
) {
237 tag_ptr
= secondaryChain(tag
, chain_ptr
, &secondary_depth
);
238 set_lat
+= secondary_depth
;
239 // set depth for statistics fix this later!!! egh
240 sets
[set
].depth
= set_lat
;
242 if (tag_ptr
!= NULL
) {
243 /* need to move tag into primary table */
244 // need to preserve chain: fix this egh
245 sets
[set
].tags
[assoc
-1]->chain_ptr
= tag_ptr
->chain_ptr
;
246 tagSwap(tag_ptr
- tagStore
, sets
[set
].tags
[assoc
-1] - tagStore
);
247 tag_ptr
= sets
[set
].findTag(tag
, chain_ptr
);
248 assert(tag_ptr
!=NULL
);
252 set_lat
= set_lat
* hashDelay
+ hitLatency
;
253 if (tag_ptr
!= NULL
) {
254 // IIC replacement: if this is not the first element of
256 sets
[set
].moveToHead(tag_ptr
);
258 hitHashDepth
.sample(sets
[set
].depth
);
260 hitDepthTotal
+= sets
[set
].depth
;
261 tag_ptr
->status
|= BlkReferenced
;
263 if (tag_ptr
->whenReady
> curTick() && tag_ptr
->whenReady
- curTick() > set_lat
) {
264 lat
= tag_ptr
->whenReady
- curTick();
267 tag_ptr
->refCount
+= 1;
270 // fall through: cache block not found, not a hit...
271 missHashDepth
.sample(sets
[set
].depth
);
273 missDepthTotal
+= sets
[set
].depth
;
281 IIC::findBlock(Addr addr
) const
283 Addr tag
= extractTag(addr
);
284 unsigned set
= hash(addr
);
286 unsigned long chain_ptr
= tagNull
;
288 IICTag
*tag_ptr
= sets
[set
].findTag(tag
, chain_ptr
);
289 if (tag_ptr
== NULL
&& chain_ptr
!= tagNull
) {
291 tag_ptr
= secondaryChain(tag
, chain_ptr
, &secondary_depth
);
298 IIC::findVictim(Addr addr
, PacketList
&writebacks
)
300 DPRINTF(IIC
, "Finding Replacement for %x\n", addr
);
301 unsigned set
= hash(addr
);
303 unsigned long *tmp_data
= new unsigned long[numSub
];
305 // Get a enough subblocks for a full cache line
306 for (unsigned i
= 0; i
< numSub
; ++i
){
307 tmp_data
[i
] = getFreeDataBlock(writebacks
);
308 assert(dataReferenceCount
[tmp_data
[i
]]==0);
311 tag_ptr
= getFreeTag(set
, writebacks
);
314 for (unsigned i
= 0; i
< numSub
; ++i
) {
315 tag_ptr
->data_ptr
[i
] = tmp_data
[i
];
316 dataReferenceCount
[tag_ptr
->data_ptr
[i
]]++;
318 tag_ptr
->numData
= numSub
;
319 assert(tag_ptr
- tagStore
< primaryBound
); // make sure it is in primary
320 tag_ptr
->chain_ptr
= tagNull
;
321 sets
[set
].moveToHead(tag_ptr
);
324 list
<unsigned long> tag_indexes
;
325 repl
->doAdvance(tag_indexes
);
327 while (!tag_indexes.empty()) {
328 if (!tagStore[tag_indexes.front()].isCompressed()) {
329 compress_blocks.push_back(&tagStore[tag_indexes.front()]);
331 tag_indexes.pop_front();
335 tag_ptr
->re
= (void*)repl
->add(tag_ptr
-tagStore
);
341 IIC::insertBlock(Addr addr
, BlkType
* blk
, int context_src
)
346 IIC::freeReplacementBlock(PacketList
& writebacks
)
349 unsigned long data_ptr
;
350 /* consult replacement policy */
351 tag_ptr
= &tagStore
[repl
->getRepl()];
352 assert(tag_ptr
->isValid());
354 DPRINTF(Cache
, "Replacing %x in IIC: %s\n",
355 regenerateBlkAddr(tag_ptr
->tag
,0),
356 tag_ptr
->isDirty() ? "writeback" : "clean");
357 /* write back replaced block data */
358 if (tag_ptr
&& (tag_ptr
->isValid())) {
360 totalRefs
+= tag_ptr
->refCount
;
362 tag_ptr
->refCount
= 0;
364 if (tag_ptr
->isDirty()) {
365 /* PacketPtr writeback =
366 buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
367 tag_ptr->req->asid, tag_ptr->xc, blkSize,
371 Request
*writebackReq
= new Request(regenerateBlkAddr(tag_ptr
->tag
, 0),
372 blkSize
, 0, Request::wbMasterId
);
373 PacketPtr writeback
= new Packet(writebackReq
, MemCmd::Writeback
);
374 writeback
->allocate();
375 memcpy(writeback
->getPtr
<uint8_t>(), tag_ptr
->data
, blkSize
);
377 writebacks
.push_back(writeback
);
381 // free the data blocks
382 for (int i
= 0; i
< tag_ptr
->numData
; ++i
) {
383 data_ptr
= tag_ptr
->data_ptr
[i
];
384 assert(dataReferenceCount
[data_ptr
]>0);
385 if (--dataReferenceCount
[data_ptr
] == 0) {
386 freeDataBlock(data_ptr
);
393 IIC::getFreeDataBlock(PacketList
& writebacks
)
395 unsigned long data_ptr
;
397 /* find data block */
398 while (blkFreelist
.empty()) {
399 freeReplacementBlock(writebacks
);
402 data_ptr
= blkFreelist
.front();
403 blkFreelist
.pop_front();
404 DPRINTF(IICMore
,"Found free data at %d\n",data_ptr
);
411 IIC::getFreeTag(int set
, PacketList
& writebacks
)
413 unsigned long tag_index
;
416 tag_ptr
= sets
[set
].findFree();
417 // if no free in primary, and secondary exists
418 if (!tag_ptr
&& numSecondary
) {
419 // need to spill a tag into secondary storage
420 while (freelist
== tagNull
) {
421 // get replacements until one is in secondary
422 freeReplacementBlock(writebacks
);
425 tag_index
= freelist
;
426 freelist
= tagStore
[freelist
].chain_ptr
;
429 assert(tag_index
!= tagNull
);
430 tagSwap(tag_index
, sets
[set
].tags
[assoc
-1] - tagStore
);
431 tagStore
[tag_index
].chain_ptr
= sets
[set
].chain_ptr
;
432 sets
[set
].chain_ptr
= tag_index
;
434 tag_ptr
= sets
[set
].tags
[assoc
-1];
436 DPRINTF(IICMore
,"Found free tag at %d\n",tag_ptr
- tagStore
);
438 if (!warmedUp
&& tagsInUse
.value() >= warmupBound
) {
440 warmupCycle
= curTick();
447 IIC::freeTag(IICTag
*tag_ptr
)
449 unsigned long tag_index
, tmp_index
;
452 // we have a tag to clear
453 DPRINTF(IICMore
,"Freeing Tag for %x\n",
454 regenerateBlkAddr(tag_ptr
->tag
,0));
457 tag_ptr
->numData
= 0;
459 tag_index
= tag_ptr
- tagStore
;
460 if (tag_index
>= primaryBound
) {
461 // tag_ptr points to secondary store
462 assert(tag_index
< tagNull
); // remove this?? egh
463 if (tag_ptr
->chain_ptr
== tagNull
) {
464 // need to fix chain list
465 unsigned tmp_set
= hash(tag_ptr
->tag
<< tagShift
);
466 if (sets
[tmp_set
].chain_ptr
== tag_index
) {
467 sets
[tmp_set
].chain_ptr
= tagNull
;
469 tmp_index
= sets
[tmp_set
].chain_ptr
;
470 while (tmp_index
!= tagNull
471 && tagStore
[tmp_index
].chain_ptr
!= tag_index
) {
472 tmp_index
= tagStore
[tmp_index
].chain_ptr
;
474 assert(tmp_index
!= tagNull
);
475 tagStore
[tmp_index
].chain_ptr
= tagNull
;
477 tag_ptr
->chain_ptr
= freelist
;
478 freelist
= tag_index
;
481 // copy next chained entry to this tag location
482 tmp_index
= tag_ptr
->chain_ptr
;
483 tagSwap(tmp_index
, tag_index
);
484 tagStore
[tmp_index
].chain_ptr
= freelist
;
485 freelist
= tmp_index
;
489 // tag_ptr in primary hash table
490 assert(tag_index
< primaryBound
);
492 unsigned tmp_set
= hash(tag_ptr
->tag
<< tagShift
);
493 if (sets
[tmp_set
].chain_ptr
!= tagNull
) { // collapse chain
494 tmp_index
= sets
[tmp_set
].chain_ptr
;
495 tagSwap(tag_index
, tmp_index
);
496 tagStore
[tmp_index
].chain_ptr
= freelist
;
497 freelist
= tmp_index
;
499 sets
[tmp_set
].chain_ptr
= tag_ptr
->chain_ptr
;
500 sets
[tmp_set
].moveToTail(tag_ptr
);
507 IIC::freeDataBlock(unsigned long data_ptr
)
509 assert(dataReferenceCount
[data_ptr
] == 0);
510 DPRINTF(IICMore
, "Freeing data at %d\n", data_ptr
);
511 blkFreelist
.push_front(data_ptr
);
514 /** Use a simple modulo hash. */
515 #define SIMPLE_HASH 0
518 IIC::hash(Addr addr
) const {
520 return extractTag(addr
) % iic_hash_size
;
522 Addr tag
, mask
, x
, y
;
523 tag
= extractTag(addr
);
524 mask
= hashSets
-1; /* assumes iic_hash_size is a power of 2 */
526 y
= (tag
>> (int)(::log((double)hashSets
)/::log((double)2))) & mask
;
527 assert (x
< hashSets
&& y
< hashSets
);
534 IICSet::moveToHead(IICTag
*tag
)
539 // write 'next' block into blks[i], moving up from MRU toward LRU
540 // until we overwrite the block we moved to head.
542 // start by setting up to write 'blk' into blks[0]
548 // swap blks[i] and next
549 IICTag
*tmp
= tags
[i
];
553 } while (next
!= tag
);
557 IICSet::moveToTail(IICTag
*tag
)
559 if (tags
[assoc
-1] == tag
)
562 // write 'next' block into blks[i], moving up from MRU toward LRU
563 // until we overwrite the block we moved to head.
565 // start by setting up to write 'blk' into blks[0]
571 // swap blks[i] and next
572 IICTag
*tmp
= tags
[i
];
576 } while (next
!= tag
);
580 IIC::tagSwap(unsigned long index1
, unsigned long index2
)
582 DPRINTF(IIC
,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1
,
583 tagStore
[index1
].tag
<<tagShift
, index2
,
584 tagStore
[index2
].tag
<<tagShift
);
586 tmp_tag
= tagStore
[index1
];
587 tagStore
[index1
] = tagStore
[index2
];
588 tagStore
[index2
] = tmp_tag
;
589 if (tagStore
[index1
].isValid())
590 repl
->fixTag(tagStore
[index1
].re
, index2
, index1
);
591 if (tagStore
[index2
].isValid())
592 repl
->fixTag(tagStore
[index2
].re
, index1
, index2
);
597 IIC::secondaryChain(Addr tag
, unsigned long chain_ptr
,
601 while (chain_ptr
!= tagNull
) {
602 DPRINTF(IIC
,"Searching secondary at %d for %x\n", chain_ptr
,
604 if (tagStore
[chain_ptr
].tag
== tag
&&
605 (tagStore
[chain_ptr
].isValid())) {
607 return &tagStore
[chain_ptr
];
610 chain_ptr
= tagStore
[chain_ptr
].chain_ptr
;
617 IIC::invalidateBlk(IIC::BlkType
*tag_ptr
)
620 for (int i
= 0; i
< tag_ptr
->numData
; ++i
) {
621 dataReferenceCount
[tag_ptr
->data_ptr
[i
]]--;
622 if (dataReferenceCount
[tag_ptr
->data_ptr
[i
]] == 0) {
623 freeDataBlock(tag_ptr
->data_ptr
[i
]);
626 repl
->removeEntry(tag_ptr
->re
);
634 for (int i
= 0; i
< numTags
; i
++){
635 tagStore
[i
].clearLoadLocks();
642 for (unsigned i
= 0; i
< numTags
; ++i
) {
643 if (tagStore
[i
].isValid()) {
644 totalRefs
+= tagStore
[i
].refCount
;