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/utility.hh"
38 #include "arch/predecoder.hh"
39 #include "config/the_isa.hh"
40 #include "cpu/inorder/resources/cache_unit.hh"
41 #include "cpu/inorder/pipeline_traits.hh"
42 #include "cpu/inorder/cpu.hh"
43 #include "cpu/inorder/resource_pool.hh"
44 #include "mem/request.hh"
47 using namespace TheISA
;
48 using namespace ThePipeline
;
51 CacheUnit::CachePort::recvAtomic(PacketPtr pkt
)
53 panic("CacheUnit::CachePort doesn't expect recvAtomic callback!");
58 CacheUnit::CachePort::recvFunctional(PacketPtr pkt
)
60 panic("CacheUnit::CachePort doesn't expect recvFunctional callback!");
64 CacheUnit::CachePort::recvStatusChange(Status status
)
66 if (status
== RangeChange
)
69 panic("CacheUnit::CachePort doesn't expect recvStatusChange callback!");
73 CacheUnit::CachePort::recvTiming(Packet
*pkt
)
75 cachePortUnit
->processCacheCompletion(pkt
);
80 CacheUnit::CachePort::recvRetry()
82 cachePortUnit
->recvRetry();
85 CacheUnit::CacheUnit(string res_name
, int res_id
, int res_width
,
86 int res_latency
, InOrderCPU
*_cpu
, ThePipeline::Params
*params
)
87 : Resource(res_name
, res_id
, res_width
, res_latency
, _cpu
),
88 cachePortBlocked(false), predecoder(NULL
)
90 cachePort
= new CachePort(this);
92 // Hard-Code Selection For Now
93 if (res_name
== "icache_port")
95 else if (res_name
== "dcache_port")
98 fatal("Unrecognized TLB name passed by user");
100 for (int i
=0; i
< MaxThreads
; i
++) {
101 tlbBlocked
[i
] = false;
113 CacheUnit::getPort(const string
&if_name
, int idx
)
115 if (if_name
== resName
)
124 // Currently Used to Model TLB Latency. Eventually
125 // Switch to Timing TLB translations.
126 resourceEvent
= new CacheUnitEvent
[width
];
132 CacheUnit::getSlot(DynInstPtr inst
)
134 ThreadID tid
= inst
->readTid();
136 if (tlbBlocked
[inst
->threadNumber
]) {
140 // For a Split-Load, the instruction would have processed once already
141 // causing the address to be unset.
142 if (!inst
->validMemAddr() && !inst
->splitInst
) {
143 panic("[tid:%i][sn:%i] Mem. Addr. must be set before requesting cache access\n",
144 inst
->readTid(), inst
->seqNum
);
147 Addr req_addr
= inst
->getMemAddr();
149 if (resName
== "icache_port" ||
150 find(addrList
[tid
].begin(), addrList
[tid
].end(), req_addr
) ==
151 addrList
[tid
].end()) {
153 int new_slot
= Resource::getSlot(inst
);
158 inst
->memTime
= curTick
;
159 setAddrDependency(inst
);
162 // Allow same instruction multiple accesses to same address
163 // should only happen maybe after a squashed inst. needs to replay
164 if (addrMap
[tid
][req_addr
] == inst
->seqNum
) {
165 int new_slot
= Resource::getSlot(inst
);
172 DPRINTF(InOrderCachePort
,
173 "[tid:%i] Denying request because there is an outstanding"
174 " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
175 inst
->readTid(), req_addr
, addrMap
[tid
][req_addr
], inst
->memTime
);
184 CacheUnit::setAddrDependency(DynInstPtr inst
)
186 Addr req_addr
= inst
->getMemAddr();
187 ThreadID tid
= inst
->readTid();
189 addrList
[tid
].push_back(req_addr
);
190 addrMap
[tid
][req_addr
] = inst
->seqNum
;
193 "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n",
194 inst
->readTid(), inst
->seqNum
, req_addr
);
196 //@NOTE: 10 is an arbitrarily "high" number here, but to be exact
197 // we would need to know the # of outstanding accesses
198 // a priori. Information like fetch width, stage width,
199 // and the branch resolution stage would be useful for the
200 // icache_port (among other things). For the dcache, the #
201 // of outstanding cache accesses might be sufficient.
202 assert(addrList
[tid
].size() < 10);
206 CacheUnit::removeAddrDependency(DynInstPtr inst
)
208 ThreadID tid
= inst
->readTid();
210 Addr mem_addr
= inst
->getMemAddr();
212 inst
->unsetMemAddr();
214 // Erase from Address List
215 vector
<Addr
>::iterator vect_it
= find(addrList
[tid
].begin(), addrList
[tid
].end(),
217 assert(vect_it
!= addrList
[tid
].end() || inst
->splitInst
);
219 if (vect_it
!= addrList
[tid
].end()) {
221 "[tid:%i]: [sn:%i] Address %08p removed from dependency list\n",
222 inst
->readTid(), inst
->seqNum
, (*vect_it
));
224 addrList
[tid
].erase(vect_it
);
226 // Erase From Address Map (Used for Debugging)
227 addrMap
[tid
].erase(addrMap
[tid
].find(mem_addr
));
234 CacheUnit::findRequest(DynInstPtr inst
)
236 map
<int, ResReqPtr
>::iterator map_it
= reqMap
.begin();
237 map
<int, ResReqPtr
>::iterator map_end
= reqMap
.end();
239 while (map_it
!= map_end
) {
240 CacheRequest
* cache_req
= dynamic_cast<CacheRequest
*>((*map_it
).second
);
244 cache_req
->getInst() == inst
&&
245 cache_req
->instIdx
== inst
->resSched
.top()->idx
) {
255 CacheUnit::findSplitRequest(DynInstPtr inst
, int idx
)
257 map
<int, ResReqPtr
>::iterator map_it
= reqMap
.begin();
258 map
<int, ResReqPtr
>::iterator map_end
= reqMap
.end();
260 while (map_it
!= map_end
) {
261 CacheRequest
* cache_req
= dynamic_cast<CacheRequest
*>((*map_it
).second
);
265 cache_req
->getInst() == inst
&&
266 cache_req
->instIdx
== idx
) {
277 CacheUnit::getRequest(DynInstPtr inst
, int stage_num
, int res_idx
,
278 int slot_num
, unsigned cmd
)
280 ScheduleEntry
* sched_entry
= inst
->resSched
.top();
282 if (!inst
->validMemAddr()) {
283 panic("Mem. Addr. must be set before requesting cache access\n");
286 MemCmd::Command pkt_cmd
;
288 switch (sched_entry
->cmd
)
290 case InitSecondSplitRead
:
291 pkt_cmd
= MemCmd::ReadReq
;
293 DPRINTF(InOrderCachePort
,
294 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
295 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
298 case InitiateReadData
:
299 pkt_cmd
= MemCmd::ReadReq
;
301 DPRINTF(InOrderCachePort
,
302 "[tid:%i]: Read request from [sn:%i] for addr %08p\n",
303 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
306 case InitSecondSplitWrite
:
307 pkt_cmd
= MemCmd::WriteReq
;
309 DPRINTF(InOrderCachePort
,
310 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
311 inst
->readTid(), inst
->seqNum
, inst
->split2ndAddr
);
314 case InitiateWriteData
:
315 pkt_cmd
= MemCmd::WriteReq
;
317 DPRINTF(InOrderCachePort
,
318 "[tid:%i]: Write request from [sn:%i] for addr %08p\n",
319 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
323 pkt_cmd
= MemCmd::ReadReq
;
325 DPRINTF(InOrderCachePort
,
326 "[tid:%i]: Fetch request from [sn:%i] for addr %08p\n",
327 inst
->readTid(), inst
->seqNum
, inst
->getMemAddr());
331 panic("%i: Unexpected request type (%i) to %s", curTick
,
332 sched_entry
->cmd
, name());
335 return new CacheRequest(this, inst
, stage_num
, id
, slot_num
,
336 sched_entry
->cmd
, 0, pkt_cmd
,
337 0/*flags*/, this->cpu
->readCpuId(),
338 inst
->resSched
.top()->idx
);
342 CacheUnit::requestAgain(DynInstPtr inst
, bool &service_request
)
344 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
347 // Check to see if this instruction is requesting the same command
348 // or a different one
349 if (cache_req
->cmd
!= inst
->resSched
.top()->cmd
&&
350 cache_req
->instIdx
== inst
->resSched
.top()->idx
) {
351 // If different, then update command in the request
352 cache_req
->cmd
= inst
->resSched
.top()->cmd
;
353 DPRINTF(InOrderCachePort
,
354 "[tid:%i]: [sn:%i]: Updating the command for this "
355 "instruction\n ", inst
->readTid(), inst
->seqNum
);
357 service_request
= true;
358 } else if (inst
->resSched
.top()->idx
!= CacheUnit::InitSecondSplitRead
&&
359 inst
->resSched
.top()->idx
!= CacheUnit::InitSecondSplitWrite
) {
360 // If same command, just check to see if memory access was completed
361 // but dont try to re-execute
362 DPRINTF(InOrderCachePort
,
363 "[tid:%i]: [sn:%i]: requesting this resource again\n",
364 inst
->readTid(), inst
->seqNum
);
366 service_request
= true;
371 CacheUnit::doTLBAccess(DynInstPtr inst
, CacheReqPtr cache_req
, int acc_size
,
372 int flags
, TheISA::TLB::Mode tlb_mode
)
374 ThreadID tid
= inst
->readTid();
375 Addr aligned_addr
= inst
->getMemAddr();
376 unsigned stage_num
= cache_req
->getStageNum();
377 unsigned slot_idx
= cache_req
->getSlot();
379 if (tlb_mode
== TheISA::TLB::Execute
) {
380 inst
->fetchMemReq
= new Request(inst
->readTid(), aligned_addr
,
381 acc_size
, flags
, inst
->readPC(),
382 cpu
->readCpuId(), inst
->readTid());
383 cache_req
->memReq
= inst
->fetchMemReq
;
385 if (!cache_req
->is2ndSplit()) {
386 inst
->dataMemReq
= new Request(cpu
->asid
[tid
], aligned_addr
,
387 acc_size
, flags
, inst
->readPC(),
388 cpu
->readCpuId(), inst
->readTid());
389 cache_req
->memReq
= inst
->dataMemReq
;
391 assert(inst
->splitInst
);
393 inst
->splitMemReq
= new Request(cpu
->asid
[tid
],
400 cache_req
->memReq
= inst
->splitMemReq
;
406 _tlb
->translateAtomic(cache_req
->memReq
,
407 cpu
->thread
[tid
]->getTC(), tlb_mode
);
409 if (cache_req
->fault
!= NoFault
) {
410 DPRINTF(InOrderTLB
, "[tid:%i]: %s encountered while translating "
411 "addr:%08p for [sn:%i].\n", tid
, cache_req
->fault
->name(),
412 cache_req
->memReq
->getVaddr(), inst
->seqNum
);
414 cpu
->pipelineStage
[stage_num
]->setResStall(cache_req
, tid
);
416 tlbBlocked
[tid
] = true;
418 cache_req
->tlbStall
= true;
420 scheduleEvent(slot_idx
, 1);
422 cpu
->trap(cache_req
->fault
, tid
);
424 DPRINTF(InOrderTLB
, "[tid:%i]: [sn:%i] virt. addr %08p translated "
425 "to phys. addr:%08p.\n", tid
, inst
->seqNum
,
426 cache_req
->memReq
->getVaddr(),
427 cache_req
->memReq
->getPaddr());
430 return cache_req
->fault
;
435 CacheUnit::read(DynInstPtr inst
, Addr addr
, T
&data
, unsigned flags
)
437 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
438 assert(cache_req
&& "Can't Find Instruction for Read!");
440 // The block size of our peer
441 unsigned blockSize
= this->cachePort
->peerBlockSize();
443 //The size of the data we're trying to read.
444 int dataSize
= sizeof(T
);
446 if (inst
->split2ndAccess
) {
447 dataSize
= inst
->split2ndSize
;
448 cache_req
->splitAccess
= true;
449 cache_req
->split2ndAccess
= true;
451 DPRINTF(InOrderCachePort
, "[sn:%i] Split Read Access (2 of 2) for (%#x, %#x).\n", inst
->seqNum
,
452 inst
->getMemAddr(), inst
->split2ndAddr
);
456 //The address of the second part of this access if it needs to be split
457 //across a cache line boundary.
458 Addr secondAddr
= roundDown(addr
+ dataSize
- 1, blockSize
);
461 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
462 DPRINTF(InOrderCachePort
, "%i: sn[%i] Split Read Access (1 of 2) for (%#x, %#x).\n", curTick
, inst
->seqNum
,
465 // Save All "Total" Split Information
466 // ==============================
467 inst
->splitInst
= true;
468 inst
->splitMemData
= new uint8_t[dataSize
];
469 inst
->splitTotalSize
= dataSize
;
471 if (!inst
->splitInstSked
) {
472 // Schedule Split Read/Complete for Instruction
473 // ==============================
474 int stage_num
= cache_req
->getStageNum();
476 int stage_pri
= ThePipeline::getNextPriority(inst
, stage_num
);
478 inst
->resSched
.push(new ScheduleEntry(stage_num
,
480 cpu
->resPool
->getResIdx(DCache
),
481 CacheUnit::InitSecondSplitRead
,
485 inst
->resSched
.push(new ScheduleEntry(stage_num
+ 1,
487 cpu
->resPool
->getResIdx(DCache
),
488 CacheUnit::CompleteSecondSplitRead
,
491 inst
->splitInstSked
= true;
493 DPRINTF(InOrderCachePort
, "[tid:%i] [sn:%i] Retrying Split Read Access (1 of 2) for (%#x, %#x).\n",
494 inst
->readTid(), inst
->seqNum
, addr
, secondAddr
);
497 // Split Information for First Access
498 // ==============================
499 dataSize
= secondAddr
- addr
;
500 cache_req
->splitAccess
= true;
502 // Split Information for Second Access
503 // ==============================
504 inst
->split2ndSize
= addr
+ sizeof(T
) - secondAddr
;
505 inst
->split2ndAddr
= secondAddr
;
506 inst
->split2ndDataPtr
= inst
->splitMemData
+ dataSize
;
507 inst
->split2ndFlags
= flags
;
510 doTLBAccess(inst
, cache_req
, dataSize
, flags
, TheISA::TLB::Read
);
512 if (cache_req
->fault
== NoFault
) {
513 if (!cache_req
->splitAccess
) {
514 cache_req
->reqData
= new uint8_t[dataSize
];
515 doCacheAccess(inst
, NULL
);
517 if (!inst
->split2ndAccess
) {
518 cache_req
->reqData
= inst
->splitMemData
;
520 cache_req
->reqData
= inst
->split2ndDataPtr
;
523 doCacheAccess(inst
, NULL
, cache_req
);
527 return cache_req
->fault
;
532 CacheUnit::write(DynInstPtr inst
, T data
, Addr addr
, unsigned flags
,
535 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(findRequest(inst
));
536 assert(cache_req
&& "Can't Find Instruction for Write!");
538 // The block size of our peer
539 unsigned blockSize
= this->cachePort
->peerBlockSize();
541 //The size of the data we're trying to read.
542 int dataSize
= sizeof(T
);
544 if (inst
->split2ndAccess
) {
545 dataSize
= inst
->split2ndSize
;
546 cache_req
->splitAccess
= true;
547 cache_req
->split2ndAccess
= true;
549 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (2 of 2) for (%#x, %#x).\n", inst
->seqNum
,
550 inst
->getMemAddr(), inst
->split2ndAddr
);
553 //The address of the second part of this access if it needs to be split
554 //across a cache line boundary.
555 Addr secondAddr
= roundDown(addr
+ dataSize
- 1, blockSize
);
557 if (secondAddr
> addr
&& !inst
->split2ndAccess
) {
559 DPRINTF(InOrderCachePort
, "[sn:%i] Split Write Access (1 of 2) for (%#x, %#x).\n", inst
->seqNum
,
562 // Save All "Total" Split Information
563 // ==============================
564 inst
->splitInst
= true;
565 inst
->splitTotalSize
= dataSize
;
567 if (!inst
->splitInstSked
) {
568 // Schedule Split Read/Complete for Instruction
569 // ==============================
570 int stage_num
= cache_req
->getStageNum();
572 int stage_pri
= ThePipeline::getNextPriority(inst
, stage_num
);
574 inst
->resSched
.push(new ScheduleEntry(stage_num
,
576 cpu
->resPool
->getResIdx(DCache
),
577 CacheUnit::InitSecondSplitWrite
,
581 inst
->resSched
.push(new ScheduleEntry(stage_num
+ 1,
583 cpu
->resPool
->getResIdx(DCache
),
584 CacheUnit::CompleteSecondSplitWrite
,
587 inst
->splitInstSked
= true;
589 DPRINTF(InOrderCachePort
, "[tid:%i] sn:%i] Retrying Split Read Access (1 of 2) for (%#x, %#x).\n",
590 inst
->readTid(), inst
->seqNum
, addr
, secondAddr
);
595 // Split Information for First Access
596 // ==============================
597 dataSize
= secondAddr
- addr
;
598 cache_req
->splitAccess
= true;
600 // Split Information for Second Access
601 // ==============================
602 inst
->split2ndSize
= addr
+ sizeof(T
) - secondAddr
;
603 inst
->split2ndAddr
= secondAddr
;
604 inst
->split2ndStoreDataPtr
= &cache_req
->inst
->storeData
;
605 inst
->split2ndStoreDataPtr
+= dataSize
;
606 inst
->split2ndFlags
= flags
;
607 inst
->splitInstSked
= true;
610 doTLBAccess(inst
, cache_req
, dataSize
, flags
, TheISA::TLB::Write
);
612 if (cache_req
->fault
== NoFault
) {
613 if (!cache_req
->splitAccess
) {
614 // Remove this line since storeData is saved in INST?
615 cache_req
->reqData
= new uint8_t[dataSize
];
616 doCacheAccess(inst
, write_res
);
618 doCacheAccess(inst
, write_res
, cache_req
);
623 return cache_req
->fault
;
628 CacheUnit::execute(int slot_num
)
630 if (cachePortBlocked
) {
631 DPRINTF(InOrderCachePort
, "Cache Port Blocked. Cannot Access\n");
635 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(reqMap
[slot_num
]);
638 DynInstPtr inst
= cache_req
->inst
;
640 ThreadID tid
= inst
->readTid();
641 int seq_num
= inst
->seqNum
;
642 std::string acc_type
= "write";
646 cache_req
->fault
= NoFault
;
648 switch (cache_req
->cmd
)
652 //@TODO: Switch to size of full cache block. Store in fetch buffer
653 int acc_size
= sizeof(TheISA::MachInst
);
655 doTLBAccess(inst
, cache_req
, acc_size
, 0, TheISA::TLB::Execute
);
657 // Only Do Access if no fault from TLB
658 if (cache_req
->fault
== NoFault
) {
660 DPRINTF(InOrderCachePort
,
661 "[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
662 tid
, name(), cache_req
->inst
->getMemAddr());
664 cache_req
->reqData
= new uint8_t[acc_size
];
666 inst
->setCurResSlot(slot_num
);
674 case InitiateReadData
:
678 case InitiateWriteData
:
680 DPRINTF(InOrderCachePort
,
681 "[tid:%u]: [sn:%i] Initiating data %s access to %s for addr. %08p\n",
682 tid
, inst
->seqNum
, acc_type
, name(), cache_req
->inst
->getMemAddr());
684 inst
->setCurResSlot(slot_num
);
686 if (inst
->isDataPrefetch() || inst
->isInstPrefetch()) {
694 case InitSecondSplitRead
:
695 DPRINTF(InOrderCachePort
,
696 "[tid:%u]: [sn:%i] Initiating split data read access to %s for addr. %08p\n",
697 tid
, inst
->seqNum
, name(), cache_req
->inst
->split2ndAddr
);
698 inst
->split2ndAccess
= true;
699 assert(inst
->split2ndAddr
!= 0);
700 read(inst
, inst
->split2ndAddr
, inst
->split2ndData
, inst
->split2ndFlags
);
703 case InitSecondSplitWrite
:
704 DPRINTF(InOrderCachePort
,
705 "[tid:%u]: [sn:%i] Initiating split data write access to %s for addr. %08p\n",
706 tid
, inst
->seqNum
, name(), cache_req
->inst
->getMemAddr());
708 inst
->split2ndAccess
= true;
709 assert(inst
->split2ndAddr
!= 0);
710 write(inst
, inst
->split2ndAddr
, inst
->split2ndData
, inst
->split2ndFlags
, NULL
);
715 if (cache_req
->isMemAccComplete()) {
716 DPRINTF(InOrderCachePort
,
717 "[tid:%i]: Completing Fetch Access for [sn:%i]\n",
721 DPRINTF(InOrderCachePort
, "[tid:%i]: Instruction [sn:%i] is: %s\n",
722 tid
, seq_num
, inst
->staticInst
->disassemble(inst
->PC
));
724 removeAddrDependency(inst
);
726 delete cache_req
->dataPkt
;
728 // Do not stall and switch threads for fetch... for now..
729 // TODO: We need to detect cache misses for latencies > 1
730 // cache_req->setMemStall(false);
734 DPRINTF(InOrderCachePort
,
735 "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n",
737 DPRINTF(InOrderStall
,
738 "STALL: [tid:%i]: Fetch miss from %08p\n",
739 tid
, cache_req
->inst
->readPC());
740 cache_req
->setCompleted(false);
741 //cache_req->setMemStall(true);
745 case CompleteReadData
:
746 case CompleteWriteData
:
747 DPRINTF(InOrderCachePort
,
748 "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
751 if (cache_req
->isMemAccComplete() ||
752 inst
->isDataPrefetch() ||
753 inst
->isInstPrefetch()) {
754 removeAddrDependency(inst
);
755 cache_req
->setMemStall(false);
758 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
759 tid
, cache_req
->inst
->getMemAddr());
760 cache_req
->setCompleted(false);
761 cache_req
->setMemStall(true);
765 case CompleteSecondSplitRead
:
766 DPRINTF(InOrderCachePort
,
767 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Read Access\n",
770 if (cache_req
->isMemAccComplete() ||
771 inst
->isDataPrefetch() ||
772 inst
->isInstPrefetch()) {
773 removeAddrDependency(inst
);
774 cache_req
->setMemStall(false);
777 DPRINTF(InOrderStall
, "STALL: [tid:%i]: Data miss from %08p\n",
778 tid
, cache_req
->inst
->split2ndAddr
);
779 cache_req
->setCompleted(false);
780 cache_req
->setMemStall(true);
784 case CompleteSecondSplitWrite
:
785 DPRINTF(InOrderCachePort
,
786 "[tid:%i]: [sn:%i]: Trying to Complete Split Data Write Access\n",
789 if (cache_req
->isMemAccComplete() ||
790 inst
->isDataPrefetch() ||
791 inst
->isInstPrefetch()) {
792 removeAddrDependency(inst
);
793 cache_req
->setMemStall(false);
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);
804 fatal("Unrecognized command to %s", resName
);
809 CacheUnit::prefetch(DynInstPtr inst
)
811 warn_once("Prefetching currently unimplemented");
813 CacheReqPtr cache_req
814 = dynamic_cast<CacheReqPtr
>(reqMap
[inst
->getCurResSlot()]);
817 // Clean-Up cache resource request so
818 // other memory insts. can use them
819 cache_req
->setCompleted();
820 cachePortBlocked
= false;
821 cache_req
->setMemAccPending(false);
822 cache_req
->setMemAccCompleted();
823 inst
->unsetMemAddr();
828 CacheUnit::writeHint(DynInstPtr inst
)
830 warn_once("Write Hints currently unimplemented");
832 CacheReqPtr cache_req
833 = dynamic_cast<CacheReqPtr
>(reqMap
[inst
->getCurResSlot()]);
836 // Clean-Up cache resource request so
837 // other memory insts. can use them
838 cache_req
->setCompleted();
839 cachePortBlocked
= false;
840 cache_req
->setMemAccPending(false);
841 cache_req
->setMemAccCompleted();
842 inst
->unsetMemAddr();
845 // @TODO: Split into doCacheRead() and doCacheWrite()
847 CacheUnit::doCacheAccess(DynInstPtr inst
, uint64_t *write_res
, CacheReqPtr split_req
)
849 Fault fault
= NoFault
;
851 ThreadID tid
= inst
->readTid();
854 CacheReqPtr cache_req
;
856 if (split_req
== NULL
) {
857 cache_req
= dynamic_cast<CacheReqPtr
>(reqMap
[inst
->getCurResSlot()]);
859 cache_req
= split_req
;
864 // Check for LL/SC and if so change command
865 if (cache_req
->memReq
->isLLSC() && cache_req
->pktCmd
== MemCmd::ReadReq
) {
866 cache_req
->pktCmd
= MemCmd::LoadLockedReq
;
869 if (cache_req
->pktCmd
== MemCmd::WriteReq
) {
871 cache_req
->memReq
->isSwap() ? MemCmd::SwapReq
:
872 (cache_req
->memReq
->isLLSC() ? MemCmd::StoreCondReq
876 cache_req
->dataPkt
= new CacheReqPacket(cache_req
, cache_req
->pktCmd
,
877 Packet::Broadcast
, cache_req
->instIdx
);
879 if (cache_req
->dataPkt
->isRead()) {
880 cache_req
->dataPkt
->dataStatic(cache_req
->reqData
);
881 } else if (cache_req
->dataPkt
->isWrite()) {
882 if (inst
->split2ndAccess
) {
883 cache_req
->dataPkt
->dataStatic(inst
->split2ndStoreDataPtr
);
885 cache_req
->dataPkt
->dataStatic(&cache_req
->inst
->storeData
);
888 if (cache_req
->memReq
->isCondSwap()) {
890 cache_req
->memReq
->setExtraData(*write_res
);
894 bool do_access
= true; // flag to suppress cache access
896 Request
*memReq
= cache_req
->dataPkt
->req
;
898 if (cache_req
->dataPkt
->isWrite() && cache_req
->memReq
->isLLSC()) {
899 assert(cache_req
->inst
->isStoreConditional());
900 DPRINTF(InOrderCachePort
, "Evaluating Store Conditional access\n");
901 do_access
= TheISA::handleLockedWrite(cpu
, memReq
);
904 DPRINTF(InOrderCachePort
,
905 "[tid:%i] [sn:%i] attempting to access cache\n",
909 if (!cachePort
->sendTiming(cache_req
->dataPkt
)) {
910 DPRINTF(InOrderCachePort
,
911 "[tid:%i] [sn:%i] cannot access cache, because port "
912 "is blocked. now waiting to retry request\n", tid
,
914 cache_req
->setCompleted(false);
915 cachePortBlocked
= true;
917 DPRINTF(InOrderCachePort
,
918 "[tid:%i] [sn:%i] is now waiting for cache response\n",
920 cache_req
->setCompleted();
921 cache_req
->setMemAccPending();
922 cachePortBlocked
= false;
924 } else if (!do_access
&& memReq
->isLLSC()){
925 // Store-Conditional instructions complete even if they "failed"
926 assert(cache_req
->inst
->isStoreConditional());
927 cache_req
->setCompleted(true);
930 "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
933 processCacheCompletion(cache_req
->dataPkt
);
935 // Make cache request again since access due to
936 // inability to access
937 DPRINTF(InOrderStall
, "STALL: \n");
938 cache_req
->setCompleted(false);
945 CacheUnit::processCacheCompletion(PacketPtr pkt
)
947 // Cast to correct packet type
948 CacheReqPacket
* cache_pkt
= dynamic_cast<CacheReqPacket
*>(pkt
);
952 if (cache_pkt
->cacheReq
->isSquashed()) {
953 DPRINTF(InOrderCachePort
,
954 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
955 cache_pkt
->cacheReq
->getInst()->readTid(),
956 cache_pkt
->cacheReq
->getInst()->seqNum
);
958 "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
959 cache_pkt
->cacheReq
->getTid(),
960 cache_pkt
->cacheReq
->seqNum
);
962 cache_pkt
->cacheReq
->done();
970 DPRINTF(InOrderCachePort
,
971 "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n",
972 cache_pkt
->cacheReq
->getInst()->readTid(),
973 cache_pkt
->cacheReq
->getInst()->seqNum
,
974 cache_pkt
->cacheReq
->getInst()->getMemAddr());
976 // Cast to correct request type
977 CacheRequest
*cache_req
= dynamic_cast<CacheReqPtr
>(
978 findSplitRequest(cache_pkt
->cacheReq
->getInst(), cache_pkt
->instIdx
));
982 "[tid:%u]: [sn:%i]: Can't find slot for cache access to addr. %08p\n",
983 cache_pkt
->cacheReq
->getInst()->readTid(),
984 cache_pkt
->cacheReq
->getInst()->seqNum
,
985 cache_pkt
->cacheReq
->getInst()->getMemAddr());
991 // Get resource request info
992 unsigned stage_num
= cache_req
->getStageNum();
993 DynInstPtr inst
= cache_req
->inst
;
994 ThreadID tid
= cache_req
->inst
->readTid();
996 if (!cache_req
->isSquashed()) {
997 if (inst
->resSched
.top()->cmd
== CompleteFetch
) {
998 DPRINTF(InOrderCachePort
,
999 "[tid:%u]: [sn:%i]: Processing fetch access\n",
1002 // NOTE: This is only allowing a thread to fetch one line
1003 // at a time. Re-examine when/if prefetching
1004 // gets implemented.
1005 //memcpy(fetchData[tid], cache_pkt->getPtr<uint8_t>(),
1006 // cache_pkt->getSize());
1008 // Get the instruction from the array of the cache line.
1009 // @todo: update thsi
1010 ExtMachInst ext_inst
;
1011 StaticInstPtr staticInst
= NULL
;
1012 Addr inst_pc
= inst
->readPC();
1013 MachInst mach_inst
=
1014 TheISA::gtoh(*reinterpret_cast<TheISA::MachInst
*>
1015 (cache_pkt
->getPtr
<uint8_t>()));
1017 predecoder
.setTC(cpu
->thread
[tid
]->getTC());
1018 predecoder
.moreBytes(inst_pc
, inst_pc
, mach_inst
);
1019 ext_inst
= predecoder
.getExtMachInst();
1021 inst
->setMachInst(ext_inst
);
1023 // Set Up More TraceData info
1024 if (inst
->traceData
) {
1025 inst
->traceData
->setStaticInst(inst
->staticInst
);
1026 inst
->traceData
->setPC(inst
->readPC());
1029 } else if (inst
->staticInst
&& inst
->isMemRef()) {
1030 DPRINTF(InOrderCachePort
,
1031 "[tid:%u]: [sn:%i]: Processing cache access\n",
1034 if (inst
->splitInst
) {
1035 inst
->splitFinishCnt
++;
1037 if (inst
->splitFinishCnt
== 2) {
1038 cache_req
->memReq
->setVirt(0/*inst->tid*/,
1040 inst
->splitTotalSize
,
1044 Packet
split_pkt(cache_req
->memReq
, cache_req
->pktCmd
,
1048 if (inst
->isLoad()) {
1049 split_pkt
.dataStatic(inst
->splitMemData
);
1051 split_pkt
.dataStatic(&inst
->storeData
);
1054 inst
->completeAcc(&split_pkt
);
1057 inst
->completeAcc(pkt
);
1060 if (inst
->isLoad()) {
1061 assert(cache_pkt
->isRead());
1063 if (cache_pkt
->req
->isLLSC()) {
1064 DPRINTF(InOrderCachePort
,
1065 "[tid:%u]: Handling Load-Linked for [sn:%u]\n",
1067 TheISA::handleLockedRead(cpu
, cache_pkt
->req
);
1070 // @NOTE: Hardcoded to for load instructions. Assumes that
1071 // the dest. idx 0 is always where the data is loaded to.
1072 DPRINTF(InOrderCachePort
,
1073 "[tid:%u]: [sn:%i]: Data loaded was: %08p\n",
1074 tid
, inst
->seqNum
, inst
->readIntResult(0));
1075 DPRINTF(InOrderCachePort
,
1076 "[tid:%u]: [sn:%i]: FP Data loaded was: %08p\n",
1077 tid
, inst
->seqNum
, inst
->readFloatResult(0));
1078 } else if(inst
->isStore()) {
1079 assert(cache_pkt
->isWrite());
1081 DPRINTF(InOrderCachePort
,
1082 "[tid:%u]: [sn:%i]: Data stored was: FIX ME\n",
1083 tid
, inst
->seqNum
/*,
1084 getMemData(cache_pkt)*/);
1090 cache_req
->setMemAccPending(false);
1091 cache_req
->setMemAccCompleted();
1093 if (cache_req
->isMemStall() &&
1094 cpu
->threadModel
== InOrderCPU::SwitchOnCacheMiss
) {
1095 DPRINTF(InOrderCachePort
, "[tid:%u] Waking up from Cache Miss.\n", tid
);
1097 cpu
->activateContext(tid
);
1099 DPRINTF(ThreadModel
, "Activating [tid:%i] after return from cache"
1103 // Wake up the CPU (if it went to sleep and was waiting on this
1104 // completion event).
1107 DPRINTF(Activity
, "[tid:%u] Activating %s due to cache completion\n",
1108 tid
, cpu
->pipelineStage
[stage_num
]->name());
1110 cpu
->switchToActive(stage_num
);
1112 DPRINTF(InOrderCachePort
,
1113 "[tid:%u] Miss on block @ %08p completed, but squashed\n",
1114 tid
, cache_req
->inst
->readPC());
1115 cache_req
->setMemAccCompleted();
1120 CacheUnit::recvRetry()
1122 DPRINTF(InOrderCachePort
, "Unblocking Cache Port. \n");
1124 assert(cachePortBlocked
);
1126 // Clear the cache port for use again
1127 cachePortBlocked
= false;
1132 CacheUnitEvent::CacheUnitEvent()
1137 CacheUnitEvent::process()
1139 DynInstPtr inst
= resource
->reqMap
[slotIdx
]->inst
;
1140 int stage_num
= resource
->reqMap
[slotIdx
]->getStageNum();
1141 ThreadID tid
= inst
->threadNumber
;
1142 CacheReqPtr req_ptr
= dynamic_cast<CacheReqPtr
>(resource
->reqMap
[slotIdx
]);
1144 DPRINTF(InOrderTLB
, "Waking up from TLB Miss caused by [sn:%i].\n",
1147 CacheUnit
* tlb_res
= dynamic_cast<CacheUnit
*>(resource
);
1150 tlb_res
->tlbBlocked
[tid
] = false;
1152 tlb_res
->cpu
->pipelineStage
[stage_num
]->
1153 unsetResStall(tlb_res
->reqMap
[slotIdx
], tid
);
1155 req_ptr
->tlbStall
= false;
1157 if (req_ptr
->isSquashed()) {
1163 CacheUnit::squashDueToMemStall(DynInstPtr inst
, int stage_num
,
1164 InstSeqNum squash_seq_num
, ThreadID tid
)
1166 // If squashing due to memory stall, then we do NOT want to
1167 // squash the instruction that caused the stall so we
1168 // increment the sequence number here to prevent that.
1170 // NOTE: This is only for the SwitchOnCacheMiss Model
1171 // NOTE: If you have multiple outstanding misses from the same
1172 // thread then you need to reevaluate this code
1173 // NOTE: squash should originate from
1174 // pipeline_stage.cc:processInstSchedule
1175 DPRINTF(InOrderCachePort
, "Squashing above [sn:%u]\n",
1176 squash_seq_num
+ 1);
1178 squash(inst
, stage_num
, squash_seq_num
+ 1, tid
);
1183 CacheUnit::squash(DynInstPtr inst
, int stage_num
,
1184 InstSeqNum squash_seq_num
, ThreadID tid
)
1186 vector
<int> slot_remove_list
;
1188 map
<int, ResReqPtr
>::iterator map_it
= reqMap
.begin();
1189 map
<int, ResReqPtr
>::iterator map_end
= reqMap
.end();
1191 while (map_it
!= map_end
) {
1192 ResReqPtr req_ptr
= (*map_it
).second
;
1195 req_ptr
->getInst()->readTid() == tid
&&
1196 req_ptr
->getInst()->seqNum
> squash_seq_num
) {
1198 DPRINTF(InOrderCachePort
,
1199 "[tid:%i] Squashing request from [sn:%i]\n",
1200 req_ptr
->getInst()->readTid(), req_ptr
->getInst()->seqNum
);
1202 if (req_ptr
->isSquashed()) {
1203 DPRINTF(AddrDep
, "Request for [tid:%i] [sn:%i] already squashed, ignoring squash process.\n",
1204 req_ptr
->getInst()->readTid(),
1205 req_ptr
->getInst()->seqNum
);
1210 req_ptr
->setSquashed();
1212 req_ptr
->getInst()->setSquashed();
1214 CacheReqPtr cache_req
= dynamic_cast<CacheReqPtr
>(req_ptr
);
1217 int req_slot_num
= req_ptr
->getSlot();
1219 if (cache_req
->tlbStall
) {
1220 tlbBlocked
[tid
] = false;
1222 int stall_stage
= reqMap
[req_slot_num
]->getStageNum();
1224 cpu
->pipelineStage
[stall_stage
]->
1225 unsetResStall(reqMap
[req_slot_num
], tid
);
1228 if (!cache_req
->tlbStall
&& !cache_req
->isMemAccPending()) {
1229 // Mark request for later removal
1230 cpu
->reqRemoveList
.push(req_ptr
);
1232 // Mark slot for removal from resource
1233 slot_remove_list
.push_back(req_ptr
->getSlot());
1235 DPRINTF(InOrderCachePort
,
1236 "[tid:%i] Request from [sn:%i] squashed, but still pending completion.\n",
1237 req_ptr
->getInst()->readTid(), req_ptr
->getInst()->seqNum
);
1239 "[tid:%i] Request from [sn:%i] squashed (split:%i), but still pending completion.\n",
1240 req_ptr
->getInst()->readTid(), req_ptr
->getInst()->seqNum
,
1241 req_ptr
->getInst()->splitInst
);
1244 if (req_ptr
->getInst()->validMemAddr()) {
1245 DPRINTF(AddrDep
, "Squash of [tid:%i] [sn:%i], attempting to remove addr. %08p dependencies.\n",
1246 req_ptr
->getInst()->readTid(),
1247 req_ptr
->getInst()->seqNum
,
1248 req_ptr
->getInst()->getMemAddr());
1250 removeAddrDependency(req_ptr
->getInst());
1257 // Now Delete Slot Entry from Req. Map
1258 for (int i
= 0; i
< slot_remove_list
.size(); i
++)
1259 freeSlot(slot_remove_list
[i
]);
1263 CacheUnit::getMemData(Packet
*packet
)
1265 switch (packet
->getSize())
1268 return packet
->get
<uint8_t>();
1271 return packet
->get
<uint16_t>();
1274 return packet
->get
<uint32_t>();
1277 return packet
->get
<uint64_t>();
1280 panic("bad store data size = %d\n", packet
->getSize());
1284 // Extra Template Definitions
1285 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1289 CacheUnit::read(DynInstPtr inst
, Addr addr
, Twin32_t
&data
, unsigned flags
);
1293 CacheUnit::read(DynInstPtr inst
, Addr addr
, Twin64_t
&data
, unsigned flags
);
1297 CacheUnit::read(DynInstPtr inst
, Addr addr
, uint64_t &data
, unsigned flags
);
1301 CacheUnit::read(DynInstPtr inst
, Addr addr
, uint32_t &data
, unsigned flags
);
1305 CacheUnit::read(DynInstPtr inst
, Addr addr
, uint16_t &data
, unsigned flags
);
1309 CacheUnit::read(DynInstPtr inst
, Addr addr
, uint8_t &data
, unsigned flags
);
1311 #endif //DOXYGEN_SHOULD_SKIP_THIS
1315 CacheUnit::read(DynInstPtr inst
, Addr addr
, double &data
, unsigned flags
)
1317 return read(inst
, addr
, *(uint64_t*)&data
, flags
);
1322 CacheUnit::read(DynInstPtr inst
, Addr addr
, float &data
, unsigned flags
)
1324 return read(inst
, addr
, *(uint32_t*)&data
, flags
);
1330 CacheUnit::read(DynInstPtr inst
, Addr addr
, int32_t &data
, unsigned flags
)
1332 return read(inst
, addr
, (uint32_t&)data
, flags
);
1335 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1339 CacheUnit::write(DynInstPtr inst
, Twin32_t data
, Addr addr
,
1340 unsigned flags
, uint64_t *res
);
1344 CacheUnit::write(DynInstPtr inst
, Twin64_t data
, Addr addr
,
1345 unsigned flags
, uint64_t *res
);
1349 CacheUnit::write(DynInstPtr inst
, uint64_t data
, Addr addr
,
1350 unsigned flags
, uint64_t *res
);
1354 CacheUnit::write(DynInstPtr inst
, uint32_t data
, Addr addr
,
1355 unsigned flags
, uint64_t *res
);
1359 CacheUnit::write(DynInstPtr inst
, uint16_t data
, Addr addr
,
1360 unsigned flags
, uint64_t *res
);
1364 CacheUnit::write(DynInstPtr inst
, uint8_t data
, Addr addr
,
1365 unsigned flags
, uint64_t *res
);
1367 #endif //DOXYGEN_SHOULD_SKIP_THIS
1371 CacheUnit::write(DynInstPtr inst
, double data
, Addr addr
, unsigned flags
,
1374 return write(inst
, *(uint64_t*)&data
, addr
, flags
, res
);
1379 CacheUnit::write(DynInstPtr inst
, float data
, Addr addr
, unsigned flags
,
1382 return write(inst
, *(uint32_t*)&data
, addr
, flags
, res
);
1388 CacheUnit::write(DynInstPtr inst
, int32_t data
, Addr addr
, unsigned flags
,
1391 return write(inst
, (uint32_t)data
, addr
, flags
, res
);