1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 */
30
31#include "arch/locked_mem.hh"
32#include "arch/mmaped_ipr.hh"
33#include "arch/utility.hh"
34#include "base/bigint.hh"
35#include "cpu/exetrace.hh"
36#include "cpu/simple/timing.hh"
37#include "mem/packet.hh"
38#include "mem/packet_access.hh"
39#include "params/TimingSimpleCPU.hh"
40#include "sim/system.hh"
41
42using namespace std;
43using namespace TheISA;
44
45Port *
46TimingSimpleCPU::getPort(const std::string &if_name, int idx)
47{
48 if (if_name == "dcache_port")
49 return &dcachePort;
50 else if (if_name == "icache_port")
51 return &icachePort;
52 else
53 panic("No Such Port\n");
54}
55
56void
57TimingSimpleCPU::init()
58{
59 BaseCPU::init();
60#if FULL_SYSTEM
61 for (int i = 0; i < threadContexts.size(); ++i) {
62 ThreadContext *tc = threadContexts[i];
63
64 // initialize CPU, including PC
65 TheISA::initCPU(tc, _cpuId);
66 }
67#endif
68}
69
70Tick
71TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
72{
73 panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
74 return curTick;
75}
76
77void
78TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
79{
80 //No internal storage to update, jusst return
81 return;
82}
83
84void
85TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
86{
87 if (status == RangeChange) {
88 if (!snoopRangeSent) {
89 snoopRangeSent = true;
90 sendStatusChange(Port::RangeChange);
91 }
92 return;
93 }
94
95 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
96}
97
98
99void
100TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
101{
102 pkt = _pkt;
103 cpu->schedule(this, t);
104}
105
106TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
107 : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
108 dcachePort(this, p->clock), fetchEvent(this)
109{
110 _status = Idle;
111
112 icachePort.snoopRangeSent = false;
113 dcachePort.snoopRangeSent = false;
114
115 ifetch_pkt = dcache_pkt = NULL;
116 drainEvent = NULL;
117 previousTick = 0;
118 changeState(SimObject::Running);
119}
120
121
122TimingSimpleCPU::~TimingSimpleCPU()
123{
124}
125
126void
127TimingSimpleCPU::serialize(ostream &os)
128{
129 SimObject::State so_state = SimObject::getState();
130 SERIALIZE_ENUM(so_state);
131 BaseSimpleCPU::serialize(os);
132}
133
134void
135TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
136{
137 SimObject::State so_state;
138 UNSERIALIZE_ENUM(so_state);
139 BaseSimpleCPU::unserialize(cp, section);
140}
141
142unsigned int
143TimingSimpleCPU::drain(Event *drain_event)
144{
145 // TimingSimpleCPU is ready to drain if it's not waiting for
146 // an access to complete.
147 if (_status == Idle || _status == Running || _status == SwitchedOut) {
148 changeState(SimObject::Drained);
149 return 0;
150 } else {
151 changeState(SimObject::Draining);
152 drainEvent = drain_event;
153 return 1;
154 }
155}
156
157void
158TimingSimpleCPU::resume()
159{
160 DPRINTF(SimpleCPU, "Resume\n");
161 if (_status != SwitchedOut && _status != Idle) {
162 assert(system->getMemoryMode() == Enums::timing);
163
164 if (fetchEvent.scheduled())
165 deschedule(fetchEvent);
166
167 schedule(fetchEvent, nextCycle());
168 }
169
170 changeState(SimObject::Running);
171}
172
173void
174TimingSimpleCPU::switchOut()
175{
176 assert(_status == Running || _status == Idle);
177 _status = SwitchedOut;
178 numCycles += tickToCycles(curTick - previousTick);
179
180 // If we've been scheduled to resume but are then told to switch out,
181 // we'll need to cancel it.
182 if (fetchEvent.scheduled())
183 deschedule(fetchEvent);
184}
185
186
187void
188TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
189{
190 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
191
192 // if any of this CPU's ThreadContexts are active, mark the CPU as
193 // running and schedule its tick event.
194 for (int i = 0; i < threadContexts.size(); ++i) {
195 ThreadContext *tc = threadContexts[i];
196 if (tc->status() == ThreadContext::Active && _status != Running) {
197 _status = Running;
198 break;
199 }
200 }
201
202 if (_status != Running) {
203 _status = Idle;
204 }
205 assert(threadContexts.size() == 1);
206 previousTick = curTick;
207}
208
209
210void
211TimingSimpleCPU::activateContext(int thread_num, int delay)
212{
213 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
214
215 assert(thread_num == 0);
216 assert(thread);
217
218 assert(_status == Idle);
219
220 notIdleFraction++;
221 _status = Running;
222
223 // kick things off by initiating the fetch of the next instruction
224 schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
225}
226
227
228void
229TimingSimpleCPU::suspendContext(int thread_num)
230{
231 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
232
233 assert(thread_num == 0);
234 assert(thread);
235
236 if (_status == Idle)
237 return;
238
239 assert(_status == Running);
240
241 // just change status to Idle... if status != Running,
242 // completeInst() will not initiate fetch of next instruction.
243
244 notIdleFraction--;
245 _status = Idle;
246}
247
248bool
249TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
250{
251 RequestPtr req = pkt->req;
252 if (req->isMmapedIpr()) {
253 Tick delay;
254 delay = TheISA::handleIprRead(thread->getTC(), pkt);
255 new IprEvent(pkt, this, nextCycle(curTick + delay));
256 _status = DcacheWaitResponse;
257 dcache_pkt = NULL;
258 } else if (!dcachePort.sendTiming(pkt)) {
259 _status = DcacheRetry;
260 dcache_pkt = pkt;
261 } else {
262 _status = DcacheWaitResponse;
263 // memory system takes ownership of packet
264 dcache_pkt = NULL;
265 }
266 return dcache_pkt == NULL;
267}
268
269void
270TimingSimpleCPU::sendData(Fault fault, RequestPtr req,
271 uint8_t *data, uint64_t *res, bool read)
272{
273 _status = Running;
274 if (fault != NoFault) {
275 delete data;
276 delete req;
277
278 translationFault(fault);
279 return;
280 }
281 PacketPtr pkt;
282 buildPacket(pkt, req, read);
283 pkt->dataDynamic<uint8_t>(data);
284 if (req->getFlags().isSet(Request::NO_ACCESS)) {
285 assert(!dcache_pkt);
286 pkt->makeResponse();
287 completeDataAccess(pkt);
288 } else if (read) {
289 handleReadPacket(pkt);
290 } else {
291 bool do_access = true; // flag to suppress cache access
292
293 if (req->isLocked()) {
294 do_access = TheISA::handleLockedWrite(thread, req);
295 } else if (req->isCondSwap()) {
296 assert(res);
297 req->setExtraData(*res);
298 }
299
300 if (do_access) {
301 dcache_pkt = pkt;
302 handleWritePacket();
303 } else {
304 _status = DcacheWaitResponse;
305 completeDataAccess(pkt);
306 }
307 }
308}
309
310void
311TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2,
312 RequestPtr req1, RequestPtr req2, RequestPtr req,
313 uint8_t *data, bool read)
314{
315 _status = Running;
316 if (fault1 != NoFault || fault2 != NoFault) {
317 delete data;
318 delete req1;
319 delete req2;
320 if (fault1 != NoFault)
321 translationFault(fault1);
322 else if (fault2 != NoFault)
323 translationFault(fault2);
324 return;
325 }
326 PacketPtr pkt1, pkt2;
327 buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
328 if (req->getFlags().isSet(Request::NO_ACCESS)) {
329 assert(!dcache_pkt);
330 pkt1->makeResponse();
331 completeDataAccess(pkt1);
332 } else if (read) {
333 if (handleReadPacket(pkt1)) {
334 SplitFragmentSenderState * send_state =
335 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
336 send_state->clearFromParent();
337 if (handleReadPacket(pkt2)) {
338 send_state = dynamic_cast<SplitFragmentSenderState *>(
339 pkt1->senderState);
340 send_state->clearFromParent();
341 }
342 }
343 } else {
344 dcache_pkt = pkt1;
345 if (handleWritePacket()) {
346 SplitFragmentSenderState * send_state =
347 dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
348 send_state->clearFromParent();
349 dcache_pkt = pkt2;
350 if (handleWritePacket()) {
351 send_state = dynamic_cast<SplitFragmentSenderState *>(
352 pkt1->senderState);
353 send_state->clearFromParent();
354 }
355 }
356 }
357}
358
359void
360TimingSimpleCPU::translationFault(Fault fault)
361{
362 numCycles += tickToCycles(curTick - previousTick);
363 previousTick = curTick;
364
365 if (traceData) {
366 // Since there was a fault, we shouldn't trace this instruction.
367 delete traceData;
368 traceData = NULL;
369 }
370
371 postExecute();
372
373 if (getState() == SimObject::Draining) {
374 advancePC(fault);
375 completeDrain();
376 } else {
377 advanceInst(fault);
378 }
379}
380
381void
382TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
383{
384 MemCmd cmd;
385 if (read) {
386 cmd = MemCmd::ReadReq;
387 if (req->isLocked())
388 cmd = MemCmd::LoadLockedReq;
389 } else {
390 cmd = MemCmd::WriteReq;
391 if (req->isLocked()) {
392 cmd = MemCmd::StoreCondReq;
393 } else if (req->isSwap()) {
394 cmd = MemCmd::SwapReq;
395 }
396 }
397 pkt = new Packet(req, cmd, Packet::Broadcast);
398}
399
400void
401TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
402 RequestPtr req1, RequestPtr req2, RequestPtr req,
403 uint8_t *data, bool read)
404{
405 pkt1 = pkt2 = NULL;
406
407 assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
408
409 if (req->getFlags().isSet(Request::NO_ACCESS)) {
410 buildPacket(pkt1, req, read);
411 return;
412 }
413
414 buildPacket(pkt1, req1, read);
415 buildPacket(pkt2, req2, read);
416
417 req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
418 PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
419 Packet::Broadcast);
420
421 pkt->dataDynamic<uint8_t>(data);
422 pkt1->dataStatic<uint8_t>(data);
423 pkt2->dataStatic<uint8_t>(data + req1->getSize());
424
425 SplitMainSenderState * main_send_state = new SplitMainSenderState;
426 pkt->senderState = main_send_state;
427 main_send_state->fragments[0] = pkt1;
428 main_send_state->fragments[1] = pkt2;
429 main_send_state->outstanding = 2;
430 pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
431 pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
432}
433
434template <class T>
435Fault
436TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
437{
438 Fault fault;
439 const int asid = 0;
440 const int thread_id = 0;
441 const Addr pc = thread->readPC();
442 int block_size = dcachePort.peerBlockSize();
443 int data_size = sizeof(T);
444
445 RequestPtr req = new Request(asid, addr, data_size,
446 flags, pc, _cpuId, thread_id);
447
448 Addr split_addr = roundDown(addr + data_size - 1, block_size);
449 assert(split_addr <= addr || split_addr - addr < block_size);
450
451
452 _status = DTBWaitResponse;
453 if (split_addr > addr) {
454 RequestPtr req1, req2;
455 assert(!req->isLocked() && !req->isSwap());
456 req->splitOnVaddr(split_addr, req1, req2);
457
458 typedef SplitDataTranslation::WholeTranslationState WholeState;
459 WholeState *state = new WholeState(req1, req2, req,
460 (uint8_t *)(new T), BaseTLB::Read);
461 thread->dtb->translateTiming(req1, tc,
462 new SplitDataTranslation(this, 0, state), BaseTLB::Read);
463 thread->dtb->translateTiming(req2, tc,
464 new SplitDataTranslation(this, 1, state), BaseTLB::Read);
465 } else {
466 DataTranslation *translation =
467 new DataTranslation(this, (uint8_t *)(new T), NULL, BaseTLB::Read);
468 thread->dtb->translateTiming(req, tc, translation, BaseTLB::Read);
469 }
470
471 if (traceData) {
472 traceData->setData(data);
473 traceData->setAddr(addr);
474 }
475
476 // This will need a new way to tell if it has a dcache attached.
477 if (req->isUncacheable())
478 recordEvent("Uncached Read");
479
480 return NoFault;
481}
482
483#ifndef DOXYGEN_SHOULD_SKIP_THIS
484
485template
486Fault
487TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
488
489template
490Fault
491TimingSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
492
493template
494Fault
495TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
496
497template
498Fault
499TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
500
501template
502Fault
503TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
504
505template
506Fault
507TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
508
509#endif //DOXYGEN_SHOULD_SKIP_THIS
510
511template<>
512Fault
513TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
514{
515 return read(addr, *(uint64_t*)&data, flags);
516}
517
518template<>
519Fault
520TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
521{
522 return read(addr, *(uint32_t*)&data, flags);
523}
524
525
526template<>
527Fault
528TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
529{
530 return read(addr, (uint32_t&)data, flags);
531}
532
533bool
534TimingSimpleCPU::handleWritePacket()
535{
536 RequestPtr req = dcache_pkt->req;
537 if (req->isMmapedIpr()) {
538 Tick delay;
539 delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
540 new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
541 _status = DcacheWaitResponse;
542 dcache_pkt = NULL;
543 } else if (!dcachePort.sendTiming(dcache_pkt)) {
544 _status = DcacheRetry;
545 } else {
546 _status = DcacheWaitResponse;
547 // memory system takes ownership of packet
548 dcache_pkt = NULL;
549 }
550 return dcache_pkt == NULL;
551}
552
553template <class T>
554Fault
555TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
556{
557 const int asid = 0;
558 const int thread_id = 0;
559 const Addr pc = thread->readPC();
560 int block_size = dcachePort.peerBlockSize();
561 int data_size = sizeof(T);
562
563 RequestPtr req = new Request(asid, addr, data_size,
564 flags, pc, _cpuId, thread_id);
565
566 Addr split_addr = roundDown(addr + data_size - 1, block_size);
567 assert(split_addr <= addr || split_addr - addr < block_size);
568
569 T *dataP = new T;
570 *dataP = TheISA::htog(data);
571 _status = DTBWaitResponse;
572 if (split_addr > addr) {
573 RequestPtr req1, req2;
574 assert(!req->isLocked() && !req->isSwap());
575 req->splitOnVaddr(split_addr, req1, req2);
576
577 typedef SplitDataTranslation::WholeTranslationState WholeState;
578 WholeState *state = new WholeState(req1, req2, req,
579 (uint8_t *)dataP, BaseTLB::Write);
580 thread->dtb->translateTiming(req1, tc,
581 new SplitDataTranslation(this, 0, state), BaseTLB::Write);
582 thread->dtb->translateTiming(req2, tc,
583 new SplitDataTranslation(this, 1, state), BaseTLB::Write);
584 } else {
585 DataTranslation *translation =
586 new DataTranslation(this, (uint8_t *)dataP, res, BaseTLB::Write);
587 thread->dtb->translateTiming(req, tc, translation, BaseTLB::Write);
588 }
589
590 if (traceData) {
591 traceData->setAddr(req->getVaddr());
592 traceData->setData(data);
593 }
594
595 // This will need a new way to tell if it's hooked up to a cache or not.
596 if (req->isUncacheable())
597 recordEvent("Uncached Write");
598
599 // If the write needs to have a fault on the access, consider calling
600 // changeStatus() and changing it to "bad addr write" or something.
601 return NoFault;
602}
603
604
605#ifndef DOXYGEN_SHOULD_SKIP_THIS
606template
607Fault
608TimingSimpleCPU::write(Twin32_t data, Addr addr,
609 unsigned flags, uint64_t *res);
610
611template
612Fault
613TimingSimpleCPU::write(Twin64_t data, Addr addr,
614 unsigned flags, uint64_t *res);
615
616template
617Fault
618TimingSimpleCPU::write(uint64_t data, Addr addr,
619 unsigned flags, uint64_t *res);
620
621template
622Fault
623TimingSimpleCPU::write(uint32_t data, Addr addr,
624 unsigned flags, uint64_t *res);
625
626template
627Fault
628TimingSimpleCPU::write(uint16_t data, Addr addr,
629 unsigned flags, uint64_t *res);
630
631template
632Fault
633TimingSimpleCPU::write(uint8_t data, Addr addr,
634 unsigned flags, uint64_t *res);
635
636#endif //DOXYGEN_SHOULD_SKIP_THIS
637
638template<>
639Fault
640TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
641{
642 return write(*(uint64_t*)&data, addr, flags, res);
643}
644
645template<>
646Fault
647TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
648{
649 return write(*(uint32_t*)&data, addr, flags, res);
650}
651
652
653template<>
654Fault
655TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
656{
657 return write((uint32_t)data, addr, flags, res);
658}
659
660
661void
662TimingSimpleCPU::fetch()
663{
664 DPRINTF(SimpleCPU, "Fetch\n");
665
666 if (!curStaticInst || !curStaticInst->isDelayedCommit())
667 checkForInterrupts();
668
669 checkPcEventQueue();
670
671 bool fromRom = isRomMicroPC(thread->readMicroPC());
672
673 if (!fromRom && !curMacroStaticInst) {
674 Request *ifetch_req = new Request();
675 ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
676 setupFetchRequest(ifetch_req);
677 thread->itb->translateTiming(ifetch_req, tc, &fetchTranslation,
678 BaseTLB::Execute);
679 } else {
680 _status = IcacheWaitResponse;
681 completeIfetch(NULL);
682
683 numCycles += tickToCycles(curTick - previousTick);
684 previousTick = curTick;
685 }
686}
687
688
689void
690TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
691{
692 if (fault == NoFault) {
693 ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
694 ifetch_pkt->dataStatic(&inst);
695
696 if (!icachePort.sendTiming(ifetch_pkt)) {
697 // Need to wait for retry
698 _status = IcacheRetry;
699 } else {
700 // Need to wait for cache to respond
701 _status = IcacheWaitResponse;
702 // ownership of packet transferred to memory system
703 ifetch_pkt = NULL;
704 }
705 } else {
706 delete req;
707 // fetch fault: advance directly to next instruction (fault handler)
708 advanceInst(fault);
709 }
710
711 numCycles += tickToCycles(curTick - previousTick);
712 previousTick = curTick;
713}
714
715
716void
717TimingSimpleCPU::advanceInst(Fault fault)
718{
719 if (fault != NoFault || !stayAtPC)
720 advancePC(fault);
721
722 if (_status == Running) {
723 // kick off fetch of next instruction... callback from icache
724 // response will cause that instruction to be executed,
725 // keeping the CPU running.
726 fetch();
727 }
728}
729
730
731void
732TimingSimpleCPU::completeIfetch(PacketPtr pkt)
733{
734 DPRINTF(SimpleCPU, "Complete ICache Fetch\n");
735
736 // received a response from the icache: execute the received
737 // instruction
738
739 assert(!pkt || !pkt->isError());
740 assert(_status == IcacheWaitResponse);
741
742 _status = Running;
743
744 numCycles += tickToCycles(curTick - previousTick);
745 previousTick = curTick;
746
747 if (getState() == SimObject::Draining) {
748 if (pkt) {
749 delete pkt->req;
750 delete pkt;
751 }
752
753 completeDrain();
754 return;
755 }
756
757 preExecute();
758 if (curStaticInst &&
759 curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
760 // load or store: just send to dcache
761 Fault fault = curStaticInst->initiateAcc(this, traceData);
762 if (_status != Running) {
763 // instruction will complete in dcache response callback
764 assert(_status == DcacheWaitResponse ||
765 _status == DcacheRetry || DTBWaitResponse);
766 assert(fault == NoFault);
767 } else {
768 if (fault != NoFault && traceData) {
769 // If there was a fault, we shouldn't trace this instruction.
770 delete traceData;
771 traceData = NULL;
772 }
773
774 postExecute();
775 // @todo remove me after debugging with legion done
776 if (curStaticInst && (!curStaticInst->isMicroop() ||
777 curStaticInst->isFirstMicroop()))
778 instCnt++;
779 advanceInst(fault);
780 }
781 } else if (curStaticInst) {
782 // non-memory instruction: execute completely now
783 Fault fault = curStaticInst->execute(this, traceData);
784
785 // keep an instruction count
786 if (fault == NoFault)
787 countInst();
788 else if (traceData) {
789 // If there was a fault, we shouldn't trace this instruction.
790 delete traceData;
791 traceData = NULL;
792 }
793
794 postExecute();
795 // @todo remove me after debugging with legion done
796 if (curStaticInst && (!curStaticInst->isMicroop() ||
797 curStaticInst->isFirstMicroop()))
798 instCnt++;
799 advanceInst(fault);
800 } else {
801 advanceInst(NoFault);
802 }
803
804 if (pkt) {
805 delete pkt->req;
806 delete pkt;
807 }
808}
809
810void
811TimingSimpleCPU::IcachePort::ITickEvent::process()
812{
813 cpu->completeIfetch(pkt);
814}
815
816bool
817TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
818{
819 if (pkt->isResponse() && !pkt->wasNacked()) {
820 // delay processing of returned data until next CPU clock edge
821 Tick next_tick = cpu->nextCycle(curTick);
822
823 if (next_tick == curTick)
824 cpu->completeIfetch(pkt);
825 else
826 tickEvent.schedule(pkt, next_tick);
827
828 return true;
829 }
830 else if (pkt->wasNacked()) {
831 assert(cpu->_status == IcacheWaitResponse);
832 pkt->reinitNacked();
833 if (!sendTiming(pkt)) {
834 cpu->_status = IcacheRetry;
835 cpu->ifetch_pkt = pkt;
836 }
837 }
838 //Snooping a Coherence Request, do nothing
839 return true;
840}
841
842void
843TimingSimpleCPU::IcachePort::recvRetry()
844{
845 // we shouldn't get a retry unless we have a packet that we're
846 // waiting to transmit
847 assert(cpu->ifetch_pkt != NULL);
848 assert(cpu->_status == IcacheRetry);
849 PacketPtr tmp = cpu->ifetch_pkt;
850 if (sendTiming(tmp)) {
851 cpu->_status = IcacheWaitResponse;
852 cpu->ifetch_pkt = NULL;
853 }
854}
855
856void
857TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
858{
859 // received a response from the dcache: complete the load or store
860 // instruction
861 assert(!pkt->isError());
862
863 numCycles += tickToCycles(curTick - previousTick);
864 previousTick = curTick;
865
866 if (pkt->senderState) {
867 SplitFragmentSenderState * send_state =
868 dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
869 assert(send_state);
870 delete pkt->req;
871 delete pkt;
872 PacketPtr big_pkt = send_state->bigPkt;
873 delete send_state;
874
875 SplitMainSenderState * main_send_state =
876 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
877 assert(main_send_state);
878 // Record the fact that this packet is no longer outstanding.
879 assert(main_send_state->outstanding != 0);
880 main_send_state->outstanding--;
881
882 if (main_send_state->outstanding) {
883 return;
884 } else {
885 delete main_send_state;
886 big_pkt->senderState = NULL;
887 pkt = big_pkt;
888 }
889 }
890
891 assert(_status == DcacheWaitResponse || _status == DTBWaitResponse);
892 _status = Running;
893
894 Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
895
896 // keep an instruction count
897 if (fault == NoFault)
898 countInst();
899 else if (traceData) {
900 // If there was a fault, we shouldn't trace this instruction.
901 delete traceData;
902 traceData = NULL;
903 }
904
905 // the locked flag may be cleared on the response packet, so check
906 // pkt->req and not pkt to see if it was a load-locked
907 if (pkt->isRead() && pkt->req->isLocked()) {
908 TheISA::handleLockedRead(thread, pkt->req);
909 }
910
911 delete pkt->req;
912 delete pkt;
913
914 postExecute();
915
916 if (getState() == SimObject::Draining) {
917 advancePC(fault);
918 completeDrain();
919
920 return;
921 }
922
923 advanceInst(fault);
924}
925
926
927void
928TimingSimpleCPU::completeDrain()
929{
930 DPRINTF(Config, "Done draining\n");
931 changeState(SimObject::Drained);
932 drainEvent->process();
933}
934
935void
936TimingSimpleCPU::DcachePort::setPeer(Port *port)
937{
938 Port::setPeer(port);
939
940#if FULL_SYSTEM
941 // Update the ThreadContext's memory ports (Functional/Virtual
942 // Ports)
943 cpu->tcBase()->connectMemPorts(cpu->tcBase());
944#endif
945}
946
947bool
948TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
949{
950 if (pkt->isResponse() && !pkt->wasNacked()) {
951 // delay processing of returned data until next CPU clock edge
952 Tick next_tick = cpu->nextCycle(curTick);
953
954 if (next_tick == curTick) {
955 cpu->completeDataAccess(pkt);
956 } else {
957 tickEvent.schedule(pkt, next_tick);
958 }
959
960 return true;
961 }
962 else if (pkt->wasNacked()) {
963 assert(cpu->_status == DcacheWaitResponse);
964 pkt->reinitNacked();
965 if (!sendTiming(pkt)) {
966 cpu->_status = DcacheRetry;
967 cpu->dcache_pkt = pkt;
968 }
969 }
970 //Snooping a Coherence Request, do nothing
971 return true;
972}
973
974void
975TimingSimpleCPU::DcachePort::DTickEvent::process()
976{
977 cpu->completeDataAccess(pkt);
978}
979
980void
981TimingSimpleCPU::DcachePort::recvRetry()
982{
983 // we shouldn't get a retry unless we have a packet that we're
984 // waiting to transmit
985 assert(cpu->dcache_pkt != NULL);
986 assert(cpu->_status == DcacheRetry);
987 PacketPtr tmp = cpu->dcache_pkt;
988 if (tmp->senderState) {
989 // This is a packet from a split access.
990 SplitFragmentSenderState * send_state =
991 dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
992 assert(send_state);
993 PacketPtr big_pkt = send_state->bigPkt;
994
995 SplitMainSenderState * main_send_state =
996 dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
997 assert(main_send_state);
998
999 if (sendTiming(tmp)) {
1000 // If we were able to send without retrying, record that fact
1001 // and try sending the other fragment.
1002 send_state->clearFromParent();
1003 int other_index = main_send_state->getPendingFragment();
1004 if (other_index > 0) {
1005 tmp = main_send_state->fragments[other_index];
1006 cpu->dcache_pkt = tmp;
1007 if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
1008 (big_pkt->isWrite() && cpu->handleWritePacket())) {
1009 main_send_state->fragments[other_index] = NULL;
1010 }
1011 } else {
1012 cpu->_status = DcacheWaitResponse;
1013 // memory system takes ownership of packet
1014 cpu->dcache_pkt = NULL;
1015 }
1016 }
1017 } else if (sendTiming(tmp)) {
1018 cpu->_status = DcacheWaitResponse;
1019 // memory system takes ownership of packet
1020 cpu->dcache_pkt = NULL;
1021 }
1022}
1023
1024TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
1025 Tick t)
1026 : pkt(_pkt), cpu(_cpu)
1027{
1028 cpu->schedule(this, t);
1029}
1030
1031void
1032TimingSimpleCPU::IprEvent::process()
1033{
1034 cpu->completeDataAccess(pkt);
1035}
1036
1037const char *
1038TimingSimpleCPU::IprEvent::description() const
1039{
1040 return "Timing Simple CPU Delay IPR event";
1041}
1042
1043
1044void
1045TimingSimpleCPU::printAddr(Addr a)
1046{
1047 dcachePort.printAddr(a);
1048}
1049
1050
1051////////////////////////////////////////////////////////////////////////
1052//
1053// TimingSimpleCPU Simulation Object
1054//
1055TimingSimpleCPU *
1056TimingSimpleCPUParams::create()
1057{
1058 numThreads = 1;
1059#if !FULL_SYSTEM
1060 if (workload.size() != 1)
1061 panic("only one workload allowed");
1062#endif
1063 return new TimingSimpleCPU(this);
1064}