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