--- trunk/src/cpus/cpu_sh.c 2007/10/08 16:20:48 31 +++ trunk/src/cpus/cpu_sh.c 2007/10/08 16:20:58 32 @@ -25,29 +25,43 @@ * SUCH DAMAGE. * * - * $Id: cpu_sh.c,v 1.21 2006/07/25 21:49:14 debug Exp $ + * $Id: cpu_sh.c,v 1.53 2006/10/31 11:07:05 debug Exp $ * * Hitachi SuperH ("SH") CPU emulation. * - * TODO + * TODO: It would be nice if this could encompass both 64-bit SH5, and + * 32-bit SH encodings. Right now, it only really supports 32-bit mode. */ #include #include #include #include +#include #include "cpu.h" +#include "device.h" +#include "float_emul.h" #include "machine.h" #include "memory.h" #include "misc.h" +#include "settings.h" #include "symbol.h" +#include "sh4_exception.h" +#include "sh4_mmu.h" -#define DYNTRANS_DUALMODE_32 + +#define DYNTRANS_32 +#define DYNTRANS_DELAYSLOT #include "tmp_sh_head.c" +extern int quiet_mode; + +void sh_pc_to_pointers(struct cpu *); + + /* * sh_cpu_new(): * @@ -79,23 +93,21 @@ cpu->is_32bit = cpu->cd.sh.cpu_type.bits == 32; cpu->cd.sh.compact = 1; /* Default to 16-bit opcode mode */ + if (!cpu->is_32bit) { + fatal("SH64 emulation not implemented. Sorry.\n"); + exit(1); + } + + cpu->instruction_has_delayslot = sh_cpu_instruction_has_delayslot; + cpu->translate_v2p = sh_translate_v2p; - if (cpu->is_32bit) { - cpu->run_instr = sh32_run_instr; - cpu->update_translation_table = sh32_update_translation_table; - cpu->invalidate_translation_caches = - sh32_invalidate_translation_caches; - cpu->invalidate_code_translation = - sh32_invalidate_code_translation; - } else { - cpu->run_instr = sh_run_instr; - cpu->update_translation_table = sh_update_translation_table; - cpu->invalidate_translation_caches = - sh_invalidate_translation_caches; - cpu->invalidate_code_translation = - sh_invalidate_code_translation; - } + cpu->run_instr = sh_run_instr; + cpu->update_translation_table = sh_update_translation_table; + cpu->invalidate_translation_caches = + sh_invalidate_translation_caches; + cpu->invalidate_code_translation = + sh_invalidate_code_translation; /* Only show name and caches etc for CPU nr 0 (in SMP machines): */ if (cpu_id == 0) { @@ -105,8 +117,58 @@ /* Initial value of FPSCR (according to the SH4 manual): */ cpu->cd.sh.fpscr = 0x00040001; + /* (Initial value of the program counter on reboot is 0xA0000000.) */ + /* Start in Privileged Mode: */ - cpu->cd.sh.sr = SH_SR_MD; + cpu->cd.sh.sr = SH_SR_MD | SH_SR_IMASK; + + /* Stack pointer at end of physical RAM: */ + cpu->cd.sh.r[15] = cpu->machine->physical_ram_in_mb * 1048576 - 64; + + CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); + CPU_SETTINGS_ADD_REGISTER32("sr", cpu->cd.sh.sr); + CPU_SETTINGS_ADD_REGISTER32("pr", cpu->cd.sh.pr); + CPU_SETTINGS_ADD_REGISTER32("vbr", cpu->cd.sh.vbr); + CPU_SETTINGS_ADD_REGISTER32("gbr", cpu->cd.sh.gbr); + CPU_SETTINGS_ADD_REGISTER32("macl", cpu->cd.sh.macl); + CPU_SETTINGS_ADD_REGISTER32("mach", cpu->cd.sh.mach); + CPU_SETTINGS_ADD_REGISTER32("fpscr", cpu->cd.sh.fpscr); + CPU_SETTINGS_ADD_REGISTER32("fpul", cpu->cd.sh.fpul); + for (i=0; icd.sh.r[i]); + } + for (i=0; icd.sh.r_bank[i]); + } + for (i=0; icd.sh.fr[i]); + snprintf(tmpstr, sizeof(tmpstr), "xf%i", i); + CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.xf[i]); + } + for (i=0; icd.sh.itlb_hi[i]); + snprintf(tmpstr, sizeof(tmpstr), "itlb_lo_%i", i); + CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.itlb_lo[i]); + } + for (i=0; icd.sh.utlb_hi[i]); + snprintf(tmpstr, sizeof(tmpstr), "utlb_lo_%i", i); + CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.utlb_lo[i]); + } + + /* SH4-specific memory mapped registers, TLBs, caches, etc: */ + if (cpu->cd.sh.cpu_type.arch == 4) + device_add(machine, "sh4"); return 1; } @@ -138,8 +200,62 @@ */ void sh_cpu_dumpinfo(struct cpu *cpu) { - debug("\n"); - /* TODO */ + debug(" (%s-endian)\n", + cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little"); +} + + +/* + * sh_cpu_instruction_has_delayslot(): + * + * Return 1 if an opcode is a branch, 0 otherwise. + */ +int sh_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib) +{ + uint16_t iword = *((uint16_t *)&ib[0]); + int hi4, lo4, lo8; + + if (!cpu->is_32bit) + return 0; + + if (cpu->byte_order == EMUL_BIG_ENDIAN) + iword = BE16_TO_HOST(iword); + else + iword = LE16_TO_HOST(iword); + + hi4 = iword >> 12; lo4 = iword & 15; lo8 = iword & 255; + + switch (hi4) { + case 0x0: + if (iword == 0x000b) /* rts */ + return 1; + if (iword == 0x002b) /* rte */ + return 1; + if (lo8 == 0x03) /* bsrf */ + return 1; + if (lo8 == 0x23) /* braf */ + return 1; + break; + case 0x4: + switch (lo8) { + case 0x0b: /* jsr */ + case 0x2b: /* jmp */ + return 1; + } + break; + case 0x8: + switch ((iword >> 8) & 0xf) { + case 0xd: /* bt/s */ + case 0xf: /* bf/s */ + return 1; + } + break; + case 0xa: /* bra */ + case 0xb: /* bsr */ + return 1; + } + + return 0; } @@ -156,22 +272,17 @@ char *symbol; uint64_t offset; int i, x = cpu->cpu_id, nregs = cpu->cd.sh.compact? 16 : 64; - int bits32 = cpu->cd.sh.cpu_type.bits == 32; if (gprs) { /* Special registers (pc, ...) first: */ symbol = get_symbol_name(&cpu->machine->symbol_context, cpu->pc, &offset); - debug("cpu%i: pc = 0x", x); - if (bits32) - debug("%08x", (int)cpu->pc); - else - debug("%016llx", (long long)cpu->pc); + debug("cpu%i: pc = 0x%08"PRIx32, x, (uint32_t)cpu->pc); debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); - debug("cpu%i: sr = %s, %s, %s, %s, %s, %s, imask=0x%x, " - "%s, %s\n", x, + debug("cpu%i: sr = 0x%08"PRIx32" (%s, %s, %s, %s, %s, %s," + " imask=0x%x, %s, %s)\n", x, (int32_t)cpu->cd.sh.sr, (cpu->cd.sh.sr & SH_SR_MD)? "MD" : "!md", (cpu->cd.sh.sr & SH_SR_RB)? "RB" : "!rb", (cpu->cd.sh.sr & SH_SR_BL)? "BL" : "!bl", @@ -182,59 +293,63 @@ (cpu->cd.sh.sr & SH_SR_S)? "S" : "!s", (cpu->cd.sh.sr & SH_SR_T)? "T" : "!t"); - if (bits32) { - /* 32-bit: */ - for (i=0; icd.sh.r[i]); - if ((i % 4) == 3) - debug("\n"); - } - } else { - /* 64-bit: */ - for (i=0; i> 1) + ((i & 1) << 4); - if ((i % 2) == 0) - debug("cpu%i:", x); - debug(" r%02i = 0x%016llx ", r, - (long long)cpu->cd.sh.r[r]); - if ((i % 2) == 1) - debug("\n"); - } + symbol = get_symbol_name(&cpu->machine->symbol_context, + cpu->cd.sh.pr, &offset); + debug("cpu%i: pr = 0x%08"PRIx32, x, (uint32_t)cpu->cd.sh.pr); + debug(" <%s>\n", symbol != NULL? symbol : " no symbol "); + + debug("cpu%i: mach = 0x%08"PRIx32" macl = 0x%08"PRIx32 + " gbr = 0x%08"PRIx32"\n", x, (uint32_t)cpu->cd.sh.mach, + (uint32_t)cpu->cd.sh.macl, (uint32_t)cpu->cd.sh.gbr); + + for (i=0; icd.sh.r[i]); + if ((i % 4) == 3) + debug("\n"); } } -} + if (coprocs & 1) { + /* Floating point: */ + debug("cpu%i: fpscr = 0x%08"PRIx32" fpul = 0x%08"PRIx32 + "\n", x, cpu->cd.sh.fpscr, cpu->cd.sh.fpul); + + for (i=0; icd.sh.fr[i]); + if ((i % 4) == 3) + debug("\n"); + } -/* - * sh_cpu_register_match(): - */ -void sh_cpu_register_match(struct machine *m, char *name, - int writeflag, uint64_t *valuep, int *match_register) -{ - int cpunr = 0; - - /* CPU number: */ - - /* TODO */ + for (i=0; icd.sh.xf[i]); + if ((i % 4) == 3) + debug("\n"); + } + } - /* Register name: */ - if (strcasecmp(name, "pc") == 0) { - if (writeflag) { - m->cpus[cpunr]->pc = *valuep; - } else - *valuep = m->cpus[cpunr]->pc; - *match_register = 1; - } else if (name[0] == 'r' && isdigit((int)name[1])) { - int nr = atoi(name + 1); - if (nr >= 0 && nr < SH_N_GPRS) { - if (writeflag) - m->cpus[cpunr]->cd.sh.r[nr] = *valuep; - else - *valuep = m->cpus[cpunr]->cd.sh.r[nr]; - *match_register = 1; + if (coprocs & 2) { + /* System registers, etc: */ + debug("cpu%i: vbr = 0x%08"PRIx32" sgr = 0x%08"PRIx32 + "\n", x, cpu->cd.sh.vbr, cpu->cd.sh.sgr); + debug("cpu%i: spc = 0x%08"PRIx32" ssr = 0x%08"PRIx32"\n", + x, cpu->cd.sh.spc, cpu->cd.sh.ssr); + debug("cpu%i: expevt = 0x%"PRIx32" intevt = 0x%"PRIx32 + " tra = 0x%"PRIx32"\n", x, cpu->cd.sh.expevt, + cpu->cd.sh.intevt, cpu->cd.sh.tra); + + for (i=0; icd.sh.r_bank[i]); + if ((i % 2) == 1) + debug("\n"); } } } @@ -251,6 +366,25 @@ */ void sh_cpu_tlbdump(struct machine *m, int x, int rawflag) { + int i, j; + + for (j=0; jncpus; j++) { + struct cpu *cpu = m->cpus[j]; + + if (x >= 0 && j != x) + continue; + + for (i=0; icd.sh.itlb_hi[i], i, + (uint32_t) cpu->cd.sh.itlb_lo[i]); + for (i=0; icd.sh.utlb_hi[i], i, + (uint32_t) cpu->cd.sh.utlb_lo[i]); + } } @@ -269,10 +403,39 @@ /* * sh_cpu_interrupt(): + * + * Note: This gives higher interrupt priority to lower number interrupts. + * Hopefully this is correct. */ int sh_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) { - fatal("sh_cpu_interrupt(): TODO\n"); + int word_index, bit_index; + + if (cpu->cd.sh.int_to_assert == 0 || irq_nr < cpu->cd.sh.int_to_assert) + cpu->cd.sh.int_to_assert = irq_nr; + + /* + * TODO: Keep track of all pending interrupts at multiple levels... + * + * This is just a quick hack: + */ + cpu->cd.sh.int_level = 1; + if (irq_nr == SH_INTEVT_TMU0_TUNI0) + cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 12) & 0xf; + if (irq_nr == SH_INTEVT_TMU1_TUNI1) + cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 8) & 0xf; + if (irq_nr == SH_INTEVT_TMU2_TUNI2) + cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 4) & 0xf; + if (irq_nr >= SH4_INTEVT_SCIF_ERI && + irq_nr <= SH4_INTEVT_SCIF_TXI) + cpu->cd.sh.int_level = (cpu->cd.sh.intc_iprc >> 4) & 0xf; + + irq_nr /= 0x20; + word_index = irq_nr / (sizeof(uint32_t)*8); + bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1); + + cpu->cd.sh.int_pending[word_index] |= (1 << bit_index); + return 0; } @@ -282,22 +445,62 @@ */ int sh_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) { - /* fatal("sh_cpu_interrupt_ack(): TODO\n"); */ + int word_index, bit_index; + + if (cpu->cd.sh.int_to_assert == irq_nr) { + /* + * Rescan all interrupts to see if any are still asserted. + * + * Note: The scan only has to go from irq_nr + 0x20 to the max + * index, since any lower interrupt cannot be asserted + * at this time. + */ + int i, max = 0x1000; + cpu->cd.sh.int_to_assert = 0; + + for (i=irq_nr+0x20; icd.sh.int_pending[word_index] == 0) + i += (sizeof(uint32_t)*8 - 1) * 0x20; + else if (cpu->cd.sh.int_pending[word_index] + & (1 << bit_index)) { + cpu->cd.sh.int_to_assert = i; + break; + } + } + } + + irq_nr /= 0x20; + word_index = irq_nr / (sizeof(uint32_t)*8); + bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1); + + cpu->cd.sh.int_pending[word_index] &= ~(1 << bit_index); + return 0; } /* * sh_update_sr(): + * + * Writes a new value to the status register. */ void sh_update_sr(struct cpu *cpu, uint32_t new_sr) { uint32_t old_sr = cpu->cd.sh.sr; if ((new_sr & SH_SR_RB) != (old_sr & SH_SR_RB)) { - fatal("sh_update_sr(): Register bank switching is not" - " implemented yet! TODO\n"); - exit(1); + int i; + for (i=0; icd.sh.r[i]; + cpu->cd.sh.r[i] = cpu->cd.sh.r_bank[i]; + cpu->cd.sh.r_bank[i] = tmp; + } } cpu->cd.sh.sr = new_sr; @@ -305,6 +508,132 @@ /* + * sh_update_fpscr(): + * + * Writes a new value to the floating-point status/control register. + */ +void sh_update_fpscr(struct cpu *cpu, uint32_t new_fpscr) +{ + uint32_t old_fpscr = cpu->cd.sh.fpscr; + + if ((new_fpscr & SH_FPSCR_FR) != (old_fpscr & SH_FPSCR_FR)) { + int i; + for (i=0; icd.sh.fr[i]; + cpu->cd.sh.fr[i] = cpu->cd.sh.xf[i]; + cpu->cd.sh.xf[i] = tmp; + } + } + + cpu->cd.sh.fpscr = new_fpscr; +} + + +/* + * sh_exception(): + * + * Causes a transfer of control to an exception or interrupt handler. + * If intevt > 0, then it is an interrupt, otherwise an exception. + */ +void sh_exception(struct cpu *cpu, int expevt, int intevt, uint32_t vaddr) +{ + uint32_t vbr = cpu->cd.sh.vbr; + + if (!quiet_mode) { + if (intevt > 0) + debug("[ interrupt 0x%03x", intevt); + else + debug("[ exception 0x%03x", expevt); + + debug(", pc=0x%08"PRIx32" ", (uint32_t)vaddr); + if (intevt == 0) + debug("vaddr=0x%08"PRIx32" ", vaddr); + + debug(" ]\n"); + } + + if (cpu->cd.sh.sr & SH_SR_BL) { + fatal("sh_exception(): BL bit already set. TODO\n"); + + /* This is actually OK in two cases: a User Break, + or on NMI interrupts if a special flag is set? */ + /* TODO */ + + expevt = EXPEVT_RESET_POWER; + } + + if (cpu->is_halted) { + /* + * If the exception occurred on a 'sleep' instruction, then let + * the instruction following the sleep instruction be the one + * where execution resumes when the interrupt service routine + * returns. + */ + cpu->is_halted = 0; + cpu->pc += sizeof(uint16_t); + } + + if (cpu->delay_slot) { + cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT; + cpu->pc -= sizeof(uint16_t); + } + + /* Stuff common to all exceptions: */ + cpu->cd.sh.spc = cpu->pc; + cpu->cd.sh.ssr = cpu->cd.sh.sr; + cpu->cd.sh.sgr = cpu->cd.sh.r[15]; + if (intevt > 0) { + cpu->cd.sh.intevt = intevt; + expevt = -1; + } else + cpu->cd.sh.expevt = expevt; + sh_update_sr(cpu, cpu->cd.sh.sr | SH_SR_MD | SH_SR_RB | SH_SR_BL); + + /* Most exceptions set PC to VBR + 0x100. */ + cpu->pc = vbr + 0x100; + + /* Specific cases: */ + switch (expevt) { + + case -1: /* Interrupt */ + cpu->pc = vbr + 0x600; + break; + + case EXPEVT_RESET_POWER: + case EXPEVT_RESET_MANUAL: + cpu->pc = 0xa0000000; + cpu->cd.sh.vbr = 0x00000000; + sh_update_sr(cpu, (cpu->cd.sh.sr | SH_SR_IMASK) & ~SH_SR_FD); + break; + + case EXPEVT_TLB_MISS_LD: + case EXPEVT_TLB_MISS_ST: + cpu->pc = vbr + 0x400; + case EXPEVT_TLB_PROT_LD: + case EXPEVT_TLB_PROT_ST: + case EXPEVT_TLB_MOD: + cpu->cd.sh.tea = vaddr; + cpu->cd.sh.pteh &= ~SH4_PTEH_VPN_MASK; + cpu->cd.sh.pteh |= (vaddr & SH4_PTEH_VPN_MASK); + break; + + case EXPEVT_TRAPA: + /* Note: The TRA register is already set by the + implementation of the trapa instruction. See + cpu_sh_instr.c. */ + cpu->cd.sh.spc += sizeof(uint16_t); + break; + + default:fatal("sh_exception(): exception 0x%x is not yet " + "implemented.\n", expevt); + exit(1); + } + + sh_pc_to_pointers(cpu); +} + + +/* * sh_cpu_disassemble_instr_compact(): * * SHcompact instruction disassembly. The top 4 bits of each 16-bit @@ -323,7 +652,7 @@ else iword = (instr[1] << 8) + instr[0]; - debug(": %04x \t", iword); + debug(": %04x %s\t", iword, cpu->delay_slot? "(d)" : ""); hi4 = iword >> 12; lo4 = iword & 15; lo8 = iword & 255; r8 = (iword >> 8) & 15; r4 = (iword >> 4) & 15; @@ -367,20 +696,52 @@ debug("div0u\n"); else if (lo8 == 0x1a) debug("sts\tmacl,r%i\n", r8); + else if (iword == 0x001b) + debug("sleep\n"); + else if (lo8 == 0x22) + debug("stc\tvbr,r%i\n", r8); else if (lo8 == 0x23) debug("braf\tr%i\n", r8); else if (iword == 0x0028) debug("clrmac\n"); else if (lo8 == 0x29) debug("movt\tr%i\n", r8); + else if (lo8 == 0x2a) + debug("sts\tpr,r%i\n", r8); + else if (iword == 0x002b) + debug("rte\n"); + else if (lo8 == 0x32) + debug("stc\tssr,r%i\n", r8); + else if (iword == 0x0038) + debug("ldtlb\n"); else if (iword == 0x003b) debug("brk\n"); + else if (lo8 == 0x42) + debug("stc\tspc,r%i\n", r8); else if (iword == 0x0048) debug("clrs\n"); else if (iword == 0x0058) debug("sets\n"); + else if (lo8 == 0x5a) + debug("sts\tfpul,r%i\n", r8); + else if (lo8 == 0x6a) + debug("sts\tfpscr,r%i\n", r8); + else if ((lo8 & 0x8f) == 0x82) + debug("stc\tr%i_bank,r%i\n", (lo8 >> 4) & 7, r8); else if (lo8 == 0x83) debug("pref\t@r%i\n", r8); + else if (lo8 == 0x93) + debug("ocbi\t@r%i\n", r8); + else if (lo8 == 0xa3) + debug("ocbp\t@r%i\n", r8); + else if (lo8 == 0xb3) + debug("ocbwb\t@r%i\n", r8); + else if (lo8 == 0xc3) + debug("movca.l\tr0,@r%i\n", r8); + else if (lo8 == 0xfa) + debug("stc\tdbr,r%i\n", r8); + else if (iword == 0x00ff) + debug("gxemul_dreamcast_prom_emul\n"); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8); break; @@ -458,12 +819,18 @@ debug("shll\tr%i\n", r8); else if (lo8 == 0x01) debug("shlr\tr%i\n", r8); + else if (lo8 == 0x02) + debug("sts.l\tmach,@-r%i\n", r8); + else if (lo8 == 0x03) + debug("stc.l\tsr,@-r%i\n", r8); else if (lo8 == 0x04) debug("rotl\tr%i\n", r8); else if (lo8 == 0x05) debug("rotr\tr%i\n", r8); else if (lo8 == 0x06) debug("lds.l\t@r%i+,mach\n", r8); + else if (lo8 == 0x07) + debug("ldc.l\t@r%i+,sr\n", r8); else if (lo8 == 0x08) debug("shll2\tr%i\n", r8); else if (lo8 == 0x09) @@ -482,10 +849,16 @@ debug("dt\tr%i\n", r8); else if (lo8 == 0x11) debug("cmp/pz\tr%i\n", r8); + else if (lo8 == 0x12) + debug("sts.l\tmacl,@-r%i\n", r8); + else if (lo8 == 0x13) + debug("stc.l\tgbr,@-r%i\n", r8); else if (lo8 == 0x15) debug("cmp/pl\tr%i\n", r8); else if (lo8 == 0x16) debug("lds.l\t@r%i+,macl\n", r8); + else if (lo8 == 0x17) + debug("ldc.l\t@r%i+,gbr\n", r8); else if (lo8 == 0x18) debug("shll8\tr%i\n", r8); else if (lo8 == 0x19) @@ -502,12 +875,16 @@ debug("shar\tr%i\n", r8); else if (lo8 == 0x22) debug("sts.l\tpr,@-r%i\n", r8); + else if (lo8 == 0x23) + debug("stc.l\tvbr,@-r%i\n", r8); else if (lo8 == 0x24) debug("rotcl\tr%i\n", r8); else if (lo8 == 0x25) debug("rotcr\tr%i\n", r8); else if (lo8 == 0x26) debug("lds.l\t@r%i+,pr\n", r8); + else if (lo8 == 0x27) + debug("ldc.l\t@r%i+,vbr\n", r8); else if (lo8 == 0x28) debug("shll16\tr%i\n", r8); else if (lo8 == 0x29) @@ -516,12 +893,40 @@ debug("lds\tr%i,pr\n", r8); else if (lo8 == 0x2b) debug("jmp\t@r%i\n", r8); + else if (lo8 == 0x2e) + debug("ldc\tr%i,vbr\n", r8); + else if (lo8 == 0x33) + debug("stc.l\tssr,@-r%i\n", r8); + else if (lo8 == 0x37) + debug("ldc.l\t@r%i+,ssr\n", r8); + else if (lo8 == 0x3e) + debug("ldc\tr%i,ssr\n", r8); + else if (lo8 == 0x43) + debug("stc.l\tspc,@-r%i\n", r8); + else if (lo8 == 0x47) + debug("ldc.l\t@r%i+,spc\n", r8); + else if (lo8 == 0x4e) + debug("ldc\tr%i,spc\n", r8); + else if (lo8 == 0x52) + debug("sts.l\tfpul,@-r%i\n", r8); else if (lo8 == 0x56) debug("lds.l\t@r%i+,fpul\n", r8); else if (lo8 == 0x5a) debug("lds\tr%i,fpul\n", r8); + else if (lo8 == 0x62) + debug("sts.l\tfpscr,@-r%i\n", r8); + else if (lo8 == 0x66) + debug("lds.l\t@r%i+,fpscr\n", r8); else if (lo8 == 0x6a) debug("lds\tr%i,fpscr\n", r8); + else if ((lo8 & 0x8f) == 0x83) + debug("stc.l\tr%i_bank,@-r%i\n", (lo8 >> 4) & 7, r8); + else if ((lo8 & 0x8f) == 0x87) + debug("ldc.l\t@r%i,r%i_bank\n", r8, (lo8 >> 4) & 7, r8); + else if ((lo8 & 0x8f) == 0x8e) + debug("ldc\tr%i,r%i_bank\n", r8, (lo8 >> 4) & 7); + else if (lo8 == 0xfa) + debug("ldc\tr%i,dbr\n", r8); else debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8); break; @@ -539,6 +944,8 @@ debug("mov\tr%i,r%i\n", r4, r8); else if (lo4 == 0x4) debug("mov.b\t@r%i+,r%i\n", r4, r8); + else if (lo4 == 0x5) + debug("mov.w\t@r%i+,r%i\n", r4, r8); else if (lo4 == 0x6) debug("mov.l\t@r%i+,r%i\n", r4, r8); else if (lo4 == 0x7) @@ -566,9 +973,17 @@ debug("add\t#%i,r%i\n", (int8_t)lo8, r8); break; case 0x8: - if (r8 == 0x8) + if (r8 == 0x0) { + debug("mov.b\tr0,@(%i,r%i)\n", lo4, r4); + } else if (r8 == 0x1) { + debug("mov.w\tr0,@(%i,r%i)\n", lo4 * 2, r4); + } else if (r8 == 0x4) { + debug("mov.b\t@(%i,r%i),r0\n", lo4, r4); + } else if (r8 == 0x5) { + debug("mov.w\t@(%i,r%i),r0\n", lo4 * 2, r4); + } else if (r8 == 0x8) { debug("cmp/eq\t#%i,r0\n", (int8_t)lo8); - else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) { + } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) { addr = (int8_t)lo8; addr = dumpaddr + 4 + (addr << 1); debug("b%s%s\t0x%x\n", @@ -591,9 +1006,24 @@ debug("%s\t0x%x\n", hi4==0xa? "bra":"bsr", (int)addr); break; case 0xc: - if (r8 == 0x3) + if (r8 == 0x0) + debug("mov.b\tr0,@(%i,gbr)\n", lo8); + else if (r8 == 0x1) + debug("mov.w\tr0,@(%i,gbr)\n", lo8 * 2); + else if (r8 == 0x2) + debug("mov.l\tr0,@(%i,gbr)\n", lo8 * 4); + else if (r8 == 0x3) debug("trapa\t#%i\n", (uint8_t)lo8); - else if (r8 == 0x8) + else if (r8 == 0x4) + debug("mov.b\t(%i,gbr),r0\n", lo8); + else if (r8 == 0x5) + debug("mov.w\t(%i,gbr),r0\n", lo8 * 2); + else if (r8 == 0x6) + debug("mov.l\t(%i,gbr),r0\n", lo8 * 4); + else if (r8 == 0x7) { + addr = lo8 * 4 + (dumpaddr & ~3) + 4; + debug("mova\t0x%x,r0\n", (int)addr); + } else if (r8 == 0x8) debug("tst\t#%i,r0\n", (uint8_t)lo8); else if (r8 == 0x9) debug("and\t#%i,r0\n", (uint8_t)lo8); @@ -615,6 +1045,117 @@ case 0xe: debug("mov\t#%i,r%i\n", (int8_t)lo8, r8); break; + case 0xf: + if (lo4 == 0x0) + debug("fadd\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x1) + debug("fsub\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x2) + debug("fmul\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x3) + debug("fdiv\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x4) + debug("fcmp/eq\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x5) + debug("fcmp/gt\t%sr%i,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r4, + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo4 == 0x6) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r8 & 1)? "xd" : "dr"; + r8 &= ~1; + } + debug("fmov\t@(r0,r%i),%s%i\n", r4, n, r8); + } else if (lo4 == 0x7) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r4 & 1)? "xd" : "dr"; + r4 &= ~1; + } + debug("fmov\t%s%i,@(r0,r%i)\n", n, r4, r8); + } else if (lo4 == 0x8) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r8 & 1)? "xd" : "dr"; + r8 &= ~1; + } + debug("fmov\t@r%i,%s%i\n", r4, n, r8); + } else if (lo4 == 0x9) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r8 & 1)? "xd" : "dr"; + r8 &= ~1; + } + debug("fmov\t@r%i+,%s%i\n", r4, n, r8); + } else if (lo4 == 0xa) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r4 & 1)? "xd" : "dr"; + r4 &= ~1; + } + debug("fmov\t%s%i,@r%i\n", n, r4, r8); + } else if (lo4 == 0xb) { + char *n = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n = (r4 & 1)? "xd" : "dr"; + r4 &= ~1; + } + debug("fmov\t%s%i,@-r%i\n", n, r4, r8); + } else if (lo4 == 0xc) { + char *n1 = "fr", *n2 = "fr"; + if (cpu->cd.sh.fpscr & SH_FPSCR_SZ) { + n1 = (r4 & 1)? "xd" : "dr"; + n2 = (r8 & 1)? "xd" : "dr"; + r4 &= ~1; r8 &= ~1; + } + debug("fmov\t%s%i,%s%i\n", n1, r4, n2, r8); + } else if (lo8 == 0x0d) + debug("fsts\tfpul,fr%i\n", r8); + else if (lo8 == 0x1d) + debug("flds\tfr%i,fpul\n", r8); + else if (lo8 == 0x2d) + debug("float\tfpul,%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo8 == 0x3d) + debug("ftrc\t%sr%i,fpul\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo8 == 0x4d) + debug("fneg\t%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo8 == 0x5d) + debug("fabs\t%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo8 == 0x6d) + debug("fsqrt\t%sr%i\n", + cpu->cd.sh.fpscr & SH_FPSCR_PR? "d" : "f", r8); + else if (lo8 == 0x8d) + debug("fldi0\tfr%i\n", r8); + else if (lo8 == 0x9d) + debug("fldi1\tfr%i\n", r8); + else if ((iword & 0x01ff) == 0x00fd) + debug("fsca\tfpul,dr%i\n", r8); + else if (iword == 0xf3fd) + debug("fschg\n"); + else if (iword == 0xfbfd) + debug("frchg\n"); + else if ((iword & 0xf3ff) == 0xf1fd) + debug("ftrv\txmtrx,fv%i\n", r8 & 0xc); + else if (lo4 == 0xe) + debug("fmac\tfr0,fr%i,fr%i\n", r4, r8); + else + debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, lo8); + break; default:debug("UNIMPLEMENTED hi4=0x%x\n", hi4); }