2 * Copyright (c) 2007 MIPS Technologies, Inc.
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.
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.
28 * Authors: Korey Sewell
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"
55 using namespace TheISA
;
56 using namespace ThePipeline
;
60 printMemData(uint8_t *data
, unsigned size
)
62 std::stringstream dataStr
;
63 for (unsigned pos
= 0; pos
< size
; pos
++) {
64 ccprintf(dataStr
, "%02x", data
[pos
]);
71 CacheUnit::CachePort::recvAtomic(PacketPtr pkt
)
73 panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
78 CacheUnit::CachePort::recvFunctional(PacketPtr pkt
)
80 panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
84 CacheUnit::CachePort::recvStatusChange(Status status
)
86 if (status
== RangeChange
)
89 panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
93 CacheUnit::CachePort::recvTiming(Packet
*pkt
)
95 cachePortUnit
->processCacheCompletion(pkt
);
100 CacheUnit::CachePort::recvRetry()
102 cachePortUnit
->recvRetry();
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)
110 cachePort
= new CachePort(this);
112 // Hard-Code Selection For Now
113 if (res_name
== "icache_port")
115 else if (res_name
== "dcache_port")
118 fatal("Unrecognized TLB name passed by user");
120 for (int i
=0; i
< MaxThreads
; i
++) {
121 tlbBlocked
[i
] = false;
133 CacheUnit::getPort(const string
&if_name
, int idx
)
135 if (if_name
== resName
)
144 for (int i
= 0; i
< width
; i
++) {
145 reqs
[i
] = new CacheRequest(this);
148 // Currently Used to Model TLB Latency. Eventually
149 // Switch to Timing TLB translations.
150 resourceEvent
= new CacheUnitEvent
[width
];
152 cacheBlkSize
= this->cachePort
->peerBlockSize();
153 cacheBlkMask
= cacheBlkSize
- 1;
159 CacheUnit::getSlot(DynInstPtr inst
)
161 ThreadID tid
= inst
->readTid();
163 if (tlbBlocked
[inst
->threadNumber
]) {
167 // For a Split-Load, the instruction would have processed once already
168 // causing the address to be unset.
169 if (!inst
->validMemAddr() && !inst
->splitInst
) {
170 panic("[tid:%i][sn:%i] Mem. Addr. must be set before requesting "
171 "cache access\n", inst
->readTid(), inst
->seqNum
);
174 Addr req_addr
= inst
->getMemAddr();
176 if (resName
== "icache_port" ||
177 find(addrList
[tid
].begin(), addrList
[tid
].end(), req_addr
) ==
178 addrList
[tid
].end()) {
180 int new_slot
= Resource::getSlot(inst
);
185 inst
->memTime
= curTick();
186 setAddrDependency(inst
);
189 // Allow same instruction multiple accesses to same address
190 // should only happen maybe after a squashed inst. needs to replay
191 if (addrMap
[tid
][req_addr
] == inst
->seqNum
) {
192 int new_slot
= Resource::getSlot(inst
);
199 DPRINTF(InOrderCachePort
,
200 "[tid:%i] Denying request because there is an outstanding"
201 " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
202 inst
->readTid(), req_addr
, addrMap
[tid
][req_addr
], inst
->memTime
);
211 CacheUnit::setAddrDependency(DynInstPtr inst
)
213 Addr req_addr
= inst
->getMemAddr();
214 ThreadID tid
= inst
->readTid();
216 addrList
[tid
].push_back(req_addr
);
217 addrMap
[tid
][req_addr
] = inst
->seqNum
;
220 "[tid:%i]: [sn:%i]: Address %08p added to dependency list (size=%i)\n",
221 inst
->readTid(), inst
->seqNum
, req_addr
, addrList
[tid
].size());
223 //@NOTE: 10 is an arbitrarily "high" number, but to be exact
224 // we would need to know the # of outstanding accesses
225 // a priori. Information like fetch width, stage width,
226 // fetch buffer, and the branch resolution stage would be
227 // useful for the icache_port. For the dcache port, the #
228 // of outstanding cache accesses (mshrs) would be a good
229 // sanity check here.
230 //assert(addrList[tid].size() < 10);
234 CacheUnit::removeAddrDependency(DynInstPtr inst
)
236 ThreadID tid
= inst
->readTid();
238 Addr mem_addr
= inst
->getMemAddr();
240 inst
->unsetMemAddr();
242 // Erase from Address List
243 std::list
<Addr
>::iterator list_it
= find(addrList
[tid
].begin(),
246 assert(list_it
!= addrList
[tid
].end() || inst
->splitInst
);
248 if (list_it
!= addrList
[tid
].end()) {
250 "[tid:%i]: [sn:%i] Address %08p removed from dependency "
251 "list\n", inst
->readTid(), inst
->seqNum
, (*list_it
));
253 addrList
[tid
].erase(list_it
);
255 // Erase From Address Map (Used for Debugging)
256 addrMap
[tid
].erase(addrMap
[tid
].find(mem_addr
));
263 CacheUnit::findRequest(DynInstPtr inst
)
265 for (int i
= 0; i
< width
; i
++) {
266 CacheRequest
* cache_req
=
267 dynamic_cast<CacheRequest
*>(reqs
[i
]);
270 if (cache_req
->valid
&&
271 cache_req
->getInst() == inst
&&
272 cache_req
->instIdx
== inst
->curSkedEntry
->idx
) {
281 CacheUnit::findRequest(DynInstPtr inst
, int idx
)
283 for (int i
= 0; i
< width
; i
++) {
284 CacheRequest
* cache_req
=
285 dynamic_cast<CacheRequest
*>(reqs
[i
]);
288 if (cache_req
->valid
&&
289 cache_req
->getInst() == inst
&&
290 cache_req
->instIdx
== idx
) {
300 CacheUnit::getRequest(DynInstPtr inst
, int stage_num
, int res_idx
,
301 int slot_num
, unsigned cmd
)
303 ScheduleEntry
* sched_entry
= *inst
->curSkedEntry
;
304 CacheRequest
* cache_req
= dynamic_cast<CacheRequest
*>(reqs
[slot_num
]);
306 if (!inst
->validMemAddr()) {
307 panic("Mem. Addr. must be set before requesting cache access\n");
310 MemCmd::Command pkt_cmd
;
312 switch (sched_entry
->cmd
)
314 case InitSecondSplitRead
:
315 pkt_cmd
= MemCmd::ReadReq
;
317 DPRINTF(InOrderCachePort
,
318 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
319 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
322 case InitiateReadData
:
323 pkt_cmd
= MemCmd::ReadReq
;
325 DPRINTF(InOrderCachePort
,
326 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
327 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
330 case InitSecondSplitWrite
:
331 pkt_cmd
= MemCmd::WriteReq
;
333 DPRINTF(InOrderCachePort
,
334 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
335 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
338 case InitiateWriteData
:
339 pkt_cmd
= MemCmd::WriteReq
;
341 DPRINTF(InOrderCachePort
,
342 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
343 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
347 panic("%i: Unexpected request type (%i) to %s", curTick(),
348 sched_entry
->cmd
, name());
351 cache_req
->setRequest(inst
, stage_num
, id
, slot_num
,
352 sched_entry
->cmd
, pkt_cmd
,
353 inst
->curSkedEntry
->idx
);
358 CacheUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
360 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
363 // Check to see if this instruction is requesting the same command
364 // or a different one
365 if (cache_req
->cmd
!= inst
->curSkedEntry
->cmd
&&
366 cache_req
->instIdx
== inst
->curSkedEntry
->idx
) {
367 // If different, then update command in the request
368 cache_req
->cmd
= inst
->curSkedEntry
->cmd
;
369 DPRINTF(InOrderCachePort
,
370 "[tid:%i]: [sn:%i]: Updating the command for this "
371 "instruction\n ", inst
->readTid(), inst
->seqNum
);
373 service_request
= true;
374 } else if (inst
->curSkedEntry
->idx
!= CacheUnit::InitSecondSplitRead
&&
375 inst
->curSkedEntry
->idx
!= CacheUnit::InitSecondSplitWrite
) {
376 // If same command, just check to see if memory access was completed
377 // but dont try to re-execute
378 DPRINTF(InOrderCachePort
,
379 "[tid:%i]: [sn:%i]: requesting this resource again\n",
380 inst
->readTid(), inst
->seqNum
);
382 service_request
= true;
387 CacheUnit::setupMemRequest(DynInstPtr inst
, CacheReqPtr cache_req
,
388 int acc_size
, int flags
)
390 ThreadID tid
= inst
->readTid();
391 Addr aligned_addr
= inst
->getMemAddr();
393 if (!cache_req
->is2ndSplit()) {
394 if (cache_req
->memReq
== NULL
) {
396 new Request(cpu
->asid
[tid
], aligned_addr
, acc_size
, flags
,
397 inst
->instAddr(), cpu
->readCpuId(),
399 DPRINTF(InOrderCachePort
, "[sn:%i] Created memReq @%x, ->%x\n",
400 inst
->seqNum
, &cache_req
->memReq
, cache_req
->memReq
);
403 assert(inst
->splitInst
);
405 if (inst
->splitMemReq
== NULL
) {
406 inst
->splitMemReq
= new Request(cpu
->asid
[tid
],
415 cache_req
->memReq
= inst
->splitMemReq
;
420 CacheUnit::doTLBAccess(DynInstPtr inst
, CacheReqPtr cache_req
, int acc_size
,
421 int flags
, TheISA::TLB::Mode tlb_mode
)
423 ThreadID tid
= inst
->readTid();
424 //Addr aligned_addr = inst->getMemAddr();
425 unsigned stage_num
= cache_req
->getStageNum();
426 unsigned slot_idx
= cache_req
->getSlot();
428 setupMemRequest(inst
, cache_req
, acc_size
, flags
);
431 _tlb
->translateAtomic(cache_req
->memReq
,
432 cpu
->thread
[tid
]->getTC(), tlb_mode
);
434 if (inst
->fault
!= NoFault
) {
435 DPRINTF(InOrderTLB
, "[tid:%i]: %s encountered while translating "
436 "addr:%08p for [sn:%i].\n", tid
, inst
->fault
->name(),
437 cache_req
->memReq
->getVaddr(), inst
->seqNum
);
439 cpu
->pipelineStage
[stage_num
]->setResStall(cache_req
, tid
);
441 tlbBlocked
[tid
] = true;
443 cache_req
->tlbStall
= true;
445 // schedule a time to process the tlb miss.
446 // latency hardcoded to 1 (for now), but will be updated
447 // when timing translation gets added in
448 scheduleEvent(slot_idx
, 1);
450 DPRINTF(InOrderTLB
, "[tid:%i]: [sn:%i] virt. addr %08p translated "
451 "to phys. addr:%08p.\n", tid
, inst
->seqNum
,
452 cache_req
->memReq
->getVaddr(),
453 cache_req
->memReq
->getPaddr());
459 CacheUnit::read(DynInstPtr inst
, Addr addr
,
460 uint8_t *data
, unsigned size
, unsigned flags
)
462 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
463 assert(cache_req
&& "Can't Find Instruction for Read!");
465 // The block size of our peer
466 unsigned blockSize
= this->cachePort
->peerBlockSize();
468 //The size of the data we're trying to read.
470 inst
->totalSize
= size
;
472 if (inst
->traceData
) {
473 inst
->traceData
->setAddr(addr
);
476 if (inst
->split2ndAccess
) {
477 size
= inst
->split2ndSize
;
478 cache_req
->splitAccess
= true;
479 cache_req
->split2ndAccess
= true;
481 DPRINTF(InOrderCachePort
, "[sn:%i] Split Read Access (2 of 2) for "
482 "(%#x, %#x).\n", inst
->seqNum
, inst
->getMemAddr(),
487 //The address of the second part of this access if it needs to be split
488 //across a cache line boundary.
489 Addr secondAddr
= roundDown(addr
+ size
- 1, blockSize
);
492 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
494 if (!inst
->splitInst
) {
495 DPRINTF(InOrderCachePort
, "%i: sn[%i] Split Read Access (1 of 2) for "
496 "(%#x, %#x).\n", curTick(), inst
->seqNum
, addr
, secondAddr
);
498 unsigned stage_num
= cache_req
->getStageNum();
499 unsigned cmd
= inst
->curSkedEntry
->cmd
;
501 // 1. Make A New Inst. Schedule w/Split Read/Complete Entered on
503 // ==============================
504 // 2. Reassign curSkedPtr to current command (InitiateRead) on new
506 // ==============================
507 inst
->splitInst
= true;
508 inst
->setBackSked(cpu
->createBackEndSked(inst
));
509 inst
->curSkedEntry
= inst
->backSked
->find(stage_num
, cmd
);
511 DPRINTF(InOrderCachePort
, "[tid:%i] [sn:%i] Retrying Split Read "
512 "Access (1 of 2) for (%#x, %#x).\n", inst
->readTid(),
513 inst
->seqNum
, addr
, secondAddr
);
516 // Save All "Total" Split Information
517 // ==============================
518 inst
->splitMemData
= new uint8_t[size
];
520 // Split Information for First Access
521 // ==============================
522 size
= secondAddr
- addr
;
523 cache_req
->splitAccess
= true;
525 // Split Information for Second Access
526 // ==============================
527 inst
->split2ndSize
= addr
+ fullSize
- secondAddr
;
528 inst
->split2ndAddr
= secondAddr
;
529 inst
->split2ndDataPtr
= inst
->splitMemData
+ size
;
530 inst
->split2ndFlags
= flags
;
533 doTLBAccess(inst
, cache_req
, size
, flags
, TheISA::TLB::Read
);
535 if (inst
->fault
== NoFault
) {
536 if (!cache_req
->splitAccess
) {
537 cache_req
->reqData
= new uint8_t[size
];
538 doCacheAccess(inst
, NULL
);
540 if (!inst
->split2ndAccess
) {
541 cache_req
->reqData
= inst
->splitMemData
;
543 cache_req
->reqData
= inst
->split2ndDataPtr
;
546 doCacheAccess(inst
, NULL
, cache_req
);
554 CacheUnit::write(DynInstPtr inst
, uint8_t *data
, unsigned size
,
555 Addr addr
, unsigned flags
, uint64_t *write_res
)
557 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
558 assert(cache_req
&& "Can't Find Instruction for Write!");
560 // The block size of our peer
561 unsigned blockSize
= this->cachePort
->peerBlockSize();
563 //The size of the data we're trying to write.
565 inst
->totalSize
= size
;
567 if (inst
->traceData
) {
568 inst
->traceData
->setAddr(addr
);
571 if (inst
->split2ndAccess
) {
572 size
= inst
->split2ndSize
;
573 cache_req
->splitAccess
= true;
574 cache_req
->split2ndAccess
= true;
576 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (2 of 2) for "
577 "(%#x, %#x).\n", inst
->seqNum
, inst
->getMemAddr(),
581 //The address of the second part of this access if it needs to be split
582 //across a cache line boundary.
583 Addr secondAddr
= roundDown(addr
+ size
- 1, blockSize
);
585 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
587 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (1 of 2) for "
588 "(%#x, %#x).\n", inst
->seqNum
, addr
, secondAddr
);
590 // Save All "Total" Split Information
591 // ==============================
592 inst
->splitInst
= true;
594 if (!inst
->splitInstSked
) {
595 assert(0 && "Split Requests Not Supported for Now...");
597 // Schedule Split Read/Complete for Instruction
598 // ==============================
599 int stage_num
= cache_req
->getStageNum();
600 RSkedPtr inst_sked
= (stage_num
>= ThePipeline::BackEndStartStage
) ?
601 inst
->backSked
: inst
->frontSked
;
603 // this is just an arbitrarily high priority to ensure that this
604 // gets pushed to the back of the list
607 int isplit_cmd
= CacheUnit::InitSecondSplitWrite
;
609 ScheduleEntry(stage_num
,
611 cpu
->resPool
->getResIdx(DCache
),
615 int csplit_cmd
= CacheUnit::CompleteSecondSplitWrite
;
617 ScheduleEntry(stage_num
+ 1,
619 cpu
->resPool
->getResIdx(DCache
),
622 inst
->splitInstSked
= true;
624 DPRINTF(InOrderCachePort
, "[tid:%i] sn:%i] Retrying Split Read "
625 "Access (1 of 2) for (%#x, %#x).\n",
626 inst
->readTid(), inst
->seqNum
, addr
, secondAddr
);
631 // Split Information for First Access
632 // ==============================
633 size
= secondAddr
- addr
;
634 cache_req
->splitAccess
= true;
636 // Split Information for Second Access
637 // ==============================
638 inst
->split2ndSize
= addr
+ fullSize
- secondAddr
;
639 inst
->split2ndAddr
= secondAddr
;
640 inst
->split2ndFlags
= flags
;
641 inst
->splitInstSked
= true;
644 doTLBAccess(inst
, cache_req
, size
, flags
, TheISA::TLB::Write
);
646 if (inst
->fault
== NoFault
) {
647 if (!cache_req
->splitAccess
) {
648 cache_req
->reqData
= new uint8_t[size
];
649 memcpy(cache_req
->reqData
, data
, size
);
651 //inst->split2ndStoreDataPtr = cache_req->reqData;
652 //inst->split2ndStoreDataPtr += size;
654 doCacheAccess(inst
, write_res
);
656 doCacheAccess(inst
, write_res
, cache_req
);
666 CacheUnit::execute(int slot_num
)
668 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(reqs
[slot_num
]);
671 if (cachePortBlocked
&&
672 (cache_req
->cmd
== InitiateReadData
||
673 cache_req
->cmd
== InitiateWriteData
||
674 cache_req
->cmd
== InitSecondSplitRead
||
675 cache_req
->cmd
== InitSecondSplitWrite
)) {
676 DPRINTF(InOrderCachePort
, "Cache Port Blocked. Cannot Access\n");
677 cache_req
->done(false);
681 DynInstPtr inst
= cache_req
->inst
;
683 ThreadID tid
= inst
->readTid();
684 std::string acc_type
= "write";
687 inst
->fault
= NoFault
;
689 switch (cache_req
->cmd
)
692 case InitiateReadData
:
696 case InitiateWriteData
:
697 if (cachePortBlocked
) {
698 DPRINTF(InOrderCachePort
, "Cache Port Blocked. Cannot Access\n");
699 cache_req
->done(false);
703 DPRINTF(InOrderCachePort
,
704 "[tid:%u]: [sn:%i] Initiating data %s access to %s for "
705 "addr. %08p\n", tid
, inst
->seqNum
, acc_type
, name(),
706 cache_req
->inst
->getMemAddr());
708 inst
->setCurResSlot(slot_num
);
710 if (inst
->isDataPrefetch() || inst
->isInstPrefetch()) {
718 case InitSecondSplitRead
:
719 DPRINTF(InOrderCachePort
,
720 "[tid:%u]: [sn:%i] Initiating split data read access to %s "
721 "for addr. %08p\n", tid
, inst
->seqNum
, name(),
722 cache_req
->inst
->split2ndAddr
);
723 inst
->split2ndAccess
= true;
724 assert(inst
->split2ndAddr
!= 0);
725 read(inst
, inst
->split2ndAddr
, &inst
->split2ndData
,
726 inst
->totalSize
, inst
->split2ndFlags
);
729 case InitSecondSplitWrite
:
730 DPRINTF(InOrderCachePort
,
731 "[tid:%u]: [sn:%i] Initiating split data write access to %s "
732 "for addr. %08p\n", tid
, inst
->seqNum
, name(),
733 cache_req
->inst
->getMemAddr());
735 inst
->split2ndAccess
= true;
736 assert(inst
->split2ndAddr
!= 0);
737 write(inst
, &inst
->split2ndData
, inst
->totalSize
,
738 inst
->split2ndAddr
, inst
->split2ndFlags
, NULL
);
741 case CompleteReadData
:
742 DPRINTF(InOrderCachePort
,
743 "[tid:%i]: [sn:%i]: Trying to Complete Data Read Access\n",
745 //@todo: timing translations need to check here...
746 assert(!inst
->isInstPrefetch() && "Can't Handle Inst. Prefecthes");
747 if (cache_req
->isMemAccComplete() || inst
->isDataPrefetch()) {
748 finishCacheUnitReq(inst
, cache_req
);
750 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
751 tid
, cache_req
->inst
->getMemAddr());
752 cache_req
->setCompleted(false);
753 cache_req
->setMemStall(true);
757 case CompleteWriteData
:
758 DPRINTF(InOrderCachePort
,
759 "[tid:%i]: [sn:%i]: Trying to Complete Data Write Access\n",
761 //@todo: check that timing translation is finished here
762 if (cache_req
->dataPkt
->isRead()) {
763 assert(cache_req
->memReq
->isCondSwap() ||
764 cache_req
->memReq
->isLLSC() ||
765 cache_req
->memReq
->isSwap());
767 if (!cache_req
->isMemAccComplete()) {
768 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
769 tid
, cache_req
->inst
->getMemAddr());
770 cache_req
->setCompleted(false);
771 cache_req
->setMemStall(true);
776 if (cache_req
->isMemAccPending()) {
777 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
778 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
781 //@todo: if split inst save data
783 finishCacheUnitReq(inst
, cache_req
);
786 case CompleteSecondSplitRead
:
787 DPRINTF(InOrderCachePort
,
788 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read "
789 "Access\n", tid
, inst
->seqNum
);
791 //@todo: check that timing translation is finished here
792 assert(!inst
->isInstPrefetch() && "Can't Handle Inst. Prefecthes");
793 if (cache_req
->isMemAccComplete() || inst
->isDataPrefetch()) {
794 finishCacheUnitReq(inst
, cache_req
);
796 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
797 tid
, cache_req
->inst
->split2ndAddr
);
798 cache_req
->setCompleted(false);
799 cache_req
->setMemStall(true);
803 case CompleteSecondSplitWrite
:
804 DPRINTF(InOrderCachePort
,
805 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write "
806 "Access\n", tid
, inst
->seqNum
);
807 //@todo: illegal to have a unaligned cond.swap or llsc?
808 assert(!cache_req
->memReq
->isSwap() && !cache_req
->memReq
->isCondSwap() && !cache_req
->memReq
->isLLSC());
810 if (cache_req
->isMemAccPending()) {
811 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
812 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
815 //@todo: check that timing translation is finished here
816 finishCacheUnitReq(inst
, cache_req
);
820 fatal("Unrecognized command to %s", resName
);
825 CacheUnit::finishCacheUnitReq(DynInstPtr inst
, CacheRequest
*cache_req
)
827 removeAddrDependency(inst
);
828 cache_req
->setMemStall(false);
833 CacheUnit::buildDataPacket(CacheRequest
*cache_req
)
835 // Check for LL/SC and if so change command
836 if (cache_req
->memReq
->isLLSC() && cache_req
->pktCmd
== MemCmd::ReadReq
) {
837 cache_req
->pktCmd
= MemCmd::LoadLockedReq
;
840 if (cache_req
->pktCmd
== MemCmd::WriteReq
) {
842 cache_req
->memReq
->isSwap() ? MemCmd::SwapReq
:
843 (cache_req
->memReq
->isLLSC() ? MemCmd::StoreCondReq
847 cache_req
->dataPkt
= new CacheReqPacket(cache_req
,
851 DPRINTF(InOrderCachePort
, "[slot:%i]: Slot marked for %x [pkt:%x->%x]\n",
852 cache_req
->getSlot(),
853 cache_req
->dataPkt
->getAddr(),
857 cache_req
->dataPkt
->hasSlot
= true;
858 cache_req
->dataPkt
->dataStatic(cache_req
->reqData
);
862 CacheUnit::doCacheAccess(DynInstPtr inst
, uint64_t *write_res
,
863 CacheReqPtr split_req
)
865 Fault fault
= NoFault
;
867 ThreadID tid
= inst
->readTid();
869 bool do_access
= true; // flag to suppress cache access
871 // Special Handling if this is a split request
872 CacheReqPtr cache_req
;
873 if (split_req
== NULL
)
874 cache_req
= dynamic_cast<CacheReqPtr
>(reqs
[inst
->getCurResSlot()]);
876 cache_req
= split_req
;
880 // Make a new packet inside the CacheRequest object
882 buildDataPacket(cache_req
);
884 // Special Handling for LL/SC or Compare/Swap
885 bool is_write
= cache_req
->dataPkt
->isWrite();
886 RequestPtr mem_req
= cache_req
->dataPkt
->req
;
888 DPRINTF(InOrderCachePort
,
889 "[tid:%u]: [sn:%i]: Storing data: %s\n",
891 printMemData(cache_req
->dataPkt
->getPtr
<uint8_t>(),
892 cache_req
->dataPkt
->getSize()));
894 if (mem_req
->isCondSwap()) {
896 cache_req
->memReq
->setExtraData(*write_res
);
898 if (mem_req
->isLLSC()) {
899 assert(cache_req
->inst
->isStoreConditional());
900 DPRINTF(InOrderCachePort
, "Evaluating Store Conditional access\n");
901 do_access
= TheISA::handleLockedWrite(cpu
, mem_req
);
905 // Finally, go ahead and make the access if we can...
906 DPRINTF(InOrderCachePort
,
907 "[tid:%i] [sn:%i] attempting to access cache for addr %08p\n",
908 tid
, inst
->seqNum
, cache_req
->dataPkt
->getAddr());
911 if (!cachePort
->sendTiming(cache_req
->dataPkt
)) {
912 DPRINTF(InOrderCachePort
,
913 "[tid:%i] [sn:%i] cannot access cache, because port "
914 "is blocked. now waiting to retry request\n", tid
,
916 delete cache_req
->dataPkt
;
917 cache_req
->dataPkt
= NULL
;
919 delete cache_req
->memReq
;
920 cache_req
->memReq
= NULL
;
922 cache_req
->done(false);
923 cachePortBlocked
= true;
925 DPRINTF(InOrderCachePort
,
926 "[tid:%i] [sn:%i] is now waiting for cache response\n",
928 cache_req
->setCompleted();
929 cache_req
->setMemAccPending();
930 cachePortBlocked
= false;
932 } else if (mem_req
->isLLSC()){
933 // Store-Conditional instructions complete even if they "failed"
934 assert(cache_req
->inst
->isStoreConditional());
935 cache_req
->setCompleted(true);
938 "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
941 processCacheCompletion(cache_req
->dataPkt
);
943 delete cache_req
->dataPkt
;
944 cache_req
->dataPkt
= NULL
;
946 delete cache_req
->memReq
;
947 cache_req
->memReq
= NULL
;
949 // Make cache request again since access due to
950 // inability to access
951 DPRINTF(InOrderStall
, "STALL: \n");
952 cache_req
->done(false);
958 CacheUnit::processSquash(CacheReqPacket
*cache_pkt
)
960 // The resource may no longer be actively servicing this
961 // packet. Scenarios like a store that has been sent to the
962 // memory system or access that's been squashed. If that's
963 // the case, we can't access the request slot because it
964 // will be either invalid or servicing another request.
965 if (!cache_pkt
->hasSlot
) {
966 DPRINTF(InOrderCachePort
,
967 "%x does not have a slot in unit, ignoring.\n",
968 cache_pkt
->getAddr());
970 if (cache_pkt
->reqData
) {
971 delete [] cache_pkt
->reqData
;
972 cache_pkt
->reqData
= NULL
;
975 if (cache_pkt
->memReq
) {
976 delete cache_pkt
->memReq
;
977 cache_pkt
->memReq
= NULL
;
985 DPRINTF(InOrderCachePort
, "%x has slot %i\n",
986 cache_pkt
->getAddr(), cache_pkt
->cacheReq
->getSlot());
990 // It's possible that the request is squashed but the
991 // packet is still acknowledged by the resource. Squashes
992 // should happen at the end of the cycles and trigger the
993 // code above, but if not, this would handle any timing
994 // variations due to diff. user parameters.
995 if (cache_pkt
->cacheReq
->isSquashed()) {
996 DPRINTF(InOrderCachePort
,
997 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
998 cache_pkt
->cacheReq
->getInst()->readTid(),
999 cache_pkt
->cacheReq
->getInst()->seqNum
);
1001 cache_pkt
->cacheReq
->setMemAccPending(false);
1002 cache_pkt
->cacheReq
->freeSlot();
1014 CacheUnit::processCacheCompletion(PacketPtr pkt
)
1016 CacheReqPacket
* cache_pkt
= dynamic_cast<CacheReqPacket
*>(pkt
);
1019 DPRINTF(InOrderCachePort
, "Finished request for %x [pkt:%x->%x]\n",
1020 pkt
->getAddr(), &cache_pkt
, cache_pkt
);
1022 //@todo: process Squashed Completion
1023 if (processSquash(cache_pkt
))
1026 CacheRequest
*cache_req
= dynamic_cast<CacheReqPtr
>(
1027 findRequest(cache_pkt
->cacheReq
->getInst(), cache_pkt
->instIdx
));
1030 panic("[tid:%u]: [sn:%i]: Can't find slot for cache access to "
1031 "addr. %08p\n", cache_pkt
->cacheReq
->getInst()->readTid(),
1032 cache_pkt
->cacheReq
->getInst()->seqNum
,
1033 cache_pkt
->cacheReq
->getInst()->getMemAddr());
1037 assert(cache_req
== cache_pkt
->cacheReq
);
1039 DPRINTF(InOrderCachePort
,
1040 "[tid:%u]: [sn:%i]: [slot:%i] Waking from cache access (vaddr.%08p, paddr:%08p)\n",
1041 cache_pkt
->cacheReq
->getInst()->readTid(),
1042 cache_pkt
->cacheReq
->getInst()->seqNum
,
1043 cache_req
->getSlot(),
1044 cache_pkt
->req
->getVaddr(),
1045 cache_pkt
->req
->getPaddr());
1047 // Get resource request info
1048 unsigned stage_num
= cache_req
->getStageNum();
1049 DynInstPtr inst
= cache_req
->inst
;
1050 ThreadID tid
= cache_req
->inst
->readTid();
1052 assert(!cache_req
->isSquashed());
1053 assert(inst
->staticInst
&& inst
->isMemRef());
1056 DPRINTF(InOrderCachePort
,
1057 "[tid:%u]: [sn:%i]: Processing cache access\n",
1060 PacketPtr split_pkt
= NULL
;
1061 if (inst
->splitInst
) {
1062 inst
->splitFinishCnt
++;
1064 if (inst
->splitFinishCnt
== 2) {
1065 cache_req
->memReq
->setVirt(0/*inst->tid*/,
1071 split_pkt
= new Packet(cache_req
->memReq
, cache_req
->pktCmd
,
1073 split_pkt
->dataStatic(inst
->splitMemData
);
1075 DPRINTF(InOrderCachePort
, "Completing Split Access.\n");
1076 inst
->completeAcc(split_pkt
);
1079 inst
->completeAcc(cache_pkt
);
1082 inst
->setExecuted();
1084 if (inst
->isLoad()) {
1085 assert(cache_pkt
->isRead());
1087 if (cache_pkt
->req
->isLLSC()) {
1088 DPRINTF(InOrderCachePort
,
1089 "[tid:%u]: Handling Load-Linked for [sn:%u]\n",
1091 TheISA::handleLockedRead(cpu
, cache_pkt
->req
);
1094 DPRINTF(InOrderCachePort
,
1095 "[tid:%u]: [sn:%i]: Bytes loaded were: %s\n",
1097 (split_pkt
) ? printMemData(split_pkt
->getPtr
<uint8_t>(),
1098 split_pkt
->getSize()) :
1099 printMemData(cache_pkt
->getPtr
<uint8_t>(),
1100 cache_pkt
->getSize()));
1101 } else if(inst
->isStore()) {
1102 assert(cache_pkt
->isWrite());
1104 DPRINTF(InOrderCachePort
,
1105 "[tid:%u]: [sn:%i]: Bytes stored were: %s\n",
1107 (split_pkt
) ? printMemData(split_pkt
->getPtr
<uint8_t>(),
1108 split_pkt
->getSize()) :
1109 printMemData(cache_pkt
->getPtr
<uint8_t>(),
1110 cache_pkt
->getSize()));
1113 DPRINTF(InOrderCachePort
, "Deleting packets %x (%x).\n",
1114 cache_pkt
, cache_req
->dataPkt
);
1121 cache_req
->setMemAccPending(false);
1122 cache_req
->setMemAccCompleted();
1124 if (cache_req
->isMemStall() &&
1125 cpu
->threadModel
== InOrderCPU::SwitchOnCacheMiss
) {
1126 DPRINTF(InOrderCachePort
, "[tid:%u] Waking up from Cache Miss.\n",
1129 cpu
->activateContext(tid
);
1131 DPRINTF(ThreadModel
, "Activating [tid:%i] after return from cache"
1135 // Wake up the CPU (if it went to sleep and was waiting on this
1136 // completion event).
1139 DPRINTF(Activity
, "[tid:%u] Activating %s due to cache completion\n",
1140 tid
, cpu
->pipelineStage
[stage_num
]->name());
1142 cpu
->switchToActive(stage_num
);
1146 CacheUnit::recvRetry()
1148 DPRINTF(InOrderCachePort
, "Unblocking Cache Port. \n");
1150 assert(cachePortBlocked
);
1152 // Clear the cache port for use again
1153 cachePortBlocked
= false;
1158 CacheUnitEvent::CacheUnitEvent()
1163 CacheUnitEvent::process()
1165 DynInstPtr inst
= resource
->reqs
[slotIdx
]->inst
;
1166 int stage_num
= resource
->reqs
[slotIdx
]->getStageNum();
1167 ThreadID tid
= inst
->threadNumber
;
1168 CacheReqPtr req_ptr
= dynamic_cast<CacheReqPtr
>(resource
->reqs
[slotIdx
]);
1170 DPRINTF(InOrderTLB
, "Waking up from TLB Miss caused by [sn:%i].\n",
1173 CacheUnit
* tlb_res
= dynamic_cast<CacheUnit
*>(resource
);
1176 //@todo: eventually, we should do a timing translation w/
1177 // hw page table walk on tlb miss
1178 DPRINTF(Fault
, "Handling Fault %s : [sn:%i] %x\n", inst
->fault
->name(), inst
->seqNum
, inst
->getMemAddr());
1179 inst
->fault
->invoke(tlb_res
->cpu
->tcBase(tid
), inst
->staticInst
);
1181 tlb_res
->tlbBlocked
[tid
] = false;
1183 tlb_res
->cpu
->pipelineStage
[stage_num
]->
1184 unsetResStall(tlb_res
->reqs
[slotIdx
], tid
);
1186 req_ptr
->tlbStall
= false;
1188 //@todo: timing translation needs to have some type of independent
1189 // info regarding if it's squashed or not so we can
1190 // free up the resource if a request gets squashed in the middle
1192 if (req_ptr
->isSquashed()) {
1193 req_ptr
->freeSlot();
1196 tlb_res
->cpu
->wakeCPU();
1200 CacheUnit::squashDueToMemStall(DynInstPtr inst
, int stage_num
,
1201 InstSeqNum squash_seq_num
, ThreadID tid
)
1203 // If squashing due to memory stall, then we do NOT want to
1204 // squash the instruction that caused the stall so we
1205 // increment the sequence number here to prevent that.
1207 // NOTE: This is only for the SwitchOnCacheMiss Model
1208 // NOTE: If you have multiple outstanding misses from the same
1209 // thread then you need to reevaluate this code
1210 // NOTE: squash should originate from
1211 // pipeline_stage.cc:processInstSchedule
1212 DPRINTF(InOrderCachePort
, "Squashing above [sn:%u]\n",
1213 squash_seq_num
+ 1);
1215 squash(inst
, stage_num
, squash_seq_num
+ 1, tid
);
1219 CacheUnit::squashCacheRequest(CacheReqPtr req_ptr
)
1221 DynInstPtr inst
= req_ptr
->getInst();
1223 req_ptr
->setSquashed();
1224 inst
->setSquashed();
1225 if (inst
->validMemAddr()) {
1226 DPRINTF(AddrDep
, "Squash of [tid:%i] [sn:%i], attempting to "
1227 "remove addr. %08p dependencies.\n",
1230 inst
->getMemAddr());
1232 removeAddrDependency(inst
);
1238 CacheUnit::squash(DynInstPtr inst
, int stage_num
,
1239 InstSeqNum squash_seq_num
, ThreadID tid
)
1241 for (int i
= 0; i
< width
; i
++) {
1242 ResReqPtr req_ptr
= reqs
[i
];
1244 if (req_ptr
->valid
&&
1245 req_ptr
->getInst()->readTid() == tid
&&
1246 req_ptr
->getInst()->seqNum
> squash_seq_num
) {
1248 DPRINTF(InOrderCachePort
,
1249 "[tid:%i] Squashing request from [sn:%i]\n",
1250 req_ptr
->getInst()->readTid(), req_ptr
->getInst()->seqNum
);
1252 if (req_ptr
->isSquashed()) {
1253 DPRINTF(AddrDep
, "Request for [tid:%i] [sn:%i] already "
1254 "squashed, ignoring squash process.\n",
1255 req_ptr
->getInst()->readTid(),
1256 req_ptr
->getInst()->seqNum
);
1260 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(req_ptr
);
1263 squashCacheRequest(cache_req
);
1265 int req_slot_num
= req_ptr
->getSlot();
1267 if (cache_req
->tlbStall
) {
1268 tlbBlocked
[tid
] = false;
1270 int stall_stage
= reqs
[req_slot_num
]->getStageNum();
1272 cpu
->pipelineStage
[stall_stage
]->
1273 unsetResStall(reqs
[req_slot_num
], tid
);
1276 if (cache_req
->isMemAccPending()) {
1277 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
1278 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
1281 if (!cache_req
->tlbStall
)
1282 freeSlot(req_slot_num
);
1289 CacheRequest::clearRequest()
1291 if (!memAccPending
) {
1292 if (reqData
&& !splitAccess
)
1296 DPRINTF(InOrderCachePort
, "Clearing request for %x...%x\n",
1297 memReq
->getVaddr(), (memReq
->hasPaddr()) ? memReq
->getPaddr() : 0);
1305 dataPkt
->hasSlot
= false;
1306 DPRINTF(InOrderCachePort
, "[slot:%i]: Slot unmarked for %x for [pkt:%x->%x]\n",
1307 getSlot(), dataPkt
->getAddr(), &dataPkt
, dataPkt
);
1314 memAccComplete
= false;
1315 memAccPending
= false;
1317 splitAccess
= false;
1318 splitAccessNum
= -1;
1319 split2ndAccess
= false;
1321 fetchBufferFill
= false;
1323 ResourceRequest::clearRequest();