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/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"
37 using namespace SparcISA
;
41 MiscRegFile::checkSoftInt(ThreadContext
*tc
)
43 // If PIL < 14, copy over the tm and sm bits
44 if (pil
< 14 && softint
& 0x10000)
45 tc
->getCpuPtr()->post_interrupt(IT_SOFT_INT
,16);
47 tc
->getCpuPtr()->clear_interrupt(IT_SOFT_INT
,16);
48 if (pil
< 14 && softint
& 0x1)
49 tc
->getCpuPtr()->post_interrupt(IT_SOFT_INT
,0);
51 tc
->getCpuPtr()->clear_interrupt(IT_SOFT_INT
,0);
53 // Copy over any of the other bits that are set
54 for (int bit
= 15; bit
> 0; --bit
) {
55 if (1 << bit
& softint
&& bit
> pil
)
56 tc
->getCpuPtr()->post_interrupt(IT_SOFT_INT
,bit
);
58 tc
->getCpuPtr()->clear_interrupt(IT_SOFT_INT
,bit
);
64 MiscRegFile::setFSReg(int miscReg
, const MiscReg
&val
, ThreadContext
*tc
)
68 /* Full system only ASRs */
70 setRegNoEffect(miscReg
, val
);;
73 case MISCREG_SOFTINT_CLR
:
74 return setReg(MISCREG_SOFTINT
, ~val
& softint
, tc
);
75 case MISCREG_SOFTINT_SET
:
76 return setReg(MISCREG_SOFTINT
, val
| softint
, tc
);
78 case MISCREG_TICK_CMPR
:
79 if (tickCompare
== NULL
)
80 tickCompare
= new TickCompareEvent(this, tc
);
81 setRegNoEffect(miscReg
, val
);
82 if ((tick_cmpr
& ~mask(63)) && tickCompare
->scheduled())
83 tickCompare
->deschedule();
84 time
= (tick_cmpr
& mask(63)) - (tick
& mask(63));
85 if (!(tick_cmpr
& ~mask(63)) && time
> 0) {
86 if (tickCompare
->scheduled())
87 tickCompare
->deschedule();
88 tickCompare
->schedule(time
* tc
->getCpuPtr()->cycles(1));
90 panic("writing to TICK compare register %#X\n", val
);
93 case MISCREG_STICK_CMPR
:
94 if (sTickCompare
== NULL
)
95 sTickCompare
= new STickCompareEvent(this, tc
);
96 setRegNoEffect(miscReg
, val
);
97 if ((stick_cmpr
& ~mask(63)) && sTickCompare
->scheduled())
98 sTickCompare
->deschedule();
99 time
= ((int64_t)(stick_cmpr
& mask(63)) - (int64_t)stick
) -
100 tc
->getCpuPtr()->instCount();
101 if (!(stick_cmpr
& ~mask(63)) && time
> 0) {
102 if (sTickCompare
->scheduled())
103 sTickCompare
->deschedule();
104 sTickCompare
->schedule(time
* tc
->getCpuPtr()->cycles(1) + curTick
);
106 DPRINTF(Timer
, "writing to sTICK compare register value %#X\n", val
);
110 setRegNoEffect(miscReg
, val
);
113 setRegNoEffect(miscReg
, val
);
118 panic("Shouldn't be writing HVER\n");
121 setRegNoEffect(miscReg
, val
);
123 tc
->getCpuPtr()->post_interrupt(IT_HINTP
,0);
125 tc
->getCpuPtr()->clear_interrupt(IT_HINTP
,0);
129 // clear lower 7 bits on writes.
130 setRegNoEffect(miscReg
, val
& ULL(~0x7FFF));
133 case MISCREG_QUEUE_CPU_MONDO_HEAD
:
134 case MISCREG_QUEUE_CPU_MONDO_TAIL
:
135 setRegNoEffect(miscReg
, val
);
136 if (cpu_mondo_head
!= cpu_mondo_tail
)
137 tc
->getCpuPtr()->post_interrupt(IT_CPU_MONDO
,0);
139 tc
->getCpuPtr()->clear_interrupt(IT_CPU_MONDO
,0);
141 case MISCREG_QUEUE_DEV_MONDO_HEAD
:
142 case MISCREG_QUEUE_DEV_MONDO_TAIL
:
143 setRegNoEffect(miscReg
, val
);
144 if (dev_mondo_head
!= dev_mondo_tail
)
145 tc
->getCpuPtr()->post_interrupt(IT_DEV_MONDO
,0);
147 tc
->getCpuPtr()->clear_interrupt(IT_DEV_MONDO
,0);
149 case MISCREG_QUEUE_RES_ERROR_HEAD
:
150 case MISCREG_QUEUE_RES_ERROR_TAIL
:
151 setRegNoEffect(miscReg
, val
);
152 if (res_error_head
!= res_error_tail
)
153 tc
->getCpuPtr()->post_interrupt(IT_RES_ERROR
,0);
155 tc
->getCpuPtr()->clear_interrupt(IT_RES_ERROR
,0);
157 case MISCREG_QUEUE_NRES_ERROR_HEAD
:
158 case MISCREG_QUEUE_NRES_ERROR_TAIL
:
159 setRegNoEffect(miscReg
, val
);
160 // This one doesn't have an interrupt to report to the guest OS
163 case MISCREG_HSTICK_CMPR
:
164 if (hSTickCompare
== NULL
)
165 hSTickCompare
= new HSTickCompareEvent(this, tc
);
166 setRegNoEffect(miscReg
, val
);
167 if ((hstick_cmpr
& ~mask(63)) && hSTickCompare
->scheduled())
168 hSTickCompare
->deschedule();
169 time
= ((int64_t)(hstick_cmpr
& mask(63)) - (int64_t)stick
) -
170 tc
->getCpuPtr()->instCount();
171 if (!(hstick_cmpr
& ~mask(63)) && time
> 0) {
172 if (hSTickCompare
->scheduled())
173 hSTickCompare
->deschedule();
174 hSTickCompare
->schedule(curTick
+ time
* tc
->getCpuPtr()->cycles(1));
176 DPRINTF(Timer
, "writing to hsTICK compare register value %#X\n", val
);
179 case MISCREG_HPSTATE
:
180 // T1000 spec says impl. dependent val must always be 1
181 setRegNoEffect(miscReg
, val
| HPSTATE::id
);
183 if (hpstate
& HPSTATE::tlz
&& tl
== 0 && !(hpstate
& HPSTATE::hpriv
))
184 tc
->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO
,0);
186 tc
->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO
,0);
189 case MISCREG_HTSTATE
:
190 setRegNoEffect(miscReg
, val
);
193 case MISCREG_STRAND_STS_REG
:
195 panic("No support for setting spec_en bit\n");
196 setRegNoEffect(miscReg
, bits(val
,0,0));
197 if (!bits(val
,0,0)) {
198 DPRINTF(Quiesce
, "Cpu executed quiescing instruction\n");
199 // Time to go to sleep
201 if (tc
->getKernelStats())
202 tc
->getKernelStats()->quiesce();
207 panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg
));
212 MiscRegFile::readFSReg(int miscReg
, ThreadContext
* tc
)
217 /* Privileged registers. */
218 case MISCREG_QUEUE_CPU_MONDO_HEAD
:
219 case MISCREG_QUEUE_CPU_MONDO_TAIL
:
220 case MISCREG_QUEUE_DEV_MONDO_HEAD
:
221 case MISCREG_QUEUE_DEV_MONDO_TAIL
:
222 case MISCREG_QUEUE_RES_ERROR_HEAD
:
223 case MISCREG_QUEUE_RES_ERROR_TAIL
:
224 case MISCREG_QUEUE_NRES_ERROR_HEAD
:
225 case MISCREG_QUEUE_NRES_ERROR_TAIL
:
226 case MISCREG_SOFTINT
:
227 case MISCREG_TICK_CMPR
:
228 case MISCREG_STICK_CMPR
:
230 case MISCREG_HPSTATE
:
232 case MISCREG_HTSTATE
:
233 case MISCREG_HSTICK_CMPR
:
234 return readRegNoEffect(miscReg
) ;
237 return readRegNoEffect(miscReg
) & ULL(~0x7FFF);
239 // XXX set to match Legion
240 return ULL(0x3e) << 48 |
243 //MaxGL << 16 | XXX For some reason legion doesn't set GL
247 case MISCREG_STRAND_STS_REG
:
250 sys
= tc
->getSystemPtr();
252 temp
= readRegNoEffect(miscReg
) & (STS::active
| STS::speculative
);
253 // Check that the CPU array is fully populated (by calling getNumCPus())
254 assert(sys
->getNumCPUs() > tc
->readCpuId());
256 temp
|= tc
->readCpuId() << STS::shft_id
;
258 for (x
= tc
->readCpuId() & ~3; x
< sys
->threadContexts
.size(); x
++) {
259 switch (sys
->threadContexts
[x
]->status()) {
260 case ThreadContext::Active
:
261 temp
|= STS::st_run
<< (STS::shft_fsm0
-
262 ((x
& 0x3) * (STS::shft_fsm0
-STS::shft_fsm1
)));
264 case ThreadContext::Suspended
:
265 // should this be idle?
266 temp
|= STS::st_idle
<< (STS::shft_fsm0
-
267 ((x
& 0x3) * (STS::shft_fsm0
-STS::shft_fsm1
)));
269 case ThreadContext::Halted
:
270 temp
|= STS::st_halt
<< (STS::shft_fsm0
-
271 ((x
& 0x3) * (STS::shft_fsm0
-STS::shft_fsm1
)));
274 panic("What state are we in?!\n");
280 panic("Invalid read to FS misc register\n");
284 In Niagra STICK==TICK so this isn't needed
287 sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
289 return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63)));
295 MiscRegFile::processTickCompare(ThreadContext
*tc
)
297 panic("tick compare not implemented\n");
301 MiscRegFile::processSTickCompare(ThreadContext
*tc
)
303 // since our microcode instructions take two cycles we need to check if
304 // we're actually at the correct cycle or we need to wait a little while
307 ticks
= ((int64_t)(stick_cmpr
& mask(63)) - (int64_t)stick
) -
308 tc
->getCpuPtr()->instCount();
309 assert(ticks
>= 0 && "stick compare missed interrupt cycle");
311 if (ticks
== 0 || tc
->status() == ThreadContext::Suspended
) {
312 DPRINTF(Timer
, "STick compare cycle reached at %#x\n",
313 (stick_cmpr
& mask(63)));
314 if (!(tc
->readMiscRegNoEffect(MISCREG_STICK_CMPR
) & (ULL(1) << 63))) {
315 setReg(MISCREG_SOFTINT
, softint
| (ULL(1) << 16), tc
);
318 sTickCompare
->schedule(ticks
* tc
->getCpuPtr()->cycles(1) + curTick
);
322 MiscRegFile::processHSTickCompare(ThreadContext
*tc
)
324 // since our microcode instructions take two cycles we need to check if
325 // we're actually at the correct cycle or we need to wait a little while
328 if ( tc
->status() == ThreadContext::Halted
||
329 tc
->status() == ThreadContext::Unallocated
)
332 ticks
= ((int64_t)(hstick_cmpr
& mask(63)) - (int64_t)stick
) -
333 tc
->getCpuPtr()->instCount();
334 assert(ticks
>= 0 && "hstick compare missed interrupt cycle");
336 if (ticks
== 0 || tc
->status() == ThreadContext::Suspended
) {
337 DPRINTF(Timer
, "HSTick compare cycle reached at %#x\n",
338 (stick_cmpr
& mask(63)));
339 if (!(tc
->readMiscRegNoEffect(MISCREG_HSTICK_CMPR
) & (ULL(1) << 63))) {
340 setReg(MISCREG_HINTP
, 1, tc
);
342 // Need to do something to cause interrupt to happen here !!! @todo
344 hSTickCompare
->schedule(ticks
* tc
->getCpuPtr()->cycles(1) + curTick
);