--- trunk/src/cpu_mips.c 2007/10/08 16:18:31 11 +++ trunk/src/cpu_mips.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_mips.c,v 1.46 2005/06/26 22:23:42 debug Exp $ + * $Id: cpu_mips.c,v 1.61 2005/08/07 19:12:12 debug Exp $ * * MIPS core CPU emulation. */ @@ -95,7 +95,6 @@ static char *regnames[] = MIPS_REGISTER_NAMES; static char *cop0_names[] = COP0_NAMES; - #include "cpu_mips16.c" @@ -157,7 +156,14 @@ cpu->cd.mips.cpu_type = cpu_type_defs[found]; cpu->name = cpu->cd.mips.cpu_type.name; cpu->byte_order = EMUL_LITTLE_ENDIAN; - cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER; + cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER; + cpu->update_translation_table = mips_update_translation_table; + cpu->invalidate_translation_caches_paddr = + mips_invalidate_translation_caches_paddr; + + if (cpu->cd.mips.cpu_type.isa_level <= 2 || + cpu->cd.mips.cpu_type.isa_level == 32) + cpu->is_32bit = 1; if (cpu_id == 0) debug("%s", cpu->cd.mips.cpu_type.name); @@ -175,35 +181,35 @@ */ x = DEFAULT_PCACHE_SIZE; - if (cpu->cd.mips.cpu_type.default_pdcache) - x = cpu->cd.mips.cpu_type.default_pdcache; + if (cpu->cd.mips.cpu_type.pdcache) + x = cpu->cd.mips.cpu_type.pdcache; if (machine->cache_pdcache == 0) machine->cache_pdcache = x; x = DEFAULT_PCACHE_SIZE; - if (cpu->cd.mips.cpu_type.default_picache) - x = cpu->cd.mips.cpu_type.default_picache; + if (cpu->cd.mips.cpu_type.picache) + x = cpu->cd.mips.cpu_type.picache; if (machine->cache_picache == 0) machine->cache_picache = x; if (machine->cache_secondary == 0) - machine->cache_secondary = cpu->cd.mips.cpu_type.default_scache; + machine->cache_secondary = cpu->cd.mips.cpu_type.scache; linesize = DEFAULT_PCACHE_LINESIZE; - if (cpu->cd.mips.cpu_type.default_pdlinesize) - linesize = cpu->cd.mips.cpu_type.default_pdlinesize; + if (cpu->cd.mips.cpu_type.pdlinesize) + linesize = cpu->cd.mips.cpu_type.pdlinesize; if (machine->cache_pdcache_linesize == 0) machine->cache_pdcache_linesize = linesize; linesize = DEFAULT_PCACHE_LINESIZE; - if (cpu->cd.mips.cpu_type.default_pilinesize) - linesize = cpu->cd.mips.cpu_type.default_pilinesize; + if (cpu->cd.mips.cpu_type.pilinesize) + linesize = cpu->cd.mips.cpu_type.pilinesize; if (machine->cache_picache_linesize == 0) machine->cache_picache_linesize = linesize; linesize = 0; - if (cpu->cd.mips.cpu_type.default_slinesize) - linesize = cpu->cd.mips.cpu_type.default_slinesize; + if (cpu->cd.mips.cpu_type.slinesize) + linesize = cpu->cd.mips.cpu_type.slinesize; if (machine->cache_secondary_linesize == 0) machine->cache_secondary_linesize = linesize; @@ -329,6 +335,14 @@ cpu->translate_address = translate_address_generic; } +/* Testing: */ + cpu->cd.mips.host_load = zeroed_alloc(1048576 * + sizeof(unsigned char *)); + cpu->cd.mips.host_store = zeroed_alloc(1048576 * + sizeof(unsigned char *)); + cpu->cd.mips.host_load_orig = cpu->cd.mips.host_load; + cpu->cd.mips.host_store_orig = cpu->cd.mips.host_store; + return 1; } @@ -473,15 +487,20 @@ printf("\n"); break; default: - /* TODO: MIPS32 doesn't need 0x16llx */ - if (m->cpus[i]->cd.mips.cpu_type.mmu_model == MMU10K) + switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { + case MMU10K: printf("vaddr=0x%1x..%011llx ", (int) (hi >> 60), (long long) (hi&ENTRYHI_VPN2_MASK_R10K)); - else + break; + case MMU32: + printf("vaddr=0x%08x ", (int)(hi&ENTRYHI_VPN2_MASK)); + break; + default:/* R4000 etc. */ printf("vaddr=0x%1x..%010llx ", (int) (hi >> 60), (long long) (hi&ENTRYHI_VPN2_MASK)); + } if (hi & TLB_G) printf("(global): "); else @@ -533,8 +552,7 @@ /* Print index, random, and wired: */ printf("cpu%i: (", i); - if (m->cpus[i]->cd.mips.cpu_type.isa_level < 3 || - m->cpus[i]->cd.mips.cpu_type.isa_level == 32) + if (m->cpus[i]->is_32bit) printf("index=0x%08x random=0x%08x", (int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], (int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_RANDOM]); @@ -556,8 +574,7 @@ j, (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); - else if (m->cpus[i]->cd.mips.cpu_type.isa_level < 3 || - m->cpus[i]->cd.mips.cpu_type.isa_level == 32) + else if (m->cpus[i]->is_32bit) printf("%3i: hi=0x%08x mask=0x%08x " "lo0=0x%08x lo1=0x%08x\n", j, (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, @@ -727,8 +744,7 @@ if (cpu->machine->ncpus > 1 && running) debug("cpu%i: ", cpu->cpu_id); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) debug("%08x", (int)dumpaddr); else debug("%016llx", (long long)dumpaddr); @@ -928,8 +944,12 @@ debug("syscall"); break; case SPECIAL_BREAK: - /* TODO: imm, as in 'syscall'? */ - debug("break"); + imm = (((instr[3] << 24) + (instr[2] << 16) + + (instr[1] << 8) + instr[0]) >> 6) & 0xfffff; + if (imm != 0) + debug("break\t0x%05x", imm); + else + debug("break"); break; case SPECIAL_MFSA: rd = (instr[1] >> 3) & 31; @@ -969,8 +989,7 @@ debug("%s,", regname(cpu->machine, rs)); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) debug("0x%08x", (int)addr); else debug("0x%016llx", (long long)addr); @@ -1050,8 +1069,8 @@ cpu->cd.mips.gpr[rs] + imm, &offset); /* LWC3 is PREF in the newer ISA levels: */ - /* TODO: Which ISAs? cpu->cd.mips.cpu_type.isa_level >= 4? */ - if (hi6 == HI6_LWC3) { + /* TODO: Which ISAs? IV? V? 32? 64? */ + if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) { debug("pref\t0x%x,%i(%s)", rt, imm, regname(cpu->machine, rs)); @@ -1080,8 +1099,7 @@ if (running) { debug("\t["); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) debug("0x%08x", (int)(cpu->cd.mips.gpr[rs] + imm)); else debug("0x%016llx", @@ -1105,8 +1123,7 @@ symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); debug("%s\t0x", hi6_names[hi6]); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) debug("%08x", (int)addr); else debug("%016llx", (long long)addr); @@ -1234,8 +1251,7 @@ addr = (dumpaddr + 4) + (imm << 2); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) debug("0x%08x", (int)addr); else debug("0x%016llx", (long long)addr); @@ -1268,8 +1284,7 @@ uint64_t offset; char *symbol; - bits32 = (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32)? 1 : 0; + bits32 = cpu->is_32bit; if (gprs) { /* Special registers (pc, hi/lo) first: */ @@ -1279,7 +1294,7 @@ if (bits32) debug("cpu%i: pc = %08x", cpu->cpu_id, (int)cpu->pc); else - debug("cpu%i: pc = %016llx", + debug("cpu%i: pc = 0x%016llx", cpu->cpu_id, (long long)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : @@ -1289,7 +1304,7 @@ debug("cpu%i: hi = %08x lo = %08x\n", cpu->cpu_id, (int)cpu->cd.mips.hi, (int)cpu->cd.mips.lo); else - debug("cpu%i: hi = %016llx lo = %016llx\n", + debug("cpu%i: hi = 0x%016llx lo = 0x%016llx\n", cpu->cpu_id, (long long)cpu->cd.mips.hi, (long long)cpu->cd.mips.lo); @@ -1311,19 +1326,23 @@ for (i=0; i<32; i++) { if ((i & 3) == 0) debug("cpu%i:", cpu->cpu_id); - debug(" %3s = %08x", regname(cpu->machine, i), - (int)cpu->cd.mips.gpr[i]); + if (i == MIPS_GPR_ZERO) + debug(" "); + else + debug(" %3s = %08x", regname(cpu->machine, i), (int)cpu->cd.mips.gpr[i]); if ((i & 3) == 3) debug("\n"); } } else { /* 64-bit: */ for (i=0; i<32; i++) { + int r = (i >> 1) + ((i & 1) << 4); if ((i & 1) == 0) debug("cpu%i:", cpu->cpu_id); - debug(" %3s = %016llx", - regname(cpu->machine, i), - (long long)cpu->cd.mips.gpr[i]); + if (r == MIPS_GPR_ZERO) + debug(" "); + else + debug(" %3s = 0x%016llx", regname(cpu->machine, r), (long long)cpu->cd.mips.gpr[r]); if ((i & 1) == 1) debug("\n"); } @@ -1359,9 +1378,15 @@ if (bits32) debug("=%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); - else - debug(" = 0x%016llx", (long long) - cpu->cd.mips.coproc[coprocnr]->reg[i]); + else { + if (coprocnr == 0 && (i == COP0_COUNT + || i == COP0_COMPARE || i == COP0_INDEX + || i == COP0_RANDOM || i == COP0_WIRED)) + debug(" = 0x%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); + else + debug(" = 0x%016llx", (long long) + cpu->cd.mips.coproc[coprocnr]->reg[i]); + } if ((i & nm1) == nm1) debug("\n"); @@ -1372,6 +1397,16 @@ i = 31; } + if (coprocnr == 0 && cpu->cd.mips.cpu_type.isa_level >= 32) { + debug("cpu%i: ", cpu->cpu_id); + debug("config_select1 = 0x"); + if (cpu->is_32bit) + debug("%08x", (int)cpu->cd.mips.cop0_config_select1); + else + debug("%016llx", (long long)cpu->cd.mips.cop0_config_select1); + debug("\n"); + } + /* Floating point control registers: */ if (coprocnr == 1) { for (i=0; i<32; i++) @@ -1391,88 +1426,13 @@ } -/* - * show_trace(): - * - * Show trace tree. This function should be called every time - * a function is called. cpu->cd.mips.trace_tree_depth is increased here - * and should not be increased by the caller. - * - * Note: This function should not be called if show_trace_tree == 0. - */ -static void show_trace(struct cpu *cpu, uint64_t addr) -{ - uint64_t offset; - int x, n_args_to_print; - char strbuf[50]; - char *symbol; - - cpu->cd.mips.trace_tree_depth ++; - - if (cpu->machine->ncpus > 1) - debug("cpu%i:", cpu->cpu_id); - - symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); - - for (x=0; xcd.mips.trace_tree_depth; x++) - debug(" "); - - /* debug("<%s>\n", symbol!=NULL? symbol : "no symbol"); */ - - if (symbol != NULL) - debug("<%s(", symbol); - else { - debug("<0x"); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) - debug("%08x", (int)addr); - else - debug("%016llx", (long long)addr); - debug("("); - } - - /* - * TODO: The number of arguments and the symbol type of each - * argument should be taken from the symbol table, in some way. - * - * The MIPS binary calling convention is that the first 4 - * arguments are in registers a0..a3. - * - * Choose a value greater than 4 (eg 5) to print all values in - * the A0..A3 registers and then add a ".." to indicate that - * there might be more arguments. - */ - n_args_to_print = 5; - - for (x=0; xcd.mips.gpr[x + MIPS_GPR_A0]; - - if (d > -256 && d < 256) - debug("%i", (int)d); - else if (memory_points_to_string(cpu, cpu->mem, d, 1)) - debug("\"%s\"", memory_conv_to_string(cpu, - cpu->mem, d, strbuf, sizeof(strbuf))); - else { - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) - debug("0x%x", (int)d); - else - debug("0x%llx", (long long)d); - } - - if (x < n_args_to_print - 1) - debug(","); - - /* Cannot go beyound MIPS_GPR_A3: */ - if (x == 3) - break; - } - - if (n_args_to_print > 4) - debug(".."); - - debug(")>\n"); -} +#define DYNTRANS_FUNCTION_TRACE mips_cpu_functioncall_trace +#define DYNTRANS_MIPS +#define DYNTRANS_ARCH mips +#include "cpu_dyntrans.c" +#undef DYNTRANS_MIPS +#undef DYNTRANS_ARCH +#undef DYNTRANS_FUNCTION_TRACE /* @@ -1557,8 +1517,8 @@ if (!quiet_mode) { uint64_t offset; int x; - char *symbol = get_symbol_name( - &cpu->machine->symbol_context, cpu->cd.mips.pc_last, &offset); + char *symbol = get_symbol_name(&cpu->machine->symbol_context, + cpu->cd.mips.pc_last, &offset); debug("[ "); if (cpu->machine->ncpus > 1) @@ -1586,10 +1546,16 @@ } break; default: - debug(" vaddr=0x%016llx", (long long)vaddr); + if (cpu->is_32bit) + debug(" vaddr=0x%08x", (int)vaddr); + else + debug(" vaddr=0x%016llx", (long long)vaddr); } - debug(" pc=%08llx ", (long long)cpu->cd.mips.pc_last); + if (cpu->is_32bit) + debug(" pc=0x%08x ", (int)cpu->cd.mips.pc_last); + else + debug(" pc=0x%016llx ", (long long)cpu->cd.mips.pc_last); if (symbol != NULL) debug("<%s> ]\n", symbol); @@ -1604,10 +1570,17 @@ fatal("[ "); if (cpu->machine->ncpus > 1) fatal("cpu%i: ", cpu->cpu_id); - fatal("warning: LOW reference vaddr=0x%08llx, exception %s, " - "pc=%08llx <%s> ]\n", (long long)vaddr, - exception_names[exccode], (long long)cpu->cd.mips.pc_last, - symbol? symbol : "(no symbol)"); + fatal("warning: LOW reference: vaddr="); + if (cpu->is_32bit) + fatal("0x%08x", (int)vaddr); + else + fatal("0x%016llx", (long long)vaddr); + fatal(", exception %s, pc=", exception_names[exccode]); + if (cpu->is_32bit) + fatal("0x%08x", (int)cpu->cd.mips.pc_last); + else + fatal("0x%016llx", (long long)cpu->cd.mips.pc_last); + fatal(" <%s> ]\n", symbol? symbol : "(no symbol)"); #ifdef TRACE_NULL_CRASHES /* This can be useful for debugging kernel bugs: */ @@ -1626,16 +1599,9 @@ } /* Clear the exception code bits of the cause register... */ - if (exc_model == EXC3K) { + if (exc_model == EXC3K) reg[COP0_CAUSE] &= ~R2K3K_CAUSE_EXCCODE_MASK; -#if 0 - if (exccode >= 16) { - fatal("exccode = %i (there are only 16 exceptions on R3000 and lower)\n", exccode); - cpu->running = 0; - return; - } -#endif - } else + else reg[COP0_CAUSE] &= ~CAUSE_EXCCODE_MASK; /* ... and OR in the exception code: */ @@ -1645,17 +1611,6 @@ reg[COP0_CAUSE] &= ~CAUSE_CE_MASK; reg[COP0_CAUSE] |= (coproc_nr << CAUSE_CE_SHIFT); - /* TODO: On R4000, vaddr should NOT be set on bus errors!!! */ -#if 0 - if (exccode == EXCEPTION_DBE) { - reg[COP0_BADVADDR] = vaddr; - /* sign-extend vaddr, if it is 32-bit */ - if ((vaddr >> 32) == 0 && (vaddr & 0x80000000ULL)) - reg[COP0_BADVADDR] |= - 0xffffffff00000000ULL; - } -#endif - if (tlb || (exccode >= EXCEPTION_MOD && exccode <= EXCEPTION_ADES) || exccode == EXCEPTION_VCEI || exccode == EXCEPTION_VCED) { reg[COP0_BADVADDR] = vaddr; @@ -1919,8 +1874,7 @@ for (i=0; imachine->n_breakpoints; i++) if (cached_pc == cpu->machine->breakpoint_addr[i]) { fatal("Breakpoint reached, pc=0x"); - if (cpu->cd.mips.cpu_type.isa_level < 3 || - cpu->cd.mips.cpu_type.isa_level == 32) + if (cpu->is_32bit) fatal("%08x", (int)cached_pc); else fatal("%016llx", (long long)cached_pc); @@ -2022,9 +1976,8 @@ /* no need to update cached_pc, as we're returning */ cpu->cd.mips.delay_slot = NOT_DELAYED; - if (!quiet_mode_cached && - cpu->machine->show_trace_tree) - cpu->cd.mips.trace_tree_depth --; + if (cpu->machine->show_trace_tree) + cpu_functioncall_trace_return(cpu); /* TODO: how many instrs should this count as? */ return 10; @@ -2037,7 +1990,7 @@ * registers are sign-extended: (Slow, but might be useful * to detect bugs that have to do with sign-extension.) */ - if (cpu->cd.mips.cpu_type.isa_level < 3 || cpu->cd.mips.cpu_type.isa_level == 32) { + if (cpu->is_32bit) int warning = 0; uint64_t x; @@ -2130,28 +2083,25 @@ } #endif - - #ifdef BINTRANS if ((single_step || instruction_trace_cached) && cpu->machine->bintrans_enable) cpu->cd.mips.dont_run_next_bintrans = 1; #endif - if (!quiet_mode_cached) { /* Dump CPU registers for debugging: */ if (cpu->machine->register_dump) { debug("\n"); mips_cpu_register_dump(cpu, 1, 0x1); } + } - /* Trace tree: */ - if (cpu->machine->show_trace_tree && cpu->cd.mips.show_trace_delay > 0) { - cpu->cd.mips.show_trace_delay --; - if (cpu->cd.mips.show_trace_delay == 0) - show_trace(cpu, cpu->cd.mips.show_trace_addr); - } + /* Trace tree: */ + if (cpu->machine->show_trace_tree && cpu->cd.mips.show_trace_delay > 0) { + cpu->cd.mips.show_trace_delay --; + if (cpu->cd.mips.show_trace_delay == 0) + cpu_functioncall_trace(cpu, cpu->cd.mips.show_trace_addr); } #ifdef MFHILO_DELAY @@ -2248,7 +2198,7 @@ /* NOTE: This only works on the host if offset is aligned correctly! (TODO) */ *(uint32_t *)instr = *(uint32_t *) - (cpu->cd.mips.pc_last_host_4k_page + (cached_pc & 0xfff)); + (cpu->cd.mips.pc_last_host_4k_page + (cached_pc & 0xffc)); #ifdef BINTRANS cpu->cd.mips.pc_bintrans_paddr_valid = 1; cpu->cd.mips.pc_bintrans_paddr = @@ -2318,10 +2268,8 @@ * swap if necessary: */ if (cpu->byte_order == EMUL_BIG_ENDIAN) { - instrword = instr[0]; instr[0] = instr[3]; - instr[3] = instrword; - instrword = instr[1]; instr[1] = instr[2]; - instr[2] = instrword; + int tmp = instr[0]; instr[0] = instr[3]; instr[3] = tmp; + tmp = instr[1]; instr[1] = instr[2]; instr[2] = tmp; } } @@ -2527,10 +2475,8 @@ cpu->cd.mips.delay_slot = TO_BE_DELAYED; cpu->cd.mips.delay_jmpaddr = cpu->cd.mips.gpr[rs]; - if (!quiet_mode_cached && cpu->machine->show_trace_tree - && rs == 31) { - cpu->cd.mips.trace_tree_depth --; - } + if (cpu->machine->show_trace_tree && rs == 31) + cpu_functioncall_trace_return(cpu); return 1; case SPECIAL_JALR: @@ -2547,8 +2493,7 @@ cpu->cd.mips.gpr[rd] = cached_pc + 4; /* already increased by 4 earlier */ - if (!quiet_mode_cached && cpu->machine->show_trace_tree - && rd == 31) { + if (cpu->machine->show_trace_tree && rd == 31) { cpu->cd.mips.show_trace_delay = 2; cpu->cd.mips.show_trace_addr = tmpvalue; } @@ -2769,28 +2714,73 @@ cpu->cd.mips.hi |= 0xffffffff00000000ULL; break; } - /* - * TODO: I'm too tired to think now. DMULT is probably - * correct, but is DMULTU? (Unsigned 64x64 multiply.) - * Or, hm, perhaps it is dmult which is incorrect. - */ - if (special6 == SPECIAL_DMULT || special6 == SPECIAL_DMULTU) { - /* 64x64 = 128 bit multiplication: SLOW!!! TODO */ - uint64_t i, low_add, high_add; + if (special6 == SPECIAL_DMULT) { + /* 64x64 = 128 bit multiplication, signed. */ + uint64_t s1 = cpu->cd.mips.gpr[rt]; + uint64_t s2 = cpu->cd.mips.gpr[rs]; + int n_negative = 0; + int i; + + if ((int64_t)s1 < 0) { + s1 = -(int64_t)s1; + n_negative ++; + } + if ((int64_t)s2 < 0) { + s2 = -(int64_t)s2; + n_negative ++; + } cpu->cd.mips.lo = cpu->cd.mips.hi = 0; + for (i=0; i<64; i++) { - uint64_t bit = cpu->cd.mips.gpr[rt] & ((uint64_t)1 << i); + int bit = (s1 & 0x8000000000000000ULL)? 1 : 0; + s1 <<= 1; + /* If bit in s1 set, then add s2 to hi/lo: */ if (bit) { - /* Add cpu->cd.mips.gpr[rs] to hi and lo: */ - low_add = (cpu->cd.mips.gpr[rs] << i); - high_add = (cpu->cd.mips.gpr[rs] >> (64-i)); - if (i==0) /* WEIRD BUG in the compiler? Or maybe I'm just stupid */ - high_add = 0; /* these lines are necessary, a >> 64 doesn't seem to do anything */ - if (cpu->cd.mips.lo + low_add < cpu->cd.mips.lo) + uint64_t old_lo = cpu->cd.mips.lo; + cpu->cd.mips.lo += s2; + if (cpu->cd.mips.lo < old_lo) cpu->cd.mips.hi ++; - cpu->cd.mips.lo += low_add; - cpu->cd.mips.hi += high_add; + } + if (i != 63) { + cpu->cd.mips.hi <<= 1; + cpu->cd.mips.hi += + (cpu->cd.mips.lo & 0x8000000000000000ULL) ? 1 : 0; + cpu->cd.mips.lo <<= 1; + } + } + + if (n_negative == 1) { + cpu->cd.mips.hi = -(int64_t)cpu->cd.mips.hi; + cpu->cd.mips.lo = -(int64_t)cpu->cd.mips.lo; + if ((int64_t)cpu->cd.mips.lo < 0) + cpu->cd.mips.hi --; + } + break; + } + if (special6 == SPECIAL_DMULTU) { + /* 64x64 = 128 bit multiplication, unsigned. */ + uint64_t s1 = cpu->cd.mips.gpr[rt]; + uint64_t s2 = cpu->cd.mips.gpr[rs]; + int i; + + cpu->cd.mips.lo = cpu->cd.mips.hi = 0; + + for (i=0; i<64; i++) { + int bit = (s1 & 0x8000000000000000ULL)? 1 : 0; + s1 <<= 1; + /* If bit in s1 set, then add s2 to hi/lo: */ + if (bit) { + uint64_t old_lo = cpu->cd.mips.lo; + cpu->cd.mips.lo += s2; + if (cpu->cd.mips.lo < old_lo) + cpu->cd.mips.hi ++; + } + if (i != 63) { + cpu->cd.mips.hi <<= 1; + cpu->cd.mips.hi += + (cpu->cd.mips.lo & 0x8000000000000000ULL) ? 1 : 0; + cpu->cd.mips.lo <<= 1; } } break; @@ -2920,7 +2910,7 @@ } return 1; case SPECIAL_SYNC: - imm = ((instr[1] & 7) << 2) + (instr[0] >> 6); + /* imm = ((instr[1] & 7) << 2) + (instr[0] >> 6); */ /* TODO: actually sync */ /* Clear the LLbit (at least on R10000): */ @@ -2941,19 +2931,19 @@ mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0); return 1; case SPECIAL_MFSA: - /* R5900? What on earth does this thing do? */ - rd = (instr[1] >> 3) & 31; + /* R5900? Move from shift amount register? */ + /* rd = (instr[1] >> 3) & 31; */ /* TODO */ return 1; case SPECIAL_MTSA: - /* R5900? What on earth does this thing do? */ - rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); + /* R5900? Move to shift amount register? */ + /* rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); */ /* TODO */ return 1; default: if (!instruction_trace_cached) { fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t", - cpu->cpu_id, cpu->cd.mips.pc_last, + cpu->cpu_id, (long long)cpu->cd.mips.pc_last, instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu)); } fatal("unimplemented special6 = 0x%02x\n", special6); @@ -3776,7 +3766,7 @@ default: if (!instruction_trace_cached) { fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t", - cpu->cpu_id, cpu->cd.mips.pc_last, + cpu->cpu_id, (long long)cpu->cd.mips.pc_last, instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu)); } fatal("unimplemented regimm5 = 0x%02x\n", regimm5); @@ -3803,8 +3793,7 @@ cpu->cd.mips.delay_slot = TO_BE_DELAYED; cpu->cd.mips.delay_jmpaddr = addr; - if (!quiet_mode_cached && cpu->machine->show_trace_tree && - hi6 == HI6_JAL) { + if (cpu->machine->show_trace_tree && hi6 == HI6_JAL) { cpu->cd.mips.show_trace_delay = 2; cpu->cd.mips.show_trace_addr = addr; } @@ -3881,28 +3870,8 @@ /* * TODO: The cache instruction is implementation dependant. - * This is really ugly. */ -#if 0 -Remove this... - -/* if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) { */ -/* printf("taghi=%08lx taglo=%08lx\n", - (long)cp0->reg[COP0_TAGDATA_HI], - (long)cp0->reg[COP0_TAGDATA_LO]); -*/ - if (cp0->reg[COP0_TAGDATA_HI] == 0 && - cp0->reg[COP0_TAGDATA_LO] == 0) { - /* Normal cache operation: */ - cpu->r10k_cache_disable_TODO = 0; - } else { - /* Dislocate the cache: */ - cpu->r10k_cache_disable_TODO = 1; - } -/* } */ -#endif - /* * Clear the LLbit (at least on R10000): * TODO: How about R4000? @@ -4047,7 +4016,7 @@ } else { if (!instruction_trace_cached) { fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t", - cpu->cpu_id, cpu->cd.mips.pc_last, + cpu->cpu_id, (long long)cpu->cd.mips.pc_last, instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu)); } fatal("unimplemented special_2 = 0x%02x, rs=0x%02x rt=0x%02x rd=0x%02x\n", @@ -4059,7 +4028,7 @@ default: if (!instruction_trace_cached) { fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t", - cpu->cpu_id, cpu->cd.mips.pc_last, + cpu->cpu_id, (long long)cpu->cd.mips.pc_last, instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu)); } fatal("unimplemented hi6 = 0x%02x\n", hi6); @@ -4087,28 +4056,69 @@ */ void mips_cpu_dumpinfo(struct cpu *cpu) { + int iadd = 4; struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type; - debug(" (%i-bit ", (ct->isa_level < 3 || - ct->isa_level == 32)? 32 : 64); + debug_indentation(iadd); + + debug("\n%i-bit %s (MIPS", + cpu->is_32bit? 32 : 64, + cpu->byte_order == EMUL_BIG_ENDIAN? "BE" : "LE"); + + switch (ct->isa_level) { + case 1: debug(" ISA I"); break; + case 2: debug(" ISA II"); break; + case 3: debug(" ISA III"); break; + case 4: debug(" ISA IV"); break; + case 5: debug(" ISA V"); break; + case 32: + case 64:debug("%i", ct->isa_level); break; + default:debug(" ISA level %i", ct->isa_level); + } - debug("%s, ", cpu->byte_order == EMUL_BIG_ENDIAN? "BE" : "LE"); + debug("), "); + if (ct->nr_of_tlb_entries) + debug("%i TLB entries", ct->nr_of_tlb_entries); + else + debug("no TLB"); + debug("\n"); - debug("nTLB=%i", ct->nr_of_tlb_entries); + if (ct->picache) { + debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024); + if (ct->pilinesize) + debug(", %i bytes per line", 1 << ct->pilinesize); + if (ct->piways > 1) + debug(", %i-way", ct->piways); + else + debug(", direct-mapped"); + debug("\n"); + } - if (ct->default_picache || ct->default_pdcache) - debug(", I+D = %i+%i KB", - (1 << ct->default_picache) / 1024, - (1 << ct->default_pdcache) / 1024); + if (ct->pdcache) { + debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024); + if (ct->pdlinesize) + debug(", %i bytes per line", 1 << ct->pdlinesize); + if (ct->pdways > 1) + debug(", %i-way", ct->pdways); + else + debug(", direct-mapped"); + debug("\n"); + } - if (ct->default_scache) { - int kb = (1 << ct->default_scache) / 1024; - debug(", L2 = %i %cB", - kb >= 1024? kb / 1024 : kb, - kb >= 1024? 'M' : 'K'); + if (ct->scache) { + int kb = (1 << ct->scache) / 1024; + debug("L2 cache: %i %s", + kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB"); + if (ct->slinesize) + debug(", %i bytes per line", 1 << ct->slinesize); + if (ct->sways > 1) + debug(", %i-way", ct->sways); + else + debug(", direct-mapped"); + debug("\n"); } - debug(")\n"); + debug_indentation(-iadd); } @@ -4134,27 +4144,7 @@ } -/* - * mips_cpu_family_init(): - * - * Fill in the cpu_family struct for MIPS. - */ -int mips_cpu_family_init(struct cpu_family *fp) -{ - fp->name = "MIPS"; - fp->cpu_new = mips_cpu_new; - fp->list_available_types = mips_cpu_list_available_types; - fp->register_match = mips_cpu_register_match; - fp->disassemble_instr = mips_cpu_disassemble_instr; - fp->register_dump = mips_cpu_register_dump; - fp->run = mips_cpu_run; - fp->dumpinfo = mips_cpu_dumpinfo; - fp->show_full_statistics = mips_cpu_show_full_statistics; - fp->tlbdump = mips_cpu_tlbdump; - fp->interrupt = mips_cpu_interrupt; - fp->interrupt_ack = mips_cpu_interrupt_ack; - return 1; -} +CPU_FAMILY_INIT(mips,"MIPS") #endif /* ENABLE_MIPS */