diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-01-04 15:50:01 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-01-04 15:50:01 +0000 |
commit | 060366c5ad18b3e32886d8f7ce89c6cc23abb7ff (patch) | |
tree | 89f146d5e9c985d73a4366eab1656473ca88335e /linux-user | |
parent | 6da41eafc40c543c581d8b585a906691beca43b0 (diff) |
SPARC fixes : syscall fixes - added user register window exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@494 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/main.c | 150 |
1 files changed, 129 insertions, 21 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index aa5b758d64..bc19c645f6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -299,27 +299,127 @@ void cpu_loop(CPUARMState *env) #ifdef TARGET_SPARC +//#define DEBUG_WIN + +/* WARNING: dealing with register windows _is_ complicated */ +static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) +{ + index = (index + cwp * 16) & (16 * NWINDOWS - 1); + /* wrap handling : if cwp is on the last window, then we use the + registers 'after' the end */ + if (index < 8 && env->cwp == (NWINDOWS - 1)) + index += (16 * NWINDOWS); + return index; +} + +static inline void save_window_offset(CPUSPARCState *env, int offset) +{ + unsigned int new_wim, i, cwp1; + 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)]); +#if defined(DEBUG_WIN) + printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) + stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); + env->wim = new_wim; +} + +static void save_window(CPUSPARCState *env) +{ + save_window_offset(env, 2); +} + +static void restore_window(CPUSPARCState *env) +{ + unsigned int new_wim, i, cwp1; + uint32_t *sp_ptr; + + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & + ((1LL << NWINDOWS) - 1); + + /* restore the invalid window */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); +#if defined(DEBUG_WIN) + printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", + (int)sp_ptr, cwp1); +#endif + for(i = 0; i < 16; i++) + env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); + env->wim = new_wim; +} + +static void flush_windows(CPUSPARCState *env) +{ + int offset, cwp1; +#if defined(DEBUG_WIN) + printf("flush_windows:\n"); +#endif + offset = 2; + for(;;) { + /* if restore would invoke restore_window(), then we can stop */ + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); + if (env->wim & (1 << cwp1)) + break; +#if defined(DEBUG_WIN) + printf("offset=%d: ", offset); +#endif + save_window_offset(env, offset); + offset++; + } +} + void cpu_loop (CPUSPARCState *env) { - int trapnr; - - while (1) { - trapnr = cpu_sparc_exec (env); - - switch (trapnr) { - case 0x8: case 0x10: - env->regwptr[0] = do_syscall (env, env->gregs[1], - env->regwptr[0], env->regwptr[1], env->regwptr[2], - env->regwptr[3], env->regwptr[4], env->regwptr[13]); - if (env->regwptr[0] >= 0xffffffe0) - env->psr |= PSR_CARRY; - break; - default: - printf ("Invalid trap: %d\n", trapnr); - exit (1); - } - process_pending_signals (env); - } + int trapnr, ret; + + while (1) { + trapnr = cpu_sparc_exec (env); + + switch (trapnr) { + case 0x88: + case 0x90: + ret = do_syscall (env, env->gregs[1], + env->regwptr[0], env->regwptr[1], + env->regwptr[2], env->regwptr[3], + env->regwptr[4], env->regwptr[5]); + if ((unsigned int)ret >= (unsigned int)(-515)) { + env->psr |= PSR_CARRY; + ret = -ret; + } else { + env->psr &= ~PSR_CARRY; + } + env->regwptr[0] = ret; + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case 0x83: /* flush windows */ + // flush_windows(env); + /* next instruction */ + env->pc = env->npc; + env->npc = env->npc + 4; + break; + case TT_WIN_OVF: /* window overflow */ + save_window(env); + break; + case TT_WIN_UNF: /* window underflow */ + restore_window(env); + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_sparc_dump_state(env, stderr, 0); + exit (1); + } + process_pending_signals (env); + } } #endif @@ -636,8 +736,16 @@ int main(int argc, char **argv) env->cpsr = regs->uregs[16]; } #elif defined(TARGET_SPARC) - env->pc = regs->u_regs[0]; - env->regwptr[6] = regs->u_regs[1]-0x40; + { + int i; + env->pc = regs->pc; + env->npc = regs->npc; + env->y = regs->y; + for(i = 0; i < 8; i++) + env->gregs[i] = regs->u_regs[i]; + for(i = 0; i < 8; i++) + env->regwptr[i] = regs->u_regs[i + 8]; + } #elif defined(TARGET_PPC) { int i; |