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.
42 #include "mem/cache/base_cache.hh"
43 #include "mem/cache/tags/iic.hh"
44 #include "base/intmath.hh"
45 #include "sim/root.hh" // for curTick
47 #include "base/trace.hh" // for DPRINTF
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 numBlocks(params
.size
/subSize
),
64 numTags(hashSets
* assoc
+ params
.size
/blkSize
-1),
65 numSecondary(params
.size
/blkSize
),
67 primaryBound(hashSets
* assoc
)
72 if (blkSize
< 4 || !isPowerOf2(blkSize
)) {
73 fatal("Block size must be at least 4 and a power of 2");
75 if (hashSets
<= 0 || !isPowerOf2(hashSets
)) {
76 fatal("# of hashsets must be non-zero and a power of 2");
79 fatal("associativity must be greater than zero");
81 if (hitLatency
<= 0) {
82 fatal("access latency must be greater than zero");
84 if (numSub
*subSize
!= blkSize
) {
85 fatal("blocksize must be evenly divisible by subblock size");
89 freeSecond
= numSecondary
;
92 warmupBound
= params
.size
/blkSize
;
94 // Replacement Policy Initialization
100 // allocate data reference counters
101 dataReferenceCount
= new int[numBlocks
];
102 memset(dataReferenceCount
, 0, numBlocks
*sizeof(int));
104 // Allocate storage for both internal data and block fast access data.
105 // We allocate it as one large chunk to reduce overhead and to make
108 dataStore
= new uint8_t[(numBlocks
+ numTags
) * blkSize
];
109 dataBlks
= new uint8_t*[numBlocks
];
110 for (i
= 0; i
< numBlocks
; ++i
) {
111 dataBlks
[i
] = &dataStore
[data_index
];
113 data_index
+= subSize
;
116 assert(data_index
== numBlocks
* subSize
);
118 // allocate and init tag store
119 tagStore
= new IICTag
[numTags
];
122 // allocate and init sets
123 sets
= new IICSet
[hashSets
];
124 for (i
= 0; i
< hashSets
; ++i
) {
125 sets
[i
].assoc
= assoc
;
126 sets
[i
].tags
= new IICTag
*[assoc
];
127 sets
[i
].chain_ptr
= tagNull
;
129 for (int j
= 0; j
< assoc
; ++j
) {
130 IICTag
*tag
= &tagStore
[blkIndex
++];
131 tag
->chain_ptr
= tagNull
;
132 tag
->data_ptr
.resize(numSub
);
134 tag
->trivialData
= new uint8_t[trivialSize
];
136 sets
[i
].tags
[j
] = tag
;
138 tag
->data
= &dataStore
[data_index
];
139 data_index
+= blkSize
;
143 assert(blkIndex
== primaryBound
);
145 for (i
= primaryBound
; i
< tagNull
; i
++) {
146 tagStore
[i
].chain_ptr
= i
+1;
147 //setup data ptrs to subblocks
148 tagStore
[i
].data_ptr
.resize(numSub
);
149 tagStore
[i
].size
= blkSize
;
150 tagStore
[i
].trivialData
= new uint8_t[trivialSize
];
151 tagStore
[i
].numData
= 0;
153 tagStore
[i
].data
= &dataStore
[data_index
];
154 data_index
+= blkSize
;
156 freelist
= primaryBound
;
161 delete [] dataReferenceCount
;
167 /* register cache stats */
169 IIC::regStats(const string
&name
)
171 using namespace Stats
;
173 BaseTags::regStats(name
);
175 hitHashDepth
.init(0, 20, 1);
176 missHashDepth
.init(0, 20, 1);
177 setAccess
.init(0, hashSets
, 1);
179 /** IIC Statistics */
181 .name(name
+ ".hit_hash_depth_dist")
182 .desc("Dist. of Hash lookup depths")
187 .name(name
+ ".miss_hash_depth_dist")
188 .desc("Dist. of Hash lookup depths")
192 repl
->regStats(name
);
196 .name(name
+ ".set_access_dist")
197 .desc("Dist. of Accesses across sets")
202 .name(name
+ ".miss_depth_total")
203 .desc("Total of miss depths")
207 .name(name
+ ".hash_miss")
208 .desc("Total of misses in hash table")
212 .name(name
+ ".hit_depth_total")
213 .desc("Total of hit depths")
217 .name(name
+ ".hash_hit")
218 .desc("Total of hites in hash table")
222 // probe cache for presence of given block.
224 IIC::probe(int asid
, Addr addr
) const
226 return (findBlock(addr
,asid
) != NULL
);
230 IIC::findBlock(Addr addr
, int asid
, int &lat
)
232 Addr tag
= extractTag(addr
);
233 unsigned set
= hash(addr
);
236 unsigned long chain_ptr
;
239 setAccess
.sample(set
);
241 IICTag
*tag_ptr
= sets
[set
].findTag(asid
, tag
, chain_ptr
);
243 if (tag_ptr
== NULL
&& chain_ptr
!= tagNull
) {
245 tag_ptr
= secondaryChain(asid
, tag
, chain_ptr
, &secondary_depth
);
246 set_lat
+= secondary_depth
;
247 // set depth for statistics fix this later!!! egh
248 sets
[set
].depth
= set_lat
;
250 if (tag_ptr
!= NULL
) {
251 /* need to move tag into primary table */
252 // need to preserve chain: fix this egh
253 sets
[set
].tags
[assoc
-1]->chain_ptr
= tag_ptr
->chain_ptr
;
254 tagSwap(tag_ptr
- tagStore
, sets
[set
].tags
[assoc
-1] - tagStore
);
255 tag_ptr
= sets
[set
].findTag(asid
, tag
, chain_ptr
);
256 assert(tag_ptr
!=NULL
);
260 set_lat
= set_lat
* hashDelay
+ hitLatency
;
261 if (tag_ptr
!= NULL
) {
262 // IIC replacement: if this is not the first element of
264 sets
[set
].moveToHead(tag_ptr
);
266 hitHashDepth
.sample(sets
[set
].depth
);
268 hitDepthTotal
+= sets
[set
].depth
;
269 tag_ptr
->status
|= BlkReferenced
;
271 if (tag_ptr
->whenReady
> curTick
&& tag_ptr
->whenReady
- curTick
> set_lat
) {
272 lat
= tag_ptr
->whenReady
- curTick
;
275 tag_ptr
->refCount
+= 1;
278 // fall through: cache block not found, not a hit...
279 missHashDepth
.sample(sets
[set
].depth
);
281 missDepthTotal
+= sets
[set
].depth
;
288 IIC::findBlock(Packet
* &pkt
, int &lat
)
290 Addr addr
= pkt
->getAddr();
291 int asid
= pkt
->req
->getAsid();
293 Addr tag
= extractTag(addr
);
294 unsigned set
= hash(addr
);
297 unsigned long chain_ptr
;
300 setAccess
.sample(set
);
302 IICTag
*tag_ptr
= sets
[set
].findTag(asid
, tag
, chain_ptr
);
304 if (tag_ptr
== NULL
&& chain_ptr
!= tagNull
) {
306 tag_ptr
= secondaryChain(asid
, tag
, chain_ptr
, &secondary_depth
);
307 set_lat
+= secondary_depth
;
308 // set depth for statistics fix this later!!! egh
309 sets
[set
].depth
= set_lat
;
311 if (tag_ptr
!= NULL
) {
312 /* need to move tag into primary table */
313 // need to preserve chain: fix this egh
314 sets
[set
].tags
[assoc
-1]->chain_ptr
= tag_ptr
->chain_ptr
;
315 tagSwap(tag_ptr
- tagStore
, sets
[set
].tags
[assoc
-1] - tagStore
);
316 tag_ptr
= sets
[set
].findTag(asid
, tag
, chain_ptr
);
317 assert(tag_ptr
!=NULL
);
321 set_lat
= set_lat
* hashDelay
+ hitLatency
;
322 if (tag_ptr
!= NULL
) {
323 // IIC replacement: if this is not the first element of
325 sets
[set
].moveToHead(tag_ptr
);
327 hitHashDepth
.sample(sets
[set
].depth
);
329 hitDepthTotal
+= sets
[set
].depth
;
330 tag_ptr
->status
|= BlkReferenced
;
332 if (tag_ptr
->whenReady
> curTick
&& tag_ptr
->whenReady
- curTick
> set_lat
) {
333 lat
= tag_ptr
->whenReady
- curTick
;
336 tag_ptr
->refCount
+= 1;
339 // fall through: cache block not found, not a hit...
340 missHashDepth
.sample(sets
[set
].depth
);
342 missDepthTotal
+= sets
[set
].depth
;
349 IIC::findBlock(Addr addr
, int asid
) const
351 Addr tag
= extractTag(addr
);
352 unsigned set
= hash(addr
);
354 unsigned long chain_ptr
;
356 IICTag
*tag_ptr
= sets
[set
].findTag(asid
, tag
, chain_ptr
);
357 if (tag_ptr
== NULL
&& chain_ptr
!= tagNull
) {
359 tag_ptr
= secondaryChain(asid
, tag
, chain_ptr
, &secondary_depth
);
366 IIC::findReplacement(Packet
* &pkt
, PacketList
&writebacks
,
367 BlkList
&compress_blocks
)
369 DPRINTF(IIC
, "Finding Replacement for %x\n", pkt
->getAddr());
370 unsigned set
= hash(pkt
->getAddr());
372 unsigned long *tmp_data
= new unsigned long[numSub
];
374 // Get a enough subblocks for a full cache line
375 for (int i
= 0; i
< numSub
; ++i
){
376 tmp_data
[i
] = getFreeDataBlock(writebacks
);
377 assert(dataReferenceCount
[tmp_data
[i
]]==0);
380 tag_ptr
= getFreeTag(set
, writebacks
);
383 for (int i
=0; i
< numSub
; ++i
) {
384 tag_ptr
->data_ptr
[i
] = tmp_data
[i
];
385 dataReferenceCount
[tag_ptr
->data_ptr
[i
]]++;
387 tag_ptr
->numData
= numSub
;
388 assert(tag_ptr
- tagStore
< primaryBound
); // make sure it is in primary
389 tag_ptr
->chain_ptr
= tagNull
;
390 sets
[set
].moveToHead(tag_ptr
);
393 list
<unsigned long> tag_indexes
;
394 repl
->doAdvance(tag_indexes
);
395 while (!tag_indexes
.empty()) {
396 if (!tagStore
[tag_indexes
.front()].isCompressed()) {
397 compress_blocks
.push_back(&tagStore
[tag_indexes
.front()]);
399 tag_indexes
.pop_front();
402 tag_ptr
->re
= (void*)repl
->add(tag_ptr
-tagStore
);
408 IIC::freeReplacementBlock(PacketList
& writebacks
)
411 unsigned long data_ptr
;
412 /* consult replacement policy */
413 tag_ptr
= &tagStore
[repl
->getRepl()];
414 assert(tag_ptr
->isValid());
416 DPRINTF(Cache
, "Replacing %x in IIC: %s\n",
417 regenerateBlkAddr(tag_ptr
->tag
,0),
418 tag_ptr
->isModified() ? "writeback" : "clean");
419 /* write back replaced block data */
420 if (tag_ptr
&& (tag_ptr
->isValid())) {
422 totalRefs
+= tag_ptr
->refCount
;
424 tag_ptr
->refCount
= 0;
426 if (tag_ptr
->isModified()) {
427 /* Packet * writeback =
428 buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
429 tag_ptr->req->asid, tag_ptr->xc, blkSize,
433 Request
*writebackReq
= new Request(regenerateBlkAddr(tag_ptr
->tag
, 0),
435 Packet
*writeback
= new Packet(writebackReq
, Packet::Writeback
, -1);
436 writeback
->allocate();
437 memcpy(writeback
->getPtr
<uint8_t>(), tag_ptr
->data
, blkSize
);
439 writebacks
.push_back(writeback
);
443 // free the data blocks
444 for (int i
= 0; i
< tag_ptr
->numData
; ++i
) {
445 data_ptr
= tag_ptr
->data_ptr
[i
];
446 assert(dataReferenceCount
[data_ptr
]>0);
447 if (--dataReferenceCount
[data_ptr
] == 0) {
448 freeDataBlock(data_ptr
);
455 IIC::getFreeDataBlock(PacketList
& writebacks
)
457 struct IICTag
*tag_ptr
;
458 unsigned long data_ptr
;
461 /* find data block */
462 while (blkFreelist
.empty()) {
463 freeReplacementBlock(writebacks
);
466 data_ptr
= blkFreelist
.front();
467 blkFreelist
.pop_front();
468 DPRINTF(IICMore
,"Found free data at %d\n",data_ptr
);
475 IIC::getFreeTag(int set
, PacketList
& writebacks
)
477 unsigned long tag_index
;
480 tag_ptr
= sets
[set
].findFree();
481 // if no free in primary, and secondary exists
482 if (!tag_ptr
&& numSecondary
) {
483 // need to spill a tag into secondary storage
484 while (freelist
== tagNull
) {
485 // get replacements until one is in secondary
486 freeReplacementBlock(writebacks
);
489 tag_index
= freelist
;
490 freelist
= tagStore
[freelist
].chain_ptr
;
493 assert(tag_index
!= tagNull
);
494 tagSwap(tag_index
, sets
[set
].tags
[assoc
-1] - tagStore
);
495 tagStore
[tag_index
].chain_ptr
= sets
[set
].chain_ptr
;
496 sets
[set
].chain_ptr
= tag_index
;
498 tag_ptr
= sets
[set
].tags
[assoc
-1];
500 DPRINTF(IICMore
,"Found free tag at %d\n",tag_ptr
- tagStore
);
502 if (!warmedUp
&& tagsInUse
.value() >= warmupBound
) {
504 warmupCycle
= curTick
;
511 IIC::freeTag(IICTag
*tag_ptr
)
513 unsigned long tag_index
, tmp_index
;
516 // we have a tag to clear
517 DPRINTF(IICMore
,"Freeing Tag for %x\n",
518 regenerateBlkAddr(tag_ptr
->tag
,0));
521 tag_ptr
->numData
= 0;
523 tag_index
= tag_ptr
- tagStore
;
524 if (tag_index
>= primaryBound
) {
525 // tag_ptr points to secondary store
526 assert(tag_index
< tagNull
); // remove this?? egh
527 if (tag_ptr
->chain_ptr
== tagNull
) {
528 // need to fix chain list
529 unsigned tmp_set
= hash(tag_ptr
->tag
<< tagShift
);
530 if (sets
[tmp_set
].chain_ptr
== tag_index
) {
531 sets
[tmp_set
].chain_ptr
= tagNull
;
533 tmp_index
= sets
[tmp_set
].chain_ptr
;
534 while (tmp_index
!= tagNull
535 && tagStore
[tmp_index
].chain_ptr
!= tag_index
) {
536 tmp_index
= tagStore
[tmp_index
].chain_ptr
;
538 assert(tmp_index
!= tagNull
);
539 tagStore
[tmp_index
].chain_ptr
= tagNull
;
541 tag_ptr
->chain_ptr
= freelist
;
542 freelist
= tag_index
;
545 // copy next chained entry to this tag location
546 tmp_index
= tag_ptr
->chain_ptr
;
547 tagSwap(tmp_index
, tag_index
);
548 tagStore
[tmp_index
].chain_ptr
= freelist
;
549 freelist
= tmp_index
;
553 // tag_ptr in primary hash table
554 assert(tag_index
< primaryBound
);
556 unsigned tmp_set
= hash(tag_ptr
->tag
<< tagShift
);
557 if (sets
[tmp_set
].chain_ptr
!= tagNull
) { // collapse chain
558 tmp_index
= sets
[tmp_set
].chain_ptr
;
559 tagSwap(tag_index
, tmp_index
);
560 tagStore
[tmp_index
].chain_ptr
= freelist
;
561 freelist
= tmp_index
;
563 sets
[tmp_set
].chain_ptr
= tag_ptr
->chain_ptr
;
564 sets
[tmp_set
].moveToTail(tag_ptr
);
571 IIC::freeDataBlock(unsigned long data_ptr
)
573 assert(dataReferenceCount
[data_ptr
] == 0);
574 DPRINTF(IICMore
, "Freeing data at %d\n", data_ptr
);
575 blkFreelist
.push_front(data_ptr
);
578 /** Use a simple modulo hash. */
579 #define SIMPLE_HASH 0
582 IIC::hash(Addr addr
) const {
584 return extractTag(addr
) % iic_hash_size
;
586 Addr tag
, mask
, x
, y
;
587 tag
= extractTag(addr
);
588 mask
= hashSets
-1; /* assumes iic_hash_size is a power of 2 */
590 y
= (tag
>> (int)(::log(hashSets
)/::log(2))) & mask
;
591 assert (x
< hashSets
&& y
< hashSets
);
598 IICSet::moveToHead(IICTag
*tag
)
603 // write 'next' block into blks[i], moving up from MRU toward LRU
604 // until we overwrite the block we moved to head.
606 // start by setting up to write 'blk' into blks[0]
612 // swap blks[i] and next
613 IICTag
*tmp
= tags
[i
];
617 } while (next
!= tag
);
621 IICSet::moveToTail(IICTag
*tag
)
623 if (tags
[assoc
-1] == tag
)
626 // write 'next' block into blks[i], moving up from MRU toward LRU
627 // until we overwrite the block we moved to head.
629 // start by setting up to write 'blk' into blks[0]
635 // swap blks[i] and next
636 IICTag
*tmp
= tags
[i
];
640 } while (next
!= tag
);
644 IIC::tagSwap(unsigned long index1
, unsigned long index2
)
646 DPRINTF(IIC
,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1
,
647 tagStore
[index1
].tag
<<tagShift
, index2
,
648 tagStore
[index2
].tag
<<tagShift
);
650 tmp_tag
= tagStore
[index1
];
651 tagStore
[index1
] = tagStore
[index2
];
652 tagStore
[index2
] = tmp_tag
;
653 if (tagStore
[index1
].isValid())
654 repl
->fixTag(tagStore
[index1
].re
, index2
, index1
);
655 if (tagStore
[index2
].isValid())
656 repl
->fixTag(tagStore
[index2
].re
, index1
, index2
);
661 IIC::secondaryChain(int asid
, Addr tag
, unsigned long chain_ptr
,
665 while (chain_ptr
!= tagNull
) {
666 DPRINTF(IIC
,"Searching secondary at %d for %x\n", chain_ptr
,
668 if (tagStore
[chain_ptr
].tag
== tag
&&
669 tagStore
[chain_ptr
].asid
== asid
&&
670 (tagStore
[chain_ptr
].isValid())) {
672 return &tagStore
[chain_ptr
];
675 chain_ptr
= tagStore
[chain_ptr
].chain_ptr
;
682 IIC::decompressBlock(unsigned long index
)
684 IICTag
*tag_ptr
= &tagStore
[index
];
685 if (tag_ptr
->isCompressed()) {
686 // decompress the data here.
691 IIC::compressBlock(unsigned long index
)
693 IICTag
*tag_ptr
= &tagStore
[index
];
694 if (!tag_ptr
->isCompressed()) {
695 // Compress the data here.
700 IIC::invalidateBlk(int asid
, Addr addr
)
702 IICTag
* tag_ptr
= findBlock(addr
, asid
);
704 for (int i
= 0; i
< tag_ptr
->numData
; ++i
) {
705 dataReferenceCount
[tag_ptr
->data_ptr
[i
]]--;
706 if (dataReferenceCount
[tag_ptr
->data_ptr
[i
]] == 0) {
707 freeDataBlock(tag_ptr
->data_ptr
[i
]);
710 repl
->removeEntry(tag_ptr
->re
);
716 IIC::readData(IICTag
*blk
, uint8_t *data
){
717 // assert(cache->doData());
718 assert(blk
->size
<= trivialSize
|| blk
->numData
> 0);
719 int data_size
= blk
->size
;
720 if (data_size
> trivialSize
) {
721 for (int i
= 0; i
< blk
->numData
; ++i
){
722 memcpy(data
+i
*subSize
,
723 &(dataBlks
[blk
->data_ptr
[i
]][0]),
724 (data_size
>subSize
)?subSize
:data_size
);
725 data_size
-= subSize
;
728 memcpy(data
,blk
->trivialData
,data_size
);
733 IIC::writeData(IICTag
*blk
, uint8_t *write_data
, int size
,
734 PacketList
& writebacks
){
735 // assert(cache->doData());
736 assert(size
< blkSize
|| !blk
->isCompressed());
737 DPRINTF(IIC
, "Writing %d bytes to %x\n", size
,
739 // Find the number of subblocks needed, (round up)
740 int num_subs
= (size
+ (subSize
-1))/subSize
;
741 if (size
<= trivialSize
) {
744 assert(num_subs
<= numSub
);
745 if (num_subs
> blk
->numData
) {
746 // need to allocate more data blocks
747 for (int i
= blk
->numData
; i
< num_subs
; ++i
){
748 blk
->data_ptr
[i
] = getFreeDataBlock(writebacks
);
749 dataReferenceCount
[blk
->data_ptr
[i
]] += 1;
751 } else if (num_subs
< blk
->numData
){
752 // can free data blocks
753 for (int i
=num_subs
; i
< blk
->numData
; ++i
){
754 // decrement reference count and compare to zero
757 * Make this work with copying.
759 if (--dataReferenceCount
[blk
->data_ptr
[i
]] == 0) {
760 freeDataBlock(blk
->data_ptr
[i
]);
765 blk
->numData
= num_subs
;
767 assert(size
<= trivialSize
|| blk
->numData
> 0);
768 if (size
> trivialSize
){
769 for (int i
= 0; i
< blk
->numData
; ++i
){
770 memcpy(&dataBlks
[blk
->data_ptr
[i
]][0], write_data
+ i
*subSize
,
771 (size
>subSize
)?subSize
:size
);
775 memcpy(blk
->trivialData
,write_data
,size
);
781 * @todo This code can break if the src is evicted to get a tag for the dest.
784 IIC::doCopy(Addr source
, Addr dest
, int asid
, PacketList
&writebacks
)
786 //Copy unsuported now
788 IICTag
*dest_tag
= findBlock(dest
, asid
);
791 for (int i
= 0; i
< dest_tag
->numData
; ++i
) {
792 if (--dataReferenceCount
[dest_tag
->data_ptr
[i
]] == 0) {
793 freeDataBlock(dest_tag
->data_ptr
[i
]);
796 // Reset replacement entry
798 dest_tag
= getFreeTag(hash(dest
), writebacks
);
799 dest_tag
->re
= (void*) repl
->add(dest_tag
- tagStore
);
800 dest_tag
->set
= hash(dest
);
801 dest_tag
->tag
= extractTag(dest
);
802 dest_tag
->asid
= asid
;
803 dest_tag
->status
= BlkValid
| BlkWritable
;
805 // Find the source tag here since it might move if we need to find a
806 // tag for the destination.
807 IICTag
*src_tag
= findBlock(source
, asid
);
809 assert(!cache
->doData() || src_tag
->size
<= trivialSize
810 || src_tag
->numData
> 0);
811 // point dest to source data and inc counter
812 for (int i
= 0; i
< src_tag
->numData
; ++i
) {
813 dest_tag
->data_ptr
[i
] = src_tag
->data_ptr
[i
];
814 ++dataReferenceCount
[dest_tag
->data_ptr
[i
]];
817 // Maintain fast access data.
818 memcpy(dest_tag
->data
, src_tag
->data
, blkSize
);
820 dest_tag
->xc
= src_tag
->xc
;
821 dest_tag
->size
= src_tag
->size
;
822 dest_tag
->numData
= src_tag
->numData
;
823 if (src_tag
->numData
== 0) {
824 // Data is stored in the trivial data, just copy it.
825 memcpy(dest_tag
->trivialData
, src_tag
->trivialData
, src_tag
->size
);
828 dest_tag
->status
|= BlkDirty
;
829 if (dest_tag
->size
< blkSize
) {
830 dest_tag
->status
|= BlkCompressed
;
832 dest_tag
->status
&= ~BlkCompressed
;
838 IIC::fixCopy(Packet
* &pkt
, PacketList
&writebacks
)
841 // if reference counter is greater than 1, do copy
843 Addr blk_addr
= blkAlign(pkt
->getAddr
);
844 IICTag
* blk
= findBlock(blk_addr
, pkt
->req
->getAsid());
846 if (blk
->numData
> 0 && dataReferenceCount
[blk
->data_ptr
[0]] != 1) {
848 // Mark the block as referenced so it doesn't get replaced.
849 blk
->status
|= BlkReferenced
;
850 for (int i
= 0; i
< blk
->numData
; ++i
){
851 unsigned long new_data
= getFreeDataBlock(writebacks
);
852 // Need to refresh pointer
854 * @todo Remove this refetch once we change IIC to pointer based
856 blk
= findBlock(blk_addr
, pkt
->req
->getAsid());
858 if (cache
->doData()) {
859 memcpy(&(dataBlks
[new_data
][0]),
860 &(dataBlks
[blk
->data_ptr
[i
]][0]),
863 dataReferenceCount
[blk
->data_ptr
[i
]]--;
864 dataReferenceCount
[new_data
]++;
865 blk
->data_ptr
[i
] = new_data
;
874 for (int i
= 0; i
< numTags
; ++i
) {
875 if (tagStore
[i
].isValid()) {
876 totalRefs
+= tagStore
[i
].refCount
;