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