Also fixed a few scenarios where the PPU memory write callbacks did not allow the Lua script to change the value about to be written (because the callback was called too late)
-Some warnings were suppressed (undefined-inline and return-type-c-linkage)
-Warnings as errors was enabled to make CI builds fail when warnings are introduced
-Slightly altered the behavior of SnesCpu::IdleOrRead, but this should match what ares does
-Fixed BG shifter reload timing by moving it to the last dot of every 8-dot sequence (instead of the first dot). Fixes the "BG Serial In" test.
-Changed sprite shifter init/reset logic to allow edge cases where the shifter starts outputting pixels on a different scanline (when rendering was disabled during specific portions of the scanline, etc). Fixes the "Stale Sprite Shift Regs" test.
-Tweaked code in ProcessScanlineImpl, etc. to slightly improve performance
-Fixed missing PPU register mirror reads/writes in event viewer
This adds some caching of whether we need to do sprite processing to reduce the overhead of checks when no work needs to be done. It improves performance by 1-2%.
Co-authored-by: Sour <[email protected]>
* NES: Improve sprite fetch accuracy.
For sprite fetch, this improves in-range handling (which also helps with calculating the address to fetch) and stops treating sprites differently depending on whether we think they were valid based on sprite eval. The PPU uses just OAM2 during sprite fetch and not any other state from eval about whether sprites were good or not.
This change does not affect the behavior of any automated NES tests or AccuracyCoin. It improves performance slightly.
* NES: Allow sprites on scanline 0.
During pre-render, the PPU doesn't do OAM2 init or sprite eval, but it does do sprite fetch using the current contents of OAM2, which will usually be what's left over after sprite evaluation on scanline 239. This change allows these sprites to be drawn.
In AccuracyCoin, this change makes Mesen pass the Sprites on Scanline 0 test. However, it is detected as an RGB PPU because the skipped dot doesn't currently impact the position of the first sprite out of the shifters, which is a much more invasive change.
* NES: Improve sprite shifter accuracy.
* Fix hd pack player+builder logic (Sour)
* Improve dotskip accuracy without hurting performance.
* Change rendering check in pixel output (improves accuracy, sometimes performance).
---------
Co-authored-by: Sour <[email protected]>
* NES: Reimplement PAL forced OAM refresh according to new research.
On PAL, vblank is so long that OAM may decay during it. The PPU works around this by incrementing the OAM1 address every odd dot (delayed by 1, so happening on the following even dot) during scanlines 265-310. The PPU reads from OAM1 on every dot during vblank/fblank, so by repeatedly visiting all the addresses, it reads every row and keeps OAM fresh.
When implementing this, I found that OAM was corrupting reliably. This is because the forced refresh normally leaves the OAM1 address set to $8C when rendering begins, which triggers the 2C02E+ OAM corruption bug. However, all 3 types of OAM corruption are actually fixed on PAL, so this change also restricts OAM corruption to the NTSC console region.
All tests continue to pass with this change. blargg's oam_read test fails as it should, but not as severely as it does on real hardware. I'm not clear on why, but certainly part of it is that this change allows OAM1 to be incremented twice on a single dot. Adding hacky support for limiting this to just 1 increment makes it fail a little more severely, but still not as bad as on hardware (and that change is out of scope for this commit). My best guess right now is that it has to do with the precise timing of the $2004 writes, as the OAM write and increment delays depend on the timing of the end of the CPU write.
* NES: Dendy UM6561AF-2 has OAM corruption except on $2003 writes.
Based on my testing, frame-start (2C02E+ style) and mid-frame rendering toggle (NTSC style) OAM corruption happen on Dendy, but not $2003 write OAM corruption. So, this changes corruption emulation to match that.
Tested with oam_flicker_test, oam_flicker_test_reenable, oam_read, oam_stress, and Huge Insect.
* NES: Improve OAM corruption accuracy.
Our understanding of OAM row corruption has significantly improved since Mesen's implementation of the feature that was based on oam_flicker_test.nes results. This change improves the accuracy of the two OAM corruption emulation options.
Primary OAM (OAM1) and secondary OAM (OAM2) live in the same block of memory, made up of 9-byte rows where the first 8 bytes are consecutive OAM1 bytes and the last byte is an OAM2 byte. The PPU accesses OAM on every dot. On some dots, it uses the OAM1 address ($2003), and on other dots, it uses its internal OAM2 address. If the address changes during an OAM access (the 2nd half of a dot) and this causes the selected row to change, then it can trigger either analog corruption (the new row gets 'random' data) or a row copy (the old row's 9 bytes are copied to the new row). More information can be found at nesdev.org/wiki/OAM_internals.
Address selection is fairly simple. When rendering is off, OAM1ADDR is always selected. When rendering is on, OAM1ADDR is selected on odd dots in 1-256, and otherwise OAM2ADDR is selected.
Corruption occurs on the NES in 3 situations:
1. Writing to $2003 on NTSC PPUs, because writes are not synchronized at all and so the CPU open bus value and the new value can both cause the row to change mid-access. Depending on the timing, this can do nothing, cause analog corruption, or cause row copy. This was fixed in PAL PPUs, but we don't know about Dendy.
2. Toggling rendering on an OAM2ADDR dot. Depending on the direction and the timing, this can do nothing or cause analog corruption of or row copy to the new row.
3. On 2C02E and later PPUs, having a row mismatch if rendering is enabled at the start of pre-render. This always causes a row copy from the OAM1ADDR row to the OAM2ADDR row and is required for Huge Insect to spawn enemies in level 1. (2C02C PPUs have some corruption in this situation, too, but it is not yet understood.)
This change adds support for OAM corruption in situations 1 and 2 using the "Enable PPU $2003/rendering-toggle OAM corruption" setting, which is off by default. This does not take alignment into account at all and only does row copy, not analog corruption. Recommended for developers, but probably undesirable for actual users. This setting was previously called "Enable PPU OAM row corruption emulation". Note that situation 1 ($2003 writes) is not perfectly matching blargg's oam_read test results in the most vulnerable alignment yet, suggesting there is more research to be done on this.
Situation 3 is now supported under the "Disable PPU frame-start OAM corruption (2C02D and earlier)" setting, so this corruption happens by default. Mesen was already doing some corruption here to support Huge Insect, with the previous version of this setting being called "Disable PPU OAMADDR bug emulation". These changes make the corruption more accurate and apply in more situations, so there is a chance it will break some user software, but because it is required for a game, we've opted to have it on by default. This feature should match hardware very closely, as it doesn't have the timing and analog aspects seen in situations 1 and 2.
To support these, sprite rendering was reworked a bit to more accurately manage the OAM1 and OAM2 addresses during rendering. This should make sprite rendering behavior more accurate when rendering is toggled mid-frame, although there are still inaccuracies that come up if you do this. The OAM2 address can also now be seen in the register viewer below $2003.
This was tested against a suite of NES tests, AccuracyCoin $2004 Stress Test, and oam_flicker_test.nes/oam_flicker_test_reenable.nes. The $2003-based corruption causes a few tests to change behavior when enabled (which is expected), but oam_read and related tests are not failing exactly right yet. Tests otherwise pass.
* Changes based on code review.
* Removed _spriteAddrL/_spriteAddrH members, use local variables instead.
* Simplify firstVisibleSpriteAddr assignment
---------
Co-authored-by: Sour <[email protected]>
* NES: Update [OAM1ADDR] decay timestamp during vblank/fblank.
The NES accesses OAM on every single dot. When rendering is off, it uses OAM1ADDR for this, typically guaranteeing that a single row will not decay when rendering is disabled for an extended period of time. This means, for example, that sprite 0 should never decay in Battletoads despite its extended vblank.
This change updates the decay timestamp of the current OAM1ADDR row at the start of every blanking scanline, to simulate this behavior in the common case while minimizing performance impact.
* NES: Fix OAM decay counter array size.
Decay happens row-wise and there are 32 rows, so we should only be tracking 32 counters, not 64. The code only uses the first 32 counters.
* GB: Link cable support with two local consoles
* GB: Fix crash when color blending is enabled
* GB: Fix formatting
* GB: Link UI fixes, control fixes, audio fixes
Copied from Sour's branch. Also a separate change to use separate savefiles.
* GB: Try to avoid crashes from buffer overflows
* GB: Separate savefiles with linked multiplayer
* GB: Add support for faster link speed
* GB: Move enum to correct file
* GB: Refactor, move serial transfer to function
* -Fixed secondary console sometimes running far ahead of the main console when frame counters did not match (e.g because one console had their LCD disabled longer, etc.) This would cause buffer overflows in the audio buffer.
-Fixed screen tearing when both consoles are not perfectly in sync (because of the LCD being disabled for a different amount of time, etc.)
-Fixed main console not calling PlayQueuedAudio properly mid-frame
-Reuse VS Dualsystem code to merge audio/video when possible/simple and moved that to AvMergeUtilities
Some visual glitches can appear on the secondary screen (for GB) while rewinding, but this can't really be fixed.
* Fixed warning (unused local variable)
* Prevent loading single-console save states when in dual-console modes
* Disable debugger for VS DualSystem's subconsole. Fixes issues when debugging VS DualSystem games
* Code cleanup
* Rework solution to disable debugger on second console to improve performance
Added InternalRunFrame for nes & gb to avoid checking for the presence of the second console after each cpu instruction
* Don't enable the linked GB option by default
* Removed unused function
* Netplay: Force game to reload after updating emulation settings when connecting to the server (or when the host changes game)
This ensures that e.g the GB link cable setting is applied and that the game loads correctly, regardless of the client's link cable settings (otherwise the game could load without the link mode enabled, etc.)
---------
Co-authored-by: Sour <[email protected]>
This could cause DMC DMA to happen on the wrong cycle parity, causing issues with code that uses sprite DMA to align 4016 reads to prevent DMC DMA from corrupting the read value.
* Code: Add auto-formatting rules for C++ projects (clang-format) and enforce code style via "clang-format" and "dotnet format"
* fix ui format warnings
I also made small changes to the state machine logic. They delay is now 5 ppu cycles instead of 6. I don't know why I initially used 6.
While the state machine is running, it keeps re-enabling _needStateUpdate, otherwise the state machine doesn't run every cycle.
ShiftTileRegisters() only runs when rendering is enabled.
The high bit shift register also shifts in a 1. I'm unsure why this isn't passing the BG Serial IN test.
These changes make Mesen pass the following tests in the AccuracyCoin test ROM:
Implied Dummy Reads (RTS now dummy reads during the final CPU cycle.)
Branch Dummy Reads (Branches properly dummy read from the pre-incremented-PCH Address)
Address $2004 Behavior (Writes to $2004 during a visible scanline cause OAMADDR to be bitwise ANDed with $FC)
$2004 Stress Test (All OAM2 writes become reads after the OAM Address wraps around from $FF to $00)
$2007 Stress Test (Added a small delay to the PPU Read Buffer being updated, Sprite Fetch performs a second Nametable Fetch instead of an Attribute Table Fetch, The Dummy Nametable Fetch on dot 257 uses the correct value of the v register)
This could cause OAM decay to be detected even though it should never be possible for OAM to decay while rendering is enabled (sprite eval will refresh all OAM rows on each scanline)
Tweaks the H/L address bits increment/reset logic during evaluation to better match how hardware behaves (based on test rom). Also changes sprite 0 hits to consider sprite 0 to be the first sprite that sprite eval loads (based on oamaddr), even if the sprite is not actually the first entry in OAM