mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
793f2e5bf4
commit
dde9b4c2c7
|
@ -29,7 +29,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
|
|
|
@ -202,69 +202,71 @@ 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)
|
||||
//fast joypad polling is a hack to work around edge cases not currently emulated in auto-joypad polling.
|
||||
//below is a list of games that have had input issues over the years.
|
||||
//Nuke (PD): inputs do not work
|
||||
//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
|
||||
//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
|
||||
|
||||
//immediate polling:
|
||||
if(!status.autoJoypadCounter && vcounter() >= ppu.vdisp()) {
|
||||
controllerPort1.device->latch(1);
|
||||
controllerPort2.device->latch(1);
|
||||
controllerPort1.device->latch(0);
|
||||
controllerPort2.device->latch(0);
|
||||
if(configuration.hacks.cpu.fastJoypadPolling) {
|
||||
//Taikyoku Igo - Goliath
|
||||
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;
|
||||
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();
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
} 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(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
||||
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/Deinterlace", hacks.ppu.deinterlace);
|
||||
bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle);
|
||||
|
|
|
@ -33,6 +33,7 @@ struct Configuration {
|
|||
struct CPU {
|
||||
uint overclock = 100;
|
||||
bool fastMath = false;
|
||||
bool fastJoypadPolling = false;
|
||||
} cpu;
|
||||
struct PPU {
|
||||
bool fast = true;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
auto Program::hackCompatibility() -> void {
|
||||
string entropy = settings.emulator.hack.entropy;
|
||||
bool fastJoypadPolling = false;
|
||||
bool fastPPU = settings.emulator.hack.ppu.fast;
|
||||
bool fastPPUNoSpriteLimit = settings.emulator.hack.ppu.noSpriteLimit;
|
||||
bool fastDSP = settings.emulator.hack.dsp.fast;
|
||||
|
@ -9,6 +10,8 @@ auto Program::hackCompatibility() -> void {
|
|||
auto title = superFamicom.title;
|
||||
auto region = superFamicom.region;
|
||||
|
||||
if(title == "TAIKYOKU-IGO Goliath") fastJoypadPolling = true;
|
||||
|
||||
//relies on mid-scanline rendering techniques
|
||||
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/CPU/FastJoypadPolling", fastJoypadPolling);
|
||||
emulator->configure("Hacks/PPU/Fast", fastPPU);
|
||||
emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit);
|
||||
emulator->configure("Hacks/PPU/RenderCycle", renderCycle);
|
||||
|
|
Loading…
Reference in New Issue