Revision 83469015 target-sparc/op_helper.c
b/target-sparc/op_helper.c | ||
---|---|---|
1 | 1 |
#include "exec.h" |
2 | 2 |
|
3 |
//#define DEBUG_PCALL |
|
3 | 4 |
//#define DEBUG_MMU |
4 | 5 |
|
5 | 6 |
void raise_exception(int tt) |
... | ... | |
223 | 224 |
#ifndef TARGET_SPARC64 |
224 | 225 |
void helper_ld_asi(int asi, int size, int sign) |
225 | 226 |
{ |
226 |
uint32_t ret; |
|
227 |
uint32_t ret = 0;
|
|
227 | 228 |
|
228 | 229 |
switch (asi) { |
229 | 230 |
case 3: /* MMU probe */ |
... | ... | |
299 | 300 |
} |
300 | 301 |
case 4: /* write MMU regs */ |
301 | 302 |
{ |
302 |
int reg = (T0 >> 8) & 0xf, oldreg; |
|
303 |
int reg = (T0 >> 8) & 0xf; |
|
304 |
uint32_t oldreg; |
|
303 | 305 |
|
304 | 306 |
oldreg = env->mmuregs[reg]; |
305 | 307 |
switch(reg) { |
... | ... | |
339 | 341 |
// value (T1) = src |
340 | 342 |
// address (T0) = dst |
341 | 343 |
// copy 32 bytes |
342 |
int src = T1, dst = T0;
|
|
344 |
uint32_t src = T1, dst = T0;
|
|
343 | 345 |
uint8_t temp[32]; |
344 | 346 |
|
345 | 347 |
tswap32s(&src); |
... | ... | |
353 | 355 |
// value (T1, T2) |
354 | 356 |
// address (T0) = dst |
355 | 357 |
// fill 32 bytes |
356 |
int i, dst = T0; |
|
358 |
int i; |
|
359 |
uint32_t dst = T0; |
|
357 | 360 |
uint64_t val; |
358 | 361 |
|
359 | 362 |
val = (((uint64_t)T1) << 32) | T2; |
... | ... | |
366 | 369 |
return; |
367 | 370 |
case 0x20 ... 0x2f: /* MMU passthrough */ |
368 | 371 |
{ |
369 |
int temp = T1;
|
|
372 |
uint32_t temp = T1;
|
|
370 | 373 |
if (size == 4) |
371 | 374 |
tswap32s(&temp); |
372 | 375 |
else if (size == 2) |
... | ... | |
383 | 386 |
|
384 | 387 |
void helper_ld_asi(int asi, int size, int sign) |
385 | 388 |
{ |
386 |
uint64_t ret; |
|
389 |
uint64_t ret = 0;
|
|
387 | 390 |
|
388 | 391 |
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
389 |
raise_exception(TT_PRIV_INSN);
|
|
392 |
raise_exception(TT_PRIV_ACT);
|
|
390 | 393 |
|
391 | 394 |
switch (asi) { |
392 | 395 |
case 0x14: // Bypass |
... | ... | |
401 | 404 |
tswap16s((uint16_t *)&ret); |
402 | 405 |
break; |
403 | 406 |
} |
407 |
case 0x04: // Nucleus |
|
408 |
case 0x0c: // Nucleus Little Endian (LE) |
|
409 |
case 0x10: // As if user primary |
|
410 |
case 0x11: // As if user secondary |
|
411 |
case 0x18: // As if user primary LE |
|
412 |
case 0x19: // As if user secondary LE |
|
404 | 413 |
case 0x1c: // Bypass LE |
405 | 414 |
case 0x1d: // Bypass, non-cacheable LE |
415 |
case 0x24: // Nucleus quad LDD 128 bit atomic |
|
416 |
case 0x2c: // Nucleus quad LDD 128 bit atomic |
|
417 |
case 0x4a: // UPA config |
|
418 |
case 0x82: // Primary no-fault |
|
419 |
case 0x83: // Secondary no-fault |
|
420 |
case 0x88: // Primary LE |
|
421 |
case 0x89: // Secondary LE |
|
422 |
case 0x8a: // Primary no-fault LE |
|
423 |
case 0x8b: // Secondary no-fault LE |
|
406 | 424 |
// XXX |
407 | 425 |
break; |
408 | 426 |
case 0x45: // LSU |
... | ... | |
418 | 436 |
case 0x51: // I-MMU 8k TSB pointer |
419 | 437 |
case 0x52: // I-MMU 64k TSB pointer |
420 | 438 |
case 0x55: // I-MMU data access |
421 |
case 0x56: // I-MMU tag read
|
|
439 |
// XXX
|
|
422 | 440 |
break; |
441 |
case 0x56: // I-MMU tag read |
|
442 |
{ |
|
443 |
unsigned int i; |
|
444 |
|
|
445 |
for (i = 0; i < 64; i++) { |
|
446 |
// Valid, ctx match, vaddr match |
|
447 |
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 && |
|
448 |
env->itlb_tag[i] == T0) { |
|
449 |
ret = env->itlb_tag[i]; |
|
450 |
break; |
|
451 |
} |
|
452 |
} |
|
453 |
break; |
|
454 |
} |
|
423 | 455 |
case 0x58: // D-MMU regs |
424 | 456 |
{ |
425 | 457 |
int reg = (T0 >> 3) & 0xf; |
... | ... | |
427 | 459 |
ret = env->dmmuregs[reg]; |
428 | 460 |
break; |
429 | 461 |
} |
462 |
case 0x5e: // D-MMU tag read |
|
463 |
{ |
|
464 |
unsigned int i; |
|
465 |
|
|
466 |
for (i = 0; i < 64; i++) { |
|
467 |
// Valid, ctx match, vaddr match |
|
468 |
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 && |
|
469 |
env->dtlb_tag[i] == T0) { |
|
470 |
ret = env->dtlb_tag[i]; |
|
471 |
break; |
|
472 |
} |
|
473 |
} |
|
474 |
break; |
|
475 |
} |
|
430 | 476 |
case 0x59: // D-MMU 8k TSB pointer |
431 | 477 |
case 0x5a: // D-MMU 64k TSB pointer |
432 | 478 |
case 0x5b: // D-MMU data pointer |
433 | 479 |
case 0x5d: // D-MMU data access |
434 |
case 0x5e: // D-MMU tag read |
|
480 |
case 0x48: // Interrupt dispatch, RO |
|
481 |
case 0x49: // Interrupt data receive |
|
482 |
case 0x7f: // Incoming interrupt vector, RO |
|
483 |
// XXX |
|
435 | 484 |
break; |
436 | 485 |
case 0x54: // I-MMU data in, WO |
437 | 486 |
case 0x57: // I-MMU demap, WO |
438 | 487 |
case 0x5c: // D-MMU data in, WO |
439 | 488 |
case 0x5f: // D-MMU demap, WO |
489 |
case 0x77: // Interrupt vector, WO |
|
440 | 490 |
default: |
441 | 491 |
ret = 0; |
442 | 492 |
break; |
... | ... | |
447 | 497 |
void helper_st_asi(int asi, int size, int sign) |
448 | 498 |
{ |
449 | 499 |
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
450 |
raise_exception(TT_PRIV_INSN);
|
|
500 |
raise_exception(TT_PRIV_ACT);
|
|
451 | 501 |
|
452 | 502 |
switch(asi) { |
453 | 503 |
case 0x14: // Bypass |
... | ... | |
463 | 513 |
cpu_physical_memory_write(T0, (void *) &temp, size); |
464 | 514 |
} |
465 | 515 |
return; |
516 |
case 0x04: // Nucleus |
|
517 |
case 0x0c: // Nucleus Little Endian (LE) |
|
518 |
case 0x10: // As if user primary |
|
519 |
case 0x11: // As if user secondary |
|
520 |
case 0x18: // As if user primary LE |
|
521 |
case 0x19: // As if user secondary LE |
|
466 | 522 |
case 0x1c: // Bypass LE |
467 | 523 |
case 0x1d: // Bypass, non-cacheable LE |
524 |
case 0x24: // Nucleus quad LDD 128 bit atomic |
|
525 |
case 0x2c: // Nucleus quad LDD 128 bit atomic |
|
526 |
case 0x4a: // UPA config |
|
527 |
case 0x88: // Primary LE |
|
528 |
case 0x89: // Secondary LE |
|
468 | 529 |
// XXX |
469 | 530 |
return; |
470 | 531 |
case 0x45: // LSU |
... | ... | |
475 | 536 |
env->lsu = T1 & (DMMU_E | IMMU_E); |
476 | 537 |
// Mappings generated during D/I MMU disabled mode are |
477 | 538 |
// invalid in normal mode |
478 |
if (oldreg != env->lsu) |
|
539 |
if (oldreg != env->lsu) { |
|
540 |
#ifdef DEBUG_MMU |
|
541 |
printf("LSU change: 0x%llx -> 0x%llx\n", oldreg, env->lsu); |
|
542 |
dump_mmu(env); |
|
543 |
#endif |
|
479 | 544 |
tlb_flush(env, 1); |
545 |
} |
|
480 | 546 |
return; |
481 | 547 |
} |
482 | 548 |
case 0x50: // I-MMU regs |
... | ... | |
506 | 572 |
env->immuregs[reg] = T1; |
507 | 573 |
#ifdef DEBUG_MMU |
508 | 574 |
if (oldreg != env->immuregs[reg]) { |
509 |
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]);
|
|
575 |
printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->immuregs[reg]);
|
|
510 | 576 |
} |
511 | 577 |
dump_mmu(env); |
512 | 578 |
#endif |
... | ... | |
544 | 610 |
return; |
545 | 611 |
} |
546 | 612 |
case 0x57: // I-MMU demap |
613 |
// XXX |
|
547 | 614 |
return; |
548 | 615 |
case 0x58: // D-MMU regs |
549 | 616 |
{ |
... | ... | |
574 | 641 |
env->dmmuregs[reg] = T1; |
575 | 642 |
#ifdef DEBUG_MMU |
576 | 643 |
if (oldreg != env->dmmuregs[reg]) { |
577 |
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]);
|
|
644 |
printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg, oldreg, env->dmmuregs[reg]);
|
|
578 | 645 |
} |
579 | 646 |
dump_mmu(env); |
580 | 647 |
#endif |
... | ... | |
612 | 679 |
return; |
613 | 680 |
} |
614 | 681 |
case 0x5f: // D-MMU demap |
682 |
case 0x49: // Interrupt data receive |
|
683 |
// XXX |
|
615 | 684 |
return; |
616 | 685 |
case 0x51: // I-MMU 8k TSB pointer, RO |
617 | 686 |
case 0x52: // I-MMU 64k TSB pointer, RO |
... | ... | |
620 | 689 |
case 0x5a: // D-MMU 64k TSB pointer, RO |
621 | 690 |
case 0x5b: // D-MMU data pointer, RO |
622 | 691 |
case 0x5e: // D-MMU tag read, RO |
692 |
case 0x48: // Interrupt dispatch, RO |
|
693 |
case 0x7f: // Incoming interrupt vector, RO |
|
694 |
case 0x82: // Primary no-fault, RO |
|
695 |
case 0x83: // Secondary no-fault, RO |
|
696 |
case 0x8a: // Primary no-fault LE, RO |
|
697 |
case 0x8b: // Secondary no-fault LE, RO |
|
623 | 698 |
default: |
624 | 699 |
return; |
625 | 700 |
} |
... | ... | |
704 | 779 |
T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); |
705 | 780 |
T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); |
706 | 781 |
} |
782 |
|
|
783 |
static inline uint64_t *get_gregset(uint64_t pstate) |
|
784 |
{ |
|
785 |
switch (pstate) { |
|
786 |
default: |
|
787 |
case 0: |
|
788 |
return env->bgregs; |
|
789 |
case PS_AG: |
|
790 |
return env->agregs; |
|
791 |
case PS_MG: |
|
792 |
return env->mgregs; |
|
793 |
case PS_IG: |
|
794 |
return env->igregs; |
|
795 |
} |
|
796 |
} |
|
797 |
|
|
798 |
void do_wrpstate() |
|
799 |
{ |
|
800 |
uint64_t new_pstate, pstate_regs, new_pstate_regs; |
|
801 |
uint64_t *src, *dst; |
|
802 |
|
|
803 |
new_pstate = T0 & 0xf3f; |
|
804 |
pstate_regs = env->pstate & 0xc01; |
|
805 |
new_pstate_regs = new_pstate & 0xc01; |
|
806 |
if (new_pstate_regs != pstate_regs) { |
|
807 |
// Switch global register bank |
|
808 |
src = get_gregset(new_pstate_regs); |
|
809 |
dst = get_gregset(pstate_regs); |
|
810 |
memcpy32(dst, env->gregs); |
|
811 |
memcpy32(env->gregs, src); |
|
812 |
} |
|
813 |
env->pstate = new_pstate; |
|
814 |
} |
|
815 |
|
|
816 |
void do_done(void) |
|
817 |
{ |
|
818 |
env->tl--; |
|
819 |
env->pc = env->tnpc[env->tl]; |
|
820 |
env->npc = env->tnpc[env->tl] + 4; |
|
821 |
PUT_CCR(env, env->tstate[env->tl] >> 32); |
|
822 |
env->asi = (env->tstate[env->tl] >> 24) & 0xff; |
|
823 |
env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; |
|
824 |
set_cwp(env->tstate[env->tl] & 0xff); |
|
825 |
} |
|
826 |
|
|
827 |
void do_retry(void) |
|
828 |
{ |
|
829 |
env->tl--; |
|
830 |
env->pc = env->tpc[env->tl]; |
|
831 |
env->npc = env->tnpc[env->tl]; |
|
832 |
PUT_CCR(env, env->tstate[env->tl] >> 32); |
|
833 |
env->asi = (env->tstate[env->tl] >> 24) & 0xff; |
|
834 |
env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; |
|
835 |
set_cwp(env->tstate[env->tl] & 0xff); |
|
836 |
} |
|
707 | 837 |
#endif |
708 | 838 |
|
709 | 839 |
void set_cwp(int new_cwp) |
... | ... | |
744 | 874 |
#ifdef DEBUG_PCALL |
745 | 875 |
if (loglevel & CPU_LOG_INT) { |
746 | 876 |
static int count; |
747 |
fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
|
|
877 |
fprintf(logfile, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n",
|
|
748 | 878 |
count, intno, |
749 | 879 |
env->pc, |
750 | 880 |
env->npc, env->regwptr[6]); |
... | ... | |
766 | 896 |
} |
767 | 897 |
#endif |
768 | 898 |
#if !defined(CONFIG_USER_ONLY) |
769 |
if (env->pstate & PS_IE) {
|
|
770 |
cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
|
|
899 |
if (env->tl == MAXTL) {
|
|
900 |
cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
|
|
771 | 901 |
return; |
772 | 902 |
} |
773 | 903 |
#endif |
... | ... | |
776 | 906 |
env->tpc[env->tl] = env->pc; |
777 | 907 |
env->tnpc[env->tl] = env->npc; |
778 | 908 |
env->tt[env->tl] = intno; |
779 |
env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); |
|
780 |
env->tl++; |
|
909 |
env->pstate = PS_PEF | PS_PRIV | PS_AG; |
|
910 |
env->tbr &= ~0x7fffULL; |
|
911 |
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); |
|
912 |
if (env->tl < MAXTL - 1) { |
|
913 |
env->tl++; |
|
914 |
} else { |
|
915 |
env->pstate |= PS_RED; |
|
916 |
if (env->tl != MAXTL) |
|
917 |
env->tl++; |
|
918 |
} |
|
781 | 919 |
env->pc = env->tbr; |
782 | 920 |
env->npc = env->pc + 4; |
783 | 921 |
env->exception_index = 0; |
Also available in: Unified diff