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