diff --git a/tools/virtualmips/m4k.c b/tools/virtualmips/m4k.c index 77daf8a..ef8ab80 100644 --- a/tools/virtualmips/m4k.c +++ b/tools/virtualmips/m4k.c @@ -299,9 +299,10 @@ int init_instance (vm_instance_t * vm) cpu->cp0.config_reg[3] = 0x00000020; /* set PC and PRID */ - cpu->cp0.reg[MIPS_CP0_PRID] = 0x00018700; - cpu->cp0.tlb_entries = 0; cpu->pc = m4k->start_address; + cpu->cp0.tlb_entries = 0; + cpu->cp0.reg[MIPS_CP0_PRID] = 0x00018700; + cpu->cp0.reg[MIPS_CP0_DEBUG] = 0x00010000; /* Enable magic opcodes. */ cpu->magic_opcodes = 1; diff --git a/tools/virtualmips/mips.c b/tools/virtualmips/mips.c index 552cee4..a227ff1 100644 --- a/tools/virtualmips/mips.c +++ b/tools/virtualmips/mips.c @@ -505,6 +505,70 @@ void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot) cpu->irq_pending = 0; } +/* + * Generate a Debug exception + */ +void mips_trigger_debug_exception (cpu_mips_t *cpu, u_int dexc_type) +{ + mips_cp0_t *cp0 = &cpu->cp0; + int old_dm = cpu->cp0.reg[MIPS_CP0_DEBUG] & MIPS_CP0_DEBUG_DM; + + /* Set DEPC. */ + cp0->reg[MIPS_CP0_DEPC] = cpu->pc; + + /* Update exception type bits. */ + cpu->cp0.reg[MIPS_CP0_DEBUG] &= ~(MIPS_CP0_DEBUG_DSS | + MIPS_CP0_DEBUG_DBP | MIPS_CP0_DEBUG_DDBL | MIPS_CP0_DEBUG_DDBS | + MIPS_CP0_DEBUG_DIB | MIPS_CP0_DEBUG_DINT | + MIPS_CP0_DEBUG_DDBLIMPR | MIPS_CP0_DEBUG_DDBSIMPR); + if (! old_dm) { + cpu->cp0.reg[MIPS_CP0_DEBUG] |= dexc_type; + } + + /* Update delay slot flag. */ + if (cpu->is_in_bdslot) + cpu->cp0.reg[MIPS_CP0_DEBUG] |= MIPS_CP0_DEBUG_DBD; + else + cpu->cp0.reg[MIPS_CP0_DEBUG] &= ~MIPS_CP0_DEBUG_DBD; + + /* Set Debug mode. */ + cpu->cp0.reg[MIPS_CP0_DEBUG] |= MIPS_CP0_DEBUG_DM; + cpu->cp0.reg[MIPS_CP0_DEBUG] |= MIPS_CP0_DEBUG_IEXI; + + if (cpu->vm->debug_level > 2) { + char *type = 0; + printf ("--- 0x%08x: ", cpu->pc); + + if (old_dm) + type = " Debug exception in Debug mode"; + else + switch (dexc_type) { + case MIPS_CP0_DEBUG_DSS: type = "Debug Single Step exception"; break; + case MIPS_CP0_DEBUG_DBP: type = "Debug Breakpoint exception"; break; + case MIPS_CP0_DEBUG_DDBL: type = "Debug Data Break Load exception"; break; + case MIPS_CP0_DEBUG_DDBS: type = "Debug Data Break Store exception"; break; + case MIPS_CP0_DEBUG_DIB: type = "Debug Instruction Break exception"; break; + case MIPS_CP0_DEBUG_DINT: type = "Debug Interrupt exception"; break; + case MIPS_CP0_DEBUG_DDBLIMPR: type = "Debug Data Break Load Impresize exception"; break; + case MIPS_CP0_DEBUG_DDBSIMPR: type = "Debug Data Break Store Impresize exception"; break; + } + if (type) + printf ("%s\n", type); + else + printf ("Debug exception %#x\n", dexc_type); + + printf (" c0_debug := %08x\n", cpu->cp0.reg[MIPS_CP0_DEBUG]); + printf (" c0_depc := %08x\n", cpu->cp0.reg[MIPS_CP0_DEPC]); + } + + /* Debug exception vector. */ + cpu->pc = (m_va_t) 0xffffffffbfc00480ULL; + cpu->is_mips16e = 0; + + /* Clear the pending IRQ flag */ + cpu->irq_pending = 0; +} + /* Execute fpu instruction */ void fastcall mips_exec_soft_fpu (cpu_mips_t * cpu) { diff --git a/tools/virtualmips/mips.h b/tools/virtualmips/mips.h index 02ec3dc..6c5fd7d 100644 --- a/tools/virtualmips/mips.h +++ b/tools/virtualmips/mips.h @@ -76,6 +76,8 @@ #define MIPS_CP0_WATCHLO 18 /* Low Watch address */ #define MIPS_CP0_WATCHHI 19 /* High Watch address */ #define MIPS_CP0_XCONTEXT 20 /* Extended context */ +#define MIPS_CP0_DEBUG 23 /* Debug */ +#define MIPS_CP0_DEPC 24 /* DEPC */ #define MIPS_CP0_ECC 26 /* ECC and parity */ #define MIPS_CP0_CACHERR 27 /* Cache Err/Status */ #define MIPS_CP0_TAGLO 28 /* Cache Tag Lo */ @@ -127,7 +129,6 @@ /* * CP0 Cause register */ - #define MIPS_CP0_CAUSE_BD_SLOT 0x80000000 #define MIPS_CP0_CAUSE_MASK 0x0000007C @@ -175,6 +176,25 @@ #define MIPS_CP0_CONTEXT_PTEBASE_MASK 0xff800000 #define MIPS_CP0_CONTEXT_BADVPN2_MASK 0x0007ffff0 +/* + * CP0 Debug register + */ +#define MIPS_CP0_DEBUG_DBD 0x80000000 /* Debug exception on delay slot */ +#define MIPS_CP0_DEBUG_DM 0x40000000 /* Debug mode */ +#define MIPS_CP0_DEBUG_IEXI 0x00100000 /* Imprecise Error eXception Inhibit */ +#define MIPS_CP0_DEBUG_DDBSIMPR 0x00080000 /* Debug Data Break Store Impresize exception */ +#define MIPS_CP0_DEBUG_DDBLIMPR 0x00040000 /* Debug Data Break Load Impresize exception */ +#define MIPS_CP0_DEBUG_DEXCCODE 0x00003c00 /* Debug exception code */ +#define MIPS_CP0_DEBUG_DEXCCODE_SHIFT 10 +#define MIPS_CP0_DEBUG_DINT 0x00000020 /* Debug Interrupt exception */ +#define MIPS_CP0_DEBUG_DIB 0x00000010 /* Debug Instruction Break exception */ +#define MIPS_CP0_DEBUG_DDBS 0x00000008 /* Debug Data Break Store exception */ +#define MIPS_CP0_DEBUG_DDBL 0x00000004 /* Debug Data Break Load exception */ +#define MIPS_CP0_DEBUG_DBP 0x00000002 /* Debug Breakpoint exception */ +#define MIPS_CP0_DEBUG_DSS 0x00000001 /* Debug Single Step exception */ + +#define MIPS_CP0_DEBUG_WMASK 0x10700180 /* Writable bits */ + /* TLB masks and shifts */ #define MIPS_TLB_PAGE_MASK 0x01ffe000 #define MIPS_TLB_PAGE_SHIFT 13 @@ -479,6 +499,7 @@ int mips_load_elf_image (cpu_mips_t * cpu, char *filename, void mips_delete (cpu_mips_t * cpu); int fastcall mips_update_irq_flag (cpu_mips_t * cpu); void mips_trigger_exception (cpu_mips_t * cpu, u_int exc_code, int bd_slot); +void mips_trigger_debug_exception (cpu_mips_t * cpu, u_int dexc_type); void fastcall mips_exec_soft_fpu (cpu_mips_t * cpu); void fastcall mips_exec_eret (cpu_mips_t * cpu); void fastcall mips_exec_break (cpu_mips_t * cpu, u_int code); diff --git a/tools/virtualmips/mips_codetable.c b/tools/virtualmips/mips_codetable.c index 4dd5d25..c95cf48 100644 --- a/tools/virtualmips/mips_codetable.c +++ b/tools/virtualmips/mips_codetable.c @@ -1813,6 +1813,26 @@ static int xori_op (cpu_mips_t * cpu, mips_insn_t insn) return (0); } +static int sdbbp_op (cpu_mips_t * cpu, mips_insn_t insn) +{ + /* Clear status of previos Debug exception. */ + cpu->cp0.reg[MIPS_CP0_DEBUG] &= ~MIPS_CP0_DEBUG_DEXCCODE; + + if (cpu->cp0.reg[MIPS_CP0_DEBUG] & MIPS_CP0_DEBUG_DM) { + /* Already in Debug mode: take nested debug exception. */ + mips_trigger_debug_exception (cpu, 0); + + /* Set nested exception type. */ + cpu->cp0.reg[MIPS_CP0_DEBUG] |= + MIPS_CP0_CAUSE_BP << MIPS_CP0_DEBUG_DEXCCODE_SHIFT; + + } else { + /* Take a Breakpoint exception. */ + mips_trigger_debug_exception (cpu, MIPS_CP0_DEBUG_DBP); + } + return 1; +} + static int undef_op (cpu_mips_t * cpu, mips_insn_t insn) { return unknown_op (cpu, insn); @@ -2131,7 +2151,7 @@ static const struct mips_op_desc mips_spec2_opcodes[] = { {"?spec2", undef_spec2,0x3c}, {"?spec2", undef_spec2,0x3d}, {"?spec2", undef_spec2,0x3e}, - {"?spec2", undef_spec2,0x3f}, + {"?spec2", sdbbp_op, 0x3f}, }; /* diff --git a/tools/virtualmips/mips_cp0.c b/tools/virtualmips/mips_cp0.c index 9bcce2a..15893ef 100644 --- a/tools/virtualmips/mips_cp0.c +++ b/tools/virtualmips/mips_cp0.c @@ -227,6 +227,14 @@ void mips_cp0_set_reg (cpu_mips_t * cpu, u_int cp0_reg, u_int sel, } break; + case MIPS_CP0_DEBUG: + /* Only some bits of Debug register are writable. */ + if (sel != 0) + goto unimpl; + cp0->reg[cp0_reg] &= ~MIPS_CP0_DEBUG_WMASK; + cp0->reg[cp0_reg] |= val & MIPS_CP0_DEBUG_WMASK; + break; + default: if (sel != 0) { unimpl: fprintf (stderr,