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