mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
SNES: Add support for Sufami Turbo games
This commit is contained in:
parent
8d6830a70a
commit
18269da46b
26 changed files with 333 additions and 37 deletions
|
@ -119,6 +119,7 @@
|
|||
<ClInclude Include="SNES\Coprocessors\ST018\ArmV3Types.h" />
|
||||
<ClInclude Include="SNES\Coprocessors\ST018\St018.h" />
|
||||
<ClInclude Include="SNES\Coprocessors\ST018\St018Types.h" />
|
||||
<ClInclude Include="SNES\Coprocessors\SufamiTurbo\SufamiTurbo.h" />
|
||||
<ClInclude Include="SNES\Debugger\DummyArmV3Cpu.h" />
|
||||
<ClInclude Include="SNES\Debugger\St018Debugger.h" />
|
||||
<ClInclude Include="SNES\Debugger\St018DisUtils.h" />
|
||||
|
|
|
@ -2970,6 +2970,9 @@
|
|||
<ClInclude Include="Shared\ArmEnums.h">
|
||||
<Filter>Shared</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SNES\Coprocessors\SufamiTurbo\SufamiTurbo.h">
|
||||
<Filter>SNES\Coprocessors\SufamiTurbo</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Shared\Video\RotateFilter.cpp">
|
||||
|
@ -3457,5 +3460,8 @@
|
|||
<Filter Include="SNES\Coprocessors\ST018">
|
||||
<UniqueIdentifier>{387c0b44-8063-45e8-a28a-b6d9e27b5a3f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="SNES\Coprocessors\SufamiTurbo">
|
||||
<UniqueIdentifier>{bfdd4bb9-41c2-4255-a8c3-0176c990cbf3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -61,6 +61,9 @@ public:
|
|||
case MemoryType::SnesWorkRam:
|
||||
case MemoryType::BsxMemoryPack:
|
||||
case MemoryType::BsxPsRam:
|
||||
case MemoryType::SufamiTurboFirmware:
|
||||
case MemoryType::SufamiTurboSecondCart:
|
||||
case MemoryType::SufamiTurboSecondCartRam:
|
||||
case MemoryType::SnesRegister:
|
||||
return CpuType::Snes;
|
||||
|
||||
|
@ -232,6 +235,8 @@ public:
|
|||
case MemoryType::DspProgramRom:
|
||||
case MemoryType::St018PrgRom:
|
||||
case MemoryType::St018DataRom:
|
||||
case MemoryType::SufamiTurboFirmware:
|
||||
case MemoryType::SufamiTurboSecondCart:
|
||||
case MemoryType::SpcRom:
|
||||
case MemoryType::SmsPrgRom:
|
||||
case MemoryType::SmsBootRom:
|
||||
|
@ -255,6 +260,7 @@ public:
|
|||
case MemoryType::NesSaveRam:
|
||||
case MemoryType::GbCartRam:
|
||||
case MemoryType::SnesSaveRam:
|
||||
case MemoryType::SufamiTurboSecondCartRam:
|
||||
case MemoryType::PceSaveRam:
|
||||
case MemoryType::SnesRegister:
|
||||
case MemoryType::SmsCartRam:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "SNES/Coprocessors/BSX/BsxCart.h"
|
||||
#include "SNES/Coprocessors/BSX/BsxMemoryPack.h"
|
||||
#include "SNES/Coprocessors/SGB/SuperGameboy.h"
|
||||
#include "SNES/Coprocessors/SufamiTurbo/SufamiTurbo.h"
|
||||
#include "Shared/EmuSettings.h"
|
||||
#include "Shared/SettingTypes.h"
|
||||
#include "Shared/BatteryManager.h"
|
||||
|
@ -64,12 +65,18 @@ unique_ptr<BaseCartridge> BaseCartridge::CreateCartridge(SnesConsole* console, V
|
|||
}
|
||||
cart->LoadRom();
|
||||
cart->_emu->RegisterMemory(MemoryType::SnesPrgRom, cart->_prgRom, cart->_prgRomSize);
|
||||
} else if(fileExt == ".st") {
|
||||
if(cart->LoadSufamiTurbo(romFile)) {
|
||||
return cart;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else if(fileExt == ".gb" || fileExt == ".gbc" || fileExt == ".gbx") {
|
||||
if(cart->LoadGameboy(romFile)) {
|
||||
return cart;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(romData.size() < 0x8000) {
|
||||
return nullptr;
|
||||
|
@ -88,7 +95,7 @@ unique_ptr<BaseCartridge> BaseCartridge::CreateCartridge(SnesConsole* console, V
|
|||
}
|
||||
} else {
|
||||
cart->LoadRom();
|
||||
cart->EnsureValidPrgRomSize();
|
||||
BaseCartridge::EnsureValidPrgRomSize(cart->_prgRomSize, cart->_prgRom);
|
||||
}
|
||||
|
||||
cart->_emu->RegisterMemory(MemoryType::SnesPrgRom, cart->_prgRom, cart->_prgRomSize);
|
||||
|
@ -100,18 +107,18 @@ unique_ptr<BaseCartridge> BaseCartridge::CreateCartridge(SnesConsole* console, V
|
|||
}
|
||||
}
|
||||
|
||||
void BaseCartridge::EnsureValidPrgRomSize()
|
||||
void BaseCartridge::EnsureValidPrgRomSize(uint32_t& size, uint8_t*& rom)
|
||||
{
|
||||
if((_prgRomSize & 0xFFF) != 0) {
|
||||
if((size & 0xFFF) != 0) {
|
||||
//Round up to the next 4kb size, to ensure we have access to all the rom's data
|
||||
//Memory mappings expect a multiple of 4kb to work properly
|
||||
uint32_t orgPrgSize = _prgRomSize;
|
||||
_prgRomSize = (_prgRomSize & ~0xFFF) + 0x1000;
|
||||
uint8_t* expandedPrgRom = new uint8_t[_prgRomSize];
|
||||
memset(expandedPrgRom, 0, _prgRomSize);
|
||||
memcpy(expandedPrgRom, _prgRom, orgPrgSize);
|
||||
delete[] _prgRom;
|
||||
_prgRom = expandedPrgRom;
|
||||
uint32_t orgPrgSize = size;
|
||||
size = (size & ~0xFFF) + 0x1000;
|
||||
uint8_t* expandedPrgRom = new uint8_t[size];
|
||||
memset(expandedPrgRom, 0, size);
|
||||
memcpy(expandedPrgRom, rom, orgPrgSize);
|
||||
delete[] rom;
|
||||
rom = expandedPrgRom;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,6 +411,10 @@ void BaseCartridge::SaveBattery()
|
|||
if(_gameboy) {
|
||||
_gameboy->SaveBattery();
|
||||
}
|
||||
|
||||
if(_sufamiTurbo) {
|
||||
_sufamiTurbo->SaveBattery();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseCartridge::Init(MemoryMappings &mm)
|
||||
|
@ -555,7 +566,11 @@ bool BaseCartridge::MapSpecificCarts(MemoryMappings &mm)
|
|||
{
|
||||
string name = GetCartName();
|
||||
string code = GetGameCode();
|
||||
if(GetCartName() == "DEZAEMON") {
|
||||
|
||||
if(_sufamiTurbo) {
|
||||
_sufamiTurbo->InitializeMappings(mm, _prgRomHandlers, _saveRamHandlers);
|
||||
return true;
|
||||
} else if(GetCartName() == "DEZAEMON") {
|
||||
//LOROM with mirrored SRAM?
|
||||
mm.RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, _prgRomHandlers);
|
||||
mm.RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, _prgRomHandlers);
|
||||
|
@ -644,6 +659,30 @@ void BaseCartridge::LoadSpc()
|
|||
SetupCpuHalt();
|
||||
}
|
||||
|
||||
bool BaseCartridge::LoadSufamiTurbo(VirtualFile& romFile)
|
||||
{
|
||||
_sufamiTurbo.reset(SufamiTurbo::Init(_emu, romFile));
|
||||
if(!_sufamiTurbo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<uint8_t> romData;
|
||||
romFile.ReadFile(romData);
|
||||
|
||||
_prgRomSize = (uint32_t)romData.size();
|
||||
_prgRom = new uint8_t[_prgRomSize];
|
||||
memcpy(_prgRom, romData.data(), romData.size());
|
||||
BaseCartridge::EnsureValidPrgRomSize(_prgRomSize, _prgRom);
|
||||
_emu->RegisterMemory(MemoryType::SnesPrgRom, _prgRom, _prgRomSize);
|
||||
|
||||
_saveRamSize = SufamiTurbo::GetSaveRamSize(romData);
|
||||
_saveRam = new uint8_t[_saveRamSize];
|
||||
_emu->RegisterMemory(MemoryType::SnesSaveRam, _saveRam, _saveRamSize);
|
||||
_emu->GetSettings()->InitializeRam(GetRamPowerOnState(), _saveRam, _saveRamSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseCartridge::LoadGameboy(VirtualFile& romFile)
|
||||
{
|
||||
_cartInfo = { };
|
||||
|
|
|
@ -21,6 +21,7 @@ class Gameboy;
|
|||
class SnesConsole;
|
||||
class Emulator;
|
||||
class SpcFileData;
|
||||
class SufamiTurbo;
|
||||
enum class ConsoleRegion;
|
||||
enum class RamState;
|
||||
|
||||
|
@ -47,6 +48,7 @@ private:
|
|||
BsxCart* _bsx = nullptr;
|
||||
unique_ptr<BsxMemoryPack> _bsxMemPack;
|
||||
unique_ptr<Gameboy> _gameboy;
|
||||
unique_ptr<SufamiTurbo> _sufamiTurbo;
|
||||
|
||||
CartFlags::CartFlags _flags = CartFlags::CartFlags::None;
|
||||
CoprocessorType _coprocessorType = CoprocessorType::None;
|
||||
|
@ -83,10 +85,13 @@ private:
|
|||
void InitRamPowerOnState();
|
||||
|
||||
void LoadRom();
|
||||
void EnsureValidPrgRomSize();
|
||||
|
||||
void LoadSpc();
|
||||
|
||||
bool LoadSufamiTurbo(VirtualFile& romFile);
|
||||
|
||||
bool LoadGameboy(VirtualFile& romFile);
|
||||
|
||||
void SetupCpuHalt();
|
||||
void InitCoprocessor();
|
||||
void LoadEmbeddedFirmware();
|
||||
|
@ -99,6 +104,8 @@ public:
|
|||
|
||||
static unique_ptr<BaseCartridge> CreateCartridge(SnesConsole* console, VirtualFile &romFile);
|
||||
|
||||
static void EnsureValidPrgRomSize(uint32_t& size, uint8_t*& rom);
|
||||
|
||||
void Reset();
|
||||
|
||||
void SaveBattery();
|
||||
|
|
148
Core/SNES/Coprocessors/SufamiTurbo/SufamiTurbo.h
Normal file
148
Core/SNES/Coprocessors/SufamiTurbo/SufamiTurbo.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "SNES/IMemoryHandler.h"
|
||||
#include "SNES/RomHandler.h"
|
||||
#include "SNES/MemoryMappings.h"
|
||||
#include "Shared/Emulator.h"
|
||||
#include "Shared/BatteryManager.h"
|
||||
#include "Shared/FirmwareHelper.h"
|
||||
#include "Utilities/VirtualFile.h"
|
||||
|
||||
struct SufamiTurboFilePromptMessage
|
||||
{
|
||||
char Filename[5000];
|
||||
};
|
||||
|
||||
class SufamiTurbo
|
||||
{
|
||||
private:
|
||||
Emulator* _emu = nullptr;
|
||||
string _nameSlotA;
|
||||
|
||||
uint8_t* _firmware = nullptr;
|
||||
uint32_t _firmwareSize = 0;
|
||||
|
||||
string _cartName;
|
||||
uint8_t* _cartRom = nullptr;
|
||||
uint32_t _cartRomSize = 0;
|
||||
|
||||
uint8_t* _cartRam = nullptr;
|
||||
uint32_t _cartRamSize = 0;
|
||||
|
||||
vector<unique_ptr<IMemoryHandler>> _firmwareHandlers;
|
||||
vector<unique_ptr<IMemoryHandler>> _cartRomHandlers;
|
||||
vector<unique_ptr<IMemoryHandler>> _cartRamHandlers;
|
||||
|
||||
SufamiTurbo() {}
|
||||
|
||||
public:
|
||||
static SufamiTurbo* Init(Emulator* emu, VirtualFile& slotA)
|
||||
{
|
||||
vector<uint8_t> firmware;
|
||||
if(!FirmwareHelper::LoadSufamiTurboFirmware(emu, firmware)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SufamiTurbo* st = new SufamiTurbo();
|
||||
st->_emu = emu;
|
||||
st->_nameSlotA = FolderUtilities::GetFilename(slotA.GetFileName(), false);
|
||||
|
||||
st->_firmwareSize = (uint32_t)firmware.size();
|
||||
st->_firmware = new uint8_t[st->_firmwareSize];
|
||||
memcpy(st->_firmware, firmware.data(), firmware.size());
|
||||
BaseCartridge::EnsureValidPrgRomSize(st->_firmwareSize, st->_firmware);
|
||||
emu->RegisterMemory(MemoryType::SufamiTurboFirmware, st->_firmware, st->_firmwareSize);
|
||||
for(uint32_t i = 0; i < st->_firmwareSize; i += 0x1000) {
|
||||
st->_firmwareHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(st->_firmware, i, st->_firmwareSize, MemoryType::SufamiTurboFirmware)));
|
||||
}
|
||||
|
||||
SufamiTurboFilePromptMessage msg = {};
|
||||
emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::SufamiTurboFilePrompt, &msg);
|
||||
|
||||
string slot2File = string(msg.Filename, strlen(msg.Filename));
|
||||
if(slot2File.size()) {
|
||||
VirtualFile file = slot2File;
|
||||
if(file.IsValid()) {
|
||||
vector<uint8_t> cart;
|
||||
file.ReadFile(cart);
|
||||
|
||||
st->_cartName = FolderUtilities::GetFilename(file.GetFileName(), false);
|
||||
if(st->_nameSlotA == st->_cartName) {
|
||||
st->_cartName += "_SlotB";
|
||||
}
|
||||
|
||||
st->_cartRomSize = (uint32_t)cart.size();
|
||||
st->_cartRom = new uint8_t[st->_cartRomSize];
|
||||
memcpy(st->_cartRom, cart.data(), cart.size());
|
||||
BaseCartridge::EnsureValidPrgRomSize(st->_cartRomSize, st->_cartRom);
|
||||
|
||||
emu->RegisterMemory(MemoryType::SufamiTurboSecondCart, st->_cartRom, st->_cartRomSize);
|
||||
|
||||
for(uint32_t i = 0; i < st->_cartRomSize; i += 0x1000) {
|
||||
st->_cartRomHandlers.push_back(unique_ptr<RomHandler>(new RomHandler(st->_cartRom, i, st->_cartRomSize, MemoryType::SufamiTurboSecondCart)));
|
||||
}
|
||||
|
||||
st->_cartRamSize = GetSaveRamSize(cart);
|
||||
st->_cartRam = new uint8_t[st->_cartRamSize];
|
||||
emu->RegisterMemory(MemoryType::SufamiTurboSecondCartRam, st->_cartRam, st->_cartRamSize);
|
||||
memset(st->_cartRam, 0, st->_cartRamSize);
|
||||
|
||||
emu->GetBatteryManager()->LoadBattery(st->_cartName + ".srm", st->_cartRam, st->_cartRamSize);
|
||||
|
||||
for(uint32_t i = 0; i < st->_cartRamSize; i += 0x1000) {
|
||||
st->_cartRamHandlers.push_back(unique_ptr<RamHandler>(new RamHandler(st->_cartRam, i, st->_cartRamSize, MemoryType::SufamiTurboSecondCartRam)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static uint32_t GetSaveRamSize(vector<uint8_t>& cart)
|
||||
{
|
||||
auto checkMarker = [&](string marker) {
|
||||
return std::search((char*)cart.data(), (char*)cart.data()+cart.size(), marker.c_str(), marker.c_str()+marker.size()) != (char*)cart.data() + cart.size();
|
||||
};
|
||||
|
||||
if(checkMarker("POIPOI.Ver") || checkMarker("SDBATTLE ")) {
|
||||
return 0x800;
|
||||
} else if(checkMarker("SD \xB6\xDE\xDD\xC0\xDE\xD1 GN")) {
|
||||
//SD ガンダム GN
|
||||
return 0x2000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InitializeMappings(MemoryMappings& mm, vector<unique_ptr<IMemoryHandler>>& prgRomHandlers, vector<unique_ptr<IMemoryHandler>>& saveRamHandlers)
|
||||
{
|
||||
mm.RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, prgRomHandlers);
|
||||
mm.RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, prgRomHandlers);
|
||||
|
||||
mm.RegisterHandler(0x60, 0x63, 0x8000, 0xFFFF, saveRamHandlers);
|
||||
mm.RegisterHandler(0xE0, 0xE3, 0x8000, 0xFFFF, saveRamHandlers);
|
||||
|
||||
mm.RegisterHandler(0x00, 0x1F, 0x8000, 0xFFFF, _firmwareHandlers);
|
||||
mm.RegisterHandler(0x80, 0x9F, 0x8000, 0xFFFF, _firmwareHandlers);
|
||||
|
||||
mm.RegisterHandler(0x40, 0x5F, 0x8000, 0xFFFF, _cartRomHandlers);
|
||||
mm.RegisterHandler(0xC0, 0xDF, 0x8000, 0xFFFF, _cartRomHandlers);
|
||||
|
||||
mm.RegisterHandler(0x70, 0x73, 0x8000, 0xFFFF, _cartRamHandlers);
|
||||
mm.RegisterHandler(0xF0, 0xF3, 0x8000, 0xFFFF, _cartRamHandlers);
|
||||
}
|
||||
|
||||
void SaveBattery()
|
||||
{
|
||||
if(_cartRam) {
|
||||
_emu->GetBatteryManager()->SaveBattery(_cartName + ".srm", _cartRam, _cartRamSize);
|
||||
}
|
||||
}
|
||||
|
||||
~SufamiTurbo()
|
||||
{
|
||||
delete[] _firmware;
|
||||
delete[] _cartRom;
|
||||
delete[] _cartRam;
|
||||
}
|
||||
};
|
|
@ -472,6 +472,7 @@ AddressInfo SnesConsole::GetRelativeAddress(AddressInfo& absAddress, CpuType cpu
|
|||
case MemoryType::SnesPrgRom:
|
||||
case MemoryType::SnesWorkRam:
|
||||
case MemoryType::SnesSaveRam:
|
||||
case MemoryType::SufamiTurboFirmware:
|
||||
{
|
||||
if(!mappings) {
|
||||
return unmapped;
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
SnesConsole(Emulator* emu);
|
||||
~SnesConsole();
|
||||
|
||||
static vector<string> GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".gbx", ".spc" }; }
|
||||
static vector<string> GetSupportedExtensions() { return { ".sfc", ".swc", ".fig", ".smc", ".bs", ".gb", ".gbc", ".gbx", ".spc", ".st" }; }
|
||||
static vector<string> GetSupportedSignatures() { return { "SNES-SPC700 Sound File Data" }; }
|
||||
|
||||
void Initialize();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Shared/BatteryManager.h"
|
||||
#include "Utilities/VirtualFile.h"
|
||||
#include "Utilities/FolderUtilities.h"
|
||||
#include "Utilities/StringUtilities.h"
|
||||
|
||||
void BatteryManager::Initialize(string romName, bool setBatteryFlag)
|
||||
{
|
||||
|
@ -9,9 +10,13 @@ void BatteryManager::Initialize(string romName, bool setBatteryFlag)
|
|||
_hasBattery = setBatteryFlag;
|
||||
}
|
||||
|
||||
string BatteryManager::GetBasePath()
|
||||
string BatteryManager::GetBasePath(string& extension)
|
||||
{
|
||||
return FolderUtilities::CombinePath(FolderUtilities::GetSaveFolder(), _romName);
|
||||
if(StringUtilities::StartsWith(extension, ".")) {
|
||||
return FolderUtilities::CombinePath(FolderUtilities::GetSaveFolder(), _romName + extension);
|
||||
} else {
|
||||
return FolderUtilities::CombinePath(FolderUtilities::GetSaveFolder(), extension);
|
||||
}
|
||||
}
|
||||
|
||||
void BatteryManager::SetBatteryProvider(shared_ptr<IBatteryProvider> provider)
|
||||
|
@ -32,7 +37,7 @@ void BatteryManager::SaveBattery(string extension, uint8_t* data, uint32_t lengt
|
|||
}
|
||||
|
||||
_hasBattery = true;
|
||||
ofstream out(GetBasePath() + extension, ios::binary);
|
||||
ofstream out(GetBasePath(extension), ios::binary);
|
||||
if(out) {
|
||||
out.write((char*)data, length);
|
||||
}
|
||||
|
@ -52,7 +57,7 @@ vector<uint8_t> BatteryManager::LoadBattery(string extension)
|
|||
//Used by movie player to provider initial state of ram at startup
|
||||
batteryData = provider->LoadBattery(extension);
|
||||
} else {
|
||||
VirtualFile file = GetBasePath() + extension;
|
||||
VirtualFile file = GetBasePath(extension);
|
||||
if(file.IsValid()) {
|
||||
file.ReadFile(batteryData);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ private:
|
|||
std::weak_ptr<IBatteryProvider> _provider;
|
||||
std::weak_ptr<IBatteryRecorder> _recorder;
|
||||
|
||||
string GetBasePath();
|
||||
string GetBasePath(string& extension);
|
||||
|
||||
public:
|
||||
void Initialize(string romName, bool setBatteryFlag = false);
|
||||
|
|
|
@ -16,6 +16,7 @@ enum class FirmwareType
|
|||
ST011,
|
||||
ST018,
|
||||
Satellaview,
|
||||
SufamiTurbo,
|
||||
Gameboy,
|
||||
GameboyColor,
|
||||
GameboyAdvance,
|
||||
|
@ -185,6 +186,25 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool LoadSufamiTurboFirmware(Emulator* emu, vector<uint8_t>& data)
|
||||
{
|
||||
string filename = "SufamiTurbo.sfc";
|
||||
|
||||
if(AttemptLoadFirmware(data, filename, 0x40000)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MissingFirmwareMessage msg(filename.c_str(), FirmwareType::SufamiTurbo, 0x40000);
|
||||
emu->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
|
||||
|
||||
if(AttemptLoadFirmware(data, filename, 0x40000)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MessageManager::DisplayMessage("Error", "Could not find firmware file for Sufami Turbo");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LoadSgbFirmware(Emulator* emu, uint8_t** prgRom, uint32_t& prgSize, bool useSgb2, bool promptForFirmware)
|
||||
{
|
||||
string filename = useSgb2 ? "SGB2.sfc" : "SGB1.sfc";
|
||||
|
|
|
@ -22,6 +22,7 @@ enum class ConsoleNotificationType
|
|||
ViewerRefresh,
|
||||
EventViewerRefresh,
|
||||
MissingFirmware,
|
||||
SufamiTurboFilePrompt,
|
||||
BeforeGameUnload,
|
||||
BeforeGameLoad,
|
||||
GameLoadFailed,
|
||||
|
|
|
@ -38,6 +38,9 @@ enum class MemoryType
|
|||
St018PrgRom,
|
||||
St018DataRom,
|
||||
St018WorkRam,
|
||||
SufamiTurboFirmware,
|
||||
SufamiTurboSecondCart,
|
||||
SufamiTurboSecondCartRam,
|
||||
|
||||
GbPrgRom,
|
||||
GbWorkRam,
|
||||
|
|
|
@ -76,6 +76,8 @@ namespace Mesen.Config
|
|||
case MemoryType.PcePrgRom:
|
||||
case MemoryType.SmsPrgRom:
|
||||
case MemoryType.SpcRom:
|
||||
case MemoryType.SufamiTurboFirmware:
|
||||
case MemoryType.SufamiTurboSecondCart:
|
||||
case MemoryType.DspProgramRom:
|
||||
case MemoryType.DspDataRom:
|
||||
case MemoryType.GbBootRom:
|
||||
|
@ -107,11 +109,12 @@ namespace Mesen.Config
|
|||
return ImportWorkRamLabels;
|
||||
|
||||
case MemoryType.SnesSaveRam:
|
||||
case MemoryType.BsxMemoryPack:
|
||||
case MemoryType.SufamiTurboSecondCartRam:
|
||||
case MemoryType.NesSaveRam:
|
||||
case MemoryType.PceSaveRam:
|
||||
case MemoryType.GbCartRam:
|
||||
case MemoryType.SmsCartRam:
|
||||
case MemoryType.BsxMemoryPack:
|
||||
case MemoryType.GbaSaveRam:
|
||||
case MemoryType.WsCartRam:
|
||||
return ImportSaveRamLabels;
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace Mesen.Debugger.Utilities
|
|||
RomFormat.Sg => true,
|
||||
RomFormat.ColecoVision => true,
|
||||
RomFormat.Gba => true,
|
||||
RomFormat.Ws => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
|
|
@ -621,6 +621,9 @@ namespace Mesen.Interop
|
|||
St018PrgRom,
|
||||
St018DataRom,
|
||||
St018WorkRam,
|
||||
SufamiTurboFirmware,
|
||||
SufamiTurboSecondCart,
|
||||
SufamiTurboSecondCartRam,
|
||||
|
||||
GbPrgRom,
|
||||
GbWorkRam,
|
||||
|
|
|
@ -257,6 +257,7 @@ namespace Mesen.Interop
|
|||
ST011,
|
||||
ST018,
|
||||
Satellaview,
|
||||
SufamiTurbo,
|
||||
Gameboy,
|
||||
GameboyColor,
|
||||
GameboyAdvance,
|
||||
|
@ -285,6 +286,12 @@ namespace Mesen.Interop
|
|||
public UInt32 AltSize;
|
||||
}
|
||||
|
||||
public struct SufamiTurboFilePromptMessage
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5000)]
|
||||
public byte[] Filename;
|
||||
}
|
||||
|
||||
public struct ExecuteShortcutParams
|
||||
{
|
||||
public EmulatorShortcut Shortcut;
|
||||
|
|
|
@ -18,6 +18,8 @@ public static class FirmwareTypeExtensions
|
|||
case FirmwareType.ST011: return new("st011.rom") { new(0xD000, "8B2B3F3F3E6E29F4D21D8BC736B400BC988B7D2214EBEE15643F01C1FEE2F364") };
|
||||
case FirmwareType.ST018: return new("st018.rom") { new(0x28000, "6DF209AB5D2524D1839C038BE400AE5EB20DAFC14A3771A3239CD9E8ACD53806") };
|
||||
|
||||
case FirmwareType.SufamiTurbo: return new("SufamiTurbo.sfc") { new(0x40000, "EDACB453DA14F825F05D1134D6035F4BF034E55F7CFB97C70C4EE107EABC7342") };
|
||||
|
||||
case FirmwareType.Satellaview: return new("BS-X.bin") {
|
||||
new(1024 * 1024,
|
||||
"27CFDB99F7E4252BF3740D420147B63C4C88616883BC5E7FE43F2F30BF8C8CBB", //Japan, no DRM
|
||||
|
|
|
@ -71,6 +71,9 @@ namespace Mesen.Interop
|
|||
case MemoryType.SnesCgRam:
|
||||
case MemoryType.BsxPsRam:
|
||||
case MemoryType.BsxMemoryPack:
|
||||
case MemoryType.SufamiTurboFirmware:
|
||||
case MemoryType.SufamiTurboSecondCart:
|
||||
case MemoryType.SufamiTurboSecondCartRam:
|
||||
case MemoryType.SnesRegister:
|
||||
return CpuType.Snes;
|
||||
|
||||
|
@ -246,6 +249,8 @@ namespace Mesen.Interop
|
|||
case MemoryType.DspProgramRom:
|
||||
case MemoryType.St018PrgRom:
|
||||
case MemoryType.St018DataRom:
|
||||
case MemoryType.SufamiTurboFirmware:
|
||||
case MemoryType.SufamiTurboSecondCart:
|
||||
case MemoryType.SpcRom:
|
||||
case MemoryType.SmsPrgRom:
|
||||
case MemoryType.SmsBootRom:
|
||||
|
@ -272,6 +277,9 @@ namespace Mesen.Interop
|
|||
case MemoryType.St018PrgRom:
|
||||
case MemoryType.St018DataRom:
|
||||
case MemoryType.St018WorkRam:
|
||||
case MemoryType.SufamiTurboFirmware:
|
||||
case MemoryType.SufamiTurboSecondCart:
|
||||
case MemoryType.SufamiTurboSecondCartRam:
|
||||
|
||||
//Gameboy
|
||||
case MemoryType.GbPrgRom:
|
||||
|
@ -461,6 +469,10 @@ namespace Mesen.Interop
|
|||
|
||||
MemoryType.BsxPsRam => "PSRAM",
|
||||
MemoryType.BsxMemoryPack => "MPACK",
|
||||
|
||||
MemoryType.SufamiTurboFirmware => "BOOT",
|
||||
MemoryType.SufamiTurboSecondCart => "BPRG",
|
||||
MemoryType.SufamiTurboSecondCartRam => "BRAM",
|
||||
|
||||
MemoryType.GameboyMemory => "CPU",
|
||||
MemoryType.GbPrgRom => "PRG",
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace Mesen.Interop
|
|||
ViewerRefresh,
|
||||
EventViewerRefresh,
|
||||
MissingFirmware,
|
||||
SufamiTurboFilePrompt,
|
||||
BeforeGameUnload,
|
||||
BeforeGameLoad,
|
||||
GameLoadFailed,
|
||||
|
|
|
@ -1725,6 +1725,8 @@
|
|||
<Message ID="PromptSaveChanges">Save changes?</Message>
|
||||
<Message ID="PromptKeepChanges">Keep changes?</Message>
|
||||
|
||||
<Message ID="PromptLoadSufamiTurbo">Do you want to load a second Sufami Turbo ROM to insert into slot B?</Message>
|
||||
|
||||
<Message ID="UnknownFirmwareHash">This file does not match any of the known firmwares and may not work properly.

Expected (SHA256): {0}
Current (SHA256): {1}</Message>
|
||||
<Message ID="InvalidFirmwareSize">This file does not have the required size.

Expected: {0} bytes
Current: {1} bytes</Message>
|
||||
<Message ID="PromptDeleteFirmware">The following file will be deleted permanently. Are you sure?

{0}</Message>
|
||||
|
@ -2683,6 +2685,7 @@ E
|
|||
<Value ID="ST010">ST010</Value>
|
||||
<Value ID="ST011">ST011</Value>
|
||||
<Value ID="ST018">ST018</Value>
|
||||
<Value ID="SufamiTurbo">Sufami Turbo</Value>
|
||||
<Value ID="Satellaview">Satellaview (BS-X)</Value>
|
||||
<Value ID="Gameboy">Game Boy CPU</Value>
|
||||
<Value ID="GameboyColor">Game Boy Color CPU</Value>
|
||||
|
@ -2749,7 +2752,10 @@ E
|
|||
<Value ID="St018PrgRom">ST018 PRG ROM</Value>
|
||||
<Value ID="St018DataRom">ST018 Data ROM</Value>
|
||||
<Value ID="St018WorkRam">ST018 Work RAM</Value>
|
||||
|
||||
<Value ID="SufamiTurboFirmware">Sufami Turbo Firmware</Value>
|
||||
<Value ID="SufamiTurboSecondCart">Sufami Slot B ROM</Value>
|
||||
<Value ID="SufamiTurboSecondCartRam">Sufami Slot B RAM</Value>
|
||||
|
||||
<Value ID="GameboyMemory">GB - CPU Memory</Value>
|
||||
<Value ID="GbPrgRom">GB - PRG ROM</Value>
|
||||
<Value ID="GbWorkRam">GB - Work RAM</Value>
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace Mesen.Utilities
|
|||
public const string NesAsmLabelExt = "fns";
|
||||
public const string BinExt = "bin";
|
||||
public const string NesExt = "nes";
|
||||
public const string SufamiTurboExt = "st";
|
||||
|
||||
public static async Task<string?> OpenFile(string? initialFolder, IRenderRoot? parent, params string[] extensions)
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ namespace Mesen.Utilities
|
|||
foreach(string ext in extensions) {
|
||||
if(ext == FileDialogHelper.RomExt) {
|
||||
filter.Add(new FilePickerFileType("All ROM files") { Patterns = new List<string>() {
|
||||
"*.sfc", "*.fig", "*.smc", "*.bs", "*.spc",
|
||||
"*.sfc", "*.fig", "*.smc", "*.bs", "*.st", "*.spc",
|
||||
"*.nes", "*.fds", "*.unif", "*.unf", "*.studybox", "*.nsf", "*.nsfe",
|
||||
"*.gb", "*.gbc", "*.gbx", "*.gbs",
|
||||
"*.pce", "*.sgx", "*.cue", "*.hes",
|
||||
|
@ -60,7 +61,7 @@ namespace Mesen.Utilities
|
|||
"*.ws", "*.wsc",
|
||||
"*.zip", "*.7z"
|
||||
} });
|
||||
filter.Add(new FilePickerFileType("SNES ROM files") { Patterns = new List<string>() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.spc" } });
|
||||
filter.Add(new FilePickerFileType("SNES ROM files") { Patterns = new List<string>() { "*.sfc", "*.fig", "*.smc", "*.bs", "*.st", "*.spc" } });
|
||||
filter.Add(new FilePickerFileType("NES ROM files") { Patterns = new List<string>() { "*.nes", "*.fds", "*.unif", "*.unf", "*.studybox", "*.nsf", "*.nsfe" } });
|
||||
filter.Add(new FilePickerFileType("GB ROM files") { Patterns = new List<string>() { "*.gb", "*.gbc", "*.gbx", "*.gbs" } });
|
||||
filter.Add(new FilePickerFileType("GBA ROM files") { Patterns = new List<string>() { "*.gba" } });
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Mesen.Utilities
|
|||
public static class FolderHelper
|
||||
{
|
||||
private static HashSet<string> _romExtensions = new HashSet<string>() {
|
||||
".sfc", ".smc", ".fig", ".swc", ".bs",
|
||||
".sfc", ".smc", ".fig", ".swc", ".bs", ".st",
|
||||
".gb", ".gbc", ".gbx",
|
||||
".nes", ".unif", ".unf", ".fds", ".studybox",
|
||||
".pce", ".sgx", ".cue",
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
</c:OptionSection>
|
||||
|
||||
<c:OptionSection Header="{l:Translate lblSnes}" Icon="Assets/SnesIcon.png" >
|
||||
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,*">
|
||||
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,*">
|
||||
<TextBlock Text="DSP-1" Grid.Row="1" />
|
||||
<c:FirmwareSelect FirmwareType="DSP1" Grid.Column="1" Grid.Row="1" />
|
||||
|
||||
|
@ -111,20 +111,23 @@
|
|||
<TextBlock Text="Satellaview / BS-X" Grid.Row="6" />
|
||||
<c:FirmwareSelect FirmwareType="Satellaview" Grid.Column="1" Grid.Row="6" />
|
||||
|
||||
<TextBlock Text="Super Game Boy (v1)" Grid.Row="7" />
|
||||
<c:FirmwareSelect FirmwareType="SGB1" Grid.Column="1" Grid.Row="7" />
|
||||
<TextBlock Text="Sufami Turbo" Grid.Row="7" />
|
||||
<c:FirmwareSelect FirmwareType="SufamiTurbo" Grid.Column="1" Grid.Row="7" />
|
||||
|
||||
<TextBlock Text="Super Game Boy (v2)" Grid.Row="8" />
|
||||
<c:FirmwareSelect FirmwareType="SGB2" Grid.Column="1" Grid.Row="8" />
|
||||
<TextBlock Text="Super Game Boy (v1)" Grid.Row="8" />
|
||||
<c:FirmwareSelect FirmwareType="SGB1" Grid.Column="1" Grid.Row="8" />
|
||||
|
||||
<TextBlock Text="ST010" Grid.Row="9" />
|
||||
<c:FirmwareSelect FirmwareType="ST010" Grid.Column="1" Grid.Row="9" />
|
||||
<TextBlock Text="Super Game Boy (v2)" Grid.Row="9" />
|
||||
<c:FirmwareSelect FirmwareType="SGB2" Grid.Column="1" Grid.Row="9" />
|
||||
|
||||
<TextBlock Text="ST011" Grid.Row="10" />
|
||||
<c:FirmwareSelect FirmwareType="ST011" Grid.Column="1" Grid.Row="10" />
|
||||
<TextBlock Text="ST010" Grid.Row="10" />
|
||||
<c:FirmwareSelect FirmwareType="ST010" Grid.Column="1" Grid.Row="10" />
|
||||
|
||||
<TextBlock Text="ST018" Grid.Row="11" />
|
||||
<c:FirmwareSelect FirmwareType="ST018" Grid.Column="1" Grid.Row="11" />
|
||||
<TextBlock Text="ST011" Grid.Row="11" />
|
||||
<c:FirmwareSelect FirmwareType="ST011" Grid.Column="1" Grid.Row="11" />
|
||||
|
||||
<TextBlock Text="ST018" Grid.Row="12" />
|
||||
<c:FirmwareSelect FirmwareType="ST018" Grid.Column="1" Grid.Row="12" />
|
||||
</Grid>
|
||||
</c:OptionSection>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ using Mesen.Controls;
|
|||
using Mesen.Localization;
|
||||
using System.Diagnostics;
|
||||
using Avalonia.VisualTree;
|
||||
using System.Text;
|
||||
|
||||
namespace Mesen.Windows
|
||||
{
|
||||
|
@ -367,7 +368,7 @@ namespace Mesen.Windows
|
|||
});
|
||||
break;
|
||||
|
||||
case ConsoleNotificationType.MissingFirmware:
|
||||
case ConsoleNotificationType.MissingFirmware: {
|
||||
MissingFirmwareMessage msg = Marshal.PtrToStructure<MissingFirmwareMessage>(e.Parameter);
|
||||
TaskCompletionSource tcs = new TaskCompletionSource();
|
||||
Dispatcher.UIThread.Post(async () => {
|
||||
|
@ -376,6 +377,25 @@ namespace Mesen.Windows
|
|||
});
|
||||
tcs.Task.Wait();
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleNotificationType.SufamiTurboFilePrompt: {
|
||||
SufamiTurboFilePromptMessage msg = Marshal.PtrToStructure<SufamiTurboFilePromptMessage>(e.Parameter);
|
||||
TaskCompletionSource tcs = new TaskCompletionSource();
|
||||
Dispatcher.UIThread.Post(async () => {
|
||||
if(await MesenMsgBox.Show(this, "PromptLoadSufamiTurbo", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
|
||||
string? selectedFile = await FileDialogHelper.OpenFile(null, this, FileDialogHelper.SufamiTurboExt);
|
||||
if(selectedFile != null) {
|
||||
byte[] file = Encoding.UTF8.GetBytes(selectedFile);
|
||||
Array.Copy(file, msg.Filename, file.Length);
|
||||
Marshal.StructureToPtr<SufamiTurboFilePromptMessage>(msg, e.Parameter, false);
|
||||
}
|
||||
}
|
||||
tcs.SetResult();
|
||||
});
|
||||
tcs.Task.Wait();
|
||||
break;
|
||||
}
|
||||
|
||||
case ConsoleNotificationType.BeforeGameLoad:
|
||||
Dispatcher.UIThread.Post(() => {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
const std::initializer_list<string> VirtualFile::RomExtensions = {
|
||||
".nes", ".fds", ".unif", ".unf", ".nsf", ".nsfe", ".studybox",
|
||||
".sfc", ".swc", ".fig", ".smc", ".bs", ".spc",
|
||||
".sfc", ".swc", ".fig", ".smc", ".bs", ".st", ".spc",
|
||||
".gb", ".gbc", ".gbx", ".gbs",
|
||||
".pce", ".sgx", ".cue", ".hes",
|
||||
".sms", ".gg", ".sg", ".col",
|
||||
|
|
Loading…
Add table
Reference in a new issue