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 396  
397 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 401 static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
401 402 {
402 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 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 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 417 sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]);
420 418 #if defined(DEBUG_WIN)
421 419 printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
422 420 (int)sp_ptr, cwp1);
423 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 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 437 static void restore_window(CPUSPARCState *env)
435 438 {
436 439 unsigned int new_wim, i, cwp1;
437   - uint32_t *sp_ptr;
  440 + uint32_t *sp_ptr, reg;
438 441  
439 442 new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
440 443 ((1LL << NWINDOWS) - 1);
... ... @@ -446,32 +449,34 @@ static void restore_window(CPUSPARCState *env)
446 449 printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
447 450 (int)sp_ptr, cwp1);
448 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 457 env->wim = new_wim;
452 458 }
453 459  
454   -#if 0
455 460 static void flush_windows(CPUSPARCState *env)
456 461 {
457 462 int offset, cwp1;
458   -#if defined(DEBUG_WIN)
459   - printf("flush_windows:\n");
460   -#endif
461   - offset = 2;
  463 +
  464 + offset = 1;
462 465 for(;;) {
463 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 468 if (env->wim & (1 << cwp1))
466 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 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 478 #endif
  479 +}
475 480  
476 481 void cpu_loop (CPUSPARCState *env)
477 482 {
... ... @@ -500,7 +505,7 @@ void cpu_loop (CPUSPARCState *env)
500 505 env->npc = env->npc + 4;
501 506 break;
502 507 case 0x83: /* flush windows */
503   - // flush_windows(env);
  508 + flush_windows(env);
504 509 /* next instruction */
505 510 env->pc = env->npc;
506 511 env->npc = env->npc + 4;
... ...