Backport Fixed PPU bus address on cycle 0 + improved MMC3 IRQ timing

This commit is contained in:
vailkyte 2023-05-18 14:14:46 -05:00 committed by GitHub
parent 019a3f9da1
commit 415441a069
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 13 deletions

View File

@ -4,7 +4,6 @@
#include "BaseMapper.h"
#include "CPU.h"
#include "EmulationSettings.h"
#include "A12Watcher.h"
class MMC3 : public BaseMapper
@ -28,7 +27,7 @@ class MMC3 : public BaseMapper
bool _wramEnabled;
bool _wramWriteProtected;
A12Watcher _a12Watcher;
uint64_t _a12LowClock = 0;
bool _forceMmc3RevAIrqs;
@ -189,9 +188,8 @@ class MMC3 : public BaseMapper
{
BaseMapper::StreamState(saving);
ArrayInfo<uint8_t> registers = { _registers, 8 };
SnapshotInfo a12Watcher{ &_a12Watcher };
Stream(_state.Reg8000, _state.RegA000, _state.RegA001, _currentRegister, _chrMode, _prgMode,
_irqReloadValue, _irqCounter, _irqReload, _irqEnabled, a12Watcher,
_irqReloadValue, _irqCounter, _irqReload, _irqEnabled, _a12LowClock,
_wramEnabled, _wramWriteProtected, registers);
}
@ -265,10 +263,22 @@ class MMC3 : public BaseMapper
_console->GetCpu()->SetIrqSource(IRQSource::External);
}
bool IsA12RisingEdge(uint16_t addr)
{
if(addr & 0x1000) {
bool isRisingEdge = _a12LowClock > 0 && (_console->GetCpu()->GetCycleCount() - _a12LowClock) >= 3;
_a12LowClock = 0;
return isRisingEdge;
} else if(_a12LowClock == 0) {
_a12LowClock = _console->GetCpu()->GetCycleCount();
}
return false;
}
public:
virtual void NotifyVRAMAddressChange(uint16_t addr) override
{
if(_a12Watcher.UpdateVramAddress(addr, _console->GetPpu()->GetFrameCycle()) == A12StateChange::Rise) {
if(IsA12RisingEdge(addr)) {
uint32_t count = _irqCounter;
if(_irqCounter == 0 || _irqReload) {
_irqCounter = _irqReloadValue;

View File

@ -112,7 +112,7 @@ void PPU::Reset()
_firstVisibleSpriteAddr = 0;
_lastVisibleSpriteAddr = 0;
memset(_oamDecayCycles, 0, sizeof(_oamDecayCycles));
_enableOamDecay = _settings->CheckFlag(EmulationFlags::EnableOamDecay);
@ -999,7 +999,7 @@ void PPU::ProcessScanline()
}
} else if(_cycle == 337 || _cycle == 339) {
if(IsRenderingEnabled()) {
ReadVram(GetNameTableAddr());
_nextTile.TileAddr = ReadVram(GetNameTableAddr());
if(_scanline == -1 && _cycle == 339 && (_frameCount & 0x01) && _nesModel == NesModel::NTSC && _settings->GetPpuModel() == PpuModel::Ppu2C02) {
//This behavior is NTSC-specific - PAL frames are always the same number of cycles
@ -1270,12 +1270,20 @@ void PPU::Exec()
}
//Cycle = 0
if(_scanline == -1) {
_statusFlags.SpriteOverflow = false;
_statusFlags.Sprite0Hit = false;
//Switch to alternate output buffer (VideoDecoder may still be decoding the last frame buffer)
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
if(_scanline < 240) {
if(_scanline == -1) {
_statusFlags.SpriteOverflow = false;
_statusFlags.Sprite0Hit = false;
//Switch to alternate output buffer (VideoDecoder may still be decoding the last frame buffer)
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
} else if(_prevRenderingEnabled) {
if(_scanline > 0 || (!(_frameCount & 0x01) || _nesModel != NesModel::NTSC || _settings->GetPpuModel() != PpuModel::Ppu2C02)) {
//Set bus address to the tile address calculated from the unused NT fetches at the end of the previous scanline
//This doesn't happen on scanline 0 if the last dot of the previous frame was skipped
SetBusAddress((_nextTile.TileAddr << 4) | (_state.VideoRamAddr >> 12) | _flags.BackgroundPatternAddr);
}
}
} else if(_scanline == 240) {
//At the start of vblank, the bus address is set back to VideoRamAddr.
//According to Visual NES, this occurs on scanline 240, cycle 1, but is done here on cycle for performance reasons