From 6e5cff66c3b8693a8e69258c4d48d91a2382b012 Mon Sep 17 00:00:00 2001 From: L-Spiro Date: Wed, 15 Mar 2023 19:58:55 +0900 Subject: [PATCH] Attempting to fix NMI timing issue. Now edge is properly detected and delay is properly 1 cycle. --- Src/Cpu/LSNCpu6502.cpp | 12 ++++++++---- Src/Cpu/LSNCpu6502.h | 10 ++++++---- Src/Ppu/LSNPpu2C0X.h | 29 ++++++++++++++++------------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Src/Cpu/LSNCpu6502.cpp b/Src/Cpu/LSNCpu6502.cpp index f249355..e80dc31 100644 --- a/Src/Cpu/LSNCpu6502.cpp +++ b/Src/Cpu/LSNCpu6502.cpp @@ -1085,7 +1085,9 @@ namespace lsn { m_ui8DmaPos( 0 ), m_ui8DmaValue( 0 ), m_bNmiStatusLine( false ), + m_bLastNmiStatusLine( false ), m_bHandleNmi( false ), + m_bDetectedNmi( false ), m_bIrqStatusLine( false ), m_bHandleIrq( false ), m_bIsReadCycle( true ), @@ -1128,7 +1130,7 @@ namespace lsn { pc.PC = m_pbBus->Read( 0xFFFC ) | (m_pbBus->Read( 0xFFFD ) << 8); - m_bHandleNmi = m_bNmiStatusLine = false; + m_bHandleNmi = m_bDetectedNmi = m_bLastNmiStatusLine = m_bNmiStatusLine = false; m_bHandleIrq = m_bIrqStatusLine = false; } @@ -1142,7 +1144,9 @@ namespace lsn { (this->*m_pfTickFunc)(); //m_bHandleNmi |= (m_bNmiStatusLine && --m_ui8NmiCounter == 0); - m_bHandleNmi |= m_bNmiStatusLine; + m_bHandleNmi = m_bDetectedNmi; + m_bDetectedNmi |= (!m_bLastNmiStatusLine && m_bNmiStatusLine); + m_bLastNmiStatusLine = m_bNmiStatusLine; m_bHandleIrq |= m_bIrqStatusLine; ++m_ui64CycleCount; @@ -1709,7 +1713,7 @@ namespace lsn { LSN_PUSH( m_ui8Status | uint8_t( LSN_STATUS_FLAGS::LSN_SF_BREAK ) ); // It is also at this point that the branch vector is determined. Store it in LSN_CPU_CONTEXT::a.ui16Address. m_ccCurContext.a.ui16Address = m_bHandleNmi ? uint16_t( LSN_VECTORS::LSN_V_NMI ) : uint16_t( LSN_VECTORS::LSN_V_IRQ_BRK ); - if ( m_bHandleNmi ) { m_bHandleNmi = false; } + if ( m_bHandleNmi ) { m_bHandleNmi = m_bDetectedNmi = false; } } /** Pushes status without B. */ @@ -1721,7 +1725,7 @@ namespace lsn { LSN_PUSH( ui8Status ); // It is also at this point that the branch vector is determined. Store it in LSN_CPU_CONTEXT::a.ui16Address. m_ccCurContext.a.ui16Address = m_bHandleNmi ? uint16_t( LSN_VECTORS::LSN_V_NMI ) : uint16_t( LSN_VECTORS::LSN_V_IRQ_BRK ); - if ( m_bHandleNmi ) { m_bHandleNmi = false; } + if ( m_bHandleNmi ) { m_bHandleNmi = m_bDetectedNmi = false; } } /** Pushes status an decrements S. */ diff --git a/Src/Cpu/LSNCpu6502.h b/Src/Cpu/LSNCpu6502.h index 912e989..8fcbc4c 100644 --- a/Src/Cpu/LSNCpu6502.h +++ b/Src/Cpu/LSNCpu6502.h @@ -1,4 +1,4 @@ -/** +/** * Copyright L. Spiro 2021 * * Written by: Shawn (L. Spiro) Wilcoxen @@ -225,7 +225,9 @@ namespace lsn { uint8_t m_ui8DmaPos; /**< The DMA transfer offset.*/ uint8_t m_ui8DmaValue; /**< The DMA transfer value.*/ bool m_bNmiStatusLine; /**< The status line for NMI. */ - bool m_bHandleNmi; /**< Once an NMI edge is detected, this is set to indicate that it needs to be handled. */ + bool m_bLastNmiStatusLine; /**< THe last status line for NMI. */ + bool m_bDetectedNmi; /**< The edge detector for the φ2 part of the cycle. */ + bool m_bHandleNmi; /**< Once an NMI edge is detected, this is set to indicate that it needs to be handled on the φ1 of the next cycle. */ bool m_bIrqStatusLine; /**< The status line for IRQ. */ bool m_bHandleIrq; /**< Once the IRQ status line is detected as having triggered, this tells us to handle an IRQ on the next instruction. */ bool m_bIsReadCycle; /**< Is this CPU cycle a read cycle? */ @@ -754,9 +756,9 @@ namespace lsn { inline void CCpu6502::Cmp( uint8_t _ui8RegVal, uint8_t _ui8OpVal ) { // If the value in the accumulator is equal or greater than the compared value, the Carry will be set. SetBit( m_ui8Status, _ui8RegVal >= _ui8OpVal ); - // The equal (Z) and negative (N) flags will be set based on equality or lack thereof… + // The equal (Z) and negative (N) flags will be set based on equality or lack thereof… SetBit( m_ui8Status, _ui8RegVal == _ui8OpVal ); - // …and the sign (IE A>=$80) of the accumulator. + // …and the sign (IE A>=$80) of the accumulator. SetBit( m_ui8Status, ((_ui8RegVal - _ui8OpVal) & 0x80) != 0 ); } diff --git a/Src/Ppu/LSNPpu2C0X.h b/Src/Ppu/LSNPpu2C0X.h index 16a6578..c63f822 100644 --- a/Src/Ppu/LSNPpu2C0X.h +++ b/Src/Ppu/LSNPpu2C0X.h @@ -748,19 +748,22 @@ namespace lsn { */ static void LSN_FASTCALL Read2002( void * _pvParm0, uint16_t /*_ui16Parm1*/, uint8_t * /*_pui8Data*/, uint8_t &_ui8Ret ) { CPpu2C0X * ppPpu = reinterpret_cast(_pvParm0); - // Reading $2002 within a few PPU clocks of when VBL is set results in special-case behavior. - if ( ppPpu->m_ui16CurY == (_tPreRender + _tRender + _tPostRender) ) { - // Reading one PPU clock before reads it as clear and never sets the flag or generates NMI for that frame. - if ( ppPpu->m_ui16CurX == (1 - 1) ) { - ppPpu->m_bSuppressNmi = true; - ppPpu->m_psPpuStatus.s.ui8VBlank = 0; - //::OutputDebugStringA( ("ULTIMATE MOVE: SUPPRESSION!!\r\n") ); - } - else if ( ppPpu->m_ui16CurX == (1 - 0) || ppPpu->m_ui16CurX == (1 + 1) ) { - // Reading on the same PPU clock or one later reads it as set, clears it, and suppresses the NMI for that frame. - ppPpu->m_bSuppressNmi = true; - ppPpu->m_psPpuStatus.s.ui8VBlank = 1; - //::OutputDebugStringA( ("ULTIMATE MOVE: SUPPRESSION!!\r\n") ); + if ( ppPpu->m_pcPpuCtrl.s.ui8Nmi ) { + // Reading $2002 within a few PPU clocks of when VBL is set results in special-case behavior. + if ( ppPpu->m_ui16CurY == (_tPreRender + _tRender + _tPostRender) ) { + // Reading one PPU clock before reads it as clear and never sets the flag or generates NMI for that frame. + if ( ppPpu->m_ui16CurX == (1 - 1) ) { + ppPpu->m_bSuppressNmi = true; + ppPpu->m_psPpuStatus.s.ui8VBlank = 0; + //::OutputDebugStringA( ("ULTIMATE MOVE: SUPPRESSION!!\r\n") ); + } + else if ( ppPpu->m_ui16CurX == (1 - 0) || ppPpu->m_ui16CurX == (1 + 1) ) { + // Reading on the same PPU clock or one later reads it as set, clears it, and suppresses the NMI for that frame. + ppPpu->m_bSuppressNmi = true; + ppPpu->m_psPpuStatus.s.ui8VBlank = 1; + //::OutputDebugStringA( ("ULTIMATE MOVE: SUPPRESSION!!\r\n") ); + } + //ppPpu->m_bSuppressNmi = false; // This line changes nothing whether present or absent. } }