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