mirror of
https://github.com/simple64/simple64.git
synced 2026-09-03 10:54:31 +02:00
352 lines
9.1 KiB
C++
352 lines
9.1 KiB
C++
#include "../state.hpp"
|
|
|
|
#ifdef PARALLEL_INTEGRATION
|
|
#include "../rsp_1.1.h"
|
|
#include "m64p_plugin.h"
|
|
namespace RSP
|
|
{
|
|
extern RSP_INFO rsp;
|
|
} // namespace RSP
|
|
#endif
|
|
|
|
using namespace RSP;
|
|
|
|
extern "C"
|
|
{
|
|
|
|
#ifdef INTENSE_DEBUG
|
|
void log_rsp_mem_parallel(void);
|
|
#endif
|
|
|
|
int RSP_MFC0(RSP::CPUState *rsp, unsigned rt, unsigned rd)
|
|
{
|
|
rd &= 15;
|
|
uint32_t res = *rsp->cp0.cr[rd];
|
|
if (rt)
|
|
rsp->sr[rt] = res;
|
|
|
|
#ifdef PARALLEL_INTEGRATION
|
|
if (rd == CP0_REGISTER_SP_SEMAPHORE)
|
|
{
|
|
*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
|
|
|
|
//if (rd == 4) // SP_STATUS_REG
|
|
// fprintf(stderr, "READING STATUS REG!\n");
|
|
|
|
return MODE_CONTINUE;
|
|
}
|
|
|
|
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)
|
|
{
|
|
//fprintf(stderr, "Writing 0x%x to status reg!\n", rt);
|
|
|
|
uint32_t status = *rsp->cp0.cr[CP0_REGISTER_SP_STATUS];
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef PARALLEL_INTEGRATION
|
|
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) | 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)
|
|
length = 0x1000 - (*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF);
|
|
|
|
unsigned i = 0;
|
|
uint32_t source = *rsp->cp0.cr[CP0_REGISTER_DMA_DRAM];
|
|
uint32_t dest = *rsp->cp0.cr[CP0_REGISTER_DMA_CACHE];
|
|
|
|
#ifdef INTENSE_DEBUG
|
|
fprintf(stderr, "DMA READ: (0x%x <- 0x%x) len %u, count %u, skip %u\n", dest & 0x1ffc, source & 0x7ffffc,
|
|
length, count + 1, skip);
|
|
#endif
|
|
|
|
do
|
|
{
|
|
unsigned j = 0;
|
|
do
|
|
{
|
|
uint32_t source_addr = (source + j) & 0x7FFFFC;
|
|
uint32_t dest_addr = (dest + j) & 0x1FFC;
|
|
uint32_t word = rsp->rdram[source_addr >> 2];
|
|
|
|
if (dest_addr & 0x1000)
|
|
{
|
|
// Invalidate IMEM.
|
|
unsigned block = (dest_addr & 0xfff) / CODE_BLOCK_SIZE;
|
|
rsp->dirty_blocks |= (0x3 << block) >> 1;
|
|
//rsp->dirty_blocks = ~0u;
|
|
rsp->imem[(dest_addr & 0xfff) >> 2] = word;
|
|
}
|
|
else
|
|
rsp->dmem[dest_addr >> 2] = word;
|
|
|
|
j += 4;
|
|
} while (j < length);
|
|
|
|
source += length + skip;
|
|
dest += length;
|
|
} while (++i < count);
|
|
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = source;
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = dest;
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH] = 0xff8;
|
|
|
|
#ifdef INTENSE_DEBUG
|
|
log_rsp_mem_parallel();
|
|
#endif
|
|
return rsp->dirty_blocks ? MODE_CHECK_FLAGS : MODE_CONTINUE;
|
|
}
|
|
|
|
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) | 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)
|
|
length = 0x1000 - (*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] & 0xFFF);
|
|
|
|
uint32_t dest = *rsp->cp0.cr[CP0_REGISTER_DMA_DRAM];
|
|
uint32_t source = *rsp->cp0.cr[CP0_REGISTER_DMA_CACHE];
|
|
|
|
#ifdef INTENSE_DEBUG
|
|
fprintf(stderr, "DMA WRITE: (0x%x <- 0x%x) len %u, count %u, skip %u\n", dest & 0x7ffffc, source & 0x1ffc,
|
|
length, count + 1, skip);
|
|
#endif
|
|
|
|
unsigned i = 0;
|
|
do
|
|
{
|
|
unsigned j = 0;
|
|
|
|
do
|
|
{
|
|
uint32_t source_addr = (source + j) & 0x1FFC;
|
|
uint32_t dest_addr = (dest + j) & 0x7FFFFC;
|
|
|
|
rsp->rdram[dest_addr >> 2] =
|
|
(source_addr & 0x1000) ? rsp->imem[(source_addr & 0xfff) >> 2] : rsp->dmem[source_addr >> 2];
|
|
|
|
j += 4;
|
|
} while (j < length);
|
|
|
|
source += length;
|
|
dest += length + skip;
|
|
} while (++i < count);
|
|
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = source;
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = dest;
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH] = 0xff8;
|
|
#ifdef INTENSE_DEBUG
|
|
log_rsp_mem_parallel();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
int RSP_MTC0(RSP::CPUState *rsp, unsigned rd, unsigned rt)
|
|
{
|
|
uint32_t val = rsp->sr[rt];
|
|
|
|
switch (static_cast<CP0Registers>(rd & 15))
|
|
{
|
|
case CP0_REGISTER_DMA_CACHE:
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_CACHE] = val & 0x1ff8;
|
|
break;
|
|
|
|
case CP0_REGISTER_DMA_DRAM:
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_DRAM] = val & 0xfffff8;
|
|
break;
|
|
|
|
case CP0_REGISTER_DMA_READ_LENGTH:
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_READ_LENGTH] = val;
|
|
#ifdef PARALLEL_INTEGRATION
|
|
return rsp_dma_read(rsp);
|
|
#else
|
|
return MODE_DMA_READ;
|
|
#endif
|
|
|
|
case CP0_REGISTER_DMA_WRITE_LENGTH:
|
|
*rsp->cp0.cr[CP0_REGISTER_DMA_WRITE_LENGTH] = val;
|
|
#ifdef PARALLEL_INTEGRATION
|
|
rsp_dma_write(rsp);
|
|
#endif
|
|
break;
|
|
|
|
case CP0_REGISTER_SP_STATUS:
|
|
return rsp_status_write(rsp, val);
|
|
|
|
case CP0_REGISTER_SP_SEMAPHORE:
|
|
*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 & 0xfffff8u);
|
|
#endif
|
|
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 & 0xfffff8u);
|
|
#endif
|
|
*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;
|
|
|
|
case CP0_REGISTER_CMD_CLOCK:
|
|
*rsp->cp0.cr[CP0_REGISTER_CMD_CLOCK] = val;
|
|
break;
|
|
|
|
case CP0_REGISTER_CMD_STATUS:
|
|
rdp_status_write(rsp, val);
|
|
break;
|
|
|
|
case CP0_REGISTER_CMD_CURRENT:
|
|
case CP0_REGISTER_CMD_BUSY:
|
|
case CP0_REGISTER_CMD_PIPE_BUSY:
|
|
case CP0_REGISTER_CMD_TMEM_BUSY:
|
|
break;
|
|
|
|
default:
|
|
*rsp->cp0.cr[rd & 15] = val;
|
|
break;
|
|
}
|
|
|
|
return MODE_CONTINUE;
|
|
}
|
|
}
|