timing.cc (3673:34386ba8cb41) timing.cc (3686:fa8d8b90cd8a)
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/utility.hh"
33#include "cpu/exetrace.hh"
34#include "cpu/simple/timing.hh"
35#include "mem/packet.hh"
36#include "mem/packet_access.hh"
37#include "sim/builder.hh"
38#include "sim/system.hh"
39
40using namespace std;
41using namespace TheISA;
42
43Port *
44TimingSimpleCPU::getPort(const std::string &if_name, int idx)
45{
46 if (if_name == "dcache_port")
47 return &dcachePort;
48 else if (if_name == "icache_port")
49 return &icachePort;
50 else
51 panic("No Such Port\n");
52}
53
54void
55TimingSimpleCPU::init()
56{
57 BaseCPU::init();
58#if FULL_SYSTEM
59 for (int i = 0; i < threadContexts.size(); ++i) {
60 ThreadContext *tc = threadContexts[i];
61
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/utility.hh"
33#include "cpu/exetrace.hh"
34#include "cpu/simple/timing.hh"
35#include "mem/packet.hh"
36#include "mem/packet_access.hh"
37#include "sim/builder.hh"
38#include "sim/system.hh"
39
40using namespace std;
41using namespace TheISA;
42
43Port *
44TimingSimpleCPU::getPort(const std::string &if_name, int idx)
45{
46 if (if_name == "dcache_port")
47 return &dcachePort;
48 else if (if_name == "icache_port")
49 return &icachePort;
50 else
51 panic("No Such Port\n");
52}
53
54void
55TimingSimpleCPU::init()
56{
57 BaseCPU::init();
58#if FULL_SYSTEM
59 for (int i = 0; i < threadContexts.size(); ++i) {
60 ThreadContext *tc = threadContexts[i];
61
62 // initialize the mem pointers
63 tc->init();
64
65 // initialize CPU, including PC
66 TheISA::initCPU(tc, tc->readCpuId());
67 }
68#endif
69}
70
71Tick
72TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
73{
74 panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
75 return curTick;
76}
77
78void
79TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
80{
81 //No internal storage to update, jusst return
82 return;
83}
84
85void
86TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
87{
88 if (status == RangeChange) {
89 if (!snoopRangeSent) {
90 snoopRangeSent = true;
91 sendStatusChange(Port::RangeChange);
92 }
93 return;
94 }
95
96 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
97}
98
99
100void
101TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
102{
103 pkt = _pkt;
104 Event::schedule(t);
105}
106
107TimingSimpleCPU::TimingSimpleCPU(Params *p)
108 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock),
109 cpu_id(p->cpu_id)
110{
111 _status = Idle;
112
113 icachePort.snoopRangeSent = false;
114 dcachePort.snoopRangeSent = false;
115
116 ifetch_pkt = dcache_pkt = NULL;
117 drainEvent = NULL;
118 fetchEvent = NULL;
119 previousTick = 0;
120 changeState(SimObject::Running);
121}
122
123
124TimingSimpleCPU::~TimingSimpleCPU()
125{
126}
127
128void
129TimingSimpleCPU::serialize(ostream &os)
130{
131 SimObject::State so_state = SimObject::getState();
132 SERIALIZE_ENUM(so_state);
133 BaseSimpleCPU::serialize(os);
134}
135
136void
137TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
138{
139 SimObject::State so_state;
140 UNSERIALIZE_ENUM(so_state);
141 BaseSimpleCPU::unserialize(cp, section);
142}
143
144unsigned int
145TimingSimpleCPU::drain(Event *drain_event)
146{
147 // TimingSimpleCPU is ready to drain if it's not waiting for
148 // an access to complete.
149 if (status() == Idle || status() == Running || status() == SwitchedOut) {
150 changeState(SimObject::Drained);
151 return 0;
152 } else {
153 changeState(SimObject::Draining);
154 drainEvent = drain_event;
155 return 1;
156 }
157}
158
159void
160TimingSimpleCPU::resume()
161{
162 if (_status != SwitchedOut && _status != Idle) {
163 assert(system->getMemoryMode() == System::Timing);
164
165 // Delete the old event if it existed.
166 if (fetchEvent) {
167 if (fetchEvent->scheduled())
168 fetchEvent->deschedule();
169
170 delete fetchEvent;
171 }
172
173 fetchEvent =
174 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
175 fetchEvent->schedule(nextCycle());
176 }
177
178 changeState(SimObject::Running);
179 previousTick = curTick;
180}
181
182void
183TimingSimpleCPU::switchOut()
184{
185 assert(status() == Running || status() == Idle);
186 _status = SwitchedOut;
187 numCycles += curTick - previousTick;
188
189 // If we've been scheduled to resume but are then told to switch out,
190 // we'll need to cancel it.
191 if (fetchEvent && fetchEvent->scheduled())
192 fetchEvent->deschedule();
193}
194
195
196void
197TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
198{
199 BaseCPU::takeOverFrom(oldCPU);
200
201 // if any of this CPU's ThreadContexts are active, mark the CPU as
202 // running and schedule its tick event.
203 for (int i = 0; i < threadContexts.size(); ++i) {
204 ThreadContext *tc = threadContexts[i];
205 if (tc->status() == ThreadContext::Active && _status != Running) {
206 _status = Running;
207 break;
208 }
209 }
210
211 if (_status != Running) {
212 _status = Idle;
213 }
214
215 Port *peer;
216 if (icachePort.getPeer() == NULL) {
217 peer = oldCPU->getPort("icache_port")->getPeer();
218 icachePort.setPeer(peer);
219 } else {
220 peer = icachePort.getPeer();
221 }
222 peer->setPeer(&icachePort);
223
224 if (dcachePort.getPeer() == NULL) {
225 peer = oldCPU->getPort("dcache_port")->getPeer();
226 dcachePort.setPeer(peer);
227 } else {
228 peer = dcachePort.getPeer();
229 }
230 peer->setPeer(&dcachePort);
231}
232
233
234void
235TimingSimpleCPU::activateContext(int thread_num, int delay)
236{
237 assert(thread_num == 0);
238 assert(thread);
239
240 assert(_status == Idle);
241
242 notIdleFraction++;
243 _status = Running;
62 // initialize CPU, including PC
63 TheISA::initCPU(tc, tc->readCpuId());
64 }
65#endif
66}
67
68Tick
69TimingSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
70{
71 panic("TimingSimpleCPU doesn't expect recvAtomic callback!");
72 return curTick;
73}
74
75void
76TimingSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
77{
78 //No internal storage to update, jusst return
79 return;
80}
81
82void
83TimingSimpleCPU::CpuPort::recvStatusChange(Status status)
84{
85 if (status == RangeChange) {
86 if (!snoopRangeSent) {
87 snoopRangeSent = true;
88 sendStatusChange(Port::RangeChange);
89 }
90 return;
91 }
92
93 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!");
94}
95
96
97void
98TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
99{
100 pkt = _pkt;
101 Event::schedule(t);
102}
103
104TimingSimpleCPU::TimingSimpleCPU(Params *p)
105 : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock),
106 cpu_id(p->cpu_id)
107{
108 _status = Idle;
109
110 icachePort.snoopRangeSent = false;
111 dcachePort.snoopRangeSent = false;
112
113 ifetch_pkt = dcache_pkt = NULL;
114 drainEvent = NULL;
115 fetchEvent = NULL;
116 previousTick = 0;
117 changeState(SimObject::Running);
118}
119
120
121TimingSimpleCPU::~TimingSimpleCPU()
122{
123}
124
125void
126TimingSimpleCPU::serialize(ostream &os)
127{
128 SimObject::State so_state = SimObject::getState();
129 SERIALIZE_ENUM(so_state);
130 BaseSimpleCPU::serialize(os);
131}
132
133void
134TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
135{
136 SimObject::State so_state;
137 UNSERIALIZE_ENUM(so_state);
138 BaseSimpleCPU::unserialize(cp, section);
139}
140
141unsigned int
142TimingSimpleCPU::drain(Event *drain_event)
143{
144 // TimingSimpleCPU is ready to drain if it's not waiting for
145 // an access to complete.
146 if (status() == Idle || status() == Running || status() == SwitchedOut) {
147 changeState(SimObject::Drained);
148 return 0;
149 } else {
150 changeState(SimObject::Draining);
151 drainEvent = drain_event;
152 return 1;
153 }
154}
155
156void
157TimingSimpleCPU::resume()
158{
159 if (_status != SwitchedOut && _status != Idle) {
160 assert(system->getMemoryMode() == System::Timing);
161
162 // Delete the old event if it existed.
163 if (fetchEvent) {
164 if (fetchEvent->scheduled())
165 fetchEvent->deschedule();
166
167 delete fetchEvent;
168 }
169
170 fetchEvent =
171 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
172 fetchEvent->schedule(nextCycle());
173 }
174
175 changeState(SimObject::Running);
176 previousTick = curTick;
177}
178
179void
180TimingSimpleCPU::switchOut()
181{
182 assert(status() == Running || status() == Idle);
183 _status = SwitchedOut;
184 numCycles += curTick - previousTick;
185
186 // If we've been scheduled to resume but are then told to switch out,
187 // we'll need to cancel it.
188 if (fetchEvent && fetchEvent->scheduled())
189 fetchEvent->deschedule();
190}
191
192
193void
194TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
195{
196 BaseCPU::takeOverFrom(oldCPU);
197
198 // if any of this CPU's ThreadContexts are active, mark the CPU as
199 // running and schedule its tick event.
200 for (int i = 0; i < threadContexts.size(); ++i) {
201 ThreadContext *tc = threadContexts[i];
202 if (tc->status() == ThreadContext::Active && _status != Running) {
203 _status = Running;
204 break;
205 }
206 }
207
208 if (_status != Running) {
209 _status = Idle;
210 }
211
212 Port *peer;
213 if (icachePort.getPeer() == NULL) {
214 peer = oldCPU->getPort("icache_port")->getPeer();
215 icachePort.setPeer(peer);
216 } else {
217 peer = icachePort.getPeer();
218 }
219 peer->setPeer(&icachePort);
220
221 if (dcachePort.getPeer() == NULL) {
222 peer = oldCPU->getPort("dcache_port")->getPeer();
223 dcachePort.setPeer(peer);
224 } else {
225 peer = dcachePort.getPeer();
226 }
227 peer->setPeer(&dcachePort);
228}
229
230
231void
232TimingSimpleCPU::activateContext(int thread_num, int delay)
233{
234 assert(thread_num == 0);
235 assert(thread);
236
237 assert(_status == Idle);
238
239 notIdleFraction++;
240 _status = Running;
241
242#if FULL_SYSTEM
243 // Connect the ThreadContext's memory ports (Functional/Virtual
244 // Ports)
245 tc->connectMemPorts();
246#endif
247
244 // kick things off by initiating the fetch of the next instruction
245 fetchEvent =
246 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
247 fetchEvent->schedule(nextCycle(curTick + cycles(delay)));
248}
249
250
251void
252TimingSimpleCPU::suspendContext(int thread_num)
253{
254 assert(thread_num == 0);
255 assert(thread);
256
257 assert(_status == Running);
258
259 // just change status to Idle... if status != Running,
260 // completeInst() will not initiate fetch of next instruction.
261
262 notIdleFraction--;
263 _status = Idle;
264}
265
266
267template <class T>
268Fault
269TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
270{
271 Request *req =
272 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
273 cpu_id, /* thread ID */ 0);
274
275 if (traceData) {
276 traceData->setAddr(req->getVaddr());
277 }
278
279 // translate to physical address
280 Fault fault = thread->translateDataReadReq(req);
281
282 // Now do the access.
283 if (fault == NoFault) {
284 PacketPtr pkt =
285 new Packet(req, Packet::ReadReq, Packet::Broadcast);
286 pkt->dataDynamic<T>(new T);
287
288 if (!dcachePort.sendTiming(pkt)) {
289 _status = DcacheRetry;
290 dcache_pkt = pkt;
291 } else {
292 _status = DcacheWaitResponse;
293 // memory system takes ownership of packet
294 dcache_pkt = NULL;
295 }
296 } else {
297 delete req;
298 }
299
300 // This will need a new way to tell if it has a dcache attached.
301 if (req->isUncacheable())
302 recordEvent("Uncached Read");
303
304 return fault;
305}
306
307#ifndef DOXYGEN_SHOULD_SKIP_THIS
308
309template
310Fault
311TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
312
313template
314Fault
315TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
316
317template
318Fault
319TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
320
321template
322Fault
323TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
324
325#endif //DOXYGEN_SHOULD_SKIP_THIS
326
327template<>
328Fault
329TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
330{
331 return read(addr, *(uint64_t*)&data, flags);
332}
333
334template<>
335Fault
336TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
337{
338 return read(addr, *(uint32_t*)&data, flags);
339}
340
341
342template<>
343Fault
344TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
345{
346 return read(addr, (uint32_t&)data, flags);
347}
348
349
350template <class T>
351Fault
352TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
353{
354 Request *req =
355 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
356 cpu_id, /* thread ID */ 0);
357
358 // translate to physical address
359 Fault fault = thread->translateDataWriteReq(req);
360
361 // Now do the access.
362 if (fault == NoFault) {
363 assert(dcache_pkt == NULL);
364 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
365 dcache_pkt->allocate();
366 dcache_pkt->set(data);
367
368 bool do_access = true; // flag to suppress cache access
369
370 if (req->isLocked()) {
371 do_access = TheISA::handleLockedWrite(thread, req);
372 }
373
374 if (do_access) {
375 if (!dcachePort.sendTiming(dcache_pkt)) {
376 _status = DcacheRetry;
377 } else {
378 _status = DcacheWaitResponse;
379 // memory system takes ownership of packet
380 dcache_pkt = NULL;
381 }
382 }
383 } else {
384 delete req;
385 }
386
387 // This will need a new way to tell if it's hooked up to a cache or not.
388 if (req->isUncacheable())
389 recordEvent("Uncached Write");
390
391 // If the write needs to have a fault on the access, consider calling
392 // changeStatus() and changing it to "bad addr write" or something.
393 return fault;
394}
395
396
397#ifndef DOXYGEN_SHOULD_SKIP_THIS
398template
399Fault
400TimingSimpleCPU::write(uint64_t data, Addr addr,
401 unsigned flags, uint64_t *res);
402
403template
404Fault
405TimingSimpleCPU::write(uint32_t data, Addr addr,
406 unsigned flags, uint64_t *res);
407
408template
409Fault
410TimingSimpleCPU::write(uint16_t data, Addr addr,
411 unsigned flags, uint64_t *res);
412
413template
414Fault
415TimingSimpleCPU::write(uint8_t data, Addr addr,
416 unsigned flags, uint64_t *res);
417
418#endif //DOXYGEN_SHOULD_SKIP_THIS
419
420template<>
421Fault
422TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
423{
424 return write(*(uint64_t*)&data, addr, flags, res);
425}
426
427template<>
428Fault
429TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
430{
431 return write(*(uint32_t*)&data, addr, flags, res);
432}
433
434
435template<>
436Fault
437TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
438{
439 return write((uint32_t)data, addr, flags, res);
440}
441
442
443void
444TimingSimpleCPU::fetch()
445{
446 if (!curStaticInst || !curStaticInst->isDelayedCommit())
447 checkForInterrupts();
448
449 Request *ifetch_req = new Request();
450 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0);
451 Fault fault = setupFetchRequest(ifetch_req);
452
453 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
454 ifetch_pkt->dataStatic(&inst);
455
456 if (fault == NoFault) {
457 if (!icachePort.sendTiming(ifetch_pkt)) {
458 // Need to wait for retry
459 _status = IcacheRetry;
460 } else {
461 // Need to wait for cache to respond
462 _status = IcacheWaitResponse;
463 // ownership of packet transferred to memory system
464 ifetch_pkt = NULL;
465 }
466 } else {
467 delete ifetch_req;
468 delete ifetch_pkt;
469 // fetch fault: advance directly to next instruction (fault handler)
470 advanceInst(fault);
471 }
472
473 numCycles += curTick - previousTick;
474 previousTick = curTick;
475}
476
477
478void
479TimingSimpleCPU::advanceInst(Fault fault)
480{
481 advancePC(fault);
482
483 if (_status == Running) {
484 // kick off fetch of next instruction... callback from icache
485 // response will cause that instruction to be executed,
486 // keeping the CPU running.
487 fetch();
488 }
489}
490
491
492void
493TimingSimpleCPU::completeIfetch(PacketPtr pkt)
494{
495 // received a response from the icache: execute the received
496 // instruction
497 assert(pkt->result == Packet::Success);
498 assert(_status == IcacheWaitResponse);
499
500 _status = Running;
501
502 numCycles += curTick - previousTick;
503 previousTick = curTick;
504
505 if (getState() == SimObject::Draining) {
506 delete pkt->req;
507 delete pkt;
508
509 completeDrain();
510 return;
511 }
512
513 preExecute();
514 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
515 // load or store: just send to dcache
516 Fault fault = curStaticInst->initiateAcc(this, traceData);
517 if (_status != Running) {
518 // instruction will complete in dcache response callback
519 assert(_status == DcacheWaitResponse || _status == DcacheRetry);
520 assert(fault == NoFault);
521 } else {
522 if (fault == NoFault) {
523 // early fail on store conditional: complete now
524 assert(dcache_pkt != NULL);
525 fault = curStaticInst->completeAcc(dcache_pkt, this,
526 traceData);
527 delete dcache_pkt->req;
528 delete dcache_pkt;
529 dcache_pkt = NULL;
530 }
531 postExecute();
532 advanceInst(fault);
533 }
534 } else {
535 // non-memory instruction: execute completely now
536 Fault fault = curStaticInst->execute(this, traceData);
537 postExecute();
538 advanceInst(fault);
539 }
540
541 delete pkt->req;
542 delete pkt;
543}
544
545void
546TimingSimpleCPU::IcachePort::ITickEvent::process()
547{
548 cpu->completeIfetch(pkt);
549}
550
551bool
552TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
553{
554 if (pkt->isResponse()) {
555 // delay processing of returned data until next CPU clock edge
556 Tick mem_time = pkt->req->getTime();
557 Tick next_tick = cpu->nextCycle(mem_time);
558
559 if (next_tick == curTick)
560 cpu->completeIfetch(pkt);
561 else
562 tickEvent.schedule(pkt, next_tick);
563
564 return true;
565 }
566 else {
567 //Snooping a Coherence Request, do nothing
568 return true;
569 }
570}
571
572void
573TimingSimpleCPU::IcachePort::recvRetry()
574{
575 // we shouldn't get a retry unless we have a packet that we're
576 // waiting to transmit
577 assert(cpu->ifetch_pkt != NULL);
578 assert(cpu->_status == IcacheRetry);
579 PacketPtr tmp = cpu->ifetch_pkt;
580 if (sendTiming(tmp)) {
581 cpu->_status = IcacheWaitResponse;
582 cpu->ifetch_pkt = NULL;
583 }
584}
585
586void
587TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
588{
589 // received a response from the dcache: complete the load or store
590 // instruction
591 assert(pkt->result == Packet::Success);
592 assert(_status == DcacheWaitResponse);
593 _status = Running;
594
595 numCycles += curTick - previousTick;
596 previousTick = curTick;
597
598 Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
599
600 if (pkt->isRead() && pkt->req->isLocked()) {
601 TheISA::handleLockedRead(thread, pkt->req);
602 }
603
604 delete pkt->req;
605 delete pkt;
606
607 postExecute();
608
609 if (getState() == SimObject::Draining) {
610 advancePC(fault);
611 completeDrain();
612
613 return;
614 }
615
616 advanceInst(fault);
617}
618
619
620void
621TimingSimpleCPU::completeDrain()
622{
623 DPRINTF(Config, "Done draining\n");
624 changeState(SimObject::Drained);
625 drainEvent->process();
626}
627
628bool
629TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
630{
631 if (pkt->isResponse()) {
632 // delay processing of returned data until next CPU clock edge
633 Tick mem_time = pkt->req->getTime();
634 Tick next_tick = cpu->nextCycle(mem_time);
635
636 if (next_tick == curTick)
637 cpu->completeDataAccess(pkt);
638 else
639 tickEvent.schedule(pkt, next_tick);
640
641 return true;
642 }
643 else {
644 //Snooping a coherence req, do nothing
645 return true;
646 }
647}
648
649void
650TimingSimpleCPU::DcachePort::DTickEvent::process()
651{
652 cpu->completeDataAccess(pkt);
653}
654
655void
656TimingSimpleCPU::DcachePort::recvRetry()
657{
658 // we shouldn't get a retry unless we have a packet that we're
659 // waiting to transmit
660 assert(cpu->dcache_pkt != NULL);
661 assert(cpu->_status == DcacheRetry);
662 PacketPtr tmp = cpu->dcache_pkt;
663 if (sendTiming(tmp)) {
664 cpu->_status = DcacheWaitResponse;
665 // memory system takes ownership of packet
666 cpu->dcache_pkt = NULL;
667 }
668}
669
670
671////////////////////////////////////////////////////////////////////////
672//
673// TimingSimpleCPU Simulation Object
674//
675BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
676
677 Param<Counter> max_insts_any_thread;
678 Param<Counter> max_insts_all_threads;
679 Param<Counter> max_loads_any_thread;
680 Param<Counter> max_loads_all_threads;
681 Param<Tick> progress_interval;
682 SimObjectParam<System *> system;
683 Param<int> cpu_id;
684
685#if FULL_SYSTEM
686 SimObjectParam<TheISA::ITB *> itb;
687 SimObjectParam<TheISA::DTB *> dtb;
688 Param<Tick> profile;
689
690 Param<bool> do_quiesce;
691 Param<bool> do_checkpoint_insts;
692 Param<bool> do_statistics_insts;
693#else
694 SimObjectParam<Process *> workload;
695#endif // FULL_SYSTEM
696
697 Param<int> clock;
698 Param<int> phase;
699
700 Param<bool> defer_registration;
701 Param<int> width;
702 Param<bool> function_trace;
703 Param<Tick> function_trace_start;
704 Param<bool> simulate_stalls;
705
706END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
707
708BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
709
710 INIT_PARAM(max_insts_any_thread,
711 "terminate when any thread reaches this inst count"),
712 INIT_PARAM(max_insts_all_threads,
713 "terminate when all threads have reached this inst count"),
714 INIT_PARAM(max_loads_any_thread,
715 "terminate when any thread reaches this load count"),
716 INIT_PARAM(max_loads_all_threads,
717 "terminate when all threads have reached this load count"),
718 INIT_PARAM(progress_interval, "Progress interval"),
719 INIT_PARAM(system, "system object"),
720 INIT_PARAM(cpu_id, "processor ID"),
721
722#if FULL_SYSTEM
723 INIT_PARAM(itb, "Instruction TLB"),
724 INIT_PARAM(dtb, "Data TLB"),
725 INIT_PARAM(profile, ""),
726 INIT_PARAM(do_quiesce, ""),
727 INIT_PARAM(do_checkpoint_insts, ""),
728 INIT_PARAM(do_statistics_insts, ""),
729#else
730 INIT_PARAM(workload, "processes to run"),
731#endif // FULL_SYSTEM
732
733 INIT_PARAM(clock, "clock speed"),
734 INIT_PARAM_DFLT(phase, "clock phase", 0),
735 INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
736 INIT_PARAM(width, "cpu width"),
737 INIT_PARAM(function_trace, "Enable function trace"),
738 INIT_PARAM(function_trace_start, "Cycle to start function trace"),
739 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
740
741END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
742
743
744CREATE_SIM_OBJECT(TimingSimpleCPU)
745{
746 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
747 params->name = getInstanceName();
748 params->numberOfThreads = 1;
749 params->max_insts_any_thread = max_insts_any_thread;
750 params->max_insts_all_threads = max_insts_all_threads;
751 params->max_loads_any_thread = max_loads_any_thread;
752 params->max_loads_all_threads = max_loads_all_threads;
753 params->progress_interval = progress_interval;
754 params->deferRegistration = defer_registration;
755 params->clock = clock;
756 params->phase = phase;
757 params->functionTrace = function_trace;
758 params->functionTraceStart = function_trace_start;
759 params->system = system;
760 params->cpu_id = cpu_id;
761
762#if FULL_SYSTEM
763 params->itb = itb;
764 params->dtb = dtb;
765 params->profile = profile;
766 params->do_quiesce = do_quiesce;
767 params->do_checkpoint_insts = do_checkpoint_insts;
768 params->do_statistics_insts = do_statistics_insts;
769#else
770 params->process = workload;
771#endif
772
773 TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
774 return cpu;
775}
776
777REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU)
778
248 // kick things off by initiating the fetch of the next instruction
249 fetchEvent =
250 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
251 fetchEvent->schedule(nextCycle(curTick + cycles(delay)));
252}
253
254
255void
256TimingSimpleCPU::suspendContext(int thread_num)
257{
258 assert(thread_num == 0);
259 assert(thread);
260
261 assert(_status == Running);
262
263 // just change status to Idle... if status != Running,
264 // completeInst() will not initiate fetch of next instruction.
265
266 notIdleFraction--;
267 _status = Idle;
268}
269
270
271template <class T>
272Fault
273TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
274{
275 Request *req =
276 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
277 cpu_id, /* thread ID */ 0);
278
279 if (traceData) {
280 traceData->setAddr(req->getVaddr());
281 }
282
283 // translate to physical address
284 Fault fault = thread->translateDataReadReq(req);
285
286 // Now do the access.
287 if (fault == NoFault) {
288 PacketPtr pkt =
289 new Packet(req, Packet::ReadReq, Packet::Broadcast);
290 pkt->dataDynamic<T>(new T);
291
292 if (!dcachePort.sendTiming(pkt)) {
293 _status = DcacheRetry;
294 dcache_pkt = pkt;
295 } else {
296 _status = DcacheWaitResponse;
297 // memory system takes ownership of packet
298 dcache_pkt = NULL;
299 }
300 } else {
301 delete req;
302 }
303
304 // This will need a new way to tell if it has a dcache attached.
305 if (req->isUncacheable())
306 recordEvent("Uncached Read");
307
308 return fault;
309}
310
311#ifndef DOXYGEN_SHOULD_SKIP_THIS
312
313template
314Fault
315TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
316
317template
318Fault
319TimingSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
320
321template
322Fault
323TimingSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
324
325template
326Fault
327TimingSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
328
329#endif //DOXYGEN_SHOULD_SKIP_THIS
330
331template<>
332Fault
333TimingSimpleCPU::read(Addr addr, double &data, unsigned flags)
334{
335 return read(addr, *(uint64_t*)&data, flags);
336}
337
338template<>
339Fault
340TimingSimpleCPU::read(Addr addr, float &data, unsigned flags)
341{
342 return read(addr, *(uint32_t*)&data, flags);
343}
344
345
346template<>
347Fault
348TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
349{
350 return read(addr, (uint32_t&)data, flags);
351}
352
353
354template <class T>
355Fault
356TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
357{
358 Request *req =
359 new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
360 cpu_id, /* thread ID */ 0);
361
362 // translate to physical address
363 Fault fault = thread->translateDataWriteReq(req);
364
365 // Now do the access.
366 if (fault == NoFault) {
367 assert(dcache_pkt == NULL);
368 dcache_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
369 dcache_pkt->allocate();
370 dcache_pkt->set(data);
371
372 bool do_access = true; // flag to suppress cache access
373
374 if (req->isLocked()) {
375 do_access = TheISA::handleLockedWrite(thread, req);
376 }
377
378 if (do_access) {
379 if (!dcachePort.sendTiming(dcache_pkt)) {
380 _status = DcacheRetry;
381 } else {
382 _status = DcacheWaitResponse;
383 // memory system takes ownership of packet
384 dcache_pkt = NULL;
385 }
386 }
387 } else {
388 delete req;
389 }
390
391 // This will need a new way to tell if it's hooked up to a cache or not.
392 if (req->isUncacheable())
393 recordEvent("Uncached Write");
394
395 // If the write needs to have a fault on the access, consider calling
396 // changeStatus() and changing it to "bad addr write" or something.
397 return fault;
398}
399
400
401#ifndef DOXYGEN_SHOULD_SKIP_THIS
402template
403Fault
404TimingSimpleCPU::write(uint64_t data, Addr addr,
405 unsigned flags, uint64_t *res);
406
407template
408Fault
409TimingSimpleCPU::write(uint32_t data, Addr addr,
410 unsigned flags, uint64_t *res);
411
412template
413Fault
414TimingSimpleCPU::write(uint16_t data, Addr addr,
415 unsigned flags, uint64_t *res);
416
417template
418Fault
419TimingSimpleCPU::write(uint8_t data, Addr addr,
420 unsigned flags, uint64_t *res);
421
422#endif //DOXYGEN_SHOULD_SKIP_THIS
423
424template<>
425Fault
426TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
427{
428 return write(*(uint64_t*)&data, addr, flags, res);
429}
430
431template<>
432Fault
433TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
434{
435 return write(*(uint32_t*)&data, addr, flags, res);
436}
437
438
439template<>
440Fault
441TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
442{
443 return write((uint32_t)data, addr, flags, res);
444}
445
446
447void
448TimingSimpleCPU::fetch()
449{
450 if (!curStaticInst || !curStaticInst->isDelayedCommit())
451 checkForInterrupts();
452
453 Request *ifetch_req = new Request();
454 ifetch_req->setThreadContext(cpu_id, /* thread ID */ 0);
455 Fault fault = setupFetchRequest(ifetch_req);
456
457 ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
458 ifetch_pkt->dataStatic(&inst);
459
460 if (fault == NoFault) {
461 if (!icachePort.sendTiming(ifetch_pkt)) {
462 // Need to wait for retry
463 _status = IcacheRetry;
464 } else {
465 // Need to wait for cache to respond
466 _status = IcacheWaitResponse;
467 // ownership of packet transferred to memory system
468 ifetch_pkt = NULL;
469 }
470 } else {
471 delete ifetch_req;
472 delete ifetch_pkt;
473 // fetch fault: advance directly to next instruction (fault handler)
474 advanceInst(fault);
475 }
476
477 numCycles += curTick - previousTick;
478 previousTick = curTick;
479}
480
481
482void
483TimingSimpleCPU::advanceInst(Fault fault)
484{
485 advancePC(fault);
486
487 if (_status == Running) {
488 // kick off fetch of next instruction... callback from icache
489 // response will cause that instruction to be executed,
490 // keeping the CPU running.
491 fetch();
492 }
493}
494
495
496void
497TimingSimpleCPU::completeIfetch(PacketPtr pkt)
498{
499 // received a response from the icache: execute the received
500 // instruction
501 assert(pkt->result == Packet::Success);
502 assert(_status == IcacheWaitResponse);
503
504 _status = Running;
505
506 numCycles += curTick - previousTick;
507 previousTick = curTick;
508
509 if (getState() == SimObject::Draining) {
510 delete pkt->req;
511 delete pkt;
512
513 completeDrain();
514 return;
515 }
516
517 preExecute();
518 if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
519 // load or store: just send to dcache
520 Fault fault = curStaticInst->initiateAcc(this, traceData);
521 if (_status != Running) {
522 // instruction will complete in dcache response callback
523 assert(_status == DcacheWaitResponse || _status == DcacheRetry);
524 assert(fault == NoFault);
525 } else {
526 if (fault == NoFault) {
527 // early fail on store conditional: complete now
528 assert(dcache_pkt != NULL);
529 fault = curStaticInst->completeAcc(dcache_pkt, this,
530 traceData);
531 delete dcache_pkt->req;
532 delete dcache_pkt;
533 dcache_pkt = NULL;
534 }
535 postExecute();
536 advanceInst(fault);
537 }
538 } else {
539 // non-memory instruction: execute completely now
540 Fault fault = curStaticInst->execute(this, traceData);
541 postExecute();
542 advanceInst(fault);
543 }
544
545 delete pkt->req;
546 delete pkt;
547}
548
549void
550TimingSimpleCPU::IcachePort::ITickEvent::process()
551{
552 cpu->completeIfetch(pkt);
553}
554
555bool
556TimingSimpleCPU::IcachePort::recvTiming(PacketPtr pkt)
557{
558 if (pkt->isResponse()) {
559 // delay processing of returned data until next CPU clock edge
560 Tick mem_time = pkt->req->getTime();
561 Tick next_tick = cpu->nextCycle(mem_time);
562
563 if (next_tick == curTick)
564 cpu->completeIfetch(pkt);
565 else
566 tickEvent.schedule(pkt, next_tick);
567
568 return true;
569 }
570 else {
571 //Snooping a Coherence Request, do nothing
572 return true;
573 }
574}
575
576void
577TimingSimpleCPU::IcachePort::recvRetry()
578{
579 // we shouldn't get a retry unless we have a packet that we're
580 // waiting to transmit
581 assert(cpu->ifetch_pkt != NULL);
582 assert(cpu->_status == IcacheRetry);
583 PacketPtr tmp = cpu->ifetch_pkt;
584 if (sendTiming(tmp)) {
585 cpu->_status = IcacheWaitResponse;
586 cpu->ifetch_pkt = NULL;
587 }
588}
589
590void
591TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
592{
593 // received a response from the dcache: complete the load or store
594 // instruction
595 assert(pkt->result == Packet::Success);
596 assert(_status == DcacheWaitResponse);
597 _status = Running;
598
599 numCycles += curTick - previousTick;
600 previousTick = curTick;
601
602 Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
603
604 if (pkt->isRead() && pkt->req->isLocked()) {
605 TheISA::handleLockedRead(thread, pkt->req);
606 }
607
608 delete pkt->req;
609 delete pkt;
610
611 postExecute();
612
613 if (getState() == SimObject::Draining) {
614 advancePC(fault);
615 completeDrain();
616
617 return;
618 }
619
620 advanceInst(fault);
621}
622
623
624void
625TimingSimpleCPU::completeDrain()
626{
627 DPRINTF(Config, "Done draining\n");
628 changeState(SimObject::Drained);
629 drainEvent->process();
630}
631
632bool
633TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
634{
635 if (pkt->isResponse()) {
636 // delay processing of returned data until next CPU clock edge
637 Tick mem_time = pkt->req->getTime();
638 Tick next_tick = cpu->nextCycle(mem_time);
639
640 if (next_tick == curTick)
641 cpu->completeDataAccess(pkt);
642 else
643 tickEvent.schedule(pkt, next_tick);
644
645 return true;
646 }
647 else {
648 //Snooping a coherence req, do nothing
649 return true;
650 }
651}
652
653void
654TimingSimpleCPU::DcachePort::DTickEvent::process()
655{
656 cpu->completeDataAccess(pkt);
657}
658
659void
660TimingSimpleCPU::DcachePort::recvRetry()
661{
662 // we shouldn't get a retry unless we have a packet that we're
663 // waiting to transmit
664 assert(cpu->dcache_pkt != NULL);
665 assert(cpu->_status == DcacheRetry);
666 PacketPtr tmp = cpu->dcache_pkt;
667 if (sendTiming(tmp)) {
668 cpu->_status = DcacheWaitResponse;
669 // memory system takes ownership of packet
670 cpu->dcache_pkt = NULL;
671 }
672}
673
674
675////////////////////////////////////////////////////////////////////////
676//
677// TimingSimpleCPU Simulation Object
678//
679BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
680
681 Param<Counter> max_insts_any_thread;
682 Param<Counter> max_insts_all_threads;
683 Param<Counter> max_loads_any_thread;
684 Param<Counter> max_loads_all_threads;
685 Param<Tick> progress_interval;
686 SimObjectParam<System *> system;
687 Param<int> cpu_id;
688
689#if FULL_SYSTEM
690 SimObjectParam<TheISA::ITB *> itb;
691 SimObjectParam<TheISA::DTB *> dtb;
692 Param<Tick> profile;
693
694 Param<bool> do_quiesce;
695 Param<bool> do_checkpoint_insts;
696 Param<bool> do_statistics_insts;
697#else
698 SimObjectParam<Process *> workload;
699#endif // FULL_SYSTEM
700
701 Param<int> clock;
702 Param<int> phase;
703
704 Param<bool> defer_registration;
705 Param<int> width;
706 Param<bool> function_trace;
707 Param<Tick> function_trace_start;
708 Param<bool> simulate_stalls;
709
710END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
711
712BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
713
714 INIT_PARAM(max_insts_any_thread,
715 "terminate when any thread reaches this inst count"),
716 INIT_PARAM(max_insts_all_threads,
717 "terminate when all threads have reached this inst count"),
718 INIT_PARAM(max_loads_any_thread,
719 "terminate when any thread reaches this load count"),
720 INIT_PARAM(max_loads_all_threads,
721 "terminate when all threads have reached this load count"),
722 INIT_PARAM(progress_interval, "Progress interval"),
723 INIT_PARAM(system, "system object"),
724 INIT_PARAM(cpu_id, "processor ID"),
725
726#if FULL_SYSTEM
727 INIT_PARAM(itb, "Instruction TLB"),
728 INIT_PARAM(dtb, "Data TLB"),
729 INIT_PARAM(profile, ""),
730 INIT_PARAM(do_quiesce, ""),
731 INIT_PARAM(do_checkpoint_insts, ""),
732 INIT_PARAM(do_statistics_insts, ""),
733#else
734 INIT_PARAM(workload, "processes to run"),
735#endif // FULL_SYSTEM
736
737 INIT_PARAM(clock, "clock speed"),
738 INIT_PARAM_DFLT(phase, "clock phase", 0),
739 INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
740 INIT_PARAM(width, "cpu width"),
741 INIT_PARAM(function_trace, "Enable function trace"),
742 INIT_PARAM(function_trace_start, "Cycle to start function trace"),
743 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles")
744
745END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
746
747
748CREATE_SIM_OBJECT(TimingSimpleCPU)
749{
750 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
751 params->name = getInstanceName();
752 params->numberOfThreads = 1;
753 params->max_insts_any_thread = max_insts_any_thread;
754 params->max_insts_all_threads = max_insts_all_threads;
755 params->max_loads_any_thread = max_loads_any_thread;
756 params->max_loads_all_threads = max_loads_all_threads;
757 params->progress_interval = progress_interval;
758 params->deferRegistration = defer_registration;
759 params->clock = clock;
760 params->phase = phase;
761 params->functionTrace = function_trace;
762 params->functionTraceStart = function_trace_start;
763 params->system = system;
764 params->cpu_id = cpu_id;
765
766#if FULL_SYSTEM
767 params->itb = itb;
768 params->dtb = dtb;
769 params->profile = profile;
770 params->do_quiesce = do_quiesce;
771 params->do_checkpoint_insts = do_checkpoint_insts;
772 params->do_statistics_insts = do_statistics_insts;
773#else
774 params->process = workload;
775#endif
776
777 TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
778 return cpu;
779}
780
781REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU)
782