SA-1: Fixed SA-1 vector logic

Reads done by the code should return the values at the read address, rather than returning the vector register value (fixes Gradius/Contra 3 SA-1 romhacks that are known to work on hardware)
This commit is contained in:
Sour 2020-03-01 17:51:02 -05:00
parent 806523055f
commit 1d6253d2e5
8 changed files with 50 additions and 37 deletions

View file

@ -475,7 +475,7 @@ void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt)
ClearFlags(ProcFlags::Decimal);
_state.K = 0;
_state.PC = ReadDataWord(vector);
_state.PC = ReadVector(vector);
} else {
PushByte(_state.K);
PushWord(_state.PC);
@ -485,7 +485,7 @@ void Cpu::ProcessInterrupt(uint16_t vector, bool forHardwareInterrupt)
ClearFlags(ProcFlags::Decimal);
_state.K = 0;
_state.PC = ReadDataWord(vector);
_state.PC = ReadVector(vector);
}
}

View file

@ -88,6 +88,17 @@ void Cpu::ProcessCpuCycle()
_state.IrqLock = _dmaController->ProcessPendingTransfers();
}
uint16_t Cpu::ReadVector(uint16_t vector)
{
//Overridden in SA-1 to return the correct value directly, rather than loading from ROM
return ReadDataWord(vector);
}
uint16_t Cpu::GetResetVector()
{
return _memoryManager->PeekWord(Cpu::ResetVector);
}
#ifndef DUMMYCPU
uint8_t Cpu::Read(uint32_t addr, MemoryOperationType type)
{
@ -106,8 +117,3 @@ void Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
UpdateIrqNmiFlags();
}
#endif
uint16_t Cpu::GetResetVector()
{
return _memoryManager->PeekWord(Cpu::ResetVector);
}

View file

@ -63,6 +63,8 @@ private:
uint16_t ReadOperandWord();
uint32_t ReadOperandLong();
uint16_t ReadVector(uint16_t vector);
uint8_t Read(uint32_t addr, MemoryOperationType type);
void SetSP(uint16_t sp);

View file

@ -603,9 +603,7 @@ void Sa1::UpdatePrgRomMappings()
void Sa1::UpdateVectorMappings()
{
MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings();
_sa1VectorHandler.reset(new Sa1VectorHandler(cpuMappings->GetHandler(0xF000), &_state, false));
_cpuVectorHandler.reset(new Sa1VectorHandler(cpuMappings->GetHandler(0xF000), &_state, true));
_mappings.RegisterHandler(0x00, 0x00, 0xF000, 0xFFFF, _sa1VectorHandler.get());
_cpuVectorHandler.reset(new Sa1VectorHandler(cpuMappings->GetHandler(0xF000), &_state));
cpuMappings->RegisterHandler(0x00, 0x00, 0xF000, 0xFFFF, _cpuVectorHandler.get());
}
@ -785,6 +783,20 @@ CpuState Sa1::GetCpuState()
return _cpu->GetState();
}
uint16_t Sa1::ReadVector(uint16_t vector)
{
switch(vector) {
case Sa1Cpu::NmiVector: return _state.Sa1NmiVector;
case Sa1Cpu::ResetVector: return _state.Sa1ResetVector;
case Sa1Cpu::IrqVector: return _state.Sa1IrqVector;
}
//BRK/COP vectors are taken from ROM
uint8_t low = ReadSa1(vector);
uint8_t high = ReadSa1(vector + 1);
return (high << 8) | low;
}
MemoryMappings* Sa1::GetMemoryMappings()
{
return &_mappings;

View file

@ -32,7 +32,6 @@ private:
unique_ptr<IMemoryHandler> _iRamHandler;
unique_ptr<IMemoryHandler> _bwRamHandler;
unique_ptr<IMemoryHandler> _sa1VectorHandler;
unique_ptr<IMemoryHandler> _cpuVectorHandler;
vector<unique_ptr<IMemoryHandler>> _cpuBwRamHandlers;
@ -90,5 +89,6 @@ public:
uint32_t DebugGetInternalRamSize();
CpuState GetCpuState();
uint16_t ReadVector(uint16_t vector);
MemoryMappings* GetMemoryMappings();
};

View file

@ -129,9 +129,14 @@ void Sa1Cpu::Write(uint32_t addr, uint8_t value, MemoryOperationType type)
_sa1->WriteSa1(addr, value, type);
}
uint16_t Sa1Cpu::ReadVector(uint16_t vector)
{
return _sa1->ReadVector(vector);
}
uint16_t Sa1Cpu::GetResetVector()
{
return _sa1->ReadSa1(Sa1Cpu::ResetVector) | (_sa1->ReadSa1(Sa1Cpu::ResetVector+1) << 8);
return _sa1->ReadVector(Sa1Cpu::ResetVector);
}
void Sa1Cpu::IncreaseCycleCount(uint64_t cycleCount)

View file

@ -40,6 +40,7 @@ private:
uint8_t GetOpCode();
uint16_t ReadVector(uint16_t vector);
uint16_t GetResetVector();
void ProcessCpuCycle(uint32_t addr);

View file

@ -9,43 +9,30 @@ class Sa1VectorHandler : public IMemoryHandler
private:
IMemoryHandler * _handler;
Sa1State* _state;
bool _forSnesCpu;
public:
Sa1VectorHandler(IMemoryHandler* handler, Sa1State* state, bool forSnesCpu)
Sa1VectorHandler(IMemoryHandler* handler, Sa1State* state)
{
_handler = handler;
_state = state;
_forSnesCpu = forSnesCpu;
}
uint8_t Read(uint32_t addr) override
{
if(addr >= Sa1Cpu::NmiVector && addr <= Sa1Cpu::ResetVector + 1) {
//Override the regular handlers
if(_forSnesCpu) {
if(_state->UseCpuNmiVector) {
if(addr == Sa1Cpu::NmiVector) {
return (uint8_t)_state->CpuNmiVector;
} else if(addr == Sa1Cpu::NmiVector + 1) {
return (uint8_t)(_state->CpuNmiVector >> 8);
}
if(_state->UseCpuNmiVector) {
if(addr == Sa1Cpu::NmiVector) {
return (uint8_t)_state->CpuNmiVector;
} else if(addr == Sa1Cpu::NmiVector + 1) {
return (uint8_t)(_state->CpuNmiVector >> 8);
}
if(_state->UseCpuIrqVector) {
if(addr == Sa1Cpu::IrqVector) {
return (uint8_t)_state->CpuIrqVector;
} else if(addr == Sa1Cpu::IrqVector + 1) {
return (uint8_t)(_state->CpuIrqVector >> 8);
}
}
} else {
switch(addr) {
case Sa1Cpu::NmiVector: return (uint8_t)_state->Sa1NmiVector;
case Sa1Cpu::NmiVector + 1: return (uint8_t)(_state->Sa1NmiVector >> 8);
case Sa1Cpu::ResetVector: return (uint8_t)_state->Sa1ResetVector;
case Sa1Cpu::ResetVector + 1: return (uint8_t)(_state->Sa1ResetVector >> 8);
case Sa1Cpu::IrqVector: return (uint8_t)_state->Sa1IrqVector;
case Sa1Cpu::IrqVector + 1: return (uint8_t)(_state->Sa1IrqVector >> 8);
}
if(_state->UseCpuIrqVector) {
if(addr == Sa1Cpu::IrqVector) {
return (uint8_t)_state->CpuIrqVector;
} else if(addr == Sa1Cpu::IrqVector + 1) {
return (uint8_t)(_state->CpuIrqVector >> 8);
}
}
}