ua2005.cc revision 5531:a5ff5e57fafd
1/*
2 * Copyright (c) 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
29#include "arch/sparc/kernel_stats.hh"
30#include "arch/sparc/miscregfile.hh"
31#include "base/bitfield.hh"
32#include "base/trace.hh"
33#include "cpu/base.hh"
34#include "cpu/thread_context.hh"
35#include "sim/system.hh"
36
37using namespace SparcISA;
38
39
40void
41MiscRegFile::checkSoftInt(ThreadContext *tc)
42{
43    BaseCPU *cpu = tc->getCpuPtr();
44
45    // If PIL < 14, copy over the tm and sm bits
46    if (pil < 14 && softint & 0x10000)
47        cpu->post_interrupt(IT_SOFT_INT, 16);
48    else
49        cpu->clear_interrupt(IT_SOFT_INT, 16);
50    if (pil < 14 && softint & 0x1)
51        cpu->post_interrupt(IT_SOFT_INT, 0);
52    else
53        cpu->clear_interrupt(IT_SOFT_INT, 0);
54
55    // Copy over any of the other bits that are set
56    for (int bit = 15; bit > 0; --bit) {
57        if (1 << bit & softint && bit > pil)
58            cpu->post_interrupt(IT_SOFT_INT, bit);
59        else
60            cpu->clear_interrupt(IT_SOFT_INT, bit);
61    }
62}
63
64
65void
66MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
67{
68    BaseCPU *cpu = tc->getCpuPtr();
69
70    int64_t time;
71    switch (miscReg) {
72        /* Full system only ASRs */
73      case MISCREG_SOFTINT:
74        setRegNoEffect(miscReg, val);;
75        checkSoftInt(tc);
76        break;
77      case MISCREG_SOFTINT_CLR:
78        return setReg(MISCREG_SOFTINT, ~val & softint, tc);
79      case MISCREG_SOFTINT_SET:
80        return setReg(MISCREG_SOFTINT, val | softint, tc);
81
82      case MISCREG_TICK_CMPR:
83        if (tickCompare == NULL)
84            tickCompare = new TickCompareEvent(this, tc);
85        setRegNoEffect(miscReg, val);
86        if ((tick_cmpr & ~mask(63)) && tickCompare->scheduled())
87            tickCompare->deschedule();
88        time = (tick_cmpr & mask(63)) - (tick & mask(63));
89        if (!(tick_cmpr & ~mask(63)) && time > 0) {
90            if (tickCompare->scheduled())
91                tickCompare->deschedule();
92            tickCompare->schedule(time * cpu->ticks(1));
93        }
94        panic("writing to TICK compare register %#X\n", val);
95        break;
96
97      case MISCREG_STICK_CMPR:
98        if (sTickCompare == NULL)
99            sTickCompare = new STickCompareEvent(this, tc);
100        setRegNoEffect(miscReg, val);
101        if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled())
102            sTickCompare->deschedule();
103        time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) -
104            cpu->instCount();
105        if (!(stick_cmpr & ~mask(63)) && time > 0) {
106            if (sTickCompare->scheduled())
107                sTickCompare->deschedule();
108            sTickCompare->schedule(time * cpu->ticks(1) + curTick);
109        }
110        DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val);
111        break;
112
113      case MISCREG_PSTATE:
114        setRegNoEffect(miscReg, val);
115
116      case MISCREG_PIL:
117        setRegNoEffect(miscReg, val);
118        checkSoftInt(tc);
119        break;
120
121      case MISCREG_HVER:
122        panic("Shouldn't be writing HVER\n");
123
124      case MISCREG_HINTP:
125        setRegNoEffect(miscReg, val);
126        if (hintp)
127            cpu->post_interrupt(IT_HINTP, 0);
128        else
129            cpu->clear_interrupt(IT_HINTP, 0);
130        break;
131
132      case MISCREG_HTBA:
133        // clear lower 7 bits on writes.
134        setRegNoEffect(miscReg, val & ULL(~0x7FFF));
135        break;
136
137      case MISCREG_QUEUE_CPU_MONDO_HEAD:
138      case MISCREG_QUEUE_CPU_MONDO_TAIL:
139        setRegNoEffect(miscReg, val);
140        if (cpu_mondo_head != cpu_mondo_tail)
141            cpu->post_interrupt(IT_CPU_MONDO, 0);
142        else
143            cpu->clear_interrupt(IT_CPU_MONDO, 0);
144        break;
145      case MISCREG_QUEUE_DEV_MONDO_HEAD:
146      case MISCREG_QUEUE_DEV_MONDO_TAIL:
147        setRegNoEffect(miscReg, val);
148        if (dev_mondo_head != dev_mondo_tail)
149            cpu->post_interrupt(IT_DEV_MONDO, 0);
150        else
151            cpu->clear_interrupt(IT_DEV_MONDO, 0);
152        break;
153      case MISCREG_QUEUE_RES_ERROR_HEAD:
154      case MISCREG_QUEUE_RES_ERROR_TAIL:
155        setRegNoEffect(miscReg, val);
156        if (res_error_head != res_error_tail)
157            cpu->post_interrupt(IT_RES_ERROR, 0);
158        else
159            cpu->clear_interrupt(IT_RES_ERROR, 0);
160        break;
161      case MISCREG_QUEUE_NRES_ERROR_HEAD:
162      case MISCREG_QUEUE_NRES_ERROR_TAIL:
163        setRegNoEffect(miscReg, val);
164        // This one doesn't have an interrupt to report to the guest OS
165        break;
166
167      case MISCREG_HSTICK_CMPR:
168        if (hSTickCompare == NULL)
169            hSTickCompare = new HSTickCompareEvent(this, tc);
170        setRegNoEffect(miscReg, val);
171        if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled())
172            hSTickCompare->deschedule();
173        time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) -
174            cpu->instCount();
175        if (!(hstick_cmpr & ~mask(63)) && time > 0) {
176            if (hSTickCompare->scheduled())
177                hSTickCompare->deschedule();
178            hSTickCompare->schedule(curTick + time * cpu->ticks(1));
179        }
180        DPRINTF(Timer, "writing to hsTICK compare register value %#X\n", val);
181        break;
182
183      case MISCREG_HPSTATE:
184        // T1000 spec says impl. dependent val must always be 1
185        setRegNoEffect(miscReg, val | HPSTATE::id);
186#if FULL_SYSTEM
187        if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
188            cpu->post_interrupt(IT_TRAP_LEVEL_ZERO, 0);
189        else
190            cpu->clear_interrupt(IT_TRAP_LEVEL_ZERO, 0);
191#endif
192        break;
193      case MISCREG_HTSTATE:
194        setRegNoEffect(miscReg, val);
195        break;
196
197      case MISCREG_STRAND_STS_REG:
198        if (bits(val,2,2))
199            panic("No support for setting spec_en bit\n");
200        setRegNoEffect(miscReg, bits(val,0,0));
201        if (!bits(val,0,0)) {
202            DPRINTF(Quiesce, "Cpu executed quiescing instruction\n");
203            // Time to go to sleep
204            tc->suspend();
205            if (tc->getKernelStats())
206                tc->getKernelStats()->quiesce();
207        }
208        break;
209
210      default:
211        panic("Invalid write to FS misc register %s\n",
212              getMiscRegName(miscReg));
213    }
214}
215
216MiscReg
217MiscRegFile::readFSReg(int miscReg, ThreadContext * tc)
218{
219    uint64_t temp;
220
221    switch (miscReg) {
222        /* Privileged registers. */
223      case MISCREG_QUEUE_CPU_MONDO_HEAD:
224      case MISCREG_QUEUE_CPU_MONDO_TAIL:
225      case MISCREG_QUEUE_DEV_MONDO_HEAD:
226      case MISCREG_QUEUE_DEV_MONDO_TAIL:
227      case MISCREG_QUEUE_RES_ERROR_HEAD:
228      case MISCREG_QUEUE_RES_ERROR_TAIL:
229      case MISCREG_QUEUE_NRES_ERROR_HEAD:
230      case MISCREG_QUEUE_NRES_ERROR_TAIL:
231      case MISCREG_SOFTINT:
232      case MISCREG_TICK_CMPR:
233      case MISCREG_STICK_CMPR:
234      case MISCREG_PIL:
235      case MISCREG_HPSTATE:
236      case MISCREG_HINTP:
237      case MISCREG_HTSTATE:
238      case MISCREG_HSTICK_CMPR:
239        return readRegNoEffect(miscReg) ;
240
241      case MISCREG_HTBA:
242        return readRegNoEffect(miscReg) & ULL(~0x7FFF);
243      case MISCREG_HVER:
244        // XXX set to match Legion
245        return ULL(0x3e) << 48 |
246               ULL(0x23) << 32 |
247               ULL(0x20) << 24 |
248                   //MaxGL << 16 | XXX For some reason legion doesn't set GL
249                   MaxTL << 8  |
250           (NWindows -1) << 0;
251
252      case MISCREG_STRAND_STS_REG:
253        System *sys;
254        int x;
255        sys = tc->getSystemPtr();
256
257        temp = readRegNoEffect(miscReg) & (STS::active | STS::speculative);
258        // Check that the CPU array is fully populated
259        // (by calling getNumCPus())
260        assert(sys->getNumCPUs() > tc->readCpuId());
261
262        temp |= tc->readCpuId()  << STS::shft_id;
263
264        for (x = tc->readCpuId() & ~3; x < sys->threadContexts.size(); x++) {
265            switch (sys->threadContexts[x]->status()) {
266              case ThreadContext::Active:
267                temp |= STS::st_run << (STS::shft_fsm0 -
268                        ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1)));
269                break;
270              case ThreadContext::Suspended:
271                // should this be idle?
272                temp |= STS::st_idle << (STS::shft_fsm0 -
273                        ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1)));
274                break;
275              case ThreadContext::Halted:
276                temp |= STS::st_halt << (STS::shft_fsm0 -
277                        ((x & 0x3) * (STS::shft_fsm0-STS::shft_fsm1)));
278                break;
279              default:
280                panic("What state are we in?!\n");
281            } // switch
282        } // for
283
284        return temp;
285      default:
286        panic("Invalid read to FS misc register\n");
287    }
288}
289
290void
291MiscRegFile::processTickCompare(ThreadContext *tc)
292{
293    panic("tick compare not implemented\n");
294}
295
296void
297MiscRegFile::processSTickCompare(ThreadContext *tc)
298{
299    // since our microcode instructions take two cycles we need to check if
300    // we're actually at the correct cycle or we need to wait a little while
301    // more
302    int ticks;
303    ticks = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) -
304        tc->getCpuPtr()->instCount();
305    assert(ticks >= 0 && "stick compare missed interrupt cycle");
306
307    if (ticks == 0 || tc->status() == ThreadContext::Suspended) {
308        DPRINTF(Timer, "STick compare cycle reached at %#x\n",
309                (stick_cmpr & mask(63)));
310        if (!(tc->readMiscRegNoEffect(MISCREG_STICK_CMPR) & (ULL(1) << 63))) {
311            setReg(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc);
312        }
313    } else
314        sTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick);
315}
316
317void
318MiscRegFile::processHSTickCompare(ThreadContext *tc)
319{
320    // since our microcode instructions take two cycles we need to check if
321    // we're actually at the correct cycle or we need to wait a little while
322    // more
323    int ticks;
324    if ( tc->status() == ThreadContext::Halted ||
325         tc->status() == ThreadContext::Unallocated)
326       return;
327
328    ticks = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) -
329        tc->getCpuPtr()->instCount();
330    assert(ticks >= 0 && "hstick compare missed interrupt cycle");
331
332    if (ticks == 0 || tc->status() == ThreadContext::Suspended) {
333        DPRINTF(Timer, "HSTick compare cycle reached at %#x\n",
334                (stick_cmpr & mask(63)));
335        if (!(tc->readMiscRegNoEffect(MISCREG_HSTICK_CMPR) & (ULL(1) << 63))) {
336            setReg(MISCREG_HINTP, 1, tc);
337        }
338        // Need to do something to cause interrupt to happen here !!! @todo
339    } else
340        hSTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick);
341}
342
343