From 793f2e5bf44a421237905c6638ce05f6e2d6cb5f Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Mon, 30 Dec 2019 06:00:17 +0900 Subject: [PATCH] v113.4 Completely disabled auto-joypad timing (happens immediately) (fixes World Masters until this can be emulated fully) Disabled fast PPU for Winter Olympic Games (changes OAM tiledata address mid-frame) Disabled fast PPU for World Cup Striker (I'm not sure yet why it's not compatible) Cleared overscan region when disabling overscan (fixes World Class Service SNES Tester) Added override for invalid SNES header in Yuyu no Quiz de Go! Go! --- bsnes/emulator/emulator.hpp | 2 +- bsnes/heuristics/super-famicom.cpp | 3 ++ bsnes/sfc/cpu/timing.cpp | 51 ++++++++++++++++++++++------ bsnes/sfc/ppu-fast/ppu.cpp | 9 +++++ bsnes/sfc/ppu/main.cpp | 8 +++++ bsnes/target-bsnes/program/hacks.cpp | 7 ++++ 6 files changed, 69 insertions(+), 11 deletions(-) diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index f9b771d3..e367da1c 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -29,7 +29,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "113.3"; + static const string Version = "113.4"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/heuristics/super-famicom.cpp b/bsnes/heuristics/super-famicom.cpp index 7c1507eb..0101a246 100644 --- a/bsnes/heuristics/super-famicom.cpp +++ b/bsnes/heuristics/super-famicom.cpp @@ -266,6 +266,9 @@ auto SuperFamicom::board() const -> string { if(headerAddress == 0x40ffb0) mode = "EXHIROM-"; } + //this game's title ovewrites the map mode with '!' (0x21), but is a LOROM game + if(title() == "YUYU NO QUIZ DE GO!GO") mode = "LOROM-"; + if(mode == "LOROM-" && headerAddress == 0x407fb0) mode = "EXLOROM-"; bool epsonRTC = false; diff --git a/bsnes/sfc/cpu/timing.cpp b/bsnes/sfc/cpu/timing.cpp index d4f713bd..da6f668c 100644 --- a/bsnes/sfc/cpu/timing.cpp +++ b/bsnes/sfc/cpu/timing.cpp @@ -5,11 +5,7 @@ auto CPU::dmaCounter() const -> uint { //joypad auto-poll clock divider auto CPU::joypadCounter() const -> uint { - //todo: this should be &255, but it causes too many issues in games, due to incomplete emulation: - //Nuke (PD): inputs do not work (unless clearing $421x to $00) - //Taikyoku Igo - Goliath: start button not acknowledged (unless clearing $421x to $ff) - //Tatakae Genshijin 2: attract sequence ends early - return counter.cpu & 31; + return counter.cpu & 255; } auto CPU::stepOnce() -> void { @@ -206,6 +202,41 @@ auto CPU::dmaEdge() -> void { //called every 256 clocks; see CPU::step() auto CPU::joypadEdge() -> void { + //todo: auto-joypad polling should poll one bit every 256 clock cycles, + //but it causes too many issues in games, due to incomplete emulation: + //Nuke (PD): inputs do not work (unless clearing $421x to $00) + //Taikyoku Igo - Goliath: start button not acknowledged (unless clearing $421x to $ff) + //Tatakae Genshijin 2: attract sequence ends early + //Williams Arcade's Greatest Hits: verifies io.joy# should be set to 0 and not ~0 + //World Masters Golf: inputs do not work at all + + //immediate polling: + if(!status.autoJoypadCounter && vcounter() >= ppu.vdisp()) { + controllerPort1.device->latch(1); + controllerPort2.device->latch(1); + controllerPort1.device->latch(0); + controllerPort2.device->latch(0); + + io.joy1 = 0; + io.joy2 = 0; + io.joy3 = 0; + io.joy4 = 0; + + for(uint index : range(16)) { + uint2 port0 = controllerPort1.device->data(); + uint2 port1 = controllerPort2.device->data(); + + io.joy1 = io.joy1 << 1 | port0.bit(0); + io.joy2 = io.joy2 << 1 | port1.bit(0); + io.joy3 = io.joy3 << 1 | port0.bit(1); + io.joy4 = io.joy4 << 1 | port1.bit(1); + } + + status.autoJoypadCounter = 16; + } + return; + + //disabled cycle-timed polling: if(vcounter() >= ppu.vdisp()) { //cache enable state at first iteration if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll; @@ -218,11 +249,11 @@ auto CPU::joypadEdge() -> void { controllerPort1.device->latch(0); controllerPort2.device->latch(0); - //shift registers are flushed at start of auto joypad polling - io.joy1 = ~0; - io.joy2 = ~0; - io.joy3 = ~0; - io.joy4 = ~0; + //shift registers are cleared at start of auto joypad polling + io.joy1 = 0; + io.joy2 = 0; + io.joy3 = 0; + io.joy4 = 0; } uint2 port0 = controllerPort1.device->data(); diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index 474d63e4..0ebb3450 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -94,6 +94,15 @@ auto PPU::main() -> void { auto PPU::scanline() -> void { if(vcounter() == 0) { + if(latch.overscan && !io.overscan) { + //when disabling overscan, clear the overscan area that won't be rendered to: + for(uint y = 1; y <= 240; y++) { + if(y >= 8 && y <= 231) continue; + auto output = ppu.output + y * 1024; + memory::fill(output, 1024); + } + } + ppubase.display.interlace = io.interlace; ppubase.display.overscan = io.overscan; latch.overscan = io.overscan; diff --git a/bsnes/sfc/ppu/main.cpp b/bsnes/sfc/ppu/main.cpp index be5f8a43..d2330d7c 100644 --- a/bsnes/sfc/ppu/main.cpp +++ b/bsnes/sfc/ppu/main.cpp @@ -1,5 +1,13 @@ auto PPU::main() -> void { if(vcounter() == 0) { + if(display.overscan && !io.overscan) { + //when disabling overscan, clear the overscan area that won't be rendered to: + for(uint y = 1; y <= 240; y++) { + if(y >= 8 && y <= 231) continue; + auto output = ppu.output + y * 1024; + memory::fill(output, 1024); + } + } display.interlace = io.interlace; display.overscan = io.overscan; bg1.frame(); diff --git a/bsnes/target-bsnes/program/hacks.cpp b/bsnes/target-bsnes/program/hacks.cpp index 4f831525..b0e89472 100644 --- a/bsnes/target-bsnes/program/hacks.cpp +++ b/bsnes/target-bsnes/program/hacks.cpp @@ -15,6 +15,13 @@ auto Program::hackCompatibility() -> void { //stage 2 uses pseudo-hires in a way that's not compatible with the scanline-based renderer if(title == "SFC クレヨンシンチャン") fastPPU = false; + //title screen game select (after choosing a game) changes OAM tiledata address mid-frame + //this is only supported by the cycle-based PPU renderer + if(title == "Winter olympics") fastPPU = false; + + //title screen shows remnants of the flag after choosing a language with the scanline-based renderer + if(title == "WORLD CUP STRIKER") fastPPU = false; + //relies on cycle-accurate writes to the echo buffer if(title == "KOUSHIEN_2") fastDSP = false;