GB: Allow picking GB model (original vs color) and using a boot rom
+Adds boot rom/sprite ram in hex editor +Allow colorized GB games in GBC mode
This commit is contained in:
parent
8b2a6b5fa6
commit
faf4d62ef4
39 changed files with 437 additions and 163 deletions
|
@ -48,6 +48,22 @@ enum class CoprocessorType
|
|||
Gameboy
|
||||
};
|
||||
|
||||
enum class FirmwareType
|
||||
{
|
||||
CX4,
|
||||
DSP1,
|
||||
DSP1B,
|
||||
DSP2,
|
||||
DSP3,
|
||||
DSP4,
|
||||
ST010,
|
||||
ST011,
|
||||
ST018,
|
||||
Satellaview,
|
||||
Gameboy,
|
||||
GameboyColor
|
||||
};
|
||||
|
||||
struct RomInfo
|
||||
{
|
||||
SnesCartInformation Header;
|
||||
|
@ -69,4 +85,4 @@ namespace CartFlags
|
|||
ExHiRom = 16,
|
||||
CopierHeader = 32
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
return CpuType::Gameboy;
|
||||
|
||||
default:
|
||||
|
|
|
@ -533,6 +533,7 @@ AddressInfo Debugger::GetRelativeAddress(AddressInfo absAddress, CpuType cpuType
|
|||
case SnesMemoryType::GbWorkRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
return { _cart->GetGameboy()->GetRelativeAddress(absAddress), SnesMemoryType::GameboyMemory };
|
||||
|
||||
case SnesMemoryType::DspProgramRom:
|
||||
|
|
|
@ -77,6 +77,8 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
|
|||
_gbCartRamSize = _gameboy ? _gameboy->DebugGetMemorySize(SnesMemoryType::GbCartRam) : 0;
|
||||
_gbHighRam = _gameboy ? _gameboy->DebugGetMemory(SnesMemoryType::GbHighRam) : nullptr;
|
||||
_gbHighRamSize = _gameboy ? _gameboy->DebugGetMemorySize(SnesMemoryType::GbHighRam) : 0;
|
||||
_gbBootRom = _gameboy ? _gameboy->DebugGetMemory(SnesMemoryType::GbBootRom) : nullptr;
|
||||
_gbBootRomSize = _gameboy ? _gameboy->DebugGetMemorySize(SnesMemoryType::GbBootRom) : 0;
|
||||
|
||||
_prgCache = vector<DisassemblyInfo>(_prgRomSize);
|
||||
_sramCache = vector<DisassemblyInfo>(_sramSize);
|
||||
|
@ -93,6 +95,7 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
|
|||
_gbWorkRamCache = vector<DisassemblyInfo>(_gbWorkRamSize);
|
||||
_gbCartRamCache = vector<DisassemblyInfo>(_gbCartRamSize);
|
||||
_gbHighRamCache = vector<DisassemblyInfo>(_gbHighRamSize);
|
||||
_gbBootRomCache = vector<DisassemblyInfo>(_gbBootRomSize);
|
||||
|
||||
for(int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) {
|
||||
_needDisassemble[i] = true;
|
||||
|
@ -113,6 +116,7 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
|
|||
_sources[(int)SnesMemoryType::GbWorkRam] = { _gbWorkRam, &_gbWorkRamCache, _gbWorkRamSize };
|
||||
_sources[(int)SnesMemoryType::GbCartRam] = { _gbCartRam, &_gbCartRamCache, _gbCartRamSize };
|
||||
_sources[(int)SnesMemoryType::GbHighRam] = { _gbHighRam, &_gbHighRamCache, _gbHighRamSize };
|
||||
_sources[(int)SnesMemoryType::GbBootRom] = { _gbBootRom, &_gbBootRomCache, _gbBootRomSize };
|
||||
|
||||
if(_necDspProgramRomSize > 0) {
|
||||
//Build cache for the entire DSP chip (since it only contains instructions)
|
||||
|
|
|
@ -58,6 +58,7 @@ private:
|
|||
vector<DisassemblyInfo> _gbWorkRamCache;
|
||||
vector<DisassemblyInfo> _gbCartRamCache;
|
||||
vector<DisassemblyInfo> _gbHighRamCache;
|
||||
vector<DisassemblyInfo> _gbBootRomCache;
|
||||
|
||||
SimpleLock _disassemblyLock;
|
||||
vector<DisassemblyResult> _disassembly;
|
||||
|
@ -105,6 +106,8 @@ private:
|
|||
uint32_t _gbCartRamSize;
|
||||
uint8_t* _gbHighRam;
|
||||
uint32_t _gbHighRamSize;
|
||||
uint8_t* _gbBootRom;
|
||||
uint32_t _gbBootRomSize;
|
||||
|
||||
DisassemblerSource GetSource(SnesMemoryType type);
|
||||
vector<DisassemblyResult>& GetDisassemblyList(CpuType type);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
struct MissingFirmwareMessage
|
||||
{
|
||||
const char* Filename;
|
||||
CoprocessorType FirmwareType;
|
||||
FirmwareType Firmware;
|
||||
uint32_t Size;
|
||||
};
|
||||
|
||||
|
@ -49,8 +49,20 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool AttemptLoadFirmware(uint8_t** out, string filename, uint32_t size)
|
||||
{
|
||||
VirtualFile firmware(FolderUtilities::CombinePath(FolderUtilities::GetFirmwareFolder(), filename));
|
||||
if(firmware.IsValid() && firmware.GetSize() == size) {
|
||||
*out = new uint8_t[firmware.GetSize()];
|
||||
firmware.ReadFile(*out, (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)
|
||||
static bool LoadDspFirmware(Console *console, FirmwareType type, 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)
|
||||
{
|
||||
if(embeddedFirware.size() == programSize + dataSize) {
|
||||
programRom.insert(programRom.end(), embeddedFirware.begin(), embeddedFirware.begin() + programSize);
|
||||
|
@ -62,7 +74,7 @@ public:
|
|||
|
||||
MissingFirmwareMessage msg;
|
||||
msg.Filename = combinedFilename.c_str();
|
||||
msg.FirmwareType = coprocessorType;
|
||||
msg.Firmware = type;
|
||||
msg.Size = programSize + dataSize;
|
||||
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
|
||||
|
||||
|
@ -83,7 +95,7 @@ public:
|
|||
|
||||
MissingFirmwareMessage msg;
|
||||
msg.Filename = "BsxBios.sfc";
|
||||
msg.FirmwareType = CoprocessorType::Satellaview;
|
||||
msg.Firmware = FirmwareType::Satellaview;
|
||||
msg.Size = 1024*1024;
|
||||
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
|
||||
|
||||
|
@ -94,4 +106,26 @@ public:
|
|||
MessageManager::DisplayMessage("Error", "Could not find firmware file for BS-X");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LoadGbBootRom(Console* console, uint8_t** bootRom, FirmwareType type)
|
||||
{
|
||||
string filename = type == FirmwareType::Gameboy ? "dmg_boot.bin" : "cgb_boot.bin";
|
||||
uint32_t size = type == FirmwareType::Gameboy ? 256 : 2304;
|
||||
if(AttemptLoadFirmware(bootRom, filename, size)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MissingFirmwareMessage msg;
|
||||
msg.Filename = filename.c_str();
|
||||
msg.Firmware = type;
|
||||
msg.Size = size;
|
||||
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg);
|
||||
|
||||
if(AttemptLoadFirmware(bootRom, filename, size)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MessageManager::DisplayMessage("Error", "Could not find boot rom: " + filename);
|
||||
return false;
|
||||
}
|
||||
};
|
|
@ -14,6 +14,7 @@
|
|||
#include "GameboyHeader.h"
|
||||
#include "EmuSettings.h"
|
||||
#include "MessageManager.h"
|
||||
#include "FirmwareHelper.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "../Utilities/Serializer.h"
|
||||
|
||||
|
@ -50,7 +51,16 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile)
|
|||
gb->_cartRam = new uint8_t[gb->_cartRamSize];
|
||||
gb->_hasBattery = header.HasBattery();
|
||||
|
||||
gb->_cgbMode = (header.CgbFlag & 0x80) != 0;
|
||||
shared_ptr<EmuSettings> settings = console->GetSettings();
|
||||
EmulationConfig cfg = settings->GetEmulationConfig();
|
||||
switch(cfg.GbModel) {
|
||||
default:
|
||||
case GameboyModel::Auto: gb->_cgbMode = (header.CgbFlag & 0x80) != 0; break;
|
||||
|
||||
case GameboyModel::Gameboy: gb->_cgbMode = false; break;
|
||||
case GameboyModel::GameboyColor: gb->_cgbMode = true; break;
|
||||
}
|
||||
|
||||
gb->_workRamSize = gb->_cgbMode ? 0x8000 : 0x2000;
|
||||
gb->_videoRamSize = gb->_cgbMode ? 0x4000 : 0x2000;
|
||||
|
||||
|
@ -59,6 +69,15 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile)
|
|||
gb->_spriteRam = new uint8_t[Gameboy::SpriteRamSize];
|
||||
gb->_highRam = new uint8_t[Gameboy::HighRamSize];
|
||||
|
||||
gb->_useBootRom = cfg.GbUseBootRom;
|
||||
gb->_bootRomSize = 0;
|
||||
if(gb->_useBootRom) {
|
||||
gb->_useBootRom = FirmwareHelper::LoadGbBootRom(console, &gb->_bootRom, gb->_cgbMode ? FirmwareType::GameboyColor : FirmwareType::Gameboy);
|
||||
if(gb->_useBootRom) {
|
||||
gb->_bootRomSize = gb->_cgbMode ? 9 * 256 : 256;
|
||||
}
|
||||
}
|
||||
|
||||
return gb;
|
||||
}
|
||||
|
||||
|
@ -77,11 +96,13 @@ Gameboy::~Gameboy()
|
|||
|
||||
delete[] _highRam;
|
||||
delete[] _workRam;
|
||||
|
||||
delete[] _bootRom;
|
||||
}
|
||||
|
||||
void Gameboy::PowerOn()
|
||||
{
|
||||
EmuSettings* settings = _console->GetSettings().get();
|
||||
shared_ptr<EmuSettings> settings = _console->GetSettings();
|
||||
settings->InitializeRam(_cartRam, _cartRamSize);
|
||||
settings->InitializeRam(_workRam, _workRamSize);
|
||||
settings->InitializeRam(_spriteRam, Gameboy::SpriteRamSize);
|
||||
|
@ -148,9 +169,11 @@ uint32_t Gameboy::DebugGetMemorySize(SnesMemoryType type)
|
|||
switch(type) {
|
||||
case SnesMemoryType::GbPrgRom: return _prgRomSize;
|
||||
case SnesMemoryType::GbWorkRam: return _workRamSize;
|
||||
case SnesMemoryType::GbVideoRam: return _videoRamSize;
|
||||
case SnesMemoryType::GbCartRam: return _cartRamSize;
|
||||
case SnesMemoryType::GbHighRam: return Gameboy::HighRamSize;
|
||||
case SnesMemoryType::GbBootRom: return _bootRomSize;
|
||||
case SnesMemoryType::GbVideoRam: return _videoRamSize;
|
||||
case SnesMemoryType::GbSpriteRam: return Gameboy::SpriteRamSize;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -160,9 +183,11 @@ uint8_t* Gameboy::DebugGetMemory(SnesMemoryType type)
|
|||
switch(type) {
|
||||
case SnesMemoryType::GbPrgRom: return _prgRom;
|
||||
case SnesMemoryType::GbWorkRam: return _workRam;
|
||||
case SnesMemoryType::GbVideoRam: return _videoRam;
|
||||
case SnesMemoryType::GbCartRam: return _cartRam;
|
||||
case SnesMemoryType::GbHighRam: return _highRam;
|
||||
case SnesMemoryType::GbBootRom: return _bootRom;
|
||||
case SnesMemoryType::GbVideoRam: return _videoRam;
|
||||
case SnesMemoryType::GbSpriteRam: return _spriteRam;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +234,9 @@ AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr)
|
|||
} else if(ptr >= _cartRam && ptr < _cartRam + _cartRamSize) {
|
||||
addrInfo.Address = (int32_t)(ptr - _cartRam);
|
||||
addrInfo.Type = SnesMemoryType::GbCartRam;
|
||||
} else if(ptr >= _bootRom && ptr < _bootRom + _bootRomSize) {
|
||||
addrInfo.Address = (int32_t)(ptr - _bootRom);
|
||||
addrInfo.Type = SnesMemoryType::GbBootRom;
|
||||
}
|
||||
return addrInfo;
|
||||
}
|
||||
|
@ -234,6 +262,11 @@ bool Gameboy::IsCgb()
|
|||
return _cgbMode;
|
||||
}
|
||||
|
||||
bool Gameboy::UseBootRom()
|
||||
{
|
||||
return _useBootRom;
|
||||
}
|
||||
|
||||
uint64_t Gameboy::GetCycleCount()
|
||||
{
|
||||
return _cpu->GetCycleCount();
|
||||
|
|
|
@ -19,7 +19,7 @@ private:
|
|||
static constexpr int SpriteRamSize = 0xA0;
|
||||
static constexpr int HighRamSize = 0x7F;
|
||||
|
||||
Console* _console;
|
||||
Console* _console = nullptr;
|
||||
|
||||
unique_ptr<GbMemoryManager> _memoryManager;
|
||||
unique_ptr<GbCpu> _cpu;
|
||||
|
@ -29,23 +29,27 @@ private:
|
|||
unique_ptr<GbTimer> _timer;
|
||||
unique_ptr<GbDmaController> _dmaController;
|
||||
|
||||
bool _hasBattery;
|
||||
bool _cgbMode;
|
||||
bool _hasBattery = false;
|
||||
bool _cgbMode = false;
|
||||
bool _useBootRom = false;
|
||||
|
||||
uint8_t* _prgRom;
|
||||
uint32_t _prgRomSize;
|
||||
uint8_t* _prgRom = nullptr;
|
||||
uint32_t _prgRomSize = 0;
|
||||
|
||||
uint8_t* _cartRam;
|
||||
uint32_t _cartRamSize;
|
||||
uint8_t* _cartRam = nullptr;
|
||||
uint32_t _cartRamSize = 0;
|
||||
|
||||
uint8_t* _workRam;
|
||||
uint32_t _workRamSize;
|
||||
uint8_t* _workRam = nullptr;
|
||||
uint32_t _workRamSize = 0;
|
||||
|
||||
uint8_t* _videoRam;
|
||||
uint32_t _videoRamSize;
|
||||
uint8_t* _videoRam = nullptr;
|
||||
uint32_t _videoRamSize = 0;
|
||||
|
||||
uint8_t* _spriteRam;
|
||||
uint8_t* _highRam;
|
||||
uint8_t* _spriteRam = nullptr;
|
||||
uint8_t* _highRam = nullptr;
|
||||
|
||||
uint8_t* _bootRom = nullptr;
|
||||
uint32_t _bootRomSize = 0;
|
||||
|
||||
public:
|
||||
static Gameboy* Create(Console* console, VirtualFile& romFile);
|
||||
|
@ -70,6 +74,7 @@ public:
|
|||
int32_t GetRelativeAddress(AddressInfo& absAddress);
|
||||
|
||||
bool IsCgb();
|
||||
bool UseBootRom();
|
||||
uint64_t GetCycleCount();
|
||||
uint64_t GetApuCycleCount();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ GbApu::GbApu(Console* console, Gameboy* gameboy)
|
|||
_console = console;
|
||||
_soundMixer = console->GetSoundMixer().get();
|
||||
_gameboy = gameboy;
|
||||
_state = {};
|
||||
|
||||
_soundBuffer = new int16_t[GbApu::MaxSamples*2];
|
||||
memset(_soundBuffer, 0, GbApu::MaxSamples*2*sizeof(int16_t));
|
||||
|
|
|
@ -10,23 +10,24 @@ GbCpu::GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager)
|
|||
_console = console;
|
||||
_gameboy = gameboy;
|
||||
_memoryManager = memoryManager;
|
||||
|
||||
_state = {};
|
||||
|
||||
#ifdef USEBOOTROM
|
||||
_state.PC = 0;
|
||||
_state.SP = 0xFFFF;
|
||||
#else
|
||||
_state.PC = 0x100;
|
||||
_state.SP = 0xFFFE;
|
||||
_state.A = gameboy->IsCgb() ? 0x11 : 0x01;
|
||||
_state.B = 0x00;
|
||||
_state.C = 0x13;
|
||||
_state.D = 0x00;
|
||||
_state.E = 0xD8;
|
||||
_state.H = 0x01;
|
||||
_state.L = 0x4D;
|
||||
_state.Flags = 0xB0;
|
||||
#endif
|
||||
if(_gameboy->UseBootRom()) {
|
||||
_state.PC = 0;
|
||||
_state.SP = 0xFFFF;
|
||||
} else {
|
||||
_state.PC = 0x100;
|
||||
_state.SP = 0xFFFE;
|
||||
_state.A = _gameboy->IsCgb() ? 0x11 : 0x01;
|
||||
_state.B = 0x00;
|
||||
_state.C = 0x13;
|
||||
_state.D = 0x00;
|
||||
_state.E = 0xD8;
|
||||
_state.H = 0x01;
|
||||
_state.L = 0x4D;
|
||||
_state.Flags = 0xB0;
|
||||
}
|
||||
}
|
||||
|
||||
GbCpu::~GbCpu()
|
||||
|
|
|
@ -18,25 +18,8 @@
|
|||
|
||||
void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbPpu* ppu, GbApu* apu, GbTimer* timer, GbDmaController* dmaController)
|
||||
{
|
||||
_state = {};
|
||||
_state.CgbWorkRamBank = 1;
|
||||
|
||||
_prgRom = gameboy->DebugGetMemory(SnesMemoryType::GbPrgRom);
|
||||
_prgRomSize = gameboy->DebugGetMemorySize(SnesMemoryType::GbPrgRom);
|
||||
_cartRam = gameboy->DebugGetMemory(SnesMemoryType::GbCartRam);
|
||||
_cartRamSize = gameboy->DebugGetMemorySize(SnesMemoryType::GbCartRam);
|
||||
_workRam = gameboy->DebugGetMemory(SnesMemoryType::GbWorkRam);
|
||||
_workRamSize = gameboy->DebugGetMemorySize(SnesMemoryType::GbWorkRam);
|
||||
_highRam = gameboy->DebugGetMemory(SnesMemoryType::GbHighRam);
|
||||
|
||||
#ifdef USEBOOTROM
|
||||
VirtualFile bootRom("Firmware\\boot.bin");
|
||||
bootRom.ReadFile(_bootRom, 256);
|
||||
_state.DisableBootRom = false;
|
||||
#else
|
||||
_state.DisableBootRom = true;
|
||||
#endif
|
||||
|
||||
_apu = apu;
|
||||
_ppu = ppu;
|
||||
_gameboy = gameboy;
|
||||
|
@ -47,6 +30,10 @@ void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbP
|
|||
_controlManager = console->GetControlManager().get();
|
||||
_settings = console->GetSettings().get();
|
||||
|
||||
_state = {};
|
||||
_state.CgbWorkRamBank = 1;
|
||||
_state.DisableBootRom = !_gameboy->UseBootRom();
|
||||
|
||||
MapRegisters(0x8000, 0x9FFF, RegisterAccess::ReadWrite);
|
||||
MapRegisters(0xFE00, 0xFFFF, RegisterAccess::ReadWrite);
|
||||
|
||||
|
@ -73,7 +60,10 @@ void GbMemoryManager::RefreshMappings()
|
|||
_cart->RefreshMappings();
|
||||
|
||||
if(!_state.DisableBootRom) {
|
||||
_reads[0] = _bootRom;
|
||||
Map(0x0000, 0x00FF, GbMemoryType::BootRom, 0, true);
|
||||
if(_gameboy->IsCgb()) {
|
||||
Map(0x0200, 0x08FF, GbMemoryType::BootRom, 0x200, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +210,7 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr)
|
|||
return _dmaController->Read();
|
||||
} else if(addr >= 0xFF80) {
|
||||
return _highRam[addr & 0x7F]; //80-FE
|
||||
} else if(addr >= 0xFF4D) {
|
||||
} else if(addr >= 0xFF4C) {
|
||||
if(_gameboy->IsCgb()) {
|
||||
switch(addr) {
|
||||
//FF4D - KEY1 - CGB Mode Only - Prepare Speed Switch
|
||||
|
@ -238,9 +228,9 @@ uint8_t GbMemoryManager::ReadRegister(uint16_t addr)
|
|||
}
|
||||
}
|
||||
LogDebug("[Debug] GB - Missing read handler: $" + HexUtilities::ToHex(addr));
|
||||
return 0xFF; //4D-7F, open bus
|
||||
return 0xFF; //4C-7F, open bus
|
||||
} else if(addr >= 0xFF40) {
|
||||
return _ppu->Read(addr); //40-4C
|
||||
return _ppu->Read(addr); //40-4B
|
||||
} else if(addr >= 0xFF10) {
|
||||
return _apu->Read(addr); //10-3F
|
||||
} else {
|
||||
|
@ -277,8 +267,8 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
|||
_dmaController->Write(value);
|
||||
} else if(addr >= 0xFF80) {
|
||||
_highRam[addr & 0x7F] = value; //80-FE
|
||||
} else if(addr >= 0xFF4D) {
|
||||
//4D-7F
|
||||
} else if(addr >= 0xFF4C) {
|
||||
//4C-7F
|
||||
if(addr == 0xFF50) {
|
||||
if(value & 0x01) {
|
||||
_state.DisableBootRom = true;
|
||||
|
@ -295,6 +285,12 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
|||
_dmaController->WriteCgb(addr, value);
|
||||
break;
|
||||
|
||||
case 0xFF4C: //CGB - "LCDMODE", set by boot rom to turn off CGB features for the LCD for DMG games
|
||||
if(!_state.DisableBootRom) {
|
||||
_ppu->WriteCgbRegister(addr, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF4F: //CGB - VRAM banking
|
||||
case 0xFF68: case 0xFF69: case 0xFF6A: case 0xFF6B: //CGB - Palette
|
||||
_ppu->WriteCgbRegister(addr, value);
|
||||
|
@ -312,7 +308,7 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value)
|
|||
}
|
||||
}
|
||||
} else if(addr >= 0xFF40) {
|
||||
_ppu->Write(addr, value); //40-4C
|
||||
_ppu->Write(addr, value); //40-4B
|
||||
} else if(addr >= 0xFF10) {
|
||||
_apu->Write(addr, value); //10-3F
|
||||
} else {
|
||||
|
|
|
@ -28,13 +28,6 @@ private:
|
|||
GbTimer* _timer;
|
||||
GbDmaController* _dmaController;
|
||||
|
||||
uint8_t _bootRom[256];
|
||||
uint8_t* _prgRom = nullptr;
|
||||
uint32_t _prgRomSize = 0;
|
||||
uint8_t* _workRam = nullptr;
|
||||
uint32_t _workRamSize = 0;
|
||||
uint8_t* _cartRam = nullptr;
|
||||
uint32_t _cartRamSize = 0;
|
||||
uint8_t* _highRam = nullptr;
|
||||
|
||||
uint8_t* _reads[0x100] = {};
|
||||
|
|
|
@ -22,10 +22,6 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana
|
|||
_memoryManager = memoryManager;
|
||||
_vram = vram;
|
||||
_oam = oam;
|
||||
|
||||
_state = {};
|
||||
_state.Mode = PpuMode::HBlank;
|
||||
_lastFrameTime = 0;
|
||||
|
||||
_outputBuffers[0] = new uint16_t[256 * 240];
|
||||
_outputBuffers[1] = new uint16_t[256 * 240];
|
||||
|
@ -39,17 +35,31 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana
|
|||
memset(_eventViewerBuffers[1], 0, 456 * 154 * sizeof(uint16_t));
|
||||
_currentEventViewerBuffer = _eventViewerBuffers[0];
|
||||
|
||||
#ifndef USEBOOTROM
|
||||
Write(0xFF40, 0x91);
|
||||
Write(0xFF42, 0x00);
|
||||
Write(0xFF43, 0x00);
|
||||
Write(0xFF45, 0x00);
|
||||
Write(0xFF47, 0xFC);
|
||||
Write(0xFF48, 0xFF);
|
||||
Write(0xFF49, 0xFF);
|
||||
Write(0xFF4A, 0);
|
||||
Write(0xFF4B, 0);
|
||||
#endif
|
||||
_state = {};
|
||||
_state.Mode = PpuMode::HBlank;
|
||||
_state.CgbEnabled = _gameboy->IsCgb();
|
||||
_lastFrameTime = 0;
|
||||
|
||||
if(!_gameboy->IsCgb()) {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
//Init default palette for use with DMG
|
||||
_state.CgbBgPalettes[i] = bwRgbPalette[i];
|
||||
_state.CgbObjPalettes[i] = bwRgbPalette[i];
|
||||
_state.CgbObjPalettes[i+4] = bwRgbPalette[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(!_gameboy->UseBootRom()) {
|
||||
Write(0xFF40, 0x91);
|
||||
Write(0xFF42, 0x00);
|
||||
Write(0xFF43, 0x00);
|
||||
Write(0xFF45, 0x00);
|
||||
Write(0xFF47, 0xFC);
|
||||
Write(0xFF48, 0xFF);
|
||||
Write(0xFF49, 0xFF);
|
||||
Write(0xFF4A, 0);
|
||||
Write(0xFF4B, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GbPpu::~GbPpu()
|
||||
|
@ -213,7 +223,7 @@ void GbPpu::RunDrawCycle()
|
|||
}
|
||||
|
||||
uint16_t rgbColor;
|
||||
if(_gameboy->IsCgb()) {
|
||||
if(_state.CgbEnabled) {
|
||||
if(isSprite) {
|
||||
rgbColor = _state.CgbObjPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)];
|
||||
} else {
|
||||
|
@ -221,9 +231,10 @@ void GbPpu::RunDrawCycle()
|
|||
}
|
||||
} else {
|
||||
if(isSprite) {
|
||||
rgbColor = bwRgbPalette[(((entry.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (entry.Color * 2)) & 0x03];
|
||||
uint8_t colorIndex = (((entry.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (entry.Color * 2)) & 0x03;
|
||||
rgbColor = _state.CgbObjPalettes[((entry.Attributes & 0x10) ? 4 : 0) | colorIndex];
|
||||
} else {
|
||||
rgbColor = bwRgbPalette[(_state.BgPalette >> (entry.Color * 2)) & 0x03];
|
||||
rgbColor = _state.CgbBgPalettes[(_state.BgPalette >> (entry.Color * 2)) & 0x03];
|
||||
}
|
||||
}
|
||||
_currentBuffer[outOffset] = rgbColor;
|
||||
|
@ -282,7 +293,7 @@ void GbPpu::ClockSpriteFetcher()
|
|||
uint8_t sprTile = _oam[_fetchSprite + 2];
|
||||
uint8_t sprAttr = _oam[_fetchSprite + 3];
|
||||
bool vMirror = (sprAttr & 0x40) != 0;
|
||||
uint16_t tileBank = _gameboy->IsCgb() ? ((sprAttr & 0x08) ? 0x2000 : 0x0000) : 0;
|
||||
uint16_t tileBank = _state.CgbEnabled ? ((sprAttr & 0x08) ? 0x2000 : 0x0000) : 0;
|
||||
|
||||
uint8_t sprOffsetY = vMirror ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) : (_state.Scanline - sprY);
|
||||
if(_state.LargeSprites) {
|
||||
|
@ -308,7 +319,7 @@ void GbPpu::ClockSpriteFetcher()
|
|||
|
||||
void GbPpu::FindNextSprite()
|
||||
{
|
||||
if(_prevSprite < _spriteCount && _fetchSprite < 0 && (_state.SpritesEnabled || _gameboy->IsCgb())) {
|
||||
if(_prevSprite < _spriteCount && _fetchSprite < 0 && (_state.SpritesEnabled || _state.CgbEnabled)) {
|
||||
for(int i = _prevSprite; i < _spriteCount; i++) {
|
||||
if((int)_spriteX[i] - 8 == _drawnPixels) {
|
||||
_fetchSprite = _spriteIndexes[i];
|
||||
|
@ -349,7 +360,7 @@ void GbPpu::ClockTileFetcher()
|
|||
uint16_t tileAddr = tilemapAddr + _fetchColumn + row * 32;
|
||||
uint8_t tileIndex = _vram[tileAddr];
|
||||
|
||||
uint8_t attributes = _gameboy->IsCgb() ? _vram[tileAddr | 0x2000] : 0;
|
||||
uint8_t attributes = _state.CgbEnabled ? _vram[tileAddr | 0x2000] : 0;
|
||||
bool vMirror = (attributes & 0x40) != 0;
|
||||
uint16_t tileBank = (attributes & 0x08) ? 0x2000 : 0x0000;
|
||||
|
||||
|
@ -648,12 +659,13 @@ uint8_t GbPpu::ReadCgbRegister(uint16_t addr)
|
|||
case 0xFF6B: return (_state.CgbObjPalettes[_state.CgbObjPalPosition >> 1] >> ((_state.CgbObjPalPosition & 0x01) ? 8 : 0) & 0xFF);
|
||||
}
|
||||
LogDebug("[Debug] GBC - Missing read handler: $" + HexUtilities::ToHex(addr));
|
||||
return 0;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void GbPpu::WriteCgbRegister(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0xFF4C: _state.CgbEnabled = (value & 0x0C) == 0; break;
|
||||
case 0xFF4F: _state.CgbVramBank = value & 0x01; break;
|
||||
|
||||
case 0xFF68:
|
||||
|
@ -708,7 +720,7 @@ void GbPpu::Serialize(Serializer& s)
|
|||
_state.WindowEnabled, _state.BgTileSelect, _state.BgTilemapSelect, _state.LargeSprites, _state.SpritesEnabled, _state.BgEnabled,
|
||||
_state.Status, _state.FrameCount, _lastFrameTime, _state.LyCoincidenceFlag,
|
||||
_state.CgbBgPalAutoInc, _state.CgbBgPalPosition,
|
||||
_state.CgbObjPalAutoInc, _state.CgbObjPalPosition, _state.CgbVramBank
|
||||
_state.CgbObjPalAutoInc, _state.CgbObjPalPosition, _state.CgbVramBank, _state.CgbEnabled
|
||||
);
|
||||
|
||||
s.StreamArray(_state.CgbBgPalettes, 4 * 8);
|
||||
|
|
|
@ -64,6 +64,8 @@ private:
|
|||
public:
|
||||
virtual ~GbPpu();
|
||||
|
||||
void Reset(bool useBootRom);
|
||||
|
||||
void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, uint8_t* vram, uint8_t* oam);
|
||||
|
||||
GbPpuState GetState();
|
||||
|
|
|
@ -9,9 +9,12 @@ GbTimer::GbTimer(GbMemoryManager* memoryManager, GbApu* apu)
|
|||
_apu = apu;
|
||||
_memoryManager = memoryManager;
|
||||
|
||||
_state = {};
|
||||
_state.TimerDivider = 1024;
|
||||
|
||||
//Passes boot_div-dmgABCmgb
|
||||
//But that test depends on LCD power on timings, so may be wrong.
|
||||
_divider = 0x06;
|
||||
_state.Divider = 0x06;
|
||||
}
|
||||
|
||||
GbTimer::~GbTimer()
|
||||
|
@ -20,45 +23,45 @@ GbTimer::~GbTimer()
|
|||
|
||||
void GbTimer::Exec()
|
||||
{
|
||||
_reloaded = false;
|
||||
if(_needReload) {
|
||||
_state.Reloaded = false;
|
||||
if(_state.NeedReload) {
|
||||
ReloadCounter();
|
||||
}
|
||||
SetDivider(_divider + 4);
|
||||
SetDivider(_state.Divider + 4);
|
||||
}
|
||||
|
||||
void GbTimer::ReloadCounter()
|
||||
{
|
||||
_counter = _modulo;
|
||||
_state.Counter = _state.Modulo;
|
||||
_memoryManager->RequestIrq(GbIrqSource::Timer);
|
||||
_needReload = false;
|
||||
_reloaded = true;
|
||||
_state.NeedReload = false;
|
||||
_state.Reloaded = true;
|
||||
}
|
||||
|
||||
void GbTimer::SetDivider(uint16_t newValue)
|
||||
{
|
||||
if(_timerEnabled && !(newValue & _timerDivider) && (_divider & _timerDivider)) {
|
||||
_counter++;
|
||||
if(_counter == 0) {
|
||||
_needReload = true;
|
||||
if(_state.TimerEnabled && !(newValue & _state.TimerDivider) && (_state.Divider & _state.TimerDivider)) {
|
||||
_state.Counter++;
|
||||
if(_state.Counter == 0) {
|
||||
_state.NeedReload = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t frameSeqBit = _memoryManager->IsHighSpeed() ? 0x2000 : 0x1000;
|
||||
if(!(newValue & frameSeqBit) && (_divider & frameSeqBit)) {
|
||||
if(!(newValue & frameSeqBit) && (_state.Divider & frameSeqBit)) {
|
||||
_apu->ClockFrameSequencer();
|
||||
}
|
||||
|
||||
_divider = newValue;
|
||||
_state.Divider = newValue;
|
||||
}
|
||||
|
||||
uint8_t GbTimer::Read(uint16_t addr)
|
||||
{
|
||||
switch(addr) {
|
||||
case 0xFF04: return _divider >> 8;
|
||||
case 0xFF05: return _counter; //FF05 - TIMA - Timer counter (R/W)
|
||||
case 0xFF06: return _modulo; //FF06 - TMA - Timer Modulo (R/W)
|
||||
case 0xFF07: return _control | 0xF8; //FF07 - TAC - Timer Control (R/W)
|
||||
case 0xFF04: return _state.Divider >> 8;
|
||||
case 0xFF05: return _state.Counter; //FF05 - TIMA - Timer counter (R/W)
|
||||
case 0xFF06: return _state.Modulo; //FF06 - TMA - Timer Modulo (R/W)
|
||||
case 0xFF07: return _state.Control | 0xF8; //FF07 - TAC - Timer Control (R/W)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -73,29 +76,29 @@ void GbTimer::Write(uint16_t addr, uint8_t value)
|
|||
|
||||
case 0xFF05:
|
||||
//FF05 - TIMA - Timer counter (R/W)
|
||||
if(_needReload) {
|
||||
if(_state.NeedReload) {
|
||||
//Writing to TIMA when a reload is pending will cancel the reload and IRQ request
|
||||
_needReload = false;
|
||||
_state.NeedReload = false;
|
||||
}
|
||||
|
||||
if(!_reloaded) {
|
||||
if(!_state.Reloaded) {
|
||||
//Writes to TIMA on the cycle TIMA was reloaded with TMA are ignored
|
||||
_counter = value;
|
||||
_state.Counter = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF06:
|
||||
//FF06 - TMA - Timer Modulo (R/W)
|
||||
_modulo = value;
|
||||
if(_reloaded) {
|
||||
_state.Modulo = value;
|
||||
if(_state.Reloaded) {
|
||||
//Writing to TMA on the same cycle it was reloaded into TIMA will also update TIMA
|
||||
_counter = value;
|
||||
_state.Counter = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF07: {
|
||||
//FF07 - TAC - Timer Control (R/W)
|
||||
_control = value;
|
||||
_state.Control = value;
|
||||
bool enabled = (value & 0x04) != 0;
|
||||
uint16_t newDivider = 0;
|
||||
switch(value & 0x03) {
|
||||
|
@ -105,25 +108,25 @@ void GbTimer::Write(uint16_t addr, uint8_t value)
|
|||
case 3: newDivider = 1 << 7; break;
|
||||
}
|
||||
|
||||
if(_timerEnabled) {
|
||||
if(_state.TimerEnabled) {
|
||||
//When changing the value of TAC, the TIMA register can get incremented due to a glitch
|
||||
bool incrementCounter;
|
||||
if(enabled) {
|
||||
incrementCounter = (_divider & _timerDivider) != 0 && (_divider & newDivider) == 0;
|
||||
incrementCounter = (_state.Divider & _state.TimerDivider) != 0 && (_state.Divider & newDivider) == 0;
|
||||
} else {
|
||||
incrementCounter = (_divider & _timerDivider) != 0;
|
||||
incrementCounter = (_state.Divider & _state.TimerDivider) != 0;
|
||||
}
|
||||
|
||||
if(incrementCounter) {
|
||||
_counter++;
|
||||
if(_counter == 0) {
|
||||
_state.Counter++;
|
||||
if(_state.Counter == 0) {
|
||||
ReloadCounter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_timerEnabled = enabled;
|
||||
_timerDivider = newDivider;
|
||||
_state.TimerEnabled = enabled;
|
||||
_state.TimerDivider = newDivider;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -131,5 +134,5 @@ void GbTimer::Write(uint16_t addr, uint8_t value)
|
|||
|
||||
void GbTimer::Serialize(Serializer& s)
|
||||
{
|
||||
s.Stream(_divider, _counter, _modulo, _control, _timerEnabled, _timerDivider, _needReload, _reloaded);
|
||||
s.Stream(_state.Divider, _state.Counter, _state.Modulo, _state.Control, _state.TimerEnabled, _state.TimerDivider, _state.NeedReload, _state.Reloaded);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "../Utilities/ISerializable.h"
|
||||
#include "../Utilities/Serializer.h"
|
||||
#include "GbTypes.h"
|
||||
|
||||
class GbMemoryManager;
|
||||
class GbApu;
|
||||
|
@ -9,19 +10,9 @@ class GbApu;
|
|||
class GbTimer : public ISerializable
|
||||
{
|
||||
private:
|
||||
GbMemoryManager* _memoryManager;
|
||||
GbApu* _apu;
|
||||
|
||||
uint16_t _divider = 0;
|
||||
|
||||
bool _needReload = false; //Set after TIMA (_counter) overflowed, next cycle will reload TMA into TIMA
|
||||
bool _reloaded = false; //Set during the cycle on which TIMA is reloaded (affects TMA/TIMA writes)
|
||||
uint8_t _counter = 0;
|
||||
uint8_t _modulo = 0;
|
||||
|
||||
uint8_t _control = 0;
|
||||
bool _timerEnabled = false;
|
||||
uint16_t _timerDivider = 1024;
|
||||
GbMemoryManager* _memoryManager = nullptr;
|
||||
GbApu* _apu = nullptr;
|
||||
GbTimerState _state = {};
|
||||
|
||||
void SetDivider(uint16_t value);
|
||||
void ReloadCounter();
|
||||
|
@ -30,6 +21,8 @@ public:
|
|||
GbTimer(GbMemoryManager* memoryManager, GbApu* apu);
|
||||
virtual ~GbTimer();
|
||||
|
||||
void Reset();
|
||||
|
||||
void Exec();
|
||||
|
||||
uint8_t Read(uint16_t addr);
|
||||
|
|
|
@ -179,6 +179,7 @@ struct GbPpuState
|
|||
uint8_t Status;
|
||||
uint32_t FrameCount;
|
||||
|
||||
bool CgbEnabled;
|
||||
uint8_t CgbVramBank;
|
||||
|
||||
uint8_t CgbBgPalPosition;
|
||||
|
@ -204,6 +205,20 @@ struct GbDmaControllerState
|
|||
bool CgbHdmaMode;
|
||||
};
|
||||
|
||||
struct GbTimerState
|
||||
{
|
||||
uint16_t Divider = 0;
|
||||
|
||||
bool NeedReload = false; //Set after TIMA (_counter) overflowed, next cycle will reload TMA into TIMA
|
||||
bool Reloaded = false; //Set during the cycle on which TIMA is reloaded (affects TMA/TIMA writes)
|
||||
uint8_t Counter = 0;
|
||||
uint8_t Modulo = 0;
|
||||
|
||||
uint8_t Control = 0;
|
||||
bool TimerEnabled = false;
|
||||
uint16_t TimerDivider = 1024;
|
||||
};
|
||||
|
||||
struct GbSquareState
|
||||
{
|
||||
uint16_t SweepPeriod;
|
||||
|
@ -320,6 +335,7 @@ enum class GbMemoryType
|
|||
PrgRom = (int)SnesMemoryType::GbPrgRom,
|
||||
WorkRam = (int)SnesMemoryType::GbWorkRam,
|
||||
CartRam = (int)SnesMemoryType::GbCartRam,
|
||||
BootRom = (int)SnesMemoryType::GbBootRom,
|
||||
};
|
||||
|
||||
struct GbMemoryManagerState
|
||||
|
|
|
@ -60,6 +60,7 @@ int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType)
|
|||
case SnesMemoryType::GbWorkRam: return absoluteAddr | ((uint64_t)13 << 32);
|
||||
case SnesMemoryType::GbCartRam: return absoluteAddr | ((uint64_t)14 << 32);
|
||||
case SnesMemoryType::GbHighRam: return absoluteAddr | ((uint64_t)15 << 32);
|
||||
case SnesMemoryType::GbBootRom: return absoluteAddr | ((uint64_t)16 << 32);
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +83,7 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key)
|
|||
case ((uint64_t)13 << 32): return SnesMemoryType::GbWorkRam; break;
|
||||
case ((uint64_t)14 << 32): return SnesMemoryType::GbCartRam; break;
|
||||
case ((uint64_t)15 << 32): return SnesMemoryType::GbHighRam; break;
|
||||
case ((uint64_t)16 << 32): return SnesMemoryType::GbBootRom; break;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid label key");
|
||||
|
|
|
@ -158,6 +158,7 @@ int LuaApi::GetLibrary(lua_State *lua)
|
|||
lua_pushintvalue(gbCartRam, SnesMemoryType::GbCartRam);
|
||||
lua_pushintvalue(gbVideoRam, SnesMemoryType::GbVideoRam);
|
||||
lua_pushintvalue(gbHighRam, SnesMemoryType::GbHighRam);
|
||||
lua_pushintvalue(gbBootRom, SnesMemoryType::GbBootRom);
|
||||
lua_settable(lua, -3);
|
||||
|
||||
lua_pushliteral(lua, "counterOpType");
|
||||
|
|
|
@ -69,6 +69,8 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t
|
|||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
case SnesMemoryType::GbSpriteRam:
|
||||
if(_cartridge->GetGameboy()) {
|
||||
memcpy(_cartridge->GetGameboy()->DebugGetMemory(type), buffer, length);
|
||||
}
|
||||
|
@ -112,6 +114,8 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type)
|
|||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
case SnesMemoryType::GbSpriteRam:
|
||||
return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemorySize(type) : 0;
|
||||
}
|
||||
}
|
||||
|
@ -191,6 +195,8 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer)
|
|||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
case SnesMemoryType::GbSpriteRam:
|
||||
if(_cartridge->GetGameboy()) {
|
||||
memcpy(buffer, _cartridge->GetGameboy()->DebugGetMemory(type), _cartridge->GetGameboy()->DebugGetMemorySize(type));
|
||||
}
|
||||
|
@ -261,6 +267,8 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u
|
|||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
case SnesMemoryType::GbSpriteRam:
|
||||
if(_cartridge->GetGameboy()) {
|
||||
_cartridge->GetGameboy()->DebugGetMemory(memoryType)[address] = value;
|
||||
}
|
||||
|
@ -309,6 +317,8 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address
|
|||
case SnesMemoryType::GbVideoRam:
|
||||
case SnesMemoryType::GbCartRam:
|
||||
case SnesMemoryType::GbHighRam:
|
||||
case SnesMemoryType::GbBootRom:
|
||||
case SnesMemoryType::GbSpriteRam:
|
||||
return _cartridge->GetGameboy() ? _cartridge->GetGameboy()->DebugGetMemory(memoryType)[address] : 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,13 +92,13 @@ NecDsp* NecDsp::InitCoprocessor(CoprocessorType type, Console *console, vector<u
|
|||
vector<uint8_t> programRom;
|
||||
vector<uint8_t> dataRom;
|
||||
switch(type) {
|
||||
case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break;
|
||||
case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, type, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break;
|
||||
case CoprocessorType::DSP1: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1, "dsp1.rom", "dsp1.program.rom", "dsp1.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP1B: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP1B, "dsp1b.rom", "dsp1b.program.rom", "dsp1b.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP2: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP2, "dsp2.rom", "dsp2.program.rom", "dsp2.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP3: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP3, "dsp3.rom", "dsp3.program.rom", "dsp3.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::DSP4: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::DSP4, "dsp4.rom", "dsp4.program.rom", "dsp4.data.rom", programRom, dataRom, embeddedFirware); break;
|
||||
case CoprocessorType::ST010: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST010, "st010.rom", "st010.program.rom", "st010.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break;
|
||||
case CoprocessorType::ST011: firmwareLoaded = FirmwareHelper::LoadDspFirmware(console, FirmwareType::ST011, "st011.rom", "st011.program.rom", "st011.data.rom", programRom, dataRom, embeddedFirware, 0xC000, 0x1000); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
|
|
@ -270,6 +270,13 @@ enum class ConsoleRegion
|
|||
Pal = 2
|
||||
};
|
||||
|
||||
enum class GameboyModel
|
||||
{
|
||||
Auto = 0,
|
||||
Gameboy = 1,
|
||||
GameboyColor = 2,
|
||||
};
|
||||
|
||||
struct EmulationConfig
|
||||
{
|
||||
uint32_t EmulationSpeed = 100;
|
||||
|
@ -290,6 +297,9 @@ struct EmulationConfig
|
|||
RamState RamPowerOnState = RamState::Random;
|
||||
|
||||
int64_t BsxCustomDate = -1;
|
||||
|
||||
bool GbUseBootRom = false;
|
||||
GameboyModel GbModel = GameboyModel::Auto;
|
||||
};
|
||||
|
||||
struct PreferencesConfig
|
||||
|
|
|
@ -28,7 +28,9 @@ enum class SnesMemoryType
|
|||
GbPrgRom,
|
||||
GbWorkRam,
|
||||
GbCartRam,
|
||||
GbVideoRam,
|
||||
GbHighRam,
|
||||
GbBootRom,
|
||||
GbVideoRam,
|
||||
GbSpriteRam,
|
||||
Register
|
||||
};
|
|
@ -29,6 +29,9 @@ namespace Mesen.GUI.Config
|
|||
|
||||
public long BsxCustomDate = -1;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool GbUseBootRom = false;
|
||||
public GameboyModel GbModel = GameboyModel.Auto;
|
||||
|
||||
public void ApplyConfig()
|
||||
{
|
||||
ConfigApi.SetEmulationConfig(this);
|
||||
|
@ -48,4 +51,11 @@ namespace Mesen.GUI.Config
|
|||
AllZeros = 1,
|
||||
AllOnes = 2,
|
||||
}
|
||||
|
||||
public enum GameboyModel
|
||||
{
|
||||
Auto = 0,
|
||||
Gameboy = 1,
|
||||
GameboyColor = 2,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace Mesen.GUI.Debugger
|
|||
case SnesMemoryType.GbWorkRam: type = "WRAM"; break;
|
||||
case SnesMemoryType.GbCartRam: type = "SRAM"; break;
|
||||
case SnesMemoryType.GbHighRam: type = "HRAM"; break;
|
||||
case SnesMemoryType.GbBootRom: type = "BOOT"; break;
|
||||
|
||||
case SnesMemoryType.Register: type = "REG"; break;
|
||||
}
|
||||
|
|
|
@ -89,6 +89,9 @@ namespace Mesen.GUI.Debugger
|
|||
if(DebugApi.GetMemorySize(SnesMemoryType.GbCartRam) > 0) {
|
||||
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbCartRam));
|
||||
}
|
||||
if(DebugApi.GetMemorySize(SnesMemoryType.GbBootRom) > 0) {
|
||||
cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbBootRom));
|
||||
}
|
||||
}
|
||||
|
||||
this.toolTip.SetToolTip(this.picExpressionWarning, "Condition contains invalid syntax or symbols.");
|
||||
|
|
|
@ -57,7 +57,12 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
if(DebugApi.GetMemorySize(SnesMemoryType.GbCartRam) > 0) {
|
||||
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbCartRam));
|
||||
}
|
||||
if(DebugApi.GetMemorySize(SnesMemoryType.GbBootRom) > 0) {
|
||||
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbBootRom));
|
||||
}
|
||||
this.Items.Add("-");
|
||||
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbVideoRam));
|
||||
this.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbSpriteRam));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace Mesen.GUI.Debugger.Labels
|
|||
case SnesMemoryType.GbWorkRam: sb.Append("GBWRAM:"); break;
|
||||
case SnesMemoryType.GbCartRam: sb.Append("GBSRAM:"); break;
|
||||
case SnesMemoryType.GbHighRam: sb.Append("GBHRAM:"); break;
|
||||
case SnesMemoryType.GbBootRom: sb.Append("GBBOOT:"); break;
|
||||
}
|
||||
|
||||
sb.Append(Address.ToString("X4"));
|
||||
|
@ -74,6 +75,7 @@ namespace Mesen.GUI.Debugger.Labels
|
|||
case "GBWRAM": type = SnesMemoryType.GsuWorkRam; break;
|
||||
case "GBSRAM": type = SnesMemoryType.GbCartRam; break;
|
||||
case "GBHRAM": type = SnesMemoryType.GbHighRam; break;
|
||||
case "GBBOOT": type = SnesMemoryType.GbBootRom; break;
|
||||
default: return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace Mesen.GUI.Debugger.Labels
|
|||
case SnesMemoryType.GbWorkRam: return address | ((ulong)13 << 32);
|
||||
case SnesMemoryType.GbCartRam: return address | ((ulong)14 << 32);
|
||||
case SnesMemoryType.GbHighRam: return address | ((ulong)15 << 32);
|
||||
case SnesMemoryType.GbBootRom: return address | ((ulong)16 << 32);
|
||||
}
|
||||
throw new Exception("Invalid type");
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
case SnesMemoryType.GbWorkRam: prefix = "WRAM: $"; break;
|
||||
case SnesMemoryType.GbCartRam: prefix = "SRAM: $"; break;
|
||||
case SnesMemoryType.GbHighRam: prefix = "HRAM: $"; break;
|
||||
case SnesMemoryType.GbBootRom: prefix = "BOOT: $"; break;
|
||||
default: throw new Exception("Unsupported type");
|
||||
}
|
||||
int relAddress = label.GetRelativeAddress(_cpuType).Address;
|
||||
|
|
|
@ -64,6 +64,9 @@ namespace Mesen.GUI.Debugger
|
|||
if(DebugApi.GetMemorySize(SnesMemoryType.GbCartRam) > 0) {
|
||||
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbCartRam));
|
||||
}
|
||||
if(DebugApi.GetMemorySize(SnesMemoryType.GbBootRom) > 0) {
|
||||
cboType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GbBootRom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ namespace Mesen.GUI.Debugger.Controls
|
|||
case SnesMemoryType.GbWorkRam: functionName = "WRAM: $"; break;
|
||||
case SnesMemoryType.GbCartRam: functionName = "SRAM: $"; break;
|
||||
case SnesMemoryType.GbHighRam: functionName = "HRAM: $"; break;
|
||||
case SnesMemoryType.GbBootRom: functionName = "BOOT: $"; break;
|
||||
default: throw new Exception("Unsupported type");
|
||||
}
|
||||
|
||||
|
|
|
@ -960,10 +960,17 @@
|
|||
<Value ID="GbPrgRom">GB - PRG ROM</Value>
|
||||
<Value ID="GbWorkRam">GB - Work RAM</Value>
|
||||
<Value ID="GbVideoRam">GB - Video RAM</Value>
|
||||
<Value ID="GbSpriteRam">GB - Sprite RAM</Value>
|
||||
<Value ID="GbCartRam">GB - Cart RAM</Value>
|
||||
<Value ID="GbHighRam">GB - High RAM</Value>
|
||||
<Value ID="GbBootRom">GB - Boot ROM</Value>
|
||||
<Value ID="Register">Register</Value>
|
||||
</Enum>
|
||||
<Enum ID="GameboyModel">
|
||||
<Value ID="Auto">Auto</Value>
|
||||
<Value ID="Gameboy">Game Boy</Value>
|
||||
<Value ID="GameboyColor">Game Boy Color</Value>
|
||||
</Enum>
|
||||
<Enum ID="TileFormat">
|
||||
<Value ID="Bpp2">2 bpp</Value>
|
||||
<Value ID="Bpp4">4 bpp</Value>
|
||||
|
|
76
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
76
UI/Forms/Config/frmEmulationConfig.Designer.cs
generated
|
@ -75,6 +75,11 @@
|
|||
this.radBsxLocalTime = new System.Windows.Forms.RadioButton();
|
||||
this.radBsxCustomTime = new System.Windows.Forms.RadioButton();
|
||||
this.dtpBsxCustomTime = new System.Windows.Forms.DateTimePicker();
|
||||
this.tpgGameboy = new System.Windows.Forms.TabPage();
|
||||
this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblGameboy = new System.Windows.Forms.Label();
|
||||
this.cboGameboyModel = new System.Windows.Forms.ComboBox();
|
||||
this.chkUseBootRom = new System.Windows.Forms.CheckBox();
|
||||
this.tabMain.SuspendLayout();
|
||||
this.tpgGeneral.SuspendLayout();
|
||||
this.tableLayoutPanel4.SuspendLayout();
|
||||
|
@ -93,6 +98,8 @@
|
|||
this.tpgBsx.SuspendLayout();
|
||||
this.grpBsxDateTime.SuspendLayout();
|
||||
this.tableLayoutPanel6.SuspendLayout();
|
||||
this.tpgGameboy.SuspendLayout();
|
||||
this.tableLayoutPanel7.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// baseConfigPanel
|
||||
|
@ -104,9 +111,10 @@
|
|||
// tabMain
|
||||
//
|
||||
this.tabMain.Controls.Add(this.tpgGeneral);
|
||||
this.tabMain.Controls.Add(this.tpgGameboy);
|
||||
this.tabMain.Controls.Add(this.tpgBsx);
|
||||
this.tabMain.Controls.Add(this.tpgAdvanced);
|
||||
this.tabMain.Controls.Add(this.tpgOverclocking);
|
||||
this.tabMain.Controls.Add(this.tpgBsx);
|
||||
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tabMain.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabMain.Name = "tabMain";
|
||||
|
@ -814,6 +822,64 @@
|
|||
this.dtpBsxCustomTime.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
|
||||
this.dtpBsxCustomTime.Enter += new System.EventHandler(this.dtpBsxCustomTime_Enter);
|
||||
//
|
||||
// tpgGameboy
|
||||
//
|
||||
this.tpgGameboy.Controls.Add(this.tableLayoutPanel7);
|
||||
this.tpgGameboy.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgGameboy.Name = "tpgGameboy";
|
||||
this.tpgGameboy.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgGameboy.Size = new System.Drawing.Size(437, 264);
|
||||
this.tpgGameboy.TabIndex = 6;
|
||||
this.tpgGameboy.Text = "Game Boy";
|
||||
this.tpgGameboy.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// tableLayoutPanel7
|
||||
//
|
||||
this.tableLayoutPanel7.ColumnCount = 2;
|
||||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel7.Controls.Add(this.lblGameboy, 0, 0);
|
||||
this.tableLayoutPanel7.Controls.Add(this.cboGameboyModel, 1, 0);
|
||||
this.tableLayoutPanel7.Controls.Add(this.chkUseBootRom, 0, 1);
|
||||
this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel7.Location = new System.Drawing.Point(3, 3);
|
||||
this.tableLayoutPanel7.Name = "tableLayoutPanel7";
|
||||
this.tableLayoutPanel7.RowCount = 3;
|
||||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel7.Size = new System.Drawing.Size(431, 258);
|
||||
this.tableLayoutPanel7.TabIndex = 0;
|
||||
//
|
||||
// lblGameboy
|
||||
//
|
||||
this.lblGameboy.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblGameboy.AutoSize = true;
|
||||
this.lblGameboy.Location = new System.Drawing.Point(3, 7);
|
||||
this.lblGameboy.Name = "lblGameboy";
|
||||
this.lblGameboy.Size = new System.Drawing.Size(91, 13);
|
||||
this.lblGameboy.TabIndex = 0;
|
||||
this.lblGameboy.Text = "Game Boy Model:";
|
||||
//
|
||||
// cboGameboyModel
|
||||
//
|
||||
this.cboGameboyModel.FormattingEnabled = true;
|
||||
this.cboGameboyModel.Location = new System.Drawing.Point(100, 3);
|
||||
this.cboGameboyModel.Name = "cboGameboyModel";
|
||||
this.cboGameboyModel.Size = new System.Drawing.Size(119, 21);
|
||||
this.cboGameboyModel.TabIndex = 1;
|
||||
//
|
||||
// chkUseBootRom
|
||||
//
|
||||
this.chkUseBootRom.AutoSize = true;
|
||||
this.tableLayoutPanel7.SetColumnSpan(this.chkUseBootRom, 2);
|
||||
this.chkUseBootRom.Location = new System.Drawing.Point(3, 30);
|
||||
this.chkUseBootRom.Name = "chkUseBootRom";
|
||||
this.chkUseBootRom.Size = new System.Drawing.Size(89, 17);
|
||||
this.chkUseBootRom.TabIndex = 2;
|
||||
this.chkUseBootRom.Text = "Use boot rom";
|
||||
this.chkUseBootRom.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// frmEmulationConfig
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -857,6 +923,9 @@
|
|||
this.grpBsxDateTime.ResumeLayout(false);
|
||||
this.tableLayoutPanel6.ResumeLayout(false);
|
||||
this.tableLayoutPanel6.PerformLayout();
|
||||
this.tpgGameboy.ResumeLayout(false);
|
||||
this.tableLayoutPanel7.ResumeLayout(false);
|
||||
this.tableLayoutPanel7.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
@ -911,5 +980,10 @@
|
|||
private System.Windows.Forms.RadioButton radBsxCustomTime;
|
||||
private System.Windows.Forms.DateTimePicker dtpBsxCustomTime;
|
||||
private System.Windows.Forms.DateTimePicker dtpBsxCustomDate;
|
||||
private System.Windows.Forms.TabPage tpgGameboy;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7;
|
||||
private System.Windows.Forms.Label lblGameboy;
|
||||
private System.Windows.Forms.ComboBox cboGameboyModel;
|
||||
private System.Windows.Forms.CheckBox chkUseBootRom;
|
||||
}
|
||||
}
|
|
@ -37,6 +37,9 @@ namespace Mesen.GUI.Forms.Config
|
|||
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesBeforeNmi), nudExtraScanlinesBeforeNmi);
|
||||
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesAfterNmi), nudExtraScanlinesAfterNmi);
|
||||
AddBinding(nameof(EmulationConfig.GsuClockSpeed), nudGsuClockSpeed);
|
||||
|
||||
AddBinding(nameof(EmulationConfig.GbModel), cboGameboyModel);
|
||||
AddBinding(nameof(EmulationConfig.GbUseBootRom), chkUseBootRom);
|
||||
|
||||
long customDate = ConfigManager.Config.Emulation.BsxCustomDate;
|
||||
if(customDate >= 0) {
|
||||
|
|
|
@ -213,8 +213,10 @@ namespace Mesen.GUI
|
|||
GbPrgRom,
|
||||
GbWorkRam,
|
||||
GbCartRam,
|
||||
GbVideoRam,
|
||||
GbHighRam,
|
||||
GbBootRom,
|
||||
GbVideoRam,
|
||||
GbSpriteRam,
|
||||
Register,
|
||||
}
|
||||
|
||||
|
@ -245,6 +247,7 @@ namespace Mesen.GUI
|
|||
case SnesMemoryType.GbWorkRam:
|
||||
case SnesMemoryType.GbCartRam:
|
||||
case SnesMemoryType.GbHighRam:
|
||||
case SnesMemoryType.GbBootRom:
|
||||
return CpuType.Gameboy;
|
||||
|
||||
default:
|
||||
|
@ -281,6 +284,7 @@ namespace Mesen.GUI
|
|||
case SnesMemoryType.GbWorkRam:
|
||||
case SnesMemoryType.GbCartRam:
|
||||
case SnesMemoryType.GbHighRam:
|
||||
case SnesMemoryType.GbBootRom:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -736,6 +736,7 @@ namespace Mesen.GUI
|
|||
public byte Status;
|
||||
public UInt32 FrameCount;
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)] public bool CgbEnabled;
|
||||
public byte CgbVramBank;
|
||||
|
||||
public byte CgbBgPalPosition;
|
||||
|
|
|
@ -208,10 +208,26 @@ namespace Mesen.GUI
|
|||
Gameboy
|
||||
}
|
||||
|
||||
public enum FirmwareType
|
||||
{
|
||||
CX4,
|
||||
DSP1,
|
||||
DSP1B,
|
||||
DSP2,
|
||||
DSP3,
|
||||
DSP4,
|
||||
ST010,
|
||||
ST011,
|
||||
ST018,
|
||||
Satellaview,
|
||||
Gameboy,
|
||||
GameboyColor
|
||||
}
|
||||
|
||||
public struct MissingFirmwareMessage
|
||||
{
|
||||
public IntPtr Filename;
|
||||
public CoprocessorType FirmwareType;
|
||||
public FirmwareType Firmware;
|
||||
public UInt32 Size;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,38 +28,41 @@ namespace Mesen.GUI.Utilities
|
|||
}
|
||||
}
|
||||
|
||||
private static List<string> GetExpectedHashes(CoprocessorType type)
|
||||
private static List<string> GetExpectedHashes(FirmwareType type)
|
||||
{
|
||||
switch(type) {
|
||||
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>() {
|
||||
case FirmwareType.CX4: return new List<string>() { "AE8D4D1961B93421FF00B3CAA1D0F0CE7783E749772A3369C36B3DBF0D37EF18" };
|
||||
case FirmwareType.DSP1: return new List<string>() { "91E87D11E1C30D172556BED2211CCE2EFA94BA595F58C5D264809EF4D363A97B" };
|
||||
case FirmwareType.DSP1B: return new List<string>() { "D789CB3C36B05C0B23B6C6F23BE7AA37C6E78B6EE9CEAC8D2D2AA9D8C4D35FA9" };
|
||||
case FirmwareType.DSP2: return new List<string>() { "03EF4EF26C9F701346708CB5D07847B5203CF1B0818BF2930ACD34510FFDD717" };
|
||||
case FirmwareType.DSP3: return new List<string>() { "0971B08F396C32E61989D1067DDDF8E4B14649D548B2188F7C541B03D7C69E4E" };
|
||||
case FirmwareType.DSP4: return new List<string>() { "752D03B2D74441E430B7F713001FA241F8BBCFC1A0D890ED4143F174DBE031DA" };
|
||||
case FirmwareType.ST010: return new List<string>() { "FA9BCED838FEDEA11C6F6ACE33D1878024BDD0D02CC9485899D0BDD4015EC24C" };
|
||||
case FirmwareType.ST011: return new List<string>() { "8B2B3F3F3E6E29F4D21D8BC736B400BC988B7D2214EBEE15643F01C1FEE2F364" };
|
||||
case FirmwareType.ST018: return new List<string>() { "6DF209AB5D2524D1839C038BE400AE5EB20DAFC14A3771A3239CD9E8ACD53806" };
|
||||
case FirmwareType.Satellaview: return new List<string>() {
|
||||
"27CFDB99F7E4252BF3740D420147B63C4C88616883BC5E7FE43F2F30BF8C8CBB", //Japan, no DRM
|
||||
"A49827B45FF9AC9CF5B4658190E1428E59251BC82D8A63D8E9E0F71E439F008F", //English, no DRM
|
||||
"3CE321496EDC5D77038DE2034EB3FB354D7724AFD0BC7FD0319F3EB5D57B984D", //Japan, original
|
||||
"77D94D64D745014BF8B51280A4204056CDEB9D41EA30EAE80DBC006675BEBEF8", //English, DRM
|
||||
};
|
||||
case FirmwareType.Gameboy: return new List<string>() { "CF053ECCB4CCAFFF9E67339D4E78E98DCE7D1ED59BE819D2A1BA2232C6FCE1C7", "26E71CF01E301E5DC40E987CD2ECBF6D0276245890AC829DB2A25323DA86818E" };
|
||||
case FirmwareType.GameboyColor: return new List<string>() { "B4F2E416A35EEF52CBA161B159C7C8523A92594FACB924B3EDE0D722867C50C7", "3A307A41689BEE99A9A32EA021BF45136906C86B2E4F06C806738398E4F92E45" };
|
||||
|
||||
}
|
||||
throw new Exception("Unexpected coprocessor type");
|
||||
throw new Exception("Unexpected firmware type");
|
||||
}
|
||||
|
||||
public static void RequestFirmwareFile(MissingFirmwareMessage msg)
|
||||
{
|
||||
string filename = Utf8Marshaler.GetStringFromIntPtr(msg.Filename);
|
||||
if(MesenMsgBox.Show("FirmwareNotFound", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, msg.FirmwareType.ToString(), filename, msg.Size.ToString()) == DialogResult.OK) {
|
||||
if(MesenMsgBox.Show("FirmwareNotFound", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, msg.Firmware.ToString(), filename, msg.Size.ToString()) == DialogResult.OK) {
|
||||
using(OpenFileDialog ofd = new OpenFileDialog()) {
|
||||
ofd.SetFilter(ResourceHelper.GetMessage("FilterAll"));
|
||||
if(ofd.ShowDialog(frmMain.Instance) == DialogResult.OK) {
|
||||
List<string> expectedHashes = GetExpectedHashes(msg.FirmwareType);
|
||||
List<string> expectedHashes = GetExpectedHashes(msg.Firmware);
|
||||
if(!expectedHashes.Contains(GetFileHash(ofd.FileName))) {
|
||||
if(MesenMsgBox.Show("FirmwareMismatch", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, msg.FirmwareType.ToString(), GetFileHash(ofd.FileName), expectedHashes[0]) != DialogResult.OK) {
|
||||
if(MesenMsgBox.Show("FirmwareMismatch", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, msg.Firmware.ToString(), GetFileHash(ofd.FileName), expectedHashes[0]) != DialogResult.OK) {
|
||||
//Files don't match and user cancelled the action
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue