mirror of https://github.com/bsnes-emu/bsnes.git
v108.15
Add "No VRAM Blocking" and "Echo Shadow RAM" options: These allow compatibility with very old ROM hacks that only previously ran in ZSNES and earlier Snes9X releases.
This commit is contained in:
parent
03aaaba889
commit
08e5e81609
|
@ -29,7 +29,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "108.14";
|
||||
static const string Version = "108.15";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
|
|
|
@ -612,7 +612,7 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); }
|
|||
//// Echo
|
||||
|
||||
// Current echo buffer pointer for left/right channel
|
||||
#define ECHO_PTR( ch ) (&m.ram [m.t_echo_ptr + ch * 2])
|
||||
#define ECHO_PTR( ch ) (&m.echo [m.t_echo_ptr + ch * 2])
|
||||
|
||||
// Sample in echo history buffer, where 0 is the oldest
|
||||
#define ECHO_FIR( i ) (m.echo_hist_pos [i])
|
||||
|
@ -835,9 +835,10 @@ void SPC_DSP::run( int clocks_remain )
|
|||
|
||||
//// Setup
|
||||
|
||||
void SPC_DSP::init( void* ram_64k )
|
||||
void SPC_DSP::init( void* ram_64k, void* echo_64k )
|
||||
{
|
||||
m.ram = (uint8_t*) ram_64k;
|
||||
m.ram = (uint8_t*) ram_64k;
|
||||
m.echo = (uint8_t*) echo_64k;
|
||||
mute_voices( 0 );
|
||||
disable_surround( false );
|
||||
set_output( 0, 0 );
|
||||
|
@ -861,7 +862,8 @@ void SPC_DSP::init( void* ram_64k )
|
|||
|
||||
void SPC_DSP::soft_reset_common()
|
||||
{
|
||||
require( m.ram ); // init() must have been called already
|
||||
require( m.ram ); // init() must have been called already
|
||||
require( m.echo );
|
||||
|
||||
m.noise = 0x4000;
|
||||
m.echo_hist_pos = m.echo_hist;
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
// Setup
|
||||
|
||||
// Initializes DSP and has it use the 64K RAM provided
|
||||
void init( void* ram_64k );
|
||||
void init( void* ram_64k, void* echo_64k );
|
||||
|
||||
// Sets destination for output samples. If out is NULL or out_size is 0,
|
||||
// doesn't generate any.
|
||||
|
@ -178,7 +178,8 @@ private:
|
|||
voice_t voices [voice_count];
|
||||
|
||||
// non-emulation state
|
||||
uint8_t* ram; // 64K shared RAM between DSP and SMP
|
||||
uint8_t* ram; // 64K shared RAM between DSP and SMP
|
||||
uint8_t* echo; // should point at the same memory as ram; used for older hack compatibility
|
||||
int mute_mask;
|
||||
sample_t* out;
|
||||
sample_t* out_end;
|
||||
|
|
|
@ -30,6 +30,12 @@ auto DSP::read(uint8 address) -> uint8 {
|
|||
}
|
||||
|
||||
auto DSP::write(uint8 address, uint8 data) -> void {
|
||||
if(configuration.hacks.dsp.echoShadow) {
|
||||
if(address == 0x6c && (data & 0x20)) {
|
||||
memset(echoram, 0x00, 65536);
|
||||
}
|
||||
}
|
||||
|
||||
spc_dsp.write(address, data);
|
||||
}
|
||||
|
||||
|
@ -42,7 +48,12 @@ auto DSP::power(bool reset) -> void {
|
|||
stream = Emulator::audio.createStream(2, system.apuFrequency() / 768.0);
|
||||
|
||||
if(!reset) {
|
||||
spc_dsp.init(apuram);
|
||||
if(!configuration.hacks.dsp.echoShadow) {
|
||||
spc_dsp.init(apuram, apuram);
|
||||
} else {
|
||||
memset(echoram, 0x00, 65536);
|
||||
spc_dsp.init(apuram, echoram);
|
||||
}
|
||||
spc_dsp.reset();
|
||||
spc_dsp.set_output(samplebuffer, 8192);
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,9 @@ private:
|
|||
bool fastDSP = false;
|
||||
SPC_DSP spc_dsp;
|
||||
int16 samplebuffer[8192];
|
||||
|
||||
//unserialized:
|
||||
uint8 echoram[64 * 1024] = {};
|
||||
};
|
||||
|
||||
extern DSP dsp;
|
||||
|
|
|
@ -22,12 +22,14 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
|||
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(boolean, "Hacks/PPU/NoVRAMBlocking", hacks.ppu.noVRAMBlocking);
|
||||
bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale);
|
||||
bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective);
|
||||
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
|
||||
bind(boolean, "Hacks/PPU/Mode7/Mosaic", hacks.ppu.mode7.mosaic);
|
||||
bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast);
|
||||
bind(boolean, "Hacks/DSP/Cubic", hacks.dsp.cubic);
|
||||
bind(boolean, "Hacks/DSP/EchoShadow", hacks.dsp.echoShadow);
|
||||
bind(boolean, "Hacks/Coprocessor/DelayedSync", hacks.coprocessor.delayedSync);
|
||||
bind(boolean, "Hacks/Coprocessor/PreferHLE", hacks.coprocessor.preferHLE);
|
||||
bind(natural, "Hacks/SA1/Overclock", hacks.sa1.overclock);
|
||||
|
|
|
@ -33,6 +33,7 @@ struct Configuration {
|
|||
bool fast = true;
|
||||
bool deinterlace = true;
|
||||
bool noSpriteLimit = false;
|
||||
bool noVRAMBlocking = false;
|
||||
uint renderCycle = 512;
|
||||
struct Mode7 {
|
||||
uint scale = 1;
|
||||
|
@ -44,6 +45,7 @@ struct Configuration {
|
|||
struct DSP {
|
||||
bool fast = true;
|
||||
bool cubic = false;
|
||||
bool echoShadow = false;
|
||||
} dsp;
|
||||
struct Coprocessor {
|
||||
bool delayedSync = true;
|
||||
|
|
|
@ -29,7 +29,7 @@ auto PPU::readVRAM() -> uint16 {
|
|||
|
||||
template<bool Byte>
|
||||
auto PPU::writeVRAM(uint8 data) -> void {
|
||||
if(!io.displayDisable && cpu.vcounter() < vdisp()) return;
|
||||
if(!io.displayDisable && cpu.vcounter() < vdisp() && !noVRAMBlocking()) return;
|
||||
Line::flush();
|
||||
auto address = vramAddress();
|
||||
if constexpr(Byte == 0) {
|
||||
|
|
|
@ -30,6 +30,7 @@ auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.s
|
|||
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; }
|
||||
auto PPU::noVRAMBlocking() const -> bool { return configuration.hacks.ppu.noVRAMBlocking; }
|
||||
#define ppu ppufast
|
||||
|
||||
PPU::PPU() {
|
||||
|
|
|
@ -20,6 +20,7 @@ struct PPU : PPUcounter {
|
|||
alwaysinline auto hdMosaic() const -> bool;
|
||||
alwaysinline auto deinterlace() const -> bool;
|
||||
alwaysinline auto renderCycle() const -> uint;
|
||||
alwaysinline auto noVRAMBlocking() const -> bool;
|
||||
|
||||
//ppu.cpp
|
||||
PPU();
|
||||
|
|
|
@ -6,12 +6,14 @@ auto Program::load() -> void {
|
|||
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast);
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit);
|
||||
emulator->configure("Hacks/PPU/NoVRAMBlocking", settings.emulator.hack.ppu.noVRAMBlocking);
|
||||
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);
|
||||
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
|
||||
emulator->configure("Hacks/DSP/Fast", settings.emulator.hack.dsp.fast);
|
||||
emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic);
|
||||
emulator->configure("Hacks/DSP/EchoShadow", settings.emulator.hack.dsp.echoShadow);
|
||||
emulator->configure("Hacks/Coprocessor/DelayedSync", settings.emulator.hack.coprocessor.delayedSync);
|
||||
emulator->configure("Hacks/Coprocessor/PreferHLE", settings.emulator.hack.coprocessor.preferHLE);
|
||||
emulator->configure("Hacks/SuperFX/Overclock", settings.emulator.hack.superfx.overclock);
|
||||
|
|
|
@ -65,6 +65,15 @@ auto EmulatorSettings::create() -> void {
|
|||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
||||
});
|
||||
noVRAMBlocking.setText("No VRAM blocking").setToolTip(
|
||||
"This option emulates a bug in older releases of ZSNES and Snes9X where VRAM blocking was not emulated.\n"
|
||||
"A few older ROM hacks relied on this behavior, and will render graphics incorrectly if not enabled.\n"
|
||||
"Not only is this extremely inaccurate to real hardware, it also hurts the speed of the fast PPU.\n"
|
||||
"Do not enable this option unless you need to play a game that is incompatible with bsnes otherwise."
|
||||
).setChecked(settings.emulator.hack.ppu.noVRAMBlocking).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noVRAMBlocking = noVRAMBlocking.checked();
|
||||
emulator->configure("Hacks/PPU/NoVRAMBlocking", settings.emulator.hack.ppu.noVRAMBlocking);
|
||||
});
|
||||
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
|
||||
mode7ScaleLabel.setText("Scale:");
|
||||
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
||||
|
@ -104,6 +113,14 @@ auto EmulatorSettings::create() -> void {
|
|||
settings.emulator.hack.dsp.cubic = cubicInterpolation.checked();
|
||||
emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic);
|
||||
});
|
||||
echoShadow.setText("Echo shadow RAM").setToolTip(
|
||||
"This option emulates a bug in ZSNES where echo RAM was treated as separate from APU RAM.\n"
|
||||
"Many older ROM hacks for Super Mario World relied on this behavior, and will crash without enabling this.\n"
|
||||
"It is, however, extremely inaccurate to real hardware and should not be enabled unless required."
|
||||
).setChecked(settings.emulator.hack.dsp.echoShadow).onToggle([&] {
|
||||
settings.emulator.hack.dsp.echoShadow = echoShadow.checked();
|
||||
//not a run-time setting: do not call emulator->configure() here.
|
||||
});
|
||||
coprocessorLabel.setText("Coprocessors").setFont(Font().setBold());
|
||||
coprocessorDelayedSyncOption.setText("Fast mode").setChecked(settings.emulator.hack.coprocessor.delayedSync).onToggle([&] {
|
||||
settings.emulator.hack.coprocessor.delayedSync = coprocessorDelayedSyncOption.checked();
|
||||
|
|
|
@ -117,12 +117,14 @@ auto Settings::process(bool load) -> void {
|
|||
bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast);
|
||||
bind(boolean, "Emulator/Hack/PPU/Deinterlace", emulator.hack.ppu.deinterlace);
|
||||
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
|
||||
bind(boolean, "Emulator/Hack/PPU/NoVRAMBlocking", emulator.hack.ppu.noVRAMBlocking);
|
||||
bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale);
|
||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective);
|
||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
|
||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Mosaic", emulator.hack.ppu.mode7.mosaic);
|
||||
bind(boolean, "Emulator/Hack/DSP/Fast", emulator.hack.dsp.fast);
|
||||
bind(boolean, "Emulator/Hack/DSP/Cubic", emulator.hack.dsp.cubic);
|
||||
bind(boolean, "Emulator/Hack/DSP/EchoShadow", emulator.hack.dsp.echoShadow);
|
||||
bind(boolean, "Emulator/Hack/Coprocessor/DelayedSync", emulator.hack.coprocessor.delayedSync);
|
||||
bind(boolean, "Emulator/Hack/Coprocessor/PreferHLE", emulator.hack.coprocessor.preferHLE);
|
||||
bind(natural, "Emulator/Hack/SA1/Overclock", emulator.hack.sa1.overclock);
|
||||
|
|
|
@ -103,6 +103,7 @@ struct Settings : Markup::Node {
|
|||
bool fast = true;
|
||||
bool deinterlace = true;
|
||||
bool noSpriteLimit = false;
|
||||
bool noVRAMBlocking = false;
|
||||
struct Mode7 {
|
||||
uint scale = 1;
|
||||
bool perspective = true;
|
||||
|
@ -113,6 +114,7 @@ struct Settings : Markup::Node {
|
|||
struct DSP {
|
||||
bool fast = true;
|
||||
bool cubic = false;
|
||||
bool echoShadow = false;
|
||||
} dsp;
|
||||
struct Coprocessor {
|
||||
bool delayedSync = true;
|
||||
|
@ -343,6 +345,7 @@ public:
|
|||
CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel deinterlace{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noVRAMBlocking{&ppuLayout, Size{0, 0}};
|
||||
Label mode7Label{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout mode7Layout{this, Size{~0, 0}};
|
||||
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
|
||||
|
@ -354,6 +357,7 @@ public:
|
|||
HorizontalLayout dspLayout{this, Size{~0, 0}};
|
||||
CheckLabel fastDSP{&dspLayout, Size{0, 0}};
|
||||
CheckLabel cubicInterpolation{&dspLayout, Size{0, 0}};
|
||||
CheckLabel echoShadow{&dspLayout, Size{0, 0}};
|
||||
Label coprocessorLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout coprocessorLayout{this, Size{~0, 0}};
|
||||
CheckLabel coprocessorDelayedSyncOption{&coprocessorLayout, Size{0, 0}};
|
||||
|
|
Loading…
Reference in New Issue