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;
122 tlbBlockSeqNum
[i
] = 0;
134 CacheUnit::getPort(const string
&if_name
, int idx
)
136 if (if_name
== resName
)
145 for (int i
= 0; i
< width
; i
++) {
146 reqs
[i
] = new CacheRequest(this);
149 // Currently Used to Model TLB Latency. Eventually
150 // Switch to Timing TLB translations.
151 resourceEvent
= new CacheUnitEvent
[width
];
153 cacheBlkSize
= this->cachePort
->peerBlockSize();
154 cacheBlkMask
= cacheBlkSize
- 1;
160 CacheUnit::getSlot(DynInstPtr inst
)
162 ThreadID tid
= inst
->readTid();
163 if (tlbBlocked
[tid
]) {
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 int new_slot
= Resource::getSlot(inst
);
175 inst
->memTime
= curTick();
176 //@note: add back in if you want speculative loads/store capability
177 //setAddrDependency(inst);
182 CacheUnit::setAddrDependency(DynInstPtr inst
)
184 Addr req_addr
= inst
->getMemAddr();
185 ThreadID tid
= inst
->readTid();
187 addrList
[tid
].push_back(req_addr
);
188 addrMap
[tid
][req_addr
] = inst
->seqNum
;
191 "[tid:%i]: [sn:%i]: Address %08p added to dependency list (size=%i)\n",
192 inst
->readTid(), inst
->seqNum
, req_addr
, addrList
[tid
].size());
194 //@NOTE: 10 is an arbitrarily "high" number, but to be exact
195 // we would need to know the # of outstanding accesses
196 // a priori. Information like fetch width, stage width,
197 // fetch buffer, and the branch resolution stage would be
198 // useful for the icache_port. For the dcache port, the #
199 // of outstanding cache accesses (mshrs) would be a good
200 // sanity check here.
201 //assert(addrList[tid].size() < 10);
205 CacheUnit::removeAddrDependency(DynInstPtr inst
)
207 ThreadID tid
= inst
->readTid();
209 Addr mem_addr
= inst
->getMemAddr();
211 inst
->unsetMemAddr();
213 // Erase from Address List
214 std::list
<Addr
>::iterator list_it
= find(addrList
[tid
].begin(),
217 assert(list_it
!= addrList
[tid
].end() || inst
->splitInst
);
219 if (list_it
!= addrList
[tid
].end()) {
221 "[tid:%i]: [sn:%i] Address %08p removed from dependency "
222 "list\n", inst
->readTid(), inst
->seqNum
, (*list_it
));
224 addrList
[tid
].erase(list_it
);
226 // Erase From Address Map (Used for Debugging)
227 addrMap
[tid
].erase(addrMap
[tid
].find(mem_addr
));
234 CacheUnit::findRequest(DynInstPtr inst
)
236 for (int i
= 0; i
< width
; i
++) {
237 CacheRequest
* cache_req
=
238 dynamic_cast<CacheRequest
*>(reqs
[i
]);
241 if (cache_req
->valid
&&
242 cache_req
->getInst() == inst
&&
243 cache_req
->instIdx
== inst
->curSkedEntry
->idx
) {
252 CacheUnit::findRequest(DynInstPtr inst
, int idx
)
254 for (int i
= 0; i
< width
; i
++) {
255 CacheRequest
* cache_req
=
256 dynamic_cast<CacheRequest
*>(reqs
[i
]);
259 if (cache_req
->valid
&&
260 cache_req
->getInst() == inst
&&
261 cache_req
->instIdx
== idx
) {
271 CacheUnit::getRequest(DynInstPtr inst
, int stage_num
, int res_idx
,
272 int slot_num
, unsigned cmd
)
274 ScheduleEntry
* sched_entry
= *inst
->curSkedEntry
;
275 CacheRequest
* cache_req
= dynamic_cast<CacheRequest
*>(reqs
[slot_num
]);
277 if (!inst
->validMemAddr()) {
278 panic("Mem. Addr. must be set before requesting cache access\n");
281 MemCmd::Command pkt_cmd
;
283 switch (sched_entry
->cmd
)
285 case InitSecondSplitRead
:
286 pkt_cmd
= MemCmd::ReadReq
;
288 DPRINTF(InOrderCachePort
,
289 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
290 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
293 case InitiateReadData
:
294 pkt_cmd
= MemCmd::ReadReq
;
296 DPRINTF(InOrderCachePort
,
297 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
298 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
301 case InitSecondSplitWrite
:
302 pkt_cmd
= MemCmd::WriteReq
;
304 DPRINTF(InOrderCachePort
,
305 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
306 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
309 case InitiateWriteData
:
310 pkt_cmd
= MemCmd::WriteReq
;
312 DPRINTF(InOrderCachePort
,
313 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
314 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
318 panic("%i: Unexpected request type (%i) to %s", curTick(),
319 sched_entry
->cmd
, name());
322 cache_req
->setRequest(inst
, stage_num
, id
, slot_num
,
323 sched_entry
->cmd
, pkt_cmd
,
324 inst
->curSkedEntry
->idx
);
329 CacheUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
331 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
334 // Check to see if this instruction is requesting the same command
335 // or a different one
336 if (cache_req
->cmd
!= inst
->curSkedEntry
->cmd
&&
337 cache_req
->instIdx
== inst
->curSkedEntry
->idx
) {
338 // If different, then update command in the request
339 cache_req
->cmd
= inst
->curSkedEntry
->cmd
;
340 DPRINTF(InOrderCachePort
,
341 "[tid:%i]: [sn:%i]: Updating the command for this "
342 "instruction\n", inst
->readTid(), inst
->seqNum
);
344 service_request
= true;
345 } else if (inst
->curSkedEntry
->idx
!= CacheUnit::InitSecondSplitRead
&&
346 inst
->curSkedEntry
->idx
!= CacheUnit::InitSecondSplitWrite
) {
347 // If same command, just check to see if memory access was completed
348 // but dont try to re-execute
349 DPRINTF(InOrderCachePort
,
350 "[tid:%i]: [sn:%i]: requesting this resource again\n",
351 inst
->readTid(), inst
->seqNum
);
353 service_request
= true;
358 CacheUnit::setupMemRequest(DynInstPtr inst
, CacheReqPtr cache_req
,
359 int acc_size
, int flags
)
361 ThreadID tid
= inst
->readTid();
362 Addr aligned_addr
= inst
->getMemAddr();
364 if (!cache_req
->is2ndSplit()) {
365 if (cache_req
->memReq
== NULL
) {
367 new Request(cpu
->asid
[tid
], aligned_addr
, acc_size
, flags
,
368 inst
->instAddr(), cpu
->readCpuId(),
370 DPRINTF(InOrderCachePort
, "[sn:%i] Created memReq @%x, ->%x\n",
371 inst
->seqNum
, &cache_req
->memReq
, cache_req
->memReq
);
374 assert(inst
->splitInst
);
376 if (inst
->splitMemReq
== NULL
) {
377 inst
->splitMemReq
= new Request(cpu
->asid
[tid
],
386 cache_req
->memReq
= inst
->splitMemReq
;
391 CacheUnit::doTLBAccess(DynInstPtr inst
, CacheReqPtr cache_req
, int acc_size
,
392 int flags
, TheISA::TLB::Mode tlb_mode
)
394 ThreadID tid
= inst
->readTid();
396 setupMemRequest(inst
, cache_req
, acc_size
, flags
);
398 _tlb
->translateAtomic(cache_req
->memReq
,
399 cpu
->thread
[tid
]->getTC(), tlb_mode
);
401 if (inst
->fault
!= NoFault
) {
402 DPRINTF(InOrderTLB
, "[tid:%i]: %s encountered while translating "
403 "addr:%08p for [sn:%i].\n", tid
, inst
->fault
->name(),
404 cache_req
->memReq
->getVaddr(), inst
->seqNum
);
406 tlbBlocked
[tid
] = true;
407 tlbBlockSeqNum
[tid
] = inst
->seqNum
;
410 unsigned stage_num
= cache_req
->getStageNum();
412 cpu
->pipelineStage
[stage_num
]->setResStall(cache_req
, tid
);
413 cache_req
->tlbStall
= true;
415 // schedule a time to process the tlb miss.
416 // latency hardcoded to 1 (for now), but will be updated
417 // when timing translation gets added in
418 scheduleEvent(slot_idx
, 1);
419 unsigned slot_idx
= cache_req
->getSlot();
422 // Mark it as complete so it can pass through next stage.
423 // Fault Handling will happen at commit/graduation
424 cache_req
->setCompleted();
426 DPRINTF(InOrderTLB
, "[tid:%i]: [sn:%i] virt. addr %08p translated "
427 "to phys. addr:%08p.\n", tid
, inst
->seqNum
,
428 cache_req
->memReq
->getVaddr(),
429 cache_req
->memReq
->getPaddr());
435 CacheUnit::read(DynInstPtr inst
, Addr addr
,
436 uint8_t *data
, unsigned size
, unsigned flags
)
438 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
439 assert(cache_req
&& "Can't Find Instruction for Read!");
441 // The block size of our peer
442 unsigned blockSize
= this->cachePort
->peerBlockSize();
444 //The size of the data we're trying to read.
446 inst
->totalSize
= size
;
448 if (inst
->traceData
) {
449 inst
->traceData
->setAddr(addr
);
452 if (inst
->split2ndAccess
) {
453 size
= inst
->split2ndSize
;
454 cache_req
->splitAccess
= true;
455 cache_req
->split2ndAccess
= true;
457 DPRINTF(InOrderCachePort
, "[sn:%i] Split Read Access (2 of 2) for "
458 "(%#x, %#x).\n", inst
->seqNum
, inst
->getMemAddr(),
463 //The address of the second part of this access if it needs to be split
464 //across a cache line boundary.
465 Addr secondAddr
= roundDown(addr
+ size
- 1, blockSize
);
468 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
470 if (!inst
->splitInst
) {
471 DPRINTF(InOrderCachePort
, "%i: sn[%i] Split Read Access (1 of 2) for "
472 "(%#x, %#x).\n", curTick(), inst
->seqNum
, addr
, secondAddr
);
474 unsigned stage_num
= cache_req
->getStageNum();
475 unsigned cmd
= inst
->curSkedEntry
->cmd
;
477 // 1. Make A New Inst. Schedule w/Split Read/Complete Entered on
479 // ==============================
480 // 2. Reassign curSkedPtr to current command (InitiateRead) on new
482 // ==============================
483 inst
->splitInst
= true;
484 inst
->setBackSked(cpu
->createBackEndSked(inst
));
485 inst
->curSkedEntry
= inst
->backSked
->find(stage_num
, cmd
);
487 DPRINTF(InOrderCachePort
, "[tid:%i] [sn:%i] Retrying Split Read "
488 "Access (1 of 2) for (%#x, %#x).\n", inst
->readTid(),
489 inst
->seqNum
, addr
, secondAddr
);
492 // Save All "Total" Split Information
493 // ==============================
494 inst
->splitMemData
= new uint8_t[size
];
496 // Split Information for First Access
497 // ==============================
498 size
= secondAddr
- addr
;
499 cache_req
->splitAccess
= true;
501 // Split Information for Second Access
502 // ==============================
503 inst
->split2ndSize
= addr
+ fullSize
- secondAddr
;
504 inst
->split2ndAddr
= secondAddr
;
505 inst
->split2ndDataPtr
= inst
->splitMemData
+ size
;
506 inst
->split2ndFlags
= flags
;
509 doTLBAccess(inst
, cache_req
, size
, flags
, TheISA::TLB::Read
);
511 if (inst
->fault
== NoFault
) {
512 if (!cache_req
->splitAccess
) {
513 cache_req
->reqData
= new uint8_t[size
];
514 doCacheAccess(inst
, NULL
);
516 if (!inst
->split2ndAccess
) {
517 cache_req
->reqData
= inst
->splitMemData
;
519 cache_req
->reqData
= inst
->split2ndDataPtr
;
522 doCacheAccess(inst
, NULL
, cache_req
);
530 CacheUnit::write(DynInstPtr inst
, uint8_t *data
, unsigned size
,
531 Addr addr
, unsigned flags
, uint64_t *write_res
)
533 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
534 assert(cache_req
&& "Can't Find Instruction for Write!");
536 // The block size of our peer
537 unsigned blockSize
= this->cachePort
->peerBlockSize();
539 //The size of the data we're trying to write.
541 inst
->totalSize
= size
;
543 if (inst
->traceData
) {
544 inst
->traceData
->setAddr(addr
);
547 if (inst
->split2ndAccess
) {
548 size
= inst
->split2ndSize
;
549 cache_req
->splitAccess
= true;
550 cache_req
->split2ndAccess
= true;
552 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (2 of 2) for "
553 "(%#x, %#x).\n", inst
->seqNum
, inst
->getMemAddr(),
557 //The address of the second part of this access if it needs to be split
558 //across a cache line boundary.
559 Addr secondAddr
= roundDown(addr
+ size
- 1, blockSize
);
561 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
563 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (1 of 2) for "
564 "(%#x, %#x).\n", inst
->seqNum
, addr
, secondAddr
);
566 // Save All "Total" Split Information
567 // ==============================
568 inst
->splitInst
= true;
570 if (!inst
->splitInstSked
) {
571 assert(0 && "Split Requests Not Supported for Now...");
573 // Schedule Split Read/Complete for Instruction
574 // ==============================
575 int stage_num
= cache_req
->getStageNum();
576 RSkedPtr inst_sked
= (stage_num
>= ThePipeline::BackEndStartStage
) ?
577 inst
->backSked
: inst
->frontSked
;
579 // this is just an arbitrarily high priority to ensure that this
580 // gets pushed to the back of the list
583 int isplit_cmd
= CacheUnit::InitSecondSplitWrite
;
585 ScheduleEntry(stage_num
,
587 cpu
->resPool
->getResIdx(DCache
),
591 int csplit_cmd
= CacheUnit::CompleteSecondSplitWrite
;
593 ScheduleEntry(stage_num
+ 1,
595 cpu
->resPool
->getResIdx(DCache
),
598 inst
->splitInstSked
= true;
600 DPRINTF(InOrderCachePort
, "[tid:%i] sn:%i] Retrying Split Read "
601 "Access (1 of 2) for (%#x, %#x).\n",
602 inst
->readTid(), inst
->seqNum
, addr
, secondAddr
);
607 // Split Information for First Access
608 // ==============================
609 size
= secondAddr
- addr
;
610 cache_req
->splitAccess
= true;
612 // Split Information for Second Access
613 // ==============================
614 inst
->split2ndSize
= addr
+ fullSize
- secondAddr
;
615 inst
->split2ndAddr
= secondAddr
;
616 inst
->split2ndFlags
= flags
;
617 inst
->splitInstSked
= true;
620 doTLBAccess(inst
, cache_req
, size
, flags
, TheISA::TLB::Write
);
622 if (inst
->fault
== NoFault
) {
623 if (!cache_req
->splitAccess
) {
624 cache_req
->reqData
= new uint8_t[size
];
625 memcpy(cache_req
->reqData
, data
, size
);
627 //inst->split2ndStoreDataPtr = cache_req->reqData;
628 //inst->split2ndStoreDataPtr += size;
630 doCacheAccess(inst
, write_res
);
632 doCacheAccess(inst
, write_res
, cache_req
);
642 CacheUnit::execute(int slot_num
)
644 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(reqs
[slot_num
]);
647 if (cachePortBlocked
&&
648 (cache_req
->cmd
== InitiateReadData
||
649 cache_req
->cmd
== InitiateWriteData
||
650 cache_req
->cmd
== InitSecondSplitRead
||
651 cache_req
->cmd
== InitSecondSplitWrite
)) {
652 DPRINTF(InOrderCachePort
, "Cache Port Blocked. Cannot Access\n");
653 cache_req
->done(false);
657 DynInstPtr inst
= cache_req
->inst
;
659 ThreadID tid
= inst
->readTid();
660 std::string acc_type
= "write";
663 switch (cache_req
->cmd
)
666 case InitiateReadData
:
670 case InitiateWriteData
:
671 if (cachePortBlocked
) {
672 DPRINTF(InOrderCachePort
, "Cache Port Blocked. Cannot Access\n");
673 cache_req
->done(false);
677 DPRINTF(InOrderCachePort
,
678 "[tid:%u]: [sn:%i] Initiating data %s access to %s for "
679 "addr. %08p\n", tid
, inst
->seqNum
, acc_type
, name(),
680 cache_req
->inst
->getMemAddr());
682 inst
->setCurResSlot(slot_num
);
684 if (inst
->isDataPrefetch() || inst
->isInstPrefetch()) {
692 case InitSecondSplitRead
:
693 DPRINTF(InOrderCachePort
,
694 "[tid:%u]: [sn:%i] Initiating split data read access to %s "
695 "for addr. %08p\n", tid
, inst
->seqNum
, name(),
696 cache_req
->inst
->split2ndAddr
);
697 inst
->split2ndAccess
= true;
698 assert(inst
->split2ndAddr
!= 0);
699 read(inst
, inst
->split2ndAddr
, &inst
->split2ndData
,
700 inst
->totalSize
, inst
->split2ndFlags
);
703 case InitSecondSplitWrite
:
704 DPRINTF(InOrderCachePort
,
705 "[tid:%u]: [sn:%i] Initiating split data write access to %s "
706 "for addr. %08p\n", tid
, inst
->seqNum
, name(),
707 cache_req
->inst
->getMemAddr());
709 inst
->split2ndAccess
= true;
710 assert(inst
->split2ndAddr
!= 0);
711 write(inst
, &inst
->split2ndData
, inst
->totalSize
,
712 inst
->split2ndAddr
, inst
->split2ndFlags
, NULL
);
715 case CompleteReadData
:
716 DPRINTF(InOrderCachePort
,
717 "[tid:%i]: [sn:%i]: Trying to Complete Data Read Access\n",
720 if (inst
->fault
!= NoFault
) {
721 DPRINTF(InOrderCachePort
,
722 "[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
723 "next stage.\n", tid
, inst
->seqNum
, inst
->fault
->name(),
725 finishCacheUnitReq(inst
, cache_req
);
729 //@todo: timing translations need to check here...
730 assert(!inst
->isInstPrefetch() && "Can't Handle Inst. Prefecthes");
731 if (cache_req
->isMemAccComplete() || inst
->isDataPrefetch()) {
732 finishCacheUnitReq(inst
, cache_req
);
734 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
735 tid
, cache_req
->inst
->getMemAddr());
736 cache_req
->setCompleted(false);
737 cache_req
->setMemStall(true);
741 case CompleteWriteData
:
743 DPRINTF(InOrderCachePort
,
744 "[tid:%i]: [sn:%i]: Trying to Complete Data Write Access\n",
747 if (inst
->fault
!= NoFault
) {
748 DPRINTF(InOrderCachePort
,
749 "[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to ",
750 "next stage.\n", tid
, inst
->seqNum
, inst
->fault
->name(),
752 finishCacheUnitReq(inst
, cache_req
);
756 //@todo: check that timing translation is finished here
757 RequestPtr mem_req
= cache_req
->memReq
;
758 DPRINTF(InOrderCachePort
,
759 "[tid:%i]: [sn:%i]: cSwap:%i LLSC:%i isSwap:%i isCond:%i\n",
761 mem_req
->isCondSwap(),
764 inst
->isStoreConditional());
766 if (mem_req
->isCondSwap() || mem_req
->isLLSC() || mem_req
->isSwap()) {
767 DPRINTF(InOrderCachePort
, "Detected Conditional Store Inst.\n");
769 if (!cache_req
->isMemAccComplete()) {
770 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
771 tid
, cache_req
->inst
->getMemAddr());
772 cache_req
->setCompleted(false);
773 cache_req
->setMemStall(true);
776 DPRINTF(InOrderStall
, "Mem Acc Completed\n");
780 if (cache_req
->isMemAccPending()) {
781 DPRINTF(InOrderCachePort
, "Store Instruction Pending Completion.\n");
782 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
783 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
785 DPRINTF(InOrderCachePort
, "Store Instruction Finished Completion.\n");
787 //@todo: if split inst save data
789 finishCacheUnitReq(inst
, cache_req
);
793 case CompleteSecondSplitRead
:
794 DPRINTF(InOrderCachePort
,
795 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read "
796 "Access\n", tid
, inst
->seqNum
);
798 //@todo: check that timing translation is finished here
799 assert(!inst
->isInstPrefetch() && "Can't Handle Inst. Prefecthes");
800 if (cache_req
->isMemAccComplete() || inst
->isDataPrefetch()) {
801 finishCacheUnitReq(inst
, cache_req
);
803 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
804 tid
, cache_req
->inst
->split2ndAddr
);
805 cache_req
->setCompleted(false);
806 cache_req
->setMemStall(true);
810 case CompleteSecondSplitWrite
:
811 DPRINTF(InOrderCachePort
,
812 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write "
813 "Access\n", tid
, inst
->seqNum
);
814 //@todo: illegal to have a unaligned cond.swap or llsc?
815 assert(!cache_req
->memReq
->isSwap() && !cache_req
->memReq
->isCondSwap()
816 && !cache_req
->memReq
->isLLSC());
818 if (cache_req
->isMemAccPending()) {
819 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
820 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
823 //@todo: check that timing translation is finished here
824 finishCacheUnitReq(inst
, cache_req
);
828 fatal("Unrecognized command to %s", resName
);
833 CacheUnit::finishCacheUnitReq(DynInstPtr inst
, CacheRequest
*cache_req
)
835 //@note: add back in for speculative load/store capability
836 //removeAddrDependency(inst);
837 cache_req
->setMemStall(false);
842 CacheUnit::buildDataPacket(CacheRequest
*cache_req
)
844 // Check for LL/SC and if so change command
845 if (cache_req
->memReq
->isLLSC() && cache_req
->pktCmd
== MemCmd::ReadReq
) {
846 cache_req
->pktCmd
= MemCmd::LoadLockedReq
;
849 if (cache_req
->pktCmd
== MemCmd::WriteReq
) {
851 cache_req
->memReq
->isSwap() ? MemCmd::SwapReq
:
852 (cache_req
->memReq
->isLLSC() ? MemCmd::StoreCondReq
856 cache_req
->dataPkt
= new CacheReqPacket(cache_req
,
860 DPRINTF(InOrderCachePort
, "[slot:%i]: Slot marked for %x [pkt:%x->%x]\n",
861 cache_req
->getSlot(),
862 cache_req
->dataPkt
->getAddr(),
866 cache_req
->dataPkt
->hasSlot
= true;
867 cache_req
->dataPkt
->dataStatic(cache_req
->reqData
);
871 CacheUnit::doCacheAccess(DynInstPtr inst
, uint64_t *write_res
,
872 CacheReqPtr split_req
)
874 Fault fault
= NoFault
;
876 ThreadID tid
= inst
->readTid();
878 bool do_access
= true; // flag to suppress cache access
880 // Special Handling if this is a split request
881 CacheReqPtr cache_req
;
882 if (split_req
== NULL
)
883 cache_req
= dynamic_cast<CacheReqPtr
>(reqs
[inst
->getCurResSlot()]);
885 cache_req
= split_req
;
889 // Make a new packet inside the CacheRequest object
891 buildDataPacket(cache_req
);
893 // Special Handling for LL/SC or Compare/Swap
894 bool is_write
= cache_req
->dataPkt
->isWrite();
895 RequestPtr mem_req
= cache_req
->dataPkt
->req
;
897 DPRINTF(InOrderCachePort
,
898 "[tid:%u]: [sn:%i]: Storing data: %s\n",
900 printMemData(cache_req
->dataPkt
->getPtr
<uint8_t>(),
901 cache_req
->dataPkt
->getSize()));
903 if (mem_req
->isCondSwap()) {
905 cache_req
->memReq
->setExtraData(*write_res
);
907 if (mem_req
->isLLSC()) {
908 assert(cache_req
->inst
->isStoreConditional());
909 DPRINTF(InOrderCachePort
, "Evaluating Store Conditional access\n");
910 do_access
= TheISA::handleLockedWrite(cpu
, mem_req
);
914 // Finally, go ahead and make the access if we can...
915 DPRINTF(InOrderCachePort
,
916 "[tid:%i] [sn:%i] attempting to access cache for addr %08p\n",
917 tid
, inst
->seqNum
, cache_req
->dataPkt
->getAddr());
920 if (!cachePort
->sendTiming(cache_req
->dataPkt
)) {
921 DPRINTF(InOrderCachePort
,
922 "[tid:%i] [sn:%i] cannot access cache, because port "
923 "is blocked. now waiting to retry request\n", tid
,
925 delete cache_req
->dataPkt
;
926 cache_req
->dataPkt
= NULL
;
928 delete cache_req
->memReq
;
929 cache_req
->memReq
= NULL
;
931 cache_req
->done(false);
932 cachePortBlocked
= true;
934 DPRINTF(InOrderCachePort
,
935 "[tid:%i] [sn:%i] is now waiting for cache response\n",
937 cache_req
->setCompleted();
938 cache_req
->setMemAccPending();
939 cachePortBlocked
= false;
941 } else if (mem_req
->isLLSC()){
942 // Store-Conditional instructions complete even if they "failed"
943 assert(cache_req
->inst
->isStoreConditional());
944 cache_req
->setCompleted(true);
947 "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
950 processCacheCompletion(cache_req
->dataPkt
);
952 delete cache_req
->dataPkt
;
953 cache_req
->dataPkt
= NULL
;
955 delete cache_req
->memReq
;
956 cache_req
->memReq
= NULL
;
958 // Make cache request again since access due to
959 // inability to access
960 DPRINTF(InOrderStall
, "STALL: \n");
961 cache_req
->done(false);
967 CacheUnit::processSquash(CacheReqPacket
*cache_pkt
)
969 // The resource may no longer be actively servicing this
970 // packet. Scenarios like a store that has been sent to the
971 // memory system or access that's been squashed. If that's
972 // the case, we can't access the request slot because it
973 // will be either invalid or servicing another request.
974 if (!cache_pkt
->hasSlot
) {
975 DPRINTF(InOrderCachePort
,
976 "%x does not have a slot in unit, ignoring.\n",
977 cache_pkt
->getAddr());
979 if (cache_pkt
->reqData
) {
980 delete [] cache_pkt
->reqData
;
981 cache_pkt
->reqData
= NULL
;
984 if (cache_pkt
->memReq
) {
985 delete cache_pkt
->memReq
;
986 cache_pkt
->memReq
= NULL
;
994 DPRINTF(InOrderCachePort
, "%x has slot %i\n",
995 cache_pkt
->getAddr(), cache_pkt
->cacheReq
->getSlot());
999 // It's possible that the request is squashed but the
1000 // packet is still acknowledged by the resource. Squashes
1001 // should happen at the end of the cycles and trigger the
1002 // code above, but if not, this would handle any timing
1003 // variations due to diff. user parameters.
1004 if (cache_pkt
->cacheReq
->isSquashed()) {
1005 DPRINTF(InOrderCachePort
,
1006 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
1007 cache_pkt
->cacheReq
->getInst()->readTid(),
1008 cache_pkt
->cacheReq
->getInst()->seqNum
);
1010 cache_pkt
->cacheReq
->setMemAccPending(false);
1011 cache_pkt
->cacheReq
->freeSlot();
1023 CacheUnit::processCacheCompletion(PacketPtr pkt
)
1025 CacheReqPacket
* cache_pkt
= dynamic_cast<CacheReqPacket
*>(pkt
);
1028 DPRINTF(InOrderCachePort
, "Finished request for %x [pkt:%x->%x]\n",
1029 pkt
->getAddr(), &cache_pkt
, cache_pkt
);
1031 //@todo: process Squashed Completion
1032 if (processSquash(cache_pkt
))
1035 CacheRequest
*cache_req
= dynamic_cast<CacheReqPtr
>(
1036 findRequest(cache_pkt
->cacheReq
->getInst(), cache_pkt
->instIdx
));
1039 panic("[tid:%u]: [sn:%i]: Can't find slot for cache access to "
1040 "addr. %08p\n", cache_pkt
->cacheReq
->getInst()->readTid(),
1041 cache_pkt
->cacheReq
->getInst()->seqNum
,
1042 cache_pkt
->cacheReq
->getInst()->getMemAddr());
1046 assert(cache_req
== cache_pkt
->cacheReq
);
1048 DPRINTF(InOrderCachePort
,
1049 "[tid:%u]: [sn:%i]: [slot:%i] Waking from cache access (vaddr.%08p, paddr:%08p)\n",
1050 cache_pkt
->cacheReq
->getInst()->readTid(),
1051 cache_pkt
->cacheReq
->getInst()->seqNum
,
1052 cache_req
->getSlot(),
1053 cache_pkt
->req
->getVaddr(),
1054 cache_pkt
->req
->getPaddr());
1056 // Get resource request info
1057 unsigned stage_num
= cache_req
->getStageNum();
1058 DynInstPtr inst
= cache_req
->inst
;
1059 ThreadID tid
= cache_req
->inst
->readTid();
1061 assert(!cache_req
->isSquashed());
1062 assert(inst
->staticInst
&& inst
->isMemRef());
1065 DPRINTF(InOrderCachePort
,
1066 "[tid:%u]: [sn:%i]: Processing cache access\n",
1069 PacketPtr split_pkt
= NULL
;
1070 if (inst
->splitInst
) {
1071 inst
->splitFinishCnt
++;
1073 if (inst
->splitFinishCnt
== 2) {
1074 cache_req
->memReq
->setVirt(0/*inst->tid*/,
1080 split_pkt
= new Packet(cache_req
->memReq
, cache_req
->pktCmd
,
1082 split_pkt
->dataStatic(inst
->splitMemData
);
1084 DPRINTF(InOrderCachePort
, "Completing Split Access.\n");
1085 inst
->completeAcc(split_pkt
);
1088 inst
->completeAcc(cache_pkt
);
1091 inst
->setExecuted();
1093 if (inst
->isLoad()) {
1094 assert(cache_pkt
->isRead());
1096 if (cache_pkt
->req
->isLLSC()) {
1097 DPRINTF(InOrderCachePort
,
1098 "[tid:%u]: Handling Load-Linked for [sn:%u]\n",
1100 TheISA::handleLockedRead(cpu
, cache_pkt
->req
);
1103 DPRINTF(InOrderCachePort
,
1104 "[tid:%u]: [sn:%i]: Bytes loaded were: %s\n",
1106 (split_pkt
) ? printMemData(split_pkt
->getPtr
<uint8_t>(),
1107 split_pkt
->getSize()) :
1108 printMemData(cache_pkt
->getPtr
<uint8_t>(),
1109 cache_pkt
->getSize()));
1110 } else if(inst
->isStore()) {
1111 assert(cache_pkt
->isWrite());
1113 DPRINTF(InOrderCachePort
,
1114 "[tid:%u]: [sn:%i]: Bytes stored were: %s\n",
1116 (split_pkt
) ? printMemData(split_pkt
->getPtr
<uint8_t>(),
1117 split_pkt
->getSize()) :
1118 printMemData(cache_pkt
->getPtr
<uint8_t>(),
1119 cache_pkt
->getSize()));
1122 DPRINTF(InOrderCachePort
, "Deleting packets %x (%x).\n",
1123 cache_pkt
, cache_req
->dataPkt
);
1130 cache_req
->setMemAccPending(false);
1131 cache_req
->setMemAccCompleted();
1133 if (cache_req
->isMemStall() &&
1134 cpu
->threadModel
== InOrderCPU::SwitchOnCacheMiss
) {
1135 DPRINTF(InOrderCachePort
, "[tid:%u] Waking up from Cache Miss.\n",
1138 cpu
->activateContext(tid
);
1140 DPRINTF(ThreadModel
, "Activating [tid:%i] after return from cache"
1144 // Wake up the CPU (if it went to sleep and was waiting on this
1145 // completion event).
1148 DPRINTF(Activity
, "[tid:%u] Activating %s due to cache completion\n",
1149 tid
, cpu
->pipelineStage
[stage_num
]->name());
1151 cpu
->switchToActive(stage_num
);
1155 CacheUnit::recvRetry()
1157 DPRINTF(InOrderCachePort
, "Unblocking Cache Port. \n");
1159 assert(cachePortBlocked
);
1161 // Clear the cache port for use again
1162 cachePortBlocked
= false;
1167 CacheUnitEvent::CacheUnitEvent()
1172 CacheUnitEvent::process()
1174 DynInstPtr inst
= resource
->reqs
[slotIdx
]->inst
;
1175 int stage_num
= resource
->reqs
[slotIdx
]->getStageNum();
1176 ThreadID tid
= inst
->threadNumber
;
1177 CacheReqPtr req_ptr
= dynamic_cast<CacheReqPtr
>(resource
->reqs
[slotIdx
]);
1179 DPRINTF(InOrderTLB
, "Waking up from TLB Miss caused by [sn:%i].\n",
1182 CacheUnit
* tlb_res
= dynamic_cast<CacheUnit
*>(resource
);
1185 //@todo: eventually, we should do a timing translation w/
1186 // hw page table walk on tlb miss
1187 DPRINTF(Fault
, "Handling Fault %s : [sn:%i] %x\n", inst
->fault
->name(), inst
->seqNum
, inst
->getMemAddr());
1188 inst
->fault
->invoke(tlb_res
->cpu
->tcBase(tid
), inst
->staticInst
);
1190 tlb_res
->tlbBlocked
[tid
] = false;
1192 tlb_res
->cpu
->pipelineStage
[stage_num
]->
1193 unsetResStall(tlb_res
->reqs
[slotIdx
], tid
);
1195 req_ptr
->tlbStall
= false;
1197 //@todo: timing translation needs to have some type of independent
1198 // info regarding if it's squashed or not so we can
1199 // free up the resource if a request gets squashed in the middle
1201 if (req_ptr
->isSquashed()) {
1202 req_ptr
->freeSlot();
1205 tlb_res
->cpu
->wakeCPU();
1209 CacheUnit::squashDueToMemStall(DynInstPtr inst
, int stage_num
,
1210 InstSeqNum squash_seq_num
, ThreadID tid
)
1212 // If squashing due to memory stall, then we do NOT want to
1213 // squash the instruction that caused the stall so we
1214 // increment the sequence number here to prevent that.
1216 // NOTE: This is only for the SwitchOnCacheMiss Model
1217 // NOTE: If you have multiple outstanding misses from the same
1218 // thread then you need to reevaluate this code
1219 // NOTE: squash should originate from
1220 // pipeline_stage.cc:processInstSchedule
1221 DPRINTF(InOrderCachePort
, "Squashing above [sn:%u]\n",
1222 squash_seq_num
+ 1);
1224 squash(inst
, stage_num
, squash_seq_num
+ 1, tid
);
1228 CacheUnit::squashCacheRequest(CacheReqPtr req_ptr
)
1230 DynInstPtr inst
= req_ptr
->getInst();
1231 req_ptr
->setSquashed();
1232 inst
->setSquashed();
1234 //@note: add back in for speculative load/store capability
1235 /*if (inst->validMemAddr()) {
1236 DPRINTF(AddrDep, "Squash of [tid:%i] [sn:%i], attempting to "
1237 "remove addr. %08p dependencies.\n",
1240 inst->getMemAddr());
1242 removeAddrDependency(inst);
1248 CacheUnit::squash(DynInstPtr inst
, int stage_num
,
1249 InstSeqNum squash_seq_num
, ThreadID tid
)
1251 if (tlbBlockSeqNum
[tid
] &&
1252 tlbBlockSeqNum
[tid
] > squash_seq_num
) {
1253 DPRINTF(InOrderCachePort
, "Releasing TLB Block due to "
1254 " squash after [sn:%i].\n", squash_seq_num
);
1255 tlbBlocked
[tid
] = false;
1258 for (int i
= 0; i
< width
; i
++) {
1259 ResReqPtr req_ptr
= reqs
[i
];
1261 if (req_ptr
->valid
&&
1262 req_ptr
->getInst()->readTid() == tid
&&
1263 req_ptr
->getInst()->seqNum
> squash_seq_num
) {
1265 DPRINTF(InOrderCachePort
,
1266 "[tid:%i] Squashing request from [sn:%i]\n",
1267 req_ptr
->getInst()->readTid(), req_ptr
->getInst()->seqNum
);
1269 if (req_ptr
->isSquashed()) {
1270 DPRINTF(AddrDep
, "Request for [tid:%i] [sn:%i] already "
1271 "squashed, ignoring squash process.\n",
1272 req_ptr
->getInst()->readTid(),
1273 req_ptr
->getInst()->seqNum
);
1277 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(req_ptr
);
1280 squashCacheRequest(cache_req
);
1282 int req_slot_num
= req_ptr
->getSlot();
1284 if (cache_req
->tlbStall
) {
1285 tlbBlocked
[tid
] = false;
1287 int stall_stage
= reqs
[req_slot_num
]->getStageNum();
1289 cpu
->pipelineStage
[stall_stage
]->
1290 unsetResStall(reqs
[req_slot_num
], tid
);
1293 if (cache_req
->isMemAccPending()) {
1294 cache_req
->dataPkt
->reqData
= cache_req
->reqData
;
1295 cache_req
->dataPkt
->memReq
= cache_req
->memReq
;
1298 if (!cache_req
->tlbStall
)
1299 freeSlot(req_slot_num
);
1306 CacheRequest::clearRequest()
1308 if (!memAccPending
) {
1309 if (reqData
&& !splitAccess
)
1313 DPRINTF(InOrderCachePort
, "Clearing request for %x...%x\n",
1314 memReq
->getVaddr(), (memReq
->hasPaddr()) ? memReq
->getPaddr() : 0);
1322 dataPkt
->hasSlot
= false;
1323 DPRINTF(InOrderCachePort
, "[slot:%i]: Slot unmarked for %x for [pkt:%x->%x]\n",
1324 getSlot(), dataPkt
->getAddr(), &dataPkt
, dataPkt
);
1331 memAccComplete
= false;
1332 memAccPending
= false;
1334 splitAccess
= false;
1335 splitAccessNum
= -1;
1336 split2ndAccess
= false;
1338 fetchBufferFill
= false;
1340 ResourceRequest::clearRequest();