Added BS-X support

WIP - Still some issues and missing some features (e.g date/time support)
This commit is contained in:
Sour 2020-02-19 23:53:34 -05:00
parent b856f615d1
commit cf909b56d8
33 changed files with 726 additions and 36 deletions

View file

@ -17,6 +17,9 @@
#include "Cx4.h"
#include "Obc1.h"
#include "Spc7110.h"
#include "BsxCart.h"
#include "BsxMemoryPack.h"
#include "FirmwareHelper.h"
#include "SpcFileData.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/VirtualFile.h"
@ -52,9 +55,17 @@ shared_ptr<BaseCartridge> BaseCartridge::CreateCartridge(Console* console, Virtu
cart->_console = console;
cart->_romPath = romFile;
cart->_prgRomSize = (uint32_t)romData.size();
cart->_prgRom = new uint8_t[cart->_prgRomSize];
memcpy(cart->_prgRom, romData.data(), cart->_prgRomSize);
if(FolderUtilities::GetExtension(romFile.GetFileName()) == ".bs") {
cart->_bsxMemPack.reset(new BsxMemoryPack(romData));
if(!FirmwareHelper::LoadBsxFirmware(console, &cart->_prgRom, cart->_prgRomSize)) {
return nullptr;
}
} else {
cart->_prgRomSize = (uint32_t)romData.size();
cart->_prgRom = new uint8_t[cart->_prgRomSize];
memcpy(cart->_prgRom, romData.data(), cart->_prgRomSize);
}
if(memcmp(cart->_prgRom, "SNES-SPC700 Sound File Data", 27) == 0) {
if(cart->_prgRomSize >= 0x10200) {
@ -272,6 +283,9 @@ void BaseCartridge::Reset()
if(_coprocessor) {
_coprocessor->Reset();
}
if(_bsxMemPack) {
_bsxMemPack->Reset();
}
}
RomInfo BaseCartridge::GetRomInfo()
@ -423,6 +437,18 @@ void BaseCartridge::InitCoprocessor()
_coprocessor.reset(new Sdd1(_console));
} else if(_coprocessorType == CoprocessorType::SPC7110) {
_coprocessor.reset(new Spc7110(_console, _hasRtc));
} else if(_coprocessorType == CoprocessorType::Satellaview) {
//Share save file across all .bs files that use the BS-X bios
_console->GetBatteryManager()->Initialize("bsxbios");
if(!_bsxMemPack) {
//Create an empty memory pack if the BIOS was loaded directly (instead of a .bs file)
vector<uint8_t> emptyMemPack;
_bsxMemPack.reset(new BsxMemoryPack(emptyMemPack));
}
_coprocessor.reset(new BsxCart(_console, _bsxMemPack.get()));
_bsx = dynamic_cast<BsxCart*>(_coprocessor.get());
} else if(_coprocessorType == CoprocessorType::CX4) {
_coprocessor.reset(new Cx4(_console));
_cx4 = dynamic_cast<Cx4*>(_coprocessor.get());
@ -505,6 +531,9 @@ void BaseCartridge::Serialize(Serializer &s)
if(_coprocessor) {
s.Stream(_coprocessor.get());
}
if(_bsxMemPack) {
s.Stream(_bsxMemPack.get());
}
}
string BaseCartridge::GetGameCode()
@ -633,6 +662,16 @@ Cx4* BaseCartridge::GetCx4()
return _cx4;
}
BsxCart* BaseCartridge::GetBsx()
{
return _bsx;
}
BsxMemoryPack* BaseCartridge::GetBsxMemoryPack()
{
return _bsxMemPack.get();
}
Gsu* BaseCartridge::GetGsu()
{
return _gsu;

View file

@ -12,6 +12,8 @@ class NecDsp;
class Sa1;
class Gsu;
class Cx4;
class BsxCart;
class BsxMemoryPack;
class Console;
class SpcFileData;
enum class ConsoleRegion;
@ -31,6 +33,8 @@ private:
Sa1 *_sa1 = nullptr;
Gsu *_gsu = nullptr;
Cx4 *_cx4 = nullptr;
BsxCart* _bsx = nullptr;
unique_ptr<BsxMemoryPack> _bsxMemPack;
CartFlags::CartFlags _flags = CartFlags::CartFlags::None;
CoprocessorType _coprocessorType = CoprocessorType::None;
@ -96,6 +100,8 @@ public:
Sa1* GetSa1();
Gsu* GetGsu();
Cx4* GetCx4();
BsxCart* GetBsx();
BsxMemoryPack* GetBsxMemoryPack();
void RunCoprocessors();

237
Core/BsxCart.cpp Normal file
View file

@ -0,0 +1,237 @@
#include "stdafx.h"
#include "BsxCart.h"
#include "Console.h"
#include "MemoryManager.h"
#include "MemoryMappings.h"
#include "BaseCartridge.h"
#include "BsxMemoryPack.h"
#include "RamHandler.h"
#include "EmuSettings.h"
BsxCart::BsxCart(Console* console, BsxMemoryPack* memPack)
{
_console = console;
_memoryManager = _console->GetMemoryManager().get();
_memPack = memPack;
MemoryMappings* mm = _console->GetMemoryManager()->GetMemoryMappings();
mm->RegisterHandler(0x00, 0x0F, 0x5000, 0x5FFF, this);
mm->RegisterHandler(0x10, 0x1F, 0x5000, 0x5FFF, _console->GetCartridge()->GetSaveRamHandlers());
//Regular B Bus register handler, keep a reference to it, it'll be overwritten below
_bBusHandler = mm->GetHandler(0x2000);
mm->RegisterHandler(0x00, 0x3F, 0x2000, 0x2FFF, this);
mm->RegisterHandler(0x80, 0xBF, 0x2000, 0x2FFF, this);
_psRamSize = 512 * 1024;
_psRam = new uint8_t[_psRamSize];
console->GetSettings()->InitializeRam(_psRam, _psRamSize);
for(uint32_t i = 0; i < _psRamSize / 0x1000; i++) {
_psRamHandlers.push_back(unique_ptr<IMemoryHandler>(new RamHandler(_psRam, i * 0x1000, _psRamSize, SnesMemoryType::BsxPsRam)));
}
Reset();
}
BsxCart::~BsxCart()
{
delete[] _psRam;
}
uint8_t BsxCart::Read(uint32_t addr)
{
if((addr & 0x6000) == 0x2000) {
addr &= 0xFFFF;
if(addr >= 0x2188 && addr <= 0x219F) {
//Handle BS-X $2188-219F registers
return 0;
} else {
//Use regular B-bus handler for everything else
return _bBusHandler->Read(addr);
}
}
uint8_t openBus = _memoryManager->GetOpenBus();
if((addr & 0xFFFF) != 0x5000) {
return openBus;
} else {
uint8_t reg = (addr >> 16) & 0x0F;
if(reg <= 0x0D) {
return (_regs[reg] << 7) | (openBus & 0x7F);
} else {
//E & F are write-only
return openBus & 0x7F;
}
}
}
void BsxCart::Write(uint32_t addr, uint8_t value)
{
if((addr & 0x6000) == 0x2000) {
addr &= 0xFFFF;
if(addr >= 0x2188 && addr <= 0x219F) {
//Handle BS-X register writes
} else {
//Regular B-bus handler
_bBusHandler->Write(addr, value);
}
return;
} else if((addr & 0xFFFF) != 0x5000) {
return;
}
uint8_t reg = (addr >> 16) & 0x0F;
if(reg == 0x0E) {
if(_dirty) {
memcpy(_regs, _dirtyRegs, sizeof(_regs));
UpdateMemoryMappings();
_dirty = false;
}
} else {
uint8_t regValue = (value >> 7);
if(_regs[reg] != regValue) {
_dirtyRegs[reg] = regValue;
_dirty = true;
}
}
}
void BsxCart::UpdateMemoryMappings()
{
MemoryMappings* mm = _console->GetMemoryManager()->GetMemoryMappings();
vector<unique_ptr<IMemoryHandler>>& prgHandlers = _console->GetCartridge()->GetPrgRomHandlers();
vector<unique_ptr<IMemoryHandler>>& memPackHandlers = _memPack->GetMemoryHandlers();
uint8_t unmappedBank = (_regs[0x0B] << 5);
uint8_t psRamBank = (_regs[0x05] << 4) | (_regs[0x06] << 5);
if(!_regs[0x02]) {
//LoROM
//Memory pack mapping
mm->RegisterHandler(0x00, 0x7D, 0x8000, 0xFFFF, memPackHandlers);
mm->RegisterHandler(0x40, 0x7D, 0x0000, 0x7FFF, memPackHandlers);
mm->RegisterHandler(0x80, 0xFF, 0x8000, 0xFFFF, memPackHandlers);
mm->RegisterHandler(0xC0, 0xFF, 0x0000, 0x7FFF, memPackHandlers);
//Memory hole mapping
uint16_t unmappedAddr = _regs[0x0B] ? 0x0000 : 0x8000;
if(_regs[0x09]) {
mm->RegisterHandler(0x00 | (unmappedBank << 1), 0x1F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr);
}
if(_regs[0x0A]) {
mm->RegisterHandler(0x80 | (unmappedBank << 1), 0x9F | (unmappedBank << 1), unmappedAddr, 0xFFFF, nullptr);
}
//PSRAM mapping
uint16_t psRamAddr = (psRamBank & 0x20) ? 0x0000 : 0x8000;
if(_regs[0x03]) {
mm->RegisterHandler(0x00 | (psRamBank << 1), 0x0F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0x70, 0x7D, 0x0000, 0x7FFF, _psRamHandlers);
}
if(_regs[0x04]) {
mm->RegisterHandler(0x80 | (psRamBank << 1), 0x8F | (psRamBank << 1), psRamAddr, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0xF0, 0xFF, 0x0000, 0x7FFF, _psRamHandlers);
}
} else {
//HiROM
//Memory pack mapping
mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, memPackHandlers, 8);
mm->RegisterHandler(0x40, 0x7D, 0x0000, 0xFFFF, memPackHandlers, 0);
mm->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, memPackHandlers, 8);
mm->RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, memPackHandlers, 0);
//Memory hole mapping
if(_regs[0x09]) {
mm->RegisterHandler(0x00 | unmappedBank, 0x0F | unmappedBank, 0x8000, 0xFFFF, nullptr);
mm->RegisterHandler(0x40 | unmappedBank, 0x4F | unmappedBank, 0x0000, 0xFFFF, nullptr);
}
if(_regs[0x0A]) {
mm->RegisterHandler(0x80 | unmappedBank, 0x8F | unmappedBank, 0x8000, 0xFFFF, nullptr);
mm->RegisterHandler(0xC0 | unmappedBank, 0xCF | unmappedBank, 0x0000, 0xFFFF, nullptr);
}
//PSRAM mapping
if(_regs[0x03]) {
//Lower Banks (0x00-0x7D)
mm->RegisterHandler(0x00 | psRamBank, 0x07 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8);
mm->RegisterHandler(0x40 | psRamBank, 0x47 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0x20, 0x3F, 0x6000, 0x7FFF, _psRamHandlers, 6);
}
if(_regs[0x04]) {
//Higher Banks (0x80-0xFF)
mm->RegisterHandler(0x80 | psRamBank, 0x87 | psRamBank, 0x8000, 0xFFFF, _psRamHandlers, 8);
mm->RegisterHandler(0xC0 | psRamBank, 0xC7 | psRamBank, 0x0000, 0xFFFF, _psRamHandlers);
mm->RegisterHandler(0xA0, 0xBF, 0x6000, 0x7FFF, _psRamHandlers, 6);
}
}
//BS-X BIOS mapping (can override other mappings above)
if(_regs[0x07]) {
mm->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgHandlers);
}
if(_regs[0x08]) {
mm->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, prgHandlers);
}
}
void BsxCart::Reset()
{
for(int i = 0; i < 0x10; i++) {
_regs[i] = true;
}
_regs[0x04] = false;
_regs[0x0A] = false;
_regs[0x0C] = false;
_regs[0x0D] = false;
_dirty = false;
memcpy(_dirtyRegs, _regs, sizeof(_regs));
UpdateMemoryMappings();
}
void BsxCart::Serialize(Serializer& s)
{
ArrayInfo<uint8_t> psRam = { _psRam, _psRamSize };
ArrayInfo<uint8_t> regs = { _regs, 0x10 };
ArrayInfo<uint8_t> dirtyRegs = { _dirtyRegs, 0x10 };
s.Stream(psRam, regs, dirtyRegs, _dirty);
if(!s.IsSaving()) {
UpdateMemoryMappings();
}
}
uint8_t BsxCart::Peek(uint32_t addr)
{
return 0;
}
void BsxCart::PeekBlock(uint32_t addr, uint8_t* output)
{
memset(output, 0, 0x1000);
}
AddressInfo BsxCart::GetAbsoluteAddress(uint32_t address)
{
return { -1, SnesMemoryType::Register };
}
uint8_t* BsxCart::DebugGetPsRam()
{
return _psRam;
}
uint32_t BsxCart::DebugGetPsRamSize()
{
return _psRamSize;
}

44
Core/BsxCart.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#include "stdafx.h"
#include "BaseCoprocessor.h"
class Console;
class MemoryManager;
class BsxMemoryPack;
class BsxCart : public BaseCoprocessor
{
private:
Console* _console;
MemoryManager* _memoryManager;
BsxMemoryPack* _memPack;
uint8_t* _psRam = nullptr;
uint32_t _psRamSize = 0;
vector<unique_ptr<IMemoryHandler>> _psRamHandlers;
IMemoryHandler* _bBusHandler = nullptr;
uint8_t _regs[0x10] = {};
uint8_t _dirtyRegs[0x10] = {};
bool _dirty = false;
void UpdateMemoryMappings();
public:
BsxCart(Console* console, BsxMemoryPack* memPack);
virtual ~BsxCart();
uint8_t Read(uint32_t addr) override;
void Write(uint32_t addr, uint8_t value) override;
void Reset() override;
void Serialize(Serializer& s) override;
uint8_t Peek(uint32_t addr) override;
void PeekBlock(uint32_t addr, uint8_t* output) override;
AddressInfo GetAbsoluteAddress(uint32_t address) override;
uint8_t* DebugGetPsRam();
uint32_t DebugGetPsRamSize();
};

150
Core/BsxMemoryPack.cpp Normal file
View file

@ -0,0 +1,150 @@
#include "stdafx.h"
#include "BsxMemoryPack.h"
#include "../Utilities/IpsPatcher.h"
BsxMemoryPack::BsxMemoryPack(vector<uint8_t>& data)
{
_orgData = data;
_dataSize = (uint32_t)data.size();
_data = new uint8_t[_dataSize];
memcpy(_data, data.data(), _dataSize);
_calculatedSize = std::min<uint8_t>(0x0C, (uint8_t)log2(_dataSize >> 10));
for(uint32_t i = 0; i < _dataSize / 0x1000; i++) {
_handlers.push_back(unique_ptr<BsxMemoryPackHandler>(new BsxMemoryPackHandler(this, i * 0x1000)));
}
}
BsxMemoryPack::~BsxMemoryPack()
{
delete[] _data;
}
void BsxMemoryPack::Serialize(Serializer& s)
{
s.Stream(_writeProtect, _enableCsr, _enableEsr, _enableVendorInfo, _writeByte, _command);
if(s.IsSaving()) {
//Save content of memory pack as an IPS patch
vector<uint8_t> newData(_data, _data + _dataSize);
vector<uint8_t> ipsData = IpsPatcher::CreatePatch(_orgData, newData);
VectorInfo<uint8_t> data { &ipsData };
s.Stream(data);
} else {
//Apply IPS patch to original data and overwrite the current data
vector<uint8_t> ipsData;
VectorInfo<uint8_t> data { &ipsData };
s.Stream(data);
if(ipsData.size() > 8) {
vector<uint8_t> output;
IpsPatcher::PatchBuffer(ipsData, _orgData, output);
memcpy(_data, output.data(), _dataSize);
}
}
}
void BsxMemoryPack::ProcessCommand(uint8_t value, uint32_t page)
{
_command = (_command << 8) | value;
switch(value) {
case 0x00:
case 0xFF:
_enableCsr = false;
_enableEsr = false;
_enableVendorInfo = false;
break;
case 0x10:
case 0x40:
_writeByte = true;
break;
case 0x70: _enableCsr = true; break;
case 0x71: _enableEsr = true; break;
case 0x75: _enableVendorInfo = true; break;
}
switch(_command) {
case 0x20D0: memset(_data + page * 0x10000, 0x10000, 0xFF); break; //Page erase
case 0xA7D0: memset(_data, _dataSize, 0xFF); break; //Chip erase
}
}
void BsxMemoryPack::Reset()
{
_writeProtect = true;
_enableCsr = false;
_enableEsr = false;
_writeByte = false;
_enableVendorInfo = false;
_command = 0;
}
vector<unique_ptr<IMemoryHandler>>& BsxMemoryPack::GetMemoryHandlers()
{
return _handlers;
}
uint8_t* BsxMemoryPack::DebugGetMemoryPack()
{
return _data;
}
uint32_t BsxMemoryPack::DebugGetMemoryPackSize()
{
return _dataSize;
}
BsxMemoryPack::BsxMemoryPackHandler::BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset) : RamHandler(memPack->_data, offset, memPack->_dataSize, SnesMemoryType::BsxMemoryPack)
{
_memPack = memPack;
_page = offset / 0x10000;
}
uint8_t BsxMemoryPack::BsxMemoryPackHandler::Read(uint32_t addr)
{
if(addr >= 0xC00000) {
if(_memPack->_enableEsr) {
switch(addr & 0xFFFF) {
case 0x0002: return 0xC0;
case 0x0004: return 0x82;
}
}
}
if(_memPack->_enableCsr) {
_memPack->_enableCsr = false;
return 0x80;
}
if(_memPack->_enableVendorInfo && ((addr & 0x7FFF) >= 0x7F00) && ((addr & 0x7FFF) <= 0x7F13)) {
//Flash cartridge vendor information
switch(addr & 0xFF) {
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
case 0x03: return 0x00;
case 0x04: return 0x00;
case 0x05: return 0x00;
case 0x06: return 0x10 | _memPack->_calculatedSize; //Memory Pack Type 1
case 0x07: return 0x00;
default: return 0x00;
}
}
return RamHandler::Read(addr);
}
void BsxMemoryPack::BsxMemoryPackHandler::Write(uint32_t addr, uint8_t value)
{
if(addr == 0xC00000) {
_memPack->ProcessCommand(value, _page);
}
if(!_memPack->_writeProtect) {
RamHandler::Write(addr, value);
}
}

49
Core/BsxMemoryPack.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
#include "stdafx.h"
#include "RamHandler.h"
#include "IMemoryHandler.h"
#include "../Utilities/ISerializable.h"
class BsxMemoryPackHandler;
class BsxMemoryPack : public ISerializable
{
vector<uint8_t> _orgData;
uint8_t* _data = nullptr;
uint32_t _dataSize = 0;
vector<unique_ptr<IMemoryHandler>> _handlers;
uint8_t _calculatedSize = 0x0C;
bool _writeProtect = true;
bool _enableCsr = false;
bool _enableEsr = false;
bool _enableVendorInfo = false;
bool _writeByte = false;
uint16_t _command = 0;
public:
BsxMemoryPack(vector<uint8_t>& data);
virtual ~BsxMemoryPack();
void Serialize(Serializer& s) override;
void ProcessCommand(uint8_t value, uint32_t page);
void Reset();
vector<unique_ptr<IMemoryHandler>>& GetMemoryHandlers();
uint8_t* DebugGetMemoryPack();
uint32_t DebugGetMemoryPackSize();
class BsxMemoryPackHandler : public RamHandler
{
BsxMemoryPack* _memPack;
uint32_t _page;
public:
BsxMemoryPackHandler(BsxMemoryPack* memPack, uint32_t offset);
uint8_t Read(uint32_t addr) override;
void Write(uint32_t addr, uint8_t value) override;
};
};

View file

@ -49,6 +49,8 @@
<ClInclude Include="BaseControlDevice.h" />
<ClInclude Include="BaseCoprocessor.h" />
<ClInclude Include="BatteryManager.h" />
<ClInclude Include="BsxCart.h" />
<ClInclude Include="BsxMemoryPack.h" />
<ClInclude Include="CheatManager.h" />
<ClInclude Include="ClientConnectionData.h" />
<ClInclude Include="Cpu.Shared.h" />
@ -223,6 +225,8 @@
<ClCompile Include="BatteryManager.cpp" />
<ClCompile Include="Breakpoint.cpp" />
<ClCompile Include="BreakpointManager.cpp" />
<ClCompile Include="BsxCart.cpp" />
<ClCompile Include="BsxMemoryPack.cpp" />
<ClCompile Include="CallstackManager.cpp" />
<ClCompile Include="CheatManager.cpp" />
<ClCompile Include="CodeDataLogger.cpp" />

View file

@ -503,6 +503,12 @@
<ClInclude Include="Rtc4513.h">
<Filter>SNES\Coprocessors\SPC7110</Filter>
</ClInclude>
<ClInclude Include="BsxCart.h">
<Filter>SNES\Coprocessors\BSX</Filter>
</ClInclude>
<ClInclude Include="BsxMemoryPack.h">
<Filter>SNES\Coprocessors\BSX</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -803,6 +809,12 @@
<ClCompile Include="Rtc4513.cpp">
<Filter>SNES\Coprocessors\SPC7110</Filter>
</ClCompile>
<ClCompile Include="BsxCart.cpp">
<Filter>SNES\Coprocessors\BSX</Filter>
</ClCompile>
<ClCompile Include="BsxMemoryPack.cpp">
<Filter>SNES\Coprocessors\BSX</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
@ -877,5 +889,8 @@
<Filter Include="SNES\Coprocessors\SPC7110">
<UniqueIdentifier>{996b46fc-8c11-4715-99a0-394640d3fdcf}</UniqueIdentifier>
</Filter>
<Filter Include="SNES\Coprocessors\BSX">
<UniqueIdentifier>{c519e61b-e1c6-4182-8a23-ed23b60fbf96}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -46,6 +46,8 @@ enum class SnesMemoryType
Sa1InternalRam,
GsuWorkRam,
Cx4DataRam,
BsxPsRam,
BsxMemoryPack,
Register,
};

View file

@ -403,7 +403,7 @@ void Debugger::SuspendDebugger(bool release)
_suspendRequestCount--;
} else {
#ifdef _DEBUG
throw std::runtime_error("unexpected debugger suspend::release call");
//throw std::runtime_error("unexpected debugger suspend::release call");
#endif
}
} else {

View file

@ -7,6 +7,8 @@
#include "NecDsp.h"
#include "Sa1.h"
#include "Gsu.h"
#include "BsxCart.h"
#include "BsxMemoryPack.h"
#include "Debugger.h"
#include "MemoryManager.h"
#include "LabelManager.h"
@ -54,6 +56,11 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
_gsuWorkRam = console->GetCartridge()->GetGsu() ? console->GetCartridge()->GetGsu()->DebugGetWorkRam() : nullptr;
_gsuWorkRamSize = console->GetCartridge()->GetGsu() ? console->GetCartridge()->GetGsu()->DebugGetWorkRamSize() : 0;
_bsxPsRam = console->GetCartridge()->GetBsx() ? console->GetCartridge()->GetBsx()->DebugGetPsRam() : nullptr;
_bsxPsRamSize = console->GetCartridge()->GetBsx() ? console->GetCartridge()->GetBsx()->DebugGetPsRamSize() : 0;
_bsxMemPack = console->GetCartridge()->GetBsx() ? console->GetCartridge()->GetBsxMemoryPack()->DebugGetMemoryPack() : nullptr;
_bsxMemPackSize = console->GetCartridge()->GetBsx() ? console->GetCartridge()->GetBsxMemoryPack()->DebugGetMemoryPackSize() : 0;
_prgCache = vector<DisassemblyInfo>(_prgRomSize);
_sramCache = vector<DisassemblyInfo>(_sramSize);
_wramCache = vector<DisassemblyInfo>(_wramSize);
@ -62,6 +69,8 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
_necDspRomCache = vector<DisassemblyInfo>(_necDspProgramRomSize);
_sa1InternalRamCache = vector<DisassemblyInfo>(_sa1InternalRamSize);
_gsuWorkRamCache = vector<DisassemblyInfo>(_gsuWorkRamSize);
_bsxPsRamCache = vector<DisassemblyInfo>(_bsxPsRamSize);
_bsxMemPackCache = vector<DisassemblyInfo>(_bsxMemPackSize);
for(int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) {
_needDisassemble[i] = true;
@ -75,6 +84,8 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
_sources[(int)SnesMemoryType::DspProgramRom] = { _necDspProgramRom, &_necDspRomCache, _necDspProgramRomSize };
_sources[(int)SnesMemoryType::Sa1InternalRam] = { _sa1InternalRam, &_sa1InternalRamCache, _sa1InternalRamSize };
_sources[(int)SnesMemoryType::GsuWorkRam] = { _gsuWorkRam, &_gsuWorkRamCache, _gsuWorkRamSize };
_sources[(int)SnesMemoryType::BsxPsRam] = { _bsxPsRam, &_bsxPsRamCache, _bsxPsRamSize };
_sources[(int)SnesMemoryType::BsxMemoryPack] = { _bsxMemPack, &_bsxMemPackCache, _bsxMemPackSize };
}
DisassemblerSource Disassembler::GetSource(SnesMemoryType type)
@ -468,7 +479,7 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d
if(!disInfo.IsInitialized()) {
disInfo = DisassemblyInfo(src.Data + result.Address.Address, state.PS, CpuType::Cpu);
} else {
data.Flags |= _cdl->IsCode(data.AbsoluteAddress) ? LineFlags::VerifiedCode : LineFlags::UnexecutedCode;
data.Flags |= (result.Address.Type != SnesMemoryType::PrgRom || _cdl->IsCode(data.AbsoluteAddress)) ? LineFlags::VerifiedCode : LineFlags::UnexecutedCode;
}
data.OpSize = disInfo.GetOpSize();

View file

@ -43,6 +43,8 @@ private:
vector<DisassemblyInfo> _necDspRomCache;
vector<DisassemblyInfo> _sa1InternalRamCache;
vector<DisassemblyInfo> _gsuWorkRamCache;
vector<DisassemblyInfo> _bsxPsRamCache;
vector<DisassemblyInfo> _bsxMemPackCache;
SimpleLock _disassemblyLock;
vector<DisassemblyResult> _disassembly;
@ -74,6 +76,11 @@ private:
uint8_t *_gsuWorkRam;
uint32_t _gsuWorkRamSize;
uint8_t* _bsxPsRam;
uint32_t _bsxPsRamSize;
uint8_t* _bsxMemPack;
uint32_t _bsxMemPackSize;
DisassemblerSource GetSource(SnesMemoryType type);
vector<DisassemblyResult>& GetDisassemblyList(CpuType type);
void SetDisassembleFlag(CpuType type);

View file

@ -35,6 +35,20 @@ private:
}
return false;
}
static bool AttemptLoadBsxFirmware(uint8_t** prgRom, uint32_t& prgSize)
{
VirtualFile firmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), "BS-X BIOS.sfc"));
if(firmware.IsValid() && firmware.GetSize() >= 0x8000) {
*prgRom = new uint8_t[firmware.GetSize()];
prgSize = (uint32_t)firmware.GetSize();
firmware.ReadFile(*prgRom, (uint32_t)firmware.GetSize());
return true;
}
return false;
}
public:
static bool LoadDspFirmware(Console *console, CoprocessorType coprocessorType, string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector<uint8_t> &programRom, vector<uint8_t> &dataRom, vector<uint8_t> &embeddedFirware, uint32_t programSize = 0x1800, uint32_t dataSize = 0x800)
{
@ -60,4 +74,24 @@ public:
MessageManager::DisplayMessage("Error", "Could not find firmware file for DSP: " + combinedFilename);
return false;
}
static bool LoadBsxFirmware(Console* console, uint8_t** prgRom, uint32_t& prgSize)
{
if(AttemptLoadBsxFirmware(prgRom, prgSize)) {
return true;
}
MissingFirmwareMessage msg;
msg.Filename = "BS-X BIOS.sfc";
msg.FirmwareType = CoprocessorType::Satellaview;
msg.Size = 1024*1024;
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
if(AttemptLoadBsxFirmware(prgRom, prgSize)) {
return true;
}
MessageManager::DisplayMessage("Error", "Could not find firmware file for BS-X");
return false;
}
};

View file

@ -50,6 +50,8 @@ int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType)
case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32);
case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32);
case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32);
case SnesMemoryType::BsxPsRam: return absoluteAddr | ((uint64_t)9 << 32);
case SnesMemoryType::BsxMemoryPack: return absoluteAddr | ((uint64_t)10 << 32);
default: return -1;
}
}
@ -65,6 +67,8 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key)
case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break;
case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break;
case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break;
case ((uint64_t)9 << 32): return SnesMemoryType::BsxPsRam; break;
case ((uint64_t)10 << 32): return SnesMemoryType::BsxMemoryPack; break;
}
throw std::runtime_error("Invalid label key");

View file

@ -7,6 +7,8 @@
#include "Sa1.h"
#include "Cx4.h"
#include "Gsu.h"
#include "BsxCart.h"
#include "BsxMemoryPack.h"
#include "Console.h"
#include "MemoryDumper.h"
#include "BaseCartridge.h"
@ -55,6 +57,8 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
case SnesMemoryType::Sa1InternalRam: memcpy(_cartridge->GetSa1()->DebugGetInternalRam(), buffer, length); break;
case SnesMemoryType::GsuWorkRam: memcpy(_cartridge->GetGsu()->DebugGetWorkRam(), buffer, length); break;
case SnesMemoryType::Cx4DataRam: memcpy(_cartridge->GetCx4()->DebugGetDataRam(), buffer, length); break;
case SnesMemoryType::BsxPsRam: memcpy(_cartridge->GetBsx()->DebugGetPsRam(), buffer, length); break;
case SnesMemoryType::BsxMemoryPack: memcpy(_cartridge->GetBsxMemoryPack()->DebugGetMemoryPack(), buffer, length); break;
}
}
@ -83,6 +87,8 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRamSize() : 0;;
case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0;;
case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4() ? _cartridge->GetCx4()->DebugGetDataRamSize() : 0;;
case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx() ? _cartridge->GetBsx()->DebugGetPsRamSize() : 0;;
case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack() ? _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize() : 0;;
}
}
@ -131,6 +137,8 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
case SnesMemoryType::Sa1InternalRam: memcpy(buffer, _cartridge->GetSa1()->DebugGetInternalRam(), _cartridge->GetSa1()->DebugGetInternalRamSize()); break;
case SnesMemoryType::GsuWorkRam: memcpy(buffer, _cartridge->GetGsu()->DebugGetWorkRam(), _cartridge->GetGsu()->DebugGetWorkRamSize()); break;
case SnesMemoryType::Cx4DataRam: memcpy(buffer, _cartridge->GetCx4()->DebugGetDataRam(), _cartridge->GetCx4()->DebugGetDataRamSize()); break;
case SnesMemoryType::BsxPsRam: memcpy(buffer, _cartridge->GetBsx()->DebugGetPsRam(), _cartridge->GetBsx()->DebugGetPsRamSize()); break;
case SnesMemoryType::BsxMemoryPack: memcpy(buffer, _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack(), _cartridge->GetBsxMemoryPack()->DebugGetMemoryPackSize()); break;
}
}
@ -187,6 +195,8 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
case SnesMemoryType::Sa1InternalRam: _cartridge->GetSa1()->DebugGetInternalRam()[address] = value; invalidateCache(); break;
case SnesMemoryType::GsuWorkRam: _cartridge->GetGsu()->DebugGetWorkRam()[address] = value; invalidateCache(); break;
case SnesMemoryType::Cx4DataRam: _cartridge->GetCx4()->DebugGetDataRam()[address] = value; break;
case SnesMemoryType::BsxPsRam: _cartridge->GetBsx()->DebugGetPsRam()[address] = value; break;
case SnesMemoryType::BsxMemoryPack: _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack()[address] = value; break;
}
}
@ -221,6 +231,8 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1()->DebugGetInternalRam()[address];
case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu()->DebugGetWorkRam()[address];
case SnesMemoryType::Cx4DataRam: return _cartridge->GetCx4()->DebugGetDataRam()[address];
case SnesMemoryType::BsxPsRam: return _cartridge->GetBsx()->DebugGetPsRam()[address];
case SnesMemoryType::BsxMemoryPack: return _cartridge->GetBsxMemoryPack()->DebugGetMemoryPack()[address];
}
}

View file

@ -257,7 +257,7 @@ void Spc7110::UpdateMappings()
MemoryMappings* mappings = _console->GetMemoryManager()->GetMemoryMappings();
vector<unique_ptr<IMemoryHandler>>& prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers();
uint32_t dataRomSize = (prgRomHandlers.size() - 0x100);
uint32_t dataRomSize = ((uint32_t)prgRomHandlers.size() - 0x100);
for(int i = 0; i < 3; i++) {
mappings->RegisterHandler(0xD0 + (i * 0x10), 0xDF + (i * 0x10), 0x0000, 0xFFFF, prgRomHandlers, 0, 0x100 + ((_dataRomBanks[i] * 0x100) % dataRomSize));
}

View file

@ -30,6 +30,8 @@ SOURCES_CXX := $(LIBRETRO_DIR)/libretro.cpp \
$(CORE_DIR)/BatteryManager.cpp \
$(CORE_DIR)/Breakpoint.cpp \
$(CORE_DIR)/BreakpointManager.cpp \
$(CORE_DIR)/BsxCart.cpp \
$(CORE_DIR)/BsxMemoryPack.cpp \
$(CORE_DIR)/CallstackManager.cpp \
$(CORE_DIR)/CheatManager.cpp \
$(CORE_DIR)/CodeDataLogger.cpp \

View file

@ -78,6 +78,7 @@ namespace Mesen.GUI.Config
CreateMimeType("x-mesen_s-swc", "swc", "SNES Rom", mimeTypes, cfg.AssociateRomFiles);
CreateMimeType("x-mesen_s-fig", "fig", "SNES Rom", mimeTypes, cfg.AssociateRomFiles);
CreateMimeType("x-mesen_s-spc", "spc", "SPC Sound File", mimeTypes, cfg.AssociateSpcFiles);
CreateMimeType("x-mesen_s-bs", "bs", "BS-X Memory Pack", mimeTypes, cfg.AssociateBsFiles);
CreateMimeType("x-mesen_s-mss", "mss", "Mesen-S Save State", mimeTypes, cfg.AssociateMssFiles);
CreateMimeType("x-mesen_s-msm", "msm", "Mesen-S Movie File", mimeTypes, cfg.AssociateMsmFiles);

View file

@ -25,6 +25,7 @@ namespace Mesen.GUI.Config
public bool AssociateRomFiles = false;
public bool AssociateSpcFiles = false;
public bool AssociateBsFiles = false;
public bool AssociateMsmFiles = false;
public bool AssociateMssFiles = false;
@ -138,6 +139,7 @@ namespace Mesen.GUI.Config
FileAssociationHelper.UpdateFileAssociation("msm", this.AssociateMsmFiles);
FileAssociationHelper.UpdateFileAssociation("mss", this.AssociateMssFiles);
FileAssociationHelper.UpdateFileAssociation("spc", this.AssociateSpcFiles);
FileAssociationHelper.UpdateFileAssociation("bs", this.AssociateBsFiles);
}
frmMain.Instance.TopMost = AlwaysOnTop;

View file

@ -123,6 +123,9 @@ namespace Mesen.GUI.Debugger
case SnesMemoryType.Sa1InternalRam: type = "IRAM"; break;
case SnesMemoryType.GsuWorkRam: type = "GWRAM"; break;
case SnesMemoryType.BsxPsRam: type = "PSRAM"; break;
case SnesMemoryType.BsxMemoryPack: type = "MPACK"; break;
case SnesMemoryType.Register: type = "REG"; break;
}

View file

@ -67,6 +67,16 @@ namespace Mesen.GUI.Debugger.Controls
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Cx4DataRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxPsRam) > 0) {
this.Items.Add("-");
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxPsRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxMemoryPack) > 0) {
this.Items.Add("-");
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxMemoryPack));
}
this.SelectedIndex = 0;
this.SetEnumValue(originalValue);
this._disableEvent = false;

View file

@ -79,6 +79,8 @@ namespace Mesen.GUI.Debugger.Labels
case SnesMemoryType.SpcRom: return address | ((ulong)6 << 32);
case SnesMemoryType.Sa1InternalRam: return address | ((ulong)7 << 32);
case SnesMemoryType.GsuWorkRam: return address | ((ulong)8 << 32);
case SnesMemoryType.BsxPsRam: return address | ((ulong)9 << 32);
case SnesMemoryType.BsxMemoryPack: return address | ((ulong)10 << 32);
}
throw new Exception("Invalid type");
}

View file

@ -134,6 +134,8 @@ namespace Mesen.GUI.Debugger.Controls
case SnesMemoryType.SpcRam: prefix = "RAM: $"; break;
case SnesMemoryType.SpcRom: prefix = "ROM: $"; break;
case SnesMemoryType.Sa1InternalRam: prefix = "IRAM: $"; break;
case SnesMemoryType.BsxPsRam: prefix = "PSRAM: $"; break;
case SnesMemoryType.BsxMemoryPack: prefix = "MPACK: $"; break;
default: throw new Exception("Unsupported type");
}
int relAddress = label.GetRelativeAddress().Address;

View file

@ -28,6 +28,7 @@
private void InitializeComponent()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.cboType = new Mesen.GUI.Debugger.Controls.ComboBoxWithSeparator();
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
this.nudLength = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblBytes = new System.Windows.Forms.Label();
@ -42,7 +43,6 @@
this.lblAddressSign = new System.Windows.Forms.Label();
this.txtAddress = new System.Windows.Forms.TextBox();
this.lblRange = new System.Windows.Forms.Label();
this.cboType = new Mesen.GUI.Debugger.Controls.ComboBoxWithSeparator();
this.tableLayoutPanel1.SuspendLayout();
this.flowLayoutPanel3.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
@ -52,6 +52,7 @@
//
this.baseConfigPanel.Location = new System.Drawing.Point(0, 242);
this.baseConfigPanel.Size = new System.Drawing.Size(377, 29);
this.baseConfigPanel.TabIndex = 4;
//
// tableLayoutPanel1
//
@ -81,6 +82,15 @@
this.tableLayoutPanel1.Size = new System.Drawing.Size(377, 242);
this.tableLayoutPanel1.TabIndex = 2;
//
// cboType
//
this.cboType.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.cboType.FormattingEnabled = true;
this.cboType.Location = new System.Drawing.Point(63, 3);
this.cboType.Name = "cboType";
this.cboType.Size = new System.Drawing.Size(157, 21);
this.cboType.TabIndex = 14;
//
// flowLayoutPanel3
//
this.flowLayoutPanel3.Controls.Add(this.nudLength);
@ -100,6 +110,7 @@
0,
0,
0});
this.nudLength.IsHex = false;
this.nudLength.Location = new System.Drawing.Point(3, 3);
this.nudLength.Maximum = new decimal(new int[] {
65536,
@ -243,15 +254,6 @@
this.lblRange.TabIndex = 10;
this.lblRange.Text = "(range)";
//
// cboType
//
this.cboType.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.cboType.FormattingEnabled = true;
this.cboType.Location = new System.Drawing.Point(63, 3);
this.cboType.Name = "cboType";
this.cboType.Size = new System.Drawing.Size(121, 21);
this.cboType.TabIndex = 14;
//
// frmEditLabel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -271,6 +273,7 @@
this.flowLayoutPanel2.ResumeLayout(false);
this.flowLayoutPanel2.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}

View file

@ -45,6 +45,12 @@ namespace Mesen.GUI.Debugger
if(DebugApi.GetMemorySize(SnesMemoryType.Sa1InternalRam) > 0) {
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Sa1InternalRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxPsRam) > 0) {
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxPsRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxMemoryPack) > 0) {
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxMemoryPack));
}
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Register));
} else if(cpuType == CpuType.Spc) {
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.SpcRam));

View file

@ -261,6 +261,14 @@ namespace Mesen.GUI.Debugger
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Sa1InternalRam));
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Sa1Memory));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxPsRam) > 0) {
cboMemoryType.Items.Add("-");
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxPsRam));
}
if(DebugApi.GetMemorySize(SnesMemoryType.BsxMemoryPack) > 0) {
cboMemoryType.Items.Add("-");
cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxMemoryPack));
}
cboMemoryType.SelectedIndex = 0;
cboMemoryType.EndUpdate();

View file

@ -969,6 +969,8 @@
<Value ID="Sa1InternalRam">SA-1 IRAM</Value>
<Value ID="GsuWorkRam">GSU Work RAM</Value>
<Value ID="Cx4DataRam">CX4 Data RAM</Value>
<Value ID="BsxPsRam">BS-X - PSRAM</Value>
<Value ID="BsxMemoryPack">BS-X - Memory Pack</Value>
<Value ID="Register">Register</Value>
</Enum>
<Enum ID="TileFormat">

View file

@ -71,6 +71,7 @@
this.chkMoviesOverride = new System.Windows.Forms.CheckBox();
this.grpFileAssociations = new System.Windows.Forms.GroupBox();
this.tlpFileFormat = new System.Windows.Forms.TableLayoutPanel();
this.chkBsFormat = new System.Windows.Forms.CheckBox();
this.chkSpcFormat = new System.Windows.Forms.CheckBox();
this.chkRomFormat = new System.Windows.Forms.CheckBox();
this.chkMssFormat = new System.Windows.Forms.CheckBox();
@ -452,7 +453,7 @@
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.grpPathOverrides.Controls.Add(this.tableLayoutPanel10);
this.grpPathOverrides.Location = new System.Drawing.Point(3, 177);
this.grpPathOverrides.Location = new System.Drawing.Point(3, 198);
this.grpPathOverrides.Name = "grpPathOverrides";
this.grpPathOverrides.Size = new System.Drawing.Size(528, 186);
this.grpPathOverrides.TabIndex = 15;
@ -677,7 +678,7 @@
this.grpFileAssociations.Controls.Add(this.tlpFileFormat);
this.grpFileAssociations.Location = new System.Drawing.Point(3, 3);
this.grpFileAssociations.Name = "grpFileAssociations";
this.grpFileAssociations.Size = new System.Drawing.Size(528, 65);
this.grpFileAssociations.Size = new System.Drawing.Size(528, 86);
this.grpFileAssociations.TabIndex = 12;
this.grpFileAssociations.TabStop = false;
this.grpFileAssociations.Text = "File Associations";
@ -687,6 +688,7 @@
this.tlpFileFormat.ColumnCount = 2;
this.tlpFileFormat.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFileFormat.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tlpFileFormat.Controls.Add(this.chkBsFormat, 0, 2);
this.tlpFileFormat.Controls.Add(this.chkSpcFormat, 0, 1);
this.tlpFileFormat.Controls.Add(this.chkRomFormat, 0, 0);
this.tlpFileFormat.Controls.Add(this.chkMssFormat, 1, 0);
@ -694,15 +696,24 @@
this.tlpFileFormat.Dock = System.Windows.Forms.DockStyle.Fill;
this.tlpFileFormat.Location = new System.Drawing.Point(3, 16);
this.tlpFileFormat.Name = "tlpFileFormat";
this.tlpFileFormat.RowCount = 3;
this.tlpFileFormat.RowCount = 4;
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tlpFileFormat.Size = new System.Drawing.Size(522, 46);
this.tlpFileFormat.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tlpFileFormat.Size = new System.Drawing.Size(522, 67);
this.tlpFileFormat.TabIndex = 0;
//
// chkBsFormat
//
this.chkBsFormat.AutoSize = true;
this.chkBsFormat.Location = new System.Drawing.Point(3, 49);
this.chkBsFormat.Name = "chkBsFormat";
this.chkBsFormat.Size = new System.Drawing.Size(147, 17);
this.chkBsFormat.TabIndex = 17;
this.chkBsFormat.Text = ".BS (BS-X memory packs)";
this.chkBsFormat.UseVisualStyleBackColor = true;
//
// chkSpcFormat
//
this.chkSpcFormat.AutoSize = true;
@ -751,7 +762,7 @@
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.grpDataStorageLocation.Controls.Add(this.tableLayoutPanel7);
this.grpDataStorageLocation.Location = new System.Drawing.Point(3, 74);
this.grpDataStorageLocation.Location = new System.Drawing.Point(3, 95);
this.grpDataStorageLocation.Name = "grpDataStorageLocation";
this.grpDataStorageLocation.Size = new System.Drawing.Size(528, 97);
this.grpDataStorageLocation.TabIndex = 14;
@ -955,6 +966,7 @@
0,
0,
0});
this.nudRewindBufferSize.IsHex = false;
this.nudRewindBufferSize.Location = new System.Drawing.Point(148, 0);
this.nudRewindBufferSize.Margin = new System.Windows.Forms.Padding(0);
this.nudRewindBufferSize.Maximum = new decimal(new int[] {
@ -1211,5 +1223,6 @@
private System.Windows.Forms.CheckBox chkPauseOnMovieEnd;
private System.Windows.Forms.CheckBox chkDisableGameSelectionScreen;
private System.Windows.Forms.CheckBox chkSpcFormat;
}
private System.Windows.Forms.CheckBox chkBsFormat;
}
}

View file

@ -43,6 +43,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding(nameof(PreferencesConfig.AssociateMsmFiles), chkMsmFormat);
AddBinding(nameof(PreferencesConfig.AssociateMssFiles), chkMssFormat);
AddBinding(nameof(PreferencesConfig.AssociateSpcFiles), chkSpcFormat);
AddBinding(nameof(PreferencesConfig.AssociateBsFiles), chkBsFormat);
AddBinding(nameof(PreferencesConfig.AlwaysOnTop), chkAlwaysOnTop);
AddBinding(nameof(PreferencesConfig.AutoHideMenu), chkAutoHideMenu);

View file

@ -203,6 +203,8 @@ namespace Mesen.GUI
Sa1InternalRam,
GsuWorkRam,
Cx4DataRam,
BsxPsRam,
BsxMemoryPack,
Register,
}

View file

@ -28,18 +28,24 @@ namespace Mesen.GUI.Utilities
}
}
private static string GetExpectedHash(CoprocessorType type)
private static List<string> GetExpectedHashes(CoprocessorType type)
{
switch(type) {
case CoprocessorType.CX4: return "AE8D4D1961B93421FF00B3CAA1D0F0CE7783E749772A3369C36B3DBF0D37EF18";
case CoprocessorType.DSP1: return "91E87D11E1C30D172556BED2211CCE2EFA94BA595F58C5D264809EF4D363A97B";
case CoprocessorType.DSP1B: return "D789CB3C36B05C0B23B6C6F23BE7AA37C6E78B6EE9CEAC8D2D2AA9D8C4D35FA9";
case CoprocessorType.DSP2: return "03EF4EF26C9F701346708CB5D07847B5203CF1B0818BF2930ACD34510FFDD717";
case CoprocessorType.DSP3: return "0971B08F396C32E61989D1067DDDF8E4B14649D548B2188F7C541B03D7C69E4E";
case CoprocessorType.DSP4: return "752D03B2D74441E430B7F713001FA241F8BBCFC1A0D890ED4143F174DBE031DA";
case CoprocessorType.ST010: return "FA9BCED838FEDEA11C6F6ACE33D1878024BDD0D02CC9485899D0BDD4015EC24C";
case CoprocessorType.ST011: return "8B2B3F3F3E6E29F4D21D8BC736B400BC988B7D2214EBEE15643F01C1FEE2F364";
case CoprocessorType.ST018: return "6DF209AB5D2524D1839C038BE400AE5EB20DAFC14A3771A3239CD9E8ACD53806";
case CoprocessorType.CX4: return new List<string>() { "AE8D4D1961B93421FF00B3CAA1D0F0CE7783E749772A3369C36B3DBF0D37EF18" };
case CoprocessorType.DSP1: return new List<string>() { "91E87D11E1C30D172556BED2211CCE2EFA94BA595F58C5D264809EF4D363A97B" };
case CoprocessorType.DSP1B: return new List<string>() { "D789CB3C36B05C0B23B6C6F23BE7AA37C6E78B6EE9CEAC8D2D2AA9D8C4D35FA9" };
case CoprocessorType.DSP2: return new List<string>() { "03EF4EF26C9F701346708CB5D07847B5203CF1B0818BF2930ACD34510FFDD717" };
case CoprocessorType.DSP3: return new List<string>() { "0971B08F396C32E61989D1067DDDF8E4B14649D548B2188F7C541B03D7C69E4E" };
case CoprocessorType.DSP4: return new List<string>() { "752D03B2D74441E430B7F713001FA241F8BBCFC1A0D890ED4143F174DBE031DA" };
case CoprocessorType.ST010: return new List<string>() { "FA9BCED838FEDEA11C6F6ACE33D1878024BDD0D02CC9485899D0BDD4015EC24C" };
case CoprocessorType.ST011: return new List<string>() { "8B2B3F3F3E6E29F4D21D8BC736B400BC988B7D2214EBEE15643F01C1FEE2F364" };
case CoprocessorType.ST018: return new List<string>() { "6DF209AB5D2524D1839C038BE400AE5EB20DAFC14A3771A3239CD9E8ACD53806" };
case CoprocessorType.Satellaview: return new List<string>() {
"27CFDB99F7E4252BF3740D420147B63C4C88616883BC5E7FE43F2F30BF8C8CBB", //Japan, no DRM
"A49827B45FF9AC9CF5B4658190E1428E59251BC82D8A63D8E9E0F71E439F008F", //English, no DRM
"3CE321496EDC5D77038DE2034EB3FB354D7724AFD0BC7FD0319F3EB5D57B984D", //Japan, original
"77D94D64D745014BF8B51280A4204056CDEB9D41EA30EAE80DBC006675BEBEF8", //English, DRM
};
}
throw new Exception("Unexpected coprocessor type");
}
@ -51,8 +57,9 @@ namespace Mesen.GUI.Utilities
using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterAll"));
if(ofd.ShowDialog(frmMain.Instance) == DialogResult.OK) {
if(GetFileHash(ofd.FileName) != GetExpectedHash(msg.FirmwareType)) {
if(MesenMsgBox.Show("FirmwareMismatch", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, msg.FirmwareType.ToString(), GetFileHash(ofd.FileName), GetExpectedHash(msg.FirmwareType)) != DialogResult.OK) {
List<string> expectedHashes = GetExpectedHashes(msg.FirmwareType);
if(!expectedHashes.Contains(GetFileHash(ofd.FileName))) {
if(MesenMsgBox.Show("FirmwareMismatch", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, msg.FirmwareType.ToString(), GetFileHash(ofd.FileName), expectedHashes[0]) != DialogResult.OK) {
//Files don't match and user cancelled the action
return;
}

View file

@ -137,6 +137,17 @@ string FolderUtilities::GetRecentGamesFolder()
return folder;
}
string FolderUtilities::GetExtension(string filename)
{
size_t position = filename.find_last_of('.');
if(position != string::npos) {
string ext = filename.substr(position, filename.size() - position);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
return ext;
}
return "";
}
#ifndef LIBRETRO
void FolderUtilities::CreateFolder(string folder)
{

View file

@ -34,6 +34,7 @@ public:
static vector<string> GetFilesInFolder(string rootFolder, std::unordered_set<string> extensions, bool recursive);
static string GetFilename(string filepath, bool includeExtension);
static string GetExtension(string filename);
static string GetFolderName(string filepath);
static void CreateFolder(string folder);