Core: Improve accuracy of SP_DMA_READ and SP_DMA_WRITE
This commit is contained in:
parent
837e93d775
commit
3913fb5c28
|
@ -21,18 +21,28 @@ SPRegistersReg::SPRegistersReg(uint32_t * SignalProcessorInterface) :
|
||||||
|
|
||||||
SPRegistersHandler::SPRegistersHandler(CN64System & System, CMipsMemoryVM & MMU, CRegisters & Reg) :
|
SPRegistersHandler::SPRegistersHandler(CN64System & System, CMipsMemoryVM & MMU, CRegisters & Reg) :
|
||||||
SPRegistersReg(Reg.m_SigProcessor_Interface),
|
SPRegistersReg(Reg.m_SigProcessor_Interface),
|
||||||
|
MIPSInterfaceReg(Reg.m_Mips_Interface),
|
||||||
|
m_SPMemAddrRegRead(0),
|
||||||
|
m_SPDramAddrRegRead(0),
|
||||||
|
m_ExecutedDMARead(false),
|
||||||
m_System(System),
|
m_System(System),
|
||||||
m_MMU(MMU),
|
m_MMU(MMU),
|
||||||
m_Reg(Reg),
|
m_Reg(Reg),
|
||||||
m_RspIntrReg(Reg.m_RspIntrReg),
|
m_RspIntrReg(Reg.m_RspIntrReg),
|
||||||
m_PC(Reg.m_PROGRAM_COUNTER)
|
m_PC(Reg.m_PROGRAM_COUNTER)
|
||||||
{
|
{
|
||||||
|
System.RegisterCallBack(CN64SystemCB_Reset, this, (CN64System::CallBackFunction)stSystemReset);
|
||||||
|
System.RegisterCallBack(CN64SystemCB_LoadedGameState, this, (CN64System::CallBackFunction)stLoadedGameState);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SPRegistersHandler::Read32(uint32_t Address, uint32_t & Value)
|
bool SPRegistersHandler::Read32(uint32_t Address, uint32_t & Value)
|
||||||
{
|
{
|
||||||
switch (Address & 0x1FFFFFFF)
|
switch (Address & 0x1FFFFFFF)
|
||||||
{
|
{
|
||||||
|
case 0x04040000: Value = m_ExecutedDMARead ? m_SPMemAddrRegRead : SP_MEM_ADDR_REG; break;
|
||||||
|
case 0x04040004: Value = m_ExecutedDMARead ? m_SPDramAddrRegRead : SP_DRAM_ADDR_REG; break;
|
||||||
|
case 0x04040008: Value = SP_RD_LEN_REG; break;
|
||||||
|
case 0x0404000C: Value = SP_WR_LEN_REG; break;
|
||||||
case 0x04040010: Value = SP_STATUS_REG; break;
|
case 0x04040010: Value = SP_STATUS_REG; break;
|
||||||
case 0x04040014: Value = SP_DMA_FULL_REG; break;
|
case 0x04040014: Value = SP_DMA_FULL_REG; break;
|
||||||
case 0x04040018: Value = SP_DMA_BUSY_REG; break;
|
case 0x04040018: Value = SP_DMA_BUSY_REG; break;
|
||||||
|
@ -101,7 +111,7 @@ bool SPRegistersHandler::Write32(uint32_t Address, uint32_t Value, uint32_t Mask
|
||||||
case 0x04040000: SP_MEM_ADDR_REG = (SP_MEM_ADDR_REG & ~Mask) | (MaskedValue); break;
|
case 0x04040000: SP_MEM_ADDR_REG = (SP_MEM_ADDR_REG & ~Mask) | (MaskedValue); break;
|
||||||
case 0x04040004: SP_DRAM_ADDR_REG = (SP_DRAM_ADDR_REG & ~Mask) | (MaskedValue); break;
|
case 0x04040004: SP_DRAM_ADDR_REG = (SP_DRAM_ADDR_REG & ~Mask) | (MaskedValue); break;
|
||||||
case 0x04040008:
|
case 0x04040008:
|
||||||
SP_RD_LEN_REG = (SP_RD_LEN_REG & ~Mask) | (MaskedValue);
|
SP_RD_LEN_REG = MaskedValue;
|
||||||
SP_DMA_READ();
|
SP_DMA_READ();
|
||||||
break;
|
break;
|
||||||
case 0x0404000C:
|
case 0x0404000C:
|
||||||
|
@ -114,7 +124,7 @@ bool SPRegistersHandler::Write32(uint32_t Address, uint32_t Value, uint32_t Mask
|
||||||
if ((MaskedValue & SP_CLR_BROKE) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; }
|
if ((MaskedValue & SP_CLR_BROKE) != 0) { SP_STATUS_REG &= ~SP_STATUS_BROKE; }
|
||||||
if ((MaskedValue & SP_CLR_INTR) != 0)
|
if ((MaskedValue & SP_CLR_INTR) != 0)
|
||||||
{
|
{
|
||||||
m_Reg.MI_INTR_REG &= ~MI_INTR_SP;
|
MI_INTR_REG &= ~MI_INTR_SP;
|
||||||
m_RspIntrReg &= ~MI_INTR_SP;
|
m_RspIntrReg &= ~MI_INTR_SP;
|
||||||
m_Reg.CheckInterrupts();
|
m_Reg.CheckInterrupts();
|
||||||
}
|
}
|
||||||
|
@ -141,7 +151,7 @@ bool SPRegistersHandler::Write32(uint32_t Address, uint32_t Value, uint32_t Mask
|
||||||
if ((MaskedValue & SP_SET_SIG7) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; }
|
if ((MaskedValue & SP_SET_SIG7) != 0) { SP_STATUS_REG |= SP_STATUS_SIG7; }
|
||||||
if ((MaskedValue & SP_SET_SIG0) != 0 && RspAudioSignal())
|
if ((MaskedValue & SP_SET_SIG0) != 0 && RspAudioSignal())
|
||||||
{
|
{
|
||||||
m_Reg.MI_INTR_REG |= MI_INTR_SP;
|
MI_INTR_REG |= MI_INTR_SP;
|
||||||
m_Reg.CheckInterrupts();
|
m_Reg.CheckInterrupts();
|
||||||
}
|
}
|
||||||
m_System.RunRSP();
|
m_System.RunRSP();
|
||||||
|
@ -159,84 +169,169 @@ bool SPRegistersHandler::Write32(uint32_t Address, uint32_t Value, uint32_t Mask
|
||||||
|
|
||||||
void SPRegistersHandler::SP_DMA_READ()
|
void SPRegistersHandler::SP_DMA_READ()
|
||||||
{
|
{
|
||||||
SP_DRAM_ADDR_REG &= 0x1FFFFFFF;
|
uint8_t * Dest = ((SP_MEM_ADDR_REG & 0x1000) != 0 ? m_MMU.Imem() : m_MMU.Dmem());
|
||||||
|
uint8_t * Source = m_MMU.Rdram();
|
||||||
|
uint32_t ReadPos = SP_DRAM_ADDR_REG & 0x00FFFFF8;
|
||||||
|
int32_t Length = ((SP_RD_LEN_REG & 0xFFF) | 7) + 1;
|
||||||
|
int32_t Count = ((SP_RD_LEN_REG >> 12) & 0xFF) + 1;
|
||||||
|
int32_t Skip = (SP_RD_LEN_REG >> 20) & 0xF8;
|
||||||
|
int32_t Pos = (SP_MEM_ADDR_REG & 0x0FF8);
|
||||||
|
|
||||||
if (SP_DRAM_ADDR_REG > m_MMU.RdramSize())
|
for (int32_t i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
if (HaveDebugger())
|
int32_t CopyLength = Length;
|
||||||
|
if ((Pos + Length) > 0x1000)
|
||||||
{
|
{
|
||||||
g_Notify->DisplayError(stdstr_f("%s\nSP_DRAM_ADDR_REG not in RDRAM space: % 08X", __FUNCTION__, g_Reg->SP_DRAM_ADDR_REG).c_str());
|
CopyLength = 0x1000 - Pos;
|
||||||
|
if (CopyLength <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
SP_DMA_BUSY_REG = 0;
|
|
||||||
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SP_RD_LEN_REG + 1 + (SP_MEM_ADDR_REG & 0xFFF) > 0x1000)
|
uint32_t NullLen = 0;
|
||||||
|
if ((ReadPos + Length) > m_MMU.RdramSize())
|
||||||
{
|
{
|
||||||
if (HaveDebugger())
|
if ((m_MMU.RdramSize() - ReadPos) < (uint32_t)CopyLength)
|
||||||
{
|
{
|
||||||
g_Notify->DisplayError(stdstr_f("%s\nCould not fit copy in memory segment", __FUNCTION__).c_str());
|
CopyLength = (int32_t)m_MMU.RdramSize() - (int32_t)ReadPos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NullLen = CopyLength;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((SP_MEM_ADDR_REG & 3) != 0)
|
if (NullLen != 0)
|
||||||
{
|
{
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
memset(&Dest[Pos], 0, NullLen);
|
||||||
}
|
}
|
||||||
if ((SP_DRAM_ADDR_REG & 3) != 0)
|
else
|
||||||
{
|
{
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
memcpy(&Dest[Pos], &Source[ReadPos], CopyLength);
|
||||||
}
|
}
|
||||||
if (((SP_RD_LEN_REG + 1) & 3) != 0)
|
if (CopyLength != Length)
|
||||||
{
|
{
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
ReadPos = (ReadPos + CopyLength) & 0x00FFFFFF;
|
||||||
|
CopyLength = Length - CopyLength;
|
||||||
|
Pos = 0;
|
||||||
|
if ((CopyLength + ReadPos) > m_MMU.RdramSize())
|
||||||
|
{
|
||||||
|
int32_t CopyAmount = m_MMU.RdramSize() - ReadPos;
|
||||||
|
if (CopyAmount < 0) { CopyAmount = 0; }
|
||||||
|
NullLen = CopyLength - CopyAmount;
|
||||||
|
|
||||||
|
if (CopyAmount > 0)
|
||||||
|
{
|
||||||
|
memcpy(&Dest[Pos], &Source[ReadPos], CopyLength);
|
||||||
|
}
|
||||||
|
if (NullLen > 0)
|
||||||
|
{
|
||||||
|
memset(&Dest[Pos], 0, NullLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(&Dest[Pos], &Source[ReadPos], CopyLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReadPos += CopyLength + Skip;
|
||||||
|
Pos += CopyLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_MMU.Dmem() + (SP_MEM_ADDR_REG & 0x1FFF), m_MMU.Rdram() + SP_DRAM_ADDR_REG, SP_RD_LEN_REG + 1);
|
if (Count > 1)
|
||||||
|
{
|
||||||
|
ReadPos -= Skip;
|
||||||
|
}
|
||||||
|
|
||||||
SP_DMA_BUSY_REG = 0;
|
SP_DMA_BUSY_REG = 0;
|
||||||
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
|
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
|
||||||
|
|
||||||
|
m_ExecutedDMARead = true;
|
||||||
|
m_SPMemAddrRegRead = Pos | (SP_MEM_ADDR_REG & 0x1000);
|
||||||
|
m_SPDramAddrRegRead = ReadPos;
|
||||||
|
SP_RD_LEN_REG = (SP_RD_LEN_REG & 0xFF800000) | 0x00000FF8;
|
||||||
|
SP_WR_LEN_REG = (SP_RD_LEN_REG & 0xFF800000) | 0x00000FF8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPRegistersHandler::SP_DMA_WRITE()
|
void SPRegistersHandler::SP_DMA_WRITE()
|
||||||
{
|
{
|
||||||
if (g_Reg->SP_DRAM_ADDR_REG > g_MMU->RdramSize())
|
uint8_t * Source = ((SP_MEM_ADDR_REG & 0x1000) != 0 ? m_MMU.Imem() : m_MMU.Dmem());
|
||||||
|
uint8_t * Dest = m_MMU.Rdram();
|
||||||
|
uint32_t WritePos = SP_DRAM_ADDR_REG & 0x00FFFFF8;
|
||||||
|
int32_t Length = ((SP_WR_LEN_REG & 0xFFF) | 7) + 1;
|
||||||
|
int32_t Count = ((SP_WR_LEN_REG >> 12) & 0xFF) + 1;
|
||||||
|
int32_t Skip = (SP_WR_LEN_REG >> 20) & 0xF8;
|
||||||
|
int32_t Pos = (SP_MEM_ADDR_REG & 0x0FF8);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
if (HaveDebugger())
|
int32_t CopyLength = Length;
|
||||||
|
if (Pos + Length > 0x1000)
|
||||||
{
|
{
|
||||||
g_Notify->DisplayError(stdstr_f("%s\nSP_DRAM_ADDR_REG not in RDRAM space: %08X", __FUNCTION__, g_Reg->SP_DRAM_ADDR_REG).c_str());
|
CopyLength = 0x1000 - Pos;
|
||||||
|
if (CopyLength <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_Reg->SP_WR_LEN_REG + 1 + (g_Reg->SP_MEM_ADDR_REG & 0xFFF) > 0x1000)
|
if (WritePos < m_MMU.RdramSize())
|
||||||
{
|
{
|
||||||
if (HaveDebugger())
|
int32_t CopyAmount = (int32_t)m_MMU.RdramSize() - (int32_t)WritePos;
|
||||||
|
if (CopyLength < CopyAmount)
|
||||||
{
|
{
|
||||||
g_Notify->DisplayError("SP DMA WRITE\nCould not fit copy in memory segment");
|
CopyAmount = CopyLength;
|
||||||
|
}
|
||||||
|
if (CopyAmount > 0)
|
||||||
|
{
|
||||||
|
memcpy(&Dest[WritePos], &Source[Pos], CopyAmount);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((g_Reg->SP_MEM_ADDR_REG & 3) != 0)
|
if (CopyLength != Length)
|
||||||
{
|
{
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
WritePos = (WritePos + CopyLength) & 0x00FFFFFF;
|
||||||
|
CopyLength = Length - CopyLength;
|
||||||
|
Pos = 0;
|
||||||
|
|
||||||
|
int32_t CopyAmount = (int32_t)m_MMU.RdramSize() - (int32_t)WritePos;
|
||||||
|
if (CopyLength < CopyAmount)
|
||||||
|
{
|
||||||
|
CopyAmount = CopyLength;
|
||||||
|
}
|
||||||
|
if (CopyAmount > 0)
|
||||||
|
{
|
||||||
|
memcpy(&Dest[WritePos], &Source[Pos], CopyAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WritePos += CopyLength + Skip;
|
||||||
|
Pos += CopyLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((g_Reg->SP_DRAM_ADDR_REG & 3) != 0)
|
if (Count > 1)
|
||||||
{
|
{
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
WritePos -= Skip;
|
||||||
}
|
|
||||||
if (((g_Reg->SP_WR_LEN_REG + 1) & 3) != 0)
|
|
||||||
{
|
|
||||||
g_Notify->BreakPoint(__FILE__, __LINE__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(g_MMU->Rdram() + g_Reg->SP_DRAM_ADDR_REG, g_MMU->Dmem() + (g_Reg->SP_MEM_ADDR_REG & 0x1FFF),
|
SP_DMA_BUSY_REG = 0;
|
||||||
g_Reg->SP_WR_LEN_REG + 1);
|
SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
|
||||||
|
|
||||||
g_Reg->SP_DMA_BUSY_REG = 0;
|
m_ExecutedDMARead = true;
|
||||||
g_Reg->SP_STATUS_REG &= ~SP_STATUS_DMA_BUSY;
|
m_SPMemAddrRegRead = Pos | (SP_MEM_ADDR_REG & 0x1000);
|
||||||
|
m_SPDramAddrRegRead = WritePos;
|
||||||
|
SP_RD_LEN_REG = (SP_WR_LEN_REG & 0xFF800000) | 0x00000FF8;
|
||||||
|
SP_WR_LEN_REG = (SP_WR_LEN_REG & 0xFF800000) | 0x00000FF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPRegistersHandler::SystemReset(void)
|
||||||
|
{
|
||||||
|
SP_RD_LEN_REG = 0x00000FF8;
|
||||||
|
SP_WR_LEN_REG = 0x00000FF8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPRegistersHandler::LoadedGameState(void)
|
||||||
|
{
|
||||||
|
m_SPMemAddrRegRead = 0;
|
||||||
|
m_ExecutedDMARead = false;
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "MemoryHandler.h"
|
#include "MemoryHandler.h"
|
||||||
|
#include "MIPSInterfaceHandler.h"
|
||||||
#include <Project64-core\Settings\GameSettings.h>
|
#include <Project64-core\Settings\GameSettings.h>
|
||||||
#include <Project64-core\Settings\DebugSettings.h>
|
#include <Project64-core\Settings\DebugSettings.h>
|
||||||
#include <Project64-core\Logging.h>
|
#include <Project64-core\Logging.h>
|
||||||
|
@ -36,6 +37,7 @@ class SPRegistersHandler :
|
||||||
public MemoryHandler,
|
public MemoryHandler,
|
||||||
public SPRegistersReg,
|
public SPRegistersReg,
|
||||||
private CGameSettings,
|
private CGameSettings,
|
||||||
|
private MIPSInterfaceReg,
|
||||||
private CDebugSettings,
|
private CDebugSettings,
|
||||||
private CLogging
|
private CLogging
|
||||||
{
|
{
|
||||||
|
@ -49,9 +51,17 @@ private:
|
||||||
SPRegistersHandler(const SPRegistersHandler &);
|
SPRegistersHandler(const SPRegistersHandler &);
|
||||||
SPRegistersHandler & operator=(const SPRegistersHandler &);
|
SPRegistersHandler & operator=(const SPRegistersHandler &);
|
||||||
|
|
||||||
|
static void stSystemReset(SPRegistersHandler * _this) { _this->SystemReset(); }
|
||||||
|
static void stLoadedGameState(SPRegistersHandler * _this) { _this->LoadedGameState(); }
|
||||||
|
|
||||||
void SP_DMA_READ();
|
void SP_DMA_READ();
|
||||||
void SP_DMA_WRITE();
|
void SP_DMA_WRITE();
|
||||||
|
void SystemReset(void);
|
||||||
|
void LoadedGameState(void);
|
||||||
|
|
||||||
|
uint32_t m_SPMemAddrRegRead;
|
||||||
|
uint32_t m_SPDramAddrRegRead;
|
||||||
|
bool m_ExecutedDMARead;
|
||||||
CN64System & m_System;
|
CN64System & m_System;
|
||||||
CMipsMemoryVM & m_MMU;
|
CMipsMemoryVM & m_MMU;
|
||||||
CRegisters & m_Reg;
|
CRegisters & m_Reg;
|
||||||
|
|
|
@ -2799,6 +2799,38 @@ void CX86RecompilerOps::LB_KnownAddress(x86Reg Reg, uint32_t VAddr, bool SignExt
|
||||||
MoveConstToX86reg(0, Reg);
|
MoveConstToX86reg(0, Reg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x04000000:
|
||||||
|
if (PAddr < 0x04001000)
|
||||||
|
{
|
||||||
|
if (SignExtend)
|
||||||
|
{
|
||||||
|
MoveSxVariableToX86regByte(((PAddr ^ 3) - 0x04000000) + g_MMU->Dmem(), stdstr_f("Dmem + (%X ^ 3)", (PAddr - 0x04000000)).c_str(), Reg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveZxVariableToX86regByte(((PAddr ^ 3) - 0x04000000) + g_MMU->Dmem(), stdstr_f("Dmem + (%X ^ 3)", (PAddr - 0x04000000)).c_str(), Reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (PAddr < 0x04002000)
|
||||||
|
{
|
||||||
|
if (SignExtend)
|
||||||
|
{
|
||||||
|
MoveSxVariableToX86regByte(((PAddr ^ 3) - 0x04001000) + g_MMU->Imem(), stdstr_f("Imem + (%X ^ 3)", (PAddr - 0x04001000)).c_str(), Reg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveZxVariableToX86regByte(((PAddr ^ 3) - 0x04001000) + g_MMU->Imem(), stdstr_f("Imem + (%X ^ 3)", (PAddr - 0x04001000)).c_str(), Reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MoveConstToX86reg(0, Reg);
|
||||||
|
if (ShowUnhandledMemory())
|
||||||
|
{
|
||||||
|
g_Notify->DisplayError(stdstr_f("%s\nFailed to compile address: %08X", __FUNCTION__, VAddr).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x10000000:
|
case 0x10000000:
|
||||||
if ((PAddr - 0x10000000) < g_Rom->GetRomSize())
|
if ((PAddr - 0x10000000) < g_Rom->GetRomSize())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue