fixed handling of sparc register window exceptions

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1300 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2005-02-19 17:25:31 +00:00
parent a20b552469
commit 2623cbaf1a
1 changed files with 31 additions and 26 deletions

View File

@ -396,7 +396,8 @@ void cpu_loop(CPUARMState *env)
//#define DEBUG_WIN //#define DEBUG_WIN
/* WARNING: dealing with register windows _is_ complicated */ /* WARNING: dealing with register windows _is_ complicated. More info
can be found at http://www.sics.se/~psm/sparcstack.html */
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
{ {
index = (index + cwp * 16) & (16 * NWINDOWS - 1); index = (index + cwp * 16) & (16 * NWINDOWS - 1);
@ -407,34 +408,36 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
return index; return index;
} }
static inline void save_window_offset(CPUSPARCState *env, int offset) /* save the register window 'cwp1' */
static inline void save_window_offset(CPUSPARCState *env, int cwp1)
{ {
unsigned int new_wim, i, cwp1; unsigned int i;
uint32_t *sp_ptr; uint32_t *sp_ptr;
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
/* save the window */
cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
#if defined(DEBUG_WIN) #if defined(DEBUG_WIN)
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
(int)sp_ptr, cwp1); (int)sp_ptr, cwp1);
#endif #endif
for(i = 0; i < 16; i++) for(i = 0; i < 16; i++) {
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
env->wim = new_wim; sp_ptr++;
}
} }
static void save_window(CPUSPARCState *env) static void save_window(CPUSPARCState *env)
{ {
save_window_offset(env, 2); unsigned int new_wim;
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1);
save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
env->wim = new_wim;
} }
static void restore_window(CPUSPARCState *env) static void restore_window(CPUSPARCState *env)
{ {
unsigned int new_wim, i, cwp1; unsigned int new_wim, i, cwp1;
uint32_t *sp_ptr; uint32_t *sp_ptr, reg;
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
((1LL << NWINDOWS) - 1); ((1LL << NWINDOWS) - 1);
@ -446,32 +449,34 @@ static void restore_window(CPUSPARCState *env)
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
(int)sp_ptr, cwp1); (int)sp_ptr, cwp1);
#endif #endif
for(i = 0; i < 16; i++) for(i = 0; i < 16; i++) {
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); get_user(reg, sp_ptr);
env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg;
sp_ptr++;
}
env->wim = new_wim; env->wim = new_wim;
} }
#if 0
static void flush_windows(CPUSPARCState *env) static void flush_windows(CPUSPARCState *env)
{ {
int offset, cwp1; int offset, cwp1;
#if defined(DEBUG_WIN)
printf("flush_windows:\n"); offset = 1;
#endif
offset = 2;
for(;;) { for(;;) {
/* if restore would invoke restore_window(), then we can stop */ /* if restore would invoke restore_window(), then we can stop */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1); cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
if (env->wim & (1 << cwp1)) if (env->wim & (1 << cwp1))
break; break;
#if defined(DEBUG_WIN) save_window_offset(env, cwp1);
printf("offset=%d: ", offset);
#endif
save_window_offset(env, offset);
offset++; offset++;
} }
} /* set wim so that restore will reload the registers */
cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
env->wim = 1 << cwp1;
#if defined(DEBUG_WIN)
printf("flush_windows: nb=%d\n", offset - 1);
#endif #endif
}
void cpu_loop (CPUSPARCState *env) void cpu_loop (CPUSPARCState *env)
{ {
@ -500,7 +505,7 @@ void cpu_loop (CPUSPARCState *env)
env->npc = env->npc + 4; env->npc = env->npc + 4;
break; break;
case 0x83: /* flush windows */ case 0x83: /* flush windows */
// flush_windows(env); flush_windows(env);
/* next instruction */ /* next instruction */
env->pc = env->npc; env->pc = env->npc;
env->npc = env->npc + 4; env->npc = env->npc + 4;