diff --git a/Source/3rdParty/mupen64plus-core/src/device/device.c b/Source/3rdParty/mupen64plus-core/src/device/device.c index 2c415fb6..5fd47e01 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/device.c +++ b/Source/3rdParty/mupen64plus-core/src/device/device.c @@ -129,6 +129,7 @@ void init_device(struct device* dev, { &dev->dd, dd_mecha_int_handler }, /* DD MECHA */ { &dev->dd, dd_bm_int_handler }, /* DD BM */ { &dev->dd, dd_dv_int_handler }, /* DD DRIVE */ + { &dev->sp, rsp_task_event }, }; #define R(x) read_ ## x diff --git a/Source/3rdParty/mupen64plus-core/src/device/r4300/cp0.h b/Source/3rdParty/mupen64plus-core/src/device/r4300/cp0.h index 47a15a7c..dc76586c 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/r4300/cp0.h +++ b/Source/3rdParty/mupen64plus-core/src/device/r4300/cp0.h @@ -173,7 +173,7 @@ struct interrupt_handler void (*callback)(void*); }; -enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 }; +enum { CP0_INTERRUPT_HANDLERS_COUNT = 17 }; enum { INTR_UNSAFE_R4300 = 0x01, diff --git a/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.c b/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.c index 9c81a184..db1d84dc 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.c +++ b/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.c @@ -438,6 +438,9 @@ void nmi_int_handler(void* opaque) reset_pif(&dev->pif, 1); + // HACK: reset rsp state + poweron_rsp(&dev->sp); + // setup r4300 Status flags: reset TS and SR, set BEV, ERL, and SR cp0_regs[CP0_STATUS_REG] = (cp0_regs[CP0_STATUS_REG] & ~(CP0_STATUS_SR | CP0_STATUS_TS | UINT32_C(0x00080000))) | (CP0_STATUS_ERL | CP0_STATUS_BEV | CP0_STATUS_SR); cp0_regs[CP0_CAUSE_REG] = 0x00000000; @@ -656,6 +659,11 @@ void gen_interrupt(struct r4300_core* r4300) call_interrupt_handler(&r4300->cp0, 15); break; + case RSP_TSK_EVT: + remove_interrupt_event(&r4300->cp0); + call_interrupt_handler(&r4300->cp0, 16); + break; + default: DebugMessage(M64MSG_ERROR, "Unknown interrupt queue event type %.8X.", r4300->cp0.q.first->data.type); remove_interrupt_event(&r4300->cp0); diff --git a/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.h b/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.h index 3963cdc9..bf8631bf 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.h +++ b/Source/3rdParty/mupen64plus-core/src/device/r4300/interrupt.h @@ -69,5 +69,6 @@ void nmi_int_handler(void* opaque); #define DD_MC_INT 0x1000 #define DD_BM_INT 0x2000 #define DD_DV_INT 0x4000 +#define RSP_TSK_EVT 0x8000 #endif /* M64P_DEVICE_R4300_INTERRUPT_H */ diff --git a/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.c b/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.c index 3063aa1b..45bc048b 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.c +++ b/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.c @@ -26,6 +26,7 @@ #include "device/memory/memory.h" #include "device/rcp/mi/mi_controller.h" #include "device/rcp/rsp/rsp_core.h" +#include "device/r4300/r4300_core.h" #include "plugin/plugin.h" static void update_dpc_status(struct rdp_core* dp, uint32_t w) @@ -40,7 +41,11 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FREEZE; if (dp->do_on_unfreeze & DELAY_DP_INT) + { signal_rcp_interrupt(dp->mi, MI_INTR_DP); + + clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC); + } if (dp->do_on_unfreeze & DELAY_UPDATESCREEN) gfx.updateScreen(); dp->do_on_unfreeze = 0; @@ -51,6 +56,22 @@ static void update_dpc_status(struct rdp_core* dp, uint32_t w) if (w & DPC_CLR_FLUSH) dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_FLUSH; if (w & DPC_SET_FLUSH) dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_FLUSH; + if (w & DPC_CLR_TMEM_CTR) + { + dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_TMEM_BUSY; + dp->dpc_regs[DPC_TMEM_REG] = 0; + } + if (w & DPC_CLR_PIPE_CTR) + { + dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_PIPE_BUSY; + dp->dpc_regs[DPC_PIPEBUSY_REG] = 0; + } + if (w & DPC_CLR_CMD_CTR) + { + dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_CMD_BUSY; + dp->dpc_regs[DPC_BUFBUSY_REG] = 0; + } + /* clear clock counter */ if (w & DPC_CLR_CLOCK_CTR) dp->dpc_regs[DPC_CLOCK_REG] = 0; } @@ -73,7 +94,7 @@ void poweron_rdp(struct rdp_core* dp) { memset(dp->dpc_regs, 0, DPC_REGS_COUNT*sizeof(uint32_t)); memset(dp->dps_regs, 0, DPS_REGS_COUNT*sizeof(uint32_t)); - dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK; + dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_GCLK | DPC_STATUS_PIPE_BUSY | DPC_STATUS_CBUF_READY; dp->do_on_unfreeze = 0; @@ -106,18 +127,37 @@ void write_dpc_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas return; } - masked_write(&dp->dpc_regs[reg], value, mask); - switch(reg) { case DPC_START_REG: - dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG]; + if (!(dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID)) + { + masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask); + } + dp->dpc_regs[DPC_STATUS_REG] |= DPC_STATUS_START_VALID; break; case DPC_END_REG: + masked_write(&dp->dpc_regs[reg], value & UINT32_C(0xFFFFF8), mask); + if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_START_VALID) + { + dp->dpc_regs[DPC_CURRENT_REG] = dp->dpc_regs[DPC_START_REG]; + dp->dpc_regs[DPC_STATUS_REG] &= ~DPC_STATUS_START_VALID; + } unprotect_framebuffers(&dp->fb); gfx.processRDPList(); protect_framebuffers(&dp->fb); - signal_rcp_interrupt(dp->mi, MI_INTR_DP); + if (dp->mi->regs[MI_INTR_REG] & MI_INTR_DP) + { + dp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP; + if (dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) { + dp->do_on_unfreeze |= DELAY_DP_INT; + } else { + add_interrupt_event(&dp->mi->r4300->cp0, DP_INT, dp->dpc_regs[DPC_CLOCK_REG]); + } + } + break; + default: + masked_write(&dp->dpc_regs[reg], value, mask); break; } } @@ -150,5 +190,7 @@ void rdp_interrupt_event(void* opaque) struct rdp_core* dp = (struct rdp_core*)opaque; raise_rcp_interrupt(dp->mi, MI_INTR_DP); + + clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC); } diff --git a/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.h b/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.h index 57997a1b..d7e977fd 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.h +++ b/Source/3rdParty/mupen64plus-core/src/device/rcp/rdp/rdp_core.h @@ -37,7 +37,11 @@ enum DPC_STATUS_FREEZE = 0x002, DPC_STATUS_FLUSH = 0x004, DPC_STATUS_START_GCLK = 0x008, + DPC_STATUS_TMEM_BUSY = 0x010, + DPC_STATUS_PIPE_BUSY = 0x020, + DPC_STATUS_CMD_BUSY = 0x040, DPC_STATUS_CBUF_READY = 0x080, + DPC_STATUS_DMA_BUSY = 0x100, DPC_STATUS_END_VALID = 0x200, DPC_STATUS_START_VALID = 0x400, /* DPC status - write */ diff --git a/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.c b/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.c index 99767bc0..926db841 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.c +++ b/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.c @@ -76,16 +76,20 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma) pre_framebuffer_read(&sp->dp->fb, dramaddr); for(i=0; iregs[SP_MEM_ADDR_REG] = (memaddr & 0xfff) + (dma->memaddr & 0x1000); + sp->regs[SP_DRAM_ADDR_REG] = dramaddr; + sp->regs[SP_MEM_ADDR_REG] = memaddr & 0xfff; sp->regs[SP_DRAM_ADDR_REG] = dramaddr & 0xffffff; sp->regs[SP_RD_LEN_REG] = 0xff8; + sp->regs[SP_WR_LEN_REG] = 0xff8; } /* schedule end of dma event */ @@ -146,69 +150,87 @@ static void fifo_pop(struct rsp_core* sp) static void update_sp_status(struct rsp_core* sp, uint32_t w) { /* clear / set halt */ - if ((w & 0x3) == 0x1) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT; - if ((w & 0x3) == 0x2) sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT; + if ((w & SP_CLR_HALT) && !(w & SP_SET_HALT)) + { + sp->rsp_wait &= ~WAIT_HALTED; + sp->regs[SP_STATUS_REG] &= ~SP_STATUS_HALT; + } + if ((w & SP_SET_HALT) && !(w & SP_CLR_HALT)) + { + remove_event(&sp->mi->r4300->cp0.q, SP_INT); + sp->rsp_status = 0; + sp->first_run = 1; + sp->rsp_wait |= WAIT_HALTED; + sp->regs[SP_STATUS_REG] |= SP_STATUS_HALT; + } /* clear broke */ - if (w & 0x4) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE; + if (w & SP_CLR_BROKE) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_BROKE; /* clear SP interrupt */ - if ((w & 0x18) == 0x8) + if ((w & SP_CLR_INTR) && !(w & SP_SET_INTR)) { clear_rcp_interrupt(sp->mi, MI_INTR_SP); } /* set SP interrupt */ - if ((w & 0x18) == 0x10) + if ((w & SP_SET_INTR) && !(w & SP_CLR_INTR)) { signal_rcp_interrupt(sp->mi, MI_INTR_SP); } /* clear / set single step */ - if ((w & 0x60) == 0x20) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP; - if ((w & 0x60) == 0x40) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP; + if ((w & SP_CLR_SSTEP) && !(w & SP_SET_SSTEP)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SSTEP; + if ((w & SP_SET_SSTEP) && !(w & SP_CLR_SSTEP)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SSTEP; /* clear / set interrupt on break */ - if ((w & 0x180) == 0x80) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK; - if ((w & 0x180) == 0x100) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK; + if ((w & SP_CLR_INTR_BREAK) && !(w & SP_SET_INTR_BREAK)) + { + if (sp->rsp_wait & WAIT_PENDING_SP_INT_BROKE) + { + // If a game clears SP_SET_INTR_BREAK before the interrupt happens, + // that means it would have been cleared before the BREAK command + remove_event(&sp->mi->r4300->cp0.q, SP_INT); + sp->rsp_wait &= ~WAIT_PENDING_SP_INT_BROKE; + sp->regs[SP_STATUS_REG] = sp->rsp_status; + sp->rsp_status = 0; + } + sp->regs[SP_STATUS_REG] &= ~SP_STATUS_INTR_BREAK; + } + if ((w & SP_SET_INTR_BREAK) && !(w & SP_CLR_INTR_BREAK)) sp->regs[SP_STATUS_REG] |= SP_STATUS_INTR_BREAK; /* clear / set signal 0 */ - if ((w & 0x600) == 0x200) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0; - if ((w & 0x600) == 0x400) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0; + if ((w & SP_CLR_SIG0) && !(w & SP_SET_SIG0)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG0; + if ((w & SP_SET_SIG0) && !(w & SP_CLR_SIG0)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG0; /* clear / set signal 1 */ - if ((w & 0x1800) == 0x800) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1; - if ((w & 0x1800) == 0x1000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1; + if ((w & SP_CLR_SIG1) && !(w & SP_SET_SIG1)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG1; + if ((w & SP_SET_SIG1) && !(w & SP_CLR_SIG1)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG1; /* clear / set signal 2 */ - if ((w & 0x6000) == 0x2000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2; - if ((w & 0x6000) == 0x4000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2; + if ((w & SP_CLR_SIG2) && !(w & SP_SET_SIG2)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG2; + if ((w & SP_SET_SIG2) && !(w & SP_CLR_SIG2)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG2; /* clear / set signal 3 */ - if ((w & 0x18000) == 0x8000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3; - if ((w & 0x18000) == 0x10000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3; + if ((w & SP_CLR_SIG3) && !(w & SP_SET_SIG3)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG3; + if ((w & SP_SET_SIG3) && !(w & SP_CLR_SIG3)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG3; /* clear / set signal 4 */ - if ((w & 0x60000) == 0x20000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4; - if ((w & 0x60000) == 0x40000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4; + if ((w & SP_CLR_SIG4) && !(w & SP_SET_SIG4)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG4; + if ((w & SP_SET_SIG4) && !(w & SP_CLR_SIG4)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG4; /* clear / set signal 5 */ - if ((w & 0x180000) == 0x80000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5; - if ((w & 0x180000) == 0x100000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5; + if ((w & SP_CLR_SIG5) && !(w & SP_SET_SIG5)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG5; + if ((w & SP_SET_SIG5) && !(w & SP_CLR_SIG5)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG5; /* clear / set signal 6 */ - if ((w & 0x600000) == 0x200000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6; - if ((w & 0x600000) == 0x400000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6; + if ((w & SP_CLR_SIG6) && !(w & SP_SET_SIG6)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG6; + if ((w & SP_SET_SIG6) && !(w & SP_CLR_SIG6)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG6; /* clear / set signal 7 */ - if ((w & 0x1800000) == 0x800000) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7; - if ((w & 0x1800000) == 0x1000000) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7; + if ((w & SP_CLR_SIG7) && !(w & SP_SET_SIG7)) sp->regs[SP_STATUS_REG] &= ~SP_STATUS_SIG7; + if ((w & SP_SET_SIG7) && !(w & SP_CLR_SIG7)) sp->regs[SP_STATUS_REG] |= SP_STATUS_SIG7; - if (sp->rsp_task_locked && (get_event(&sp->mi->r4300->cp0.q, SP_INT))) return; - if (!((w & 0x3) == 1) && !(w & 0x4) && !sp->rsp_task_locked) - return; - - if (!(sp->regs[SP_STATUS_REG] & SP_STATUS_HALT)) - do_SP_Task(sp); + do_SP_Task(sp); } void init_rsp(struct rsp_core* sp, @@ -230,7 +252,9 @@ void poweron_rsp(struct rsp_core* sp) memset(sp->regs2, 0, SP_REGS2_COUNT*sizeof(uint32_t)); memset(sp->fifo, 0, SP_DMA_FIFO_SIZE*sizeof(struct sp_dma)); - sp->rsp_task_locked = 0; + sp->rsp_status = 0; + sp->first_run = 1; + sp->rsp_wait = 0; sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP; sp->regs[SP_STATUS_REG] = 1; sp->regs[SP_RD_LEN_REG] = 0xff8; @@ -286,6 +310,12 @@ void write_rsp_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mas switch(reg) { + case SP_MEM_ADDR_REG: + sp->regs[SP_MEM_ADDR_REG] &= 0x1ff8; + break; + case SP_DRAM_ADDR_REG: + sp->regs[SP_DRAM_ADDR_REG] &= 0xfffff8; + break; case SP_RD_LEN_REG: fifo_push(sp, SP_DMA_WRITE); break; @@ -317,7 +347,10 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma uint32_t reg = rsp_reg2(address); if (reg == SP_PC_REG) - mask &= 0xffc; + { + masked_write(&sp->regs2[SP_PC_REG], value & 0xffc, mask); + return; + } if (reg < SP_REGS2_COUNT) masked_write(&sp->regs2[reg], value, mask); @@ -325,97 +358,71 @@ void write_rsp_regs2(void* opaque, uint32_t address, uint32_t value, uint32_t ma void do_SP_Task(struct rsp_core* sp) { - uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff; + if (sp->rsp_wait) + return; + if (get_event(&sp->mi->r4300->cp0.q, RSP_TSK_EVT)) + return; - uint32_t sp_delay_time; + uint32_t saved_status = sp->regs[SP_STATUS_REG]; + uint32_t sp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_SP; + uint32_t dp_bit_set = sp->mi->regs[MI_INTR_REG] & MI_INTR_DP; - if (sp->mem[0xfc0/4] == 1) + unprotect_framebuffers(&sp->dp->fb); + uint32_t rsp_cycles = rsp.doRspCycles(sp->first_run) / 2; + + if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP && !dp_bit_set) { - unprotect_framebuffers(&sp->dp->fb); - - //gfx.processDList(); - sp->regs2[SP_PC_REG] &= 0xfff; -#if defined(PROFILE) - timed_section_start(TIMED_SECTION_GFX); -#endif - rsp.doRspCycles(0xffffffff); -#if defined(PROFILE) - timed_section_end(TIMED_SECTION_GFX); -#endif - sp->regs2[SP_PC_REG] |= save_pc; - new_frame(); - - if (sp->mi->regs[MI_INTR_REG] & MI_INTR_DP) - { - sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP; - if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) { - sp->dp->do_on_unfreeze |= DELAY_DP_INT; - } else { - cp0_update_count(sp->mi->r4300); - add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000); - } + sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_DP; + sp->rsp_wait |= WAIT_PENDING_DP_SYNC; + if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) { + sp->dp->do_on_unfreeze |= DELAY_DP_INT; + } else { + cp0_update_count(sp->mi->r4300); + add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, rsp_cycles + sp->dp->dpc_regs[DPC_CLOCK_REG]); } - sp_delay_time = 1000; - - protect_framebuffers(&sp->dp->fb); } - else if (sp->mem[0xfc0/4] == 2) - { - //audio.processAList(); - sp->regs2[SP_PC_REG] &= 0xfff; -#if defined(PROFILE) - timed_section_start(TIMED_SECTION_AUDIO); -#endif - rsp.doRspCycles(0xffffffff); -#if defined(PROFILE) - timed_section_end(TIMED_SECTION_AUDIO); -#endif - sp->regs2[SP_PC_REG] |= save_pc; - sp_delay_time = 4000; + sp->rsp_status = sp->regs[SP_STATUS_REG]; + if ((sp->regs[SP_STATUS_REG] & SP_STATUS_HALT) == 0) + { + add_interrupt_event(&sp->mi->r4300->cp0, RSP_TSK_EVT, rsp_cycles); + sp->first_run = 0; } else { - sp->regs2[SP_PC_REG] &= 0xfff; - rsp.doRspCycles(0xffffffff); - sp->regs2[SP_PC_REG] |= save_pc; - - sp_delay_time = 0; + sp->rsp_wait |= WAIT_HALTED; + sp->first_run = 1; } - - sp->rsp_task_locked = 0; - sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP; - if ((sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE)) == 0) - { - sp->rsp_task_locked = 1; - sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP; - sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP; - } - if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP) + if ((sp->regs[SP_STATUS_REG] & SP_STATUS_BROKE) && (sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK)) { + sp->rsp_wait |= WAIT_PENDING_SP_INT_BROKE; cp0_update_count(sp->mi->r4300); - add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time); - sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP; + add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles); + sp->regs[SP_STATUS_REG] = saved_status; } + else if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP && !sp_bit_set) + { + sp->rsp_wait |= WAIT_PENDING_SP_INT; + cp0_update_count(sp->mi->r4300); + add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles); + } + sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP; + if (!sp_bit_set) + sp->mi->regs[MI_INTR_REG] &= ~MI_INTR_SP; - sp->regs[SP_STATUS_REG] &= - ~(SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT); + protect_framebuffers(&sp->dp->fb); } void rsp_interrupt_event(void* opaque) { struct rsp_core* sp = (struct rsp_core*)opaque; - if (!sp->rsp_task_locked) - { - sp->regs[SP_STATUS_REG] |= - SP_STATUS_TASKDONE | SP_STATUS_BROKE | SP_STATUS_HALT; - } + sp->regs[SP_STATUS_REG] = sp->rsp_status; + sp->rsp_status = 0; + sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP; + raise_rcp_interrupt(sp->mi, MI_INTR_SP); - if ((sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK) != 0) - { - raise_rcp_interrupt(sp->mi, MI_INTR_SP); - } + clear_rsp_wait(sp, WAIT_PENDING_SP_INT | WAIT_PENDING_SP_INT_BROKE); } void rsp_end_of_dma_event(void* opaque) @@ -423,3 +430,17 @@ void rsp_end_of_dma_event(void* opaque) struct rsp_core* sp = (struct rsp_core*)opaque; fifo_pop(sp); } + +void rsp_task_event(void* opaque) +{ + struct rsp_core* sp = (struct rsp_core*)opaque; + + do_SP_Task(sp); +} + +void clear_rsp_wait(struct rsp_core* sp, uint32_t value) +{ + sp->rsp_wait &= ~value; + + do_SP_Task(sp); +} diff --git a/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.h b/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.h index 7db69239..dd47f1e0 100644 --- a/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.h +++ b/Source/3rdParty/mupen64plus-core/src/device/rcp/rsp/rsp_core.h @@ -55,6 +55,36 @@ enum SP_STATUS_SIG7 = 0x4000, }; +enum +{ + /* SP_STATUS - write */ + SP_CLR_HALT = 0x0000001, + SP_SET_HALT = 0x0000002, + SP_CLR_BROKE = 0x0000004, + SP_CLR_INTR = 0x0000008, + SP_SET_INTR = 0x0000010, + SP_CLR_SSTEP = 0x0000020, + SP_SET_SSTEP = 0x0000040, + SP_CLR_INTR_BREAK = 0x0000080, + SP_SET_INTR_BREAK = 0x0000100, + SP_CLR_SIG0 = 0x0000200, + SP_SET_SIG0 = 0x0000400, + SP_CLR_SIG1 = 0x0000800, + SP_SET_SIG1 = 0x0001000, + SP_CLR_SIG2 = 0x0002000, + SP_SET_SIG2 = 0x0004000, + SP_CLR_SIG3 = 0x0008000, + SP_SET_SIG3 = 0x0010000, + SP_CLR_SIG4 = 0x0020000, + SP_SET_SIG4 = 0x0040000, + SP_CLR_SIG5 = 0x0080000, + SP_SET_SIG5 = 0x0100000, + SP_CLR_SIG6 = 0x0200000, + SP_SET_SIG6 = 0x0400000, + SP_CLR_SIG7 = 0x0800000, + SP_SET_SIG7 = 0x1000000, +}; + enum sp_registers { SP_MEM_ADDR_REG, @@ -81,6 +111,14 @@ enum sp_dma_dir SP_DMA_WRITE }; +enum sp_rsp_wait +{ + WAIT_PENDING_SP_INT_BROKE = 0x1, + WAIT_PENDING_SP_INT = 0x2, + WAIT_PENDING_DP_SYNC = 0x4, + WAIT_HALTED = 0x8 +}; + enum { SP_DMA_FIFO_SIZE = 2} ; struct sp_dma @@ -96,7 +134,9 @@ struct rsp_core uint32_t* mem; uint32_t regs[SP_REGS_COUNT]; uint32_t regs2[SP_REGS2_COUNT]; - uint32_t rsp_task_locked; + uint32_t rsp_status; + uint32_t first_run; + uint32_t rsp_wait; struct mi_controller* mi; struct rdp_core* dp; @@ -141,4 +181,7 @@ void do_SP_Task(struct rsp_core* sp); void rsp_interrupt_event(void* opaque); void rsp_end_of_dma_event(void* opaque); +void rsp_task_event(void* opaque); +void clear_rsp_wait(struct rsp_core* sp, uint32_t value); + #endif diff --git a/Source/3rdParty/mupen64plus-core/src/main/savestates.c b/Source/3rdParty/mupen64plus-core/src/main/savestates.c index e13e5674..a83f7370 100644 --- a/Source/3rdParty/mupen64plus-core/src/main/savestates.c +++ b/Source/3rdParty/mupen64plus-core/src/main/savestates.c @@ -958,7 +958,9 @@ static int savestates_load_m64p(struct device* dev, char *filepath) /* reset fb state */ poweron_fb(&dev->dp.fb); - dev->sp.rsp_task_locked = 0; + dev->sp.rsp_status = 0; + dev->sp.rsp_wait = 0; + dev->sp.first_run = 1; dev->r4300.cp0.interrupt_unsafe_state = 0; *r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300); @@ -1262,7 +1264,9 @@ static int savestates_load_pj64(struct device* dev, // No flashram info in pj64 savestate. poweron_flashram(&dev->cart.flashram); - dev->sp.rsp_task_locked = 0; + dev->sp.rsp_status = 0; + dev->sp.rsp_wait = 0; + dev->sp.first_run = 1; dev->r4300.cp0.interrupt_unsafe_state = 0; /* extra fb state */