timing.cc revision 2630
12810SN/A/* 22810SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan 32810SN/A * All rights reserved. 42810SN/A * 52810SN/A * Redistribution and use in source and binary forms, with or without 62810SN/A * modification, are permitted provided that the following conditions are 72810SN/A * met: redistributions of source code must retain the above copyright 82810SN/A * notice, this list of conditions and the following disclaimer; 92810SN/A * redistributions in binary form must reproduce the above copyright 102810SN/A * notice, this list of conditions and the following disclaimer in the 112810SN/A * documentation and/or other materials provided with the distribution; 122810SN/A * neither the name of the copyright holders nor the names of its 132810SN/A * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A */ 282810SN/A 292810SN/A#include "arch/utility.hh" 302810SN/A#include "cpu/exetrace.hh" 312810SN/A#include "cpu/simple/timing.hh" 322810SN/A#include "mem/packet_impl.hh" 333861SN/A#include "sim/builder.hh" 342810SN/A 352810SN/Ausing namespace std; 362810SN/Ausing namespace TheISA; 372810SN/A 382810SN/A 395338Sstever@gmail.comvoid 408831Smrinmoy.ghosh@arm.comTimingSimpleCPU::init() 418831Smrinmoy.ghosh@arm.com{ 422810SN/A //Create Memory Ports (conect them up) 433861SN/A Port *mem_dport = mem->getPort(""); 442810SN/A dcachePort.setPeer(mem_dport); 452810SN/A mem_dport->setPeer(&dcachePort); 462810SN/A 478831Smrinmoy.ghosh@arm.com Port *mem_iport = mem->getPort(""); 482810SN/A icachePort.setPeer(mem_iport); 492810SN/A mem_iport->setPeer(&icachePort); 502810SN/A 513349SN/A BaseCPU::init(); 522810SN/A#if FULL_SYSTEM 532810SN/A for (int i = 0; i < execContexts.size(); ++i) { 542810SN/A ExecContext *xc = execContexts[i]; 552810SN/A 56 // initialize CPU, including PC 57 TheISA::initCPU(xc, xc->readCpuId()); 58 } 59#endif 60} 61 62Tick 63TimingSimpleCPU::CpuPort::recvAtomic(Packet *pkt) 64{ 65 panic("TimingSimpleCPU doesn't expect recvAtomic callback!"); 66 return curTick; 67} 68 69void 70TimingSimpleCPU::CpuPort::recvFunctional(Packet *pkt) 71{ 72 panic("TimingSimpleCPU doesn't expect recvFunctional callback!"); 73} 74 75void 76TimingSimpleCPU::CpuPort::recvStatusChange(Status status) 77{ 78 panic("TimingSimpleCPU doesn't expect recvStatusChange callback!"); 79} 80 81TimingSimpleCPU::TimingSimpleCPU(Params *p) 82 : BaseSimpleCPU(p), icachePort(this), dcachePort(this) 83{ 84 _status = Idle; 85 ifetch_pkt = dcache_pkt = NULL; 86} 87 88 89TimingSimpleCPU::~TimingSimpleCPU() 90{ 91} 92 93void 94TimingSimpleCPU::serialize(ostream &os) 95{ 96 BaseSimpleCPU::serialize(os); 97 SERIALIZE_ENUM(_status); 98} 99 100void 101TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) 102{ 103 BaseSimpleCPU::unserialize(cp, section); 104 UNSERIALIZE_ENUM(_status); 105} 106 107void 108TimingSimpleCPU::switchOut(Sampler *s) 109{ 110 sampler = s; 111 if (status() == Running) { 112 _status = SwitchedOut; 113 } 114 sampler->signalSwitched(); 115} 116 117 118void 119TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU) 120{ 121 BaseCPU::takeOverFrom(oldCPU); 122 123 // if any of this CPU's ExecContexts are active, mark the CPU as 124 // running and schedule its tick event. 125 for (int i = 0; i < execContexts.size(); ++i) { 126 ExecContext *xc = execContexts[i]; 127 if (xc->status() == ExecContext::Active && _status != Running) { 128 _status = Running; 129 break; 130 } 131 } 132} 133 134 135void 136TimingSimpleCPU::activateContext(int thread_num, int delay) 137{ 138 assert(thread_num == 0); 139 assert(cpuXC); 140 141 assert(_status == Idle); 142 143 notIdleFraction++; 144 _status = Running; 145 // kick things off by initiating the fetch of the next instruction 146 Event *e = 147 new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true); 148 e->schedule(curTick + cycles(delay)); 149} 150 151 152void 153TimingSimpleCPU::suspendContext(int thread_num) 154{ 155 assert(thread_num == 0); 156 assert(cpuXC); 157 158 panic("TimingSimpleCPU::suspendContext not implemented"); 159 160 assert(_status == Running); 161 162 notIdleFraction--; 163 _status = Idle; 164} 165 166 167template <class T> 168Fault 169TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) 170{ 171 Request *data_read_req = new Request(true); 172 173 data_read_req->setVaddr(addr); 174 data_read_req->setSize(sizeof(T)); 175 data_read_req->setFlags(flags); 176 data_read_req->setTime(curTick); 177 178 if (traceData) { 179 traceData->setAddr(data_read_req->getVaddr()); 180 } 181 182 // translate to physical address 183 Fault fault = cpuXC->translateDataReadReq(data_read_req); 184 185 // Now do the access. 186 if (fault == NoFault) { 187 Packet *data_read_pkt = new Packet; 188 data_read_pkt->cmd = Read; 189 data_read_pkt->req = data_read_req; 190 data_read_pkt->dataDynamic<T>(new T); 191 data_read_pkt->addr = data_read_req->getPaddr(); 192 data_read_pkt->size = sizeof(T); 193 data_read_pkt->dest = Packet::Broadcast; 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 Request *data_write_req = new Request(true); 259 data_write_req->setVaddr(addr); 260 data_write_req->setTime(curTick); 261 data_write_req->setSize(sizeof(T)); 262 data_write_req->setFlags(flags); 263 264 // translate to physical address 265 Fault fault = cpuXC->translateDataWriteReq(data_write_req); 266 // Now do the access. 267 if (fault == NoFault) { 268 Packet *data_write_pkt = new Packet; 269 data_write_pkt->cmd = Write; 270 data_write_pkt->req = data_write_req; 271 data_write_pkt->allocate(); 272 data_write_pkt->size = sizeof(T); 273 data_write_pkt->set(data); 274 data_write_pkt->addr = data_write_req->getPaddr(); 275 data_write_pkt->dest = Packet::Broadcast; 276 277 if (!dcachePort.sendTiming(data_write_pkt)) { 278 _status = DcacheRetry; 279 dcache_pkt = data_write_pkt; 280 } else { 281 _status = DcacheWaitResponse; 282 dcache_pkt = NULL; 283 } 284 } 285 286 // This will need a new way to tell if it's hooked up to a cache or not. 287 if (data_write_req->getFlags() & UNCACHEABLE) 288 recordEvent("Uncached Write"); 289 290 // If the write needs to have a fault on the access, consider calling 291 // changeStatus() and changing it to "bad addr write" or something. 292 return fault; 293} 294 295 296#ifndef DOXYGEN_SHOULD_SKIP_THIS 297template 298Fault 299TimingSimpleCPU::write(uint64_t data, Addr addr, 300 unsigned flags, uint64_t *res); 301 302template 303Fault 304TimingSimpleCPU::write(uint32_t data, Addr addr, 305 unsigned flags, uint64_t *res); 306 307template 308Fault 309TimingSimpleCPU::write(uint16_t data, Addr addr, 310 unsigned flags, uint64_t *res); 311 312template 313Fault 314TimingSimpleCPU::write(uint8_t data, Addr addr, 315 unsigned flags, uint64_t *res); 316 317#endif //DOXYGEN_SHOULD_SKIP_THIS 318 319template<> 320Fault 321TimingSimpleCPU::write(double data, Addr addr, unsigned flags, uint64_t *res) 322{ 323 return write(*(uint64_t*)&data, addr, flags, res); 324} 325 326template<> 327Fault 328TimingSimpleCPU::write(float data, Addr addr, unsigned flags, uint64_t *res) 329{ 330 return write(*(uint32_t*)&data, addr, flags, res); 331} 332 333 334template<> 335Fault 336TimingSimpleCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res) 337{ 338 return write((uint32_t)data, addr, flags, res); 339} 340 341 342void 343TimingSimpleCPU::fetch() 344{ 345 Request *ifetch_req = new Request(true); 346 ifetch_req->setSize(sizeof(MachInst)); 347 348 ifetch_pkt = new Packet; 349 ifetch_pkt->cmd = Read; 350 ifetch_pkt->dataStatic(&inst); 351 ifetch_pkt->req = ifetch_req; 352 ifetch_pkt->size = sizeof(MachInst); 353 ifetch_pkt->dest = Packet::Broadcast; 354 355 Fault fault = setupFetchPacket(ifetch_pkt); 356 if (fault == NoFault) { 357 if (!icachePort.sendTiming(ifetch_pkt)) { 358 // Need to wait for retry 359 _status = IcacheRetry; 360 } else { 361 // Need to wait for cache to respond 362 _status = IcacheWaitResponse; 363 // ownership of packet transferred to memory system 364 ifetch_pkt = NULL; 365 } 366 } else { 367 panic("TimingSimpleCPU fetch fault handling not implemented"); 368 } 369} 370 371 372void 373TimingSimpleCPU::completeInst(Fault fault) 374{ 375 postExecute(); 376 377 if (traceData) { 378 traceData->finalize(); 379 } 380 381 advancePC(fault); 382 383 fetch(); 384} 385 386 387void 388TimingSimpleCPU::completeIfetch() 389{ 390 // received a response from the icache: execute the received 391 // instruction 392 assert(_status == IcacheWaitResponse); 393 _status = Running; 394 preExecute(); 395 if (curStaticInst->isMemRef()) { 396 // load or store: just send to dcache 397 Fault fault = curStaticInst->initiateAcc(this, traceData); 398 assert(fault == NoFault); 399 assert(_status == DcacheWaitResponse); 400 } else { 401 // non-memory instruction: execute completely now 402 Fault fault = curStaticInst->execute(this, traceData); 403 completeInst(fault); 404 } 405} 406 407 408bool 409TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt) 410{ 411 cpu->completeIfetch(); 412 return true; 413} 414 415Packet * 416TimingSimpleCPU::IcachePort::recvRetry() 417{ 418 // we shouldn't get a retry unless we have a packet that we're 419 // waiting to transmit 420 assert(cpu->ifetch_pkt != NULL); 421 assert(cpu->_status == IcacheRetry); 422 cpu->_status = IcacheWaitResponse; 423 Packet *tmp = cpu->ifetch_pkt; 424 cpu->ifetch_pkt = NULL; 425 return tmp; 426} 427 428void 429TimingSimpleCPU::completeDataAccess(Packet *pkt) 430{ 431 // received a response from the dcache: complete the load or store 432 // instruction 433 assert(pkt->result == Success); 434 assert(_status == DcacheWaitResponse); 435 _status = Running; 436 437 Fault fault = curStaticInst->completeAcc(pkt, this, traceData); 438 439 completeInst(fault); 440} 441 442 443 444bool 445TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) 446{ 447 cpu->completeDataAccess(pkt); 448 return true; 449} 450 451Packet * 452TimingSimpleCPU::DcachePort::recvRetry() 453{ 454 // we shouldn't get a retry unless we have a packet that we're 455 // waiting to transmit 456 assert(cpu->dcache_pkt != NULL); 457 assert(cpu->_status == DcacheRetry); 458 cpu->_status = DcacheWaitResponse; 459 Packet *tmp = cpu->dcache_pkt; 460 cpu->dcache_pkt = NULL; 461 return tmp; 462} 463 464 465//////////////////////////////////////////////////////////////////////// 466// 467// TimingSimpleCPU Simulation Object 468// 469BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 470 471 Param<Counter> max_insts_any_thread; 472 Param<Counter> max_insts_all_threads; 473 Param<Counter> max_loads_any_thread; 474 Param<Counter> max_loads_all_threads; 475 SimObjectParam<MemObject *> mem; 476 477#if FULL_SYSTEM 478 SimObjectParam<AlphaITB *> itb; 479 SimObjectParam<AlphaDTB *> dtb; 480 SimObjectParam<System *> system; 481 Param<int> cpu_id; 482 Param<Tick> profile; 483#else 484 SimObjectParam<Process *> workload; 485#endif // FULL_SYSTEM 486 487 Param<int> clock; 488 489 Param<bool> defer_registration; 490 Param<int> width; 491 Param<bool> function_trace; 492 Param<Tick> function_trace_start; 493 Param<bool> simulate_stalls; 494 495END_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU) 496 497BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 498 499 INIT_PARAM(max_insts_any_thread, 500 "terminate when any thread reaches this inst count"), 501 INIT_PARAM(max_insts_all_threads, 502 "terminate when all threads have reached this inst count"), 503 INIT_PARAM(max_loads_any_thread, 504 "terminate when any thread reaches this load count"), 505 INIT_PARAM(max_loads_all_threads, 506 "terminate when all threads have reached this load count"), 507 INIT_PARAM(mem, "memory"), 508 509#if FULL_SYSTEM 510 INIT_PARAM(itb, "Instruction TLB"), 511 INIT_PARAM(dtb, "Data TLB"), 512 INIT_PARAM(system, "system object"), 513 INIT_PARAM(cpu_id, "processor ID"), 514 INIT_PARAM(profile, ""), 515#else 516 INIT_PARAM(workload, "processes to run"), 517#endif // FULL_SYSTEM 518 519 INIT_PARAM(clock, "clock speed"), 520 INIT_PARAM(defer_registration, "defer system registration (for sampling)"), 521 INIT_PARAM(width, "cpu width"), 522 INIT_PARAM(function_trace, "Enable function trace"), 523 INIT_PARAM(function_trace_start, "Cycle to start function trace"), 524 INIT_PARAM(simulate_stalls, "Simulate cache stall cycles") 525 526END_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU) 527 528 529CREATE_SIM_OBJECT(TimingSimpleCPU) 530{ 531 TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params(); 532 params->name = getInstanceName(); 533 params->numberOfThreads = 1; 534 params->max_insts_any_thread = max_insts_any_thread; 535 params->max_insts_all_threads = max_insts_all_threads; 536 params->max_loads_any_thread = max_loads_any_thread; 537 params->max_loads_all_threads = max_loads_all_threads; 538 params->deferRegistration = defer_registration; 539 params->clock = clock; 540 params->functionTrace = function_trace; 541 params->functionTraceStart = function_trace_start; 542 params->mem = mem; 543 544#if FULL_SYSTEM 545 params->itb = itb; 546 params->dtb = dtb; 547 params->system = system; 548 params->cpu_id = cpu_id; 549 params->profile = profile; 550#else 551 params->process = workload; 552#endif 553 554 TimingSimpleCPU *cpu = new TimingSimpleCPU(params); 555 return cpu; 556} 557 558REGISTER_SIM_OBJECT("TimingSimpleCPU", TimingSimpleCPU) 559 560