Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / api / memsync / src / MemoryAccessBuffer.cc
CommitLineData
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
37using namespace std;
38
39////////////////////////////////////////////////
40
41MemoryAccessBuffer::MemoryAccessBuffer()
42{
43}
44
45////////////////////////////////////////////////
46
47MemoryAccessBuffer::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
55MemoryAccessBuffer::~MemoryAccessBuffer()
56{
57
58}
59
60////////////////////////////////////////////////
61
62const MemoryAccessBuffer &
63MemoryAccessBuffer::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
73bool
74MemoryAccessBuffer::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
83string
84MemoryAccessBuffer::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
98list<MemoryAccessEntry>::iterator
99MemoryAccessBuffer::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*/
121void
122MemoryAccessBuffer::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//=============================================================================
245list<MemoryAccessEntry>::iterator
246MemoryAccessBuffer::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
270list<MemoryAccessEntry>::iterator
271MemoryAccessBuffer::findL1DataEntry(LoadStoreCmd& cmd)
272{
273 return findL1DataEntry(buf_.end(), cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr());
274}
275
276list<MemoryAccessEntry>::iterator
277MemoryAccessBuffer::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 */
301list<MemoryAccessEntry>::iterator
302MemoryAccessBuffer::findL2DataEntry(list<MemoryAccessEntry>::iterator from, LoadStoreCmd& cmd)
303{
304 return findL2DataEntry(from, cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr());
305}
306
307list<MemoryAccessEntry>::iterator
308MemoryAccessBuffer::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
358list<MemoryAccessEntry>::iterator
359MemoryAccessBuffer::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
380list<MemoryAccessEntry>::iterator
381MemoryAccessBuffer::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
403list<MemoryAccessEntry>::iterator
404MemoryAccessBuffer::findLoadFillSrc(LoadStoreCmd& cmd)
405{
406 return findLoadFillSrc(buf_.end(), cmd.getCoreId(), cmd.getThrdId(), cmd.getAddr(), false);
407}
408
409list<MemoryAccessEntry>::iterator
410MemoryAccessBuffer::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
464list<MemoryAccessEntry>::iterator
465MemoryAccessBuffer::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
493list<MemoryAccessEntry>::iterator
494MemoryAccessBuffer::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//=============================================================================
535void
536MemoryAccessBuffer::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//=============================================================================
591void
592MemoryAccessBuffer::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//=============================================================================
626void
627MemoryAccessBuffer::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//=============================================================================
662void
663MemoryAccessBuffer::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//=============================================================================
717uint64_t
718MemoryAccessBuffer::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//=============================================================================
732uint64_t
733MemoryAccessBuffer::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//=============================================================================
748uint64_t
749MemoryAccessBuffer::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//=============================================================================
764uint64_t
765MemoryAccessBuffer::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//=============================================================================
781list<MemoryAccessEntry>::iterator
782MemoryAccessBuffer::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//=============================================================================
836list<MemoryAccessEntry>::iterator
837MemoryAccessBuffer::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//=============================================================================
884bool
885MemoryAccessBuffer::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}