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