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