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