diff --git a/bsnes/heuristics/super-famicom.cpp b/bsnes/heuristics/super-famicom.cpp index 5a93548e..375edf54 100644 --- a/bsnes/heuristics/super-famicom.cpp +++ b/bsnes/heuristics/super-famicom.cpp @@ -6,6 +6,7 @@ struct SuperFamicom { auto manifest() const -> string; auto region() const -> string; + auto videoRegion() const -> string; auto revision() const -> string; auto board() const -> string; auto title() const -> string; @@ -186,6 +187,11 @@ auto SuperFamicom::region() const -> string { return region ? region : "NTSC"; } +auto SuperFamicom::videoRegion() const -> string { + auto region = data[headerAddress + 0x29]; + return (region <= 0x01 || region >= 0x12) ? "NTSC" : "PAL"; +} + auto SuperFamicom::revision() const -> string { string revision; diff --git a/bsnes/processor/wdc65816/instruction.cpp b/bsnes/processor/wdc65816/instruction.cpp index 9250999b..1d39fa2c 100644 --- a/bsnes/processor/wdc65816/instruction.cpp +++ b/bsnes/processor/wdc65816/instruction.cpp @@ -8,7 +8,7 @@ N push(PC.b); IF = 1; DF = 0; PC.l = read(r.vector + 0); - PC.h = read(r.vector + 1); +L PC.h = read(r.vector + 1); PC.b = 0x00; idleJump(); } diff --git a/bsnes/sfc/cpu/irq.cpp b/bsnes/sfc/cpu/irq.cpp index d97983a3..b0bb88c6 100644 --- a/bsnes/sfc/cpu/irq.cpp +++ b/bsnes/sfc/cpu/irq.cpp @@ -3,7 +3,6 @@ auto CPU::irq(bool line) -> void { WDC65816::irq(line); if(line) { status.irqTransition = 1; - r.wai = 0; } } @@ -16,7 +15,6 @@ auto CPU::pollInterrupts() -> void { //NMI hold if(status.nmiHold.lower() && io.nmiEnable) { status.nmiTransition = 1; - r.wai = 0; } //NMI test @@ -28,7 +26,6 @@ auto CPU::pollInterrupts() -> void { status.irqHold = 0; if(status.irqLine && io.irqEnable) { status.irqTransition = 1; - r.wai = 0; } //IRQ test @@ -46,7 +43,6 @@ auto CPU::nmitimenUpdate(uint8 data) -> void { if(io.virqEnable && !io.hirqEnable && status.irqLine) { status.irqTransition = 1; - r.wai = 0; } else if(!io.irqEnable) { status.irqLine = 0; status.irqTransition = 0; @@ -54,7 +50,6 @@ auto CPU::nmitimenUpdate(uint8 data) -> void { if(io.nmiEnable.raise(data & 0x80) && status.nmiLine) { status.nmiTransition = 1; - r.wai = 0; } status.irqLock = 1; @@ -80,12 +75,14 @@ auto CPU::timeup() -> bool { auto CPU::nmiTest() -> bool { if(!status.nmiTransition) return 0; status.nmiTransition = 0; + r.wai = 0; return 1; } auto CPU::irqTest() -> bool { if(!status.irqTransition) return 0; status.irqTransition = 0; + r.wai = 0; return !r.p.i; } diff --git a/bsnes/sfc/interface/configuration.cpp b/bsnes/sfc/interface/configuration.cpp index d9392e7b..709c64ef 100644 --- a/bsnes/sfc/interface/configuration.cpp +++ b/bsnes/sfc/interface/configuration.cpp @@ -19,6 +19,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void { bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock); bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace); + bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle); bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit); bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective); diff --git a/bsnes/sfc/interface/configuration.hpp b/bsnes/sfc/interface/configuration.hpp index 6ea850b8..b8f1fda4 100644 --- a/bsnes/sfc/interface/configuration.hpp +++ b/bsnes/sfc/interface/configuration.hpp @@ -32,6 +32,7 @@ struct Configuration { bool fast = true; bool deinterlace = true; bool noSpriteLimit = false; + uint renderCycle = 512; struct Mode7 { uint scale = 1; bool perspective = true; diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index 7df82e8c..3775ab99 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -29,6 +29,7 @@ auto PPU::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.p auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; } auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; } auto PPU::deinterlace() const -> bool { return configuration.hacks.ppu.deinterlace; } +auto PPU::renderCycle() const -> uint { return configuration.hacks.ppu.renderCycle; } #define ppu ppufast PPU::PPU() { @@ -88,7 +89,7 @@ auto PPU::main() -> void { if(system.frameCounter == 0) { uint y = vcounter(); - step(512); + step(renderCycle()); if(y >= 1 && y <= 239) { if(io.displayDisable || y >= vdisp()) { lines[y].io.displayDisable = true; diff --git a/bsnes/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp index 98756bf1..60949ee9 100644 --- a/bsnes/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -19,6 +19,7 @@ struct PPU : PPUcounter { alwaysinline auto hdSupersample() const -> bool; alwaysinline auto hdMosaic() const -> bool; alwaysinline auto deinterlace() const -> bool; + alwaysinline auto renderCycle() const -> uint; //ppu.cpp PPU(); diff --git a/bsnes/target-bsnes/program/game.cpp b/bsnes/target-bsnes/program/game.cpp index c3b5b6e3..33ac1a89 100644 --- a/bsnes/target-bsnes/program/game.cpp +++ b/bsnes/target-bsnes/program/game.cpp @@ -130,6 +130,7 @@ auto Program::loadSuperFamicom(string location) -> bool { } } superFamicom.title = heuristics.title(); + superFamicom.region = heuristics.videoRegion(); superFamicom.manifest = manifest ? manifest : heuristics.manifest(); hackPatchMemory(rom); superFamicom.document = BML::unserialize(superFamicom.manifest); diff --git a/bsnes/target-bsnes/program/hacks.cpp b/bsnes/target-bsnes/program/hacks.cpp index 91deb40f..6f271926 100644 --- a/bsnes/target-bsnes/program/hacks.cpp +++ b/bsnes/target-bsnes/program/hacks.cpp @@ -3,14 +3,26 @@ auto Program::hackCompatibility() -> void { bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked(); bool fastDSP = emulatorSettings.fastDSP.checked(); bool coprocessorDelayedSync = emulatorSettings.coprocessorDelayedSyncOption.checked(); + uint renderCycle = 512; auto title = superFamicom.title; + auto region = superFamicom.region; + + //relies on mid-scanline rendering techniques if(title == "AIR STRIKE PATROL" || title == "DESERT FIGHTER") fastPPU = false; + + //relies on cycle-accurate writes to the echo buffer if(title == "KOUSHIEN_2") fastDSP = false; + + //extremely timing sensitive if(title == "RENDERING RANGER R2") fastDSP = false; + //fixes an errant scanline on the title screen due to writing to PPU registers too late + if(title == "ADVENTURES OF FRANKEN" && region == "PAL") renderCycle = 32; + emulator->configure("Hacks/PPU/Fast", fastPPU); emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit); + emulator->configure("Hacks/PPU/RenderCycle", renderCycle); emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale); emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample); diff --git a/bsnes/target-bsnes/program/program.hpp b/bsnes/target-bsnes/program/program.hpp index a7b17752..92930b5c 100644 --- a/bsnes/target-bsnes/program/program.hpp +++ b/bsnes/target-bsnes/program/program.hpp @@ -150,6 +150,7 @@ public: struct SuperFamicom : Game { string title; + string region; vector program; vector data; vector expansion;