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
This commit is contained in:
parent
6da41eafc4
commit
060366c5ad
|
@ -299,27 +299,127 @@ void cpu_loop(CPUARMState *env)
|
||||||
|
|
||||||
#ifdef TARGET_SPARC
|
#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)
|
void cpu_loop (CPUSPARCState *env)
|
||||||
{
|
{
|
||||||
int trapnr;
|
int trapnr, ret;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
trapnr = cpu_sparc_exec (env);
|
trapnr = cpu_sparc_exec (env);
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
case 0x8: case 0x10:
|
case 0x88:
|
||||||
env->regwptr[0] = do_syscall (env, env->gregs[1],
|
case 0x90:
|
||||||
env->regwptr[0], env->regwptr[1], env->regwptr[2],
|
ret = do_syscall (env, env->gregs[1],
|
||||||
env->regwptr[3], env->regwptr[4], env->regwptr[13]);
|
env->regwptr[0], env->regwptr[1],
|
||||||
if (env->regwptr[0] >= 0xffffffe0)
|
env->regwptr[2], env->regwptr[3],
|
||||||
env->psr |= PSR_CARRY;
|
env->regwptr[4], env->regwptr[5]);
|
||||||
break;
|
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
||||||
default:
|
env->psr |= PSR_CARRY;
|
||||||
printf ("Invalid trap: %d\n", trapnr);
|
ret = -ret;
|
||||||
exit (1);
|
} else {
|
||||||
}
|
env->psr &= ~PSR_CARRY;
|
||||||
process_pending_signals (env);
|
}
|
||||||
}
|
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
|
#endif
|
||||||
|
@ -636,8 +736,16 @@ int main(int argc, char **argv)
|
||||||
env->cpsr = regs->uregs[16];
|
env->cpsr = regs->uregs[16];
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_SPARC)
|
#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)
|
#elif defined(TARGET_PPC)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
Loading…
Reference in New Issue