Skip to content

Commit

Permalink
SNES: Performance improvements
Browse files Browse the repository at this point in the history
This makes performance equal or slightly better to what it was before all of the recent accuracy improvements
  • Loading branch information
SourMesen committed Dec 24, 2024
1 parent a9d3cb5 commit 30d28c8
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 52 deletions.
4 changes: 3 additions & 1 deletion Core/SNES/InternalRegisters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,5 +408,7 @@ void InternalRegisters::Serialize(Serializer& s)

SV(_hCounter);
SV(_vCounter);
SV(_irqEnabled);
if(!s.IsSaving()) {
_irqEnabled = _state.EnableHorizontalIrq || _state.EnableVerticalIrq;
}
}
6 changes: 5 additions & 1 deletion Core/SNES/SnesCpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,11 @@ void SnesCpu::IdleTakeBranch()
void SnesCpu::ProcessCpuCycle()
{
_state.CycleCount++;
_state.IrqLock = _dmaController->ProcessPendingTransfers();
if(_dmaController->HasPendingTransfer()){
_state.IrqLock = _dmaController->ProcessPendingTransfers();
} else {
_state.IrqLock = false;
}
DetectNmiSignalEdge();
}

Expand Down
2 changes: 1 addition & 1 deletion Core/SNES/SnesCpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class SnesCpu : public ISerializable
void AddrMode_StkRel();
void AddrMode_StkRelIndIdxY();

void RunOp();
__forceinline void RunOp();
__noinline void ProcessHaltedState();
__forceinline void CheckForInterrupts();

Expand Down
2 changes: 2 additions & 0 deletions Core/SNES/SnesDmaController.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class SnesDmaController final : public ISerializable
void BeginHdmaTransfer();
void BeginHdmaInit();

__forceinline bool HasPendingTransfer() { return _needToProcess; }

bool ProcessPendingTransfers();

void Write(uint16_t addr, uint8_t value);
Expand Down
64 changes: 61 additions & 3 deletions Core/SNES/SnesMemoryManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ void SnesMemoryManager::Initialize(SnesConsole *console)
{
_masterClock = 0;
_openBus = 0;

_cpuSpeed = 8;
UpdateExecCallbacks();

_console = console;
_emu = console->GetEmulator();
_regs = console->GetInternalRegisters();
Expand Down Expand Up @@ -125,6 +128,33 @@ void SnesMemoryManager::GenerateMasterClockTable()
}
}

template<uint8_t clocks>
void SnesMemoryManager::IncMasterClock()
{
if constexpr(clocks == 2) {
Exec();
} else if constexpr(clocks == 4) {
Exec();
Exec();
} else if constexpr(clocks == 6) {
Exec();
Exec();
Exec();
} else if constexpr(clocks == 8) {
Exec();
Exec();
Exec();
Exec();
} else if constexpr(clocks == 12) {
Exec();
Exec();
Exec();
Exec();
Exec();
Exec();
}
}

void SnesMemoryManager::IncMasterClock4()
{
Exec();
Expand Down Expand Up @@ -236,7 +266,7 @@ void SnesMemoryManager::ProcessEvent()

uint8_t SnesMemoryManager::Read(uint32_t addr, MemoryOperationType type)
{
IncrementMasterClockValue(_cpuSpeed - 4);
(this->*_execRead)();

uint8_t value;
IMemoryHandler *handler = _mappings.GetHandler(addr);
Expand Down Expand Up @@ -311,7 +341,8 @@ void SnesMemoryManager::PeekBlock(uint32_t addr, uint8_t *dest)

void SnesMemoryManager::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
{
IncrementMasterClockValue(_cpuSpeed);
(this->*_execWrite)();

if(_emu->ProcessMemoryWrite<CpuType::Snes>(addr, value, type)) {
IMemoryHandler* handler = _mappings.GetHandler(addr);
if(handler) {
Expand Down Expand Up @@ -389,7 +420,30 @@ uint8_t SnesMemoryManager::GetCpuSpeed()

void SnesMemoryManager::SetCpuSpeed(uint8_t speed)
{
_cpuSpeed = speed;
if(_cpuSpeed != speed) {
_cpuSpeed = speed;
UpdateExecCallbacks();
}
}

void SnesMemoryManager::UpdateExecCallbacks()
{
switch(_cpuSpeed) {
case 6:
_execRead = &SnesMemoryManager::IncMasterClock<2>;
_execWrite = &SnesMemoryManager::IncMasterClock<6>;
break;

case 8:
_execRead = &SnesMemoryManager::IncMasterClock<4>;
_execWrite = &SnesMemoryManager::IncMasterClock<8>;
break;

case 12:
_execRead = &SnesMemoryManager::IncMasterClock<8>;
_execWrite = &SnesMemoryManager::IncMasterClock<12>;
break;
}
}

MemoryType SnesMemoryManager::GetMemoryTypeBusA()
Expand Down Expand Up @@ -420,4 +474,8 @@ void SnesMemoryManager::Serialize(Serializer &s)
SV(_memTypeBusA); SV(_nextEvent); SV(_nextEventClock);
SVArray(_workRam, SnesMemoryManager::WorkRamSize);
SV(_registerHandlerB);

if(!s.IsSaving()) {
UpdateExecCallbacks();
}
}
9 changes: 8 additions & 1 deletion Core/SNES/SnesMemoryManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ class SnesMemoryManager : public ISerializable
vector<unique_ptr<IMemoryHandler>> _workRamHandlers;
uint8_t _masterClockTable[0x800] = {};

void Exec();
typedef void(SnesMemoryManager::*Func)();
Func _execRead = nullptr;
Func _execWrite = nullptr;

template<uint8_t clocks> void IncMasterClock();
void UpdateExecCallbacks();

__forceinline void Exec();

void ProcessEvent();

Expand Down
44 changes: 44 additions & 0 deletions Core/SNES/Spc.Instructions.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,51 @@
#include "pch.h"
#include "SNES/Spc.h"
#include "SNES/SnesMemoryManager.h"
#include "Shared/Emulator.h"
#include "Utilities/HexUtilities.h"

void Spc::Run()
{
if(!_enabled) {
//Used to temporarily disable the SPC when overclocking is enabled
return;
} else if(_state.StopState != SnesCpuStopState::Running) {
//STOP or SLEEP were executed - execution is stopped forever.
_emu->ProcessHaltedCpu<CpuType::Spc>();
return;
}

uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
while(_state.Cycle < targetCycle) {
ProcessCycle();
}
}

void Spc::ProcessCycle()
{
if(_opStep == SpcOpStep::ReadOpCode) {
#ifndef DUMMYSPC
_emu->ProcessInstruction<CpuType::Spc>();
#endif
_opCode = GetOpCode();
_opStep = SpcOpStep::Addressing;
_opSubStep = 0;
} else {
Exec();
}

if(_pendingCpuRegUpdate) {
//There appears to be a delay between the moment the CPU writes
//to a register and when the SPC can see the new value
//This makes the SPC see the newly written value after a 1 SPC cycle delay
//This allows Kishin Douji Zenki to boot without freezing
for(int i = 0; i < 4; i++) {
_state.CpuRegs[i] = _state.NewCpuRegs[i];
}
_pendingCpuRegUpdate = false;
}
}

void Spc::EndOp()
{
_opStep = SpcOpStep::ReadOpCode;
Expand Down
42 changes: 0 additions & 42 deletions Core/SNES/Spc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,48 +378,6 @@ void Spc::DspWriteRam(uint16_t addr, uint8_t value)
_ram[addr] = value;
}

void Spc::Run()
{
if(!_enabled) {
//Used to temporarily disable the SPC when overclocking is enabled
return;
} else if(_state.StopState != SnesCpuStopState::Running) {
//STOP or SLEEP were executed - execution is stopped forever.
_emu->ProcessHaltedCpu<CpuType::Spc>();
return;
}

uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio);
while(_state.Cycle < targetCycle) {
ProcessCycle();
}
}

void Spc::ProcessCycle()
{
if(_opStep == SpcOpStep::ReadOpCode) {
#ifndef DUMMYSPC
_emu->ProcessInstruction<CpuType::Spc>();
#endif
_opCode = GetOpCode();
_opStep = SpcOpStep::Addressing;
_opSubStep = 0;
} else {
Exec();
}

if(_pendingCpuRegUpdate) {
//There appears to be a delay between the moment the CPU writes
//to a register and when the SPC can see the new value
//This makes the SPC see the newly written value after a 1 SPC cycle delay
//This allows Kishin Douji Zenki to boot without freezing
for(int i = 0; i < 4; i++) {
_state.CpuRegs[i] = _state.NewCpuRegs[i];
}
_pendingCpuRegUpdate = false;
}
}

void Spc::ProcessEndFrame()
{
Run();
Expand Down
6 changes: 3 additions & 3 deletions Core/SNES/Spc.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ class Spc : public ISerializable
uint8_t GetOpCode();
uint8_t ReadOperandByte();

void IncCycleCount(int32_t addr);
__forceinline void IncCycleCount(int32_t addr);
void EndOp();
void EndAddr();
void ProcessCycle();
void Exec();
__forceinline void ProcessCycle();
__forceinline void Exec();

void UpdateClockRatio();
void ExitExecLoop();
Expand Down

0 comments on commit 30d28c8

Please sign in to comment.