Merge zizzer:/z/m5/Bitkeeper/newmem
[gem5.git] / src / mem / cache / tags / lru.cc
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 * Definitions of LRU tag store.
34 */
35
36 #include <string>
37
38 #include "mem/cache/base_cache.hh"
39 #include "base/intmath.hh"
40 #include "mem/cache/tags/lru.hh"
41 #include "sim/root.hh"
42
43 using namespace std;
44
45 LRUBlk*
46 CacheSet::findBlk(int asid, Addr tag) const
47 {
48 for (int i = 0; i < assoc; ++i) {
49 if (blks[i]->tag == tag && blks[i]->isValid()) {
50 return blks[i];
51 }
52 }
53 return 0;
54 }
55
56
57 void
58 CacheSet::moveToHead(LRUBlk *blk)
59 {
60 // nothing to do if blk is already head
61 if (blks[0] == blk)
62 return;
63
64 // write 'next' block into blks[i], moving up from MRU toward LRU
65 // until we overwrite the block we moved to head.
66
67 // start by setting up to write 'blk' into blks[0]
68 int i = 0;
69 LRUBlk *next = blk;
70
71 do {
72 assert(i < assoc);
73 // swap blks[i] and next
74 LRUBlk *tmp = blks[i];
75 blks[i] = next;
76 next = tmp;
77 ++i;
78 } while (next != blk);
79 }
80
81
82 // create and initialize a LRU/MRU cache structure
83 LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
84 numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency)
85 {
86 // Check parameters
87 if (blkSize < 4 || !isPowerOf2(blkSize)) {
88 fatal("Block size must be at least 4 and a power of 2");
89 }
90 if (numSets <= 0 || !isPowerOf2(numSets)) {
91 fatal("# of sets must be non-zero and a power of 2");
92 }
93 if (assoc <= 0) {
94 fatal("associativity must be greater than zero");
95 }
96 if (hitLatency <= 0) {
97 fatal("access latency must be greater than zero");
98 }
99
100 LRUBlk *blk;
101 int i, j, blkIndex;
102
103 blkMask = blkSize - 1;
104 setShift = floorLog2(blkSize);
105 setMask = numSets - 1;
106 tagShift = setShift + floorLog2(numSets);
107 warmedUp = false;
108 /** @todo Make warmup percentage a parameter. */
109 warmupBound = numSets * assoc;
110
111 sets = new CacheSet[numSets];
112 blks = new LRUBlk[numSets * assoc];
113 // allocate data storage in one big chunk
114 dataBlks = new uint8_t[numSets*assoc*blkSize];
115
116 blkIndex = 0; // index into blks array
117 for (i = 0; i < numSets; ++i) {
118 sets[i].assoc = assoc;
119
120 sets[i].blks = new LRUBlk*[assoc];
121
122 // link in the data blocks
123 for (j = 0; j < assoc; ++j) {
124 // locate next cache block
125 blk = &blks[blkIndex];
126 blk->data = &dataBlks[blkSize*blkIndex];
127 ++blkIndex;
128
129 // invalidate new cache block
130 blk->status = 0;
131
132 //EGH Fix Me : do we need to initialize blk?
133
134 // Setting the tag to j is just to prevent long chains in the hash
135 // table; won't matter because the block is invalid
136 blk->tag = j;
137 blk->whenReady = 0;
138 blk->asid = -1;
139 blk->isTouched = false;
140 blk->size = blkSize;
141 sets[i].blks[j]=blk;
142 blk->set = i;
143 }
144 }
145 }
146
147 LRU::~LRU()
148 {
149 delete [] dataBlks;
150 delete [] blks;
151 delete [] sets;
152 }
153
154 // probe cache for presence of given block.
155 bool
156 LRU::probe(int asid, Addr addr) const
157 {
158 // return(findBlock(Read, addr, asid) != 0);
159 Addr tag = extractTag(addr);
160 unsigned myset = extractSet(addr);
161
162 LRUBlk *blk = sets[myset].findBlk(asid, tag);
163
164 return (blk != NULL); // true if in cache
165 }
166
167 LRUBlk*
168 LRU::findBlock(Addr addr, int asid, int &lat)
169 {
170 Addr tag = extractTag(addr);
171 unsigned set = extractSet(addr);
172 LRUBlk *blk = sets[set].findBlk(asid, tag);
173 lat = hitLatency;
174 if (blk != NULL) {
175 // move this block to head of the MRU list
176 sets[set].moveToHead(blk);
177 if (blk->whenReady > curTick
178 && blk->whenReady - curTick > hitLatency) {
179 lat = blk->whenReady - curTick;
180 }
181 blk->refCount += 1;
182 }
183
184 return blk;
185 }
186
187 LRUBlk*
188 LRU::findBlock(Packet * &pkt, int &lat)
189 {
190 Addr addr = pkt->getAddr();
191 int asid = pkt->req->getAsid();
192
193 Addr tag = extractTag(addr);
194 unsigned set = extractSet(addr);
195 LRUBlk *blk = sets[set].findBlk(asid, tag);
196 lat = hitLatency;
197 if (blk != NULL) {
198 // move this block to head of the MRU list
199 sets[set].moveToHead(blk);
200 if (blk->whenReady > curTick
201 && blk->whenReady - curTick > hitLatency) {
202 lat = blk->whenReady - curTick;
203 }
204 blk->refCount += 1;
205 }
206
207 return blk;
208 }
209
210 LRUBlk*
211 LRU::findBlock(Addr addr, int asid) const
212 {
213 Addr tag = extractTag(addr);
214 unsigned set = extractSet(addr);
215 LRUBlk *blk = sets[set].findBlk(asid, tag);
216 return blk;
217 }
218
219 LRUBlk*
220 LRU::findReplacement(Packet * &pkt, PacketList &writebacks,
221 BlkList &compress_blocks)
222 {
223 unsigned set = extractSet(pkt->getAddr());
224 // grab a replacement candidate
225 LRUBlk *blk = sets[set].blks[assoc-1];
226 sets[set].moveToHead(blk);
227 if (blk->isValid()) {
228 replacements[0]++;
229 totalRefs += blk->refCount;
230 ++sampledRefs;
231 blk->refCount = 0;
232 } else if (!blk->isTouched) {
233 tagsInUse++;
234 blk->isTouched = true;
235 if (!warmedUp && tagsInUse.value() >= warmupBound) {
236 warmedUp = true;
237 warmupCycle = curTick;
238 }
239 }
240
241 return blk;
242 }
243
244 void
245 LRU::invalidateBlk(int asid, Addr addr)
246 {
247 LRUBlk *blk = findBlock(addr, asid);
248 if (blk) {
249 blk->status = 0;
250 blk->isTouched = false;
251 tagsInUse--;
252 }
253 }
254
255 void
256 LRU::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
257 {
258 assert(source == blkAlign(source));
259 assert(dest == blkAlign(dest));
260 LRUBlk *source_blk = findBlock(source, asid);
261 assert(source_blk);
262 LRUBlk *dest_blk = findBlock(dest, asid);
263 if (dest_blk == NULL) {
264 // Need to do a replacement
265 Request *search = new Request(dest,1,0);
266 Packet * pkt = new Packet(search, Packet::ReadReq, -1);
267 BlkList dummy_list;
268 dest_blk = findReplacement(pkt, writebacks, dummy_list);
269 if (dest_blk->isValid() && dest_blk->isModified()) {
270 // Need to writeback data.
271 /* pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
272 dest_blk->set),
273 dest_blk->req->asid,
274 dest_blk->xc,
275 blkSize,
276 dest_blk->data,
277 dest_blk->size);
278 */
279 Request *writebackReq = new Request(regenerateBlkAddr(dest_blk->tag,
280 dest_blk->set),
281 blkSize, 0);
282 Packet *writeback = new Packet(writebackReq, Packet::Writeback, -1);
283 writeback->dataDynamic<uint8_t>(dest_blk->data);
284 writebacks.push_back(writeback);
285 }
286 dest_blk->tag = extractTag(dest);
287 dest_blk->asid = asid;
288 delete search;
289 delete pkt;
290 }
291 /**
292 * @todo Can't assume the status once we have coherence on copies.
293 */
294
295 // Set this block as readable, writeable, and dirty.
296 dest_blk->status = 7;
297 memcpy(dest_blk->data, source_blk->data, blkSize);
298 }
299
300 void
301 LRU::cleanupRefs()
302 {
303 for (int i = 0; i < numSets*assoc; ++i) {
304 if (blks[i].isValid()) {
305 totalRefs += blks[i].refCount;
306 ++sampledRefs;
307 }
308 }
309 }