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