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