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