thread_context_impl.hh revision 5235:f07f46843886
1/* 2 * Copyright (c) 2004-2006 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: Kevin Lim 29 * Korey Sewell 30 */ 31 32#include "arch/regfile.hh" 33#include "cpu/o3/thread_context.hh" 34#include "cpu/quiesce_event.hh" 35 36#if FULL_SYSTEM 37template <class Impl> 38VirtualPort * 39O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc) 40{ 41 if (!src_tc) 42 return thread->getVirtPort(); 43 44 VirtualPort *vp; 45 46 vp = new VirtualPort("tc-vport", src_tc); 47 thread->connectToMemFunc(vp); 48 return vp; 49} 50 51template <class Impl> 52void 53O3ThreadContext<Impl>::dumpFuncProfile() 54{ 55 thread->dumpFuncProfile(); 56} 57#endif 58 59template <class Impl> 60void 61O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context) 62{ 63 // some things should already be set up 64#if FULL_SYSTEM 65 assert(getSystemPtr() == old_context->getSystemPtr()); 66#else 67 assert(getProcessPtr() == old_context->getProcessPtr()); 68#endif 69 70 // copy over functional state 71 setStatus(old_context->status()); 72 copyArchRegs(old_context); 73 setCpuId(old_context->readCpuId()); 74 75#if !FULL_SYSTEM 76 thread->funcExeInst = old_context->readFuncExeInst(); 77#else 78 EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent(); 79 if (other_quiesce) { 80 // Point the quiesce event's TC at this TC so that it wakes up 81 // the proper CPU. 82 other_quiesce->tc = this; 83 } 84 if (thread->quiesceEvent) { 85 thread->quiesceEvent->tc = this; 86 } 87 88 // Transfer kernel stats from one CPU to the other. 89 thread->kernelStats = old_context->getKernelStats(); 90// storeCondFailures = 0; 91 cpu->lockFlag = false; 92#endif 93 94 old_context->setStatus(ThreadContext::Unallocated); 95 96 thread->inSyscall = false; 97 thread->trapPending = false; 98} 99 100#if FULL_SYSTEM 101template <class Impl> 102void 103O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp) 104{ 105 if (vp != thread->getVirtPort()) { 106 vp->removeConn(); 107 delete vp; 108 } 109} 110#endif 111 112template <class Impl> 113void 114O3ThreadContext<Impl>::activate(int delay) 115{ 116 DPRINTF(O3CPU, "Calling activate on Thread Context %d\n", 117 getThreadNum()); 118 119 if (thread->status() == ThreadContext::Active) 120 return; 121 122#if FULL_SYSTEM 123 thread->lastActivate = curTick; 124#endif 125 126 if (thread->status() == ThreadContext::Unallocated) { 127 cpu->activateWhenReady(thread->readTid()); 128 return; 129 } 130 131 thread->setStatus(ThreadContext::Active); 132 133 // status() == Suspended 134 cpu->activateContext(thread->readTid(), delay); 135} 136 137template <class Impl> 138void 139O3ThreadContext<Impl>::suspend() 140{ 141 DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n", 142 getThreadNum()); 143 144 if (thread->status() == ThreadContext::Suspended) 145 return; 146 147#if FULL_SYSTEM 148 thread->lastActivate = curTick; 149 thread->lastSuspend = curTick; 150#endif 151/* 152#if FULL_SYSTEM 153 // Don't change the status from active if there are pending interrupts 154 if (cpu->check_interrupts()) { 155 assert(status() == ThreadContext::Active); 156 return; 157 } 158#endif 159*/ 160 thread->setStatus(ThreadContext::Suspended); 161 cpu->suspendContext(thread->readTid()); 162} 163 164template <class Impl> 165void 166O3ThreadContext<Impl>::deallocate(int delay) 167{ 168 DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n", 169 getThreadNum(), delay); 170 171 if (thread->status() == ThreadContext::Unallocated) 172 return; 173 174 thread->setStatus(ThreadContext::Unallocated); 175 cpu->deallocateContext(thread->readTid(), true, delay); 176} 177 178template <class Impl> 179void 180O3ThreadContext<Impl>::halt() 181{ 182 DPRINTF(O3CPU, "Calling halt on Thread Context %d\n", 183 getThreadNum()); 184 185 if (thread->status() == ThreadContext::Halted) 186 return; 187 188 thread->setStatus(ThreadContext::Halted); 189 cpu->haltContext(thread->readTid()); 190} 191 192template <class Impl> 193void 194O3ThreadContext<Impl>::regStats(const std::string &name) 195{ 196#if FULL_SYSTEM 197 thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system); 198 thread->kernelStats->regStats(name + ".kern"); 199#endif 200} 201 202template <class Impl> 203void 204O3ThreadContext<Impl>::serialize(std::ostream &os) 205{ 206#if FULL_SYSTEM 207 if (thread->kernelStats) 208 thread->kernelStats->serialize(os); 209#endif 210 211} 212 213template <class Impl> 214void 215O3ThreadContext<Impl>::unserialize(Checkpoint *cp, const std::string §ion) 216{ 217#if FULL_SYSTEM 218 if (thread->kernelStats) 219 thread->kernelStats->unserialize(cp, section); 220#endif 221 222} 223 224#if FULL_SYSTEM 225template <class Impl> 226Tick 227O3ThreadContext<Impl>::readLastActivate() 228{ 229 return thread->lastActivate; 230} 231 232template <class Impl> 233Tick 234O3ThreadContext<Impl>::readLastSuspend() 235{ 236 return thread->lastSuspend; 237} 238 239template <class Impl> 240void 241O3ThreadContext<Impl>::profileClear() 242{ 243 thread->profileClear(); 244} 245 246template <class Impl> 247void 248O3ThreadContext<Impl>::profileSample() 249{ 250 thread->profileSample(); 251} 252#endif 253 254template <class Impl> 255TheISA::MachInst 256O3ThreadContext<Impl>:: getInst() 257{ 258 return thread->getInst(); 259} 260 261template <class Impl> 262void 263O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc) 264{ 265 // This function will mess things up unless the ROB is empty and 266 // there are no instructions in the pipeline. 267 unsigned tid = thread->readTid(); 268 PhysRegIndex renamed_reg; 269 270 // First loop through the integer registers. 271 for (int i = 0; i < TheISA::NumIntRegs; ++i) { 272 renamed_reg = cpu->renameMap[tid].lookup(i); 273 274 DPRINTF(O3CPU, "Copying over register %i, had data %lli, " 275 "now has data %lli.\n", 276 renamed_reg, cpu->readIntReg(renamed_reg), 277 tc->readIntReg(i)); 278 279 cpu->setIntReg(renamed_reg, tc->readIntReg(i)); 280 } 281 282 // Then loop through the floating point registers. 283 for (int i = 0; i < TheISA::NumFloatRegs; ++i) { 284 renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag); 285 cpu->setFloatRegBits(renamed_reg, 286 tc->readFloatRegBits(i)); 287 } 288 289 // Copy the misc regs. 290 TheISA::copyMiscRegs(tc, this); 291 292 // Then finally set the PC, the next PC, the nextNPC, the micropc, and the 293 // next micropc. 294 cpu->setPC(tc->readPC(), tid); 295 cpu->setNextPC(tc->readNextPC(), tid); 296 cpu->setNextNPC(tc->readNextNPC(), tid); 297 cpu->setMicroPC(tc->readMicroPC(), tid); 298 cpu->setNextMicroPC(tc->readNextMicroPC(), tid); 299#if !FULL_SYSTEM 300 this->thread->funcExeInst = tc->readFuncExeInst(); 301#endif 302} 303 304template <class Impl> 305void 306O3ThreadContext<Impl>::clearArchRegs() 307{} 308 309template <class Impl> 310uint64_t 311O3ThreadContext<Impl>::readIntReg(int reg_idx) 312{ 313 reg_idx = TheISA::flattenIntIndex(this, reg_idx); 314 return cpu->readArchIntReg(reg_idx, thread->readTid()); 315} 316 317template <class Impl> 318TheISA::FloatReg 319O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width) 320{ 321 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 322 switch(width) { 323 case 32: 324 return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); 325 case 64: 326 return cpu->readArchFloatRegDouble(reg_idx, thread->readTid()); 327 default: 328 panic("Unsupported width!"); 329 return 0; 330 } 331} 332 333template <class Impl> 334TheISA::FloatReg 335O3ThreadContext<Impl>::readFloatReg(int reg_idx) 336{ 337 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 338 return cpu->readArchFloatRegSingle(reg_idx, thread->readTid()); 339} 340 341template <class Impl> 342TheISA::FloatRegBits 343O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width) 344{ 345 DPRINTF(Fault, "Reading floatint register through the TC!\n"); 346 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 347 return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); 348} 349 350template <class Impl> 351TheISA::FloatRegBits 352O3ThreadContext<Impl>::readFloatRegBits(int reg_idx) 353{ 354 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 355 return cpu->readArchFloatRegInt(reg_idx, thread->readTid()); 356} 357 358template <class Impl> 359void 360O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val) 361{ 362 reg_idx = TheISA::flattenIntIndex(this, reg_idx); 363 cpu->setArchIntReg(reg_idx, val, thread->readTid()); 364 365 // Squash if we're not already in a state update mode. 366 if (!thread->trapPending && !thread->inSyscall) { 367 cpu->squashFromTC(thread->readTid()); 368 } 369} 370 371template <class Impl> 372void 373O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width) 374{ 375 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 376 switch(width) { 377 case 32: 378 cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); 379 break; 380 case 64: 381 cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid()); 382 break; 383 } 384 385 // Squash if we're not already in a state update mode. 386 if (!thread->trapPending && !thread->inSyscall) { 387 cpu->squashFromTC(thread->readTid()); 388 } 389} 390 391template <class Impl> 392void 393O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val) 394{ 395 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 396 cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid()); 397 398 if (!thread->trapPending && !thread->inSyscall) { 399 cpu->squashFromTC(thread->readTid()); 400 } 401} 402 403template <class Impl> 404void 405O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val, 406 int width) 407{ 408 DPRINTF(Fault, "Setting floatint register through the TC!\n"); 409 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 410 cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); 411 412 // Squash if we're not already in a state update mode. 413 if (!thread->trapPending && !thread->inSyscall) { 414 cpu->squashFromTC(thread->readTid()); 415 } 416} 417 418template <class Impl> 419void 420O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val) 421{ 422 reg_idx = TheISA::flattenFloatIndex(this, reg_idx); 423 cpu->setArchFloatRegInt(reg_idx, val, thread->readTid()); 424 425 // Squash if we're not already in a state update mode. 426 if (!thread->trapPending && !thread->inSyscall) { 427 cpu->squashFromTC(thread->readTid()); 428 } 429} 430 431template <class Impl> 432void 433O3ThreadContext<Impl>::setPC(uint64_t val) 434{ 435 cpu->setPC(val, thread->readTid()); 436 437 // Squash if we're not already in a state update mode. 438 if (!thread->trapPending && !thread->inSyscall) { 439 cpu->squashFromTC(thread->readTid()); 440 } 441} 442 443template <class Impl> 444void 445O3ThreadContext<Impl>::setNextPC(uint64_t val) 446{ 447 cpu->setNextPC(val, thread->readTid()); 448 449 // Squash if we're not already in a state update mode. 450 if (!thread->trapPending && !thread->inSyscall) { 451 cpu->squashFromTC(thread->readTid()); 452 } 453} 454 455template <class Impl> 456void 457O3ThreadContext<Impl>::setMicroPC(uint64_t val) 458{ 459 cpu->setMicroPC(val, thread->readTid()); 460 461 // Squash if we're not already in a state update mode. 462 if (!thread->trapPending && !thread->inSyscall) { 463 cpu->squashFromTC(thread->readTid()); 464 } 465} 466 467template <class Impl> 468void 469O3ThreadContext<Impl>::setNextMicroPC(uint64_t val) 470{ 471 cpu->setNextMicroPC(val, thread->readTid()); 472 473 // Squash if we're not already in a state update mode. 474 if (!thread->trapPending && !thread->inSyscall) { 475 cpu->squashFromTC(thread->readTid()); 476 } 477} 478 479template <class Impl> 480void 481O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val) 482{ 483 cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid()); 484 485 // Squash if we're not already in a state update mode. 486 if (!thread->trapPending && !thread->inSyscall) { 487 cpu->squashFromTC(thread->readTid()); 488 } 489} 490 491template <class Impl> 492void 493O3ThreadContext<Impl>::setMiscReg(int misc_reg, 494 const MiscReg &val) 495{ 496 cpu->setMiscReg(misc_reg, val, thread->readTid()); 497 498 // Squash if we're not already in a state update mode. 499 if (!thread->trapPending && !thread->inSyscall) { 500 cpu->squashFromTC(thread->readTid()); 501 } 502} 503 504#if !FULL_SYSTEM 505 506template <class Impl> 507TheISA::IntReg 508O3ThreadContext<Impl>::getSyscallArg(int i) 509{ 510 return cpu->getSyscallArg(i, thread->readTid()); 511} 512 513template <class Impl> 514void 515O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val) 516{ 517 cpu->setSyscallArg(i, val, thread->readTid()); 518} 519 520template <class Impl> 521void 522O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value) 523{ 524 cpu->setSyscallReturn(return_value, thread->readTid()); 525} 526 527#endif // FULL_SYSTEM 528 529