SCons: Support building without an ISA
[gem5.git] / src / mem / cache / tags / iic.cc
1 /*
2 * Copyright (c) 2002-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 * Definitions of the Indirect Index Cache tagstore.
34 */
35
36 #include <algorithm>
37 #include <cmath>
38 #include <string>
39 #include <vector>
40
41 #include "base/intmath.hh"
42 #include "base/trace.hh"
43 #include "mem/cache/base.hh"
44 #include "mem/cache/tags/iic.hh"
45 #include "sim/core.hh"
46
47 using namespace std;
48
49 /** Track the number of accesses to each cache set. */
50 #define PROFILE_IIC 1
51
52 IIC::IIC(IIC::Params &params) :
53 hashSets(params.numSets), blkSize(params.blkSize), assoc(params.assoc),
54 hitLatency(params.hitLatency), subSize(params.subblockSize),
55 numSub(blkSize/subSize),
56 trivialSize((floorLog2(params.size/subSize)*numSub)/8),
57 tagShift(floorLog2(blkSize)), blkMask(blkSize - 1),
58 subShift(floorLog2(subSize)), subMask(numSub - 1),
59 hashDelay(params.hashDelay),
60 numTags(hashSets * assoc + params.size/blkSize -1),
61 numSecondary(params.size/blkSize),
62 tagNull(numTags),
63 primaryBound(hashSets * assoc)
64 {
65 // Check parameters
66 if (blkSize < 4 || !isPowerOf2(blkSize)) {
67 fatal("Block size must be at least 4 and a power of 2");
68 }
69 if (hashSets <= 0 || !isPowerOf2(hashSets)) {
70 fatal("# of hashsets must be non-zero and a power of 2");
71 }
72 if (assoc <= 0) {
73 fatal("associativity must be greater than zero");
74 }
75 if (hitLatency <= 0) {
76 fatal("access latency must be greater than zero");
77 }
78 if (numSub*subSize != blkSize) {
79 fatal("blocksize must be evenly divisible by subblock size");
80 }
81
82 // debug stuff
83 freeSecond = numSecondary;
84
85 warmedUp = false;
86 warmupBound = params.size/blkSize;
87 numBlocks = params.size/subSize;
88
89 // Replacement Policy Initialization
90 repl = params.rp;
91 repl->setIIC(this);
92
93 //last_miss_time = 0
94
95 // allocate data reference counters
96 dataReferenceCount = new int[numBlocks];
97 memset(dataReferenceCount, 0, numBlocks*sizeof(int));
98
99 // Allocate storage for both internal data and block fast access data.
100 // We allocate it as one large chunk to reduce overhead and to make
101 // deletion easier.
102 unsigned data_index = 0;
103 dataStore = new uint8_t[(numBlocks + numTags) * blkSize];
104 dataBlks = new uint8_t*[numBlocks];
105 for (unsigned i = 0; i < numBlocks; ++i) {
106 dataBlks[i] = &dataStore[data_index];
107 freeDataBlock(i);
108 data_index += subSize;
109 }
110
111 assert(data_index == numBlocks * subSize);
112
113 // allocate and init tag store
114 tagStore = new IICTag[numTags];
115
116 unsigned blkIndex = 0;
117 // allocate and init sets
118 sets = new IICSet[hashSets];
119 for (unsigned i = 0; i < hashSets; ++i) {
120 sets[i].assoc = assoc;
121 sets[i].tags = new IICTag*[assoc];
122 sets[i].chain_ptr = tagNull;
123
124 for (unsigned j = 0; j < assoc; ++j) {
125 IICTag *tag = &tagStore[blkIndex++];
126 tag->chain_ptr = tagNull;
127 tag->data_ptr.resize(numSub);
128 tag->size = blkSize;
129 tag->trivialData = new uint8_t[trivialSize];
130 tag->numData = 0;
131 sets[i].tags[j] = tag;
132 tag->set = i;
133 tag->data = &dataStore[data_index];
134 data_index += blkSize;
135 }
136 }
137
138 assert(blkIndex == primaryBound);
139
140 for (unsigned i = primaryBound; i < tagNull; i++) {
141 tagStore[i].chain_ptr = i+1;
142 //setup data ptrs to subblocks
143 tagStore[i].data_ptr.resize(numSub);
144 tagStore[i].size = blkSize;
145 tagStore[i].trivialData = new uint8_t[trivialSize];
146 tagStore[i].numData = 0;
147 tagStore[i].set = 0;
148 tagStore[i].data = &dataStore[data_index];
149 data_index += blkSize;
150 }
151 freelist = primaryBound;
152 }
153
154 IIC::~IIC()
155 {
156 delete [] dataReferenceCount;
157 delete [] dataStore;
158 delete [] tagStore;
159 delete [] sets;
160 }
161
162 /* register cache stats */
163 void
164 IIC::regStats(const string &name)
165 {
166 using namespace Stats;
167
168 BaseTags::regStats(name);
169
170 hitHashDepth.init(0, 20, 1);
171 missHashDepth.init(0, 20, 1);
172 setAccess.init(0, hashSets, 1);
173
174 /** IIC Statistics */
175 hitHashDepth
176 .name(name + ".hit_hash_depth_dist")
177 .desc("Dist. of Hash lookup depths")
178 .flags(pdf)
179 ;
180
181 missHashDepth
182 .name(name + ".miss_hash_depth_dist")
183 .desc("Dist. of Hash lookup depths")
184 .flags(pdf)
185 ;
186
187 repl->regStats(name);
188
189 if (PROFILE_IIC)
190 setAccess
191 .name(name + ".set_access_dist")
192 .desc("Dist. of Accesses across sets")
193 .flags(pdf)
194 ;
195
196 missDepthTotal
197 .name(name + ".miss_depth_total")
198 .desc("Total of miss depths")
199 ;
200
201 hashMiss
202 .name(name + ".hash_miss")
203 .desc("Total of misses in hash table")
204 ;
205
206 hitDepthTotal
207 .name(name + ".hit_depth_total")
208 .desc("Total of hit depths")
209 ;
210
211 hashHit
212 .name(name + ".hash_hit")
213 .desc("Total of hites in hash table")
214 ;
215 }
216
217
218 IICTag*
219 IIC::accessBlock(Addr addr, int &lat, int context_src)
220 {
221 Addr tag = extractTag(addr);
222 unsigned set = hash(addr);
223 int set_lat;
224
225 unsigned long chain_ptr = tagNull;
226
227 if (PROFILE_IIC)
228 setAccess.sample(set);
229
230 IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
231 set_lat = 1;
232 if (tag_ptr == NULL && chain_ptr != tagNull) {
233 int secondary_depth;
234 tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
235 set_lat += secondary_depth;
236 // set depth for statistics fix this later!!! egh
237 sets[set].depth = set_lat;
238
239 if (tag_ptr != NULL) {
240 /* need to move tag into primary table */
241 // need to preserve chain: fix this egh
242 sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
243 tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
244 tag_ptr = sets[set].findTag(tag, chain_ptr);
245 assert(tag_ptr!=NULL);
246 }
247
248 }
249 set_lat = set_lat * hashDelay + hitLatency;
250 if (tag_ptr != NULL) {
251 // IIC replacement: if this is not the first element of
252 // list, reorder
253 sets[set].moveToHead(tag_ptr);
254
255 hitHashDepth.sample(sets[set].depth);
256 hashHit++;
257 hitDepthTotal += sets[set].depth;
258 tag_ptr->status |= BlkReferenced;
259 lat = set_lat;
260 if (tag_ptr->whenReady > curTick && tag_ptr->whenReady - curTick > set_lat) {
261 lat = tag_ptr->whenReady - curTick;
262 }
263
264 tag_ptr->refCount += 1;
265 }
266 else {
267 // fall through: cache block not found, not a hit...
268 missHashDepth.sample(sets[set].depth);
269 hashMiss++;
270 missDepthTotal += sets[set].depth;
271 lat = set_lat;
272 }
273 return tag_ptr;
274 }
275
276
277 IICTag*
278 IIC::findBlock(Addr addr) const
279 {
280 Addr tag = extractTag(addr);
281 unsigned set = hash(addr);
282
283 unsigned long chain_ptr = tagNull;
284
285 IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
286 if (tag_ptr == NULL && chain_ptr != tagNull) {
287 int secondary_depth;
288 tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
289 }
290 return tag_ptr;
291 }
292
293
294 IICTag*
295 IIC::findVictim(Addr addr, PacketList &writebacks)
296 {
297 DPRINTF(IIC, "Finding Replacement for %x\n", addr);
298 unsigned set = hash(addr);
299 IICTag *tag_ptr;
300 unsigned long *tmp_data = new unsigned long[numSub];
301
302 // Get a enough subblocks for a full cache line
303 for (unsigned i = 0; i < numSub; ++i){
304 tmp_data[i] = getFreeDataBlock(writebacks);
305 assert(dataReferenceCount[tmp_data[i]]==0);
306 }
307
308 tag_ptr = getFreeTag(set, writebacks);
309
310 tag_ptr->set = set;
311 for (unsigned i = 0; i < numSub; ++i) {
312 tag_ptr->data_ptr[i] = tmp_data[i];
313 dataReferenceCount[tag_ptr->data_ptr[i]]++;
314 }
315 tag_ptr->numData = numSub;
316 assert(tag_ptr - tagStore < primaryBound); // make sure it is in primary
317 tag_ptr->chain_ptr = tagNull;
318 sets[set].moveToHead(tag_ptr);
319 delete [] tmp_data;
320
321 list<unsigned long> tag_indexes;
322 repl->doAdvance(tag_indexes);
323 /*
324 while (!tag_indexes.empty()) {
325 if (!tagStore[tag_indexes.front()].isCompressed()) {
326 compress_blocks.push_back(&tagStore[tag_indexes.front()]);
327 }
328 tag_indexes.pop_front();
329 }
330 */
331
332 tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
333
334 return tag_ptr;
335 }
336
337 void
338 IIC::insertBlock(Addr addr, BlkType* blk, int context_src)
339 {
340 }
341
342 void
343 IIC::freeReplacementBlock(PacketList & writebacks)
344 {
345 IICTag *tag_ptr;
346 unsigned long data_ptr;
347 /* consult replacement policy */
348 tag_ptr = &tagStore[repl->getRepl()];
349 assert(tag_ptr->isValid());
350
351 DPRINTF(Cache, "Replacing %x in IIC: %s\n",
352 regenerateBlkAddr(tag_ptr->tag,0),
353 tag_ptr->isDirty() ? "writeback" : "clean");
354 /* write back replaced block data */
355 if (tag_ptr && (tag_ptr->isValid())) {
356 replacements[0]++;
357 totalRefs += tag_ptr->refCount;
358 ++sampledRefs;
359 tag_ptr->refCount = 0;
360
361 if (tag_ptr->isDirty()) {
362 /* PacketPtr writeback =
363 buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
364 tag_ptr->req->asid, tag_ptr->xc, blkSize,
365 tag_ptr->data,
366 tag_ptr->size);
367 */
368 Request *writebackReq = new Request(regenerateBlkAddr(tag_ptr->tag, 0),
369 blkSize, 0);
370 PacketPtr writeback = new Packet(writebackReq, MemCmd::Writeback,
371 -1);
372 writeback->allocate();
373 memcpy(writeback->getPtr<uint8_t>(), tag_ptr->data, blkSize);
374
375 writebacks.push_back(writeback);
376 }
377 }
378
379 // free the data blocks
380 for (int i = 0; i < tag_ptr->numData; ++i) {
381 data_ptr = tag_ptr->data_ptr[i];
382 assert(dataReferenceCount[data_ptr]>0);
383 if (--dataReferenceCount[data_ptr] == 0) {
384 freeDataBlock(data_ptr);
385 }
386 }
387 freeTag(tag_ptr);
388 }
389
390 unsigned long
391 IIC::getFreeDataBlock(PacketList & writebacks)
392 {
393 struct IICTag *tag_ptr;
394 unsigned long data_ptr;
395
396 tag_ptr = NULL;
397 /* find data block */
398 while (blkFreelist.empty()) {
399 freeReplacementBlock(writebacks);
400 }
401
402 data_ptr = blkFreelist.front();
403 blkFreelist.pop_front();
404 DPRINTF(IICMore,"Found free data at %d\n",data_ptr);
405 return data_ptr;
406 }
407
408
409
410 IICTag*
411 IIC::getFreeTag(int set, PacketList & writebacks)
412 {
413 unsigned long tag_index;
414 IICTag *tag_ptr;
415 // Add new tag
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);
423 }
424
425 tag_index = freelist;
426 freelist = tagStore[freelist].chain_ptr;
427 freeSecond--;
428
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;
433
434 tag_ptr = sets[set].tags[assoc-1];
435 }
436 DPRINTF(IICMore,"Found free tag at %d\n",tag_ptr - tagStore);
437 tagsInUse++;
438 if (!warmedUp && tagsInUse.value() >= warmupBound) {
439 warmedUp = true;
440 warmupCycle = curTick;
441 }
442
443 return tag_ptr;
444 }
445
446 void
447 IIC::freeTag(IICTag *tag_ptr)
448 {
449 unsigned long tag_index, tmp_index;
450 // Fix tag_ptr
451 if (tag_ptr) {
452 // we have a tag to clear
453 DPRINTF(IICMore,"Freeing Tag for %x\n",
454 regenerateBlkAddr(tag_ptr->tag,0));
455 tagsInUse--;
456 tag_ptr->status = 0;
457 tag_ptr->numData = 0;
458 tag_ptr->re = NULL;
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;
468 } else {
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;
473 }
474 assert(tmp_index != tagNull);
475 tagStore[tmp_index].chain_ptr = tagNull;
476 }
477 tag_ptr->chain_ptr = freelist;
478 freelist = tag_index;
479 freeSecond++;
480 } else {
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;
486 freeSecond++;
487 }
488 } else {
489 // tag_ptr in primary hash table
490 assert(tag_index < primaryBound);
491 tag_ptr->status = 0;
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;
498 freeSecond++;
499 sets[tmp_set].chain_ptr = tag_ptr->chain_ptr;
500 sets[tmp_set].moveToTail(tag_ptr);
501 }
502 }
503 }
504 }
505
506 void
507 IIC::freeDataBlock(unsigned long data_ptr)
508 {
509 assert(dataReferenceCount[data_ptr] == 0);
510 DPRINTF(IICMore, "Freeing data at %d\n", data_ptr);
511 blkFreelist.push_front(data_ptr);
512 }
513
514 /** Use a simple modulo hash. */
515 #define SIMPLE_HASH 0
516
517 unsigned
518 IIC::hash(Addr addr) const {
519 #if SIMPLE_HASH
520 return extractTag(addr) % iic_hash_size;
521 #else
522 Addr tag, mask, x, y;
523 tag = extractTag(addr);
524 mask = hashSets-1; /* assumes iic_hash_size is a power of 2 */
525 x = tag & mask;
526 y = (tag >> (int)(::log((double)hashSets)/::log((double)2))) & mask;
527 assert (x < hashSets && y < hashSets);
528 return x ^ y;
529 #endif
530 }
531
532
533 void
534 IICSet::moveToHead(IICTag *tag)
535 {
536 if (tags[0] == tag)
537 return;
538
539 // write 'next' block into blks[i], moving up from MRU toward LRU
540 // until we overwrite the block we moved to head.
541
542 // start by setting up to write 'blk' into blks[0]
543 int i = 0;
544 IICTag *next = tag;
545
546 do {
547 assert(i < assoc);
548 // swap blks[i] and next
549 IICTag *tmp = tags[i];
550 tags[i] = next;
551 next = tmp;
552 ++i;
553 } while (next != tag);
554 }
555
556 void
557 IICSet::moveToTail(IICTag *tag)
558 {
559 if (tags[assoc-1] == tag)
560 return;
561
562 // write 'next' block into blks[i], moving up from MRU toward LRU
563 // until we overwrite the block we moved to head.
564
565 // start by setting up to write 'blk' into blks[0]
566 int i = assoc - 1;
567 IICTag *next = tag;
568
569 do {
570 assert(i >= 0);
571 // swap blks[i] and next
572 IICTag *tmp = tags[i];
573 tags[i] = next;
574 next = tmp;
575 --i;
576 } while (next != tag);
577 }
578
579 void
580 IIC::tagSwap(unsigned long index1, unsigned long index2)
581 {
582 DPRINTF(IIC,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1,
583 tagStore[index1].tag<<tagShift, index2,
584 tagStore[index2].tag<<tagShift);
585 IICTag tmp_tag;
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);
593 }
594
595
596 IICTag *
597 IIC::secondaryChain(Addr tag, unsigned long chain_ptr,
598 int *_depth) const
599 {
600 int depth = 0;
601 while (chain_ptr != tagNull) {
602 DPRINTF(IIC,"Searching secondary at %d for %x\n", chain_ptr,
603 tag<<tagShift);
604 if (tagStore[chain_ptr].tag == tag &&
605 (tagStore[chain_ptr].isValid())) {
606 *_depth = depth;
607 return &tagStore[chain_ptr];
608 }
609 depth++;
610 chain_ptr = tagStore[chain_ptr].chain_ptr;
611 }
612 *_depth = depth;
613 return NULL;
614 }
615
616 void
617 IIC::invalidateBlk(IIC::BlkType *tag_ptr)
618 {
619 if (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]);
624 }
625 }
626 repl->removeEntry(tag_ptr->re);
627 freeTag(tag_ptr);
628 }
629 }
630
631 void
632 IIC::clearLocks()
633 {
634 for (int i = 0; i < numTags; i++){
635 tagStore[i].clearLoadLocks();
636 }
637 }
638
639 void
640 IIC::cleanupRefs()
641 {
642 for (unsigned i = 0; i < numTags; ++i) {
643 if (tagStore[i].isValid()) {
644 totalRefs += tagStore[i].refCount;
645 ++sampledRefs;
646 }
647 }
648 }