| 396 |
|
|
| 397 |
//#define DEBUG_WIN |
//#define DEBUG_WIN |
| 398 |
|
|
| 399 |
/* WARNING: dealing with register windows _is_ complicated */ |
/* WARNING: dealing with register windows _is_ complicated. More info |
| 400 |
|
can be found at http://www.sics.se/~psm/sparcstack.html */ |
| 401 |
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) |
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) |
| 402 |
{ |
{ |
| 403 |
index = (index + cwp * 16) & (16 * NWINDOWS - 1); |
index = (index + cwp * 16) & (16 * NWINDOWS - 1); |
| 408 |
return index; |
return index; |
| 409 |
} |
} |
| 410 |
|
|
| 411 |
static inline void save_window_offset(CPUSPARCState *env, int offset) |
/* save the register window 'cwp1' */ |
| 412 |
|
static inline void save_window_offset(CPUSPARCState *env, int cwp1) |
| 413 |
{ |
{ |
| 414 |
unsigned int new_wim, i, cwp1; |
unsigned int i; |
| 415 |
uint32_t *sp_ptr; |
uint32_t *sp_ptr; |
| 416 |
|
|
|
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & |
|
|
((1LL << NWINDOWS) - 1); |
|
|
/* save the window */ |
|
|
cwp1 = (env->cwp + offset) & (NWINDOWS - 1); |
|
| 417 |
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); |
sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); |
| 418 |
#if defined(DEBUG_WIN) |
#if defined(DEBUG_WIN) |
| 419 |
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", |
printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", |
| 420 |
(int)sp_ptr, cwp1); |
(int)sp_ptr, cwp1); |
| 421 |
#endif |
#endif |
| 422 |
for(i = 0; i < 16; i++) |
for(i = 0; i < 16; i++) { |
| 423 |
stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); |
put_user(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); |
| 424 |
env->wim = new_wim; |
sp_ptr++; |
| 425 |
|
} |
| 426 |
} |
} |
| 427 |
|
|
| 428 |
static void save_window(CPUSPARCState *env) |
static void save_window(CPUSPARCState *env) |
| 429 |
{ |
{ |
| 430 |
save_window_offset(env, 2); |
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; |
| 435 |
} |
} |
| 436 |
|
|
| 437 |
static void restore_window(CPUSPARCState *env) |
static void restore_window(CPUSPARCState *env) |
| 438 |
{ |
{ |
| 439 |
unsigned int new_wim, i, cwp1; |
unsigned int new_wim, i, cwp1; |
| 440 |
uint32_t *sp_ptr; |
uint32_t *sp_ptr, reg; |
| 441 |
|
|
| 442 |
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & |
new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & |
| 443 |
((1LL << NWINDOWS) - 1); |
((1LL << NWINDOWS) - 1); |
| 449 |
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", |
printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", |
| 450 |
(int)sp_ptr, cwp1); |
(int)sp_ptr, cwp1); |
| 451 |
#endif |
#endif |
| 452 |
for(i = 0; i < 16; i++) |
for(i = 0; i < 16; i++) { |
| 453 |
env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); |
get_user(reg, sp_ptr); |
| 454 |
|
env->regbase[get_reg_index(env, cwp1, 8 + i)] = reg; |
| 455 |
|
sp_ptr++; |
| 456 |
|
} |
| 457 |
env->wim = new_wim; |
env->wim = new_wim; |
| 458 |
} |
} |
| 459 |
|
|
|
#if 0 |
|
| 460 |
static void flush_windows(CPUSPARCState *env) |
static void flush_windows(CPUSPARCState *env) |
| 461 |
{ |
{ |
| 462 |
int offset, cwp1; |
int offset, cwp1; |
| 463 |
#if defined(DEBUG_WIN) |
|
| 464 |
printf("flush_windows:\n"); |
offset = 1; |
|
#endif |
|
|
offset = 2; |
|
| 465 |
for(;;) { |
for(;;) { |
| 466 |
/* if restore would invoke restore_window(), then we can stop */ |
/* if restore would invoke restore_window(), then we can stop */ |
| 467 |
cwp1 = (env->cwp + 1) & (NWINDOWS - 1); |
cwp1 = (env->cwp + offset) & (NWINDOWS - 1); |
| 468 |
if (env->wim & (1 << cwp1)) |
if (env->wim & (1 << cwp1)) |
| 469 |
break; |
break; |
| 470 |
#if defined(DEBUG_WIN) |
save_window_offset(env, cwp1); |
|
printf("offset=%d: ", offset); |
|
|
#endif |
|
|
save_window_offset(env, offset); |
|
| 471 |
offset++; |
offset++; |
| 472 |
} |
} |
| 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); |
| 478 |
#endif |
#endif |
| 479 |
|
} |
| 480 |
|
|
| 481 |
void cpu_loop (CPUSPARCState *env) |
void cpu_loop (CPUSPARCState *env) |
| 482 |
{ |
{ |
| 505 |
env->npc = env->npc + 4; |
env->npc = env->npc + 4; |
| 506 |
break; |
break; |
| 507 |
case 0x83: /* flush windows */ |
case 0x83: /* flush windows */ |
| 508 |
// flush_windows(env); |
flush_windows(env); |
| 509 |
/* next instruction */ |
/* next instruction */ |
| 510 |
env->pc = env->npc; |
env->pc = env->npc; |
| 511 |
env->npc = env->npc + 4; |
env->npc = env->npc + 4; |