root / target-sparc / win_helper.c @ a8a00822
History | View | Annotate | Download (9.4 kB)
1 |
/*
|
---|---|
2 |
* Helpers for CWP and PSTATE handling
|
3 |
*
|
4 |
* Copyright (c) 2003-2005 Fabrice Bellard
|
5 |
*
|
6 |
* This library is free software; you can redistribute it and/or
|
7 |
* modify it under the terms of the GNU Lesser General Public
|
8 |
* License as published by the Free Software Foundation; either
|
9 |
* version 2 of the License, or (at your option) any later version.
|
10 |
*
|
11 |
* This library is distributed in the hope that it will be useful,
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
* Lesser General Public License for more details.
|
15 |
*
|
16 |
* You should have received a copy of the GNU Lesser General Public
|
17 |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
18 |
*/
|
19 |
|
20 |
#include "cpu.h" |
21 |
#include "helper.h" |
22 |
#include "trace.h" |
23 |
|
24 |
static inline void memcpy32(target_ulong *dst, const target_ulong *src) |
25 |
{ |
26 |
dst[0] = src[0]; |
27 |
dst[1] = src[1]; |
28 |
dst[2] = src[2]; |
29 |
dst[3] = src[3]; |
30 |
dst[4] = src[4]; |
31 |
dst[5] = src[5]; |
32 |
dst[6] = src[6]; |
33 |
dst[7] = src[7]; |
34 |
} |
35 |
|
36 |
void cpu_set_cwp(CPUState *env, int new_cwp) |
37 |
{ |
38 |
/* put the modified wrap registers at their proper location */
|
39 |
if (env->cwp == env->nwindows - 1) { |
40 |
memcpy32(env->regbase, env->regbase + env->nwindows * 16);
|
41 |
} |
42 |
env->cwp = new_cwp; |
43 |
|
44 |
/* put the wrap registers at their temporary location */
|
45 |
if (new_cwp == env->nwindows - 1) { |
46 |
memcpy32(env->regbase + env->nwindows * 16, env->regbase);
|
47 |
} |
48 |
env->regwptr = env->regbase + (new_cwp * 16);
|
49 |
} |
50 |
|
51 |
target_ulong cpu_get_psr(CPUState *env) |
52 |
{ |
53 |
helper_compute_psr(env); |
54 |
|
55 |
#if !defined(TARGET_SPARC64)
|
56 |
return env->version | (env->psr & PSR_ICC) |
|
57 |
(env->psref ? PSR_EF : 0) |
|
58 |
(env->psrpil << 8) |
|
59 |
(env->psrs ? PSR_S : 0) |
|
60 |
(env->psrps ? PSR_PS : 0) |
|
61 |
(env->psret ? PSR_ET : 0) | env->cwp;
|
62 |
#else
|
63 |
return env->psr & PSR_ICC;
|
64 |
#endif
|
65 |
} |
66 |
|
67 |
void cpu_put_psr(CPUState *env, target_ulong val)
|
68 |
{ |
69 |
env->psr = val & PSR_ICC; |
70 |
#if !defined(TARGET_SPARC64)
|
71 |
env->psref = (val & PSR_EF) ? 1 : 0; |
72 |
env->psrpil = (val & PSR_PIL) >> 8;
|
73 |
#endif
|
74 |
#if ((!defined(TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
|
75 |
cpu_check_irqs(env); |
76 |
#endif
|
77 |
#if !defined(TARGET_SPARC64)
|
78 |
env->psrs = (val & PSR_S) ? 1 : 0; |
79 |
env->psrps = (val & PSR_PS) ? 1 : 0; |
80 |
env->psret = (val & PSR_ET) ? 1 : 0; |
81 |
cpu_set_cwp(env, val & PSR_CWP); |
82 |
#endif
|
83 |
env->cc_op = CC_OP_FLAGS; |
84 |
} |
85 |
|
86 |
int cpu_cwp_inc(CPUState *env, int cwp) |
87 |
{ |
88 |
if (unlikely(cwp >= env->nwindows)) {
|
89 |
cwp -= env->nwindows; |
90 |
} |
91 |
return cwp;
|
92 |
} |
93 |
|
94 |
int cpu_cwp_dec(CPUState *env, int cwp) |
95 |
{ |
96 |
if (unlikely(cwp < 0)) { |
97 |
cwp += env->nwindows; |
98 |
} |
99 |
return cwp;
|
100 |
} |
101 |
|
102 |
#ifndef TARGET_SPARC64
|
103 |
void helper_rett(CPUState *env)
|
104 |
{ |
105 |
unsigned int cwp; |
106 |
|
107 |
if (env->psret == 1) { |
108 |
helper_raise_exception(env, TT_ILL_INSN); |
109 |
} |
110 |
|
111 |
env->psret = 1;
|
112 |
cwp = cpu_cwp_inc(env, env->cwp + 1) ;
|
113 |
if (env->wim & (1 << cwp)) { |
114 |
helper_raise_exception(env, TT_WIN_UNF); |
115 |
} |
116 |
cpu_set_cwp(env, cwp); |
117 |
env->psrs = env->psrps; |
118 |
} |
119 |
|
120 |
/* XXX: use another pointer for %iN registers to avoid slow wrapping
|
121 |
handling ? */
|
122 |
void helper_save(CPUState *env)
|
123 |
{ |
124 |
uint32_t cwp; |
125 |
|
126 |
cwp = cpu_cwp_dec(env, env->cwp - 1);
|
127 |
if (env->wim & (1 << cwp)) { |
128 |
helper_raise_exception(env, TT_WIN_OVF); |
129 |
} |
130 |
cpu_set_cwp(env, cwp); |
131 |
} |
132 |
|
133 |
void helper_restore(CPUState *env)
|
134 |
{ |
135 |
uint32_t cwp; |
136 |
|
137 |
cwp = cpu_cwp_inc(env, env->cwp + 1);
|
138 |
if (env->wim & (1 << cwp)) { |
139 |
helper_raise_exception(env, TT_WIN_UNF); |
140 |
} |
141 |
cpu_set_cwp(env, cwp); |
142 |
} |
143 |
|
144 |
void helper_wrpsr(CPUState *env, target_ulong new_psr)
|
145 |
{ |
146 |
if ((new_psr & PSR_CWP) >= env->nwindows) {
|
147 |
helper_raise_exception(env, TT_ILL_INSN); |
148 |
} else {
|
149 |
cpu_put_psr(env, new_psr); |
150 |
} |
151 |
} |
152 |
|
153 |
target_ulong helper_rdpsr(CPUState *env) |
154 |
{ |
155 |
return cpu_get_psr(env);
|
156 |
} |
157 |
|
158 |
#else
|
159 |
/* XXX: use another pointer for %iN registers to avoid slow wrapping
|
160 |
handling ? */
|
161 |
void helper_save(CPUState *env)
|
162 |
{ |
163 |
uint32_t cwp; |
164 |
|
165 |
cwp = cpu_cwp_dec(env, env->cwp - 1);
|
166 |
if (env->cansave == 0) { |
167 |
helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
|
168 |
(TT_WOTHER | |
169 |
((env->wstate & 0x38) >> 1)) : |
170 |
((env->wstate & 0x7) << 2))); |
171 |
} else {
|
172 |
if (env->cleanwin - env->canrestore == 0) { |
173 |
/* XXX Clean windows without trap */
|
174 |
helper_raise_exception(env, TT_CLRWIN); |
175 |
} else {
|
176 |
env->cansave--; |
177 |
env->canrestore++; |
178 |
cpu_set_cwp(env, cwp); |
179 |
} |
180 |
} |
181 |
} |
182 |
|
183 |
void helper_restore(CPUState *env)
|
184 |
{ |
185 |
uint32_t cwp; |
186 |
|
187 |
cwp = cpu_cwp_inc(env, env->cwp + 1);
|
188 |
if (env->canrestore == 0) { |
189 |
helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ?
|
190 |
(TT_WOTHER | |
191 |
((env->wstate & 0x38) >> 1)) : |
192 |
((env->wstate & 0x7) << 2))); |
193 |
} else {
|
194 |
env->cansave++; |
195 |
env->canrestore--; |
196 |
cpu_set_cwp(env, cwp); |
197 |
} |
198 |
} |
199 |
|
200 |
void helper_flushw(CPUState *env)
|
201 |
{ |
202 |
if (env->cansave != env->nwindows - 2) { |
203 |
helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ?
|
204 |
(TT_WOTHER | |
205 |
((env->wstate & 0x38) >> 1)) : |
206 |
((env->wstate & 0x7) << 2))); |
207 |
} |
208 |
} |
209 |
|
210 |
void helper_saved(CPUState *env)
|
211 |
{ |
212 |
env->cansave++; |
213 |
if (env->otherwin == 0) { |
214 |
env->canrestore--; |
215 |
} else {
|
216 |
env->otherwin--; |
217 |
} |
218 |
} |
219 |
|
220 |
void helper_restored(CPUState *env)
|
221 |
{ |
222 |
env->canrestore++; |
223 |
if (env->cleanwin < env->nwindows - 1) { |
224 |
env->cleanwin++; |
225 |
} |
226 |
if (env->otherwin == 0) { |
227 |
env->cansave--; |
228 |
} else {
|
229 |
env->otherwin--; |
230 |
} |
231 |
} |
232 |
|
233 |
target_ulong cpu_get_ccr(CPUState *env) |
234 |
{ |
235 |
target_ulong psr; |
236 |
|
237 |
psr = cpu_get_psr(env); |
238 |
|
239 |
return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); |
240 |
} |
241 |
|
242 |
void cpu_put_ccr(CPUState *env, target_ulong val)
|
243 |
{ |
244 |
env->xcc = (val >> 4) << 20; |
245 |
env->psr = (val & 0xf) << 20; |
246 |
CC_OP = CC_OP_FLAGS; |
247 |
} |
248 |
|
249 |
target_ulong cpu_get_cwp64(CPUState *env) |
250 |
{ |
251 |
return env->nwindows - 1 - env->cwp; |
252 |
} |
253 |
|
254 |
void cpu_put_cwp64(CPUState *env, int cwp) |
255 |
{ |
256 |
if (unlikely(cwp >= env->nwindows || cwp < 0)) { |
257 |
cwp %= env->nwindows; |
258 |
} |
259 |
cpu_set_cwp(env, env->nwindows - 1 - cwp);
|
260 |
} |
261 |
|
262 |
target_ulong helper_rdccr(CPUState *env) |
263 |
{ |
264 |
return cpu_get_ccr(env);
|
265 |
} |
266 |
|
267 |
void helper_wrccr(CPUState *env, target_ulong new_ccr)
|
268 |
{ |
269 |
cpu_put_ccr(env, new_ccr); |
270 |
} |
271 |
|
272 |
/* CWP handling is reversed in V9, but we still use the V8 register
|
273 |
order. */
|
274 |
target_ulong helper_rdcwp(CPUState *env) |
275 |
{ |
276 |
return cpu_get_cwp64(env);
|
277 |
} |
278 |
|
279 |
void helper_wrcwp(CPUState *env, target_ulong new_cwp)
|
280 |
{ |
281 |
cpu_put_cwp64(env, new_cwp); |
282 |
} |
283 |
|
284 |
static inline uint64_t *get_gregset(CPUState *env, uint32_t pstate) |
285 |
{ |
286 |
switch (pstate) {
|
287 |
default:
|
288 |
trace_win_helper_gregset_error(pstate); |
289 |
/* pass through to normal set of global registers */
|
290 |
case 0: |
291 |
return env->bgregs;
|
292 |
case PS_AG:
|
293 |
return env->agregs;
|
294 |
case PS_MG:
|
295 |
return env->mgregs;
|
296 |
case PS_IG:
|
297 |
return env->igregs;
|
298 |
} |
299 |
} |
300 |
|
301 |
void cpu_change_pstate(CPUState *env, uint32_t new_pstate)
|
302 |
{ |
303 |
uint32_t pstate_regs, new_pstate_regs; |
304 |
uint64_t *src, *dst; |
305 |
|
306 |
if (env->def->features & CPU_FEATURE_GL) {
|
307 |
/* PS_AG is not implemented in this case */
|
308 |
new_pstate &= ~PS_AG; |
309 |
} |
310 |
|
311 |
pstate_regs = env->pstate & 0xc01;
|
312 |
new_pstate_regs = new_pstate & 0xc01;
|
313 |
|
314 |
if (new_pstate_regs != pstate_regs) {
|
315 |
trace_win_helper_switch_pstate(pstate_regs, new_pstate_regs); |
316 |
|
317 |
/* Switch global register bank */
|
318 |
src = get_gregset(env, new_pstate_regs); |
319 |
dst = get_gregset(env, pstate_regs); |
320 |
memcpy32(dst, env->gregs); |
321 |
memcpy32(env->gregs, src); |
322 |
} else {
|
323 |
trace_win_helper_no_switch_pstate(new_pstate_regs); |
324 |
} |
325 |
env->pstate = new_pstate; |
326 |
} |
327 |
|
328 |
void helper_wrpstate(CPUState *env, target_ulong new_state)
|
329 |
{ |
330 |
cpu_change_pstate(env, new_state & 0xf3f);
|
331 |
|
332 |
#if !defined(CONFIG_USER_ONLY)
|
333 |
if (cpu_interrupts_enabled(env)) {
|
334 |
cpu_check_irqs(env); |
335 |
} |
336 |
#endif
|
337 |
} |
338 |
|
339 |
void helper_wrpil(CPUState *env, target_ulong new_pil)
|
340 |
{ |
341 |
#if !defined(CONFIG_USER_ONLY)
|
342 |
trace_win_helper_wrpil(env->psrpil, (uint32_t)new_pil); |
343 |
|
344 |
env->psrpil = new_pil; |
345 |
|
346 |
if (cpu_interrupts_enabled(env)) {
|
347 |
cpu_check_irqs(env); |
348 |
} |
349 |
#endif
|
350 |
} |
351 |
|
352 |
void helper_done(CPUState *env)
|
353 |
{ |
354 |
trap_state *tsptr = cpu_tsptr(env); |
355 |
|
356 |
env->pc = tsptr->tnpc; |
357 |
env->npc = tsptr->tnpc + 4;
|
358 |
cpu_put_ccr(env, tsptr->tstate >> 32);
|
359 |
env->asi = (tsptr->tstate >> 24) & 0xff; |
360 |
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); |
361 |
cpu_put_cwp64(env, tsptr->tstate & 0xff);
|
362 |
env->tl--; |
363 |
|
364 |
trace_win_helper_done(env->tl); |
365 |
|
366 |
#if !defined(CONFIG_USER_ONLY)
|
367 |
if (cpu_interrupts_enabled(env)) {
|
368 |
cpu_check_irqs(env); |
369 |
} |
370 |
#endif
|
371 |
} |
372 |
|
373 |
void helper_retry(CPUState *env)
|
374 |
{ |
375 |
trap_state *tsptr = cpu_tsptr(env); |
376 |
|
377 |
env->pc = tsptr->tpc; |
378 |
env->npc = tsptr->tnpc; |
379 |
cpu_put_ccr(env, tsptr->tstate >> 32);
|
380 |
env->asi = (tsptr->tstate >> 24) & 0xff; |
381 |
cpu_change_pstate(env, (tsptr->tstate >> 8) & 0xf3f); |
382 |
cpu_put_cwp64(env, tsptr->tstate & 0xff);
|
383 |
env->tl--; |
384 |
|
385 |
trace_win_helper_retry(env->tl); |
386 |
|
387 |
#if !defined(CONFIG_USER_ONLY)
|
388 |
if (cpu_interrupts_enabled(env)) {
|
389 |
cpu_check_irqs(env); |
390 |
} |
391 |
#endif
|
392 |
} |
393 |
#endif
|