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