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