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,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; |