Skip to content

Commit

Permalink
SNES: Fixed CPU bugs when in 6502 emulation mode
Browse files Browse the repository at this point in the history
Based on new cpu tests: https://github.com/gilyon/snes-tests
  • Loading branch information
SourMesen committed Oct 27, 2023
1 parent af2afc4 commit 010d4a6
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 44 deletions.
15 changes: 8 additions & 7 deletions Core/SNES/Coprocessors/SA1/Sa1Cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ class Sa1Cpu : public ISerializable

uint16_t GetDirectAddress(uint16_t offset, bool allowEmulationMode = true);

uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true);
uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true);
uint16_t GetDirectAddressIndirectWord(uint16_t offset);
uint32_t GetDirectAddressIndirectLong(uint16_t offset);

uint8_t GetOpCode();

Expand All @@ -64,7 +64,8 @@ class Sa1Cpu : public ISerializable

uint8_t Read(uint32_t addr, MemoryOperationType type);

void SetSP(uint16_t sp);
void SetSP(uint16_t sp, bool allowEmulationMode = true);
__forceinline void RestrictStackPointerValue();
void SetPS(uint8_t ps);

void SetRegister(uint8_t &reg, uint8_t value);
Expand Down Expand Up @@ -92,11 +93,11 @@ class Sa1Cpu : public ISerializable

uint16_t GetWordValue();

void PushByte(uint8_t value);
uint8_t PopByte();
void PushByte(uint8_t value, bool allowEmulationMode = true);
uint8_t PopByte(bool allowEmulationMode = true);

void PushWord(uint16_t value);
uint16_t PopWord();
void PushWord(uint16_t value, bool allowEmulationMode = true);
uint16_t PopWord(bool allowEmulationMode = true);

//Add/subtract instructions
void Add8(uint8_t value);
Expand Down
33 changes: 21 additions & 12 deletions Core/SNES/SnesCpu.Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,15 +411,16 @@ void SnesCpu::JSL()
uint8_t b1 = ReadOperandByte();
uint8_t b2 = ReadOperandByte();

PushByte(_state.K);
PushByte(_state.K, false);
Idle();

uint8_t b3 = ReadOperandByte();

PushWord(_state.PC - 1);
PushWord(_state.PC - 1, false);

_state.K = b3;
_state.PC = b1 | (b2 << 8);
RestrictStackPointerValue();
IdleEndJump();
}

Expand All @@ -445,7 +446,7 @@ void SnesCpu::JMP_AbsIdxXInd()
void SnesCpu::JSR_AbsIdxXInd()
{
uint8_t lsb = ReadOperandByte();
PushWord(_state.PC);
PushWord(_state.PC, false);
uint8_t msb = ReadOperandByte();

uint16_t baseAddr = (lsb | (msb << 8)) + _state.X;
Expand All @@ -455,6 +456,7 @@ void SnesCpu::JSR_AbsIdxXInd()
msb = ReadData(GetProgramAddress(baseAddr + 1));

_state.PC = (uint16_t)GetProgramAddress(lsb | (msb << 8));
RestrictStackPointerValue();
IdleEndJump();
}

Expand All @@ -479,9 +481,10 @@ void SnesCpu::RTL()
Idle();
Idle();

_state.PC = PopWord();
_state.PC = PopWord(false);
_state.PC++;
_state.K = PopByte();
_state.K = PopByte(false);
RestrictStackPointerValue();
IdleEndJump();
}

Expand Down Expand Up @@ -771,19 +774,22 @@ Push/pull operations
void SnesCpu::PEA()
{
//Push Effective Address
PushWord((uint16_t)_operand);
PushWord((uint16_t)_operand, false);
RestrictStackPointerValue();
}

void SnesCpu::PEI()
{
//Push Effective Indirect address
PushWord(ReadDataWord(_operand));
PushWord(ReadDataWord(_operand), false);
RestrictStackPointerValue();
}

void SnesCpu::PER()
{
//Push Effective Relative address
PushWord((uint16_t)((int16_t)_operand + _state.PC));
PushWord((uint16_t)((int16_t)_operand + _state.PC), false);
RestrictStackPointerValue();
}

void SnesCpu::PHB()
Expand All @@ -795,7 +801,8 @@ void SnesCpu::PHB()
void SnesCpu::PHD()
{
Idle();
PushWord(_state.D);
PushWord(_state.D, false);
RestrictStackPointerValue();
}

void SnesCpu::PHK()
Expand All @@ -817,15 +824,17 @@ void SnesCpu::PLB()
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
Idle();
Idle();
SetRegister(_state.DBR, PopByte());
SetRegister(_state.DBR, PopByte(false));
RestrictStackPointerValue();
}

void SnesCpu::PLD()
{
//"PHD and PLD push and pull two bytes from the stack."
Idle();
Idle();
SetRegister(_state.D, PopWord(), false);
SetRegister(_state.D, PopWord(false), false);
RestrictStackPointerValue();
}

void SnesCpu::PLP()
Expand Down Expand Up @@ -1286,7 +1295,7 @@ void SnesCpu::AddrMode_DirIndIdxY(bool isWrite)

void SnesCpu::AddrMode_DirIndLng()
{
_operand = GetDirectAddressIndirectLong(ReadDirectOperandByte(), false);
_operand = GetDirectAddressIndirectLong(ReadDirectOperandByte());
}

void SnesCpu::AddrMode_DirIndLngIdxY()
Expand Down
42 changes: 24 additions & 18 deletions Core/SNES/SnesCpu.Shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,65 +466,71 @@ uint16_t SnesCpu::GetWordValue()
}
}

void SnesCpu::PushByte(uint8_t value)
void SnesCpu::PushByte(uint8_t value, bool allowEmulationMode)
{
Write(_state.SP, value);
SetSP(_state.SP - 1);
SetSP(_state.SP - 1, allowEmulationMode);
}

uint8_t SnesCpu::PopByte()
uint8_t SnesCpu::PopByte(bool allowEmulationMode)
{
SetSP(_state.SP + 1);
SetSP(_state.SP + 1, allowEmulationMode);
return ReadData(_state.SP);
}

void SnesCpu::PushWord(uint16_t value)
void SnesCpu::PushWord(uint16_t value, bool allowEmulationMode)
{
PushByte(value >> 8);
PushByte((uint8_t)value);
PushByte(value >> 8, allowEmulationMode);
PushByte((uint8_t)value, allowEmulationMode);
}

uint16_t SnesCpu::PopWord()
uint16_t SnesCpu::PopWord(bool allowEmulationMode)
{
uint8_t lo = PopByte();
uint8_t hi = PopByte();
uint8_t lo = PopByte(allowEmulationMode);
uint8_t hi = PopByte(allowEmulationMode);
return lo | hi << 8;
}

uint16_t SnesCpu::GetDirectAddress(uint16_t offset, bool allowEmulationMode)
{
if(allowEmulationMode && _state.EmulationMode && (_state.D & 0xFF) == 0) {
//TODO: Check if new instruction or not (PEI)
return (uint16_t)((_state.D & 0xFF00) | (offset & 0xFF));
} else {
return (uint16_t)(_state.D + offset);
}
}

uint16_t SnesCpu::GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode)
uint16_t SnesCpu::GetDirectAddressIndirectWord(uint16_t offset)
{
uint8_t lsb = ReadData(GetDirectAddress(offset + 0));
uint8_t msb = ReadData(GetDirectAddress(offset + 1));
return (msb << 8) | lsb;
}

uint32_t SnesCpu::GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode)
uint32_t SnesCpu::GetDirectAddressIndirectLong(uint16_t offset)
{
uint8_t b1 = ReadData(GetDirectAddress(offset + 0, allowEmulationMode));
uint8_t b2 = ReadData(GetDirectAddress(offset + 1, allowEmulationMode));
uint8_t b3 = ReadData(GetDirectAddress(offset + 2, allowEmulationMode));
uint8_t b1 = ReadData(GetDirectAddress(offset + 0, false));
uint8_t b2 = ReadData(GetDirectAddress(offset + 1, false));
uint8_t b3 = ReadData(GetDirectAddress(offset + 2, false));
return (b3 << 16) | (b2 << 8) | b1;
}

void SnesCpu::SetSP(uint16_t sp)
void SnesCpu::SetSP(uint16_t sp, bool allowEmulationMode)
{
if(_state.EmulationMode) {
if(allowEmulationMode && _state.EmulationMode) {
_state.SP = 0x100 | (sp & 0xFF);
} else {
_state.SP = sp;
}
}

void SnesCpu::RestrictStackPointerValue()
{
if(_state.EmulationMode) {
_state.SP = 0x100 | (_state.SP & 0xFF);
}
}

void SnesCpu::SetPS(uint8_t ps)
{
_state.PS = ps;
Expand Down
15 changes: 8 additions & 7 deletions Core/SNES/SnesCpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ class SnesCpu : public ISerializable

uint16_t GetDirectAddress(uint16_t offset, bool allowEmulationMode = true);

uint16_t GetDirectAddressIndirectWord(uint16_t offset, bool allowEmulationMode = true);
uint32_t GetDirectAddressIndirectLong(uint16_t offset, bool allowEmulationMode = true);
uint16_t GetDirectAddressIndirectWord(uint16_t offset);
uint32_t GetDirectAddressIndirectLong(uint16_t offset);

uint8_t GetOpCode();

Expand All @@ -72,7 +72,8 @@ class SnesCpu : public ISerializable

uint8_t Read(uint32_t addr, MemoryOperationType type);

void SetSP(uint16_t sp);
void SetSP(uint16_t sp, bool allowEmulationMode = true);
__forceinline void RestrictStackPointerValue();
void SetPS(uint8_t ps);

void SetRegister(uint8_t &reg, uint8_t value);
Expand Down Expand Up @@ -100,11 +101,11 @@ class SnesCpu : public ISerializable

uint16_t GetWordValue();

void PushByte(uint8_t value);
uint8_t PopByte();
void PushByte(uint8_t value, bool allowEmulationMode = true);
uint8_t PopByte(bool allowEmulationMode = true);

void PushWord(uint16_t value);
uint16_t PopWord();
void PushWord(uint16_t value, bool allowEmulationMode = true);
uint16_t PopWord(bool allowEmulationMode = true);

//Add/subtract instructions
void Add8(uint8_t value);
Expand Down

0 comments on commit 010d4a6

Please sign in to comment.