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