Faults: Pass the StaticInst involved, if any, to a Fault's invoke method.
[gem5.git] / src / cpu / inorder / resources / cache_unit.cc
1 /*
2 * Copyright (c) 2007 MIPS Technologies, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Korey Sewell
29 *
30 */
31
32 #include <vector>
33 #include <list>
34
35 #include "arch/isa_traits.hh"
36 #include "arch/locked_mem.hh"
37 #include "arch/utility.hh"
38 #include "arch/predecoder.hh"
39 #include "config/the_isa.hh"
40 #include "cpu/inorder/resources/cache_unit.hh"
41 #include "cpu/inorder/pipeline_traits.hh"
42 #include "cpu/inorder/cpu.hh"
43 #include "cpu/inorder/resource_pool.hh"
44 #include "mem/request.hh"
45
46 using namespace std;
47 using namespace TheISA;
48 using namespace ThePipeline;
49
50 #if TRACING_ON
51 static std::string
52 printMemData(uint8_t *data, unsigned size)
53 {
54 std::stringstream dataStr;
55 for (unsigned pos = 0; pos < size; pos++) {
56 ccprintf(dataStr, "%02x", data[pos]);
57 }
58 return dataStr.str();
59 }
60 #endif
61
62 Tick
63 CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
64 {
65 panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
66 return curTick;
67 }
68
69 void
70 CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
71 {
72 panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
73 }
74
75 void
76 CacheUnit::CachePort::recvStatusChange(Status status)
77 {
78 if (status == RangeChange)
79 return;
80
81 panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
82 }
83
84 bool
85 CacheUnit::CachePort::recvTiming(Packet *pkt)
86 {
87 cachePortUnit->processCacheCompletion(pkt);
88 return true;
89 }
90
91 void
92 CacheUnit::CachePort::recvRetry()
93 {
94 cachePortUnit->recvRetry();
95 }
96
97 CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
98 int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
99 : Resource(res_name, res_id, res_width, res_latency, _cpu),
100 cachePortBlocked(false), predecoder(NULL)
101 {
102 cachePort = new CachePort(this);
103
104 // Hard-Code Selection For Now
105 if (res_name == "icache_port")
106 _tlb = params->itb;
107 else if (res_name == "dcache_port")
108 _tlb = params->dtb;
109 else
110 fatal("Unrecognized TLB name passed by user");
111
112 for (int i=0; i < MaxThreads; i++) {
113 tlbBlocked[i] = false;
114 }
115 }
116
117 TheISA::TLB*
118 CacheUnit::tlb()
119 {
120 return _tlb;
121
122 }
123
124 Port *
125 CacheUnit::getPort(const string &if_name, int idx)
126 {
127 if (if_name == resName)
128 return cachePort;
129 else
130 return NULL;
131 }
132
133 void
134 CacheUnit::init()
135 {
136 // Currently Used to Model TLB Latency. Eventually
137 // Switch to Timing TLB translations.
138 resourceEvent = new CacheUnitEvent[width];
139
140 initSlots();
141 }
142
143 int
144 CacheUnit::getSlot(DynInstPtr inst)
145 {
146 ThreadID tid = inst->readTid();
147
148 if (tlbBlocked[inst->threadNumber]) {
149 return -1;
150 }
151
152 // For a Split-Load, the instruction would have processed once already
153 // causing the address to be unset.
154 if (!inst->validMemAddr() && !inst->splitInst) {
155 panic("[tid:%i][sn:%i] Mem. Addr. must be set before requesting "
156 "cache access\n", inst->readTid(), inst->seqNum);
157 }
158
159 Addr req_addr = inst->getMemAddr();
160
161 if (resName == "icache_port" ||
162 find(addrList[tid].begin(), addrList[tid].end(), req_addr) ==
163 addrList[tid].end()) {
164
165 int new_slot = Resource::getSlot(inst);
166
167 if (new_slot == -1)
168 return -1;
169
170 inst->memTime = curTick;
171 setAddrDependency(inst);
172 return new_slot;
173 } else {
174 // Allow same instruction multiple accesses to same address
175 // should only happen maybe after a squashed inst. needs to replay
176 if (addrMap[tid][req_addr] == inst->seqNum) {
177 int new_slot = Resource::getSlot(inst);
178
179 if (new_slot == -1)
180 return -1;
181
182 return new_slot;
183 } else {
184 DPRINTF(InOrderCachePort,
185 "[tid:%i] Denying request because there is an outstanding"
186 " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
187 inst->readTid(), req_addr, addrMap[tid][req_addr], inst->memTime);
188 return -1;
189 }
190 }
191
192 return -1;
193 }
194
195 void
196 CacheUnit::setAddrDependency(DynInstPtr inst)
197 {
198 Addr req_addr = inst->getMemAddr();
199 ThreadID tid = inst->readTid();
200
201 addrList[tid].push_back(req_addr);
202 addrMap[tid][req_addr] = inst->seqNum;
203
204 DPRINTF(AddrDep,
205 "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n",
206 inst->readTid(), inst->seqNum, req_addr);
207
208 //@NOTE: 10 is an arbitrarily "high" number here, but to be exact
209 // we would need to know the # of outstanding accesses
210 // a priori. Information like fetch width, stage width,
211 // and the branch resolution stage would be useful for the
212 // icache_port (among other things). For the dcache, the #
213 // of outstanding cache accesses might be sufficient.
214 assert(addrList[tid].size() < 10);
215 }
216
217 void
218 CacheUnit::removeAddrDependency(DynInstPtr inst)
219 {
220 ThreadID tid = inst->readTid();
221
222 Addr mem_addr = inst->getMemAddr();
223
224 inst->unsetMemAddr();
225
226 // Erase from Address List
227 vector<Addr>::iterator vect_it = find(addrList[tid].begin(),
228 addrList[tid].end(),
229 mem_addr);
230 assert(vect_it != addrList[tid].end() || inst->splitInst);
231
232 if (vect_it != addrList[tid].end()) {
233 DPRINTF(AddrDep,
234 "[tid:%i]: [sn:%i] Address %08p removed from dependency "
235 "list\n", inst->readTid(), inst->seqNum, (*vect_it));
236
237 addrList[tid].erase(vect_it);
238
239 // Erase From Address Map (Used for Debugging)
240 addrMap[tid].erase(addrMap[tid].find(mem_addr));
241 }
242
243
244 }
245
246 ResReqPtr
247 CacheUnit::findRequest(DynInstPtr inst)
248 {
249 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
250 map<int, ResReqPtr>::iterator map_end = reqMap.end();
251
252 while (map_it != map_end) {
253 CacheRequest* cache_req =
254 dynamic_cast<CacheRequest*>((*map_it).second);
255 assert(cache_req);
256
257 if (cache_req &&
258 cache_req->getInst() == inst &&
259 cache_req->instIdx == inst->resSched.top()->idx) {
260 return cache_req;
261 }
262 map_it++;
263 }
264
265 return NULL;
266 }
267
268 ResReqPtr
269 CacheUnit::findSplitRequest(DynInstPtr inst, int idx)
270 {
271 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
272 map<int, ResReqPtr>::iterator map_end = reqMap.end();
273
274 while (map_it != map_end) {
275 CacheRequest* cache_req =
276 dynamic_cast<CacheRequest*>((*map_it).second);
277 assert(cache_req);
278
279 if (cache_req &&
280 cache_req->getInst() == inst &&
281 cache_req->instIdx == idx) {
282 return cache_req;
283 }
284 map_it++;
285 }
286
287 return NULL;
288 }
289
290
291 ResReqPtr
292 CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
293 int slot_num, unsigned cmd)
294 {
295 ScheduleEntry* sched_entry = inst->resSched.top();
296
297 if (!inst->validMemAddr()) {
298 panic("Mem. Addr. must be set before requesting cache access\n");
299 }
300
301 MemCmd::Command pkt_cmd;
302
303 switch (sched_entry->cmd)
304 {
305 case InitSecondSplitRead:
306 pkt_cmd = MemCmd::ReadReq;
307
308 DPRINTF(InOrderCachePort,
309 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
310 inst->readTid(), inst->seqNum, inst->split2ndAddr);
311 break;
312
313 case InitiateReadData:
314 pkt_cmd = MemCmd::ReadReq;
315
316 DPRINTF(InOrderCachePort,
317 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
318 inst->readTid(), inst->seqNum, inst->getMemAddr());
319 break;
320
321 case InitSecondSplitWrite:
322 pkt_cmd = MemCmd::WriteReq;
323
324 DPRINTF(InOrderCachePort,
325 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
326 inst->readTid(), inst->seqNum, inst->split2ndAddr);
327 break;
328
329 case InitiateWriteData:
330 pkt_cmd = MemCmd::WriteReq;
331
332 DPRINTF(InOrderCachePort,
333 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
334 inst->readTid(), inst->seqNum, inst->getMemAddr());
335 break;
336
337 case InitiateFetch:
338 pkt_cmd = MemCmd::ReadReq;
339
340 DPRINTF(InOrderCachePort,
341 "[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
342 inst->readTid(), inst->seqNum, inst->getMemAddr());
343 break;
344
345 default:
346 panic("%i: Unexpected request type (%i) to %s", curTick,
347 sched_entry->cmd, name());
348 }
349
350 return new CacheRequest(this, inst, stage_num, id, slot_num,
351 sched_entry->cmd, 0, pkt_cmd,
352 0/*flags*/, this->cpu->readCpuId(),
353 inst->resSched.top()->idx);
354 }
355
356 void
357 CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
358 {
359 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
360 assert(cache_req);
361
362 // Check to see if this instruction is requesting the same command
363 // or a different one
364 if (cache_req->cmd != inst->resSched.top()->cmd &&
365 cache_req->instIdx == inst->resSched.top()->idx) {
366 // If different, then update command in the request
367 cache_req->cmd = inst->resSched.top()->cmd;
368 DPRINTF(InOrderCachePort,
369 "[tid:%i]: [sn:%i]: Updating the command for this "
370 "instruction\n ", inst->readTid(), inst->seqNum);
371
372 service_request = true;
373 } else if (inst->resSched.top()->idx != CacheUnit::InitSecondSplitRead &&
374 inst->resSched.top()->idx != CacheUnit::InitSecondSplitWrite) {
375 // If same command, just check to see if memory access was completed
376 // but dont try to re-execute
377 DPRINTF(InOrderCachePort,
378 "[tid:%i]: [sn:%i]: requesting this resource again\n",
379 inst->readTid(), inst->seqNum);
380
381 service_request = true;
382 }
383 }
384
385 Fault
386 CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
387 int flags, TheISA::TLB::Mode tlb_mode)
388 {
389 ThreadID tid = inst->readTid();
390 Addr aligned_addr = inst->getMemAddr();
391 unsigned stage_num = cache_req->getStageNum();
392 unsigned slot_idx = cache_req->getSlot();
393
394 if (tlb_mode == TheISA::TLB::Execute) {
395 inst->fetchMemReq = new Request(inst->readTid(), aligned_addr,
396 acc_size, flags, inst->readPC(),
397 cpu->readCpuId(), inst->readTid());
398 cache_req->memReq = inst->fetchMemReq;
399 } else {
400 if (!cache_req->is2ndSplit()) {
401 inst->dataMemReq = new Request(cpu->asid[tid], aligned_addr,
402 acc_size, flags, inst->readPC(),
403 cpu->readCpuId(), inst->readTid());
404 cache_req->memReq = inst->dataMemReq;
405 } else {
406 assert(inst->splitInst);
407
408 inst->splitMemReq = new Request(cpu->asid[tid],
409 inst->split2ndAddr,
410 acc_size,
411 flags,
412 inst->readPC(),
413 cpu->readCpuId(),
414 tid);
415 cache_req->memReq = inst->splitMemReq;
416 }
417 }
418
419
420 cache_req->fault =
421 _tlb->translateAtomic(cache_req->memReq,
422 cpu->thread[tid]->getTC(), tlb_mode);
423
424 if (cache_req->fault != NoFault) {
425 DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
426 "addr:%08p for [sn:%i].\n", tid, cache_req->fault->name(),
427 cache_req->memReq->getVaddr(), inst->seqNum);
428
429 cpu->pipelineStage[stage_num]->setResStall(cache_req, tid);
430
431 tlbBlocked[tid] = true;
432
433 cache_req->tlbStall = true;
434
435 scheduleEvent(slot_idx, 1);
436
437 cpu->trap(cache_req->fault, tid, inst);
438 } else {
439 DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
440 "to phys. addr:%08p.\n", tid, inst->seqNum,
441 cache_req->memReq->getVaddr(),
442 cache_req->memReq->getPaddr());
443 }
444
445 return cache_req->fault;
446 }
447
448 Fault
449 CacheUnit::read(DynInstPtr inst, Addr addr,
450 uint8_t *data, unsigned size, unsigned flags)
451 {
452 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
453 assert(cache_req && "Can't Find Instruction for Read!");
454
455 // The block size of our peer
456 unsigned blockSize = this->cachePort->peerBlockSize();
457
458 //The size of the data we're trying to read.
459 int fullSize = size;
460 inst->totalSize = size;
461
462 if (inst->traceData) {
463 inst->traceData->setAddr(addr);
464 }
465
466 if (inst->split2ndAccess) {
467 size = inst->split2ndSize;
468 cache_req->splitAccess = true;
469 cache_req->split2ndAccess = true;
470
471 DPRINTF(InOrderCachePort, "[sn:%i] Split Read Access (2 of 2) for "
472 "(%#x, %#x).\n", inst->seqNum, inst->getMemAddr(),
473 inst->split2ndAddr);
474 }
475
476
477 //The address of the second part of this access if it needs to be split
478 //across a cache line boundary.
479 Addr secondAddr = roundDown(addr + size - 1, blockSize);
480
481
482 if (secondAddr > addr && !inst->split2ndAccess) {
483 DPRINTF(InOrderCachePort, "%i: sn[%i] Split Read Access (1 of 2) for "
484 "(%#x, %#x).\n", curTick, inst->seqNum, addr, secondAddr);
485
486 // Save All "Total" Split Information
487 // ==============================
488 inst->splitInst = true;
489 inst->splitMemData = new uint8_t[size];
490
491 if (!inst->splitInstSked) {
492 // Schedule Split Read/Complete for Instruction
493 // ==============================
494 int stage_num = cache_req->getStageNum();
495
496 int stage_pri = ThePipeline::getNextPriority(inst, stage_num);
497
498 int isplit_cmd = CacheUnit::InitSecondSplitRead;
499 inst->resSched.push(new
500 ScheduleEntry(stage_num,
501 stage_pri,
502 cpu->resPool->getResIdx(DCache),
503 isplit_cmd,
504 1));
505
506 int csplit_cmd = CacheUnit::CompleteSecondSplitRead;
507 inst->resSched.push(new
508 ScheduleEntry(stage_num + 1,
509 1/*stage_pri*/,
510 cpu->resPool->getResIdx(DCache),
511 csplit_cmd,
512 1));
513 inst->splitInstSked = true;
514 } else {
515 DPRINTF(InOrderCachePort, "[tid:%i] [sn:%i] Retrying Split Read "
516 "Access (1 of 2) for (%#x, %#x).\n", inst->readTid(),
517 inst->seqNum, addr, secondAddr);
518 }
519
520 // Split Information for First Access
521 // ==============================
522 size = secondAddr - addr;
523 cache_req->splitAccess = true;
524
525 // Split Information for Second Access
526 // ==============================
527 inst->split2ndSize = addr + fullSize - secondAddr;
528 inst->split2ndAddr = secondAddr;
529 inst->split2ndDataPtr = inst->splitMemData + size;
530 inst->split2ndFlags = flags;
531 }
532
533 doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Read);
534
535 if (cache_req->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 cache_req->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 // Schedule Split Read/Complete for Instruction
596 // ==============================
597 int stage_num = cache_req->getStageNum();
598
599 int stage_pri = ThePipeline::getNextPriority(inst, stage_num);
600
601 int isplit_cmd = CacheUnit::InitSecondSplitWrite;
602 inst->resSched.push(new
603 ScheduleEntry(stage_num,
604 stage_pri,
605 cpu->resPool->getResIdx(DCache),
606 isplit_cmd,
607 1));
608
609 int csplit_cmd = CacheUnit::CompleteSecondSplitWrite;
610 inst->resSched.push(new
611 ScheduleEntry(stage_num + 1,
612 1/*stage_pri*/,
613 cpu->resPool->getResIdx(DCache),
614 csplit_cmd,
615 1));
616 inst->splitInstSked = true;
617 } else {
618 DPRINTF(InOrderCachePort, "[tid:%i] sn:%i] Retrying Split Read "
619 "Access (1 of 2) for (%#x, %#x).\n",
620 inst->readTid(), inst->seqNum, addr, secondAddr);
621 }
622
623
624
625 // Split Information for First Access
626 // ==============================
627 size = secondAddr - addr;
628 cache_req->splitAccess = true;
629
630 // Split Information for Second Access
631 // ==============================
632 inst->split2ndSize = addr + fullSize - secondAddr;
633 inst->split2ndAddr = secondAddr;
634 inst->split2ndStoreDataPtr = &cache_req->inst->storeData;
635 inst->split2ndStoreDataPtr += size;
636 inst->split2ndFlags = flags;
637 inst->splitInstSked = true;
638 }
639
640 doTLBAccess(inst, cache_req, size, flags, TheISA::TLB::Write);
641
642 if (cache_req->fault == NoFault) {
643 if (!cache_req->splitAccess) {
644 // Remove this line since storeData is saved in INST?
645 cache_req->reqData = new uint8_t[size];
646 doCacheAccess(inst, write_res);
647 } else {
648 doCacheAccess(inst, write_res, cache_req);
649 }
650
651 }
652
653 return cache_req->fault;
654 }
655
656
657 void
658 CacheUnit::execute(int slot_num)
659 {
660 if (cachePortBlocked) {
661 DPRINTF(InOrderCachePort, "Cache Port Blocked. Cannot Access\n");
662 return;
663 }
664
665 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
666 assert(cache_req);
667
668 DynInstPtr inst = cache_req->inst;
669 #if TRACING_ON
670 ThreadID tid = inst->readTid();
671 int seq_num = inst->seqNum;
672 std::string acc_type = "write";
673
674 #endif
675
676 cache_req->fault = NoFault;
677
678 switch (cache_req->cmd)
679 {
680 case InitiateFetch:
681 {
682 //@TODO: Switch to size of full cache block. Store in fetch buffer
683 int acc_size = sizeof(TheISA::MachInst);
684
685 doTLBAccess(inst, cache_req, acc_size, 0, TheISA::TLB::Execute);
686
687 // Only Do Access if no fault from TLB
688 if (cache_req->fault == NoFault) {
689
690 DPRINTF(InOrderCachePort,
691 "[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
692 tid, name(), cache_req->inst->getMemAddr());
693
694 cache_req->reqData = new uint8_t[acc_size];
695
696 inst->setCurResSlot(slot_num);
697
698 doCacheAccess(inst);
699 }
700
701 break;
702 }
703
704 case InitiateReadData:
705 #if TRACING_ON
706 acc_type = "read";
707 #endif
708 case InitiateWriteData:
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
749 case CompleteFetch:
750 if (cache_req->isMemAccComplete()) {
751 DPRINTF(InOrderCachePort,
752 "[tid:%i]: Completing Fetch Access for [sn:%i]\n",
753 tid, inst->seqNum);
754
755
756 DPRINTF(InOrderCachePort, "[tid:%i]: Instruction [sn:%i] is: %s\n",
757 tid, seq_num, inst->staticInst->disassemble(inst->PC));
758
759 removeAddrDependency(inst);
760
761 delete cache_req->dataPkt;
762
763 // Do not stall and switch threads for fetch... for now..
764 // TODO: We need to detect cache misses for latencies > 1
765 // cache_req->setMemStall(false);
766
767 cache_req->done();
768 } else {
769 DPRINTF(InOrderCachePort,
770 "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n",
771 tid, inst->seqNum);
772 DPRINTF(InOrderStall,
773 "STALL: [tid:%i]: Fetch miss from %08p\n",
774 tid, cache_req->inst->readPC());
775 cache_req->setCompleted(false);
776 //cache_req->setMemStall(true);
777 }
778 break;
779
780 case CompleteReadData:
781 case CompleteWriteData:
782 DPRINTF(InOrderCachePort,
783 "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
784 tid, inst->seqNum);
785
786 if (cache_req->isMemAccComplete() ||
787 inst->isDataPrefetch() ||
788 inst->isInstPrefetch()) {
789 removeAddrDependency(inst);
790 cache_req->setMemStall(false);
791 cache_req->done();
792 } else {
793 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
794 tid, cache_req->inst->getMemAddr());
795 cache_req->setCompleted(false);
796 cache_req->setMemStall(true);
797 }
798 break;
799
800 case CompleteSecondSplitRead:
801 DPRINTF(InOrderCachePort,
802 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read "
803 "Access\n", tid, inst->seqNum);
804
805 if (cache_req->isMemAccComplete() ||
806 inst->isDataPrefetch() ||
807 inst->isInstPrefetch()) {
808 removeAddrDependency(inst);
809 cache_req->setMemStall(false);
810 cache_req->done();
811 } else {
812 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
813 tid, cache_req->inst->split2ndAddr);
814 cache_req->setCompleted(false);
815 cache_req->setMemStall(true);
816 }
817 break;
818
819 case CompleteSecondSplitWrite:
820 DPRINTF(InOrderCachePort,
821 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write "
822 "Access\n", tid, inst->seqNum);
823
824 if (cache_req->isMemAccComplete() ||
825 inst->isDataPrefetch() ||
826 inst->isInstPrefetch()) {
827 removeAddrDependency(inst);
828 cache_req->setMemStall(false);
829 cache_req->done();
830 } else {
831 DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
832 tid, cache_req->inst->split2ndAddr);
833 cache_req->setCompleted(false);
834 cache_req->setMemStall(true);
835 }
836 break;
837
838 default:
839 fatal("Unrecognized command to %s", resName);
840 }
841 }
842
843 void
844 CacheUnit::prefetch(DynInstPtr inst)
845 {
846 warn_once("Prefetching currently unimplemented");
847
848 CacheReqPtr cache_req
849 = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
850 assert(cache_req);
851
852 // Clean-Up cache resource request so
853 // other memory insts. can use them
854 cache_req->setCompleted();
855 cachePortBlocked = false;
856 cache_req->setMemAccPending(false);
857 cache_req->setMemAccCompleted();
858 inst->unsetMemAddr();
859 }
860
861
862 void
863 CacheUnit::writeHint(DynInstPtr inst)
864 {
865 warn_once("Write Hints currently unimplemented");
866
867 CacheReqPtr cache_req
868 = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
869 assert(cache_req);
870
871 // Clean-Up cache resource request so
872 // other memory insts. can use them
873 cache_req->setCompleted();
874 cachePortBlocked = false;
875 cache_req->setMemAccPending(false);
876 cache_req->setMemAccCompleted();
877 inst->unsetMemAddr();
878 }
879
880 // @TODO: Split into doCacheRead() and doCacheWrite()
881 Fault
882 CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res,
883 CacheReqPtr split_req)
884 {
885 Fault fault = NoFault;
886 #if TRACING_ON
887 ThreadID tid = inst->readTid();
888 #endif
889
890 CacheReqPtr cache_req;
891
892 if (split_req == NULL) {
893 cache_req = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
894 } else{
895 cache_req = split_req;
896 }
897
898 assert(cache_req);
899
900 // Check for LL/SC and if so change command
901 if (cache_req->memReq->isLLSC() && cache_req->pktCmd == MemCmd::ReadReq) {
902 cache_req->pktCmd = MemCmd::LoadLockedReq;
903 }
904
905 if (cache_req->pktCmd == MemCmd::WriteReq) {
906 cache_req->pktCmd =
907 cache_req->memReq->isSwap() ? MemCmd::SwapReq :
908 (cache_req->memReq->isLLSC() ? MemCmd::StoreCondReq
909 : MemCmd::WriteReq);
910 }
911
912 cache_req->dataPkt = new CacheReqPacket(cache_req,
913 cache_req->pktCmd,
914 Packet::Broadcast,
915 cache_req->instIdx);
916
917 if (cache_req->dataPkt->isRead()) {
918 cache_req->dataPkt->dataStatic(cache_req->reqData);
919 } else if (cache_req->dataPkt->isWrite()) {
920 if (inst->split2ndAccess) {
921 cache_req->dataPkt->dataStatic(inst->split2ndStoreDataPtr);
922 } else {
923 cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
924 }
925
926 if (cache_req->memReq->isCondSwap()) {
927 assert(write_res);
928 cache_req->memReq->setExtraData(*write_res);
929 }
930 }
931
932 bool do_access = true; // flag to suppress cache access
933
934 Request *memReq = cache_req->dataPkt->req;
935
936 if (cache_req->dataPkt->isWrite() && cache_req->memReq->isLLSC()) {
937 assert(cache_req->inst->isStoreConditional());
938 DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
939 do_access = TheISA::handleLockedWrite(cpu, memReq);
940 }
941
942 DPRINTF(InOrderCachePort,
943 "[tid:%i] [sn:%i] attempting to access cache\n",
944 tid, inst->seqNum);
945
946 if (do_access) {
947 if (!cachePort->sendTiming(cache_req->dataPkt)) {
948 DPRINTF(InOrderCachePort,
949 "[tid:%i] [sn:%i] cannot access cache, because port "
950 "is blocked. now waiting to retry request\n", tid,
951 inst->seqNum);
952 cache_req->setCompleted(false);
953 cachePortBlocked = true;
954 } else {
955 DPRINTF(InOrderCachePort,
956 "[tid:%i] [sn:%i] is now waiting for cache response\n",
957 tid, inst->seqNum);
958 cache_req->setCompleted();
959 cache_req->setMemAccPending();
960 cachePortBlocked = false;
961 }
962 } else if (!do_access && memReq->isLLSC()){
963 // Store-Conditional instructions complete even if they "failed"
964 assert(cache_req->inst->isStoreConditional());
965 cache_req->setCompleted(true);
966
967 DPRINTF(LLSC,
968 "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
969 tid, tid);
970
971 processCacheCompletion(cache_req->dataPkt);
972 } else {
973 // Make cache request again since access due to
974 // inability to access
975 DPRINTF(InOrderStall, "STALL: \n");
976 cache_req->setCompleted(false);
977 }
978
979 return fault;
980 }
981
982 void
983 CacheUnit::processCacheCompletion(PacketPtr pkt)
984 {
985 // Cast to correct packet type
986 CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
987
988 assert(cache_pkt);
989
990 if (cache_pkt->cacheReq->isSquashed()) {
991 DPRINTF(InOrderCachePort,
992 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
993 cache_pkt->cacheReq->getInst()->readTid(),
994 cache_pkt->cacheReq->getInst()->seqNum);
995 DPRINTF(RefCount,
996 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
997 cache_pkt->cacheReq->getTid(),
998 cache_pkt->cacheReq->seqNum);
999
1000 cache_pkt->cacheReq->done();
1001 delete cache_pkt;
1002
1003 cpu->wakeCPU();
1004
1005 return;
1006 }
1007
1008 DPRINTF(InOrderCachePort,
1009 "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n",
1010 cache_pkt->cacheReq->getInst()->readTid(),
1011 cache_pkt->cacheReq->getInst()->seqNum,
1012 cache_pkt->cacheReq->getInst()->getMemAddr());
1013
1014 // Cast to correct request type
1015 CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
1016 findSplitRequest(cache_pkt->cacheReq->getInst(), cache_pkt->instIdx));
1017
1018 if (!cache_req) {
1019 panic("[tid:%u]: [sn:%i]: Can't find slot for cache access to "
1020 "addr. %08p\n", cache_pkt->cacheReq->getInst()->readTid(),
1021 cache_pkt->cacheReq->getInst()->seqNum,
1022 cache_pkt->cacheReq->getInst()->getMemAddr());
1023 }
1024
1025 assert(cache_req);
1026
1027
1028 // Get resource request info
1029 unsigned stage_num = cache_req->getStageNum();
1030 DynInstPtr inst = cache_req->inst;
1031 ThreadID tid = cache_req->inst->readTid();
1032
1033 if (!cache_req->isSquashed()) {
1034 if (inst->resSched.top()->cmd == CompleteFetch) {
1035 DPRINTF(InOrderCachePort,
1036 "[tid:%u]: [sn:%i]: Processing fetch access\n",
1037 tid, inst->seqNum);
1038
1039 // NOTE: This is only allowing a thread to fetch one line
1040 // at a time. Re-examine when/if prefetching
1041 // gets implemented.
1042 //memcpy(fetchData[tid], cache_pkt->getPtr<uint8_t>(),
1043 // cache_pkt->getSize());
1044
1045 // Get the instruction from the array of the cache line.
1046 // @todo: update thsi
1047 ExtMachInst ext_inst;
1048 StaticInstPtr staticInst = NULL;
1049 Addr inst_pc = inst->readPC();
1050 MachInst mach_inst =
1051 TheISA::gtoh(*reinterpret_cast<TheISA::MachInst *>
1052 (cache_pkt->getPtr<uint8_t>()));
1053
1054 predecoder.setTC(cpu->thread[tid]->getTC());
1055 predecoder.moreBytes(inst_pc, inst_pc, mach_inst);
1056 ext_inst = predecoder.getExtMachInst();
1057
1058 inst->setMachInst(ext_inst);
1059
1060 // Set Up More TraceData info
1061 if (inst->traceData) {
1062 inst->traceData->setStaticInst(inst->staticInst);
1063 inst->traceData->setPC(inst->readPC());
1064 }
1065
1066 } else if (inst->staticInst && inst->isMemRef()) {
1067 DPRINTF(InOrderCachePort,
1068 "[tid:%u]: [sn:%i]: Processing cache access\n",
1069 tid, inst->seqNum);
1070 PacketPtr dataPkt = NULL;
1071
1072 if (inst->splitInst) {
1073 inst->splitFinishCnt++;
1074
1075 if (inst->splitFinishCnt == 2) {
1076 cache_req->memReq->setVirt(0/*inst->tid*/,
1077 inst->getMemAddr(),
1078 inst->totalSize,
1079 0,
1080 0);
1081
1082 Packet split_pkt(cache_req->memReq, cache_req->pktCmd,
1083 Packet::Broadcast);
1084
1085
1086 if (inst->isLoad()) {
1087 split_pkt.dataStatic(inst->splitMemData);
1088 } else {
1089 split_pkt.dataStatic(&inst->storeData);
1090 }
1091
1092 dataPkt = &split_pkt;
1093 }
1094 } else {
1095 dataPkt = pkt;
1096 }
1097 inst->completeAcc(dataPkt);
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(cpu, cache_pkt->req);
1107 }
1108
1109 DPRINTF(InOrderCachePort,
1110 "[tid:%u]: [sn:%i]: Bytes loaded were: %s\n",
1111 tid, inst->seqNum,
1112 printMemData(dataPkt->getPtr<uint8_t>(),
1113 dataPkt->getSize()));
1114 } else if(inst->isStore()) {
1115 assert(cache_pkt->isWrite());
1116
1117 DPRINTF(InOrderCachePort,
1118 "[tid:%u]: [sn:%i]: Bytes stored were: %s\n",
1119 tid, inst->seqNum,
1120 printMemData(dataPkt->getPtr<uint8_t>(),
1121 dataPkt->getSize()));
1122 }
1123
1124 delete cache_pkt;
1125 }
1126
1127 cache_req->setMemAccPending(false);
1128 cache_req->setMemAccCompleted();
1129
1130 if (cache_req->isMemStall() &&
1131 cpu->threadModel == InOrderCPU::SwitchOnCacheMiss) {
1132 DPRINTF(InOrderCachePort, "[tid:%u] Waking up from Cache Miss.\n",
1133 tid);
1134
1135 cpu->activateContext(tid);
1136
1137 DPRINTF(ThreadModel, "Activating [tid:%i] after return from cache"
1138 "miss.\n", tid);
1139 }
1140
1141 // Wake up the CPU (if it went to sleep and was waiting on this
1142 // completion event).
1143 cpu->wakeCPU();
1144
1145 DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
1146 tid, cpu->pipelineStage[stage_num]->name());
1147
1148 cpu->switchToActive(stage_num);
1149 } else {
1150 DPRINTF(InOrderCachePort,
1151 "[tid:%u] Miss on block @ %08p completed, but squashed\n",
1152 tid, cache_req->inst->readPC());
1153 cache_req->setMemAccCompleted();
1154 }
1155 }
1156
1157 void
1158 CacheUnit::recvRetry()
1159 {
1160 DPRINTF(InOrderCachePort, "Unblocking Cache Port. \n");
1161
1162 assert(cachePortBlocked);
1163
1164 // Clear the cache port for use again
1165 cachePortBlocked = false;
1166
1167 cpu->wakeCPU();
1168 }
1169
1170 CacheUnitEvent::CacheUnitEvent()
1171 : ResourceEvent()
1172 { }
1173
1174 void
1175 CacheUnitEvent::process()
1176 {
1177 DynInstPtr inst = resource->reqMap[slotIdx]->inst;
1178 int stage_num = resource->reqMap[slotIdx]->getStageNum();
1179 ThreadID tid = inst->threadNumber;
1180 CacheReqPtr req_ptr = dynamic_cast<CacheReqPtr>(resource->reqMap[slotIdx]);
1181
1182 DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
1183 inst->seqNum);
1184
1185 CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource);
1186 assert(tlb_res);
1187
1188 tlb_res->tlbBlocked[tid] = false;
1189
1190 tlb_res->cpu->pipelineStage[stage_num]->
1191 unsetResStall(tlb_res->reqMap[slotIdx], tid);
1192
1193 req_ptr->tlbStall = false;
1194
1195 if (req_ptr->isSquashed()) {
1196 req_ptr->done();
1197 }
1198 }
1199
1200 void
1201 CacheUnit::squashDueToMemStall(DynInstPtr inst, int stage_num,
1202 InstSeqNum squash_seq_num, ThreadID tid)
1203 {
1204 // If squashing due to memory stall, then we do NOT want to
1205 // squash the instruction that caused the stall so we
1206 // increment the sequence number here to prevent that.
1207 //
1208 // NOTE: This is only for the SwitchOnCacheMiss Model
1209 // NOTE: If you have multiple outstanding misses from the same
1210 // thread then you need to reevaluate this code
1211 // NOTE: squash should originate from
1212 // pipeline_stage.cc:processInstSchedule
1213 DPRINTF(InOrderCachePort, "Squashing above [sn:%u]\n",
1214 squash_seq_num + 1);
1215
1216 squash(inst, stage_num, squash_seq_num + 1, tid);
1217 }
1218
1219
1220 void
1221 CacheUnit::squash(DynInstPtr inst, int stage_num,
1222 InstSeqNum squash_seq_num, ThreadID tid)
1223 {
1224 vector<int> slot_remove_list;
1225
1226 map<int, ResReqPtr>::iterator map_it = reqMap.begin();
1227 map<int, ResReqPtr>::iterator map_end = reqMap.end();
1228
1229 while (map_it != map_end) {
1230 ResReqPtr req_ptr = (*map_it).second;
1231
1232 if (req_ptr &&
1233 req_ptr->getInst()->readTid() == tid &&
1234 req_ptr->getInst()->seqNum > squash_seq_num) {
1235
1236 DPRINTF(InOrderCachePort,
1237 "[tid:%i] Squashing request from [sn:%i]\n",
1238 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
1239
1240 if (req_ptr->isSquashed()) {
1241 DPRINTF(AddrDep, "Request for [tid:%i] [sn:%i] already "
1242 "squashed, ignoring squash process.\n",
1243 req_ptr->getInst()->readTid(),
1244 req_ptr->getInst()->seqNum);
1245 map_it++;
1246 continue;
1247 }
1248
1249 req_ptr->setSquashed();
1250
1251 req_ptr->getInst()->setSquashed();
1252
1253 CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
1254 assert(cache_req);
1255
1256 int req_slot_num = req_ptr->getSlot();
1257
1258 if (cache_req->tlbStall) {
1259 tlbBlocked[tid] = false;
1260
1261 int stall_stage = reqMap[req_slot_num]->getStageNum();
1262
1263 cpu->pipelineStage[stall_stage]->
1264 unsetResStall(reqMap[req_slot_num], tid);
1265 }
1266
1267 if (!cache_req->tlbStall && !cache_req->isMemAccPending()) {
1268 // Mark request for later removal
1269 cpu->reqRemoveList.push(req_ptr);
1270
1271 // Mark slot for removal from resource
1272 slot_remove_list.push_back(req_ptr->getSlot());
1273 } else {
1274 DPRINTF(InOrderCachePort,
1275 "[tid:%i] Request from [sn:%i] squashed, but still "
1276 "pending completion.\n",
1277 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
1278 DPRINTF(RefCount,
1279 "[tid:%i] Request from [sn:%i] squashed (split:%i), but "
1280 "still pending completion.\n",
1281 req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum,
1282 req_ptr->getInst()->splitInst);
1283 }
1284
1285 if (req_ptr->getInst()->validMemAddr()) {
1286 DPRINTF(AddrDep, "Squash of [tid:%i] [sn:%i], attempting to "
1287 "remove addr. %08p dependencies.\n",
1288 req_ptr->getInst()->readTid(),
1289 req_ptr->getInst()->seqNum,
1290 req_ptr->getInst()->getMemAddr());
1291
1292 removeAddrDependency(req_ptr->getInst());
1293 }
1294 }
1295
1296 map_it++;
1297 }
1298
1299 // Now Delete Slot Entry from Req. Map
1300 for (int i = 0; i < slot_remove_list.size(); i++)
1301 freeSlot(slot_remove_list[i]);
1302 }
1303