Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 11 additions & 29 deletions parallel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "rsp_jit.hpp"
#endif
#include <stdint.h>
#include <cstdarg>

#include "m64p_plugin.h"
#include "rsp_1.1.h"
Expand All @@ -19,8 +20,6 @@ RSP::CPU cpu;
#else
RSP::JIT::CPU cpu;
#endif
short MFC0_count[32];
int SP_STATUS_TIMEOUT;
} // namespace RSP

extern "C"
Expand Down Expand Up @@ -52,47 +51,33 @@ extern "C"

EXPORT unsigned int CALL parallelRSPDoRspCycles(unsigned int cycles)
{
if (*RSP::rsp.SP_STATUS_REG & SP_STATUS_HALT)
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;
}
Expand Down Expand Up @@ -153,9 +138,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));
Expand Down
215 changes: 129 additions & 86 deletions rsp/cp0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
namespace RSP
{
extern RSP_INFO rsp;
extern short MFC0_count[32];
extern int SP_STATUS_TIMEOUT;
} // namespace RSP
#endif

Expand All @@ -28,34 +26,15 @@ extern "C"
rsp->sr[rt] = res;

#ifdef PARALLEL_INTEGRATION
if (rd == CP0_REGISTER_SP_STATUS)
if (rd == CP0_REGISTER_SP_SEMAPHORE)
{
// 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;
}
*rsp->cp0.cr[CP0_REGISTER_SP_SEMAPHORE] = 1;
return MODE_EXIT;
}
#endif

#if 0 // FIXME: this is broken with upstream mupen64plus-core
if (rd == CP0_REGISTER_SP_SEMAPHORE)
// 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)
{
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;
return MODE_EXIT;
}
#endif

Expand All @@ -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)
Expand All @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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;

Expand All @@ -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:
Expand Down
Loading