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