mirror of
https://github.com/Rosalie241/RMG.git
synced 2026-07-11 09:34:00 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ec4d7c0ab | |||
| 7014796e5f | |||
| 183fb2b626 | |||
| 188fa1b6f5 | |||
| 70cf93a0e9 | |||
| c8a26ea9d4 |
+2
-1
@@ -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
|
||||
@@ -141,7 +142,7 @@ void init_device(struct device* dev,
|
||||
/* memory map */
|
||||
{ A(MM_RDRAM_DRAM, 0x3efffff), M64P_MEM_RDRAM, { &dev->rdram, RW(rdram_dram) } },
|
||||
{ A(MM_RDRAM_REGS, 0xfffff), M64P_MEM_RDRAMREG, { &dev->rdram, RW(rdram_regs) } },
|
||||
{ A(MM_RSP_MEM, 0xffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
|
||||
{ A(MM_RSP_MEM, 0x3ffff), M64P_MEM_RSPMEM, { &dev->sp, RW(rsp_mem) } },
|
||||
{ A(MM_RSP_REGS, 0xffff), M64P_MEM_RSPREG, { &dev->sp, RW(rsp_regs) } },
|
||||
{ A(MM_RSP_REGS2, 0xffff), M64P_MEM_RSP, { &dev->sp, RW(rsp_regs2) } },
|
||||
{ A(MM_DPC_REGS, 0xffff), M64P_MEM_DP, { &dev->dp, RW(dpc_regs) } },
|
||||
|
||||
+3
-2
@@ -173,11 +173,12 @@ struct interrupt_handler
|
||||
void (*callback)(void*);
|
||||
};
|
||||
|
||||
enum { CP0_INTERRUPT_HANDLERS_COUNT = 16 };
|
||||
enum { CP0_INTERRUPT_HANDLERS_COUNT = 17 };
|
||||
|
||||
enum {
|
||||
INTR_UNSAFE_R4300 = 0x01,
|
||||
INTR_UNSAFE_RSP = 0x02,
|
||||
INTR_UNSAFE_RSP = 0x02,
|
||||
INTR_UNSAFE_RDP = 0x04,
|
||||
};
|
||||
|
||||
struct cp0
|
||||
|
||||
@@ -656,6 +656,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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,13 @@ 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)
|
||||
{
|
||||
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
|
||||
|
||||
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 +58,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,11 +96,13 @@ 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;
|
||||
|
||||
poweron_fb(&dp->fb);
|
||||
|
||||
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,18 +131,35 @@ 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;
|
||||
dp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -149,6 +191,9 @@ void rdp_interrupt_event(void* opaque)
|
||||
{
|
||||
struct rdp_core* dp = (struct rdp_core*)opaque;
|
||||
|
||||
dp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RDP;
|
||||
raise_rcp_interrupt(dp->mi, MI_INTR_DP);
|
||||
|
||||
clear_rsp_wait(dp->sp, WAIT_PENDING_DP_SYNC);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+119
-104
@@ -76,13 +76,16 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma)
|
||||
pre_framebuffer_read(&sp->dp->fb, dramaddr);
|
||||
|
||||
for(i=0; i<length; i++) {
|
||||
spmem[(memaddr^S8) & 0xfff] = dram[(dramaddr^S8) & 0x7fffff];
|
||||
spmem[(memaddr & 0xfff)^S8] = dram[(dramaddr^S8) & 0x7fffff];
|
||||
memaddr++;
|
||||
dramaddr++;
|
||||
}
|
||||
dramaddr+=skip;
|
||||
}
|
||||
|
||||
sp->regs[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;
|
||||
@@ -146,69 +149,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 +251,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 +309,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 +346,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 +357,66 @@ 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)
|
||||
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->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RDP;
|
||||
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 {
|
||||
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)
|
||||
if ((sp->regs[SP_STATUS_REG] & SP_STATUS_BROKE) && (sp->regs[SP_STATUS_REG] & SP_STATUS_INTR_BREAK))
|
||||
{
|
||||
sp->rsp_task_locked = 1;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP;
|
||||
sp->mi->regs[MI_INTR_REG] |= MI_INTR_SP;
|
||||
sp->rsp_wait |= WAIT_PENDING_SP_INT_BROKE;
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, rsp_cycles);
|
||||
sp->regs[SP_STATUS_REG] = saved_status;
|
||||
}
|
||||
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP)
|
||||
else if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP && !sp_bit_set)
|
||||
{
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time);
|
||||
sp->rsp_wait |= WAIT_PENDING_SP_INT;
|
||||
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);
|
||||
}
|
||||
|
||||
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 +424,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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+6
-1
@@ -76,12 +76,16 @@ static const uint8_t Z64_SIGNATURE[4] = { 0x80, 0x37, 0x12, 0x40 };
|
||||
static const uint8_t V64_SIGNATURE[4] = { 0x37, 0x80, 0x40, 0x12 };
|
||||
static const uint8_t N64_SIGNATURE[4] = { 0x40, 0x12, 0x37, 0x80 };
|
||||
|
||||
static const uint8_t ALT_Z64_SIGNATURE[4] = { 0x31, 0x37, 0x12, 0x40 };
|
||||
|
||||
/* Tests if a file is a valid N64 rom by checking the first 4 bytes and size */
|
||||
static int is_valid_rom(const unsigned char *buffer, unsigned int size)
|
||||
{
|
||||
printf("rom signature: 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", buffer[0], buffer[1], buffer[2], buffer[3]);
|
||||
if ((memcmp(buffer, Z64_SIGNATURE, sizeof(Z64_SIGNATURE)) == 0)
|
||||
|| (memcmp(buffer, V64_SIGNATURE, sizeof(V64_SIGNATURE)) == 0 && size % 2 == 0)
|
||||
|| (memcmp(buffer, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0 && size % 4 == 0))
|
||||
|| (memcmp(buffer, N64_SIGNATURE, sizeof(N64_SIGNATURE)) == 0 && size % 4 == 0)
|
||||
|| (memcmp(buffer, ALT_Z64_SIGNATURE, sizeof(ALT_Z64_SIGNATURE)) == 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@@ -149,6 +153,7 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
|
||||
if (romimage == NULL || !is_valid_rom(romimage, size))
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "open_rom(): not a valid ROM image");
|
||||
printf("fail\n");
|
||||
return M64ERR_INPUT_INVALID;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -949,7 +949,7 @@ 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_task_locked = 0;
|
||||
dev->r4300.cp0.interrupt_unsafe_state = 0;
|
||||
|
||||
*r4300_cp0_last_addr(&dev->r4300.cp0) = *r4300_pc(&dev->r4300);
|
||||
@@ -1253,7 +1253,7 @@ 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_task_locked = 0;
|
||||
dev->r4300.cp0.interrupt_unsafe_state = 0;
|
||||
|
||||
/* extra fb state */
|
||||
|
||||
@@ -127,4 +127,3 @@ void dummyvideo_ResizeVideoOutput(int width, int height)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ extern void dummyvideo_ViWidthChanged(void);
|
||||
extern void dummyvideo_ReadScreen2(void *dest, int *width, int *height, int front);
|
||||
extern void dummyvideo_SetRenderingCallback(void (*callback)(int));
|
||||
extern void dummyvideo_ResizeVideoOutput(int width, int height);
|
||||
extern void dummyvideo_FullSync(void);
|
||||
|
||||
extern void dummyvideo_FBRead(unsigned int addr);
|
||||
extern void dummyvideo_FBWrite(unsigned int addr, unsigned int size);
|
||||
|
||||
+10
-29
@@ -20,8 +20,6 @@ RSP::CPU cpu;
|
||||
#else
|
||||
RSP::JIT::CPU cpu;
|
||||
#endif
|
||||
short MFC0_count[32];
|
||||
int SP_STATUS_TIMEOUT;
|
||||
} // namespace RSP
|
||||
|
||||
extern "C"
|
||||
@@ -53,47 +51,33 @@ extern "C"
|
||||
|
||||
EXPORT unsigned int CALL DoRspCycles(unsigned int cycles)
|
||||
{
|
||||
if (*RSP::rsp.SP_STATUS_REG & (SP_STATUS_HALT | SP_STATUS_BROKE))
|
||||
return 0;
|
||||
|
||||
// We don't know if Mupen from the outside invalidated our IMEM.
|
||||
RSP::cpu.invalidate_imem();
|
||||
if (cycles)
|
||||
{
|
||||
RSP::cpu.get_state().last_instruction_type = RSP::VU_INSTRUCTION;
|
||||
RSP::cpu.get_state().instruction_pipeline = 0;
|
||||
RSP::cpu.invalidate_imem();
|
||||
}
|
||||
|
||||
// Run CPU until we either break or we need to fire an IRQ.
|
||||
RSP::cpu.get_state().pc = *RSP::rsp.SP_PC_REG & 0xfff;
|
||||
RSP::cpu.get_state().instruction_count = 0;
|
||||
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "RUN TASK: %u\n", RSP::cpu.get_state().pc);
|
||||
log_rsp_mem_parallel();
|
||||
#endif
|
||||
|
||||
for (auto &count : RSP::MFC0_count)
|
||||
count = 0;
|
||||
|
||||
while (!(*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT))
|
||||
{
|
||||
auto mode = RSP::cpu.run();
|
||||
if (mode == RSP::MODE_CHECK_FLAGS && (*RSP::cpu.get_state().cp0.irq & 1))
|
||||
break;
|
||||
if (mode == RSP::MODE_EXIT)
|
||||
break;
|
||||
}
|
||||
|
||||
*RSP::rsp.SP_PC_REG = 0x04001000 | (RSP::cpu.get_state().pc & 0xffc);
|
||||
|
||||
// From CXD4.
|
||||
if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_BROKE)
|
||||
return cycles;
|
||||
else if (*RSP::cpu.get_state().cp0.irq & 1)
|
||||
RSP::rsp.CheckInterrupts();
|
||||
else if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT)
|
||||
return cycles;
|
||||
else if (*RSP::rsp.SP_SEMAPHORE_REG != 0) // Semaphore lock fixes.
|
||||
{
|
||||
}
|
||||
else
|
||||
RSP::SP_STATUS_TIMEOUT = 16; // From now on, wait 16 times, not 0x7fff
|
||||
|
||||
// CPU restarts with the correct SIGs.
|
||||
*RSP::rsp.SP_STATUS_REG &= ~SP_STATUS_HALT;
|
||||
*RSP::rsp.SP_PC_REG = (RSP::cpu.get_state().pc & 0xffc);
|
||||
|
||||
return cycles;
|
||||
}
|
||||
@@ -157,9 +141,6 @@ extern "C"
|
||||
*cr[RSP::CP0_REGISTER_SP_STATUS] = SP_STATUS_HALT;
|
||||
RSP::cpu.get_state().cp0.irq = RSP::rsp.MI_INTR_REG;
|
||||
|
||||
// From CXD4.
|
||||
RSP::SP_STATUS_TIMEOUT = 0x7fff;
|
||||
|
||||
RSP::cpu.set_dmem(reinterpret_cast<uint32_t *>(Rsp_Info.DMEM));
|
||||
RSP::cpu.set_imem(reinterpret_cast<uint32_t *>(Rsp_Info.IMEM));
|
||||
RSP::cpu.set_rdram(reinterpret_cast<uint32_t *>(Rsp_Info.RDRAM));
|
||||
|
||||
+130
-87
@@ -6,8 +6,6 @@
|
||||
namespace RSP
|
||||
{
|
||||
extern RSP_INFO rsp;
|
||||
extern short MFC0_count[32];
|
||||
extern int SP_STATUS_TIMEOUT;
|
||||
} // namespace RSP
|
||||
#endif
|
||||
|
||||
@@ -28,34 +26,15 @@ extern "C"
|
||||
rsp->sr[rt] = res;
|
||||
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
if (rd == CP0_REGISTER_SP_STATUS)
|
||||
{
|
||||
// Might be waiting for the CPU to set a signal bit on the STATUS register. Increment timeout
|
||||
RSP::MFC0_count[rt] += 1;
|
||||
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
|
||||
{
|
||||
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
|
||||
return MODE_CHECK_FLAGS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // FIXME: this is broken with upstream mupen64plus-core
|
||||
if (rd == CP0_REGISTER_SP_SEMAPHORE)
|
||||
{
|
||||
if (*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE])
|
||||
{
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
RSP::MFC0_count[rt] += 8; // Almost certainly waiting on the CPU. Timeout faster.
|
||||
if (RSP::MFC0_count[rt] >= RSP::SP_STATUS_TIMEOUT)
|
||||
{
|
||||
*RSP::rsp.SP_STATUS_REG |= SP_STATUS_HALT;
|
||||
return MODE_CHECK_FLAGS;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
|
||||
return MODE_EXIT;
|
||||
}
|
||||
// We don't return control to the CPU if the RDP FREEZE bit is set, doing so seems to cause flickering
|
||||
else if (rd == CP0_REGISTER_SP_STATUS && (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_FREEZE) == 0)
|
||||
{
|
||||
return MODE_EXIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -65,12 +44,44 @@ extern "C"
|
||||
return MODE_CONTINUE;
|
||||
}
|
||||
|
||||
#define RSP_HANDLE_STATUS_WRITE(flag) \
|
||||
switch (rt & (SP_SET_##flag | SP_CLR_##flag)) \
|
||||
{ \
|
||||
case SP_SET_##flag: status |= SP_STATUS_##flag; break; \
|
||||
case SP_CLR_##flag: status &= ~SP_STATUS_##flag; break; \
|
||||
default: break; \
|
||||
static inline void rdp_status_write(RSP::CPUState *rsp, uint32_t rt)
|
||||
{
|
||||
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_CMD_STATUS];
|
||||
if (rt & DPC_CLR_XBUS_DMEM_DMA)
|
||||
status &= ~DPC_STATUS_XBUS_DMEM_DMA;
|
||||
else if (rt & DPC_SET_XBUS_DMEM_DMA)
|
||||
status |= DPC_STATUS_XBUS_DMEM_DMA;
|
||||
|
||||
if (rt & DPC_CLR_FREEZE)
|
||||
status &= ~DPC_STATUS_FREEZE;
|
||||
else if (rt & DPC_SET_FREEZE)
|
||||
status |= DPC_STATUS_FREEZE;
|
||||
|
||||
if (rt & DPC_CLR_FLUSH)
|
||||
status &= ~DPC_STATUS_FLUSH;
|
||||
else if (rt & DPC_SET_FLUSH)
|
||||
status |= DPC_STATUS_FLUSH;
|
||||
|
||||
if (rt & DPC_CLR_TMEM_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_TMEM_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] = 0;
|
||||
}
|
||||
if (rt & DPC_CLR_PIPE_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_PIPE_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_PIPE_BUSY] = 0;
|
||||
}
|
||||
if (rt & DPC_CLR_CMD_CTR)
|
||||
{
|
||||
status &= ~DPC_STATUS_CMD_BUSY;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_BUSY] = 0;
|
||||
}
|
||||
|
||||
if (rt & DPC_CLR_CLOCK_CTR)
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] = 0;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] = status;
|
||||
}
|
||||
|
||||
static inline int rsp_status_write(RSP::CPUState *rsp, uint32_t rt)
|
||||
@@ -79,28 +90,69 @@ extern "C"
|
||||
|
||||
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_SP_STATUS];
|
||||
|
||||
RSP_HANDLE_STATUS_WRITE(HALT)
|
||||
RSP_HANDLE_STATUS_WRITE(SSTEP)
|
||||
RSP_HANDLE_STATUS_WRITE(INTR_BREAK)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG0)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG1)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG2)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG3)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG4)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG5)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG6)
|
||||
RSP_HANDLE_STATUS_WRITE(SIG7)
|
||||
|
||||
switch (rt & (SP_SET_INTR | SP_CLR_INTR))
|
||||
{
|
||||
case SP_SET_INTR: *rsp->cp0.irq |= 1; break;
|
||||
case SP_CLR_INTR: *rsp->cp0.irq &= ~1; break;
|
||||
default: break;
|
||||
}
|
||||
if ((rt & SP_CLR_HALT) && !(rt & SP_SET_HALT))
|
||||
status &= ~SP_STATUS_HALT;
|
||||
if ((rt & SP_SET_HALT) && !(rt & SP_CLR_HALT))
|
||||
status |= SP_STATUS_HALT;
|
||||
|
||||
if (rt & SP_CLR_BROKE)
|
||||
status &= ~SP_STATUS_BROKE;
|
||||
|
||||
if ((rt & SP_CLR_INTR) && !(rt & SP_SET_INTR))
|
||||
*rsp->cp0.irq &= ~1;
|
||||
if ((rt & SP_SET_INTR) && !(rt & SP_CLR_INTR))
|
||||
*rsp->cp0.irq |= 1;
|
||||
|
||||
if ((rt & SP_CLR_SSTEP) && !(rt & SP_SET_SSTEP))
|
||||
status &= ~SP_STATUS_SSTEP;
|
||||
if ((rt & SP_SET_SSTEP) && !(rt & SP_CLR_SSTEP))
|
||||
status |= SP_STATUS_SSTEP;
|
||||
|
||||
if ((rt & SP_CLR_INTR_BREAK) && !(rt & SP_SET_INTR_BREAK))
|
||||
status &= ~SP_STATUS_INTR_BREAK;
|
||||
if ((rt & SP_SET_INTR_BREAK) && !(rt & SP_CLR_INTR_BREAK))
|
||||
status |= SP_STATUS_INTR_BREAK;
|
||||
|
||||
if ((rt & SP_CLR_SIG0) && !(rt & SP_SET_SIG0))
|
||||
status &= ~SP_STATUS_SIG0;
|
||||
if ((rt & SP_SET_SIG0) && !(rt & SP_CLR_SIG0))
|
||||
status |= SP_STATUS_SIG0;
|
||||
|
||||
if ((rt & SP_CLR_SIG1) && !(rt & SP_SET_SIG1))
|
||||
status &= ~SP_STATUS_SIG1;
|
||||
if ((rt & SP_SET_SIG1) && !(rt & SP_CLR_SIG1))
|
||||
status |= SP_STATUS_SIG1;
|
||||
|
||||
if ((rt & SP_CLR_SIG2) && !(rt & SP_SET_SIG2))
|
||||
status &= ~SP_STATUS_SIG2;
|
||||
if ((rt & SP_SET_SIG2) && !(rt & SP_CLR_SIG2))
|
||||
status |= SP_STATUS_SIG2;
|
||||
|
||||
if ((rt & SP_CLR_SIG3) && !(rt & SP_SET_SIG3))
|
||||
status &= ~SP_STATUS_SIG3;
|
||||
if ((rt & SP_SET_SIG3) && !(rt & SP_CLR_SIG3))
|
||||
status |= SP_STATUS_SIG3;
|
||||
|
||||
if ((rt & SP_CLR_SIG4) && !(rt & SP_SET_SIG4))
|
||||
status &= ~SP_STATUS_SIG4;
|
||||
if ((rt & SP_SET_SIG4) && !(rt & SP_CLR_SIG4))
|
||||
status |= SP_STATUS_SIG4;
|
||||
|
||||
if ((rt & SP_CLR_SIG5) && !(rt & SP_SET_SIG5))
|
||||
status &= ~SP_STATUS_SIG5;
|
||||
if ((rt & SP_SET_SIG5) && !(rt & SP_CLR_SIG5))
|
||||
status |= SP_STATUS_SIG5;
|
||||
|
||||
if ((rt & SP_CLR_SIG6) && !(rt & SP_SET_SIG6))
|
||||
status &= ~SP_STATUS_SIG6;
|
||||
if ((rt & SP_SET_SIG6) && !(rt & SP_CLR_SIG6))
|
||||
status |= SP_STATUS_SIG6;
|
||||
|
||||
if ((rt & SP_CLR_SIG7) && !(rt & SP_SET_SIG7))
|
||||
status &= ~SP_STATUS_SIG7;
|
||||
if ((rt & SP_SET_SIG7) && !(rt & SP_CLR_SIG7))
|
||||
status |= SP_STATUS_SIG7;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_STATUS] = status;
|
||||
return ((*rsp->cp0.irq & 1) || (status & SP_STATUS_HALT)) ? MODE_CHECK_FLAGS : MODE_CONTINUE;
|
||||
}
|
||||
@@ -109,14 +161,9 @@ extern "C"
|
||||
static int rsp_dma_read(RSP::CPUState *rsp)
|
||||
{
|
||||
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH];
|
||||
uint32_t length = (length_reg & 0xFFF) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFFF;
|
||||
unsigned count = (length_reg >> 12) & 0xFF;
|
||||
|
||||
// Force alignment.
|
||||
length = (length + 0x7) & ~0x7;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
|
||||
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFF8;
|
||||
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
|
||||
|
||||
// Check length.
|
||||
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
|
||||
@@ -156,7 +203,7 @@ extern "C"
|
||||
|
||||
source += length + skip;
|
||||
dest += length;
|
||||
} while (++i <= count);
|
||||
} while (++i < count);
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = source;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = dest;
|
||||
@@ -171,14 +218,9 @@ extern "C"
|
||||
static void rsp_dma_write(RSP::CPUState *rsp)
|
||||
{
|
||||
uint32_t length_reg = *rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH];
|
||||
uint32_t length = (length_reg & 0xFFF) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFFF;
|
||||
unsigned count = (length_reg >> 12) & 0xFF;
|
||||
|
||||
// Force alignment.
|
||||
length = (length + 0x7) & ~0x7;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] &= ~0x3;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] &= ~0x7;
|
||||
uint32_t length = ((length_reg & 0xFFF) | 7) + 1;
|
||||
uint32_t skip = (length_reg >> 20) & 0xFF8;
|
||||
unsigned count = ((length_reg >> 12) & 0xFF) + 1;
|
||||
|
||||
// Check length.
|
||||
if (((*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF) + length) > 0x1000)
|
||||
@@ -210,7 +252,7 @@ extern "C"
|
||||
|
||||
source += length;
|
||||
dest += length + skip;
|
||||
} while (++i <= count);
|
||||
} while (++i < count);
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = source;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = dest;
|
||||
@@ -228,11 +270,11 @@ extern "C"
|
||||
switch (static_cast<CP0Registers>(rd & 15))
|
||||
{
|
||||
case CP0_REGISTER_DMA_CACHE:
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1fff;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1ff8;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_DMA_DRAM:
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xffffff;
|
||||
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xfffff8;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_DMA_READ_LENGTH:
|
||||
@@ -254,26 +296,34 @@ extern "C"
|
||||
return rsp_status_write(rsp, val);
|
||||
|
||||
case CP0_REGISTER_SP_SEMAPHORE:
|
||||
// Any write to the semaphore register, regardless of value, sets it to 0 for the next read
|
||||
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 0;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_START:
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffffff8u);
|
||||
fprintf(stderr, "CMD_START 0x%x\n", val & 0xfffff8u);
|
||||
#endif
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = *rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] =
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
|
||||
if (!(*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID))
|
||||
{
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_START] = val & 0xfffff8u;
|
||||
}
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= DPC_STATUS_START_VALID;
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_END:
|
||||
#ifdef INTENSE_DEBUG
|
||||
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffffff8u);
|
||||
fprintf(stderr, "CMD_END 0x%x\n", val & 0xfffff8u);
|
||||
#endif
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffffff8u;
|
||||
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_END] = val & 0xfffff8u;
|
||||
if (*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] & DPC_STATUS_START_VALID)
|
||||
{
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CURRENT] = *rsp->cp0.cr[CP0_REGISTER_CMD_START];
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~DPC_STATUS_START_VALID;
|
||||
}
|
||||
#ifdef PARALLEL_INTEGRATION
|
||||
RSP::rsp.ProcessRdpList();
|
||||
if (*rsp->cp0.irq & 0x20)
|
||||
return MODE_EXIT;
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -282,14 +332,7 @@ extern "C"
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_STATUS:
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x1) << 0);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x2) << 0);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x4) << 1);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x8) << 1);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] &= ~(!!(val & 0x10) << 2);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_STATUS] |= (!!(val & 0x20) << 2);
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_TMEM_BUSY] &= !(val & 0x40) * -1;
|
||||
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] &= !(val & 0x200) * -1;
|
||||
rdp_status_write(rsp, val);
|
||||
break;
|
||||
|
||||
case CP0_REGISTER_CMD_CURRENT:
|
||||
|
||||
+1
-2
@@ -1927,14 +1927,13 @@ ReturnMode CPU::run()
|
||||
{
|
||||
case MODE_BREAK:
|
||||
*state.cp0.cr[CP0_REGISTER_SP_STATUS] |= SP_STATUS_BROKE | SP_STATUS_HALT;
|
||||
if (*state.cp0.cr[CP0_REGISTER_SP_STATUS] & SP_STATUS_INTR_BREAK)
|
||||
*state.cp0.irq |= 1;
|
||||
#ifndef PARALLEL_INTEGRATION
|
||||
print_registers();
|
||||
#endif
|
||||
return MODE_BREAK;
|
||||
|
||||
case MODE_CHECK_FLAGS:
|
||||
case MODE_EXIT:
|
||||
case MODE_DMA_READ:
|
||||
return static_cast<ReturnMode>(ret);
|
||||
|
||||
|
||||
+36
-1
@@ -48,6 +48,31 @@ enum CP0Registers
|
||||
CP0_REGISTER_CMD_TMEM_BUSY = 15,
|
||||
};
|
||||
|
||||
// CMD_STATUS read bits.
|
||||
#define DPC_STATUS_XBUS_DMEM_DMA 0x001
|
||||
#define DPC_STATUS_FREEZE 0x002
|
||||
#define DPC_STATUS_FLUSH 0x004
|
||||
#define DPC_STATUS_START_GCLK 0x008
|
||||
#define DPC_STATUS_TMEM_BUSY 0x010
|
||||
#define DPC_STATUS_PIPE_BUSY 0x020
|
||||
#define DPC_STATUS_CMD_BUSY 0x040
|
||||
#define DPC_STATUS_CBUF_READY 0x080
|
||||
#define DPC_STATUS_DMA_BUSY 0x100
|
||||
#define DPC_STATUS_END_VALID 0x200
|
||||
#define DPC_STATUS_START_VALID 0x400
|
||||
|
||||
// CMD_STATUS write bits.
|
||||
#define DPC_CLR_XBUS_DMEM_DMA 0x001
|
||||
#define DPC_SET_XBUS_DMEM_DMA 0x002
|
||||
#define DPC_CLR_FREEZE 0x004
|
||||
#define DPC_SET_FREEZE 0x008
|
||||
#define DPC_CLR_FLUSH 0x010
|
||||
#define DPC_SET_FLUSH 0x020
|
||||
#define DPC_CLR_TMEM_CTR 0x040
|
||||
#define DPC_CLR_PIPE_CTR 0x080
|
||||
#define DPC_CLR_CMD_CTR 0x100
|
||||
#define DPC_CLR_CLOCK_CTR 0x200
|
||||
|
||||
// SP_STATUS read bits.
|
||||
#define SP_STATUS_HALT 0x0001
|
||||
#define SP_STATUS_BROKE 0x0002
|
||||
@@ -117,6 +142,9 @@ struct alignas(64) CP2
|
||||
struct CPUState
|
||||
{
|
||||
uint32_t pc = 0;
|
||||
uint32_t instruction_count = 0;
|
||||
uint32_t last_instruction_type = 0;
|
||||
uint32_t instruction_pipeline = 0;
|
||||
uint32_t dirty_blocks = 0;
|
||||
static_assert(CODE_BLOCKS <= 32, "Code blocks must fit in 32-bit register.");
|
||||
|
||||
@@ -138,7 +166,14 @@ enum ReturnMode
|
||||
MODE_CONTINUE = 1,
|
||||
MODE_BREAK = 2,
|
||||
MODE_DMA_READ = 3,
|
||||
MODE_CHECK_FLAGS = 4
|
||||
MODE_CHECK_FLAGS = 4,
|
||||
MODE_EXIT = 5
|
||||
};
|
||||
|
||||
enum InstructionType
|
||||
{
|
||||
VU_INSTRUCTION = 0,
|
||||
SU_INSTRUCTION = 1
|
||||
};
|
||||
|
||||
} // namespace RSP
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include "m64p_types.h"
|
||||
#include "m64p_config.h"
|
||||
#include "m64p_plugin.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
Reference in New Issue
Block a user