--- trunk/src/cpus/cpu_mips.c 2007/10/08 16:20:48 31 +++ trunk/src/cpus/cpu_mips.c 2007/10/08 16:20:58 32 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_mips.c,v 1.63 2006/08/12 11:43:13 debug Exp $ + * $Id: cpu_mips.c,v 1.69 2006/10/07 02:05:21 debug Exp $ * * MIPS core CPU emulation. */ @@ -50,6 +50,7 @@ #include "memory.h" #include "mips_cpu_types.h" #include "opcodes_mips.h" +#include "settings.h" #include "symbol.h" @@ -60,6 +61,7 @@ static char *hi6_names[] = HI6_NAMES; static char *regimm_names[] = REGIMM_NAMES; static char *special_names[] = SPECIAL_NAMES; +static char *special_rot_names[] = SPECIAL_ROT_NAMES; static char *special2_names[] = SPECIAL2_NAMES; static char *mmi_names[] = MMI_NAMES; static char *mmi0_names[] = MMI0_NAMES; @@ -323,6 +325,29 @@ cpu->translate_v2p = translate_v2p_generic; } + if (cpu->machine->prom_emulation) { + /* + * Default behaviour of jumping to 0xbfc00000 should be + * a reboot, unless machine-specific initialization code + * overrides this. + * + * Note: Specifically big-endian machines should override + * this, since the default MIPS CPU is little-endian! + */ + store_32bit_word(cpu, 0xffffffff9fc00000ULL, 0x00c0de0d); + } + + /* Add all register names to the settings: */ + CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); + CPU_SETTINGS_ADD_REGISTER64("hi", cpu->cd.mips.hi); + CPU_SETTINGS_ADD_REGISTER64("lo", cpu->cd.mips.lo); + for (i=0; icd.mips.gpr[i]); + /* TODO: Write via special handler function! */ + for (i=0; icd.mips.coproc[0]->reg[i]); + return 1; } @@ -606,19 +631,14 @@ printf("\n"); break; default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ - case MMU10K: - printf("vaddr=0x%1x..%011"PRIx64" ", - (int) (hi >> 60), (uint64_t) - (hi&ENTRYHI_VPN2_MASK_R10K)); - break; case MMU32: printf("vaddr=0x%08"PRIx32" ", - (uint32_t)(hi&ENTRYHI_VPN2_MASK)); + (uint32_t) hi); break; + case MMU10K: default:/* R4000 etc. */ - printf("vaddr=0x%1x..%010"PRIx64" ", - (int) (hi >> 60), - (uint64_t) (hi&ENTRYHI_VPN2_MASK)); + printf("vaddr=%016"PRIx64" ", + (uint64_t) hi); } if (hi & TLB_G) printf("(global): "); @@ -664,123 +684,6 @@ /* - * mips_cpu_register_match(): - */ -void mips_cpu_register_match(struct machine *m, char *name, - int writeflag, uint64_t *valuep, int *match_register) -{ - int cpunr = 0; - - /* CPU number: */ - - /* TODO */ - - /* Register name: */ - if (strcasecmp(name, "pc") == 0) { - if (writeflag) { - m->cpus[cpunr]->pc = *valuep; - if (m->cpus[cpunr]->delay_slot) { - printf("NOTE: Clearing the delay slot" - " flag! (It was set before.)\n"); - m->cpus[cpunr]->delay_slot = 0; - } - if (m->cpus[cpunr]->cd.mips.nullify_next) { - printf("NOTE: Clearing the nullify-ne" - "xt flag! (It was set before.)\n"); - m->cpus[cpunr]->cd.mips.nullify_next = 0; - } - } else - *valuep = m->cpus[cpunr]->pc; - *match_register = 1; - } else if (strcasecmp(name, "hi") == 0) { - if (writeflag) - m->cpus[cpunr]->cd.mips.hi = *valuep; - else - *valuep = m->cpus[cpunr]->cd.mips.hi; - *match_register = 1; - } else if (strcasecmp(name, "lo") == 0) { - if (writeflag) - m->cpus[cpunr]->cd.mips.lo = *valuep; - else - *valuep = m->cpus[cpunr]->cd.mips.lo; - *match_register = 1; - } else if (name[0] == 'r' && isdigit((int)name[1])) { - int nr = atoi(name + 1); - if (nr >= 0 && nr < N_MIPS_GPRS) { - if (writeflag) { - if (nr != 0) - m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep; - else - printf("WARNING: Attempt to modify r0.\n"); - } else - *valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; - *match_register = 1; - } - } else { - /* Check for a symbolic name such as "t6" or "at": */ - int nr; - for (nr=0; nrcpus[cpunr]->cd.mips.gpr[nr] = *valuep; - else - printf("WARNING: Attempt to modify r0.\n"); - } else - *valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; - *match_register = 1; - } - } - - if (!(*match_register)) { - /* Check for a symbolic coproc0 name: */ - int nr; - for (nr=0; nr<32; nr++) - if (strcmp(name, cop0_names[nr]) == 0) { - if (writeflag) { - coproc_register_write(m->cpus[cpunr], - m->cpus[cpunr]->cd.mips.coproc[0], nr, - valuep, 1, 0); - } else { - /* TODO: Use coproc_register_read instead? */ - *valuep = m->cpus[cpunr]->cd.mips.coproc[0]->reg[nr]; - } - *match_register = 1; - } - } - - /* TODO: Coprocessor 1,2,3 registers. */ - - /* Only return lowest 32 bits when doing 32-bit emulation: */ - if (!writeflag && m->cpus[cpunr]->is_32bit) - *valuep = (uint32_t) (*valuep); -} - - -/* - * cpu_flags(): - * - * Returns a pointer to a string containing "(d)" "(j)" "(dj)" or "", - * depending on the cpu's current delay_slot and last_was_jumptoself - * flags. - */ -static const char *cpu_flags(struct cpu *cpu) -{ - if (cpu->delay_slot) { - if (cpu->cd.mips.last_was_jumptoself) - return " (dj)"; - else - return " (d)"; - } else { - if (cpu->cd.mips.last_was_jumptoself) - return " (j)"; - else - return ""; - } -} - - -/* * mips_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction @@ -797,7 +700,7 @@ int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, int running, uint64_t dumpaddr) { - int hi6, special6, regimm5; + int hi6, special6, regimm5, sub; int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; uint64_t addr, offset; uint32_t instrword; @@ -839,8 +742,8 @@ debug(": %02x%02x%02x%02x", instr[3], instr[2], instr[1], instr[0]); - if (running) - debug("%s", cpu_flags(cpu)); + if (running && cpu->delay_slot) + debug(" (d)"); debug("\t"); @@ -848,11 +751,6 @@ * Decode the instruction: */ - if (cpu->cd.mips.nullify_next && running) { - debug("(nullified)"); - goto disasm_ret; - } - hi6 = (instr[3] >> 2) & 0x3f; switch (hi6) { @@ -868,6 +766,7 @@ case SPECIAL_DSLL32: case SPECIAL_DSRL32: case SPECIAL_DSRA32: + sub = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); @@ -881,12 +780,25 @@ debug("ehb"); else debug("nop (weird, sa=%i)", sa); - goto disasm_ret; - } else + break; + } + + switch (sub) { + case 0x00: debug("%s\t%s,", special_names[special6], regname(cpu->machine, rd)); debug("%s,%i", regname(cpu->machine, rt), sa); + break; + case 0x01: + debug("%s\t%s,", + special_rot_names[special6], + regname(cpu->machine, rd)); + debug("%s,%i", regname(cpu->machine, rt), sa); + break; + default:debug("UNIMPLEMENTED special, sub=0x%02x\n", + sub); + } break; case SPECIAL_DSRLV: case SPECIAL_DSRAV: @@ -897,16 +809,33 @@ rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; rd = (instr[1] >> 3) & 31; - debug("%s\t%s", - special_names[special6], regname(cpu->machine, rd)); - debug(",%s", regname(cpu->machine, rt)); - debug(",%s", regname(cpu->machine, rs)); + sub = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); + + switch (sub) { + case 0x00: + debug("%s\t%s", special_names[special6], + regname(cpu->machine, rd)); + debug(",%s", regname(cpu->machine, rt)); + debug(",%s", regname(cpu->machine, rs)); + break; + case 0x01: + debug("%s\t%s", special_rot_names[special6], + regname(cpu->machine, rd)); + debug(",%s", regname(cpu->machine, rt)); + debug(",%s", regname(cpu->machine, rs)); + break; + default:debug("UNIMPLEMENTED special, sub=0x%02x\n", + sub); + } break; case SPECIAL_JR: rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.mips.gpr[rs], &offset); - debug("jr\t%s", regname(cpu->machine, rs)); + /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ + debug("jr%s\t%s", + (instr[1] & 0x04) ? ".hb" : "", + regname(cpu->machine, rs)); if (running && symbol != NULL) debug("\t<%s>", symbol); break; @@ -915,7 +844,10 @@ rd = (instr[1] >> 3) & 31; symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->cd.mips.gpr[rs], &offset); - debug("jalr\t%s", regname(cpu->machine, rd)); + /* .hb = hazard barrier hint on MIPS32/64 rev 2 */ + debug("jalr%s\t%s", + (instr[1] & 0x04) ? ".hb" : "", + regname(cpu->machine, rd)); debug(",%s", regname(cpu->machine, rs)); if (running && symbol != NULL) debug("\t<%s>", symbol); @@ -1152,20 +1084,88 @@ } if (hi6 == HI6_SQ_SPECIAL3 && cpu->cd.mips.cpu_type.rev != MIPS_R5900) { + int msbd, lsb, sub10; special6 = instr[0] & 0x3f; - debug("%s", special3_names[special6]); rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); rt = instr[2] & 31; - rd = (instr[1] >> 3) & 31; + rd = msbd = (instr[1] >> 3) & 31; + lsb = ((instr[1] & 7) << 2) | (instr[0] >> 6); + sub10 = (rs << 5) | lsb; switch (special6) { + case SPECIAL3_EXT: + case SPECIAL3_DEXT: + case SPECIAL3_DEXTM: + case SPECIAL3_DEXTU: + debug("%s", special3_names[special6]); + if (special6 == SPECIAL3_DEXTM) + msbd += 32; + if (special6 == SPECIAL3_DEXTU) + lsb += 32; + debug("\t%s", regname(cpu->machine, rt)); + debug(",%s", regname(cpu->machine, rs)); + debug(",%i,%i", lsb, msbd + 1); + break; + + case SPECIAL3_INS: + case SPECIAL3_DINS: + case SPECIAL3_DINSM: + case SPECIAL3_DINSU: + debug("%s", special3_names[special6]); + if (special6 == SPECIAL3_DINSM) + msbd += 32; + if (special6 == SPECIAL3_DINSU) { + lsb += 32; + msbd += 32; + } + msbd -= lsb; + debug("\t%s", regname(cpu->machine, rt)); + debug(",%s", regname(cpu->machine, rs)); + debug(",%i,%i", lsb, msbd + 1); + break; + + case SPECIAL3_BSHFL: + switch (sub10) { + case BSHFL_WSBH: + case BSHFL_SEB: + case BSHFL_SEH: + switch (sub10) { + case BSHFL_WSBH: debug("wsbh"); break; + case BSHFL_SEB: debug("seb"); break; + case BSHFL_SEH: debug("seh"); break; + } + debug("\t%s", regname(cpu->machine,rd)); + debug(",%s", regname(cpu->machine,rt)); + break; + default:debug("%s", special3_names[special6]); + debug("\t(UNIMPLEMENTED)"); + } + break; + + case SPECIAL3_DBSHFL: + switch (sub10) { + case BSHFL_DSBH: + case BSHFL_DSHD: + switch (sub10) { + case BSHFL_DSBH: debug("dsbh"); break; + case BSHFL_DSHD: debug("dshd"); break; + } + debug("\t%s", regname(cpu->machine,rd)); + debug(",%s", regname(cpu->machine,rt)); + break; + default:debug("%s", special3_names[special6]); + debug("\t(UNIMPLEMENTED)"); + } + break; + case SPECIAL3_RDHWR: + debug("%s", special3_names[special6]); debug("\t%s", regname(cpu->machine, rt)); debug(",hwr%i", rd); break; - default: + default:debug("%s", special3_names[special6]); debug("\t(UNIMPLEMENTED)"); } break; @@ -1450,7 +1450,13 @@ case HI6_REGIMM: regimm5 = instr[2] & 0x1f; + rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); + imm = (instr[1] << 8) + instr[0]; + if (imm >= 32768) + imm -= 65536; + switch (regimm5) { + case REGIMM_BLTZ: case REGIMM_BGEZ: case REGIMM_BLTZL: @@ -1459,11 +1465,6 @@ case REGIMM_BLTZALL: case REGIMM_BGEZAL: case REGIMM_BGEZALL: - rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); - imm = (instr[1] << 8) + instr[0]; - if (imm >= 32768) - imm -= 65536; - debug("%s\t%s,", regimm_names[regimm5], regname(cpu->machine, rs)); @@ -1474,6 +1475,12 @@ else debug("0x%016"PRIx64, (uint64_t) addr); break; + + case REGIMM_SYNCI: + debug("%s\t%i(%s)", regimm_names[regimm5], + imm, regname(cpu->machine, rs)); + break; + default: debug("unimplemented regimm5 = 0x%02x", regimm5); } @@ -2046,12 +2053,9 @@ /* debug("[ warning: cpu%i exception while EXL is set," " not setting EPC ]\n", cpu->cpu_id); */ } else { - if (cpu->delay_slot || cpu->cd.mips.nullify_next) { + if (cpu->delay_slot) { reg[COP0_EPC] = cpu->pc - 4; reg[COP0_CAUSE] |= CAUSE_BD; - - /* TODO: Should the BD flag actually be set - on nullified slots? */ } else { reg[COP0_EPC] = cpu->pc; reg[COP0_CAUSE] &= ~CAUSE_BD; @@ -2063,8 +2067,6 @@ else cpu->delay_slot = NOT_DELAYED; - cpu->cd.mips.nullify_next = 0; - /* TODO: This is true for MIPS64, but how about others? */ if (reg[COP0_STATUS] & STATUS_BEV) base = 0xffffffffbfc00200ULL;