Commit 2623cbaf1ac9101934c06f9afece04b4b62550d8

Authored by bellard
1 parent a20b5524

fixed handling of sparc register window exceptions


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1300 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 31 additions and 26 deletions
linux-user/main.c
@@ -396,7 +396,8 @@ void cpu_loop(CPUARMState *env) @@ -396,7 +396,8 @@ void cpu_loop(CPUARMState *env)
396 396
397 //#define DEBUG_WIN 397 //#define DEBUG_WIN
398 398
399 -/* WARNING: dealing with register windows _is_ complicated */ 399 +/* WARNING: dealing with register windows _is_ complicated. More info
  400 + can be found at http://www.sics.se/~psm/sparcstack.html */
400 static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) 401 static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
401 { 402 {
402 index = (index + cwp * 16) & (16 * NWINDOWS - 1); 403 index = (index + cwp * 16) & (16 * NWINDOWS - 1);
@@ -407,34 +408,36 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) @@ -407,34 +408,36 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
407 return index; 408 return index;
408 } 409 }
409 410
410 -static inline void save_window_offset(CPUSPARCState *env, int offset) 411 +/* save the register window 'cwp1' */
  412 +static inline void save_window_offset(CPUSPARCState *env, int cwp1)
411 { 413 {
412 - unsigned int new_wim, i, cwp1; 414 + unsigned int i;
413 uint32_t *sp_ptr; 415 uint32_t *sp_ptr;
414 416
415 - new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &  
416 - ((1LL << NWINDOWS) - 1);  
417 - /* save the window */  
418 - cwp1 = (env->cwp + offset) & (NWINDOWS - 1);  
419 sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); 417 sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
420 #if defined(DEBUG_WIN) 418 #if defined(DEBUG_WIN)
421 printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", 419 printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
422 (int)sp_ptr, cwp1); 420 (int)sp_ptr, cwp1);
423 #endif 421 #endif
424 - for(i = 0; i < 16; i++)  
425 - stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]);  
426 - env->wim = new_wim; 422 + for(i = 0; i < 16; i++) {
  423 + put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
  424 + sp_ptr++;
  425 + }
427 } 426 }
428 427
429 static void save_window(CPUSPARCState *env) 428 static void save_window(CPUSPARCState *env)
430 { 429 {
431 - save_window_offset(env, 2); 430 + unsigned int new_wim;
  431 + new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
  432 + ((1LL << NWINDOWS) - 1);
  433 + save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
  434 + env->wim = new_wim;
432 } 435 }
433 436
434 static void restore_window(CPUSPARCState *env) 437 static void restore_window(CPUSPARCState *env)
435 { 438 {
436 unsigned int new_wim, i, cwp1; 439 unsigned int new_wim, i, cwp1;
437 - uint32_t *sp_ptr; 440 + uint32_t *sp_ptr, reg;
438 441
439 new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & 442 new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
440 ((1LL << NWINDOWS) - 1); 443 ((1LL << NWINDOWS) - 1);
@@ -446,32 +449,34 @@ static void restore_window(CPUSPARCState *env) @@ -446,32 +449,34 @@ static void restore_window(CPUSPARCState *env)
446 printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", 449 printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
447 (int)sp_ptr, cwp1); 450 (int)sp_ptr, cwp1);
448 #endif 451 #endif
449 - for(i = 0; i < 16; i++)  
450 - env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); 452 + for(i = 0; i < 16; i++) {
  453 + get_user(reg, sp_ptr);
  454 + env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg;
  455 + sp_ptr++;
  456 + }
451 env->wim = new_wim; 457 env->wim = new_wim;
452 } 458 }
453 459
454 -#if 0  
455 static void flush_windows(CPUSPARCState *env) 460 static void flush_windows(CPUSPARCState *env)
456 { 461 {
457 int offset, cwp1; 462 int offset, cwp1;
458 -#if defined(DEBUG_WIN)  
459 - printf("flush_windows:\n");  
460 -#endif  
461 - offset = 2; 463 +
  464 + offset = 1;
462 for(;;) { 465 for(;;) {
463 /* if restore would invoke restore_window(), then we can stop */ 466 /* if restore would invoke restore_window(), then we can stop */
464 - cwp1 = (env->cwp + 1) & (NWINDOWS - 1); 467 + cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
465 if (env->wim & (1 << cwp1)) 468 if (env->wim & (1 << cwp1))
466 break; 469 break;
467 -#if defined(DEBUG_WIN)  
468 - printf("offset=%d: ", offset);  
469 -#endif  
470 - save_window_offset(env, offset); 470 + save_window_offset(env, cwp1);
471 offset++; 471 offset++;
472 } 472 }
473 -} 473 + /* set wim so that restore will reload the registers */
  474 + cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
  475 + env->wim = 1 << cwp1;
  476 +#if defined(DEBUG_WIN)
  477 + printf("flush_windows: nb=%d\n", offset - 1);
474 #endif 478 #endif
  479 +}
475 480
476 void cpu_loop (CPUSPARCState *env) 481 void cpu_loop (CPUSPARCState *env)
477 { 482 {
@@ -500,7 +505,7 @@ void cpu_loop (CPUSPARCState *env) @@ -500,7 +505,7 @@ void cpu_loop (CPUSPARCState *env)
500 env->npc = env->npc + 4; 505 env->npc = env->npc + 4;
501 break; 506 break;
502 case 0x83: /* flush windows */ 507 case 0x83: /* flush windows */
503 - // flush_windows(env); 508 + flush_windows(env);
504 /* next instruction */ 509 /* next instruction */
505 env->pc = env->npc; 510 env->pc = env->npc;
506 env->npc = env->npc + 4; 511 env->npc = env->npc + 4;