2 * Copyright (c) 2006 The Regents of The University of Michigan
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.
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.
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"
42 using namespace SparcISA
;
47 ISA::checkSoftInt(ThreadContext
*tc
)
49 BaseCPU
*cpu
= tc
->getCpuPtr();
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);
55 cpu
->clearInterrupt(0, IT_SOFT_INT
, 16);
56 if (pil
< 14 && softint
& 0x1)
57 cpu
->postInterrupt(0, IT_SOFT_INT
, 0);
59 cpu
->clearInterrupt(0, IT_SOFT_INT
, 0);
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
);
66 cpu
->clearInterrupt(0, IT_SOFT_INT
, bit
);
70 // These functions map register indices to names
72 getMiscRegName(RegIndex index
)
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",
81 "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg",
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
];
92 ISA::setFSReg(int miscReg
, RegVal val
, ThreadContext
*tc
)
94 BaseCPU
*cpu
= tc
->getCpuPtr();
98 /* Full system only ASRs */
100 setMiscRegNoEffect(miscReg
, val
);;
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
);
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
)));
120 DPRINTF(Timer
, "writing to TICK compare register value %#X\n", val
);
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
) -
131 if (!(stick_cmpr
& ~mask(63)) && time
> 0) {
132 if (sTickCompare
->scheduled())
133 cpu
->deschedule(sTickCompare
);
134 cpu
->schedule(sTickCompare
, cpu
->clockEdge(Cycles(time
)));
136 DPRINTF(Timer
, "writing to sTICK compare register value %#X\n", val
);
140 setMiscRegNoEffect(miscReg
, val
);
144 setMiscRegNoEffect(miscReg
, val
);
149 panic("Shouldn't be writing HVER\n");
152 setMiscRegNoEffect(miscReg
, val
);
154 cpu
->postInterrupt(0, IT_HINTP
, 0);
156 cpu
->clearInterrupt(0, IT_HINTP
, 0);
160 // clear lower 7 bits on writes.
161 setMiscRegNoEffect(miscReg
, val
& ULL(~0x7FFF));
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);
170 cpu
->clearInterrupt(0, IT_CPU_MONDO
, 0);
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);
178 cpu
->clearInterrupt(0, IT_DEV_MONDO
, 0);
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);
186 cpu
->clearInterrupt(0, IT_RES_ERROR
, 0);
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
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
) -
202 if (!(hstick_cmpr
& ~mask(63)) && time
> 0) {
203 if (hSTickCompare
->scheduled())
204 cpu
->deschedule(hSTickCompare
);
205 cpu
->schedule(hSTickCompare
, cpu
->clockEdge(Cycles(time
)));
207 DPRINTF(Timer
, "writing to hsTICK compare register value %#X\n", val
);
210 case MISCREG_HPSTATE
:
212 HPSTATE newVal
= val
;
214 // T1000 spec says impl. dependent val must always be 1
215 setMiscRegNoEffect(miscReg
, newVal
);
217 if (newVal
.tlz
&& tl
== 0 && !newVal
.hpriv
)
218 cpu
->postInterrupt(0, IT_TRAP_LEVEL_ZERO
, 0);
220 cpu
->clearInterrupt(0, IT_TRAP_LEVEL_ZERO
, 0);
223 case MISCREG_HTSTATE
:
224 setMiscRegNoEffect(miscReg
, val
);
227 case MISCREG_STRAND_STS_REG
:
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
235 if (FullSystem
&& tc
->getKernelStats())
236 tc
->getKernelStats()->quiesce();
241 panic("Invalid write to FS misc register %s\n",
242 getMiscRegName(miscReg
));
247 ISA::readFSReg(int miscReg
, ThreadContext
* tc
)
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
:
265 case MISCREG_HPSTATE
:
267 case MISCREG_HTSTATE
:
268 case MISCREG_HSTICK_CMPR
:
269 return readMiscRegNoEffect(miscReg
) ;
272 return readMiscRegNoEffect(miscReg
) & ULL(~0x7FFF);
274 // XXX set to match Legion
275 return ULL(0x3e) << 48 |
278 // MaxGL << 16 | XXX For some reason legion doesn't set GL
282 case MISCREG_STRAND_STS_REG
:
285 sys
= tc
->getSystemPtr();
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());
292 temp
|= tc
->contextId() << STS::shft_id
;
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
)));
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
)));
305 case ThreadContext::Halted
:
306 temp
|= STS::st_halt
<< (STS::shft_fsm0
-
307 ((x
& 0x3) * (STS::shft_fsm0
-STS::shft_fsm1
)));
310 panic("What state are we in?!\n");
316 panic("Invalid read to FS misc register\n");
321 ISA::processTickCompare(ThreadContext
*tc
)
323 panic("tick compare not implemented\n");
327 ISA::processSTickCompare(ThreadContext
*tc
)
329 BaseCPU
*cpu
= tc
->getCpuPtr();
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
335 delay
= ((int64_t)(stick_cmpr
& mask(63)) - (int64_t)stick
) -
337 assert(delay
>= 0 && "stick compare missed interrupt cycle");
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
);
346 cpu
->schedule(sTickCompare
, cpu
->clockEdge(Cycles(delay
)));
351 ISA::processHSTickCompare(ThreadContext
*tc
)
353 BaseCPU
*cpu
= tc
->getCpuPtr();
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
359 if ( tc
->status() == ThreadContext::Halted
)
362 delay
= ((int64_t)(hstick_cmpr
& mask(63)) - (int64_t)stick
) -
364 assert(delay
>= 0 && "hstick compare missed interrupt cycle");
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
);
372 // Need to do something to cause interrupt to happen here !!! @todo
374 cpu
->schedule(hSTickCompare
, cpu
->clockEdge(Cycles(delay
)));