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