Commit 2623cbaf1ac9101934c06f9afece04b4b62550d8
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; | ... | ... |