Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: MemoryAccessBuffer.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | /************************************************************************ | |
22 | ** | |
23 | ** Copyright (C) 2002, Sun Microsystems, Inc. | |
24 | ** | |
25 | ** Sun considers its source code as an unpublished, proprietary | |
26 | ** trade secret and it is available only under strict license provisions. | |
27 | ** This copyright notice is placed here only to protect Sun in the event | |
28 | ** the source is deemed a published work. Disassembly, decompilation, | |
29 | ** or other means of reducing the object code to human readable form | |
30 | ** is prohibited by the license agreement under which this code is | |
31 | ** provided to the user or company in possession of this copy." | |
32 | ** | |
33 | *************************************************************************/ | |
34 | #include "MemoryAccessBuffer.h" | |
35 | #include <sstream> | |
36 | ||
37 | using namespace std; | |
38 | ||
39 | //////////////////////////////////////////////// | |
40 | ||
41 | MemoryAccessBuffer::MemoryAccessBuffer() | |
42 | { | |
43 | } | |
44 | ||
45 | //////////////////////////////////////////////// | |
46 | ||
47 | MemoryAccessBuffer::MemoryAccessBuffer( const MemoryAccessBuffer & orig ) | |
48 | { | |
49 | // Replace the following line with your function body. | |
50 | // RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." ); | |
51 | } | |
52 | ||
53 | //////////////////////////////////////////////// | |
54 | ||
55 | MemoryAccessBuffer::~MemoryAccessBuffer() | |
56 | { | |
57 | ||
58 | } | |
59 | ||
60 | //////////////////////////////////////////////// | |
61 | ||
62 | const MemoryAccessBuffer & | |
63 | MemoryAccessBuffer::operator=( const MemoryAccessBuffer & rhs ) | |
64 | { | |
65 | // Replace the following line with your function body. | |
66 | // RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." ); | |
67 | ||
68 | return *this; | |
69 | } | |
70 | ||
71 | //////////////////////////////////////////////// | |
72 | ||
73 | bool | |
74 | MemoryAccessBuffer::operator==( const MemoryAccessBuffer & rhs ) const | |
75 | { | |
76 | // Replace the following line with your function body. | |
77 | // RIESLING_THROW_DOMAIN_ERROR( "Unimplemented function." ); | |
78 | return false; | |
79 | } | |
80 | ||
81 | //////////////////////////////////////////////// | |
82 | ||
83 | string | |
84 | MemoryAccessBuffer::toString() const | |
85 | { | |
86 | ostringstream os; | |
87 | list<MemoryAccessEntry>::const_iterator ii; | |
88 | ||
89 | os << "MemoryAccessBuffer (size=" << buf_.size() << ")" << endl; | |
90 | for (ii = buf_.begin(); ii != buf_.end(); ii++) { | |
91 | os << ii->toString(); | |
92 | } | |
93 | os << endl; | |
94 | ||
95 | return os.str(); | |
96 | } | |
97 | ||
98 | list<MemoryAccessEntry>::iterator | |
99 | MemoryAccessBuffer::pushBack(MemoryAccessEntry& entry) | |
100 | { | |
101 | list<MemoryAccessEntry>::iterator ii; | |
102 | buf_.push_back(entry); | |
103 | ii = buf_.end(); | |
104 | ||
105 | MSYNC_DEBUG(2, "MAB Pushback\n%s", entry.toString().c_str()); | |
106 | MSYNC_DEBUG(4, "%s", toString().c_str()); | |
107 | ||
108 | return (--ii); | |
109 | } | |
110 | ||
111 | /* STORE_COMMIT cannot be removed until all of the associated STORE_ACK, | |
112 | STORE_INV, and STORE_UPDATE have done. | |
113 | Considering the following sequence: | |
114 | STORE_COMMIT->LOAD_DATA (L1 hit) | |
115 | The LOAD_DATA should get data from memory which is old. If the STORE_COMMIT | |
116 | data is written to the memory, then the LOAD_DATA will get the new data which | |
117 | is wrong. | |
118 | (Probably STORE_INV is not needed in my algorithm. Think it more before remove | |
119 | this requirement.) | |
120 | */ | |
121 | void | |
122 | MemoryAccessBuffer::popFront(vector<MemoryAccessEntry>* wdbuf, Tso::TsoChecker* tsoChecker) | |
123 | { | |
124 | list<MemoryAccessEntry>::iterator ii; | |
125 | ||
126 | ii = buf_.begin(); | |
127 | ||
128 | while (ii != buf_.end() && (ii->isExecuted() || ii->isPopped())) { | |
129 | ||
130 | if (ii->getEntryType() == MEM_STORE_COMMIT) { | |
131 | if (!ii->isInvDone()) { | |
132 | MSYNC_DEBUG(2, "popFront: MEM_STORE_COMMIT wait for invalidation, ii=%s", ii->toString().c_str()); | |
133 | break; // must wait until all invalidation is done | |
134 | } | |
135 | // list<MemoryAccessEntry>::iterator it, it1; | |
136 | // it = ii->getLink(); | |
137 | // while (it != ii) { // note that the front() is not removed | |
138 | // it1 = it->getLink(); | |
139 | // it->setExecuted(true); | |
140 | // /* Set executed bit rather than remove them now to let them stay at MAB | |
141 | // until they reach to the head. | |
142 | // The main concern is the STORE_UPDATE record which is required for L1 | |
143 | // hit. There may be some problem if remove too early. | |
144 | // */ | |
145 | // // buf_.erase(it); | |
146 | ||
147 | // it = it1; | |
148 | // } | |
149 | if (ii->isLink2Valid()) { | |
150 | ii->getLink2()->setAcked(true); | |
151 | } | |
152 | if (!ii->isPopped() && !ii->isWriteBack()) { | |
153 | wdbuf->push_back(*ii); // write data to memory | |
154 | } | |
155 | } | |
156 | ||
157 | if (ii->getEntryType() == MEM_EVICT) { | |
158 | if (!ii->isInvDone()) { | |
159 | MSYNC_DEBUG(2, "popFront: MEM_EVICT wait for invalidation, ii=%s", ii->toString().c_str()); | |
160 | break; // must wait until all invalidation is done | |
161 | } | |
162 | } | |
163 | ||
164 | /* Note that N2 guarantees that LoadFill must be before the STEP that set | |
165 | executed_ flag, hence, N2 always sets cacheL1_ false. Therefore, in N2 | |
166 | the LoadData can be removed as soon as it reach to the head of the MAB | |
167 | and is executed. */ | |
168 | if (ii->getEntryType() == MEM_LOAD_DATA) { | |
169 | if (ii->getDsrc() == DSRC_L2_MEMORY && ii->isCacheL1()) { | |
170 | if (!ii->isLinkValid()) { | |
171 | MSYNC_DEBUG(2, "popFront: MEM_LOAD_DATA wait for LoadFill, ii=%s", ii->toString().c_str()); | |
172 | break; // must wait until LoadFill | |
173 | } | |
174 | } | |
175 | } | |
176 | ||
177 | if (ii->getEntryType() == MEM_FETCH_DATA) { | |
178 | if (ii->getDsrc() == DSRC_L2_MEMORY && ii->isCacheL1()) { | |
179 | if (!ii->isLinkValid()) { | |
180 | MSYNC_DEBUG(2, "popFront: MEM_FETCH_DATA wait for FetchFill, ii=%s", ii->toString().c_str()); | |
181 | break; // must wait until FetchFill | |
182 | // if (ii->isLink2Valid() && !ii->isAcked()) break; // must wait StoreL2Commit removed | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | MSYNC_DEBUG(2, "MAB Remove (front)\nii=%s", ii->toString().c_str()); | |
188 | ||
189 | #ifdef TSO | |
190 | /************************************************************************ | |
191 | * Interface to TsoChecker | |
192 | ************************************************************************/ | |
193 | // if a (load) entry is marked as popped, then it is never executed, don't | |
194 | // let it get added to tso checking structure. | |
195 | if (tsoChecker && !(ii->isPopped())) { | |
196 | switch (ii->getEntryType()) { | |
197 | case MEM_STORE_COMMIT: | |
198 | if (ii->getDmaStore() == false) { | |
199 | // if this is a DMA_STORE entry, don't let it go to TsoChecker | |
200 | tsoChecker->input(ii->getThrdId(), ii->getIseq(), ii->getItype(), ii->getEntryType(), | |
201 | ii->getAddr(), ii->getData(), | |
202 | (ii->getItype() == ITYPE_ATOMIC && !(ii->isSwitchData())) ? (uint8_t) 0 : ii->getSizeV(), | |
203 | ii->getDsrc(), | |
204 | ii->getId(), | |
205 | ii->getGlobal(), ii->getId()); | |
206 | } | |
207 | break; | |
208 | case MEM_LOAD_DATA: | |
209 | tsoChecker->input(ii->getThrdId(), ii->getIseq(), ii->getItype(), ii->getEntryType(), | |
210 | ii->getAddr(), ii->getData(), ii->getSizeV(), ii->getDsrc(), | |
211 | ii->getDsrcMid(), | |
212 | ii->getGlobal(), ii->getId()); | |
213 | break; | |
214 | default: break; | |
215 | } | |
216 | } | |
217 | #endif | |
218 | ||
219 | ii++; | |
220 | buf_.pop_front(); // remove the front one | |
221 | // Note that when an entry is removed, all links to this entry becomes | |
222 | // undefined. | |
223 | } | |
224 | ||
225 | MSYNC_DEBUG(4, "mab=%s", toString().c_str()); | |
226 | ||
227 | // // see if we can write back completed store_commits earlier | |
228 | // ii = buf_.begin(); | |
229 | // while (ii != buf_.end()) { | |
230 | // if ((ii->getEntryType() == MEM_STORE_COMMIT) && | |
231 | // (ii->isExecuted() && ii->isInvDone()) && | |
232 | // (!ii->isWriteBack())) | |
233 | // { | |
234 | // if (updateMemory(ii) == true) { | |
235 | // MSYNC_DEBUG(1, "popFront: early WriteMemory id=%d T%d pa=%#llx data=%#llx", (int)ii->getId(), (int)ii->getThrdId(), ii->getAddr(), ii->getData()); | |
236 | // wdbuf->push_back(*ii); // write data to memory | |
237 | // } | |
238 | // } | |
239 | // ii++; | |
240 | // } | |
241 | } | |
242 | ||
243 | //============================================================================= | |
244 | //============================================================================= | |
245 | list<MemoryAccessEntry>::iterator | |
246 | MemoryAccessBuffer::findL1InstrEntry(LoadStoreCmd& cmd) | |
247 | { | |
248 | list<MemoryAccessEntry>::iterator ii, match; | |
249 | uint64_t addr = cmd.getAddr(); | |
250 | uint32_t cid = cmd.getCoreId(); | |
251 | ||
252 | if (buf_.size() == 0) { | |
253 | return buf_.end(); | |
254 | } | |
255 | ||
256 | ii = buf_.end(); | |
257 | do { | |
258 | ii--; | |
259 | if (!ii->isPopped() && | |
260 | cid == ii->getCoreId() && | |
261 | (addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
262 | (ii->getEntryType() == MEM_FETCH_FILL)) { | |
263 | return (ii); | |
264 | } | |
265 | } while (ii != buf_.begin()); | |
266 | ||
267 | return (buf_.end()); | |
268 | } | |
269 | ||
270 | list<MemoryAccessEntry>::iterator | |
271 | MemoryAccessBuffer::findL1DataEntry(LoadStoreCmd& cmd) | |
272 | { | |
273 | return findL1DataEntry(buf_.end(), cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr()); | |
274 | } | |
275 | ||
276 | list<MemoryAccessEntry>::iterator | |
277 | MemoryAccessBuffer::findL1DataEntry(list<MemoryAccessEntry>::iterator from, uint32_t cid, uint32_t tid, uint64_t addr) | |
278 | { | |
279 | list<MemoryAccessEntry>::iterator ii, match; | |
280 | ||
281 | if (buf_.size() == 0) { | |
282 | return buf_.end(); | |
283 | } | |
284 | ||
285 | ii = from; | |
286 | do { | |
287 | ii--; | |
288 | if (!ii->isPopped() && | |
289 | cid == ii->getCoreId() && | |
290 | (addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
291 | (ii->getEntryType() == MEM_STORE_UPDATE || | |
292 | ii->getEntryType() == MEM_LOAD_FILL)) { | |
293 | return (ii); | |
294 | } | |
295 | } while (ii != buf_.begin()); | |
296 | ||
297 | return (buf_.end()); | |
298 | } | |
299 | ||
300 | /* The first, from, does not participate in the search */ | |
301 | list<MemoryAccessEntry>::iterator | |
302 | MemoryAccessBuffer::findL2DataEntry(list<MemoryAccessEntry>::iterator from, LoadStoreCmd& cmd) | |
303 | { | |
304 | return findL2DataEntry(from, cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr()); | |
305 | } | |
306 | ||
307 | list<MemoryAccessEntry>::iterator | |
308 | MemoryAccessBuffer::findL2DataEntry(list<MemoryAccessEntry>::iterator from, uint32_t cid, uint32_t tid, uint64_t addr, bool executed) | |
309 | { | |
310 | list<MemoryAccessEntry>::iterator ii; | |
311 | ||
312 | if (buf_.size() == 0 || from == buf_.begin()) { | |
313 | return buf_.end(); | |
314 | } | |
315 | ||
316 | int l2reg = 0; | |
317 | if (((addr & 0xf000000000) >= 0xa000000000) && | |
318 | ((addr & 0xf000000000) <= 0xbf00000000)) | |
319 | { | |
320 | // l2 registers | |
321 | l2reg = 1; | |
322 | } | |
323 | ||
324 | ii = from; | |
325 | do | |
326 | { | |
327 | ii--; | |
328 | if (!ii->isPopped() && | |
329 | ((addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) && | |
330 | (ii->getEntryType() == MEM_STORE_COMMIT)) | |
331 | { | |
332 | if ((executed == true) && (ii->isExecuted() == false)) | |
333 | { | |
334 | // we are looking for a store_commit entry that is already executed | |
335 | continue; | |
336 | } | |
337 | else | |
338 | { | |
339 | if ((l2reg == 1) && | |
340 | ((ii->getCoreId() / RieslingInterface::cores_per_cpu) != (cid / RieslingInterface::cores_per_cpu))) | |
341 | { | |
342 | // For, each node has its own l2 register set, those registers | |
343 | // are not accessable by other nodes, so the node-id must be the | |
344 | // same to be considered as a match. | |
345 | continue; | |
346 | } | |
347 | else | |
348 | { | |
349 | return (ii); | |
350 | } | |
351 | } | |
352 | } | |
353 | } while (ii != buf_.begin()); | |
354 | ||
355 | return (buf_.end()); | |
356 | } | |
357 | ||
358 | list<MemoryAccessEntry>::iterator | |
359 | MemoryAccessBuffer::findStoreInvStoreUpdateSrc(LoadStoreCmd& cmd) | |
360 | { | |
361 | list<MemoryAccessEntry>::iterator ii; | |
362 | uint32_t cbit = 1 << cmd.getCoreId(); | |
363 | ||
364 | if (buf_.size() == 0) { | |
365 | return buf_.end(); | |
366 | } | |
367 | ||
368 | for (ii = buf_.begin(); ii != buf_.end(); ii++) { | |
369 | if (!ii->isPopped() && | |
370 | ii->getEntryType() == MEM_STORE_COMMIT && | |
371 | cmd.getSrcTid() == ii->getThrdId() && | |
372 | (cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
373 | (cbit & ii->getInv()) != 0 && (cbit & ii->getCinv()) == 0) { | |
374 | return (ii); | |
375 | } | |
376 | } | |
377 | return (buf_.end()); | |
378 | } | |
379 | ||
380 | list<MemoryAccessEntry>::iterator | |
381 | MemoryAccessBuffer::findStoreAckSrc(LoadStoreCmd& cmd) | |
382 | { | |
383 | list<MemoryAccessEntry>::iterator ii; | |
384 | ||
385 | if (buf_.size() == 0) { | |
386 | return buf_.end(); | |
387 | } | |
388 | ||
389 | MSYNC_DEBUG(4, "%s", toString().c_str()); | |
390 | ||
391 | for (ii = buf_.begin(); ii != buf_.end(); ii++) { | |
392 | if (!ii->isPopped() && | |
393 | ii->getEntryType() == MEM_STORE_COMMIT && | |
394 | cmd.getSrcTid() == ii->getThrdId() && | |
395 | (cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
396 | !(ii->isAcked())) { | |
397 | return (ii); | |
398 | } | |
399 | } | |
400 | return (buf_.end()); | |
401 | } | |
402 | ||
403 | list<MemoryAccessEntry>::iterator | |
404 | MemoryAccessBuffer::findLoadFillSrc(LoadStoreCmd& cmd) | |
405 | { | |
406 | return findLoadFillSrc(buf_.end(), cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr(), false); | |
407 | } | |
408 | ||
409 | list<MemoryAccessEntry>::iterator | |
410 | MemoryAccessBuffer::findLoadFillSrc(list<MemoryAccessEntry>::iterator endMark, uint32_t cid, uint32_t tid, uint64_t addr, bool noFault) | |
411 | { | |
412 | list<MemoryAccessEntry>::iterator ii; | |
413 | ||
414 | if (buf_.size() == 0) { | |
415 | return buf_.end(); | |
416 | } | |
417 | ||
418 | for (ii = buf_.begin(); ii != endMark; ii++) { | |
419 | #ifdef N2MODEL | |
420 | if (!ii->isPopped() && | |
421 | ii->getEntryType() == MEM_LOAD_DATA && | |
422 | ii->getDsrc() == DSRC_L2_MEMORY && | |
423 | tid == ii->getThrdId() && | |
424 | !ii->isExecuted()) { | |
425 | if (!noFault) { | |
426 | if ((addr & ADDR_MASK) != (ii->getAddr() & ADDR_MASK)) | |
427 | { | |
428 | MS_ERROR("LoadFill mismatches with address of 1st non-executed LoadData of that thread. tid=%d PA=%llx", tid, addr); | |
429 | return buf_.end(); | |
430 | } | |
431 | if (ii->isLinkValid()) | |
432 | { | |
433 | MS_ERROR("LoadFill finds 1st non-executed LoadData having LoadFill already. tid=%d PA=%llx", tid, addr); | |
434 | return buf_.end(); | |
435 | } | |
436 | return (ii); | |
437 | } | |
438 | else { | |
439 | if (((addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) && | |
440 | (!ii->isLinkValid())) { | |
441 | return (ii); | |
442 | } | |
443 | else { | |
444 | return buf_.end(); | |
445 | } | |
446 | } | |
447 | } | |
448 | #else | |
449 | if (!ii->isPopped() && | |
450 | ii->getEntryType() == MEM_LOAD_DATA && | |
451 | ii->getDsrc() == DSRC_L2_MEMORY && | |
452 | ii->isCacheL1() && | |
453 | cid == ii->getCoreId() && | |
454 | (addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
455 | // !ii->isExecuted() && | |
456 | !ii->isLinkValid()) { // the last condition assumes the LoadFill | |
457 | return (ii); // is in the same order as LoadData in the same core | |
458 | } | |
459 | #endif | |
460 | } | |
461 | return (buf_.end()); | |
462 | } | |
463 | ||
464 | list<MemoryAccessEntry>::iterator | |
465 | MemoryAccessBuffer::findFetchFillSrc(LoadStoreCmd& cmd) | |
466 | { | |
467 | list<MemoryAccessEntry>::iterator ii; | |
468 | uint32_t cid = cmd.getCoreId(); | |
469 | uint32_t tid = cmd.getThrdId(); | |
470 | ||
471 | if (buf_.size() == 0) { | |
472 | return buf_.end(); | |
473 | } | |
474 | ||
475 | MSYNC_DEBUG(4, "Find cid=%d tid=%d addr=%llx", | |
476 | cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr()); | |
477 | MSYNC_DEBUG(4, "%s", toString().c_str()); | |
478 | ||
479 | for (ii = buf_.begin(); ii != buf_.end(); ii++) { | |
480 | if (!ii->isPopped() && | |
481 | ii->getEntryType() == MEM_FETCH_DATA && | |
482 | ii->getDsrc() == DSRC_L2_MEMORY && | |
483 | ii->isCacheL1() && | |
484 | cid == ii->getCoreId() && | |
485 | (cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) && | |
486 | !ii->isLinkValid()) { // the last condition assumes the LoadFill | |
487 | return (ii); // is in the same order as LoadData in the same core | |
488 | } | |
489 | } | |
490 | return (buf_.end()); | |
491 | } | |
492 | ||
493 | list<MemoryAccessEntry>::iterator | |
494 | MemoryAccessBuffer::findEvictInvSrc(LoadStoreCmd& cmd) | |
495 | { | |
496 | list<MemoryAccessEntry>::iterator ii; | |
497 | uint32_t cbit = 1 << cmd.getCoreId(); | |
498 | ||
499 | if (buf_.size() == 0) { | |
500 | return buf_.end(); | |
501 | } | |
502 | ||
503 | list<MemoryAccessEntry>::iterator jj = buf_.end(); | |
504 | for (ii = buf_.begin(); ii != buf_.end(); ii++) { | |
505 | if (!ii->isPopped() && | |
506 | ii->getEntryType() == MEM_EVICT && | |
507 | cmd.getSrcBank() == ii->getSrcBank() && | |
508 | cmd.getSet() == ii->getSet() && | |
509 | // the address offset within a dcache line size must match | |
510 | (cmd.getAddr() & (DCACHE_LINE_SIZE - 1)) == (ii->getAddr() & (DCACHE_LINE_SIZE - 1)) && | |
511 | // this assume we have one-to-one mapping between EVICT and EVICT_INV, | |
512 | // if we have more than one EVICT_INV for one EVICT, this can be in | |
513 | // trouble. 4/28/05 | |
514 | (cbit & ii->getInv()) != 0) { | |
515 | if ((cbit & ii->getCinv()) == 0) { | |
516 | // the first time we match up the entry, handle it. | |
517 | return (ii); | |
518 | } | |
519 | else { | |
520 | // we can have multiple EVICT_INV point to one EVICT, the first | |
521 | // match will take care of business, when the others come, we won't | |
522 | // have a real match for them, so just return the first match, | |
523 | // otherwise we will hit no match assert. | |
524 | jj = ii; | |
525 | //cerr << "WARNING: MemoryAccessBuffer::findEvictInvSrc: extra EVICT_INV, cmd=" << cmd.toString() << endl;//DBX | |
526 | } | |
527 | } | |
528 | } | |
529 | //return (buf_.end()); | |
530 | return jj; | |
531 | } | |
532 | ||
533 | //============================================================================= | |
534 | //============================================================================= | |
535 | void | |
536 | MemoryAccessBuffer::empty(int tid) | |
537 | { | |
538 | MSYNC_DEBUG(3, "Before empty T%d load entries:\n%s", tid, toString().c_str()); | |
539 | ||
540 | if (tid == -1) | |
541 | { | |
542 | // we are going to flush out the entire buffer, write back completed | |
543 | // store_commits first. If we are just to empty a particular strand's | |
544 | // entries, we should not have any completed store_commit entries for | |
545 | // that strand, so not looking for those here. | |
546 | list<MemoryAccessEntry>::iterator ii = buf_.begin(); | |
547 | while (ii != buf_.end()) | |
548 | { | |
549 | if ((ii->getEntryType() == MEM_STORE_COMMIT) && | |
550 | (ii->isExecuted() && ii->isInvDone()) && | |
551 | (!ii->isWriteBack())) | |
552 | { | |
553 | MSYNC_DEBUG(2, "before flush WriteMemory id=%d T%d pa=%#llx data=%#llx", (int)ii->getId(), (int)ii->getThrdId(), ii->getAddr(), ii->getData()); | |
554 | // write data to memory | |
555 | rif_->writeMemory(ii->getCoreId(), ii->getThrdId(), (ii->getAddr() & ADDR_MASK), ii->getData(), 8); | |
556 | } | |
557 | ii++; | |
558 | } | |
559 | } | |
560 | ||
561 | list<MemoryAccessEntry>::iterator ii; | |
562 | ii = buf_.end(); | |
563 | int size = buf_.size(); | |
564 | while (size > 0) { | |
565 | ii--; | |
566 | size--; | |
567 | //TODO check for entry type if we only empty a particular buffer, | |
568 | // e.g., load buffer. Otherwise remove all entries of the | |
569 | // specified strand-id. | |
570 | // if (ii->getThrdId() == tid) { | |
571 | if ((tid == -1) || | |
572 | ((ii->getThrdId() == tid) && | |
573 | (ii->getEntryType() == MEM_LOAD_DATA || ii->getEntryType() == MEM_LOAD_FILL) && | |
574 | (!ii->isExecuted()))) { | |
575 | //TODO make sure we free the space properly | |
576 | MSYNC_DEBUG(2, "%s Empty T%d load entry=%s", "MAB", tid, ii->toString().c_str()); | |
577 | ii->setPopped(); | |
578 | if (ii->getItype() == ITYPE_ATOMIC) { | |
579 | // an atomic instr comes with both load and store entries, | |
580 | // pop both of them. | |
581 | popBackStore(ii); | |
582 | } | |
583 | buf_.erase(ii); | |
584 | } | |
585 | } | |
586 | MSYNC_DEBUG(3, "After empty T%d:\n%s", tid, toString().c_str()); | |
587 | } | |
588 | ||
589 | //============================================================================= | |
590 | //============================================================================= | |
591 | void | |
592 | MemoryAccessBuffer::popBack(int tid, int count) | |
593 | { | |
594 | MSYNC_DEBUG(3, "Before popBack:\n%s", toString().c_str()); | |
595 | assert(buf_.size() >= count); | |
596 | ||
597 | list<MemoryAccessEntry>::iterator ii; | |
598 | ii = buf_.end(); | |
599 | int size = buf_.size(); | |
600 | while (size > 0 && count > 0) { | |
601 | ii--; | |
602 | size--; | |
603 | if ((ii->getThrdId() == tid) && | |
604 | (ii->getEntryType() == MEM_LOAD_DATA)) { | |
605 | MSYNC_DEBUG(2, "%s Remove (back): load=%s", "MAB", ii->toString().c_str()); | |
606 | //TODO make sure we free the space properly | |
607 | ||
608 | // there might be LOAD_FILL of this entry to come, so don't | |
609 | // remove it, just mark as popped, so later we can retire it | |
610 | // (as if it is an executed entry) | |
611 | //buf_.erase(ii); | |
612 | ii->setPopped(); | |
613 | count--; | |
614 | if (ii->getItype() == ITYPE_ATOMIC) { | |
615 | // an atomic instr comes with both load and store entries, | |
616 | // pop both of them. | |
617 | popBackStore(ii); | |
618 | } | |
619 | } | |
620 | } | |
621 | MSYNC_DEBUG(3, "After popBack:\n%s", toString().c_str()); | |
622 | } | |
623 | ||
624 | //============================================================================= | |
625 | //============================================================================= | |
626 | void | |
627 | MemoryAccessBuffer::popBackStore(list<MemoryAccessEntry>::iterator& ii) | |
628 | { | |
629 | list<MemoryAccessEntry>::iterator jj = buf_.end(); | |
630 | //int size2 = buf_.size(); | |
631 | bool found = false; | |
632 | //while (!found && size2 > 0) { | |
633 | while (!found && (jj != ii)) { | |
634 | // we are looking for a store_commit (jj) of an atomic instr, the SC | |
635 | // always comes after the corresponding load_data (ii), so if jj | |
636 | // reaches ii, then we know there is no SC associated with the ld_data | |
637 | jj--; | |
638 | //size2--; | |
639 | if ((jj->getThrdId() == ii->getThrdId()) && | |
640 | (jj->getEntryType() == MEM_STORE_COMMIT) && | |
641 | (jj->getItype() == ITYPE_ATOMIC) && | |
642 | (!jj->isPopped())) { | |
643 | MSYNC_DEBUG(2, "%s Remove (back): store=%s", "MAB", jj->toString().c_str()); | |
644 | jj->setPopped(); | |
645 | found = true; | |
646 | } | |
647 | } | |
648 | if (found) { | |
649 | refreshLoadEntry(jj); | |
650 | } | |
651 | else { | |
652 | MSYNC_DEBUG(1, "WARNING: popBackStore(): no matched store entry for load=%s", ii->toString().c_str()); | |
653 | } | |
654 | } | |
655 | ||
656 | //============================================================================= | |
657 | // once a store entry is removed from buffer (i.e., marked as popped due to | |
658 | // error injection), all the load entries that get data from the removed store | |
659 | // entry must look for new source to refresh their data. | |
660 | // Actually, we have to refresh store-commit as well. | |
661 | //============================================================================= | |
662 | void | |
663 | MemoryAccessBuffer::refreshLoadEntry(list<MemoryAccessEntry>::iterator fromMark) | |
664 | { | |
665 | //cerr << "DBX: MemoryAccessBuffer::refreshLoadEntry\n";//DBX | |
666 | ||
667 | list<MemoryAccessEntry>::iterator ii = fromMark; | |
668 | while (ii != buf_.end()) { | |
669 | ii++; | |
670 | if (ii->getEntryType() == MEM_LOAD_DATA) { | |
671 | // load_data | |
672 | uint32_t cid = ii->getCoreId(); | |
673 | uint32_t tid = ii->getThrdId(); | |
674 | uint64_t addr = ii->getAddr(); | |
675 | switch (ii->getDsrc()) { | |
676 | case DSRC_L1: | |
677 | ii->setData(getL1Data(ii, cid, tid, addr)); | |
678 | break; | |
679 | case DSRC_L2_MEMORY: | |
680 | ii->setData(getL2Data(ii, cid, tid, addr)); | |
681 | break; | |
682 | } | |
683 | } | |
684 | else if (ii->getEntryType() == MEM_LOAD_FILL) { | |
685 | // load_fill | |
686 | uint32_t cid = ii->getCoreId(); | |
687 | uint32_t tid = ii->getThrdId(); | |
688 | uint64_t addr = ii->getAddr(); | |
689 | list<MemoryAccessEntry>::iterator mlink = findLoadFillSrc(ii, cid, tid, addr, true); | |
690 | if (mlink == buf_.end()) { | |
691 | // read aligned 8 bytes | |
692 | ii->setData((rif_->readMemory(cid, tid, (addr & ADDR_MASK), 8))); | |
693 | } | |
694 | else { | |
695 | ii->setData(getL2Data(mlink, cid, tid, addr)); | |
696 | } | |
697 | } | |
698 | else if (ii->getEntryType() == MEM_STORE_COMMIT) { | |
699 | // store_commit | |
700 | if ((ii->getMerged() == true) && ((ii->getAddr() & ADDR_MASK) == (fromMark->getAddr() & ADDR_MASK))) { | |
701 | // if we had to merge data for this SC entry, we need to re-do | |
702 | // it again, because the previous SC entry may be thrown out | |
703 | // by error injection. | |
704 | uint32_t cid = ii->getCoreId(); | |
705 | uint32_t tid = ii->getThrdId(); | |
706 | uint64_t addr = ii->getAddr(); | |
707 | uint64_t mdata = getL2Data(ii, cid, tid, addr); | |
708 | mdata = merge(mdata, ii->getOrigData(), ii->getOrigSizeV()); | |
709 | ii->setData(mdata); | |
710 | } | |
711 | } | |
712 | } | |
713 | } | |
714 | ||
715 | //============================================================================= | |
716 | //============================================================================= | |
717 | uint64_t | |
718 | MemoryAccessBuffer::getL1Data(list<MemoryAccessEntry>::iterator from, uint32_t cid, uint32_t tid, uint64_t addr) | |
719 | { | |
720 | list<MemoryAccessEntry>::iterator mae = findL1DataEntry(from, cid, tid, addr); | |
721 | if (mae == buf_.end()) { | |
722 | // read aligned 8 bytes | |
723 | return (rif_->readMemory(cid, tid, (addr & ADDR_MASK), 8)); | |
724 | } | |
725 | else { | |
726 | return (mae->getData()); | |
727 | } | |
728 | } | |
729 | ||
730 | //============================================================================= | |
731 | //============================================================================= | |
732 | uint64_t | |
733 | MemoryAccessBuffer::getL2Data(list<MemoryAccessEntry>::iterator from, uint32_t cid, uint32_t tid, uint64_t addr, bool executed) | |
734 | { | |
735 | list<MemoryAccessEntry>::iterator mae = findL2DataEntry(from, cid, tid, addr, executed); | |
736 | if (mae == buf_.end()) { | |
737 | // read aligned 8 bytes | |
738 | return (rif_->readMemory(cid, tid, (addr & ADDR_MASK), 8)); | |
739 | } | |
740 | else { | |
741 | return (mae->getData()); | |
742 | } | |
743 | } | |
744 | ||
745 | //============================================================================= | |
746 | // copied from MemorySync::merge() | |
747 | //============================================================================= | |
748 | uint64_t | |
749 | MemoryAccessBuffer::merge (uint64_t todata, uint64_t fromdata, uint8_t mgvec) | |
750 | { | |
751 | uint64_t data; | |
752 | uint64_t byteMask1 = byteMask(~mgvec); | |
753 | uint64_t byteMask2 = byteMask(mgvec); | |
754 | data = (todata & byteMask1) | (fromdata & byteMask2); | |
755 | ||
756 | //MSYNC_DEBUG(4, "MemoryAccessBuffer::merge: todata=0x%llx fdata=0x%llx merge=0x%x result=0x%llx", todata, fromdata, (int) mgvec, data); | |
757 | ||
758 | return (data); | |
759 | } | |
760 | ||
761 | //============================================================================= | |
762 | // copied from MemorySync::byteMask() | |
763 | //============================================================================= | |
764 | uint64_t | |
765 | MemoryAccessBuffer::byteMask(const uint8_t vbyte) | |
766 | { | |
767 | uint64_t mask = 0ull; | |
768 | uint8_t bitSelector = 0x80; // 10000000 | |
769 | ||
770 | for (int i = 0; i < 8; i++) { | |
771 | mask = mask << 8; | |
772 | mask = ((vbyte & bitSelector) == 0) ? mask : mask | 0xffull; | |
773 | bitSelector >>= 1; | |
774 | } | |
775 | return (mask); | |
776 | } | |
777 | ||
778 | //============================================================================= | |
779 | // search for a matching dma_store_start entry with exe=0 | |
780 | //============================================================================= | |
781 | list<MemoryAccessEntry>::iterator | |
782 | MemoryAccessBuffer::findDmaStoreStart(LoadStoreCmd& cmd, int type) | |
783 | { | |
784 | list<MemoryAccessEntry>::iterator ii = buf_.begin(); | |
785 | while (ii != buf_.end()) | |
786 | { | |
787 | if ((ii->getEntryType() == MEM_DMA_STORE_START) && | |
788 | (!ii->isExecuted())) | |
789 | { | |
790 | if (type == DMA_EVICT) | |
791 | { | |
792 | // EVICT | |
793 | if ((cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) | |
794 | { | |
795 | return ii; | |
796 | } | |
797 | } | |
798 | else if (type == DMA_EVICT_INV) | |
799 | { | |
800 | // EVICT_INV | |
801 | uint32_t cbit = 1 << cmd.getCoreId(); | |
802 | if ((cmd.getSrcBank() == ii->getSrcBank()) && | |
803 | // set is always 0 at the moment | |
804 | (cmd.getSet() == ii->getSet()) && | |
805 | // the address offset within a dcache line size must match | |
806 | ((cmd.getAddr() & (DCACHE_LINE_SIZE - 1)) == (ii->getAddr() & (DCACHE_LINE_SIZE - 1))) && | |
807 | (((ii->getInv() & cbit) != 0) && ((ii->getCinv() & cbit) == 0))) | |
808 | { | |
809 | return ii; | |
810 | } | |
811 | } | |
812 | else if (type == DMA_STORE) | |
813 | { | |
814 | // corresponding DMA_STORE | |
815 | if ((cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) | |
816 | { | |
817 | return ii; | |
818 | } | |
819 | } | |
820 | else | |
821 | { | |
822 | MS_ERROR("findDmaStoreStart given wrong type %d", type); | |
823 | return buf_.end(); | |
824 | } | |
825 | } | |
826 | ii++; | |
827 | } | |
828 | // get here only if not finding any matched entry | |
829 | return buf_.end(); | |
830 | } | |
831 | ||
832 | //============================================================================= | |
833 | // search for a matching dma_store entry with inv_vec==0 (EVICT), or one | |
834 | // with the corresponding bit in inv_vec==1 (EVICT_INV) | |
835 | //============================================================================= | |
836 | list<MemoryAccessEntry>::iterator | |
837 | MemoryAccessBuffer::findDmaStoreEntry(LoadStoreCmd& cmd, int type) | |
838 | { | |
839 | list<MemoryAccessEntry>::iterator ii = buf_.begin(); | |
840 | while (ii != buf_.end()) { | |
841 | if ((ii->getEntryType() == MEM_STORE_COMMIT) && | |
842 | (ii->getDmaStore() == true)) { | |
843 | if (type == DMA_EVICT) { | |
844 | // EVICT | |
845 | if (((cmd.getAddr() & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) && | |
846 | (ii->getInvSet() == false)) { | |
847 | // inv_vec is not set yet, this is the one. | |
848 | return ii; | |
849 | } | |
850 | } | |
851 | else if (type == DMA_EVICT_INV) { | |
852 | // EVICT_INV | |
853 | uint32_t cbit = 1 << cmd.getCoreId(); | |
854 | if ((cmd.getSrcBank() == ii->getSrcBank()) && | |
855 | (cmd.getSet() == ii->getSet()) && | |
856 | // the address offset within a dcache line size must match | |
857 | ((cmd.getAddr() & (DCACHE_LINE_SIZE - 1)) == (ii->getAddr() & (DCACHE_LINE_SIZE - 1))) && | |
858 | (((ii->getInv() & cbit) != 0) && ((ii->getCinv() & cbit) == 0))) { | |
859 | // if the corresponding bit in inv_vec is 1 and is not | |
860 | // set yet, this is the one. | |
861 | return ii; | |
862 | } | |
863 | } | |
864 | else | |
865 | { | |
866 | MS_ERROR("findDmaStoreEntry given wrong type %d", type); | |
867 | return buf_.end(); | |
868 | } | |
869 | } | |
870 | ii++; | |
871 | } | |
872 | // did not find any matched entry | |
873 | return buf_.end(); | |
874 | } | |
875 | ||
876 | ||
877 | //============================================================================= | |
878 | // when a store_commit is completed (including related inv & upd), write the | |
879 | // data back to memory if there is no address conflict with load entries in | |
880 | // front of the store_commit in MAB. Even if the data is written back here, | |
881 | // it will be written back to memory again when the store_commit reaches the | |
882 | // head of MAB, though it is a duplicate act. ===> not working yet, 3/31/2006 | |
883 | //============================================================================= | |
884 | bool | |
885 | MemoryAccessBuffer::updateMemory(list<MemoryAccessEntry>::iterator stCommit) | |
886 | { | |
887 | if (buf_.size() <= 1) { | |
888 | // there is at most one entry, nothing to check about, the data | |
889 | // will be written back by normal MAB checking, no need to do it here. | |
890 | return false; | |
891 | } | |
892 | else { | |
893 | uint64_t addr = stCommit->getAddr(); | |
894 | list<MemoryAccessEntry>::iterator ii = stCommit; | |
895 | bool writeBack = true; | |
896 | do { | |
897 | // 4/20/06. We said that Riesling could post a STCOM from the MAB | |
898 | // to Global Memory early. We need to change the condition when | |
899 | //this can be done. | |
900 | // | |
901 | // OLD | |
902 | // If there is nothing in the MAB before the STCOM to the same | |
903 | // L2 cache line PA[39:4]. | |
904 | // | |
905 | // NEW | |
906 | // If there is nothing in the MAB before the STCOM to the same | |
907 | // L1 index PA[10:4] | |
908 | // | |
909 | // More details: | |
910 | // It is correct that the STCOM had ivect=0 even though it | |
911 | // doesn't seem to make sense. It has ivect=0 because there was | |
912 | // an earlier Load to a different PA, but to the same L1 index | |
913 | // that replaced the entry in the L1$. That is why the Store did | |
914 | // not need to invalidate the L1$. | |
915 | ii--; | |
916 | if (ii->getEntryType() == MEM_LOAD_DATA) { | |
917 | if ((!ii->isExecuted() && !ii->isPopped()) && | |
918 | ((ii->getAddr() & L1_CACHE_INDEX_MASK) == (addr & L1_CACHE_INDEX_MASK))) { | |
919 | // entry of the same cache line | |
920 | // make it simpler and more conservative, if there is an entry | |
921 | // of the same cache line in frontend of this store_commit, | |
922 | // don't write the store_commit data back to memory. | |
923 | writeBack = false; | |
924 | } | |
925 | } | |
926 | else if ((ii->getAddr() & L2_CACHE_LINE_MASK) == (addr & L2_CACHE_LINE_MASK)) { | |
927 | writeBack = false; | |
928 | } | |
929 | // if ((ii->getEntryType() == MEM_LOAD_DATA) && | |
930 | // (!ii->isExecuted() && !ii->isPopped())) { | |
931 | // // there is a load from the same cache line which is | |
932 | // // not completed yet, cannot write the store_commit data | |
933 | // // back to memory | |
934 | // writeBack = false; | |
935 | // } | |
936 | // else if ((ii->getEntryType() == MEM_STORE_COMMIT) && | |
937 | // ((!ii->isExecuted() && !ii->isPopped()) || | |
938 | // (ii->isExecuted() && !ii->isInvDone()))) { | |
939 | // // there is a store to the same cache line which is | |
940 | // // not completed yet, cannot write the store_commit data | |
941 | // // back to memory | |
942 | // writeBack = false; | |
943 | // } | |
944 | // else if ((ii->getEntryType() == MEM_STORE_UPDATE) || | |
945 | // (ii->getEntryType() == MEM_LOAD_FILL)) { | |
946 | // // have to wait til no store_update/load_fill of the same | |
947 | // // cache line is in front of this store_commit | |
948 | // writeBack = false; | |
949 | // } | |
950 | // else if ((ii->getEntryType() == MEM_EVICT) && | |
951 | // (!ii->isInvDone())) { | |
952 | // // if there is a incompleted MEM_EVICT in front, wait | |
953 | // writeBack = false; | |
954 | // } | |
955 | // } | |
956 | } while ((writeBack == true) && (ii != buf_.begin())); | |
957 | ||
958 | if (writeBack == true) { | |
959 | stCommit->setWriteBack(); | |
960 | } | |
961 | ||
962 | return writeBack; | |
963 | } | |
964 | } |