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