thread_context_impl.hh revision 2834:c8342a71404b
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
35using namespace TheISA;
36
37#if FULL_SYSTEM
38template <class Impl>
39VirtualPort *
40O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc)
41{
42    if (!src_tc)
43        return thread->getVirtPort();
44
45    VirtualPort *vp;
46    Port *mem_port;
47
48    vp = new VirtualPort("tc-vport", src_tc);
49    mem_port = cpu->system->physmem->getPort("functional");
50    mem_port->setPeer(vp);
51    vp->setPeer(mem_port);
52    return vp;
53}
54
55template <class Impl>
56void
57O3ThreadContext<Impl>::dumpFuncProfile()
58{
59    // Currently not supported
60}
61#endif
62
63template <class Impl>
64void
65O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
66{
67    // some things should already be set up
68#if FULL_SYSTEM
69    assert(getSystemPtr() == old_context->getSystemPtr());
70#else
71    assert(getProcessPtr() == old_context->getProcessPtr());
72#endif
73
74    // copy over functional state
75    setStatus(old_context->status());
76    copyArchRegs(old_context);
77    setCpuId(old_context->readCpuId());
78
79#if !FULL_SYSTEM
80    thread->funcExeInst = old_context->readFuncExeInst();
81#else
82    EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
83    if (other_quiesce) {
84        // Point the quiesce event's TC at this TC so that it wakes up
85        // the proper CPU.
86        other_quiesce->tc = this;
87    }
88    if (thread->quiesceEvent) {
89        thread->quiesceEvent->tc = this;
90    }
91
92    // Transfer kernel stats from one CPU to the other.
93    thread->kernelStats = old_context->getKernelStats();
94//    storeCondFailures = 0;
95    cpu->lockFlag = false;
96#endif
97
98    old_context->setStatus(ThreadContext::Unallocated);
99
100    thread->inSyscall = false;
101    thread->trapPending = false;
102}
103
104#if FULL_SYSTEM
105template <class Impl>
106void
107O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
108{
109    delete vp->getPeer();
110    delete vp;
111}
112#endif
113
114template <class Impl>
115void
116O3ThreadContext<Impl>::activate(int delay)
117{
118    DPRINTF(O3CPU, "Calling activate on AlphaTC\n");
119
120    if (thread->status() == ThreadContext::Active)
121        return;
122
123#if FULL_SYSTEM
124    thread->lastActivate = curTick;
125#endif
126
127    if (thread->status() == ThreadContext::Unallocated) {
128        cpu->activateWhenReady(thread->readTid());
129        return;
130    }
131
132    thread->setStatus(ThreadContext::Active);
133
134    // status() == Suspended
135    cpu->activateContext(thread->readTid(), delay);
136}
137
138template <class Impl>
139void
140O3ThreadContext<Impl>::suspend()
141{
142    DPRINTF(O3CPU, "Calling suspend on AlphaTC\n");
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()
167{
168    DPRINTF(O3CPU, "Calling deallocate on AlphaTC\n");
169
170    if (thread->status() == ThreadContext::Unallocated)
171        return;
172
173    thread->setStatus(ThreadContext::Unallocated);
174    cpu->deallocateContext(thread->readTid());
175}
176
177template <class Impl>
178void
179O3ThreadContext<Impl>::halt()
180{
181    DPRINTF(O3CPU, "Calling halt on AlphaTC\n");
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 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
242template <class Impl>
243void
244O3ThreadContext<Impl>::profileSample()
245{}
246#endif
247
248template <class Impl>
249TheISA::MachInst
250O3ThreadContext<Impl>:: getInst()
251{
252    return thread->getInst();
253}
254
255template <class Impl>
256void
257O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
258{
259    // This function will mess things up unless the ROB is empty and
260    // there are no instructions in the pipeline.
261    unsigned tid = thread->readTid();
262    PhysRegIndex renamed_reg;
263
264    // First loop through the integer registers.
265    for (int i = 0; i < TheISA::NumIntRegs; ++i) {
266        renamed_reg = cpu->renameMap[tid].lookup(i);
267
268        DPRINTF(O3CPU, "Copying over register %i, had data %lli, "
269                "now has data %lli.\n",
270                renamed_reg, cpu->readIntReg(renamed_reg),
271                tc->readIntReg(i));
272
273        cpu->setIntReg(renamed_reg, tc->readIntReg(i));
274    }
275
276    // Then loop through the floating point registers.
277    for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
278        renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
279        cpu->setFloatRegBits(renamed_reg,
280                             tc->readFloatRegBits(i));
281    }
282
283    // Copy the misc regs.
284    copyMiscRegs(tc, this);
285
286    // Then finally set the PC and the next PC.
287    cpu->setPC(tc->readPC(), tid);
288    cpu->setNextPC(tc->readNextPC(), tid);
289#if !FULL_SYSTEM
290    this->thread->funcExeInst = tc->readFuncExeInst();
291#endif
292}
293
294template <class Impl>
295void
296O3ThreadContext<Impl>::clearArchRegs()
297{}
298
299template <class Impl>
300uint64_t
301O3ThreadContext<Impl>::readIntReg(int reg_idx)
302{
303    return cpu->readArchIntReg(reg_idx, thread->readTid());
304}
305
306template <class Impl>
307FloatReg
308O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width)
309{
310    switch(width) {
311      case 32:
312        return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
313      case 64:
314        return cpu->readArchFloatRegDouble(reg_idx, thread->readTid());
315      default:
316        panic("Unsupported width!");
317        return 0;
318    }
319}
320
321template <class Impl>
322FloatReg
323O3ThreadContext<Impl>::readFloatReg(int reg_idx)
324{
325    return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
326}
327
328template <class Impl>
329FloatRegBits
330O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width)
331{
332    DPRINTF(Fault, "Reading floatint register through the TC!\n");
333    return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
334}
335
336template <class Impl>
337FloatRegBits
338O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
339{
340    return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
341}
342
343template <class Impl>
344void
345O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
346{
347    cpu->setArchIntReg(reg_idx, val, thread->readTid());
348
349    // Squash if we're not already in a state update mode.
350    if (!thread->trapPending && !thread->inSyscall) {
351        cpu->squashFromTC(thread->readTid());
352    }
353}
354
355template <class Impl>
356void
357O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
358{
359    switch(width) {
360      case 32:
361        cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
362        break;
363      case 64:
364        cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid());
365        break;
366    }
367
368    // Squash if we're not already in a state update mode.
369    if (!thread->trapPending && !thread->inSyscall) {
370        cpu->squashFromTC(thread->readTid());
371    }
372}
373
374template <class Impl>
375void
376O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
377{
378    cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
379
380    if (!thread->trapPending && !thread->inSyscall) {
381        cpu->squashFromTC(thread->readTid());
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    cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
392
393    // Squash if we're not already in a state update mode.
394    if (!thread->trapPending && !thread->inSyscall) {
395        cpu->squashFromTC(thread->readTid());
396    }
397}
398
399template <class Impl>
400void
401O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
402{
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>
436Fault
437O3ThreadContext<Impl>::setMiscReg(int misc_reg, const MiscReg &val)
438{
439    Fault ret_fault = cpu->setMiscReg(misc_reg, 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    return ret_fault;
447}
448
449template <class Impl>
450Fault
451O3ThreadContext<Impl>::setMiscRegWithEffect(int misc_reg,
452                                                const MiscReg &val)
453{
454    Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val,
455                                                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    return ret_fault;
463}
464
465#if !FULL_SYSTEM
466
467template <class Impl>
468TheISA::IntReg
469O3ThreadContext<Impl>::getSyscallArg(int i)
470{
471    return cpu->getSyscallArg(i, thread->readTid());
472}
473
474template <class Impl>
475void
476O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val)
477{
478    cpu->setSyscallArg(i, val, thread->readTid());
479}
480
481template <class Impl>
482void
483O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value)
484{
485    cpu->setSyscallReturn(return_value, thread->readTid());
486}
487
488#endif // FULL_SYSTEM
489
490