--- trunk/src/cpus/cpu_mips_coproc.c 2007/10/08 16:20:10 26 +++ trunk/src/cpus/cpu_mips_coproc.c 2007/10/08 16:21:17 34 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2003-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_mips_coproc.c,v 1.37 2006/06/25 02:46:07 debug Exp $ + * $Id: cpu_mips_coproc.c,v 1.62 2007/02/03 16:18:56 debug Exp $ * * Emulation of MIPS coprocessors. */ @@ -45,6 +45,7 @@ #include "mips_cpu_types.h" #include "misc.h" #include "opcodes_mips.h" +#include "timer.h" #ifndef ENABLE_MIPS @@ -438,6 +439,23 @@ /* + * mips_timer_tick(): + */ +static void mips_timer_tick(struct timer *timer, void *extra) +{ + struct cpu *cpu = (struct cpu *) extra; + + cpu->cd.mips.compare_interrupts_pending ++; + + if ((int32_t) (cpu->cd.mips.coproc[0]->reg[COP0_COUNT] - + cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]) < 0) { + cpu->cd.mips.coproc[0]->reg[COP0_COUNT] = + cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]; + } +} + + +/* * mips_coproc_tlb_set_entry(): * * Used by machine setup code, if a specific machine emulation starts up @@ -533,8 +551,46 @@ INVALIDATE_VADDR); } } else { - /* TODO: Implement support for other. */ - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); + int non4kpages = 0; + uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL; + + if (cpu->is_32bit) { + topbit = 0x80000000; + fillmask = 0xffffffff00000000ULL; + } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { + topbit <<= 43; + fillmask <<= 4; + } else { + topbit <<= 39; + } + + for (i=0; itlbs[i].hi & ~fillmask; + if (vaddr0 & topbit) + vaddr0 |= fillmask; + vaddr1 = vaddr0 | 0x1000; /* TODO: mask */ + + if (tlb[i].lo0 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, + vaddr0, INVALIDATE_VADDR); + if (tlb[i].lo1 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, + vaddr1, INVALIDATE_VADDR); + } + } + + if (non4kpages) { + cpu->invalidate_translation_caches(cpu, + 0, INVALIDATE_ALL); + } } } @@ -557,7 +613,11 @@ if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_WIRED) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR) unimpl = 0; - if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) unimpl = 0; + if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) { + /* TODO: Increase count in a more meaningful way! */ + cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1); + unimpl = 0; + } if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE) unimpl = 0; if (cp->coproc_nr==0 && reg_nr==COP0_STATUS) unimpl = 0; @@ -715,13 +775,49 @@ unimpl = 0; break; case COP0_COMPARE: - /* Clear the timer interrupt bit (bit 7): */ - cpu->cd.mips.compare_register_set = 1; - mips_cpu_interrupt_ack(cpu, 7); + if (cpu->machine->emulated_hz > 0) { + int32_t compare_diff = tmp - + cp->reg[COP0_COMPARE]; + double hz; + + if (compare_diff < 0) + hz = tmp - cp->reg[COP0_COUNT]; + + if (compare_diff == 0) + hz = 0; + else + hz = (double)cpu->machine->emulated_hz + / (double)compare_diff; +/* + * TODO: DON'T HARDCODE THIS! + */ +hz = 100.0; + + /* Initialize or re-set the periodic timer: */ + if (hz > 0) { + if (cpu->cd.mips.timer == NULL) + cpu->cd.mips.timer = timer_add( + hz, mips_timer_tick, cpu); + else + timer_update_frequency( + cpu->cd.mips.timer, hz); + } + } + + /* Ack the periodic timer, if it was asserted: */ + if (cp->reg[COP0_CAUSE] & 0x8000 && + cpu->cd.mips.compare_interrupts_pending > 0) + cpu->cd.mips.compare_interrupts_pending --; + + /* Clear the timer interrupt assertion (bit 7): */ + cp->reg[COP0_CAUSE] &= ~0x8000; + if (tmp != (uint64_t)(int64_t)(int32_t)tmp) fatal("WARNING: trying to write a 64-bit value" " to the COMPARE register!\n"); + tmp = (int64_t)(int32_t)tmp; + cpu->cd.mips.compare_register_set = 1; unimpl = 0; break; case COP0_ENTRYHI: @@ -821,15 +917,6 @@ cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); } - -#if 1 - /* - * NOTE: This is not needed for NetBSD, but - * Ultrix and Linux still needs this. They - * shouldn't, though. Something else is buggy. - */ - cpu_create_or_reset_tc(cpu); -#endif } unimpl = 0; break; @@ -1175,7 +1262,7 @@ /* bc1f, bc1t, bc1fl, bc1tl: */ if ((function & 0x03e00000) == 0x01000000) { - int nd, tf, imm, cond_true; + int nd, tf, imm; char *instr_mnem; /* cc are bits 20..18: */ @@ -1198,36 +1285,10 @@ if (unassemble_only) return 1; - if (cpu->delay_slot) { - fatal("%s: jump inside a jump's delay slot, " - "or similar. TODO\n", instr_mnem); - cpu->running = 0; - return 1; - } - - /* Both the FCCR and FCSR contain condition code bits... */ - if (cc == 0) - cond_true = (cp->fcr[MIPS_FPU_FCSR] >> - MIPS_FCSR_FCC0_SHIFT) & 1; - else - cond_true = (cp->fcr[MIPS_FPU_FCSR] >> - (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1; - - if (!tf) - cond_true = !cond_true; - - if (cond_true) { - cpu->delay_slot = TO_BE_DELAYED; - cpu->delay_jmpaddr = cpu->pc + (imm << 2); - } else { - /* "likely": */ - if (nd) { - /* nullify the delay slot */ - cpu->cd.mips.nullify_next = 1; - } - } - - return 1; + fatal("INTERNAL ERROR: MIPS coprocessor branches should not" + " be implemented in cpu_mips_coproc.c, but in" + " cpu_mips_instr.c!\n"); + exit(1); } /* add.fmt: Floating-point add */ @@ -1441,19 +1502,13 @@ R2K3K_INDEX_SHIFT; if (i >= cp->nr_of_tlbs) { /* TODO: exception? */ - fatal("warning: tlbr from index %i (too " - "high)\n", i); + fatal("[ warning: tlbr from index %i (too " + "high) ]\n", i); return; } - /* - * TODO: Hm. Earlier I had an & ~0x3f on the high - * assignment and an & ~0xff on the lo0 assignment. - * I wonder why. - */ - - cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; /* & ~0x3f; */ - cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */ + cp->reg[COP0_ENTRYHI] = cp->tlbs[i].hi; + cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0; } else { /* R4000: */ i = cp->reg[COP0_INDEX] & INDEX_MASK; @@ -1550,16 +1605,17 @@ void coproc_tlbwri(struct cpu *cpu, int randomflag) { struct mips_coproc *cp = cpu->cd.mips.coproc[0]; - int index, g_bit, old_asid = -1; + int index, g_bit; uint64_t oldvaddr; if (randomflag) { if (cpu->cd.mips.cpu_type.exc_model == EXC3K) { - cp->reg[COP0_RANDOM] = - ((random() % (cp->nr_of_tlbs - 8)) + 8) - << R2K3K_RANDOM_SHIFT; - index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) - >> R2K3K_RANDOM_SHIFT; + index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) + >> R2K3K_RANDOM_SHIFT) - 1; + /* R3000 always has 8 wired entries: */ + if (index < 8) + index = cp->nr_of_tlbs - 1; + cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT; } else { cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random() % (cp->nr_of_tlbs - cp->reg[COP0_WIRED])); @@ -1606,53 +1662,58 @@ /* * Any virtual address translation for the old TLB entry must be * invalidated first: + * + * (Only Valid entries need to be invalidated, and only those that + * are either Global, or have the same ASID as the new entry will + * have. No other address translations should be active anyway.) */ switch (cpu->cd.mips.cpu_type.mmu_model) { case MMU3K: oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK; - oldvaddr &= 0xffffffffULL; - if (oldvaddr & 0x80000000ULL) - oldvaddr |= 0xffffffff00000000ULL; - old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) - >> R2K3K_ENTRYHI_ASID_SHIFT; + oldvaddr = (int32_t) oldvaddr; + + if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V && + (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G || + (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) == + (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) )) + cpu->invalidate_translation_caches(cpu, oldvaddr, + INVALIDATE_VADDR); - cpu->invalidate_translation_caches(cpu, oldvaddr, - INVALIDATE_VADDR); break; default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { - oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K; + oldvaddr = cp->tlbs[index].hi & + (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK); /* 44 addressable bits: */ if (oldvaddr & 0x80000000000ULL) - oldvaddr |= 0xfffff00000000000ULL; + oldvaddr |= 0x3ffff00000000000ULL; } else if (cpu->is_32bit) { /* MIPS32 etc.: */ oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; oldvaddr = (int32_t)oldvaddr; } else { /* Assume MMU4K */ - oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; + oldvaddr = cp->tlbs[index].hi & + (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK); /* 40 addressable bits: */ if (oldvaddr & 0x8000000000ULL) - oldvaddr |= 0xffffff0000000000ULL; + oldvaddr |= 0x3fffff0000000000ULL; } -#if 1 - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); -#else /* * TODO: non-4KB page sizes! */ - cpu->invalidate_translation_caches(cpu, oldvaddr, - INVALIDATE_VADDR); - cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000, - INVALIDATE_VADDR); -#endif + if (cp->tlbs[index].lo0 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, oldvaddr, + INVALIDATE_VADDR); + if (cp->tlbs[index].lo1 & ENTRYLO_V) + cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000, + INVALIDATE_VADDR); } - +#if 0 /* * Check for duplicate entries. (There should not be two mappings * from one virtual address to physical addresses.) @@ -1667,7 +1728,8 @@ int i; unsigned int asid; - vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K; + vaddr1 = cp->reg[COP0_ENTRYHI] & + (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID; /* Since this is just a warning, it's probably not necessary to use R4000 masks etc. */ @@ -1680,7 +1742,8 @@ (cp->tlbs[i].hi & ENTRYHI_ASID) != asid) continue; - vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K; + vaddr2 = cp->tlbs[i].hi & + (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 & ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V))) fatal("\n[ WARNING! tlbw%s to index 0x%02x " @@ -1690,7 +1753,7 @@ (long long)vaddr1, asid, i); } } - +#endif /* Write the new entry: */ @@ -1714,93 +1777,143 @@ INVALIDATE_PADDR); } + /* Set new last_written_tlb_index hint: */ + cpu->cd.mips.last_written_tlb_index = index; + + if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) { + fatal("Wow! Interesting case; tlbw* while caches" + " are isolated. TODO\n"); + /* Don't update the translation table in this + case... */ + exit(1); + } + /* If we have a memblock (host page) for the physical page, then add a translation for it immediately: */ if (memblock != NULL && - cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) { - memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1)); + cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) cpu->update_translation_table(cpu, vaddr, memblock, wf, paddr); - } } else { - /* R4000: */ - g_bit = (cp->reg[COP0_ENTRYLO0] & - cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G; + /* R4000 etc.: */ + unsigned char *memblock = NULL; + int pfn_shift = 12, vpn_shift = 12; + int wf0, wf1, mask; + uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp; + cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK]; cp->tlbs[index].hi = cp->reg[COP0_ENTRYHI]; cp->tlbs[index].lo1 = cp->reg[COP0_ENTRYLO1]; cp->tlbs[index].lo0 = cp->reg[COP0_ENTRYLO0]; + wf0 = cp->tlbs[index].lo0 & ENTRYLO_D; + wf1 = cp->tlbs[index].lo1 & ENTRYLO_D; + + mask = cp->reg[COP0_PAGEMASK]; if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { - /* NOTE: The VR4131 (and possibly others) don't have - a Global bit in entryhi */ - cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK]; + pfn_shift = 10; + mask |= 0x07ff; } else { - cp->tlbs[index].lo0 &= ~ENTRYLO_G; - cp->tlbs[index].lo1 &= ~ENTRYLO_G; - - cp->tlbs[index].hi &= ~TLB_G; - if (g_bit) - cp->tlbs[index].hi |= TLB_G; + mask |= 0x1fff; } - - /* Invalidate any code translations, if we are writing - Dirty pages to the TLB: */ - if (cp->reg[COP0_PAGEMASK] != 0 && - cp->reg[COP0_PAGEMASK] != 0x1800) { - printf("TODO: MASK = %08"PRIx32"\n", - (uint32_t)cp->reg[COP0_PAGEMASK]); + switch (mask) { + case 0x00007ff: + if (cp->tlbs[index].lo0 & ENTRYLO_V || + cp->tlbs[index].lo1 & ENTRYLO_V) { + fatal("1KB pages don't work with dyntrans.\n"); + exit(1); + } + vpn_shift = 10; + break; + case 0x0001fff: break; + case 0x0007fff: vpn_shift = 14; break; + case 0x001ffff: vpn_shift = 16; break; + case 0x007ffff: vpn_shift = 18; break; + case 0x01fffff: vpn_shift = 20; break; + case 0x07fffff: vpn_shift = 22; break; + case 0x1ffffff: vpn_shift = 24; break; + case 0x7ffffff: vpn_shift = 26; break; + default:fatal("Unimplemented MASK = 0x%016x\n", mask); exit(1); } - if (cp->tlbs[index].lo0 & ENTRYLO_D) - cpu->invalidate_code_translation(cpu, - ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK) - >> ENTRYLO_PFN_SHIFT) << 12, - INVALIDATE_PADDR); - if (cp->tlbs[index].lo1 & ENTRYLO_D) - cpu->invalidate_code_translation(cpu, - ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK) - >> ENTRYLO_PFN_SHIFT) << 12, - INVALIDATE_PADDR); - -#if 1 - if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { - oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K; + paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK) + >> ENTRYLO_PFN_SHIFT) << pfn_shift; + paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK) + >> ENTRYLO_PFN_SHIFT) << pfn_shift; + + if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { + vaddr0 = cp->tlbs[index].hi & + (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K); /* 44 addressable bits: */ - if (oldvaddr & 0x80000000000ULL) - oldvaddr |= 0xfffff00000000000ULL; + if (vaddr0 & 0x80000000000ULL) + vaddr0 |= 0x3ffff00000000000ULL; } else if (cpu->is_32bit) { /* MIPS32 etc.: */ - oldvaddr = (int32_t)oldvaddr; + vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; + vaddr0 = (int32_t)vaddr0; } else { /* Assume MMU4K */ - oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK; + vaddr0 = cp->tlbs[index].hi & + (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK); /* 40 addressable bits: */ - if (oldvaddr & 0x8000000000ULL) - oldvaddr |= 0xffffff0000000000ULL; + if (vaddr0 & 0x8000000000ULL) + vaddr0 |= 0x3fffff0000000000ULL; } -cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo0 & -ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR); -cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo1 & -ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR); + vaddr1 = vaddr0 | (1 << vpn_shift); -#endif - } -} + g_bit = (cp->reg[COP0_ENTRYLO0] & + cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G; + if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { + /* NOTE: The VR4131 (and possibly others) don't have + a Global bit in entryhi */ + cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK]; + } else { + cp->tlbs[index].lo0 &= ~ENTRYLO_G; + cp->tlbs[index].lo1 &= ~ENTRYLO_G; -/* - * coproc_rfe(): - * - * Return from exception. (R3000 etc.) - */ -void coproc_rfe(struct cpu *cpu) -{ - cpu->cd.mips.coproc[0]->reg[COP0_STATUS] = - (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) | - ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2); + cp->tlbs[index].hi &= ~TLB_G; + if (g_bit) + cp->tlbs[index].hi |= TLB_G; + } + + /* + * Invalidate any code translations, if we are writing Dirty + * pages to the TLB: (TODO: 4KB hardcoded... ugly) + */ + for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) { + if (wf0) + cpu->invalidate_code_translation(cpu, + paddr0 + ptmp, INVALIDATE_PADDR); + if (wf1) + cpu->invalidate_code_translation(cpu, + paddr1 + ptmp, INVALIDATE_PADDR); + } + + /* + * If we have a memblock (host page) for the physical page, + * then add a translation for it immediately, to save some + * time. (It would otherwise be added later on anyway, + * because of a translation miss.) + * + * NOTE/TODO: This is only for 4KB pages so far. It would + * be too expensive to add e.g. 16MB pages like + * this. + */ + memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0); + if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V) + cpu->update_translation_table(cpu, vaddr0, memblock, + wf0, paddr0); + memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0); + if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V) + cpu->update_translation_table(cpu, vaddr1, memblock, + wf1, paddr1); + + /* Set new last_written_tlb_index hint: */ + cpu->cd.mips.last_written_tlb_index = index; + } } @@ -2022,106 +2135,73 @@ /* TLB operations and other things: */ if (cp->coproc_nr == 0) { + if (!unassemble_only) { + fatal("FATAL INTERNAL ERROR: Should be implemented" + " with dyntrans instead.\n"); + exit(1); + } + op = (function) & 0xff; switch (co_bit) { case 1: switch (op) { case COP0_TLBR: /* Read indexed TLB entry */ - if (unassemble_only) { - debug("tlbr\n"); - return; - } - coproc_tlbpr(cpu, 1); + debug("tlbr\n"); return; case COP0_TLBWI: /* Write indexed */ case COP0_TLBWR: /* Write random */ - if (unassemble_only) { - if (op == COP0_TLBWI) - debug("tlbwi"); - else - debug("tlbwr"); - if (!running) { - debug("\n"); - return; - } - debug("\tindex=%08llx", - (long long)cp->reg[COP0_INDEX]); - debug(", random=%08llx", - (long long)cp->reg[COP0_RANDOM]); - debug(", mask=%016llx", - (long long)cp->reg[COP0_PAGEMASK]); - debug(", hi=%016llx", - (long long)cp->reg[COP0_ENTRYHI]); - debug(", lo0=%016llx", - (long long)cp->reg[COP0_ENTRYLO0]); - debug(", lo1=%016llx\n", - (long long)cp->reg[COP0_ENTRYLO1]); + if (op == COP0_TLBWI) + debug("tlbwi"); + else + debug("tlbwr"); + if (!running) { + debug("\n"); return; } - coproc_tlbwri(cpu, op == COP0_TLBWR); + debug("\tindex=%08llx", + (long long)cp->reg[COP0_INDEX]); + debug(", random=%08llx", + (long long)cp->reg[COP0_RANDOM]); + debug(", mask=%016llx", + (long long)cp->reg[COP0_PAGEMASK]); + debug(", hi=%016llx", + (long long)cp->reg[COP0_ENTRYHI]); + debug(", lo0=%016llx", + (long long)cp->reg[COP0_ENTRYLO0]); + debug(", lo1=%016llx\n", + (long long)cp->reg[COP0_ENTRYLO1]); return; case COP0_TLBP: /* Probe TLB for matching entry */ - if (unassemble_only) { - debug("tlbp\n"); - return; - } - coproc_tlbpr(cpu, 0); + debug("tlbp\n"); return; case COP0_RFE: /* R2000/R3000 only: Return from Exception */ - if (unassemble_only) { - debug("rfe\n"); - return; - } - coproc_rfe(cpu); + debug("rfe\n"); return; case COP0_ERET: /* R4000: Return from exception */ - if (unassemble_only) { - debug("eret\n"); - return; - } - coproc_eret(cpu); + debug("eret\n"); return; case COP0_DERET: - if (unassemble_only) { - debug("deret\n"); - return; + debug("deret\n"); + return; + case COP0_WAIT: + { + int code = (function >> 6) & 0x7ffff; + debug("wait"); + if (code > 0) + debug("\t0x%x", code); + debug("\n"); } - /* - * According to the MIPS64 manual, deret - * loads PC from the DEPC cop0 register, and - * jumps there immediately. No delay slot. - * - * TODO: This instruction is only available - * if the processor is in debug mode. (What - * does that mean?) TODO: This instruction - * is undefined in a delay slot. - */ - cpu->pc = cp->reg[COP0_DEPC]; - cpu->delay_slot = 0; - cp->reg[COP0_STATUS] &= ~STATUS_EXL; return; case COP0_STANDBY: - if (unassemble_only) { - debug("standby\n"); - return; - } - /* TODO: Hm. Do something here? */ + debug("standby\n"); return; case COP0_SUSPEND: - if (unassemble_only) { - debug("suspend\n"); - return; - } - /* TODO: Hm. Do something here? */ + debug("suspend\n"); return; case COP0_HIBERNATE: - if (unassemble_only) { - debug("hibernate\n"); - return; - } - /* TODO: Hm. Do something here? */ + debug("hibernate\n"); return; default: ; @@ -2141,17 +2221,6 @@ return; } - /* TODO: RM5200 idle (?) */ - if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) { - if (unassemble_only) { - debug("idle(?)\n"); /* TODO */ - return; - } - - /* Idle? TODO */ - return; - } - if (unassemble_only) { debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function); return;