mirror of https://github.com/bsnes-emu/bsnes.git
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!
This commit is contained in:
parent
cc4ab9bc25
commit
793f2e5bf4
|
@ -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.3";
|
static const string Version = "113.4";
|
||||||
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";
|
||||||
|
|
|
@ -266,6 +266,9 @@ auto SuperFamicom::board() const -> string {
|
||||||
if(headerAddress == 0x40ffb0) mode = "EXHIROM-";
|
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-";
|
if(mode == "LOROM-" && headerAddress == 0x407fb0) mode = "EXLOROM-";
|
||||||
|
|
||||||
bool epsonRTC = false;
|
bool epsonRTC = false;
|
||||||
|
|
|
@ -5,11 +5,7 @@ auto CPU::dmaCounter() const -> uint {
|
||||||
|
|
||||||
//joypad auto-poll clock divider
|
//joypad auto-poll clock divider
|
||||||
auto CPU::joypadCounter() const -> uint {
|
auto CPU::joypadCounter() const -> uint {
|
||||||
//todo: this should be &255, but it causes too many issues in games, due to incomplete emulation:
|
return counter.cpu & 255;
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::stepOnce() -> void {
|
auto CPU::stepOnce() -> void {
|
||||||
|
@ -206,6 +202,41 @@ 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,
|
||||||
|
//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()) {
|
if(vcounter() >= ppu.vdisp()) {
|
||||||
//cache enable state at first iteration
|
//cache enable state at first iteration
|
||||||
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll;
|
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = io.autoJoypadPoll;
|
||||||
|
@ -218,11 +249,11 @@ auto CPU::joypadEdge() -> void {
|
||||||
controllerPort1.device->latch(0);
|
controllerPort1.device->latch(0);
|
||||||
controllerPort2.device->latch(0);
|
controllerPort2.device->latch(0);
|
||||||
|
|
||||||
//shift registers are flushed at start of auto joypad polling
|
//shift registers are cleared at start of auto joypad polling
|
||||||
io.joy1 = ~0;
|
io.joy1 = 0;
|
||||||
io.joy2 = ~0;
|
io.joy2 = 0;
|
||||||
io.joy3 = ~0;
|
io.joy3 = 0;
|
||||||
io.joy4 = ~0;
|
io.joy4 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint2 port0 = controllerPort1.device->data();
|
uint2 port0 = controllerPort1.device->data();
|
||||||
|
|
|
@ -94,6 +94,15 @@ auto PPU::main() -> void {
|
||||||
|
|
||||||
auto PPU::scanline() -> void {
|
auto PPU::scanline() -> void {
|
||||||
if(vcounter() == 0) {
|
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<uint16>(output, 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ppubase.display.interlace = io.interlace;
|
ppubase.display.interlace = io.interlace;
|
||||||
ppubase.display.overscan = io.overscan;
|
ppubase.display.overscan = io.overscan;
|
||||||
latch.overscan = io.overscan;
|
latch.overscan = io.overscan;
|
||||||
|
|
|
@ -1,5 +1,13 @@
|
||||||
auto PPU::main() -> void {
|
auto PPU::main() -> void {
|
||||||
if(vcounter() == 0) {
|
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<uint16>(output, 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
display.interlace = io.interlace;
|
display.interlace = io.interlace;
|
||||||
display.overscan = io.overscan;
|
display.overscan = io.overscan;
|
||||||
bg1.frame();
|
bg1.frame();
|
||||||
|
|
|
@ -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
|
//stage 2 uses pseudo-hires in a way that's not compatible with the scanline-based renderer
|
||||||
if(title == "SFC クレヨンシンチャン") fastPPU = false;
|
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
|
//relies on cycle-accurate writes to the echo buffer
|
||||||
if(title == "KOUSHIEN_2") fastDSP = false;
|
if(title == "KOUSHIEN_2") fastDSP = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue