--- trunk/src/cpus/cpu_mips.c 2007/10/08 16:20:40 30 +++ trunk/src/cpus/cpu_mips.c 2007/10/08 16:21:53 38 @@ -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.c,v 1.63 2006/08/12 11:43:13 debug Exp $ + * $Id: cpu_mips.c,v 1.77 2007/04/10 17:52:27 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; @@ -86,7 +88,7 @@ * Convert a register number into either 'r0', 'r31' etc, or a symbolic * name, depending on machine->show_symbolic_register_names. * - * NOTE: _NOT_ reentrant. + * NOTE: This helper function is _NOT_ reentrant. */ static char *regname(struct machine *machine, int r) { @@ -302,6 +304,23 @@ debug(")"); } + /* Register the CPU's interrupts: */ + for (i=2; i<8; i++) { + struct interrupt template; + char name[50]; + snprintf(name, sizeof(name), "%s.%i", cpu->path, i); + memset(&template, 0, sizeof(template)); + template.line = 1 << (STATUS_IM_SHIFT + i); + template.name = name; + template.extra = cpu; + template.interrupt_assert = mips_cpu_interrupt_assert; + template.interrupt_deassert = mips_cpu_interrupt_deassert; + interrupt_handler_register(&template); + + if (i == 7) + INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare); + } + /* System coprocessor (0), and FPU (1): */ cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); @@ -323,6 +342,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; } @@ -491,6 +533,9 @@ /* Raw output: */ if (rawflag) { for (i=0; incpus; i++) { + struct mips_coproc *cop0 = + m->cpus[i]->cd.mips.coproc[0]; + if (x >= 0 && i != x) continue; @@ -498,20 +543,18 @@ printf("cpu%i: (", i); 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]); + printf("index=0x%08x random=0x%08x", + (int) cop0->reg[COP0_INDEX], + (int) cop0->reg[COP0_RANDOM]); else printf("index=0x%016"PRIx64 " random=0x%016"PRIx64, - (uint64_t)m->cpus[i]->cd.mips.coproc[0]-> - reg[COP0_INDEX], (uint64_t)m->cpus[i]-> - cd.mips.coproc[0]->reg[COP0_RANDOM]); + (uint64_t) cop0->reg[COP0_INDEX], + (uint64_t) cop0->reg[COP0_RANDOM]); if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) - printf(" wired=0x%"PRIx64, (uint64_t) m->cpus - [i]->cd.mips.coproc[0]->reg[COP0_WIRED]); + printf(" wired=0x%"PRIx64, + (uint64_t) cop0->reg[COP0_WIRED]); printf(")\n"); @@ -519,31 +562,36 @@ nr_of_tlb_entries; j++) { if (m->cpus[i]->cd.mips.cpu_type.mmu_model == MMU3K) - printf("%3i: hi=0x%08x lo=0x%08x\n", j, - (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, - (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); + printf("%3i: hi=0x%08"PRIx32" lo=0x%08" + PRIx32"\n", j, + (uint32_t) cop0->tlbs[j].hi, + (uint32_t) cop0->tlbs[j].lo0); 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, - (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, - (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, - (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); + printf("%3i: hi=0x%08"PRIx32" mask=0x" + "%08"PRIx32" lo0=0x%08"PRIx32 + " lo1=0x%08"PRIx32"\n", j, + (uint32_t) cop0->tlbs[j].hi, + (uint32_t) cop0->tlbs[j].mask, + (uint32_t) cop0->tlbs[j].lo0, + (uint32_t) cop0->tlbs[j].lo1); else - printf("%3i: hi=0x%016"PRIx64" mask=0x%016"PRIx64" " - "lo0=0x%016"PRIx64" lo1=0x%016"PRIx64"\n", j, - (uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, - (uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, - (uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, - (uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); + printf("%3i: hi=0x%016"PRIx64" mask=" + "0x%016"PRIx64" lo0=0x%016"PRIx64 + " lo1=0x%016"PRIx64"\n", j, + (uint64_t) cop0->tlbs[j].hi, + (uint64_t) cop0->tlbs[j].mask, + (uint64_t) cop0->tlbs[j].lo0, + (uint64_t) cop0->tlbs[j].lo1); } } + return; } /* Nicely formatted output: */ for (i=0; incpus; i++) { int pageshift = 12; + struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0]; if (x >= 0 && i != x) continue; @@ -556,31 +604,26 @@ switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { case 1: case 2: printf("index=0x%x random=0x%x", - (int) ((m->cpus[i]->cd.mips.coproc[0]-> - reg[COP0_INDEX] & R2K3K_INDEX_MASK) + (int) ((cop0->reg[COP0_INDEX] & R2K3K_INDEX_MASK) >> R2K3K_INDEX_SHIFT), - (int) ((m->cpus[i]->cd.mips.coproc[0]-> - reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) + (int) ((cop0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) >> R2K3K_RANDOM_SHIFT)); break; default:printf("index=0x%x random=0x%x", - (int) (m->cpus[i]->cd.mips.coproc[0]-> - reg[COP0_INDEX] & INDEX_MASK), - (int) (m->cpus[i]->cd.mips.coproc[0]-> - reg[COP0_RANDOM] & RANDOM_MASK)); - printf(" wired=0x%"PRIx64, (uint64_t) - m->cpus[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); + (int) (cop0->reg[COP0_INDEX] & INDEX_MASK), + (int) (cop0->reg[COP0_RANDOM] & RANDOM_MASK)); + printf(" wired=0x%"PRIx64, + (uint64_t) cop0->reg[COP0_WIRED]); } printf(")\n"); for (j=0; jcpus[i]->cd.mips.cpu_type. nr_of_tlb_entries; j++) { - uint64_t hi,lo0,lo1,mask; - hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi; - lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0; - lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1; - mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask; + uint64_t hi = cop0->tlbs[j].hi; + uint64_t lo0 = cop0->tlbs[j].lo0; + uint64_t lo1 = cop0->tlbs[j].lo1; + uint64_t mask = cop0->tlbs[j].mask; printf("%3i: ", j); switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { @@ -606,19 +649,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 +702,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 +718,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 +760,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 +769,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 +784,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 +798,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 +827,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 +862,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 +1102,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; @@ -1277,7 +1295,7 @@ if (cache_op==2) debug("index store tag"), showtag=1; if (cache_op==3) debug("create dirty exclusive"); if (cache_op==4) debug("hit invalidate"); - if (cache_op==5) debug("fill OR hit writeback invalidate"); + if (cache_op==5) debug("fill OR hit writeback invalidate"); if (cache_op==6) debug("hit writeback"); if (cache_op==7) debug("hit set virtual"); if (running) @@ -1450,7 +1468,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 +1483,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 +1493,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); } @@ -1551,8 +1576,8 @@ " "); else debug(" %3s=%016"PRIx64"%016"PRIx64, - regname(cpu->machine, r), - (uint64_t)cpu->cd.mips.gpr_quadhi[r], + regname(cpu->machine, r), (uint64_t) + cpu->cd.mips.gpr_quadhi[r], (uint64_t)cpu->cd.mips.gpr[r]); if ((i & 1) == 1) debug("\n"); @@ -1616,15 +1641,19 @@ debug(" c%i,%02i", coprocnr, i); if (bits32) - debug("=%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); + debug("=%08x", (int)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]); + debug(" = 0x%08x", + (int) cpu->cd.mips.coproc[ + coprocnr]->reg[i]); else debug(" = 0x%016"PRIx64, (uint64_t) - cpu->cd.mips.coproc[coprocnr]->reg[i]); + cpu->cd.mips.coproc[ + coprocnr]->reg[i]); } if ((i & nm1) == nm1) @@ -1676,184 +1705,21 @@ } -static void add_response_word(struct cpu *cpu, char *r, uint64_t value, - size_t maxlen, int len) -{ - char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64; - if (len == 4) - value &= 0xffffffffULL; - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { - if (len == 4) { - value = ((value & 0xff) << 24) + - ((value & 0xff00) << 8) + - ((value & 0xff0000) >> 8) + - ((value & 0xff000000) >> 24); - } else { - value = ((value & 0xff) << 56) + - ((value & 0xff00) << 40) + - ((value & 0xff0000) << 24) + - ((value & 0xff000000ULL) << 8) + - ((value & 0xff00000000ULL) >> 8) + - ((value & 0xff0000000000ULL) >> 24) + - ((value & 0xff000000000000ULL) >> 40) + - ((value & 0xff00000000000000ULL) >> 56); - } - } - snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value); -} - - -/* - * mips_cpu_gdb_stub(): - * - * Execute a "remote GDB" command. Returns 1 on success, 0 on error. - */ -char *mips_cpu_gdb_stub(struct cpu *cpu, char *cmd) -{ - if (strcmp(cmd, "g") == 0) { - /* 76 registers: gprs, sr, lo, hi, badvaddr, cause, pc, - fprs, fsr, fir, fp. */ - int i; - char *r; - size_t wlen = cpu->is_32bit? - sizeof(uint32_t) : sizeof(uint64_t); - size_t len = 1 + 76 * wlen; - r = malloc(len); - if (r == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - r[0] = '\0'; - for (i=0; i<32; i++) - add_response_word(cpu, r, cpu->cd.mips.gpr[i], - len, wlen); - add_response_word(cpu, r, - cpu->cd.mips.coproc[0]->reg[COP0_STATUS], len, wlen); - add_response_word(cpu, r, cpu->cd.mips.lo, len, wlen); - add_response_word(cpu, r, cpu->cd.mips.hi, len, wlen); - add_response_word(cpu, r, - cpu->cd.mips.coproc[0]->reg[COP0_BADVADDR], len, wlen); - add_response_word(cpu, r, - cpu->cd.mips.coproc[0]->reg[COP0_CAUSE], len, wlen); - add_response_word(cpu, r, cpu->pc, len, wlen); - for (i=0; i<32; i++) - add_response_word(cpu, r, - cpu->cd.mips.coproc[1]->reg[i], len, wlen); - add_response_word(cpu, r, - cpu->cd.mips.coproc[1]->reg[31] /* fcsr */, len, wlen); - add_response_word(cpu, r, - cpu->cd.mips.coproc[1]->reg[0] /* fcir */, len, wlen); - - /* TODO: fp = gpr 30? */ - add_response_word(cpu, r, cpu->cd.mips.gpr[30], len, wlen); - - return r; - } - - if (cmd[0] == 'p') { - int regnr = strtol(cmd + 1, NULL, 16); - size_t wlen = cpu->is_32bit? sizeof(uint32_t):sizeof(uint64_t); - size_t len = 2 * wlen + 1; - char *r = malloc(len); - r[0] = '\0'; - if (regnr >= 0 && regnr <= 31) { - add_response_word(cpu, r, - cpu->cd.mips.gpr[regnr], len, wlen); - } else if (regnr == 0x20) { - add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> - reg[COP0_STATUS], len, wlen); - } else if (regnr == 0x21) { - add_response_word(cpu, r, cpu->cd.mips.lo, len, wlen); - } else if (regnr == 0x22) { - add_response_word(cpu, r, cpu->cd.mips.hi, len, wlen); - } else if (regnr == 0x23) { - add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> - reg[COP0_BADVADDR], len, wlen); - } else if (regnr == 0x24) { - add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> - reg[COP0_CAUSE], len, wlen); - } else if (regnr == 0x25) { - add_response_word(cpu, r, cpu->pc, len, wlen); - } else if (regnr >= 0x26 && regnr <= 0x45 && - cpu->cd.mips.coproc[1] != NULL) { - add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> - reg[regnr - 0x26], len, wlen); - } else if (regnr == 0x46) { - add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> - fcr[MIPS_FPU_FCSR], len, wlen); - } else if (regnr == 0x47) { - add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> - fcr[MIPS_FPU_FCIR], len, wlen); - } else { - /* Unimplemented: */ - add_response_word(cpu, r, 0xcc000 + regnr, len, wlen); - } - return r; - } - - fatal("mips_cpu_gdb_stub(): cmd='%s' TODO\n", cmd); - return NULL; -} - - /* - * mips_cpu_interrupt(): - * - * Cause an interrupt. If irq_nr is 2..7, then it is a MIPS hardware - * interrupt. 0 and 1 are ignored (software interrupts). + * mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert(): * - * If irq_nr is >= 8, then this function calls md_interrupt(). + * Assert or deassert a MIPS CPU interrupt by masking in or out bits + * in the CAUSE register of coprocessor 0. */ -int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) +void mips_cpu_interrupt_assert(struct interrupt *interrupt) { - if (irq_nr >= 8) { - if (cpu->machine->md_interrupt != NULL) - cpu->machine->md_interrupt(cpu->machine, - cpu, irq_nr, 1); - else - fatal("mips_cpu_interrupt(): irq_nr = %i, " - "but md_interrupt = NULL ?\n", irq_nr); - return 1; - } - - if (irq_nr < 2) - return 0; - - cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= - ((1 << irq_nr) << STATUS_IM_SHIFT); - - return 1; + struct cpu *cpu = interrupt->extra; + cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line; } - - -/* - * mips_cpu_interrupt_ack(): - * - * Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware - * interrupt. Interrupts 0..1 are ignored (software interrupts). - * - * If irq_nr is >= 8, then it is machine dependent, and md_interrupt() is - * called. - */ -int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) +void mips_cpu_interrupt_deassert(struct interrupt *interrupt) { - if (irq_nr >= 8) { - if (cpu->machine->md_interrupt != NULL) - cpu->machine->md_interrupt(cpu->machine, cpu, - irq_nr, 0); - else - fatal("mips_cpu_interrupt_ack(): irq_nr = %i, " - "but md_interrupt = NULL ?\n", irq_nr); - return 1; - } - - if (irq_nr < 2) - return 0; - - cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= - ~((1 << irq_nr) << STATUS_IM_SHIFT); - - return 1; + struct cpu *cpu = interrupt->extra; + cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~interrupt->line; } @@ -2046,12 +1912,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 +1926,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;