mirror of https://github.com/bsnes-emu/bsnes.git
Update to v104 release.
byuu says: Changelog: - emulator/interface: removed unused Region struct - gba/cpu: optimized CPU::step() as much as I could for a slight speedup¹ - gba/cpu: synchronize the APU better during FIFO updates - higan/md, icarus: add automatic region detection; make it the default option [hex\_usr] - picks NTSC-J if there's more than one match ... eventually, this will be a setting - higan/md, icarus: support all three combinations of SRAM (8-bit low, 8-bit high, 16-bit) - processor/arm7tdmi: fix bug when changing to THUMB mode via MSR [MerryMage] - tomoko: redesigned crash detector to only occur once for all three ruby drivers - this will reduce disk thrashing since the configuration file only needs to be written out one extra time - technically, it's twice ... but we should've always been writing one out on first run in case it crashes then - tomoko: defaulted back to the safest ruby drivers, given the optimal drivers have some stability concerns ¹: minor errata: spotted a typo saying `synchronize(cpu)` when the CPU is stopped, instead of `synchronize(ppu)`. This will be fixed in the v104 official 7zip archives. I'm kind of rushing here but, it's really good timing for me to push out a new official release. The blocking issues are resolved or close to it, and we need lots of testing of the new major changes. I'm going to consider this a semi-stable testing release and leave links to v103 just in case.
This commit is contained in:
parent
55f19c3e0d
commit
ba384a7c48
|
@ -12,13 +12,13 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "103.32";
|
||||
static const string Version = "104";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "103";
|
||||
static const string SerializerVersion = "104";
|
||||
|
||||
namespace Constants {
|
||||
namespace Colorburst {
|
||||
|
|
|
@ -9,11 +9,6 @@ struct Interface {
|
|||
bool overscan;
|
||||
} information;
|
||||
|
||||
struct Region {
|
||||
string name;
|
||||
};
|
||||
vector<Region> regions;
|
||||
|
||||
struct Medium {
|
||||
uint id;
|
||||
string name;
|
||||
|
|
|
@ -20,12 +20,18 @@ auto CPU::main() -> void {
|
|||
ARM7TDMI::irq = irq.ime && (irq.enable & irq.flag);
|
||||
|
||||
if(stopped()) {
|
||||
if(!(irq.enable & irq.flag & Interrupt::Keypad)) return step(16);
|
||||
if(!(irq.enable & irq.flag & Interrupt::Keypad)) {
|
||||
Thread::step(16);
|
||||
synchronize(cpu);
|
||||
synchronize(apu);
|
||||
}
|
||||
context.stopped = false;
|
||||
}
|
||||
|
||||
if(halted()) {
|
||||
if(!(irq.enable & irq.flag)) return step(16);
|
||||
if(!(irq.enable & irq.flag)) {
|
||||
return step(16);
|
||||
}
|
||||
context.halted = false;
|
||||
}
|
||||
|
||||
|
@ -33,22 +39,22 @@ auto CPU::main() -> void {
|
|||
}
|
||||
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
for(auto& dma : this->dma) {
|
||||
dma.waiting = max(0, dma.waiting - (int)clocks);
|
||||
}
|
||||
dma[0].waiting = max(0, dma[0].waiting - (int)clocks);
|
||||
dma[1].waiting = max(0, dma[1].waiting - (int)clocks);
|
||||
dma[2].waiting = max(0, dma[2].waiting - (int)clocks);
|
||||
dma[3].waiting = max(0, dma[3].waiting - (int)clocks);
|
||||
|
||||
if(!context.dmaActive) {
|
||||
context.dmaActive = true;
|
||||
while(true) {
|
||||
bool transferred = false;
|
||||
for(auto& dma : this->dma) transferred |= dma.run();
|
||||
if(!transferred) break;
|
||||
}
|
||||
while(dma[0].run() | dma[1].run() | dma[2].run() | dma[3].run());
|
||||
context.dmaActive = false;
|
||||
}
|
||||
|
||||
for(auto _ : range(clocks)) {
|
||||
for(auto& timer : this->timer) timer.run();
|
||||
timer[0].run();
|
||||
timer[1].run();
|
||||
timer[2].run();
|
||||
timer[3].run();
|
||||
context.clock++;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
|
|||
//private:
|
||||
struct DMA {
|
||||
//dma.cpp
|
||||
auto run() -> bool;
|
||||
inline auto run() -> bool;
|
||||
auto transfer() -> void;
|
||||
|
||||
uint2 id;
|
||||
|
@ -98,7 +98,7 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
|
|||
|
||||
struct Timer {
|
||||
//timer.cpp
|
||||
auto run() -> void;
|
||||
inline auto run() -> void;
|
||||
auto step() -> void;
|
||||
|
||||
uint2 id;
|
||||
|
@ -128,7 +128,7 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
|
|||
} serial;
|
||||
|
||||
struct Keypad {
|
||||
//auto keypad.cpp
|
||||
//keypad.cpp
|
||||
auto run() -> void;
|
||||
|
||||
uint1 enable;
|
||||
|
@ -189,8 +189,8 @@ struct CPU : Processor::ARM7TDMI, Thread, IO {
|
|||
uint32 load; //write location of slot buffer
|
||||
integer wait = 1; //number of clocks before next slot load
|
||||
|
||||
auto empty() const { return addr == load; }
|
||||
auto full() const { return load - addr == 16; }
|
||||
inline auto empty() const { return addr == load; }
|
||||
inline auto full() const { return load - addr == 16; }
|
||||
} prefetch;
|
||||
|
||||
struct Context {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
auto CPU::DMA::run() -> bool {
|
||||
if(cpu.stopped() || !active || waiting) return false;
|
||||
if(!active || waiting) return false;
|
||||
|
||||
transfer();
|
||||
if(irq) cpu.irq.flag |= CPU::Interrupt::DMA0 << id;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
auto CPU::Timer::run() -> void {
|
||||
if(cpu.stopped()) return;
|
||||
|
||||
if(pending) {
|
||||
pending = false;
|
||||
if(enable) period = reload;
|
||||
|
@ -29,6 +27,7 @@ auto CPU::Timer::step() -> void {
|
|||
}
|
||||
|
||||
auto CPU::runFIFO(uint n) -> void {
|
||||
synchronize(apu);
|
||||
apu.fifo[n].read();
|
||||
if(apu.fifo[n].size > 16) return;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Cartridge cartridge;
|
|||
auto Cartridge::load() -> bool {
|
||||
information = {};
|
||||
|
||||
if(auto loaded = platform->load(ID::MegaDrive, "Mega Drive", "md", {"NTSC-J", "NTSC-U", "PAL"})) {
|
||||
if(auto loaded = platform->load(ID::MegaDrive, "Mega Drive", "md", {"Auto", "NTSC-J", "NTSC-U", "PAL"})) {
|
||||
information.pathID = loaded.pathID();
|
||||
information.region = loaded.option();
|
||||
} else return false;
|
||||
|
@ -20,27 +20,43 @@ auto Cartridge::load() -> bool {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
information.title = document["information/title"].text();
|
||||
|
||||
if(information.region == "Auto") {
|
||||
if(auto region = document["board/region"].text()) {
|
||||
information.region = region.upcase();
|
||||
} else {
|
||||
information.region = "NTSC-J";
|
||||
}
|
||||
}
|
||||
|
||||
if(auto node = document["board/rom"]) {
|
||||
rom.size = node["size"].natural();
|
||||
rom.size = node["size"].natural() >> 1;
|
||||
rom.mask = bit::round(rom.size) - 1;
|
||||
if(rom.size) {
|
||||
rom.data = new uint8[rom.mask + 1];
|
||||
rom.data = new uint16[rom.mask + 1]();
|
||||
if(auto name = node["name"].text()) {
|
||||
if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) {
|
||||
fp->read(rom.data, rom.size);
|
||||
for(uint n : range(rom.size)) rom.data[n] = fp->readm(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(auto node = document["board/ram"]) {
|
||||
ram.size = node["size"].natural();
|
||||
if(auto mode = node["mode"].text()) {
|
||||
if(mode == "lo" ) ram.bits = 0x00ff;
|
||||
if(mode == "hi" ) ram.bits = 0xff00;
|
||||
if(mode == "word") ram.bits = 0xffff;
|
||||
}
|
||||
ram.size = node["size"].natural() >> (ram.bits == 0xffff);
|
||||
ram.mask = bit::round(ram.size) - 1;
|
||||
if(ram.size) {
|
||||
ram.data = new uint8[ram.mask + 1];
|
||||
ram.data = new uint16[ram.mask + 1]();
|
||||
if(auto name = node["name"].text()) {
|
||||
if(auto fp = platform->open(pathID(), name, File::Read)) {
|
||||
fp->read(ram.data, ram.size);
|
||||
for(uint n : range(ram.size)) {
|
||||
if(ram.bits != 0xffff) ram.data[n] = fp->readm(1) * 0x0101;
|
||||
if(ram.bits == 0xffff) ram.data[n] = fp->readm(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +70,10 @@ auto Cartridge::save() -> void {
|
|||
|
||||
if(auto name = document["board/ram/name"].text()) {
|
||||
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
||||
fp->write(ram.data, ram.size);
|
||||
for(uint n : range(ram.size)) {
|
||||
if(ram.bits != 0xffff) fp->writem(ram.data[n], 1);
|
||||
if(ram.bits == 0xffff) fp->writem(ram.data[n], 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,22 +91,21 @@ auto Cartridge::power() -> void {
|
|||
for(auto n : range(8)) bank[n] = n;
|
||||
}
|
||||
|
||||
auto Cartridge::read(uint24 addr) -> uint16 {
|
||||
if(addr.bit(21) && ram.size && ramEnable) {
|
||||
uint16 data = ram.data[addr + 0 & ram.mask] << 8;
|
||||
return data | ram.data[addr + 1 & ram.mask] << 0;
|
||||
auto Cartridge::read(uint24 address) -> uint16 {
|
||||
if(address.bit(21) && ram.size && ramEnable) {
|
||||
return ram.data[address >> 1 & ram.mask];
|
||||
} else {
|
||||
addr = bank[addr >> 19 & 7] << 19 | (addr & 0x7ffff);
|
||||
uint16 data = rom.data[addr + 0 & rom.mask] << 8;
|
||||
return data | rom.data[addr + 1 & rom.mask] << 0;
|
||||
address = bank[address.bits(19,21)] << 19 | address.bits(0,18);
|
||||
return rom.data[address >> 1 & rom.mask];
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::write(uint24 addr, uint16 data) -> void {
|
||||
auto Cartridge::write(uint24 address, uint16 data) -> void {
|
||||
//emulating RAM write protect bit breaks some commercial software
|
||||
if(addr.bit(21) && ram.size && ramEnable /* && ramWritable */) {
|
||||
ram.data[addr + 0 & ram.mask] = data >> 8;
|
||||
ram.data[addr + 1 & ram.mask] = data >> 0;
|
||||
if(address.bit(21) && ram.size && ramEnable /* && ramWritable */) {
|
||||
if(ram.bits == 0x00ff) data = data.byte(0) * 0x0101;
|
||||
if(ram.bits == 0xff00) data = data.byte(1) * 0x0101;
|
||||
ram.data[address >> 1 & ram.mask] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,10 @@ struct Cartridge {
|
|||
} information;
|
||||
|
||||
struct Memory {
|
||||
uint8* data = nullptr;
|
||||
uint16* data = nullptr;
|
||||
uint size = 0;
|
||||
uint mask = 0;
|
||||
uint bits = 0;
|
||||
};
|
||||
|
||||
Memory rom;
|
||||
|
|
|
@ -9,11 +9,6 @@ Interface::Interface() {
|
|||
information.name = "Mega Drive";
|
||||
information.overscan = true;
|
||||
|
||||
regions.append({"Autodetect"});
|
||||
regions.append({"NTSC-J"});
|
||||
regions.append({"NTSC-U"});
|
||||
regions.append({"PAL"});
|
||||
|
||||
media.append({ID::MegaDrive, "Mega Drive", "md"});
|
||||
|
||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||
|
|
|
@ -35,6 +35,7 @@ auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
|
|||
psr.t = data.bit (5);
|
||||
psr.f = data.bit (6);
|
||||
psr.i = data.bit (7);
|
||||
if(!mode && psr.t) r(15).data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@ Settings::Settings() {
|
|||
set("Library/Location", {Path::user(), "Emulation/"});
|
||||
set("Library/IgnoreManifests", false);
|
||||
|
||||
set("Video/Driver", ruby::Video::optimalDriver());
|
||||
set("Video/Driver/Crashed", false);
|
||||
set("Video/Driver", ruby::Video::safestDriver());
|
||||
set("Video/Synchronize", false);
|
||||
set("Video/Shader", "Blur");
|
||||
set("Video/BlurEmulation", true);
|
||||
|
@ -41,8 +40,7 @@ Settings::Settings() {
|
|||
set("Video/Fullscreen/IntegralScaling", true);
|
||||
set("Video/Fullscreen/Exclusive", false);
|
||||
|
||||
set("Audio/Driver", ruby::Audio::optimalDriver());
|
||||
set("Audio/Driver/Crashed", false);
|
||||
set("Audio/Driver", ruby::Audio::safestDriver());
|
||||
set("Audio/Device", "");
|
||||
set("Audio/Frequency", 48000);
|
||||
set("Audio/Latency", 0);
|
||||
|
@ -53,11 +51,12 @@ Settings::Settings() {
|
|||
set("Audio/Balance", 50);
|
||||
set("Audio/Reverb/Enable", false);
|
||||
|
||||
set("Input/Driver", ruby::Input::optimalDriver());
|
||||
set("Input/Driver/Crashed", false);
|
||||
set("Input/Driver", ruby::Input::safestDriver());
|
||||
set("Input/Frequency", 5);
|
||||
set("Input/FocusLoss/Pause", false);
|
||||
set("Input/FocusLoss/AllowInput", false);
|
||||
|
||||
set("Crashed", false);
|
||||
}
|
||||
|
||||
auto Settings::save() -> void {
|
||||
|
|
|
@ -33,26 +33,22 @@ Program::Program(string_vector args) {
|
|||
new Presentation;
|
||||
presentation->setVisible();
|
||||
|
||||
if(settings["Video/Driver/Crashed"].boolean()) {
|
||||
if(settings["Crashed"].boolean()) {
|
||||
MessageDialog().setText("Driver crash detected. Video/Audio/Input drivers have been disabled.").information();
|
||||
settings["Video/Driver"].setValue("None");
|
||||
MessageDialog().setText("Video driver crash detected. Driver has been reset to 'None'").information();
|
||||
settings["Audio/Driver"].setValue("None");
|
||||
settings["Input/Driver"].setValue("None");
|
||||
}
|
||||
settings["Video/Driver/Crashed"].setValue(true);
|
||||
|
||||
settings["Crashed"].setValue(true);
|
||||
settings.save();
|
||||
|
||||
video = Video::create(settings["Video/Driver"].text());
|
||||
video->setContext(presentation->viewport.handle());
|
||||
video->setBlocking(settings["Video/Synchronize"].boolean());
|
||||
if(!video->ready()) MessageDialog().setText("Failed to initialize video driver").warning();
|
||||
settings["Video/Driver/Crashed"].setValue(false);
|
||||
settings.save();
|
||||
presentation->clearViewport();
|
||||
|
||||
if(settings["Audio/Driver/Crashed"].boolean()) {
|
||||
settings["Audio/Driver"].setValue("None");
|
||||
MessageDialog().setText("Audio driver crash detected. Driver has been reset to 'None'").information();
|
||||
}
|
||||
settings["Audio/Driver/Crashed"].setValue(true);
|
||||
settings.save();
|
||||
audio = Audio::create(settings["Audio/Driver"].text());
|
||||
audio->setExclusive(settings["Audio/Exclusive"].boolean());
|
||||
audio->setContext(presentation->viewport.handle());
|
||||
|
@ -60,20 +56,13 @@ Program::Program(string_vector args) {
|
|||
audio->setBlocking(settings["Audio/Synchronize"].boolean());
|
||||
audio->setChannels(2);
|
||||
if(!audio->ready()) MessageDialog().setText("Failed to initialize audio driver").warning();
|
||||
settings["Audio/Driver/Crashed"].setValue(false);
|
||||
settings.save();
|
||||
|
||||
if(settings["Input/Driver/Crashed"].boolean()) {
|
||||
settings["Input/Driver"].setValue("None");
|
||||
MessageDialog().setText("Input driver crash detected. Driver has been reset to 'None'").information();
|
||||
}
|
||||
settings["Input/Driver/Crashed"].setValue(true);
|
||||
settings.save();
|
||||
input = Input::create(settings["Input/Driver"].text());
|
||||
input->setContext(presentation->viewport.handle());
|
||||
input->onChange({&InputManager::onChange, &inputManager()});
|
||||
if(!input->ready()) MessageDialog().setText("Failed to initialize input driver").warning();
|
||||
settings["Input/Driver/Crashed"].setValue(false);
|
||||
|
||||
settings["Crashed"].setValue(false);
|
||||
settings.save();
|
||||
|
||||
new InputManager;
|
||||
|
|
|
@ -11,12 +11,13 @@ struct MegaDriveCartridge {
|
|||
MegaDriveCartridge::MegaDriveCartridge(string location, uint8_t* data, uint size) {
|
||||
if(size < 0x200) return;
|
||||
|
||||
string ramMode = "none";
|
||||
|
||||
uint32_t ramFrom = 0;
|
||||
ramFrom |= data[0x01b4] << 24;
|
||||
ramFrom |= data[0x01b5] << 16;
|
||||
ramFrom |= data[0x01b6] << 8;
|
||||
ramFrom |= data[0x01b7] << 0;
|
||||
ramFrom &= ~1; //for some reason, most games specify 00200001 as RAM start offset
|
||||
|
||||
uint32_t ramTo = 0;
|
||||
ramTo |= data[0x01b8] << 24;
|
||||
|
@ -24,14 +25,42 @@ MegaDriveCartridge::MegaDriveCartridge(string location, uint8_t* data, uint size
|
|||
ramTo |= data[0x01ba] << 8;
|
||||
ramTo |= data[0x01bb] << 0;
|
||||
|
||||
uint32_t ramSize = ramTo - ramFrom;
|
||||
if(ramSize > 0x020000) ramSize = 0; //sanity check
|
||||
ramSize = bit::round(ramSize);
|
||||
if(!(ramFrom & 1) && !(ramTo & 1)) ramMode = "lo";
|
||||
if( (ramFrom & 1) && (ramTo & 1)) ramMode = "hi";
|
||||
if(!(ramFrom & 1) && (ramTo & 1)) ramMode = "word";
|
||||
|
||||
manifest.append("board\n");
|
||||
uint32_t ramSize = ramTo - ramFrom + 1;
|
||||
if(ramMode == "lo") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1;
|
||||
if(ramMode == "hi") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1;
|
||||
if(ramMode == "word") ramSize = ramTo - ramFrom + 1;
|
||||
if(ramMode != "none") ramSize = bit::round(min(0x20000, ramSize));
|
||||
|
||||
string_vector regions;
|
||||
string region = slice((const char*)&data[0x1f0], 0, 16).trimRight(" ");
|
||||
if(!regions) {
|
||||
if(region == "JAPAN" ) regions.append("ntsc-j");
|
||||
if(region == "EUROPE") regions.append("pal");
|
||||
}
|
||||
if(!regions) {
|
||||
if(region.find("J")) regions.append("ntsc-j");
|
||||
if(region.find("U")) regions.append("ntsc-u");
|
||||
if(region.find("E")) regions.append("pal");
|
||||
if(region.find("W")) regions.append("ntsc-j", "ntsc-u", "pal");
|
||||
}
|
||||
if(!regions && region.size() == 1) {
|
||||
uint8_t field = region.hex();
|
||||
if(field & 0x01) regions.append("ntsc-j");
|
||||
if(field & 0x04) regions.append("ntsc-u");
|
||||
if(field & 0x08) regions.append("pal");
|
||||
}
|
||||
if(!regions) {
|
||||
regions.append("ntsc-j");
|
||||
}
|
||||
|
||||
manifest.append("board region=", regions.left(), "\n");
|
||||
manifest.append(" rom name=program.rom size=0x", hex(size), "\n");
|
||||
if(ramSize)
|
||||
manifest.append(" ram name=save.ram size=0x", hex(ramSize), " offset=0x", hex(ramFrom), "\n");
|
||||
if(ramSize && ramMode != "none")
|
||||
manifest.append(" ram name=save.ram size=0x", hex(ramSize), " offset=0x", hex(ramFrom), " mode=", ramMode, "\n");
|
||||
manifest.append("\n");
|
||||
manifest.append("information\n");
|
||||
manifest.append(" title: ", Location::prefix(location), "\n");
|
||||
|
|
Loading…
Reference in New Issue