| 22 |
|
|
| 23 |
#define MIPS_DEBUG_DISAS |
#define MIPS_DEBUG_DISAS |
| 24 |
|
|
| 25 |
|
#define GETPC() (__builtin_return_address(0)) |
| 26 |
|
|
| 27 |
/*****************************************************************************/ |
/*****************************************************************************/ |
| 28 |
/* Exceptions processing helpers */ |
/* Exceptions processing helpers */ |
| 29 |
void cpu_loop_exit(void) |
void cpu_loop_exit(void) |
| 48 |
do_raise_exception_err(exception, 0); |
do_raise_exception_err(exception, 0); |
| 49 |
} |
} |
| 50 |
|
|
| 51 |
|
void do_restore_state (void *pc_ptr) |
| 52 |
|
{ |
| 53 |
|
TranslationBlock *tb; |
| 54 |
|
unsigned long pc = (unsigned long) pc_ptr; |
| 55 |
|
|
| 56 |
|
tb = tb_find_pc (pc); |
| 57 |
|
cpu_restore_state (tb, env, pc, NULL); |
| 58 |
|
} |
| 59 |
|
|
| 60 |
|
void do_raise_exception_direct (uint32_t exception) |
| 61 |
|
{ |
| 62 |
|
do_restore_state (GETPC ()); |
| 63 |
|
do_raise_exception_err (exception, 0); |
| 64 |
|
} |
| 65 |
|
|
| 66 |
#define MEMSUFFIX _raw |
#define MEMSUFFIX _raw |
| 67 |
#include "op_helper_mem.c" |
#include "op_helper_mem.c" |
| 68 |
#undef MEMSUFFIX |
#undef MEMSUFFIX |
| 90 |
|
|
| 91 |
void do_mult (void) |
void do_mult (void) |
| 92 |
{ |
{ |
| 93 |
set_HILO((int64_t)T0 * (int64_t)T1); |
set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
| 94 |
} |
} |
| 95 |
|
|
| 96 |
void do_multu (void) |
void do_multu (void) |
| 102 |
{ |
{ |
| 103 |
int64_t tmp; |
int64_t tmp; |
| 104 |
|
|
| 105 |
tmp = ((int64_t)T0 * (int64_t)T1); |
tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
| 106 |
set_HILO((int64_t)get_HILO() + tmp); |
set_HILO((int64_t)get_HILO() + tmp); |
| 107 |
} |
} |
| 108 |
|
|
| 118 |
{ |
{ |
| 119 |
int64_t tmp; |
int64_t tmp; |
| 120 |
|
|
| 121 |
tmp = ((int64_t)T0 * (int64_t)T1); |
tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1); |
| 122 |
set_HILO((int64_t)get_HILO() - tmp); |
set_HILO((int64_t)get_HILO() - tmp); |
| 123 |
} |
} |
| 124 |
|
|
| 370 |
val = T0 & 0xFFFFF0FF; |
val = T0 & 0xFFFFF0FF; |
| 371 |
old = env->CP0_EntryHi; |
old = env->CP0_EntryHi; |
| 372 |
env->CP0_EntryHi = val; |
env->CP0_EntryHi = val; |
| 373 |
|
/* If the ASID changes, flush qemu's TLB. */ |
| 374 |
|
if ((old & 0xFF) != (val & 0xFF)) |
| 375 |
|
tlb_flush (env, 1); |
| 376 |
rn = "EntryHi"; |
rn = "EntryHi"; |
| 377 |
break; |
break; |
| 378 |
case 11: |
case 11: |
| 545 |
addr = tlb->PFN[0]; |
addr = tlb->PFN[0]; |
| 546 |
end = addr + (tlb->end - tlb->VPN); |
end = addr + (tlb->end - tlb->VPN); |
| 547 |
tb_invalidate_page_range(addr, end); |
tb_invalidate_page_range(addr, end); |
| 548 |
|
/* FIXME: Might be faster to just invalidate the whole "tlb" here |
| 549 |
|
and refill it on demand from our simulated TLB. */ |
| 550 |
|
addr = tlb->VPN; |
| 551 |
|
while (addr < tlb->end) { |
| 552 |
|
tlb_flush_page (env, addr); |
| 553 |
|
addr += TARGET_PAGE_SIZE; |
| 554 |
|
} |
| 555 |
} |
} |
| 556 |
if (tlb->V[1]) { |
if (tlb->V[1]) { |
| 557 |
addr = tlb->PFN[1]; |
addr = tlb->PFN[1]; |
| 558 |
end = addr + (tlb->end - tlb->VPN); |
end = addr + (tlb->end - tlb->VPN); |
| 559 |
tb_invalidate_page_range(addr, end); |
tb_invalidate_page_range(addr, end); |
| 560 |
|
/* FIXME: Might be faster to just invalidate the whole "tlb" here |
| 561 |
|
and refill it on demand from our simulated TLB. */ |
| 562 |
|
addr = tlb->end; |
| 563 |
|
while (addr < tlb->end2) { |
| 564 |
|
tlb_flush_page (env, addr); |
| 565 |
|
addr += TARGET_PAGE_SIZE; |
| 566 |
|
} |
| 567 |
} |
} |
| 568 |
} |
} |
| 569 |
|
|
| 579 |
size = env->CP0_PageMask >> 13; |
size = env->CP0_PageMask >> 13; |
| 580 |
size = 4 * (size + 1); |
size = 4 * (size + 1); |
| 581 |
tlb->end = tlb->VPN + (1 << (8 + size)); |
tlb->end = tlb->VPN + (1 << (8 + size)); |
| 582 |
|
tlb->end2 = tlb->end + (1 << (8 + size)); |
| 583 |
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; |
| 584 |
tlb->V[0] = env->CP0_EntryLo0 & 2; |
tlb->V[0] = env->CP0_EntryLo0 & 2; |
| 585 |
tlb->D[0] = env->CP0_EntryLo0 & 4; |
tlb->D[0] = env->CP0_EntryLo0 & 4; |
| 636 |
int size; |
int size; |
| 637 |
|
|
| 638 |
tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; |
tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)]; |
| 639 |
|
|
| 640 |
|
/* If this will change the current ASID, flush qemu's TLB. */ |
| 641 |
|
/* FIXME: Could avoid flushing things which match global entries... */ |
| 642 |
|
if ((env->CP0_EntryHi & 0xFF) != tlb->ASID) |
| 643 |
|
tlb_flush (env, 1); |
| 644 |
|
|
| 645 |
env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
env->CP0_EntryHi = tlb->VPN | tlb->ASID; |
| 646 |
size = (tlb->end - tlb->VPN) >> 12; |
size = (tlb->end - tlb->VPN) >> 12; |
| 647 |
env->CP0_PageMask = (size - 1) << 13; |
env->CP0_PageMask = (size - 1) << 13; |
| 705 |
|
|
| 706 |
#if !defined(CONFIG_USER_ONLY) |
#if !defined(CONFIG_USER_ONLY) |
| 707 |
|
|
| 708 |
|
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr); |
| 709 |
|
|
| 710 |
#define MMUSUFFIX _mmu |
#define MMUSUFFIX _mmu |
| 711 |
#define GETPC() (__builtin_return_address(0)) |
#define ALIGNED_ONLY |
| 712 |
|
|
| 713 |
#define SHIFT 0 |
#define SHIFT 0 |
| 714 |
#include "softmmu_template.h" |
#include "softmmu_template.h" |
| 722 |
#define SHIFT 3 |
#define SHIFT 3 |
| 723 |
#include "softmmu_template.h" |
#include "softmmu_template.h" |
| 724 |
|
|
| 725 |
|
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr) |
| 726 |
|
{ |
| 727 |
|
env->CP0_BadVAddr = addr; |
| 728 |
|
do_restore_state (retaddr); |
| 729 |
|
do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); |
| 730 |
|
} |
| 731 |
|
|
| 732 |
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) |
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) |
| 733 |
{ |
{ |
| 734 |
TranslationBlock *tb; |
TranslationBlock *tb; |