mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-23 00:13:05 +02:00
v113.5
It seems auto-joypad poll timing is needed for most games. So that's back in as before. Instead, I added an override for Taikyoku Igo - Goliath specifically, until auto-joypad emulation can be improved further.
This commit is contained in:
@@ -29,7 +29,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "bsnes";
|
static const string Name = "bsnes";
|
||||||
static const string Version = "113.4";
|
static const string Version = "113.5";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org";
|
static const string Website = "https://byuu.org";
|
||||||
|
@@ -202,69 +202,71 @@ auto CPU::dmaEdge() -> void {
|
|||||||
|
|
||||||
//called every 256 clocks; see CPU::step()
|
//called every 256 clocks; see CPU::step()
|
||||||
auto CPU::joypadEdge() -> void {
|
auto CPU::joypadEdge() -> void {
|
||||||
//todo: auto-joypad polling should poll one bit every 256 clock cycles,
|
//fast joypad polling is a hack to work around edge cases not currently emulated in auto-joypad polling.
|
||||||
//but it causes too many issues in games, due to incomplete emulation:
|
//below is a list of games that have had input issues over the years.
|
||||||
//Nuke (PD): inputs do not work (unless clearing $421x to $00)
|
//Nuke (PD): inputs do not work
|
||||||
//Taikyoku Igo - Goliath: start button not acknowledged (unless clearing $421x to $ff)
|
//Super Conflict: sends random inputs even with no buttons pressed
|
||||||
|
//Super Star Wars: Start button auto-unpauses
|
||||||
|
//Taikyoku Igo - Goliath: start button not acknowledged
|
||||||
//Tatakae Genshijin 2: attract sequence ends early
|
//Tatakae Genshijin 2: attract sequence ends early
|
||||||
//Williams Arcade's Greatest Hits: verifies io.joy# should be set to 0 and not ~0
|
//Williams Arcade's Greatest Hits: inputs fire on their own
|
||||||
//World Masters Golf: inputs do not work at all
|
//World Masters Golf: inputs do not work at all
|
||||||
|
|
||||||
//immediate polling:
|
if(configuration.hacks.cpu.fastJoypadPolling) {
|
||||||
if(!status.autoJoypadCounter && vcounter() >= ppu.vdisp()) {
|
//Taikyoku Igo - Goliath
|
||||||
controllerPort1.device->latch(1);
|
if(!status.autoJoypadCounter && vcounter() >= ppu.vdisp()) {
|
||||||
controllerPort2.device->latch(1);
|
controllerPort1.device->latch(1);
|
||||||
controllerPort1.device->latch(0);
|
controllerPort2.device->latch(1);
|
||||||
controllerPort2.device->latch(0);
|
controllerPort1.device->latch(0);
|
||||||
|
controllerPort2.device->latch(0);
|
||||||
|
|
||||||
io.joy1 = 0;
|
io.joy1 = 0;
|
||||||
io.joy2 = 0;
|
io.joy2 = 0;
|
||||||
io.joy3 = 0;
|
io.joy3 = 0;
|
||||||
io.joy4 = 0;
|
io.joy4 = 0;
|
||||||
|
|
||||||
for(uint index : range(16)) {
|
for(uint index : range(16)) {
|
||||||
uint2 port0 = controllerPort1.device->data();
|
uint2 port0 = controllerPort1.device->data();
|
||||||
uint2 port1 = controllerPort2.device->data();
|
uint2 port1 = controllerPort2.device->data();
|
||||||
|
|
||||||
io.joy1 = io.joy1 << 1 | port0.bit(0);
|
io.joy1 = io.joy1 << 1 | port0.bit(0);
|
||||||
io.joy2 = io.joy2 << 1 | port1.bit(0);
|
io.joy2 = io.joy2 << 1 | port1.bit(0);
|
||||||
io.joy3 = io.joy3 << 1 | port0.bit(1);
|
io.joy3 = io.joy3 << 1 | port0.bit(1);
|
||||||
io.joy4 = io.joy4 << 1 | port1.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;
|
|
||||||
status.autoJoypadActive = status.autoJoypadCounter <= 15;
|
|
||||||
|
|
||||||
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
|
||||||
if(status.autoJoypadCounter == 0) {
|
|
||||||
controllerPort1.device->latch(1);
|
|
||||||
controllerPort2.device->latch(1);
|
|
||||||
controllerPort1.device->latch(0);
|
|
||||||
controllerPort2.device->latch(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();
|
status.autoJoypadCounter = 16;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if(vcounter() >= ppu.vdisp()) {
|
||||||
|
//cache enable state at first iteration
|
||||||
|
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll;
|
||||||
|
status.autoJoypadActive = status.autoJoypadCounter <= 15;
|
||||||
|
|
||||||
status.autoJoypadCounter++;
|
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
||||||
|
if(status.autoJoypadCounter == 0) {
|
||||||
|
controllerPort1.device->latch(1);
|
||||||
|
controllerPort2.device->latch(1);
|
||||||
|
controllerPort1.device->latch(0);
|
||||||
|
controllerPort2.device->latch(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();
|
||||||
|
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++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
|||||||
bind(text, "Hacks/Entropy", hacks.entropy);
|
bind(text, "Hacks/Entropy", hacks.entropy);
|
||||||
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
||||||
bind(boolean, "Hacks/CPU/FastMath", hacks.cpu.fastMath);
|
bind(boolean, "Hacks/CPU/FastMath", hacks.cpu.fastMath);
|
||||||
|
bind(boolean, "Hacks/CPU/FastJoypadPolling", hacks.cpu.fastJoypadPolling);
|
||||||
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
||||||
bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace);
|
bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace);
|
||||||
bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle);
|
bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle);
|
||||||
|
@@ -33,6 +33,7 @@ struct Configuration {
|
|||||||
struct CPU {
|
struct CPU {
|
||||||
uint overclock = 100;
|
uint overclock = 100;
|
||||||
bool fastMath = false;
|
bool fastMath = false;
|
||||||
|
bool fastJoypadPolling = false;
|
||||||
} cpu;
|
} cpu;
|
||||||
struct PPU {
|
struct PPU {
|
||||||
bool fast = true;
|
bool fast = true;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
auto Program::hackCompatibility() -> void {
|
auto Program::hackCompatibility() -> void {
|
||||||
string entropy = settings.emulator.hack.entropy;
|
string entropy = settings.emulator.hack.entropy;
|
||||||
|
bool fastJoypadPolling = false;
|
||||||
bool fastPPU = settings.emulator.hack.ppu.fast;
|
bool fastPPU = settings.emulator.hack.ppu.fast;
|
||||||
bool fastPPUNoSpriteLimit = settings.emulator.hack.ppu.noSpriteLimit;
|
bool fastPPUNoSpriteLimit = settings.emulator.hack.ppu.noSpriteLimit;
|
||||||
bool fastDSP = settings.emulator.hack.dsp.fast;
|
bool fastDSP = settings.emulator.hack.dsp.fast;
|
||||||
@@ -9,6 +10,8 @@ auto Program::hackCompatibility() -> void {
|
|||||||
auto title = superFamicom.title;
|
auto title = superFamicom.title;
|
||||||
auto region = superFamicom.region;
|
auto region = superFamicom.region;
|
||||||
|
|
||||||
|
if(title == "TAIKYOKU-IGO Goliath") fastJoypadPolling = true;
|
||||||
|
|
||||||
//relies on mid-scanline rendering techniques
|
//relies on mid-scanline rendering techniques
|
||||||
if(title == "AIR STRIKE PATROL" || title == "DESERT FIGHTER") fastPPU = false;
|
if(title == "AIR STRIKE PATROL" || title == "DESERT FIGHTER") fastPPU = false;
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ auto Program::hackCompatibility() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emulator->configure("Hacks/Entropy", entropy);
|
emulator->configure("Hacks/Entropy", entropy);
|
||||||
|
emulator->configure("Hacks/CPU/FastJoypadPolling", fastJoypadPolling);
|
||||||
emulator->configure("Hacks/PPU/Fast", fastPPU);
|
emulator->configure("Hacks/PPU/Fast", fastPPU);
|
||||||
emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit);
|
emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit);
|
||||||
emulator->configure("Hacks/PPU/RenderCycle", renderCycle);
|
emulator->configure("Hacks/PPU/RenderCycle", renderCycle);
|
||||||
|
Reference in New Issue
Block a user