atomic.cc (4928:951bd17db218) atomic.cc (4940:23874ae87540)
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 */
30
31#include "arch/locked_mem.hh"
32#include "arch/mmaped_ipr.hh"
33#include "arch/utility.hh"
34#include "base/bigint.hh"
35#include "cpu/exetrace.hh"
36#include "cpu/simple/atomic.hh"
37#include "mem/packet.hh"
38#include "mem/packet_access.hh"
39#include "params/AtomicSimpleCPU.hh"
40#include "sim/system.hh"
41
42using namespace std;
43using namespace TheISA;
44
45AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
46 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
47{
48}
49
50
51void
52AtomicSimpleCPU::TickEvent::process()
53{
54 cpu->tick();
55}
56
57const char *
58AtomicSimpleCPU::TickEvent::description()
59{
60 return "AtomicSimpleCPU tick";
61}
62
63Port *
64AtomicSimpleCPU::getPort(const std::string &if_name, int idx)
65{
66 if (if_name == "dcache_port")
67 return &dcachePort;
68 else if (if_name == "icache_port")
69 return &icachePort;
70 else
71 panic("No Such Port\n");
72}
73
74void
75AtomicSimpleCPU::init()
76{
77 BaseCPU::init();
78#if FULL_SYSTEM
79 for (int i = 0; i < threadContexts.size(); ++i) {
80 ThreadContext *tc = threadContexts[i];
81
82 // initialize CPU, including PC
83 TheISA::initCPU(tc, tc->readCpuId());
84 }
85#endif
86}
87
88bool
89AtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
90{
91 panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
92 return true;
93}
94
95Tick
96AtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
97{
98 //Snooping a coherence request, just return
99 return 0;
100}
101
102void
103AtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
104{
105 //No internal storage to update, just return
106 return;
107}
108
109void
110AtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
111{
112 if (status == RangeChange) {
113 if (!snoopRangeSent) {
114 snoopRangeSent = true;
115 sendStatusChange(Port::RangeChange);
116 }
117 return;
118 }
119
120 panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
121}
122
123void
124AtomicSimpleCPU::CpuPort::recvRetry()
125{
126 panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
127}
128
129void
130AtomicSimpleCPU::DcachePort::setPeer(Port *port)
131{
132 Port::setPeer(port);
133
134#if FULL_SYSTEM
135 // Update the ThreadContext's memory ports (Functional/Virtual
136 // Ports)
137 cpu->tcBase()->connectMemPorts();
138#endif
139}
140
141AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
142 : BaseSimpleCPU(p), tickEvent(this),
143 width(p->width), simulate_stalls(p->simulate_stalls),
144 icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
145{
146 _status = Idle;
147
148 icachePort.snoopRangeSent = false;
149 dcachePort.snoopRangeSent = false;
150
151 ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
152 data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
153 data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
154}
155
156
157AtomicSimpleCPU::~AtomicSimpleCPU()
158{
159}
160
161void
162AtomicSimpleCPU::serialize(ostream &os)
163{
164 SimObject::State so_state = SimObject::getState();
165 SERIALIZE_ENUM(so_state);
166 Status _status = status();
167 SERIALIZE_ENUM(_status);
168 BaseSimpleCPU::serialize(os);
169 nameOut(os, csprintf("%s.tickEvent", name()));
170 tickEvent.serialize(os);
171}
172
173void
174AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
175{
176 SimObject::State so_state;
177 UNSERIALIZE_ENUM(so_state);
178 UNSERIALIZE_ENUM(_status);
179 BaseSimpleCPU::unserialize(cp, section);
180 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
181}
182
183void
184AtomicSimpleCPU::resume()
185{
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Steve Reinhardt
29 */
30
31#include "arch/locked_mem.hh"
32#include "arch/mmaped_ipr.hh"
33#include "arch/utility.hh"
34#include "base/bigint.hh"
35#include "cpu/exetrace.hh"
36#include "cpu/simple/atomic.hh"
37#include "mem/packet.hh"
38#include "mem/packet_access.hh"
39#include "params/AtomicSimpleCPU.hh"
40#include "sim/system.hh"
41
42using namespace std;
43using namespace TheISA;
44
45AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
46 : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
47{
48}
49
50
51void
52AtomicSimpleCPU::TickEvent::process()
53{
54 cpu->tick();
55}
56
57const char *
58AtomicSimpleCPU::TickEvent::description()
59{
60 return "AtomicSimpleCPU tick";
61}
62
63Port *
64AtomicSimpleCPU::getPort(const std::string &if_name, int idx)
65{
66 if (if_name == "dcache_port")
67 return &dcachePort;
68 else if (if_name == "icache_port")
69 return &icachePort;
70 else
71 panic("No Such Port\n");
72}
73
74void
75AtomicSimpleCPU::init()
76{
77 BaseCPU::init();
78#if FULL_SYSTEM
79 for (int i = 0; i < threadContexts.size(); ++i) {
80 ThreadContext *tc = threadContexts[i];
81
82 // initialize CPU, including PC
83 TheISA::initCPU(tc, tc->readCpuId());
84 }
85#endif
86}
87
88bool
89AtomicSimpleCPU::CpuPort::recvTiming(PacketPtr pkt)
90{
91 panic("AtomicSimpleCPU doesn't expect recvTiming callback!");
92 return true;
93}
94
95Tick
96AtomicSimpleCPU::CpuPort::recvAtomic(PacketPtr pkt)
97{
98 //Snooping a coherence request, just return
99 return 0;
100}
101
102void
103AtomicSimpleCPU::CpuPort::recvFunctional(PacketPtr pkt)
104{
105 //No internal storage to update, just return
106 return;
107}
108
109void
110AtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
111{
112 if (status == RangeChange) {
113 if (!snoopRangeSent) {
114 snoopRangeSent = true;
115 sendStatusChange(Port::RangeChange);
116 }
117 return;
118 }
119
120 panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
121}
122
123void
124AtomicSimpleCPU::CpuPort::recvRetry()
125{
126 panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
127}
128
129void
130AtomicSimpleCPU::DcachePort::setPeer(Port *port)
131{
132 Port::setPeer(port);
133
134#if FULL_SYSTEM
135 // Update the ThreadContext's memory ports (Functional/Virtual
136 // Ports)
137 cpu->tcBase()->connectMemPorts();
138#endif
139}
140
141AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
142 : BaseSimpleCPU(p), tickEvent(this),
143 width(p->width), simulate_stalls(p->simulate_stalls),
144 icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this)
145{
146 _status = Idle;
147
148 icachePort.snoopRangeSent = false;
149 dcachePort.snoopRangeSent = false;
150
151 ifetch_req.setThreadContext(p->cpu_id, 0); // Add thread ID if we add MT
152 data_read_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
153 data_write_req.setThreadContext(p->cpu_id, 0); // Add thread ID here too
154}
155
156
157AtomicSimpleCPU::~AtomicSimpleCPU()
158{
159}
160
161void
162AtomicSimpleCPU::serialize(ostream &os)
163{
164 SimObject::State so_state = SimObject::getState();
165 SERIALIZE_ENUM(so_state);
166 Status _status = status();
167 SERIALIZE_ENUM(_status);
168 BaseSimpleCPU::serialize(os);
169 nameOut(os, csprintf("%s.tickEvent", name()));
170 tickEvent.serialize(os);
171}
172
173void
174AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
175{
176 SimObject::State so_state;
177 UNSERIALIZE_ENUM(so_state);
178 UNSERIALIZE_ENUM(_status);
179 BaseSimpleCPU::unserialize(cp, section);
180 tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
181}
182
183void
184AtomicSimpleCPU::resume()
185{
186 DPRINTF(SimpleCPU, "Resume\n");
186 if (_status != SwitchedOut && _status != Idle) {
187 assert(system->getMemoryMode() == Enums::atomic);
188
189 changeState(SimObject::Running);
190 if (thread->status() == ThreadContext::Active) {
191 if (!tickEvent.scheduled()) {
192 tickEvent.schedule(nextCycle());
193 }
194 }
195 }
196}
197
198void
199AtomicSimpleCPU::switchOut()
200{
201 assert(status() == Running || status() == Idle);
202 _status = SwitchedOut;
203
204 tickEvent.squash();
205}
206
207
208void
209AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
210{
211 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
212
213 assert(!tickEvent.scheduled());
214
215 // if any of this CPU's ThreadContexts are active, mark the CPU as
216 // running and schedule its tick event.
217 for (int i = 0; i < threadContexts.size(); ++i) {
218 ThreadContext *tc = threadContexts[i];
219 if (tc->status() == ThreadContext::Active && _status != Running) {
220 _status = Running;
221 tickEvent.schedule(nextCycle());
222 break;
223 }
224 }
225 if (_status != Running) {
226 _status = Idle;
227 }
228}
229
230
231void
232AtomicSimpleCPU::activateContext(int thread_num, int delay)
233{
187 if (_status != SwitchedOut && _status != Idle) {
188 assert(system->getMemoryMode() == Enums::atomic);
189
190 changeState(SimObject::Running);
191 if (thread->status() == ThreadContext::Active) {
192 if (!tickEvent.scheduled()) {
193 tickEvent.schedule(nextCycle());
194 }
195 }
196 }
197}
198
199void
200AtomicSimpleCPU::switchOut()
201{
202 assert(status() == Running || status() == Idle);
203 _status = SwitchedOut;
204
205 tickEvent.squash();
206}
207
208
209void
210AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
211{
212 BaseCPU::takeOverFrom(oldCPU, &icachePort, &dcachePort);
213
214 assert(!tickEvent.scheduled());
215
216 // if any of this CPU's ThreadContexts are active, mark the CPU as
217 // running and schedule its tick event.
218 for (int i = 0; i < threadContexts.size(); ++i) {
219 ThreadContext *tc = threadContexts[i];
220 if (tc->status() == ThreadContext::Active && _status != Running) {
221 _status = Running;
222 tickEvent.schedule(nextCycle());
223 break;
224 }
225 }
226 if (_status != Running) {
227 _status = Idle;
228 }
229}
230
231
232void
233AtomicSimpleCPU::activateContext(int thread_num, int delay)
234{
235 DPRINTF(SimpleCPU, "ActivateContext %d (%d cycles)\n", thread_num, delay);
236
234 assert(thread_num == 0);
235 assert(thread);
236
237 assert(_status == Idle);
238 assert(!tickEvent.scheduled());
239
240 notIdleFraction++;
241
242 //Make sure ticks are still on multiples of cycles
243 tickEvent.schedule(nextCycle(curTick + cycles(delay)));
244 _status = Running;
245}
246
247
248void
249AtomicSimpleCPU::suspendContext(int thread_num)
250{
237 assert(thread_num == 0);
238 assert(thread);
239
240 assert(_status == Idle);
241 assert(!tickEvent.scheduled());
242
243 notIdleFraction++;
244
245 //Make sure ticks are still on multiples of cycles
246 tickEvent.schedule(nextCycle(curTick + cycles(delay)));
247 _status = Running;
248}
249
250
251void
252AtomicSimpleCPU::suspendContext(int thread_num)
253{
254 DPRINTF(SimpleCPU, "SuspendContext %d\n", thread_num);
255
251 assert(thread_num == 0);
252 assert(thread);
253
254 assert(_status == Running);
255
256 // tick event may not be scheduled if this gets called from inside
257 // an instruction's execution, e.g. "quiesce"
258 if (tickEvent.scheduled())
259 tickEvent.deschedule();
260
261 notIdleFraction--;
262 _status = Idle;
263}
264
265
266template <class T>
267Fault
268AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
269{
270 // use the CPU's statically allocated read request and packet objects
271 Request *req = &data_read_req;
272 req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
273
274 if (traceData) {
275 traceData->setAddr(addr);
276 }
277
278 // translate to physical address
279 Fault fault = thread->translateDataReadReq(req);
280
281 // Now do the access.
282 if (fault == NoFault) {
283 Packet pkt =
284 Packet(req,
285 req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
286 Packet::Broadcast);
287 pkt.dataStatic(&data);
288
289 if (req->isMmapedIpr())
290 dcache_latency = TheISA::handleIprRead(thread->getTC(), &pkt);
291 else
292 dcache_latency = dcachePort.sendAtomic(&pkt);
293 dcache_access = true;
294 assert(!pkt.isError());
295
296 data = gtoh(data);
297
298 if (req->isLocked()) {
299 TheISA::handleLockedRead(thread, req);
300 }
301 }
302
303 // This will need a new way to tell if it has a dcache attached.
304 if (req->isUncacheable())
305 recordEvent("Uncached Read");
306
307 return fault;
308}
309
310#ifndef DOXYGEN_SHOULD_SKIP_THIS
311
312template
313Fault
314AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
315
316template
317Fault
318AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
319
320template
321Fault
322AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
323
324template
325Fault
326AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
327
328template
329Fault
330AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
331
332template
333Fault
334AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
335
336#endif //DOXYGEN_SHOULD_SKIP_THIS
337
338template<>
339Fault
340AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
341{
342 return read(addr, *(uint64_t*)&data, flags);
343}
344
345template<>
346Fault
347AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
348{
349 return read(addr, *(uint32_t*)&data, flags);
350}
351
352
353template<>
354Fault
355AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
356{
357 return read(addr, (uint32_t&)data, flags);
358}
359
360
361template <class T>
362Fault
363AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
364{
365 // use the CPU's statically allocated write request and packet objects
366 Request *req = &data_write_req;
367 req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
368
369 if (traceData) {
370 traceData->setAddr(addr);
371 }
372
373 // translate to physical address
374 Fault fault = thread->translateDataWriteReq(req);
375
376 // Now do the access.
377 if (fault == NoFault) {
378 MemCmd cmd = MemCmd::WriteReq; // default
379 bool do_access = true; // flag to suppress cache access
380
381 if (req->isLocked()) {
382 cmd = MemCmd::StoreCondReq;
383 do_access = TheISA::handleLockedWrite(thread, req);
384 } else if (req->isSwap()) {
385 cmd = MemCmd::SwapReq;
386 if (req->isCondSwap()) {
387 assert(res);
388 req->setExtraData(*res);
389 }
390 }
391
392 if (do_access) {
393 Packet pkt = Packet(req, cmd, Packet::Broadcast);
394 pkt.dataStatic(&data);
395
396 if (req->isMmapedIpr()) {
397 dcache_latency = TheISA::handleIprWrite(thread->getTC(), &pkt);
398 } else {
399 data = htog(data);
400 dcache_latency = dcachePort.sendAtomic(&pkt);
401 }
402 dcache_access = true;
403 assert(!pkt.isError());
404
405 if (req->isSwap()) {
406 assert(res);
407 *res = pkt.get<T>();
408 }
409 }
410
411 if (res && !req->isSwap()) {
412 *res = req->getExtraData();
413 }
414 }
415
416 // This will need a new way to tell if it's hooked up to a cache or not.
417 if (req->isUncacheable())
418 recordEvent("Uncached Write");
419
420 // If the write needs to have a fault on the access, consider calling
421 // changeStatus() and changing it to "bad addr write" or something.
422 return fault;
423}
424
425
426#ifndef DOXYGEN_SHOULD_SKIP_THIS
427
428template
429Fault
430AtomicSimpleCPU::write(Twin32_t data, Addr addr,
431 unsigned flags, uint64_t *res);
432
433template
434Fault
435AtomicSimpleCPU::write(Twin64_t data, Addr addr,
436 unsigned flags, uint64_t *res);
437
438template
439Fault
440AtomicSimpleCPU::write(uint64_t data, Addr addr,
441 unsigned flags, uint64_t *res);
442
443template
444Fault
445AtomicSimpleCPU::write(uint32_t data, Addr addr,
446 unsigned flags, uint64_t *res);
447
448template
449Fault
450AtomicSimpleCPU::write(uint16_t data, Addr addr,
451 unsigned flags, uint64_t *res);
452
453template
454Fault
455AtomicSimpleCPU::write(uint8_t data, Addr addr,
456 unsigned flags, uint64_t *res);
457
458#endif //DOXYGEN_SHOULD_SKIP_THIS
459
460template<>
461Fault
462AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
463{
464 return write(*(uint64_t*)&data, addr, flags, res);
465}
466
467template<>
468Fault
469AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
470{
471 return write(*(uint32_t*)&data, addr, flags, res);
472}
473
474
475template<>
476Fault
477AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
478{
479 return write((uint32_t)data, addr, flags, res);
480}
481
482
483void
484AtomicSimpleCPU::tick()
485{
256 assert(thread_num == 0);
257 assert(thread);
258
259 assert(_status == Running);
260
261 // tick event may not be scheduled if this gets called from inside
262 // an instruction's execution, e.g. "quiesce"
263 if (tickEvent.scheduled())
264 tickEvent.deschedule();
265
266 notIdleFraction--;
267 _status = Idle;
268}
269
270
271template <class T>
272Fault
273AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
274{
275 // use the CPU's statically allocated read request and packet objects
276 Request *req = &data_read_req;
277 req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
278
279 if (traceData) {
280 traceData->setAddr(addr);
281 }
282
283 // translate to physical address
284 Fault fault = thread->translateDataReadReq(req);
285
286 // Now do the access.
287 if (fault == NoFault) {
288 Packet pkt =
289 Packet(req,
290 req->isLocked() ? MemCmd::LoadLockedReq : MemCmd::ReadReq,
291 Packet::Broadcast);
292 pkt.dataStatic(&data);
293
294 if (req->isMmapedIpr())
295 dcache_latency = TheISA::handleIprRead(thread->getTC(), &pkt);
296 else
297 dcache_latency = dcachePort.sendAtomic(&pkt);
298 dcache_access = true;
299 assert(!pkt.isError());
300
301 data = gtoh(data);
302
303 if (req->isLocked()) {
304 TheISA::handleLockedRead(thread, req);
305 }
306 }
307
308 // This will need a new way to tell if it has a dcache attached.
309 if (req->isUncacheable())
310 recordEvent("Uncached Read");
311
312 return fault;
313}
314
315#ifndef DOXYGEN_SHOULD_SKIP_THIS
316
317template
318Fault
319AtomicSimpleCPU::read(Addr addr, Twin32_t &data, unsigned flags);
320
321template
322Fault
323AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
324
325template
326Fault
327AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
328
329template
330Fault
331AtomicSimpleCPU::read(Addr addr, uint32_t &data, unsigned flags);
332
333template
334Fault
335AtomicSimpleCPU::read(Addr addr, uint16_t &data, unsigned flags);
336
337template
338Fault
339AtomicSimpleCPU::read(Addr addr, uint8_t &data, unsigned flags);
340
341#endif //DOXYGEN_SHOULD_SKIP_THIS
342
343template<>
344Fault
345AtomicSimpleCPU::read(Addr addr, double &data, unsigned flags)
346{
347 return read(addr, *(uint64_t*)&data, flags);
348}
349
350template<>
351Fault
352AtomicSimpleCPU::read(Addr addr, float &data, unsigned flags)
353{
354 return read(addr, *(uint32_t*)&data, flags);
355}
356
357
358template<>
359Fault
360AtomicSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
361{
362 return read(addr, (uint32_t&)data, flags);
363}
364
365
366template <class T>
367Fault
368AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
369{
370 // use the CPU's statically allocated write request and packet objects
371 Request *req = &data_write_req;
372 req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
373
374 if (traceData) {
375 traceData->setAddr(addr);
376 }
377
378 // translate to physical address
379 Fault fault = thread->translateDataWriteReq(req);
380
381 // Now do the access.
382 if (fault == NoFault) {
383 MemCmd cmd = MemCmd::WriteReq; // default
384 bool do_access = true; // flag to suppress cache access
385
386 if (req->isLocked()) {
387 cmd = MemCmd::StoreCondReq;
388 do_access = TheISA::handleLockedWrite(thread, req);
389 } else if (req->isSwap()) {
390 cmd = MemCmd::SwapReq;
391 if (req->isCondSwap()) {
392 assert(res);
393 req->setExtraData(*res);
394 }
395 }
396
397 if (do_access) {
398 Packet pkt = Packet(req, cmd, Packet::Broadcast);
399 pkt.dataStatic(&data);
400
401 if (req->isMmapedIpr()) {
402 dcache_latency = TheISA::handleIprWrite(thread->getTC(), &pkt);
403 } else {
404 data = htog(data);
405 dcache_latency = dcachePort.sendAtomic(&pkt);
406 }
407 dcache_access = true;
408 assert(!pkt.isError());
409
410 if (req->isSwap()) {
411 assert(res);
412 *res = pkt.get<T>();
413 }
414 }
415
416 if (res && !req->isSwap()) {
417 *res = req->getExtraData();
418 }
419 }
420
421 // This will need a new way to tell if it's hooked up to a cache or not.
422 if (req->isUncacheable())
423 recordEvent("Uncached Write");
424
425 // If the write needs to have a fault on the access, consider calling
426 // changeStatus() and changing it to "bad addr write" or something.
427 return fault;
428}
429
430
431#ifndef DOXYGEN_SHOULD_SKIP_THIS
432
433template
434Fault
435AtomicSimpleCPU::write(Twin32_t data, Addr addr,
436 unsigned flags, uint64_t *res);
437
438template
439Fault
440AtomicSimpleCPU::write(Twin64_t data, Addr addr,
441 unsigned flags, uint64_t *res);
442
443template
444Fault
445AtomicSimpleCPU::write(uint64_t data, Addr addr,
446 unsigned flags, uint64_t *res);
447
448template
449Fault
450AtomicSimpleCPU::write(uint32_t data, Addr addr,
451 unsigned flags, uint64_t *res);
452
453template
454Fault
455AtomicSimpleCPU::write(uint16_t data, Addr addr,
456 unsigned flags, uint64_t *res);
457
458template
459Fault
460AtomicSimpleCPU::write(uint8_t data, Addr addr,
461 unsigned flags, uint64_t *res);
462
463#endif //DOXYGEN_SHOULD_SKIP_THIS
464
465template<>
466Fault
467AtomicSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
468{
469 return write(*(uint64_t*)&data, addr, flags, res);
470}
471
472template<>
473Fault
474AtomicSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
475{
476 return write(*(uint32_t*)&data, addr, flags, res);
477}
478
479
480template<>
481Fault
482AtomicSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
483{
484 return write((uint32_t)data, addr, flags, res);
485}
486
487
488void
489AtomicSimpleCPU::tick()
490{
491 DPRINTF(SimpleCPU, "Tick\n");
492
486 Tick latency = cycles(1); // instruction takes one cycle by default
487
488 for (int i = 0; i < width; ++i) {
489 numCycles++;
490
491 if (!curStaticInst || !curStaticInst->isDelayedCommit())
492 checkForInterrupts();
493
494 Fault fault = setupFetchRequest(&ifetch_req);
495
496 if (fault == NoFault) {
497 Tick icache_latency = 0;
498 bool icache_access = false;
499 dcache_access = false; // assume no dcache access
500
501 //Fetch more instruction memory if necessary
502 //if(predecoder.needMoreBytes())
503 //{
504 icache_access = true;
505 Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
506 Packet::Broadcast);
507 ifetch_pkt.dataStatic(&inst);
508
509 icache_latency = icachePort.sendAtomic(&ifetch_pkt);
510 // ifetch_req is initialized to read the instruction directly
511 // into the CPU object's inst field.
512 //}
513
514 preExecute();
515
516 if(curStaticInst)
517 {
518 fault = curStaticInst->execute(this, traceData);
519 postExecute();
520 }
521
522 // @todo remove me after debugging with legion done
523 if (curStaticInst && (!curStaticInst->isMicroop() ||
524 curStaticInst->isFirstMicroop()))
525 instCnt++;
526
527 if (simulate_stalls) {
528 Tick icache_stall =
529 icache_access ? icache_latency - cycles(1) : 0;
530 Tick dcache_stall =
531 dcache_access ? dcache_latency - cycles(1) : 0;
532 Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
533 if (cycles(stall_cycles) < (icache_stall + dcache_stall))
534 latency += cycles(stall_cycles+1);
535 else
536 latency += cycles(stall_cycles);
537 }
538
539 }
540 if(fault != NoFault || !stayAtPC)
541 advancePC(fault);
542 }
543
544 if (_status != Idle)
545 tickEvent.schedule(curTick + latency);
546}
547
548
549////////////////////////////////////////////////////////////////////////
550//
551// AtomicSimpleCPU Simulation Object
552//
553AtomicSimpleCPU *
554AtomicSimpleCPUParams::create()
555{
556 AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
557 params->name = name;
558 params->numberOfThreads = 1;
559 params->max_insts_any_thread = max_insts_any_thread;
560 params->max_insts_all_threads = max_insts_all_threads;
561 params->max_loads_any_thread = max_loads_any_thread;
562 params->max_loads_all_threads = max_loads_all_threads;
563 params->progress_interval = progress_interval;
564 params->deferRegistration = defer_registration;
565 params->phase = phase;
566 params->clock = clock;
567 params->functionTrace = function_trace;
568 params->functionTraceStart = function_trace_start;
569 params->width = width;
570 params->simulate_stalls = simulate_stalls;
571 params->system = system;
572 params->cpu_id = cpu_id;
573 params->tracer = tracer;
574
575#if FULL_SYSTEM
576 params->itb = itb;
577 params->dtb = dtb;
578 params->profile = profile;
579 params->do_quiesce = do_quiesce;
580 params->do_checkpoint_insts = do_checkpoint_insts;
581 params->do_statistics_insts = do_statistics_insts;
582#else
583 if (workload.size() != 1)
584 panic("only one workload allowed");
585 params->process = workload[0];
586#endif
587
588 AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
589 return cpu;
590}
493 Tick latency = cycles(1); // instruction takes one cycle by default
494
495 for (int i = 0; i < width; ++i) {
496 numCycles++;
497
498 if (!curStaticInst || !curStaticInst->isDelayedCommit())
499 checkForInterrupts();
500
501 Fault fault = setupFetchRequest(&ifetch_req);
502
503 if (fault == NoFault) {
504 Tick icache_latency = 0;
505 bool icache_access = false;
506 dcache_access = false; // assume no dcache access
507
508 //Fetch more instruction memory if necessary
509 //if(predecoder.needMoreBytes())
510 //{
511 icache_access = true;
512 Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
513 Packet::Broadcast);
514 ifetch_pkt.dataStatic(&inst);
515
516 icache_latency = icachePort.sendAtomic(&ifetch_pkt);
517 // ifetch_req is initialized to read the instruction directly
518 // into the CPU object's inst field.
519 //}
520
521 preExecute();
522
523 if(curStaticInst)
524 {
525 fault = curStaticInst->execute(this, traceData);
526 postExecute();
527 }
528
529 // @todo remove me after debugging with legion done
530 if (curStaticInst && (!curStaticInst->isMicroop() ||
531 curStaticInst->isFirstMicroop()))
532 instCnt++;
533
534 if (simulate_stalls) {
535 Tick icache_stall =
536 icache_access ? icache_latency - cycles(1) : 0;
537 Tick dcache_stall =
538 dcache_access ? dcache_latency - cycles(1) : 0;
539 Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
540 if (cycles(stall_cycles) < (icache_stall + dcache_stall))
541 latency += cycles(stall_cycles+1);
542 else
543 latency += cycles(stall_cycles);
544 }
545
546 }
547 if(fault != NoFault || !stayAtPC)
548 advancePC(fault);
549 }
550
551 if (_status != Idle)
552 tickEvent.schedule(curTick + latency);
553}
554
555
556////////////////////////////////////////////////////////////////////////
557//
558// AtomicSimpleCPU Simulation Object
559//
560AtomicSimpleCPU *
561AtomicSimpleCPUParams::create()
562{
563 AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
564 params->name = name;
565 params->numberOfThreads = 1;
566 params->max_insts_any_thread = max_insts_any_thread;
567 params->max_insts_all_threads = max_insts_all_threads;
568 params->max_loads_any_thread = max_loads_any_thread;
569 params->max_loads_all_threads = max_loads_all_threads;
570 params->progress_interval = progress_interval;
571 params->deferRegistration = defer_registration;
572 params->phase = phase;
573 params->clock = clock;
574 params->functionTrace = function_trace;
575 params->functionTraceStart = function_trace_start;
576 params->width = width;
577 params->simulate_stalls = simulate_stalls;
578 params->system = system;
579 params->cpu_id = cpu_id;
580 params->tracer = tracer;
581
582#if FULL_SYSTEM
583 params->itb = itb;
584 params->dtb = dtb;
585 params->profile = profile;
586 params->do_quiesce = do_quiesce;
587 params->do_checkpoint_insts = do_checkpoint_insts;
588 params->do_statistics_insts = do_statistics_insts;
589#else
590 if (workload.size() != 1)
591 panic("only one workload allowed");
592 params->process = workload[0];
593#endif
594
595 AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
596 return cpu;
597}