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