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