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:
byuu 2019-12-31 10:22:31 +09:00
parent 793f2e5bf4
commit dde9b4c2c7
5 changed files with 63 additions and 55 deletions

View File

@ -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";

View File

@ -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++;
}
}
}

View File

@ -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);

View File

@ -33,6 +33,7 @@ struct Configuration {
struct CPU {
uint overclock = 100;
bool fastMath = false;
bool fastJoypadPolling = false;
} cpu;
struct PPU {
bool fast = true;

View File

@ -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);