inorder: utilize cached skeds in pipeline
[gem5.git] / src / cpu / inorder / resources / cache_unit.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
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: Korey Sewell
29 *
30 */
31
32 #include <vector>
33 #include <list>
34
35 #include "arch/isa_traits.hh"
36 #include "arch/locked_mem.hh"
37 #include "arch/utility.hh"
38 #include "arch/predecoder.hh"
39 #include "config/the_isa.hh"
40 #include "cpu/inorder/resources/cache_unit.hh"
41 #include "cpu/inorder/pipeline_traits.hh"
42 #include "cpu/inorder/cpu.hh"
43 #include "cpu/inorder/resource_pool.hh"
44 #include "mem/request.hh"
45
46 using namespace std;
47 using namespace TheISA;
48 using namespace ThePipeline;
49
50 #if TRACING_ON
51 static std::string
52 printMemData(uint8_t *data, unsigned size)
53 {
54 std::stringstream dataStr;
55 for (unsigned pos = 0; pos < size; pos++) {
56 ccprintf(dataStr, "%02x", data[pos]);
57 }
58 return dataStr.str();
59 }
60 #endif
61
62 Tick
63 CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
64 {
65 panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
66 return curTick();
67 }
68
69 void
70 CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
71 {
72 panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
73 }
74
75 void
76 CacheUnit::CachePort::recvStatusChange(Status status)
77 {
78 if (status == RangeChange)
79 return;
80
81 panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
82 }
83
84 bool
85 CacheUnit::CachePort::recvTiming(Packet *pkt)
86 {
87 cachePortUnit->processCacheCompletion(pkt);
88 return true;
89 }
90
91 void
92 CacheUnit::CachePort::recvRetry()
93 {
94 cachePortUnit->recvRetry();
95 }
96
97 CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
98 int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
99 : Resource(res_name, res_id, res_width, res_latency, _cpu),
100 cachePortBlocked(false)
101 {
102 cachePort = new CachePort(this);
103
104 // Hard-Code Selection For Now
105 if (res_name == "icache_port")
106 _tlb = params->itb;
107 else if (res_name == "dcache_port")
108 _tlb = params->dtb;
109 else
110 fatal("Unrecognized TLB name passed by user");
111
112 for (int i=0; i < MaxThreads; i++) {
113 tlbBlocked[i] = false;
114 }
115 }
116
117 TheISA::TLB*
118 CacheUnit::tlb()
119 {
120 return _tlb;
121
122 }
123
124 Port *
125 CacheUnit::getPort(const string &if_name, int idx)
126 {
127 if (if_name == resName)
128 return cachePort;
129 else
130 return NULL;
131 }
132
133 void
134 CacheUnit::init()
135 {
136 // Currently Used to Model TLB Latency. Eventually
137 // Switch to Timing TLB translations.
138 resourceEvent = new CacheUnitEvent[width];
139
140 cacheBlkSize = this->cachePort->peerBlockSize();
141 cacheBlkMask = cacheBlkSize - 1;
142
143 initSlots();
144 }
145
146 int
147 CacheUnit::getSlot(DynInstPtr inst)
148 {
149 ThreadID tid = inst->readTid();
150
151 if (tlbBlocked[inst->threadNumber]) {
152 return -1;
153 }
154
155 // For a Split-Load, the instruction would have processed once already
156 // causing the address to be unset.
157 if (!inst->validMemAddr() && !inst->splitInst) {
158 panic("[tid:%i][sn:%i] Mem. Addr. must be set before requesting "
159 "cache access\n", inst->readTid(), inst->seqNum);
160 }
161
162 Addr req_addr = inst->getMemAddr();
163
164 if (resName == "icache_port" ||
165 find(addrList[tid].begin(), addrList[tid].end(), req_addr) ==
166 addrList[tid].end()) {
167
168 int new_slot = Resource::getSlot(inst);
169
170 if (new_slot == -1)
171 return -1;
172
173 inst->memTime = curTick();
174 setAddrDependency(inst);
175 return new_slot;
176 } else {
177 // Allow same instruction multiple accesses to same address
178 // should only happen maybe after a squashed inst. needs to replay
179 if (addrMap[tid][req_addr] == inst->seqNum) {
180 int new_slot = Resource::getSlot(inst);
181
182 if (new_slot == -1)
183 return -1;
184
185 return new_slot;
186 } else {
187 DPRINTF(InOrderCachePort,
188 "[tid:%i] Denying request because there is an outstanding"
189 " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
190 inst->readTid(), req_addr, addrMap[tid][req_addr], inst->memTime);
191 return -1;
192 }
193 }
194
195 return -1;
196 }
197
198 void
199 CacheUnit::setAddrDependency(DynInstPtr inst)
200 {
201 Addr req_addr = inst->getMemAddr();
202 ThreadID tid = inst->readTid();
203
204 addrList[tid].push_back(req_addr);
205 addrMap[tid][req_addr] = inst->seqNum;
206
207 DPRINTF(AddrDep,
208 "[tid:%i]: [sn:%i]: Address %08p added to dependency list (size=%i)\n",
209 inst->readTid(), inst->seqNum, req_addr, addrList[tid].size());
210
211 //@NOTE: 10 is an arbitrarily "high" number, but to be exact
212 // we would need to know the # of outstanding accesses
213 // a priori. Information like fetch width, stage width,
214 // fetch buffer, and the branch resolution stage would be
215 // useful for the icache_port. For the dcache port, the #
216 // of outstanding cache accesses (mshrs) would be a good
217 // sanity check here.
218 //assert(addrList[tid].size() < 10);
219 }
220
221 void
222 CacheUnit::removeAddrDependency(DynInstPtr inst)
223 {
224 ThreadID tid = inst->readTid();
225
226 Addr mem_addr = inst->getMemAddr();
227
228 inst->unsetMemAddr();
229
230 // Erase from Address List
231 vector<Addr>::iterator vect_it = find(addrList[tid].begin(),
232 addrList[tid].end(),
233 mem_addr);
234 assert(vect_it != addrList[tid].end() || inst->splitInst);
235
236 if (vect_it != addrList[tid].end()) {
237 DPRINTF(AddrDep,
238 "[tid:%i]: [sn:%i] Address %08p removed from dependency "
239 "list\n", inst->readTid(), inst->seqNum, (*vect_it));
240
241 addrList[tid].erase(vect_it);
242
243 // Erase From Address Map (Used for Debugging)
244 addrMap[tid].erase(addrMap[tid].find(mem_addr));
245 }
246
247
248 }
249
250 ResReqPtr
251 CacheUnit::findRequest(DynInstPtr inst)
252 {
253 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
254 map<int, ResReqPtr>::iterator map_end = reqMap.end();
255
256 while (map_it != map_end) {
257 CacheRequest* cache_req =
258 dynamic_cast<CacheRequest*>((*map_it).second);
259 assert(cache_req);
260
261 if (cache_req &&
262 cache_req->getInst() == inst &&
263 cache_req->instIdx == inst->curSkedEntry->idx) {
264 return cache_req;
265 }
266 map_it++;
267 }
268
269 return NULL;
270 }
271
272 ResReqPtr
273 CacheUnit::findRequest(DynInstPtr inst, int idx)
274 {
275 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
276 map<int, ResReqPtr>::iterator map_end = reqMap.end();
277
278 while (map_it != map_end) {
279 CacheRequest* cache_req =
280 dynamic_cast<CacheRequest*>((*map_it).second);
281 assert(cache_req);
282
283 if (cache_req &&
284 cache_req->getInst() == inst &&
285 cache_req->instIdx == idx) {
286 return cache_req;
287 }
288 map_it++;
289 }
290
291 return NULL;
292 }
293
294
295 ResReqPtr
296 CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
297 int slot_num, unsigned cmd)
298 {
299 ScheduleEntry* sched_entry = *inst->curSkedEntry;
300
301 if (!inst->validMemAddr()) {
302 panic("Mem. Addr. must be set before requesting cache access\n");
303 }
304
305 MemCmd::Command pkt_cmd;
306
307 switch (sched_entry->cmd)
308 {
309 case InitSecondSplitRead:
310 pkt_cmd = MemCmd::ReadReq;
311
312 DPRINTF(InOrderCachePort,
313 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
314 inst->readTid(), inst->seqNum, inst->split2ndAddr);
315 break;
316
317 case InitiateReadData:
318 pkt_cmd = MemCmd::ReadReq;
319
320 DPRINTF(InOrderCachePort,
321 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
322 inst->readTid(), inst->seqNum, inst->getMemAddr());
323 break;
324
325 case InitSecondSplitWrite:
326 pkt_cmd = MemCmd::WriteReq;
327
328 DPRINTF(InOrderCachePort,
329 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
330 inst->readTid(), inst->seqNum, inst->split2ndAddr);
331 break;
332
333 case InitiateWriteData:
334 pkt_cmd = MemCmd::WriteReq;
335
336 DPRINTF(InOrderCachePort,
337 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
338 inst->readTid(), inst->seqNum, inst->getMemAddr());
339 break;
340
341 default:
342 panic("%i: Unexpected request type (%i) to %s", curTick(),
343 sched_entry->cmd, name());
344 }
345
346 return new CacheRequest(this, inst, stage_num, id, slot_num,
347 sched_entry->cmd, 0, pkt_cmd,
348 0/*flags*/, this->cpu->readCpuId(),
349 inst->curSkedEntry->idx);
350 }
351
352 void
353 CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
354 {
355 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
356 assert(cache_req);
357
358 // Check to see if this instruction is requesting the same command
359 // or a different one
360 if (cache_req->cmd != inst->curSkedEntry->cmd &&
361 cache_req->instIdx == inst->curSkedEntry->idx) {
362 // If different, then update command in the request
363 cache_req->cmd = inst->curSkedEntry->cmd;
364 DPRINTF(InOrderCachePort,
365 "[tid:%i]: [sn:%i]: Updating the command for this "
366 "instruction\n ", inst->readTid(), inst->seqNum);
367
368 service_request = true;
369 } else if (inst->curSkedEntry->idx != CacheUnit::InitSecondSplitRead &&
370 inst->curSkedEntry->idx != CacheUnit::InitSecondSplitWrite) {
371 // If same command, just check to see if memory access was completed
372 // but dont try to re-execute
373 DPRINTF(InOrderCachePort,
374 "[tid:%i]: [sn:%i]: requesting this resource again\n",
375 inst->readTid(), inst->seqNum);
376
377 service_request = true;
378 }
379 }
380
381 void
382 CacheUnit::setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
383 int acc_size, int flags)
384 {
385 ThreadID tid = inst->readTid();
386 Addr aligned_addr = inst->getMemAddr();
387
388 if (!cache_req->is2ndSplit()) {
389 inst->dataMemReq =
390 new Request(cpu->asid[tid], aligned_addr, acc_size, flags,
391 inst->instAddr(), cpu->readCpuId(),
392 tid);
393 cache_req->memReq = inst->dataMemReq;
394 } else {
395 assert(inst->splitInst);
396
397 inst->splitMemReq = new Request(cpu->asid[tid],
398 inst->split2ndAddr,
399 acc_size,
400 flags,
401 inst->instAddr(),
402 cpu->readCpuId(),
403 tid);
404 cache_req->memReq = inst->splitMemReq;
405 }
406 }
407
408 void
409 CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
410 int flags, TheISA::TLB::Mode tlb_mode)
411 {
412 ThreadID tid = inst->readTid();
413 //Addr aligned_addr = inst->getMemAddr();
414 unsigned stage_num = cache_req->getStageNum();
415 unsigned slot_idx = cache_req->getSlot();
416
417 setupMemRequest(inst, cache_req, acc_size, flags);
418
419 inst->fault =
420 _tlb->translateAtomic(cache_req->memReq,
421 cpu->thread[tid]->getTC(), tlb_mode);
422
423 if (inst->fault != NoFault) {
424 DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
425 "addr:%08p for [sn:%i].\n", tid, inst->fault->name(),
426 cache_req->memReq->getVaddr(), inst->seqNum);
427
428 cpu->pipelineStage[stage_num]->setResStall(cache_req, tid);
429
430 tlbBlocked[tid] = true;
431
432 cache_req->tlbStall = true;
433
434 scheduleEvent(slot_idx, 1);
435
436 cpu->trap(inst->fault, tid, inst);
437 } else {
438 DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
439 "to phys. addr:%08p.\n", tid, inst->seqNum,
440 cache_req->memReq->getVaddr(),
441 cache_req->memReq->getPaddr());
442 }
443
444 }
445
446 Fault
447 CacheUnit::read(DynInstPtr inst, Addr addr,
448 uint8_t *data, unsigned size, unsigned flags)
449 {
450 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
451 assert(cache_req && "Can't Find Instruction for Read!");
452
453 // The block size of our peer
454 unsigned blockSize = this->cachePort->peerBlockSize();
455
456 //The size of the data we're trying to read.
457 int fullSize = size;
458 inst->totalSize = size;
459
460 if (inst->traceData) {
461 inst->traceData->setAddr(addr);
462 }
463
464 if (inst->split2ndAccess) {
465 size = inst->split2ndSize;
466 cache_req->splitAccess = true;
467 cache_req->split2ndAccess = true;
468
469 DPRINTF(InOrderCachePort, "[sn:%i] Split Read Access (2 of 2) for "
470 "(%#x, %#x).\n", inst->seqNum, inst->getMemAddr(),
471 inst->split2ndAddr);
472 }
473
474
475 //The address of the second part of this access if it needs to be split
476 //across a cache line boundary.
477 Addr secondAddr = roundDown(addr + size - 1, blockSize);
478
479
480 if (secondAddr > addr && !inst->split2ndAccess) {
481 DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (1 of 2) for "
482 "(%#x, %#x).\n", curTick(), inst->seqNum, addr, secondAddr);
483
484 // Save All "Total" Split Information
485 // ==============================
486 inst->splitInst = true;
487 inst->splitMemData = new uint8_t[size];
488
489 if (!inst->splitInstSked) {
490 assert(0 && "Split Requests Not Supported for Now...");
491
492 // Schedule Split Read/Complete for Instruction
493 // ==============================
494 int stage_num = cache_req->getStageNum();
495
496 int stage_pri = ThePipeline::getNextPriority(inst, stage_num);
497
498 int isplit_cmd = CacheUnit::InitSecondSplitRead;
499 inst->resSched.push(new
500 ScheduleEntry(stage_num,
501 stage_pri,
502 cpu->resPool->getResIdx(DCache),
503 isplit_cmd,
504 1));
505
506 int csplit_cmd = CacheUnit::CompleteSecondSplitRead;
507 inst->resSched.push(new
508 ScheduleEntry(stage_num + 1,
509 1/*stage_pri*/,
510 cpu->resPool->getResIdx(DCache),
511 csplit_cmd,
512 1));
513 inst->splitInstSked = true;
514 } else {
515 DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] Retrying Split Read "
516 "Access (1 of 2) for (%#x, %#x).\n", inst->readTid(),
517 inst->seqNum, addr, secondAddr);
518 }
519
520 // Split Information for First Access
521 // ==============================
522 size = secondAddr - addr;
523 cache_req->splitAccess = true;
524
525 // Split Information for Second Access
526 // ==============================
527 inst->split2ndSize = addr + fullSize - secondAddr;
528 inst->split2ndAddr = secondAddr;
529 inst->split2ndDataPtr = inst->splitMemData + size;
530 inst->split2ndFlags = flags;
531 }
532
533 doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Read);
534
535 if (inst->fault == NoFault) {
536 if (!cache_req->splitAccess) {
537 cache_req->reqData = new uint8_t[size];
538 doCacheAccess(inst, NULL);
539 } else {
540 if (!inst->split2ndAccess) {
541 cache_req->reqData = inst->splitMemData;
542 } else {
543 cache_req->reqData = inst->split2ndDataPtr;
544 }
545
546 doCacheAccess(inst, NULL, cache_req);
547 }
548 }
549
550 return inst->fault;
551 }
552
553 Fault
554 CacheUnit::write(DynInstPtr inst, uint8_t *data, unsigned size,
555 Addr addr, unsigned flags, uint64_t *write_res)
556 {
557 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
558 assert(cache_req && "Can't Find Instruction for Write!");
559
560 // The block size of our peer
561 unsigned blockSize = this->cachePort->peerBlockSize();
562
563 //The size of the data we're trying to write.
564 int fullSize = size;
565 inst->totalSize = size;
566
567 if (inst->traceData) {
568 inst->traceData->setAddr(addr);
569 }
570
571 if (inst->split2ndAccess) {
572 size = inst->split2ndSize;
573 cache_req->splitAccess = true;
574 cache_req->split2ndAccess = true;
575
576 DPRINTF(InOrderCachePort, "[sn:%i] Split Write Access (2 of 2) for "
577 "(%#x, %#x).\n", inst->seqNum, inst->getMemAddr(),
578 inst->split2ndAddr);
579 }
580
581 //The address of the second part of this access if it needs to be split
582 //across a cache line boundary.
583 Addr secondAddr = roundDown(addr + size - 1, blockSize);
584
585 if (secondAddr > addr && !inst->split2ndAccess) {
586
587 DPRINTF(InOrderCachePort, "[sn:%i] Split Write Access (1 of 2) for "
588 "(%#x, %#x).\n", inst->seqNum, addr, secondAddr);
589
590 // Save All "Total" Split Information
591 // ==============================
592 inst->splitInst = true;
593
594 if (!inst->splitInstSked) {
595 assert(0 && "Split Requests Not Supported for Now...");
596
597 // Schedule Split Read/Complete for Instruction
598 // ==============================
599 int stage_num = cache_req->getStageNum();
600
601 int stage_pri = ThePipeline::getNextPriority(inst, stage_num);
602
603 int isplit_cmd = CacheUnit::InitSecondSplitWrite;
604 inst->resSched.push(new
605 ScheduleEntry(stage_num,
606 stage_pri,
607 cpu->resPool->getResIdx(DCache),
608 isplit_cmd,
609 1));
610
611 int csplit_cmd = CacheUnit::CompleteSecondSplitWrite;
612 inst->resSched.push(new
613 ScheduleEntry(stage_num + 1,
614 1/*stage_pri*/,
615 cpu->resPool->getResIdx(DCache),
616 csplit_cmd,
617 1));
618 inst->splitInstSked = true;
619 } else {
620 DPRINTF(InOrderCachePort, "[tid:%i] sn:%i] Retrying Split Read "
621 "Access (1 of 2) for (%#x, %#x).\n",
622 inst->readTid(), inst->seqNum, addr, secondAddr);
623 }
624
625
626
627 // Split Information for First Access
628 // ==============================
629 size = secondAddr - addr;
630 cache_req->splitAccess = true;
631
632 // Split Information for Second Access
633 // ==============================
634 inst->split2ndSize = addr + fullSize - secondAddr;
635 inst->split2ndAddr = secondAddr;
636 inst->split2ndStoreDataPtr = &cache_req->inst->storeData;
637 inst->split2ndStoreDataPtr += size;
638 inst->split2ndFlags = flags;
639 inst->splitInstSked = true;
640 }
641
642 doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Write);
643
644 if (inst->fault == NoFault) {
645 if (!cache_req->splitAccess) {
646 // Remove this line since storeData is saved in INST?
647 cache_req->reqData = new uint8_t[size];
648 doCacheAccess(inst, write_res);
649 } else {
650 doCacheAccess(inst, write_res, cache_req);
651 }
652
653 }
654
655 return inst->fault;
656 }
657
658
659 void
660 CacheUnit::execute(int slot_num)
661 {
662 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
663 assert(cache_req);
664
665 if (cachePortBlocked) {
666 DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
667 cache_req->setCompleted(false);
668 return;
669 }
670
671
672 DynInstPtr inst = cache_req->inst;
673 #if TRACING_ON
674 ThreadID tid = inst->readTid();
675 std::string acc_type = "write";
676 #endif
677
678 inst->fault = NoFault;
679
680 switch (cache_req->cmd)
681 {
682
683 case InitiateReadData:
684 #if TRACING_ON
685 acc_type = "read";
686 #endif
687 case InitiateWriteData:
688
689 DPRINTF(InOrderCachePort,
690 "[tid:%u]: [sn:%i] Initiating data %s access to %s for "
691 "addr. %08p\n", tid, inst->seqNum, acc_type, name(),
692 cache_req->inst->getMemAddr());
693
694 inst->setCurResSlot(slot_num);
695
696 if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
697 inst->execute();
698 } else {
699 inst->initiateAcc();
700 }
701
702 break;
703
704 case InitSecondSplitRead:
705 DPRINTF(InOrderCachePort,
706 "[tid:%u]: [sn:%i] Initiating split data read access to %s "
707 "for addr. %08p\n", tid, inst->seqNum, name(),
708 cache_req->inst->split2ndAddr);
709 inst->split2ndAccess = true;
710 assert(inst->split2ndAddr != 0);
711 read(inst, inst->split2ndAddr, &inst->split2ndData,
712 inst->totalSize, inst->split2ndFlags);
713 break;
714
715 case InitSecondSplitWrite:
716 DPRINTF(InOrderCachePort,
717 "[tid:%u]: [sn:%i] Initiating split data write access to %s "
718 "for addr. %08p\n", tid, inst->seqNum, name(),
719 cache_req->inst->getMemAddr());
720
721 inst->split2ndAccess = true;
722 assert(inst->split2ndAddr != 0);
723 write(inst, &inst->split2ndData, inst->totalSize,
724 inst->split2ndAddr, inst->split2ndFlags, NULL);
725 break;
726
727 case CompleteReadData:
728 case CompleteWriteData:
729 DPRINTF(InOrderCachePort,
730 "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
731 tid, inst->seqNum);
732
733 if (cache_req->isMemAccComplete() ||
734 inst->isDataPrefetch() ||
735 inst->isInstPrefetch()) {
736 removeAddrDependency(inst);
737 cache_req->setMemStall(false);
738 cache_req->done();
739 } else {
740 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
741 tid, cache_req->inst->getMemAddr());
742 cache_req->setCompleted(false);
743 cache_req->setMemStall(true);
744 }
745 break;
746
747 case CompleteSecondSplitRead:
748 DPRINTF(InOrderCachePort,
749 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read "
750 "Access\n", tid, inst->seqNum);
751
752 if (cache_req->isMemAccComplete() ||
753 inst->isDataPrefetch() ||
754 inst->isInstPrefetch()) {
755 removeAddrDependency(inst);
756 cache_req->setMemStall(false);
757 cache_req->done();
758 } else {
759 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
760 tid, cache_req->inst->split2ndAddr);
761 cache_req->setCompleted(false);
762 cache_req->setMemStall(true);
763 }
764 break;
765
766 case CompleteSecondSplitWrite:
767 DPRINTF(InOrderCachePort,
768 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write "
769 "Access\n", tid, inst->seqNum);
770
771 if (cache_req->isMemAccComplete() ||
772 inst->isDataPrefetch() ||
773 inst->isInstPrefetch()) {
774 removeAddrDependency(inst);
775 cache_req->setMemStall(false);
776 cache_req->done();
777 } else {
778 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
779 tid, cache_req->inst->split2ndAddr);
780 cache_req->setCompleted(false);
781 cache_req->setMemStall(true);
782 }
783 break;
784
785 default:
786 fatal("Unrecognized command to %s", resName);
787 }
788 }
789
790 // @TODO: Split into doCacheRead() and doCacheWrite()
791 void
792 CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res,
793 CacheReqPtr split_req)
794 {
795 Fault fault = NoFault;
796 #if TRACING_ON
797 ThreadID tid = inst->readTid();
798 #endif
799
800 CacheReqPtr cache_req;
801
802 if (split_req == NULL) {
803 cache_req = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
804 } else{
805 cache_req = split_req;
806 }
807
808 assert(cache_req);
809
810 // Check for LL/SC and if so change command
811 if (cache_req->memReq->isLLSC() && cache_req->pktCmd == MemCmd::ReadReq) {
812 cache_req->pktCmd = MemCmd::LoadLockedReq;
813 }
814
815 if (cache_req->pktCmd == MemCmd::WriteReq) {
816 cache_req->pktCmd =
817 cache_req->memReq->isSwap() ? MemCmd::SwapReq :
818 (cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq
819 : MemCmd::WriteReq);
820 }
821
822 cache_req->dataPkt = new CacheReqPacket(cache_req,
823 cache_req->pktCmd,
824 Packet::Broadcast,
825 cache_req->instIdx);
826
827 if (cache_req->dataPkt->isRead()) {
828 cache_req->dataPkt->dataStatic(cache_req->reqData);
829 } else if (cache_req->dataPkt->isWrite()) {
830 if (inst->split2ndAccess) {
831 cache_req->dataPkt->dataStatic(inst->split2ndStoreDataPtr);
832 } else {
833 cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
834 }
835
836 if (cache_req->memReq->isCondSwap()) {
837 assert(write_res);
838 cache_req->memReq->setExtraData(*write_res);
839 }
840 }
841
842 bool do_access = true; // flag to suppress cache access
843
844 Request *memReq = cache_req->dataPkt->req;
845
846 if (cache_req->dataPkt->isWrite() && cache_req->memReq->isLLSC()) {
847 assert(cache_req->inst->isStoreConditional());
848 DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
849 do_access = TheISA::handleLockedWrite(cpu, memReq);
850 }
851
852 DPRINTF(InOrderCachePort,
853 "[tid:%i] [sn:%i] attempting to access cache for addr %08p\n",
854 tid, inst->seqNum, cache_req->dataPkt->getAddr());
855
856 if (do_access) {
857 if (!cachePort->sendTiming(cache_req->dataPkt)) {
858 DPRINTF(InOrderCachePort,
859 "[tid:%i] [sn:%i] cannot access cache, because port "
860 "is blocked. now waiting to retry request\n", tid,
861 inst->seqNum);
862 cache_req->setCompleted(false);
863 cachePortBlocked = true;
864 } else {
865 DPRINTF(InOrderCachePort,
866 "[tid:%i] [sn:%i] is now waiting for cache response\n",
867 tid, inst->seqNum);
868 cache_req->setCompleted();
869 cache_req->setMemAccPending();
870 cachePortBlocked = false;
871 }
872 } else if (!do_access && memReq->isLLSC()){
873 // Store-Conditional instructions complete even if they "failed"
874 assert(cache_req->inst->isStoreConditional());
875 cache_req->setCompleted(true);
876
877 DPRINTF(LLSC,
878 "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
879 tid, tid);
880
881 processCacheCompletion(cache_req->dataPkt);
882 } else {
883 // Make cache request again since access due to
884 // inability to access
885 DPRINTF(InOrderStall, "STALL: \n");
886 cache_req->setCompleted(false);
887 }
888
889 }
890
891 void
892 CacheUnit::processCacheCompletion(PacketPtr pkt)
893 {
894 // Cast to correct packet type
895 CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
896
897 assert(cache_pkt);
898
899 if (cache_pkt->cacheReq->isSquashed()) {
900 DPRINTF(InOrderCachePort,
901 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
902 cache_pkt->cacheReq->getInst()->readTid(),
903 cache_pkt->cacheReq->getInst()->seqNum);
904 DPRINTF(RefCount,
905 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
906 cache_pkt->cacheReq->getTid(),
907 cache_pkt->cacheReq->seqNum);
908
909 cache_pkt->cacheReq->done();
910 delete cache_pkt;
911
912 cpu->wakeCPU();
913
914 return;
915 }
916
917 DPRINTF(InOrderCachePort,
918 "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n",
919 cache_pkt->cacheReq->getInst()->readTid(),
920 cache_pkt->cacheReq->getInst()->seqNum,
921 cache_pkt->cacheReq->getInst()->getMemAddr());
922
923 // Cast to correct request type
924 CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
925 findRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx));
926
927 if (!cache_req) {
928 panic("[tid:%u]: [sn:%i]: Can't find slot for cache access to "
929 "addr. %08p\n", cache_pkt->cacheReq->getInst()->readTid(),
930 cache_pkt->cacheReq->getInst()->seqNum,
931 cache_pkt->cacheReq->getInst()->getMemAddr());
932 }
933
934 assert(cache_req);
935
936
937 // Get resource request info
938 unsigned stage_num = cache_req->getStageNum();
939 DynInstPtr inst = cache_req->inst;
940 ThreadID tid = cache_req->inst->readTid();
941
942 if (!cache_req->isSquashed()) {
943 if (inst->staticInst && inst->isMemRef()) {
944 DPRINTF(InOrderCachePort,
945 "[tid:%u]: [sn:%i]: Processing cache access\n",
946 tid, inst->seqNum);
947 PacketPtr dataPkt = NULL;
948
949 if (inst->splitInst) {
950 inst->splitFinishCnt++;
951
952 if (inst->splitFinishCnt == 2) {
953 cache_req->memReq->setVirt(0/*inst->tid*/,
954 inst->getMemAddr(),
955 inst->totalSize,
956 0,
957 0);
958
959 Packet split_pkt(cache_req->memReq, cache_req->pktCmd,
960 Packet::Broadcast);
961
962
963 if (inst->isLoad()) {
964 split_pkt.dataStatic(inst->splitMemData);
965 } else {
966 split_pkt.dataStatic(&inst->storeData);
967 }
968
969 dataPkt = &split_pkt;
970 }
971 } else {
972 dataPkt = pkt;
973 }
974 inst->completeAcc(dataPkt);
975
976 if (inst->isLoad()) {
977 assert(cache_pkt->isRead());
978
979 if (cache_pkt->req->isLLSC()) {
980 DPRINTF(InOrderCachePort,
981 "[tid:%u]: Handling Load-Linked for [sn:%u]\n",
982 tid, inst->seqNum);
983 TheISA::handleLockedRead(cpu, cache_pkt->req);
984 }
985
986 DPRINTF(InOrderCachePort,
987 "[tid:%u]: [sn:%i]: Bytes loaded were: %s\n",
988 tid, inst->seqNum,
989 printMemData(dataPkt->getPtr<uint8_t>(),
990 dataPkt->getSize()));
991 } else if(inst->isStore()) {
992 assert(cache_pkt->isWrite());
993
994 DPRINTF(InOrderCachePort,
995 "[tid:%u]: [sn:%i]: Bytes stored were: %s\n",
996 tid, inst->seqNum,
997 printMemData(dataPkt->getPtr<uint8_t>(),
998 dataPkt->getSize()));
999 }
1000
1001 delete cache_pkt;
1002 }
1003
1004 cache_req->setMemAccPending(false);
1005 cache_req->setMemAccCompleted();
1006
1007 if (cache_req->isMemStall() &&
1008 cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
1009 DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n",
1010 tid);
1011
1012 cpu->activateContext(tid);
1013
1014 DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
1015 "miss.\n", tid);
1016 }
1017
1018 // Wake up the CPU (if it went to sleep and was waiting on this
1019 // completion event).
1020 cpu->wakeCPU();
1021
1022 DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
1023 tid, cpu->pipelineStage[stage_num]->name());
1024
1025 cpu->switchToActive(stage_num);
1026 } else {
1027 DPRINTF(InOrderCachePort,
1028 "[tid:%u] Miss on block @ %08p completed, but squashed\n",
1029 tid, cache_req->inst->instAddr());
1030 cache_req->setMemAccCompleted();
1031 }
1032 }
1033
1034 void
1035 CacheUnit::recvRetry()
1036 {
1037 DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n");
1038
1039 assert(cachePortBlocked);
1040
1041 // Clear the cache port for use again
1042 cachePortBlocked = false;
1043
1044 cpu->wakeCPU();
1045 }
1046
1047 CacheUnitEvent::CacheUnitEvent()
1048 : ResourceEvent()
1049 { }
1050
1051 void
1052 CacheUnitEvent::process()
1053 {
1054 DynInstPtr inst = resource->reqMap[slotIdx]->inst;
1055 int stage_num = resource->reqMap[slotIdx]->getStageNum();
1056 ThreadID tid = inst->threadNumber;
1057 CacheReqPtr req_ptr = dynamic_cast<CacheReqPtr>(resource->reqMap[slotIdx]);
1058
1059 DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
1060 inst->seqNum);
1061
1062 CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource);
1063 assert(tlb_res);
1064
1065 tlb_res->tlbBlocked[tid] = false;
1066
1067 tlb_res->cpu->pipelineStage[stage_num]->
1068 unsetResStall(tlb_res->reqMap[slotIdx], tid);
1069
1070 req_ptr->tlbStall = false;
1071
1072 if (req_ptr->isSquashed()) {
1073 req_ptr->done();
1074 }
1075 }
1076
1077 void
1078 CacheUnit::squashDueToMemStall(DynInstPtr inst, int stage_num,
1079 InstSeqNum squash_seq_num, ThreadID tid)
1080 {
1081 // If squashing due to memory stall, then we do NOT want to
1082 // squash the instruction that caused the stall so we
1083 // increment the sequence number here to prevent that.
1084 //
1085 // NOTE: This is only for the SwitchOnCacheMiss Model
1086 // NOTE: If you have multiple outstanding misses from the same
1087 // thread then you need to reevaluate this code
1088 // NOTE: squash should originate from
1089 // pipeline_stage.cc:processInstSchedule
1090 DPRINTF(InOrderCachePort, "Squashing above [sn:%u]\n",
1091 squash_seq_num + 1);
1092
1093 squash(inst, stage_num, squash_seq_num + 1, tid);
1094 }
1095
1096 void
1097 CacheUnit::squashCacheRequest(CacheReqPtr req_ptr)
1098 {
1099 DynInstPtr inst = req_ptr->getInst();
1100
1101 req_ptr->setSquashed();
1102 inst->setSquashed();
1103 if (inst->validMemAddr()) {
1104 DPRINTF(AddrDep, "Squash of [tid:%i] [sn:%i], attempting to "
1105 "remove addr. %08p dependencies.\n",
1106 inst->readTid(),
1107 inst->seqNum,
1108 inst->getMemAddr());
1109
1110 removeAddrDependency(inst);
1111 }
1112 }
1113
1114
1115 void
1116 CacheUnit::squash(DynInstPtr inst, int stage_num,
1117 InstSeqNum squash_seq_num, ThreadID tid)
1118 {
1119 vector<int> slot_remove_list;
1120
1121 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
1122 map<int, ResReqPtr>::iterator map_end = reqMap.end();
1123
1124 while (map_it != map_end) {
1125 ResReqPtr req_ptr = (*map_it).second;
1126
1127 if (req_ptr &&
1128 req_ptr->getInst()->readTid() == tid &&
1129 req_ptr->getInst()->seqNum > squash_seq_num) {
1130
1131 DPRINTF(InOrderCachePort,
1132 "[tid:%i] Squashing request from [sn:%i]\n",
1133 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
1134
1135 if (req_ptr->isSquashed()) {
1136 DPRINTF(AddrDep, "Request for [tid:%i] [sn:%i] already "
1137 "squashed, ignoring squash process.\n",
1138 req_ptr->getInst()->readTid(),
1139 req_ptr->getInst()->seqNum);
1140 map_it++;
1141 continue;
1142 }
1143
1144 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
1145 assert(cache_req);
1146
1147 squashCacheRequest(cache_req);
1148
1149 int req_slot_num = req_ptr->getSlot();
1150
1151 if (cache_req->tlbStall) {
1152 tlbBlocked[tid] = false;
1153
1154 int stall_stage = reqMap[req_slot_num]->getStageNum();
1155
1156 cpu->pipelineStage[stall_stage]->
1157 unsetResStall(reqMap[req_slot_num], tid);
1158 }
1159
1160 if (!cache_req->tlbStall && !cache_req->isMemAccPending()) {
1161 // Mark request for later removal
1162 cpu->reqRemoveList.push(req_ptr);
1163
1164 // Mark slot for removal from resource
1165 slot_remove_list.push_back(req_ptr->getSlot());
1166 } else {
1167 DPRINTF(InOrderCachePort,
1168 "[tid:%i] Request from [sn:%i] squashed, but still "
1169 "pending completion.\n",
1170 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
1171 DPRINTF(RefCount,
1172 "[tid:%i] Request from [sn:%i] squashed (split:%i), but "
1173 "still pending completion.\n",
1174 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum,
1175 req_ptr->getInst()->splitInst);
1176 }
1177
1178 }
1179
1180 map_it++;
1181 }
1182
1183 // Now Delete Slot Entry from Req. Map
1184 for (int i = 0; i < slot_remove_list.size(); i++)
1185 freeSlot(slot_remove_list[i]);
1186 }
1187