diff --git a/.gitignore b/.gitignore index 5175783..71fd310 100644 --- a/.gitignore +++ b/.gitignore @@ -161,6 +161,8 @@ $RECYCLE.BIN/ .DS_Store *.nes *.sfc +*.gb +*.gbc *.sav *.svs *.trt diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index 1400c15..a59447b 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -21,6 +21,7 @@ #include "BsxMemoryPack.h" #include "FirmwareHelper.h" #include "SpcFileData.h" +#include "SuperGameboy.h" #include "Gameboy.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/VirtualFile.h" @@ -243,7 +244,14 @@ CoprocessorType BaseCartridge::GetCoprocessorType() case 0x03: return CoprocessorType::SA1; case 0x04: return CoprocessorType::SDD1; case 0x05: return CoprocessorType::RTC; - case 0x0E: return CoprocessorType::Satellaview; + case 0x0E: + switch(_cartInfo.RomType) { + case 0xE3: return CoprocessorType::SGB; + case 0xE5: return CoprocessorType::Satellaview; + default: return CoprocessorType::None; + } + break; + case 0x0F: switch(_cartInfo.CartridgeType) { case 0x00: @@ -496,9 +504,11 @@ void BaseCartridge::InitCoprocessor() if(_coprocessorType == CoprocessorType::SA1) { _coprocessor.reset(new Sa1(_console)); _sa1 = dynamic_cast(_coprocessor.get()); + _needCoprocSync = true; } else if(_coprocessorType == CoprocessorType::GSU) { _coprocessor.reset(new Gsu(_console, _coprocessorRamSize)); _gsu = dynamic_cast(_coprocessor.get()); + _needCoprocSync = true; } else if(_coprocessorType == CoprocessorType::SDD1) { _coprocessor.reset(new Sdd1(_console)); } else if(_coprocessorType == CoprocessorType::SPC7110) { @@ -518,8 +528,13 @@ void BaseCartridge::InitCoprocessor() } else if(_coprocessorType == CoprocessorType::CX4) { _coprocessor.reset(new Cx4(_console)); _cx4 = dynamic_cast(_coprocessor.get()); + _needCoprocSync = true; } else if(_coprocessorType == CoprocessorType::OBC1 && _saveRamSize > 0) { _coprocessor.reset(new Obc1(_console, _saveRam, _saveRamSize)); + } else if(_coprocessorType == CoprocessorType::SGB) { + _coprocessor.reset(new SuperGameboy(_console)); + _sgb = dynamic_cast(_coprocessor.get()); + _needCoprocSync = true; } } @@ -612,8 +627,16 @@ bool BaseCartridge::LoadGameboy(VirtualFile &romFile) _cartInfo = { }; _headerOffset = Gameboy::HeaderOffset; - _coprocessorType = CoprocessorType::Gameboy; - SetupCpuHalt(); + + if(_gameboy->IsSgb()) { + if(!FirmwareHelper::LoadSgbFirmware(_console, &_prgRom, _prgRomSize)) { + return false; + } + LoadRom(); + } else { + _coprocessorType = CoprocessorType::Gameboy; + SetupCpuHalt(); + } return true; } @@ -738,6 +761,7 @@ void BaseCartridge::DisplayCartInfo() case CoprocessorType::ST011: coProcMessage += "ST011"; break; case CoprocessorType::ST018: coProcMessage += "ST018"; break; case CoprocessorType::Gameboy: coProcMessage += "Game Boy"; break; + case CoprocessorType::SGB: coProcMessage += "Super Game Boy"; break; } MessageManager::Log(coProcMessage); } @@ -782,6 +806,11 @@ Cx4* BaseCartridge::GetCx4() return _cx4; } +SuperGameboy* BaseCartridge::GetSuperGameboy() +{ + return _sgb; +} + BsxCart* BaseCartridge::GetBsx() { return _bsx; diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index bfcbcb6..f9d65f4 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -2,9 +2,9 @@ #include "stdafx.h" #include "IMemoryHandler.h" #include "CartTypes.h" +#include "BaseCoprocessor.h" #include "../Utilities/ISerializable.h" -class BaseCoprocessor; class MemoryMappings; class VirtualFile; class EmuSettings; @@ -12,6 +12,7 @@ class NecDsp; class Sa1; class Gsu; class Cx4; +class SuperGameboy; class BsxCart; class BsxMemoryPack; class Gameboy; @@ -29,11 +30,14 @@ private: SnesCartInformation _cartInfo = {}; uint32_t _headerOffset = 0; + bool _needCoprocSync = false; unique_ptr _coprocessor; + NecDsp *_necDsp = nullptr; Sa1 *_sa1 = nullptr; Gsu *_gsu = nullptr; Cx4 *_cx4 = nullptr; + SuperGameboy *_sgb = nullptr; BsxCart* _bsx = nullptr; unique_ptr _bsxMemPack; unique_ptr _gameboy; @@ -107,11 +111,19 @@ public: Sa1* GetSa1(); Gsu* GetGsu(); Cx4* GetCx4(); + SuperGameboy* GetSuperGameboy(); BsxCart* GetBsx(); BsxMemoryPack* GetBsxMemoryPack(); Gameboy* GetGameboy(); void RunCoprocessors(); + + __forceinline void SyncCoprocessors() + { + if(_needCoprocSync) { + _coprocessor->Run(); + } + } BaseCoprocessor* GetCoprocessor(); diff --git a/Core/BaseCoprocessor.h b/Core/BaseCoprocessor.h index b884ae7..dbbd9bb 100644 --- a/Core/BaseCoprocessor.h +++ b/Core/BaseCoprocessor.h @@ -9,7 +9,8 @@ public: using IMemoryHandler::IMemoryHandler; virtual void Reset() = 0; - + + virtual void Run() { } virtual void ProcessEndOfFrame() { } virtual void LoadBattery() { } virtual void SaveBattery() { } diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index d66e6c0..e169c44 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -12,7 +12,7 @@ BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType, IEvent _debugger = debugger; _cpuType = cpuType; _hasBreakpoint = false; - _eventManager = eventManager ? eventManager : debugger->GetEventManager().get(); + _eventManager = eventManager ? eventManager : debugger->GetEventManager(cpuType).get(); } void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) diff --git a/Core/CartTypes.h b/Core/CartTypes.h index 707fe71..72dc6d8 100644 --- a/Core/CartTypes.h +++ b/Core/CartTypes.h @@ -45,7 +45,8 @@ enum class CoprocessorType ST011, ST018, CX4, - Gameboy + Gameboy, + SGB }; enum class FirmwareType @@ -61,7 +62,9 @@ enum class FirmwareType ST018, Satellaview, Gameboy, - GameboyColor + GameboyColor, + SgbGameboyCpu, + SGB }; struct RomInfo diff --git a/Core/Console.cpp b/Core/Console.cpp index 6141b8f..cbac889 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -432,7 +432,7 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _memoryManager->Initialize(this); _internalRegisters->Initialize(this); - if(_cart->GetGameboy()) { + if(_cart->GetCoprocessor() == nullptr && _cart->GetGameboy()) { _cart->GetGameboy()->PowerOn(); _settings->SetFlag(EmulationFlags::GameboyMode); } else { @@ -887,57 +887,6 @@ uint32_t Console::GetFrameCount() } } -template -void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) -{ - if(_debugger) { - _debugger->ProcessMemoryRead(addr, value, opType); - } -} - -template -void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) -{ - if(_debugger) { - _debugger->ProcessMemoryWrite(addr, value, opType); - } -} - -void Console::ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType) -{ - if(_debugger) { - _debugger->ProcessPpuRead(addr, value, memoryType); - } -} - -void Console::ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType) -{ - if(_debugger) { - _debugger->ProcessPpuWrite(addr, value, memoryType); - } -} - -void Console::ProcessWorkRamRead(uint32_t addr, uint8_t value) -{ - if(_debugger) { - _debugger->ProcessWorkRamRead(addr, value); - } -} - -void Console::ProcessWorkRamWrite(uint32_t addr, uint8_t value) -{ - if(_debugger) { - _debugger->ProcessWorkRamWrite(addr, value); - } -} - -void Console::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) -{ - if(_debugger) { - _debugger->ProcessPpuCycle(scanline, cycle); - } -} - template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi) { diff --git a/Core/Console.h b/Core/Console.h index 2a11bc9..09d39a2 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "CartTypes.h" #include "DebugTypes.h" +#include "Debugger.h" #include "ConsoleLock.h" #include "../Utilities/Timer.h" #include "../Utilities/VirtualFile.h" @@ -172,13 +173,55 @@ public: uint32_t GetFrameCount(); double GetFps(); - template void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); - template void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); - void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType); - void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType); - void ProcessWorkRamRead(uint32_t addr, uint8_t value); - void ProcessWorkRamWrite(uint32_t addr, uint8_t value); - void ProcessPpuCycle(uint16_t scanline, uint16_t cycle); + template __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType) + { + if(_debugger) { + _debugger->ProcessMemoryRead(addr, value, opType); + } + } + + template __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType) + { + if(_debugger) { + _debugger->ProcessMemoryWrite(addr, value, opType); + } + } + + __forceinline void ProcessPpuRead(uint32_t addr, uint8_t value, SnesMemoryType memoryType) + { + if(_debugger) { + _debugger->ProcessPpuRead(addr, value, memoryType); + } + } + + __forceinline void ProcessPpuWrite(uint32_t addr, uint8_t value, SnesMemoryType memoryType) + { + if(_debugger) { + _debugger->ProcessPpuWrite(addr, value, memoryType); + } + } + + __forceinline void ProcessWorkRamRead(uint32_t addr, uint8_t value) + { + if(_debugger) { + _debugger->ProcessWorkRamRead(addr, value); + } + } + + __forceinline void ProcessWorkRamWrite(uint32_t addr, uint8_t value) + { + if(_debugger) { + _debugger->ProcessWorkRamWrite(addr, value); + } + } + + template __forceinline void ProcessPpuCycle() + { + if(_debugger) { + _debugger->ProcessPpuCycle(); + } + } + template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); void ProcessEvent(EventType type); void BreakImmediately(BreakSource source); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 45a37f8..8bad87b 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -70,6 +70,7 @@ + @@ -236,6 +237,7 @@ + @@ -371,6 +373,7 @@ Create Create + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index b0930e1..d8c4c4c 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -596,6 +596,12 @@ Debugger\Assembler + + SNES\Coprocessors\SuperGameboy + + + GB + @@ -956,6 +962,9 @@ GB\APU + + SNES\Coprocessors\SuperGameboy + @@ -1048,5 +1057,8 @@ {8abb14c6-e2ee-48cb-ad91-38402cb8510c} + + {50d3ab3e-f393-4fa3-a8a6-8ec593089f1b} + \ No newline at end of file diff --git a/Core/CpuDebugger.cpp b/Core/CpuDebugger.cpp index aa78c18..926f0fa 100644 --- a/Core/CpuDebugger.cpp +++ b/Core/CpuDebugger.cpp @@ -32,7 +32,7 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType) _memoryAccessCounter = debugger->GetMemoryAccessCounter().get(); _cpu = debugger->GetConsole()->GetCpu().get(); _sa1 = debugger->GetConsole()->GetCartridge()->GetSa1(); - _codeDataLogger = debugger->GetCodeDataLogger().get(); + _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _settings = debugger->GetConsole()->GetSettings().get(); _memoryManager = debugger->GetConsole()->GetMemoryManager().get(); @@ -78,11 +78,10 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType } if(_traceLogger->IsCpuLogged(_cpuType)) { - DebugState debugState; - _debugger->GetState(debugState, true); + _debugger->GetState(_debugState, true); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, state.PS, _cpuType); - _traceLogger->Log(_cpuType, debugState, disInfo); + _traceLogger->Log(_cpuType, _debugState, disInfo); } uint32_t pc = (state.K << 16) | state.PC; @@ -197,9 +196,8 @@ void CpuDebugger::Step(int32_t stepCount, StepType type) } break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::PpuStep: step.PpuStepCount = stepCount; _step.reset(new StepRequest(step)); break; + case StepType::SpecificScanline: step.BreakScanline = stepCount; _step.reset(new StepRequest(step)); break; } } _step.reset(new StepRequest(step)); @@ -214,6 +212,21 @@ void CpuDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool _eventManager->AddEvent(forNmi ? DebugEventType::Nmi : DebugEventType::Irq); } +void CpuDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) +{ + if(_step->PpuStepCount > 0) { + _step->PpuStepCount--; + if(_step->PpuStepCount == 0) { + _debugger->SleepUntilResume(BreakSource::PpuStep); + } + } + + if(cycle == 0 && scanline == _step->BreakScanline) { + _step->BreakScanline = -1; + _debugger->SleepUntilResume(BreakSource::PpuStep); + } +} + MemoryMappings& CpuDebugger::GetMemoryMappings() { if(_cpuType == CpuType::Cpu) { diff --git a/Core/CpuDebugger.h b/Core/CpuDebugger.h index e978f97..9ae83ab 100644 --- a/Core/CpuDebugger.h +++ b/Core/CpuDebugger.h @@ -41,7 +41,8 @@ class CpuDebugger final : public IDebugger bool _enableBreakOnUninitRead = false; uint8_t _prevOpCode = 0xFF; uint32_t _prevProgramCounter = 0; - + DebugState _debugState; + MemoryMappings& GetMemoryMappings(); CpuState GetState(); bool IsRegister(uint32_t addr); @@ -55,6 +56,7 @@ public: void Run(); void Step(int32_t stepCount, StepType type); void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); + void ProcessPpuCycle(uint16_t scanline, uint16_t cycle); shared_ptr GetEventManager(); shared_ptr GetAssembler(); diff --git a/Core/Cx4.h b/Core/Cx4.h index 6a501b2..678c3e9 100644 --- a/Core/Cx4.h +++ b/Core/Cx4.h @@ -114,7 +114,7 @@ public: void Reset() override; - void Run(); + void Run() override; uint8_t Read(uint32_t addr) override; void Write(uint32_t addr, uint8_t value) override; diff --git a/Core/Cx4Debugger.cpp b/Core/Cx4Debugger.cpp index 5d03430..4c0de7d 100644 --- a/Core/Cx4Debugger.cpp +++ b/Core/Cx4Debugger.cpp @@ -20,7 +20,7 @@ Cx4Debugger::Cx4Debugger(Debugger* debugger) { _debugger = debugger; - _codeDataLogger = debugger->GetCodeDataLogger().get(); + _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _traceLogger = debugger->GetTraceLogger().get(); _disassembler = debugger->GetDisassembler().get(); _memoryAccessCounter = debugger->GetMemoryAccessCounter().get(); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 69ac5d5..938bff1 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -42,6 +42,8 @@ #include "InternalRegisters.h" #include "AluMulDiv.h" #include "Assembler.h" +#include "Gameboy.h" +#include "GbPpu.h" #include "GbAssembler.h" #include "GameboyHeader.h" #include "../Utilities/HexUtilities.h" @@ -59,6 +61,7 @@ Debugger::Debugger(shared_ptr console) _memoryManager = console->GetMemoryManager(); _dmaController = console->GetDmaController(); _internalRegs = console->GetInternalRegisters(); + _gameboy = _cart->GetGameboy(); _labelManager.reset(new LabelManager(this)); _watchExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(this, CpuType::Cpu)); @@ -77,7 +80,7 @@ Debugger::Debugger(shared_ptr console) _ppuTools.reset(new PpuTools(_console.get(), _ppu.get())); _scriptManager.reset(new ScriptManager(this)); - if(_cart->GetGameboy()) { + if(_gameboy) { _gbDebugger.reset(new GbDebugger(this)); } _cpuDebugger.reset(new CpuDebugger(this, CpuType::Cpu)); @@ -98,8 +101,9 @@ Debugger::Debugger(shared_ptr console) _breakRequestCount = 0; _suspendRequestCount = 0; + CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); - GetCodeDataLogger()->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), _cart->GetCrc32()); + GetCodeDataLogger(cpuType)->LoadCdlFile(cdlFile, _settings->CheckDebuggerFlag(DebuggerFlags::AutoResetCdl), _cart->GetCrc32()); RefreshCodeCache(); @@ -116,8 +120,9 @@ Debugger::~Debugger() void Debugger::Release() { + CpuType cpuType = _gbDebugger ? CpuType::Gameboy : CpuType::Cpu; string cdlFile = FolderUtilities::CombinePath(FolderUtilities::GetDebuggerFolder(), FolderUtilities::GetFilename(_cart->GetRomInfo().RomFile.GetFileName(), false) + ".cdl"); - GetCodeDataLogger()->SaveCdlFile(cdlFile, _cart->GetCrc32()); + GetCodeDataLogger(cpuType)->SaveCdlFile(cdlFile, _cart->GetCrc32()); while(_executionStopped) { Run(); @@ -146,7 +151,10 @@ void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationTy case CpuType::Cx4: _cx4Debugger->ProcessRead(addr, value, opType); break; case CpuType::Gameboy: _gbDebugger->ProcessRead(addr, value, opType); break; } - _scriptManager->ProcessMemoryOperation(addr, value, opType, type); + + if(_scriptManager->HasScript()) { + _scriptManager->ProcessMemoryOperation(addr, value, opType, type); + } } template @@ -161,7 +169,10 @@ void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationT case CpuType::Cx4: _cx4Debugger->ProcessWrite(addr, value, opType); break; case CpuType::Gameboy: _gbDebugger->ProcessWrite(addr, value, opType); break; } - _scriptManager->ProcessMemoryOperation(addr, value, opType, type); + + if(_scriptManager->HasScript()) { + _scriptManager->ProcessMemoryOperation(addr, value, opType, type); + } } void Debugger::ProcessWorkRamRead(uint32_t addr, uint8_t value) @@ -200,30 +211,41 @@ void Debugger::ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memo _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); } -void Debugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) +template +void Debugger::ProcessPpuCycle() { - _ppuTools->UpdateViewers(scanline, cycle); - - if(_step->PpuStepCount > 0) { - _step->PpuStepCount--; - if(_step->PpuStepCount == 0) { - SleepUntilResume(BreakSource::PpuStep); - } + uint16_t scanline; + uint16_t cycle; + if(cpuType == CpuType::Gameboy) { + scanline = _gameboy->GetPpu()->GetScanline(); + cycle = _gameboy->GetPpu()->GetCycle(); + } else { + scanline = _ppu->GetScanline(); + cycle = _memoryManager->GetHClock(); } - if(cycle == 0 && scanline == _step->BreakScanline) { - _step->BreakScanline = -1; - SleepUntilResume(BreakSource::PpuStep); - } else if(_breakRequestCount > 0) { + _ppuTools->UpdateViewers(scanline, cycle, cpuType); + + switch(cpuType) { + case CpuType::Cpu: + //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) + if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { + _spc->Run(); + } else if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { + _cart->RunCoprocessors(); + } + + _cpuDebugger->ProcessPpuCycle(scanline, cycle); + break; + + case CpuType::Gameboy: + _gbDebugger->ProcessPpuCycle(scanline, cycle); + break; + } + + if(_breakRequestCount > 0) { SleepUntilResume(BreakSource::Unspecified); } - - //Catch up SPC/DSP as needed (if we're tracing or debugging those particular CPUs) - if(_traceLogger->IsCpuLogged(CpuType::Spc) || _settings->CheckDebuggerFlag(DebuggerFlags::SpcDebuggerEnabled)) { - _spc->Run(); - } else if(_traceLogger->IsCpuLogged(CpuType::NecDsp)) { - _cart->RunCoprocessors(); - } } void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operation, int breakpointId) @@ -300,8 +322,13 @@ void Debugger::ProcessEvent(EventType type) default: break; case EventType::StartFrame: - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh); - GetEventManager()->ClearFrameEvents(); + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Cpu); + GetEventManager(CpuType::Cpu)->ClearFrameEvents(); + break; + + case EventType::GbStartFrame: + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh, (void*)CpuType::Gameboy); + GetEventManager(CpuType::Gameboy)->ClearFrameEvents(); break; case EventType::Reset: @@ -356,23 +383,17 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type) StepRequest step; IDebugger *debugger = nullptr; - switch(type) { - case StepType::PpuStep: step.PpuStepCount = stepCount; _step.reset(new StepRequest(step)); break; - case StepType::SpecificScanline: step.BreakScanline = stepCount; _step.reset(new StepRequest(step)); break; - default: - switch(cpuType) { - case CpuType::Cpu: debugger = _cpuDebugger.get(); break; - case CpuType::Spc: debugger = _spcDebugger.get(); break; - case CpuType::NecDsp: debugger = _necDspDebugger.get(); break; - case CpuType::Sa1: debugger = _sa1Debugger.get(); break; - case CpuType::Gsu: debugger = _gsuDebugger.get(); break; - case CpuType::Cx4: debugger = _cx4Debugger.get(); break; - case CpuType::Gameboy: debugger = _gbDebugger.get(); break; - } - debugger->Step(stepCount, type); - break; + switch(cpuType) { + case CpuType::Cpu: debugger = _cpuDebugger.get(); break; + case CpuType::Spc: debugger = _spcDebugger.get(); break; + case CpuType::NecDsp: debugger = _necDspDebugger.get(); break; + case CpuType::Sa1: debugger = _sa1Debugger.get(); break; + case CpuType::Gsu: debugger = _gsuDebugger.get(); break; + case CpuType::Cx4: debugger = _cx4Debugger.get(); break; + case CpuType::Gameboy: debugger = _gbDebugger.get(); break; } - + debugger->Step(stepCount, type); + if(!debugger) { _step.reset(new StepRequest(step)); } @@ -565,28 +586,37 @@ AddressInfo Debugger::GetRelativeAddress(AddressInfo absAddress, CpuType cpuType } } -void Debugger::SetCdlData(uint8_t *cdlData, uint32_t length) +void Debugger::SetCdlData(CpuType cpuType, uint8_t *cdlData, uint32_t length) { DebugBreakHelper helper(this); - GetCodeDataLogger()->SetCdlData(cdlData, length); + GetCodeDataLogger(cpuType)->SetCdlData(cdlData, length); RefreshCodeCache(); } -void Debugger::MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags) +void Debugger::MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags) { DebugBreakHelper helper(this); - GetCodeDataLogger()->MarkBytesAs(start, end, flags); + GetCodeDataLogger(cpuType)->MarkBytesAs(start, end, flags); RefreshCodeCache(); } void Debugger::RefreshCodeCache() { _disassembler->ResetPrgCache(); + RebuildPrgCache(CpuType::Cpu); + RebuildPrgCache(CpuType::Gameboy); +} + +void Debugger::RebuildPrgCache(CpuType cpuType) +{ + shared_ptr cdl = GetCodeDataLogger(cpuType); + if(!cdl) { + return; + } - shared_ptr cdl = GetCodeDataLogger(); uint32_t prgRomSize = cdl->GetPrgSize(); AddressInfo addrInfo; - addrInfo.Type = _gbDebugger ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; + addrInfo.Type = cpuType == CpuType::Gameboy ? SnesMemoryType::GbPrgRom : SnesMemoryType::PrgRom; for(uint32_t i = 0; i < prgRomSize; i++) { if(cdl->IsCode(i)) { @@ -598,7 +628,8 @@ void Debugger::RefreshCodeCache() void Debugger::GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData) { - shared_ptr cdl = GetCodeDataLogger(); + CpuType cpuType = DebugUtilities::ToCpuType(memoryType); + shared_ptr cdl = GetCodeDataLogger(cpuType); if(memoryType == SnesMemoryType::PrgRom || memoryType == SnesMemoryType::GbPrgRom) { cdl->GetCdlData(offset, length, cdlData); } else { @@ -654,7 +685,7 @@ void Debugger::SaveRomToDisk(string filename, bool saveAsIps, CdlStripOption str output = IpsPatcher::CreatePatch(_cart->GetOriginalPrgRom(), rom); } else { if(stripOption != CdlStripOption::StripNone) { - GetCodeDataLogger()->StripData(rom.data(), stripOption); + GetCodeDataLogger(gb ? CpuType::Gameboy : CpuType::Cpu)->StripData(rom.data(), stripOption); //Preserve rom header regardless of CDL file contents if(gb) { @@ -689,10 +720,10 @@ shared_ptr Debugger::GetMemoryAccessCounter() return _memoryAccessCounter; } -shared_ptr Debugger::GetCodeDataLogger() +shared_ptr Debugger::GetCodeDataLogger(CpuType cpuType) { - if(_gbDebugger) { - return _gbDebugger->GetCodeDataLogger(); + if(cpuType == CpuType::Gameboy) { + return _gbDebugger ? _gbDebugger->GetCodeDataLogger() : nullptr; } else { return _codeDataLogger; } @@ -708,9 +739,9 @@ shared_ptr Debugger::GetPpuTools() return _ppuTools; } -shared_ptr Debugger::GetEventManager() +shared_ptr Debugger::GetEventManager(CpuType cpuType) { - if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + if(cpuType == CpuType::Gameboy) { return std::dynamic_pointer_cast(_gbDebugger->GetEventManager()); } else { return std::dynamic_pointer_cast(_cpuDebugger->GetEventManager()); @@ -776,3 +807,6 @@ template void Debugger::ProcessMemoryWrite(uint32_t addr, uint template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); + +template void Debugger::ProcessPpuCycle(); +template void Debugger::ProcessPpuCycle(); diff --git a/Core/Debugger.h b/Core/Debugger.h index 5d61d09..cd1c66c 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -36,6 +36,7 @@ class GbDebugger; class Breakpoint; class IEventManager; class IAssembler; +class Gameboy; enum class EventType; enum class EvalResultType : int32_t; @@ -51,7 +52,9 @@ private: shared_ptr _cart; shared_ptr _internalRegs; shared_ptr _dmaController; - + + Gameboy* _gameboy = nullptr; + shared_ptr _settings; unique_ptr _spcDebugger; unique_ptr _cpuDebugger; @@ -81,7 +84,6 @@ private: bool _waitForBreakResume = false; void Reset(); - void SleepUntilResume(BreakSource source, MemoryOperationInfo *operation = nullptr, int breakpointId = -1); public: Debugger(shared_ptr console); @@ -99,7 +101,9 @@ public: void ProcessPpuRead(uint16_t addr, uint8_t value, SnesMemoryType memoryType); void ProcessPpuWrite(uint16_t addr, uint8_t value, SnesMemoryType memoryType); - void ProcessPpuCycle(uint16_t scanline, uint16_t cycle); + + template + void ProcessPpuCycle(); template void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); @@ -119,6 +123,7 @@ public: void BreakImmediately(BreakSource source); void ProcessBreakConditions(bool needBreak, BreakpointManager *bpManager, MemoryOperationInfo &operation, AddressInfo &addressInfo, BreakSource source = BreakSource::Unspecified); + void SleepUntilResume(BreakSource source, MemoryOperationInfo* operation = nullptr, int breakpointId = -1); void GetState(DebugState &state, bool partialPpuState); @@ -126,9 +131,11 @@ public: AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType); void GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData); - void SetCdlData(uint8_t * cdlData, uint32_t length); - void MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags); + void SetCdlData(CpuType cpuType, uint8_t * cdlData, uint32_t length); + void MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags); + void RefreshCodeCache(); + void RebuildPrgCache(CpuType cpuType); void SetBreakpoints(Breakpoint breakpoints[], uint32_t length); @@ -137,10 +144,10 @@ public: shared_ptr GetTraceLogger(); shared_ptr GetMemoryDumper(); shared_ptr GetMemoryAccessCounter(); - shared_ptr GetCodeDataLogger(); + shared_ptr GetCodeDataLogger(CpuType cpuType); shared_ptr GetDisassembler(); shared_ptr GetPpuTools(); - shared_ptr GetEventManager(); + shared_ptr GetEventManager(CpuType cpuType); shared_ptr GetLabelManager(); shared_ptr GetScriptManager(); shared_ptr GetCallstackManager(CpuType cpuType); diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index 8e9a55f..bc384d6 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -125,7 +125,7 @@ Disassembler::Disassembler(shared_ptr console, shared_ptr& Disassembler::GetDisassemblyList(CpuType type) uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuType type) { - DisassemblerSource src = GetSource(addrInfo.Type); + DisassemblerSource& src = GetSource(addrInfo.Type); bool needDisassemble = false; int returnSize = 0; diff --git a/Core/Disassembler.h b/Core/Disassembler.h index 437d4c0..f1fc10d 100644 --- a/Core/Disassembler.h +++ b/Core/Disassembler.h @@ -109,7 +109,7 @@ private: uint8_t* _gbBootRom; uint32_t _gbBootRomSize; - DisassemblerSource GetSource(SnesMemoryType type); + DisassemblerSource& GetSource(SnesMemoryType type); vector& GetDisassemblyList(CpuType type); void SetDisassembleFlag(CpuType type); diff --git a/Core/EventType.h b/Core/EventType.h index 4f150e1..153b2c4 100644 --- a/Core/EventType.h +++ b/Core/EventType.h @@ -11,5 +11,7 @@ enum class EventType InputPolled, StateLoaded, StateSaved, + GbStartFrame, + GbEndFrame, EventTypeSize }; \ No newline at end of file diff --git a/Core/FirmwareHelper.h b/Core/FirmwareHelper.h index 6661a4c..13a047c 100644 --- a/Core/FirmwareHelper.h +++ b/Core/FirmwareHelper.h @@ -107,15 +107,43 @@ public: return false; } - static bool LoadGbBootRom(Console* console, uint8_t** bootRom, FirmwareType type) + static bool LoadSgbFirmware(Console* console, uint8_t** prgRom, uint32_t& prgSize) { - string filename = type == FirmwareType::Gameboy ? "dmg_boot.bin" : "cgb_boot.bin"; - uint32_t size = type == FirmwareType::Gameboy ? 256 : 2304; - if(AttemptLoadFirmware(bootRom, filename, size)) { + prgSize = 0x40000; + if(AttemptLoadFirmware(prgRom, "SgbBios.sfc", prgSize)) { return true; } MissingFirmwareMessage msg; + msg.Filename = "SgbBios.sfc"; + msg.Firmware = FirmwareType::SGB; + msg.Size = prgSize; + console->GetNotificationManager()->SendNotification(ConsoleNotificationType::MissingFirmware, &msg); + + if(AttemptLoadFirmware(prgRom, "SgbBios.sfc", prgSize)) { + return true; + } + + MessageManager::DisplayMessage("Error", "Could not find firmware file for Super Game Boy"); + return false; + } + + static bool LoadGbBootRom(Console* console, uint8_t** bootRom, FirmwareType type) + { + string filename; + switch(type) { + default: + case FirmwareType::Gameboy: filename = "dmg_boot.bin"; break; + case FirmwareType::GameboyColor: filename = "cgb_boot.bin"; break; + case FirmwareType::SgbGameboyCpu: filename = "sgb_boot.bin"; break; + } + + uint32_t size = type == FirmwareType::GameboyColor ? 2304 : 256; + if(AttemptLoadFirmware(bootRom, filename, size)) { + return true; + } + + /*MissingFirmwareMessage msg; msg.Filename = filename.c_str(); msg.Firmware = type; msg.Size = size; @@ -125,7 +153,7 @@ public: return true; } - MessageManager::DisplayMessage("Error", "Could not find boot rom: " + filename); + MessageManager::DisplayMessage("Error", "Could not find boot rom: " + filename);*/ return false; } }; \ No newline at end of file diff --git a/Core/Gameboy.cpp b/Core/Gameboy.cpp index c4f6eee..3944459 100644 --- a/Core/Gameboy.cpp +++ b/Core/Gameboy.cpp @@ -15,6 +15,8 @@ #include "EmuSettings.h" #include "MessageManager.h" #include "FirmwareHelper.h" +#include "SuperGameboy.h" +#include "GbBootRom.h" #include "../Utilities/VirtualFile.h" #include "../Utilities/Serializer.h" @@ -53,28 +55,53 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile) shared_ptr 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; + GameboyModel model = cfg.GbModel; + if(model == GameboyModel::Auto) { + if((header.CgbFlag & 0x80) != 0) { + model = GameboyModel::GameboyColor; + } else { + model = GameboyModel::SuperGameboy; + } } - gb->_workRamSize = gb->_cgbMode ? 0x8000 : 0x2000; - gb->_videoRamSize = gb->_cgbMode ? 0x4000 : 0x2000; + gb->_model = model; + + bool cgbMode = gb->_model == GameboyModel::GameboyColor; + gb->_workRamSize = cgbMode ? 0x8000 : 0x2000; + gb->_videoRamSize = cgbMode ? 0x4000 : 0x2000; gb->_workRam = new uint8_t[gb->_workRamSize]; gb->_videoRam = new uint8_t[gb->_videoRamSize]; 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; + + FirmwareType type = FirmwareType::Gameboy; + if(gb->_model == GameboyModel::SuperGameboy) { + type = FirmwareType::SgbGameboyCpu; + } else if(gb->_model == GameboyModel::GameboyColor) { + type = FirmwareType::GameboyColor; + } + + gb->_bootRomSize = cgbMode ? 9 * 256 : 256; + if(!FirmwareHelper::LoadGbBootRom(console, &gb->_bootRom, type)) { + switch(gb->_model) { + default: + case GameboyModel::Gameboy: + gb->_bootRom = new uint8_t[gb->_bootRomSize]; + memcpy(gb->_bootRom, dmgBootRom, gb->_bootRomSize); + break; + + case GameboyModel::GameboyColor: + gb->_bootRom = new uint8_t[gb->_bootRomSize]; + memcpy(gb->_bootRom, cgbBootRom, gb->_bootRomSize); + break; + + case GameboyModel::SuperGameboy: + gb->_bootRom = new uint8_t[gb->_bootRomSize]; + memcpy(gb->_bootRom, sgbBootRom, gb->_bootRomSize); + break; } } @@ -84,6 +111,16 @@ Gameboy* Gameboy::Create(Console* console, VirtualFile &romFile) return nullptr; } +Gameboy::Gameboy() +{ + _ppu.reset(new GbPpu()); + _apu.reset(new GbApu()); + _cpu.reset(new GbCpu()); + _memoryManager.reset(new GbMemoryManager()); + _timer.reset(new GbTimer()); + _dmaController.reset(new GbDmaController()); +} + Gameboy::~Gameboy() { SaveBattery(); @@ -100,7 +137,7 @@ Gameboy::~Gameboy() delete[] _bootRom; } -void Gameboy::PowerOn() +void Gameboy::PowerOn(SuperGameboy* superGameboy) { shared_ptr settings = _console->GetSettings(); settings->InitializeRam(_cartRam, _cartRamSize); @@ -114,17 +151,15 @@ void Gameboy::PowerOn() LoadBattery(); - _ppu.reset(new GbPpu()); - _apu.reset(new GbApu(_console, this)); - _memoryManager.reset(new GbMemoryManager()); - _timer.reset(new GbTimer(_memoryManager.get(), _apu.get())); - _dmaController.reset(new GbDmaController()); + _timer->Init(_memoryManager.get(), _apu.get()); + _apu->Init(_console, this); _cart->Init(this, _memoryManager.get()); _memoryManager->Init(_console, this, _cart.get(), _ppu.get(), _apu.get(), _timer.get(), _dmaController.get()); - - _cpu.reset(new GbCpu(_console, this, _memoryManager.get())); + _cpu->Init(_console, this, _memoryManager.get()); _ppu->Init(_console, this, _memoryManager.get(), _dmaController.get(), _videoRam, _spriteRam); _dmaController->Init(_memoryManager.get(), _ppu.get(), _cpu.get()); + + _superGameboy = superGameboy; } void Gameboy::Exec() @@ -134,6 +169,12 @@ void Gameboy::Exec() void Gameboy::Run(uint64_t masterClock) { + if(!(_superGameboy->GetControl() & 0x80)) { + return; + } + + //TODO support SGB2 timings + masterClock = (masterClock - _superGameboy->GetResetClock()) / 5; while(_memoryManager->GetCycleCount() < masterClock) { _cpu->Exec(); } @@ -210,6 +251,11 @@ GbCpu* Gameboy::GetCpu() return _cpu.get(); } +void Gameboy::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount) +{ + _apu->GetSoundSamples(samples, sampleCount); +} + AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr) { AddressInfo addrInfo = { -1, SnesMemoryType::Register }; @@ -269,12 +315,17 @@ GameboyHeader Gameboy::GetHeader() bool Gameboy::IsCgb() { - return _cgbMode; + return _model == GameboyModel::GameboyColor; } -bool Gameboy::UseBootRom() +bool Gameboy::IsSgb() { - return _useBootRom; + return _model == GameboyModel::SuperGameboy; +} + +SuperGameboy* Gameboy::GetSgb() +{ + return _superGameboy; } uint64_t Gameboy::GetCycleCount() diff --git a/Core/Gameboy.h b/Core/Gameboy.h index ecab6e3..b3f07a2 100644 --- a/Core/Gameboy.h +++ b/Core/Gameboy.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "DebugTypes.h" #include "GameboyHeader.h" +#include "SettingTypes.h" #include "../Utilities/ISerializable.h" class Console; @@ -12,6 +13,7 @@ class GbCart; class GbTimer; class GbMemoryManager; class GbDmaController; +class SuperGameboy; class VirtualFile; class Gameboy : public ISerializable @@ -21,6 +23,7 @@ private: static constexpr int HighRamSize = 0x7F; Console* _console = nullptr; + SuperGameboy* _superGameboy = nullptr; unique_ptr _memoryManager; unique_ptr _cpu; @@ -30,9 +33,9 @@ private: unique_ptr _timer; unique_ptr _dmaController; + GameboyModel _model = GameboyModel::Auto; + bool _hasBattery = false; - bool _cgbMode = false; - bool _useBootRom = false; uint8_t* _prgRom = nullptr; uint32_t _prgRomSize = 0; @@ -52,13 +55,15 @@ private: uint8_t* _bootRom = nullptr; uint32_t _bootRomSize = 0; + Gameboy(); + public: static constexpr int HeaderOffset = 0x134; static Gameboy* Create(Console* console, VirtualFile& romFile); virtual ~Gameboy(); - void PowerOn(); + void PowerOn(SuperGameboy* superGameboy = nullptr); void Exec(); void Run(uint64_t masterClock); @@ -68,6 +73,7 @@ public: GbPpu* GetPpu(); GbCpu* GetCpu(); + void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); GbState GetState(); GameboyHeader GetHeader(); @@ -78,7 +84,9 @@ public: int32_t GetRelativeAddress(AddressInfo& absAddress); bool IsCgb(); - bool UseBootRom(); + bool IsSgb(); + SuperGameboy* GetSgb(); + uint64_t GetCycleCount(); uint64_t GetApuCycleCount(); diff --git a/Core/GbApu.cpp b/Core/GbApu.cpp index 9b055fa..267b8e2 100644 --- a/Core/GbApu.cpp +++ b/Core/GbApu.cpp @@ -6,21 +6,42 @@ #include "EmuSettings.h" #include "../Utilities/Serializer.h" -GbApu::GbApu(Console* console, Gameboy* gameboy) +GbApu::GbApu() { + _soundBuffer = new int16_t[GbApu::MaxSamples * 2]; + memset(_soundBuffer, 0, GbApu::MaxSamples * 2 * sizeof(int16_t)); + + _leftChannel = blip_new(GbApu::MaxSamples); + _rightChannel = blip_new(GbApu::MaxSamples); +} + +void GbApu::Init(Console* console, Gameboy* gameboy) +{ + _square1.reset(new GbSquareChannel(this)); + _square2.reset(new GbSquareChannel(this)); + _wave.reset(new GbWaveChannel(this)); + _noise.reset(new GbNoiseChannel(this)); + + _prevLeftOutput = 0; + _prevRightOutput = 0; + _clockCounter = 0; + _prevClockCount = 0; + _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)); + blip_clear(_leftChannel); + blip_clear(_rightChannel); - _leftChannel = blip_new(GbApu::MaxSamples); - _rightChannel = blip_new(GbApu::MaxSamples); - - blip_set_rates(_leftChannel, GbApu::ApuFrequency, GbApu::SampleRate); - blip_set_rates(_rightChannel, GbApu::ApuFrequency, GbApu::SampleRate); + if(_gameboy->IsSgb()) { + blip_set_rates(_leftChannel, _console->GetMasterClockRate() / 5, GbApu::SampleRate); + blip_set_rates(_rightChannel, _console->GetMasterClockRate() / 5, GbApu::SampleRate); + } else { + blip_set_rates(_leftChannel, GbApu::ApuFrequency, GbApu::SampleRate); + blip_set_rates(_rightChannel, GbApu::ApuFrequency, GbApu::SampleRate); + } } GbApu::~GbApu() @@ -34,10 +55,10 @@ GbApuDebugState GbApu::GetState() { GbApuDebugState state; state.Common = _state; - state.Square1 = _square1.GetState(); - state.Square2 = _square2.GetState(); - state.Wave = _wave.GetState(); - state.Noise = _noise.GetState(); + state.Square1 = _square1->GetState(); + state.Square2 = _square2->GetState(); + state.Wave = _wave->GetState(); + state.Noise = _noise->GetState(); return state; } @@ -51,19 +72,19 @@ void GbApu::Run() _clockCounter += clocksToRun; } else { while(clocksToRun > 0) { - uint32_t minTimer = std::min({ clocksToRun, _square1.GetState().Timer, _square2.GetState().Timer, _wave.GetState().Timer, _noise.GetState().Timer }); + uint32_t minTimer = std::min({ clocksToRun, _square1->GetState().Timer, _square2->GetState().Timer, _wave->GetState().Timer, _noise->GetState().Timer }); clocksToRun -= minTimer; - _square1.Exec(minTimer); - _square2.Exec(minTimer); - _wave.Exec(minTimer); - _noise.Exec(minTimer); + _square1->Exec(minTimer); + _square2->Exec(minTimer); + _wave->Exec(minTimer); + _noise->Exec(minTimer); int16_t leftOutput = ( - (_square1.GetOutput() & _state.EnableLeftSq1) + - (_square2.GetOutput() & _state.EnableLeftSq2) + - (_wave.GetOutput() & _state.EnableLeftWave) + - (_noise.GetOutput() & _state.EnableLeftNoise) + (_square1->GetOutput() & _state.EnableLeftSq1) + + (_square2->GetOutput() & _state.EnableLeftSq2) + + (_wave->GetOutput() & _state.EnableLeftWave) + + (_noise->GetOutput() & _state.EnableLeftNoise) ) * (_state.LeftVolume + 1) * 40; if(_prevLeftOutput != leftOutput) { @@ -72,10 +93,10 @@ void GbApu::Run() } int16_t rightOutput = ( - (_square1.GetOutput() & _state.EnableRightSq1) + - (_square2.GetOutput() & _state.EnableRightSq2) + - (_wave.GetOutput() & _state.EnableRightWave) + - (_noise.GetOutput() & _state.EnableRightNoise) + (_square1->GetOutput() & _state.EnableRightSq1) + + (_square2->GetOutput() & _state.EnableRightSq2) + + (_wave->GetOutput() & _state.EnableRightWave) + + (_noise->GetOutput() & _state.EnableRightNoise) ) * (_state.RightVolume + 1) * 40; if(_prevRightOutput != rightOutput) { @@ -87,17 +108,29 @@ void GbApu::Run() } } - if(_clockCounter >= 20000) { + if(!_gameboy->IsSgb() && _clockCounter >= 20000) { blip_end_frame(_leftChannel, _clockCounter); blip_end_frame(_rightChannel, _clockCounter); uint32_t sampleCount = (uint32_t)blip_read_samples(_leftChannel, _soundBuffer, GbApu::MaxSamples, 1); blip_read_samples(_rightChannel, _soundBuffer + 1, GbApu::MaxSamples, 1); - _console->GetSoundMixer()->PlayAudioBuffer(_soundBuffer, sampleCount, GbApu::SampleRate); + _soundMixer->PlayAudioBuffer(_soundBuffer, sampleCount, GbApu::SampleRate); _clockCounter = 0; } } +void GbApu::GetSoundSamples(int16_t* &samples, uint32_t& sampleCount) +{ + Run(); + blip_end_frame(_leftChannel, _clockCounter); + blip_end_frame(_rightChannel, _clockCounter); + + sampleCount = (uint32_t)blip_read_samples(_leftChannel, _soundBuffer, GbApu::MaxSamples, 1); + blip_read_samples(_rightChannel, _soundBuffer + 1, GbApu::MaxSamples, 1); + samples = _soundBuffer; + _clockCounter = 0; +} + void GbApu::ClockFrameSequencer() { Run(); @@ -107,18 +140,18 @@ void GbApu::ClockFrameSequencer() } if((_state.FrameSequenceStep & 0x01) == 0) { - _square1.ClockLengthCounter(); - _square2.ClockLengthCounter(); - _wave.ClockLengthCounter(); - _noise.ClockLengthCounter(); + _square1->ClockLengthCounter(); + _square2->ClockLengthCounter(); + _wave->ClockLengthCounter(); + _noise->ClockLengthCounter(); if((_state.FrameSequenceStep & 0x03) == 2) { - _square1.ClockSweepUnit(); + _square1->ClockSweepUnit(); } } else if(_state.FrameSequenceStep == 7) { - _square1.ClockEnvelope(); - _square2.ClockEnvelope(); - _noise.ClockEnvelope(); + _square1->ClockEnvelope(); + _square2->ClockEnvelope(); + _noise->ClockEnvelope(); } _state.FrameSequenceStep = (_state.FrameSequenceStep + 1) & 0x07; @@ -130,16 +163,16 @@ uint8_t GbApu::Read(uint16_t addr) switch(addr) { case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14: - return _square1.Read(addr - 0xFF10); + return _square1->Read(addr - 0xFF10); case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19: - return _square2.Read(addr - 0xFF15); + return _square2->Read(addr - 0xFF15); case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E: - return _wave.Read(addr - 0xFF1A); + return _wave->Read(addr - 0xFF1A); case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - return _noise.Read(addr - 0xFF1F); + return _noise->Read(addr - 0xFF1F); case 0xFF24: return ( @@ -165,15 +198,15 @@ uint8_t GbApu::Read(uint16_t addr) return ( (_state.ApuEnabled ? 0x80 : 0) | 0x70 | //open bus - ((_state.ApuEnabled && _noise.Enabled()) ? 0x08 : 0) | - ((_state.ApuEnabled && _wave.Enabled()) ? 0x04 : 0) | - ((_state.ApuEnabled && _square2.Enabled()) ? 0x02 : 0) | - ((_state.ApuEnabled && _square1.Enabled()) ? 0x01 : 0) + ((_state.ApuEnabled && _noise->Enabled()) ? 0x08 : 0) | + ((_state.ApuEnabled && _wave->Enabled()) ? 0x04 : 0) | + ((_state.ApuEnabled && _square2->Enabled()) ? 0x02 : 0) | + ((_state.ApuEnabled && _square1->Enabled()) ? 0x01 : 0) ); case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37: case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F: - return _wave.ReadRam(addr); + return _wave->ReadRam(addr); } //Open bus @@ -196,19 +229,19 @@ void GbApu::Write(uint16_t addr, uint8_t value) switch(addr) { case 0xFF10: case 0xFF11: case 0xFF12: case 0xFF13: case 0xFF14: - _square1.Write(addr - 0xFF10, value); + _square1->Write(addr - 0xFF10, value); break; case 0xFF16: case 0xFF17: case 0xFF18: case 0xFF19: - _square2.Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit + _square2->Write(addr - 0xFF15, value); //Same as square1, but without a sweep unit break; case 0xFF1A: case 0xFF1B: case 0xFF1C: case 0xFF1D: case 0xFF1E: - _wave.Write(addr - 0xFF1A, value); + _wave->Write(addr - 0xFF1A, value); break; case 0xFF20: case 0xFF21: case 0xFF22: case 0xFF23: - _noise.Write(addr - 0xFF1F, value); + _noise->Write(addr - 0xFF1F, value); break; case 0xFF24: @@ -234,10 +267,10 @@ void GbApu::Write(uint16_t addr, uint8_t value) bool apuEnabled = (value & 0x80) != 0; if(_state.ApuEnabled != apuEnabled) { if(!apuEnabled) { - _square1.Disable(); - _square2.Disable(); - _wave.Disable(); - _noise.Disable(); + _square1->Disable(); + _square2->Disable(); + _wave->Disable(); + _noise->Disable(); Write(0xFF24, 0); Write(0xFF25, 0); } else { @@ -251,7 +284,7 @@ void GbApu::Write(uint16_t addr, uint8_t value) } case 0xFF30: case 0xFF31: case 0xFF32: case 0xFF33: case 0xFF34: case 0xFF35: case 0xFF36: case 0xFF37: case 0xFF38: case 0xFF39: case 0xFF3A: case 0xFF3B: case 0xFF3C: case 0xFF3D: case 0xFF3E: case 0xFF3F: - _wave.WriteRam(addr, value); + _wave->WriteRam(addr, value); break; } } @@ -288,10 +321,10 @@ void GbApu::Serialize(Serializer& s) _prevLeftOutput, _prevRightOutput, _clockCounter, _prevClockCount ); - s.Stream(&_square1); - s.Stream(&_square2); - s.Stream(&_wave); - s.Stream(&_noise); + s.Stream(_square1.get()); + s.Stream(_square2.get()); + s.Stream(_wave.get()); + s.Stream(_noise.get()); } template void GbApu::ProcessLengthEnableFlag(uint8_t value, uint8_t& length, bool& lengthEnabled, bool& enabled); diff --git a/Core/GbApu.h b/Core/GbApu.h index 2030d0c..155fa8d 100644 --- a/Core/GbApu.h +++ b/Core/GbApu.h @@ -12,18 +12,20 @@ class SoundMixer; class GbApu : public ISerializable { +public: + static constexpr int SampleRate = 96000; + private: static constexpr int ApuFrequency = 1024 * 1024 * 4; //4mhz static constexpr int MaxSamples = 4000; - static constexpr int SampleRate = 96000; Console* _console = nullptr; Gameboy* _gameboy = nullptr; SoundMixer* _soundMixer = nullptr; - GbSquareChannel _square1 = GbSquareChannel(this); - GbSquareChannel _square2 = GbSquareChannel(this); - GbWaveChannel _wave = GbWaveChannel(this); - GbNoiseChannel _noise = GbNoiseChannel(this); + unique_ptr _square1; + unique_ptr _square2; + unique_ptr _wave; + unique_ptr _noise; int16_t* _soundBuffer = nullptr; blip_t* _leftChannel = nullptr; @@ -37,13 +39,17 @@ private: GbApuState _state = {}; public: - GbApu(Console* console, Gameboy* gameboy); + GbApu(); virtual ~GbApu(); + void Init(Console* console, Gameboy* gameboy); + GbApuDebugState GetState(); void Run(); + void GetSoundSamples(int16_t* &samples, uint32_t& sampleCount); + void ClockFrameSequencer(); uint8_t Read(uint16_t addr); diff --git a/Core/GbAssembler.cpp b/Core/GbAssembler.cpp index 57ccaff..0470415 100644 --- a/Core/GbAssembler.cpp +++ b/Core/GbAssembler.cpp @@ -14,6 +14,10 @@ GbAssembler::GbAssembler(shared_ptr labelManager) InitAssembler(); } +GbAssembler::~GbAssembler() +{ +} + void GbAssembler::InitAssembler() { for(int i = 0; i < 512; i++) { @@ -112,7 +116,7 @@ int GbAssembler::ReadValue(string operand, int min, int max, unordered_map '9')) { return -1; } @@ -218,6 +222,9 @@ void GbAssembler::PushWord(uint16_t operand, vector& output, uint32_t& void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector& output, uint32_t& address, unordered_map& localLabels, bool firstPass) { switch(entry.Type) { + default: + break; + case ParamType::Byte: PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address); break; diff --git a/Core/GbAssembler.h b/Core/GbAssembler.h index bd3b768..e18dca3 100644 --- a/Core/GbAssembler.h +++ b/Core/GbAssembler.h @@ -50,6 +50,7 @@ private: public: GbAssembler(shared_ptr labelManager); + virtual ~GbAssembler(); uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode); }; \ No newline at end of file diff --git a/Core/GbBootRom.h b/Core/GbBootRom.h new file mode 100644 index 0000000..f5790fa --- /dev/null +++ b/Core/GbBootRom.h @@ -0,0 +1,250 @@ +#pragma once +#include "stdafx.h" + +//Embedded copies of LIJI32's open source boot roms +//The original source for these is here: https://github.com/LIJI32/SameBoy/tree/master/BootROMs + +uint8_t dmgBootRom[256] = { + 0x31, 0xFE, 0xFF, 0x21, 0x00, 0x80, 0x22, 0xCB, 0x6C, 0x28, 0xFB, 0x3E, + 0x80, 0xE0, 0x26, 0xE0, 0x11, 0x3E, 0xF3, 0xE0, 0x12, 0xE0, 0x25, 0x3E, + 0x77, 0xE0, 0x24, 0x3E, 0xFC, 0xE0, 0x47, 0x11, 0x04, 0x01, 0x21, 0x10, + 0x80, 0x1A, 0x47, 0xCD, 0x82, 0x00, 0xCD, 0x82, 0x00, 0x13, 0x7B, 0xEE, + 0x34, 0x20, 0xF2, 0x11, 0xB1, 0x00, 0x0E, 0x08, 0x1A, 0x13, 0x22, 0x23, + 0x0D, 0x20, 0xF9, 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, + 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20, 0xF9, 0x2E, 0x0F, 0x18, 0xF5, + 0x3E, 0x91, 0xE0, 0x40, 0x06, 0x2D, 0xCD, 0xA3, 0x00, 0x3E, 0x83, 0xCD, + 0xAA, 0x00, 0x06, 0x05, 0xCD, 0xA3, 0x00, 0x3E, 0xC1, 0xCD, 0xAA, 0x00, + 0x06, 0x46, 0xCD, 0xA3, 0x00, 0x21, 0xB0, 0x01, 0xE5, 0xF1, 0x21, 0x4D, + 0x01, 0x01, 0x13, 0x00, 0x11, 0xD8, 0x00, 0xC3, 0xFE, 0x00, 0x3E, 0x04, + 0x0E, 0x00, 0xCB, 0x20, 0xF5, 0xCB, 0x11, 0xF1, 0xCB, 0x11, 0x3D, 0x20, + 0xF5, 0x79, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xE5, 0x21, 0x0F, 0xFF, 0xCB, + 0x86, 0xCB, 0x46, 0x28, 0xFC, 0xE1, 0xC9, 0xCD, 0x97, 0x00, 0x05, 0x20, + 0xFA, 0xC9, 0xE0, 0x13, 0x3E, 0x87, 0xE0, 0x14, 0xC9, 0x3C, 0x42, 0xB9, + 0xA5, 0xB9, 0xA5, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x50 +}; + +uint8_t sgbBootRom[256] = { + 0x31, 0xFE, 0xFF, 0x21, 0x00, 0x80, 0x22, 0xCB, 0x6C, 0x28, 0xFB, 0x3E, + 0x80, 0xE0, 0x26, 0xE0, 0x11, 0x3E, 0xF3, 0xE0, 0x12, 0xE0, 0x25, 0x3E, + 0x77, 0xE0, 0x24, 0x3E, 0x00, 0xE0, 0x47, 0x11, 0x04, 0x01, 0x21, 0x10, + 0x80, 0x1A, 0x47, 0xCD, 0xC9, 0x00, 0xCD, 0xC9, 0x00, 0x13, 0x7B, 0xEE, + 0x34, 0x20, 0xF2, 0x11, 0xEA, 0x00, 0x0E, 0x08, 0x1A, 0x13, 0x22, 0x23, + 0x0D, 0x20, 0xF9, 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, + 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20, 0xF9, 0x2E, 0x0F, 0x18, 0xF5, + 0x3E, 0x91, 0xE0, 0x40, 0x3E, 0xF1, 0xE0, 0x80, 0x21, 0x04, 0x01, 0xAF, + 0x4F, 0xAF, 0xE2, 0x3E, 0x30, 0xE2, 0xF0, 0x80, 0xCD, 0xB7, 0x00, 0xE5, + 0x06, 0x0E, 0x16, 0x00, 0xCD, 0xAD, 0x00, 0x82, 0x57, 0x05, 0x20, 0xF8, + 0xCD, 0xB7, 0x00, 0xE1, 0x06, 0x0E, 0xCD, 0xAD, 0x00, 0xCD, 0xB7, 0x00, + 0x05, 0x20, 0xF7, 0x3E, 0x20, 0xE2, 0x3E, 0x30, 0xE2, 0xF0, 0x80, 0xC6, + 0x02, 0xE0, 0x80, 0x3E, 0x58, 0xBD, 0x20, 0xC9, 0x0E, 0x13, 0x3E, 0xC1, + 0xE2, 0x0C, 0x3E, 0x07, 0xE2, 0x3E, 0xFC, 0xE0, 0x47, 0x3E, 0x01, 0x21, + 0x60, 0xC0, 0xC3, 0xFE, 0x00, 0x3E, 0x4F, 0xBD, 0x38, 0x02, 0x2A, 0xC9, + 0x23, 0xAF, 0xC9, 0x5F, 0x16, 0x08, 0x3E, 0x10, 0xCB, 0x1B, 0x38, 0x01, + 0x87, 0xE2, 0x3E, 0x30, 0xE2, 0x15, 0xC8, 0x18, 0xF1, 0x3E, 0x04, 0x0E, + 0x00, 0xCB, 0x20, 0xF5, 0xCB, 0x11, 0xF1, 0xCB, 0x11, 0x3D, 0x20, 0xF5, + 0x79, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xE5, 0x21, 0x0F, 0xFF, 0xCB, 0x86, + 0xCB, 0x46, 0x28, 0xFC, 0xE1, 0xC9, 0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, + 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x50 +}; + +uint8_t cgbBootRom[2304] = { + 0x31, 0xFE, 0xFF, 0xCD, 0x26, 0x06, 0x3E, 0x02, 0x0E, 0x70, 0xE2, 0x26, + 0xD0, 0xCD, 0x29, 0x06, 0xE2, 0x26, 0xFE, 0x0E, 0xA0, 0x22, 0x0D, 0x20, + 0xFC, 0x0E, 0x10, 0x22, 0x2F, 0x0D, 0x20, 0xFB, 0xE0, 0xC1, 0xE0, 0x80, + 0x3E, 0x80, 0xE0, 0x26, 0xE0, 0x11, 0x3E, 0xF3, 0xE0, 0x12, 0xE0, 0x25, + 0x3E, 0x77, 0xE0, 0x24, 0x21, 0x30, 0xFF, 0x3E, 0xFC, 0xE0, 0x47, 0x11, + 0x04, 0x01, 0x21, 0x10, 0x80, 0x1A, 0x47, 0xCD, 0xF1, 0x05, 0x13, 0x7B, + 0xFE, 0x34, 0x20, 0xF5, 0xCD, 0xAE, 0x06, 0x3E, 0x01, 0xE0, 0x4F, 0xCD, + 0x26, 0x06, 0xCD, 0x53, 0x06, 0x06, 0x03, 0xAF, 0xE0, 0x4F, 0x11, 0xE1, + 0x05, 0x0E, 0x08, 0x21, 0x81, 0xFF, 0xAF, 0x2F, 0x22, 0x22, 0x1A, 0x1C, + 0xF6, 0x20, 0x47, 0x1A, 0x1D, 0xF6, 0x84, 0x1F, 0xCB, 0x18, 0x70, 0x2C, + 0x22, 0xAF, 0x22, 0x22, 0x1A, 0x1C, 0x22, 0x1A, 0x1C, 0x22, 0xAF, 0x0D, + 0x20, 0xE1, 0xCD, 0xC6, 0x07, 0x3E, 0x91, 0xE0, 0x40, 0x3E, 0xC1, 0xCD, + 0x1F, 0x06, 0xCD, 0xE4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x16, 0x36, + 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, 0x58, 0xC9, 0x3E, 0x70, + 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, 0x75, 0x95, 0x99, 0x34, + 0x6F, 0x15, 0xFF, 0x97, 0x4B, 0x90, 0x17, 0x10, 0x39, 0xF7, 0xF6, 0xA2, + 0x49, 0x4E, 0xC3, 0x68, 0xE0, 0x8B, 0xF0, 0xCE, 0x0C, 0x29, 0xE8, 0xB7, + 0x86, 0x9A, 0x52, 0x01, 0x9D, 0x71, 0x9C, 0xBD, 0x5D, 0x6D, 0x67, 0x3F, + 0x6B, 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, 0x61, 0x18, 0x66, 0x6A, + 0xBF, 0x0D, 0xF4, 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, 0x61, 0x18, + 0x66, 0x6A, 0xBF, 0x0D, 0xF4, 0xB3, 0x00, 0x04, 0x05, 0x23, 0x22, 0x03, + 0x1F, 0x0F, 0x0A, 0x05, 0x13, 0x24, 0x87, 0x25, 0x1E, 0x2C, 0x15, 0x20, + 0x1F, 0x14, 0x05, 0x21, 0x0D, 0x0E, 0x05, 0x1D, 0x05, 0x12, 0x09, 0x03, + 0x02, 0x1A, 0x19, 0x19, 0x29, 0x2A, 0x1A, 0x2D, 0x2A, 0x2D, 0x24, 0x26, + 0x1A, 0x2A, 0x1E, 0x29, 0x22, 0x22, 0x05, 0x2A, 0x06, 0x05, 0x21, 0x19, + 0x2A, 0x2A, 0x28, 0x02, 0x10, 0x19, 0x2A, 0x2A, 0x05, 0x00, 0x27, 0x24, + 0x16, 0x19, 0x06, 0x20, 0x0C, 0x24, 0x0B, 0x27, 0x12, 0x27, 0x18, 0x1F, + 0x32, 0x11, 0x2E, 0x06, 0x1B, 0x00, 0x2F, 0x29, 0x29, 0x00, 0x00, 0x13, + 0x22, 0x17, 0x12, 0x1D, 0x42, 0x45, 0x46, 0x41, 0x41, 0x52, 0x42, 0x45, + 0x4B, 0x45, 0x4B, 0x20, 0x52, 0x2D, 0x55, 0x52, 0x41, 0x52, 0x20, 0x49, + 0x4E, 0x41, 0x49, 0x4C, 0x49, 0x43, 0x45, 0x20, 0x52, 0x20, 0x20, 0xE8, + 0x90, 0x90, 0x90, 0xA0, 0xA0, 0xA0, 0xC0, 0xC0, 0xC0, 0x48, 0x48, 0x48, + 0x00, 0x00, 0x00, 0xD8, 0xD8, 0xD8, 0x28, 0x28, 0x28, 0x60, 0x60, 0x60, + 0xD0, 0xD0, 0xD0, 0x80, 0x40, 0x40, 0x20, 0xE0, 0xE0, 0x20, 0x10, 0x10, + 0x18, 0x20, 0x20, 0x20, 0xE8, 0xE8, 0xE0, 0x20, 0xE0, 0x10, 0x88, 0x10, + 0x80, 0x80, 0x40, 0x20, 0x20, 0x38, 0x20, 0x20, 0x90, 0x20, 0x20, 0xA0, + 0x98, 0x98, 0x48, 0x1E, 0x1E, 0x58, 0x88, 0x88, 0x10, 0x20, 0x20, 0x10, + 0x20, 0x20, 0x18, 0xE0, 0xE0, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, + 0x90, 0xB0, 0x90, 0xA0, 0xB0, 0xA0, 0xC0, 0xB0, 0xC0, 0x80, 0xB0, 0x40, + 0x88, 0x20, 0x68, 0xDE, 0x00, 0x70, 0xDE, 0x20, 0x78, 0x98, 0xB0, 0x48, + 0x80, 0xE0, 0x50, 0x20, 0xB8, 0xE0, 0x88, 0xB0, 0x10, 0x20, 0x00, 0x10, + 0x20, 0xE0, 0x18, 0xE0, 0x18, 0x00, 0x18, 0xE0, 0x20, 0xA8, 0xE0, 0x20, + 0x18, 0xE0, 0x00, 0xC8, 0x18, 0xE0, 0x00, 0xE0, 0x40, 0x20, 0x18, 0xE0, + 0xE0, 0x18, 0x30, 0x20, 0xE0, 0xE8, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0xF8, + 0xE0, 0x20, 0x08, 0x00, 0x00, 0x10, 0xFF, 0x7F, 0xBF, 0x32, 0xD0, 0x00, + 0x00, 0x00, 0x9F, 0x63, 0x79, 0x42, 0xB0, 0x15, 0xCB, 0x04, 0xFF, 0x7F, + 0x31, 0x6E, 0x4A, 0x45, 0x00, 0x00, 0xFF, 0x7F, 0xEF, 0x1B, 0x00, 0x02, + 0x00, 0x00, 0xFF, 0x7F, 0x1F, 0x42, 0xF2, 0x1C, 0x00, 0x00, 0xFF, 0x7F, + 0x94, 0x52, 0x4A, 0x29, 0x00, 0x00, 0xFF, 0x7F, 0xFF, 0x03, 0x2F, 0x01, + 0x00, 0x00, 0xFF, 0x7F, 0xEF, 0x03, 0xD6, 0x01, 0x00, 0x00, 0xFF, 0x7F, + 0xB5, 0x42, 0xC8, 0x3D, 0x00, 0x00, 0x74, 0x7E, 0xFF, 0x03, 0x80, 0x01, + 0x00, 0x00, 0xFF, 0x67, 0xAC, 0x77, 0x13, 0x1A, 0x6B, 0x2D, 0xD6, 0x7E, + 0xFF, 0x4B, 0x75, 0x21, 0x00, 0x00, 0xFF, 0x53, 0x5F, 0x4A, 0x52, 0x7E, + 0x00, 0x00, 0xFF, 0x4F, 0xD2, 0x7E, 0x4C, 0x3A, 0xE0, 0x1C, 0xED, 0x03, + 0xFF, 0x7F, 0x5F, 0x25, 0x00, 0x00, 0x6A, 0x03, 0x1F, 0x02, 0xFF, 0x03, + 0xFF, 0x7F, 0xFF, 0x7F, 0xDF, 0x01, 0x12, 0x01, 0x00, 0x00, 0x1F, 0x23, + 0x5F, 0x03, 0xF2, 0x00, 0x09, 0x00, 0xFF, 0x7F, 0xEA, 0x03, 0x1F, 0x01, + 0x00, 0x00, 0x9F, 0x29, 0x1A, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFF, 0x7F, + 0x7F, 0x02, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xE0, 0x03, 0x06, 0x02, + 0x20, 0x01, 0xFF, 0x7F, 0xEB, 0x7E, 0x1F, 0x00, 0x00, 0x7C, 0xFF, 0x7F, + 0xFF, 0x3F, 0x00, 0x7E, 0x1F, 0x00, 0xFF, 0x7F, 0xFF, 0x03, 0x1F, 0x00, + 0x00, 0x00, 0xFF, 0x03, 0x1F, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFF, 0x7F, + 0x3F, 0x03, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7F, 0x03, + 0xFF, 0x7F, 0xFF, 0x7F, 0x8C, 0x7E, 0x00, 0x7C, 0x00, 0x00, 0xFF, 0x7F, + 0xEF, 0x1B, 0x80, 0x61, 0x00, 0x00, 0xFF, 0x7F, 0xEA, 0x7F, 0x5F, 0x7D, + 0x00, 0x00, 0x78, 0x47, 0x90, 0x32, 0x87, 0x1D, 0x61, 0x08, 0x03, 0x90, + 0x0F, 0x18, 0x00, 0x78, 0x81, 0x09, 0x12, 0x15, 0x54, 0x93, 0x99, 0x9C, + 0x9F, 0xA2, 0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x3C, 0x33, 0x00, + 0x03, 0x1C, 0x0F, 0x1F, 0x7B, 0x1C, 0x3E, 0x3C, 0xFD, 0xB6, 0xF7, 0xF7, + 0x71, 0x01, 0x7F, 0xFC, 0x30, 0xC0, 0x7F, 0x78, 0xFF, 0xFD, 0xDD, 0xCF, + 0x00, 0x23, 0x60, 0xFC, 0x6F, 0xD4, 0xBC, 0x35, 0x08, 0xFF, 0xC8, 0x80, + 0xF0, 0x53, 0xF8, 0x6A, 0xDF, 0x7C, 0x3D, 0x81, 0x7D, 0x79, 0x3C, 0xF3, + 0x43, 0xE7, 0x0F, 0xC7, 0x00, 0xFC, 0x01, 0xD2, 0xB4, 0xAD, 0x2B, 0x41, + 0x0E, 0x34, 0x13, 0x1C, 0x41, 0x38, 0x31, 0xFF, 0xEF, 0xF3, 0xE0, 0x5F, + 0xD7, 0xD7, 0xFF, 0x3F, 0xE0, 0xF6, 0xAF, 0xDA, 0x9F, 0xFD, 0xA9, 0xE8, + 0xFC, 0xDA, 0xBC, 0x3E, 0x7D, 0xA9, 0xE8, 0x00, 0xFF, 0xCF, 0x1F, 0xFF, + 0xFD, 0x28, 0x1D, 0x80, 0x1C, 0x3D, 0x3C, 0xFF, 0xF4, 0x2A, 0x38, 0xA9, + 0x3F, 0xFF, 0x40, 0x70, 0x00, 0xFF, 0xC5, 0xC0, 0xBF, 0xF6, 0xAA, 0xCF, + 0xE1, 0xD2, 0x00, 0xF3, 0xE3, 0xF7, 0xF3, 0xB4, 0x27, 0x77, 0x5F, 0xF5, + 0xFC, 0x38, 0x48, 0x00, 0xFF, 0xC7, 0x3F, 0xB4, 0xAD, 0x28, 0xEF, 0xAF, + 0xC4, 0xCF, 0x20, 0xCE, 0x8E, 0x9F, 0x90, 0x1E, 0xFF, 0xFF, 0x42, 0x1C, + 0xA9, 0x33, 0x00, 0xFF, 0x09, 0x9F, 0x8F, 0xE2, 0x1F, 0x5F, 0xFD, 0x48, + 0x3E, 0x3F, 0xA7, 0xBF, 0xCF, 0x3C, 0x42, 0x38, 0xA8, 0x7F, 0xAF, 0xFC, + 0x00, 0xFF, 0xCF, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xCA, 0xFE, 0xFF, 0xD4, + 0x00, 0xFF, 0xFF, 0x2B, 0xFE, 0xFD, 0x4F, 0x00, 0xFC, 0xFC, 0x53, 0xFF, + 0xFC, 0x0F, 0xF7, 0xFD, 0x30, 0xFF, 0x1E, 0x3D, 0xFC, 0x45, 0xFF, 0x87, + 0x1F, 0xF7, 0xBF, 0x03, 0xFF, 0x3F, 0xFE, 0x5D, 0x54, 0x00, 0xFF, 0xFC, + 0x01, 0xC0, 0x83, 0x03, 0x87, 0xD3, 0x4F, 0x54, 0x8F, 0x3C, 0xD2, 0xAA, + 0x2A, 0xFC, 0x06, 0xBE, 0x3E, 0xDF, 0xDF, 0xDD, 0xCF, 0x00, 0xC8, 0x0E, + 0xFF, 0x7B, 0xFC, 0xF3, 0x15, 0xC0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, + 0x03, 0xC2, 0xFF, 0x87, 0xFF, 0x50, 0xF8, 0x00, 0xFF, 0x03, 0xC7, 0x83, + 0xE3, 0x61, 0xF1, 0xB6, 0x53, 0x7C, 0xDF, 0xDA, 0xAF, 0xF4, 0xA5, 0x4A, + 0xD7, 0xD7, 0x55, 0xD7, 0xFF, 0xF1, 0xE0, 0x6F, 0xDB, 0xF0, 0xF9, 0xF1, + 0x00, 0xFB, 0xF9, 0x7F, 0x7B, 0xB7, 0xFF, 0x3F, 0x1E, 0xD0, 0x1C, 0xAA, + 0xA4, 0xFF, 0xCF, 0x00, 0xFC, 0x3F, 0x13, 0x1E, 0x31, 0x7C, 0xF8, 0xE5, + 0xF5, 0xF5, 0xD7, 0xD7, 0x01, 0xFF, 0x7F, 0x4F, 0x77, 0xC7, 0x22, 0x9F, + 0x03, 0x7D, 0x01, 0x1D, 0x24, 0x38, 0x6D, 0x02, 0x71, 0xCD, 0xF4, 0x05, + 0x3E, 0x04, 0x0E, 0x00, 0xCB, 0x20, 0xF5, 0xCB, 0x11, 0xF1, 0xCB, 0x11, + 0x3D, 0x20, 0xF5, 0x79, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xE5, 0x21, 0x0F, + 0xFF, 0xCB, 0x86, 0xCB, 0x46, 0x28, 0xFC, 0xE1, 0xC9, 0xCD, 0xEA, 0x07, + 0xCD, 0x09, 0x06, 0x05, 0x20, 0xF7, 0xC9, 0xE0, 0x13, 0x3E, 0x87, 0xE0, + 0x14, 0xC9, 0x21, 0x00, 0x80, 0xAF, 0x22, 0xCB, 0x6C, 0x28, 0xFA, 0xC9, + 0xCD, 0x33, 0x06, 0x1A, 0xA1, 0x47, 0x1C, 0x1C, 0x1A, 0x1D, 0x1D, 0xA1, + 0xCB, 0x37, 0xB0, 0xCB, 0x41, 0x28, 0x02, 0xCB, 0x37, 0x23, 0x22, 0xCB, + 0x31, 0xC9, 0xCD, 0x4D, 0x06, 0xCD, 0x30, 0x06, 0x1C, 0x7B, 0xC9, 0x21, + 0x96, 0x04, 0x11, 0x7F, 0x80, 0x0E, 0x30, 0x46, 0x05, 0x28, 0x36, 0x04, + 0x23, 0x37, 0xCB, 0x10, 0x38, 0x20, 0xCB, 0x20, 0x38, 0x03, 0x2A, 0x18, + 0x20, 0xCB, 0x20, 0x20, 0x05, 0x46, 0x23, 0x37, 0xCB, 0x10, 0x4F, 0x30, + 0x03, 0xCB, 0x3F, 0xFE, 0x87, 0xCB, 0x20, 0x38, 0x02, 0xB1, 0xFE, 0xA1, + 0x18, 0x07, 0xCB, 0x20, 0x38, 0x03, 0x1B, 0x1A, 0x13, 0x13, 0x12, 0xCB, + 0x20, 0x20, 0xD1, 0x18, 0xC6, 0x62, 0x2E, 0x80, 0x11, 0x04, 0x01, 0x0E, + 0xF0, 0xCD, 0x4A, 0x06, 0xC6, 0x16, 0x5F, 0xCD, 0x4A, 0x06, 0xD6, 0x16, + 0x5F, 0xFE, 0x1C, 0x20, 0xEE, 0x23, 0x11, 0x8E, 0x04, 0x0E, 0x08, 0x1A, + 0x13, 0x22, 0x23, 0x0D, 0x20, 0xF9, 0xC9, 0x3E, 0x01, 0xE0, 0x4F, 0x16, + 0x1A, 0x06, 0x02, 0xCD, 0x15, 0x06, 0x21, 0xC0, 0x98, 0x0E, 0x03, 0x7E, + 0xFE, 0x0F, 0x28, 0x05, 0x34, 0xE6, 0x07, 0x28, 0x03, 0x23, 0x18, 0xF3, + 0x7D, 0xF6, 0x1F, 0x6F, 0x23, 0x0D, 0x20, 0xEB, 0x15, 0x20, 0xDE, 0xC9, + 0x3E, 0x01, 0xCD, 0xDA, 0x07, 0xCD, 0xDF, 0x07, 0xCD, 0xDA, 0x07, 0x3E, + 0xFF, 0xE0, 0x00, 0x57, 0x59, 0x2E, 0x0D, 0xFA, 0x43, 0x01, 0xCB, 0x7F, + 0xCC, 0x24, 0x07, 0xCB, 0x7F, 0xE0, 0x4C, 0xF0, 0x80, 0x47, 0x28, 0x05, + 0xF0, 0xC1, 0xA7, 0x20, 0x06, 0xAF, 0x4F, 0x3E, 0x11, 0x61, 0xC9, 0xCD, + 0x24, 0x07, 0xE0, 0x4C, 0x3E, 0x01, 0xC9, 0x21, 0x7D, 0x04, 0x4F, 0x06, + 0x00, 0x09, 0x7E, 0xC9, 0x3E, 0x01, 0xE0, 0x6C, 0xCD, 0x4C, 0x07, 0xCB, + 0x7F, 0xC4, 0x8A, 0x08, 0xE6, 0x7F, 0x47, 0xF0, 0xC1, 0xA7, 0x28, 0x05, + 0xCD, 0x1B, 0x07, 0x18, 0x01, 0x78, 0xCD, 0x09, 0x06, 0xCD, 0xA1, 0x07, + 0x3E, 0x04, 0x11, 0x08, 0x00, 0x2E, 0x7C, 0xC9, 0x21, 0x4B, 0x01, 0x7E, + 0xFE, 0x33, 0x28, 0x05, 0x3D, 0x20, 0x40, 0x18, 0x0C, 0x2E, 0x44, 0x2A, + 0xFE, 0x30, 0x20, 0x37, 0x7E, 0xFE, 0x31, 0x20, 0x32, 0x2E, 0x34, 0x0E, + 0x10, 0xAF, 0x86, 0x2C, 0x0D, 0x20, 0xFB, 0x47, 0x21, 0x00, 0x02, 0x7D, + 0xD6, 0x5E, 0xC8, 0x2A, 0xB8, 0x20, 0xF8, 0x7D, 0xD6, 0x41, 0x38, 0x0E, + 0xE5, 0x7D, 0xC6, 0x7A, 0x6F, 0x7E, 0xE1, 0x4F, 0xFA, 0x37, 0x01, 0xB9, + 0x20, 0xE5, 0x7D, 0xC6, 0x5D, 0x6F, 0x78, 0xE0, 0x80, 0x7E, 0xC9, 0xAF, + 0xC9, 0x21, 0xD9, 0x02, 0x06, 0x00, 0x4F, 0x09, 0xC9, 0xCD, 0x99, 0x07, + 0x1E, 0x00, 0x2A, 0xE5, 0x21, 0x7E, 0x03, 0x4F, 0x09, 0x16, 0x08, 0x0E, + 0x6A, 0xCD, 0xCF, 0x07, 0xE1, 0xCB, 0x5B, 0x20, 0x04, 0x1E, 0x08, 0x18, + 0xE9, 0x4E, 0x21, 0x7E, 0x03, 0x09, 0x16, 0x08, 0x18, 0x05, 0x21, 0x81, + 0xFF, 0x16, 0x40, 0x1E, 0x00, 0x0E, 0x68, 0x3E, 0x80, 0xB3, 0xE2, 0x0C, + 0x2A, 0xE2, 0x15, 0x20, 0xFB, 0xC9, 0xE0, 0x4F, 0x21, 0xA5, 0x08, 0x0E, + 0x51, 0x06, 0x05, 0x2A, 0xE2, 0x0C, 0x05, 0x20, 0xFA, 0xC9, 0x3E, 0x20, + 0xE0, 0x00, 0xF0, 0x00, 0x2F, 0xE6, 0x0F, 0xC8, 0x2E, 0x00, 0x2C, 0x1F, + 0x30, 0xFC, 0x3E, 0x10, 0xE0, 0x00, 0xF0, 0x00, 0x2F, 0x17, 0x17, 0xE6, + 0x0C, 0x85, 0x6F, 0xF0, 0xC1, 0xBD, 0xC8, 0x7D, 0xE0, 0xC1, 0xC5, 0xD5, + 0xCD, 0x1B, 0x07, 0xCD, 0x99, 0x07, 0x2C, 0x2C, 0x4E, 0x21, 0x7F, 0x03, + 0x09, 0x3A, 0xFE, 0x7F, 0x20, 0x02, 0x23, 0x23, 0xF5, 0x2A, 0xE5, 0x21, + 0x81, 0xFF, 0xCD, 0x80, 0x08, 0x2E, 0x83, 0xCD, 0x80, 0x08, 0xE1, 0xE0, + 0x87, 0x2A, 0xE5, 0x21, 0x82, 0xFF, 0xCD, 0x80, 0x08, 0x2E, 0x84, 0xCD, + 0x80, 0x08, 0xE1, 0xE0, 0x88, 0xF1, 0x28, 0x02, 0x23, 0x23, 0xF0, 0xBB, + 0xE6, 0xDE, 0x47, 0x2A, 0xE6, 0xDE, 0x80, 0x47, 0xFA, 0xBC, 0xFF, 0xCB, + 0x97, 0x4E, 0xCB, 0x91, 0x89, 0x1F, 0xEA, 0xBC, 0xFF, 0x78, 0x1F, 0xEA, + 0xBB, 0xFF, 0x2D, 0x2A, 0xE0, 0xBF, 0x2A, 0xE0, 0xC0, 0x2A, 0xE0, 0x85, + 0x2A, 0xE0, 0x86, 0xCD, 0x09, 0x06, 0xCD, 0xC6, 0x07, 0x3E, 0x2D, 0xE0, + 0xC2, 0xD1, 0xC1, 0xC9, 0x11, 0x08, 0x00, 0x4B, 0x77, 0x19, 0x0D, 0x20, + 0xFB, 0xC9, 0xF5, 0xCD, 0x09, 0x06, 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, + 0x2F, 0x99, 0x0E, 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20, 0xF9, 0x2E, + 0x0F, 0x18, 0xF5, 0xF1, 0xC9, 0x88, 0x00, 0x98, 0xA0, 0x12, 0x88, 0x00, + 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index 64a71a5..87ccb6c 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -5,7 +5,7 @@ #include "GbMemoryManager.h" #include "../Utilities/Serializer.h" -GbCpu::GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager) +void GbCpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager) { _console = console; _gameboy = gameboy; @@ -13,21 +13,8 @@ GbCpu::GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager) _state = {}; - 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 = _gameboy->IsCgb() ? 0x00 : 0x13; - _state.D = 0x00; - _state.E = _gameboy->IsCgb() ? 0x08 : 0xD8; - _state.H = _gameboy->IsCgb() ? 0x00 : 0x01; - _state.L = _gameboy->IsCgb() ? 0x7C : 0x4D; - _state.Flags = _gameboy->IsCgb() ? 0x80 : 0xB0; - } + _state.PC = 0; + _state.SP = 0xFFFF; } GbCpu::~GbCpu() diff --git a/Core/GbCpu.h b/Core/GbCpu.h index a4efac3..580fecb 100644 --- a/Core/GbCpu.h +++ b/Core/GbCpu.h @@ -140,9 +140,10 @@ private: void PREFIX(); public: - GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager); virtual ~GbCpu(); + void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager); + GbCpuState GetState(); bool IsHalted(); diff --git a/Core/GbDebugger.cpp b/Core/GbDebugger.cpp index 1cb2768..28eba6c 100644 --- a/Core/GbDebugger.cpp +++ b/Core/GbDebugger.cpp @@ -188,9 +188,8 @@ void GbDebugger::Step(int32_t stepCount, StepType type) } break; - case StepType::SpecificScanline: - case StepType::PpuStep: - break; + case StepType::PpuStep: step.PpuStepCount = stepCount; _step.reset(new StepRequest(step)); break; + case StepType::SpecificScanline: step.BreakScanline = stepCount; _step.reset(new StepRequest(step)); break; } _step.reset(new StepRequest(step)); @@ -205,6 +204,21 @@ void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc) _eventManager->AddEvent(DebugEventType::Irq); } +void GbDebugger::ProcessPpuCycle(uint16_t scanline, uint16_t cycle) +{ + if(_step->PpuStepCount > 0) { + _step->PpuStepCount--; + if(_step->PpuStepCount == 0) { + _debugger->SleepUntilResume(BreakSource::PpuStep); + } + } + + if(cycle == 0 && scanline == _step->BreakScanline) { + _step->BreakScanline = -1; + _debugger->SleepUntilResume(BreakSource::PpuStep); + } +} + shared_ptr GbDebugger::GetEventManager() { return _eventManager; diff --git a/Core/GbDebugger.h b/Core/GbDebugger.h index f862a75..8a9090a 100644 --- a/Core/GbDebugger.h +++ b/Core/GbDebugger.h @@ -48,6 +48,7 @@ public: void Run(); void Step(int32_t stepCount, StepType type); void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc); + void ProcessPpuCycle(uint16_t scanline, uint16_t cycle); shared_ptr GetEventManager(); shared_ptr GetAssembler(); diff --git a/Core/GbMemoryManager.cpp b/Core/GbMemoryManager.cpp index ee6927e..a234280 100644 --- a/Core/GbMemoryManager.cpp +++ b/Core/GbMemoryManager.cpp @@ -11,6 +11,8 @@ #include "EmuSettings.h" #include "ControlManager.h" #include "SnesController.h" +#include "BaseCartridge.h" +#include "SuperGameboy.h" #include "MessageManager.h" #include "../Utilities/VirtualFile.h" #include "../Utilities/Serializer.h" @@ -30,14 +32,13 @@ void GbMemoryManager::Init(Console* console, Gameboy* gameboy, GbCart* cart, GbP _controlManager = console->GetControlManager().get(); _settings = console->GetSettings().get(); + memset(_reads, 0, sizeof(_reads)); + memset(_writes, 0, sizeof(_writes)); + _state = {}; _state.CgbWorkRamBank = 1; - _state.DisableBootRom = !_gameboy->UseBootRom(); - if(_gameboy->UseBootRom()) { - _state.CycleCount = 8; //Makes boot_sclk_align serial test pass - } else { - _state.CycleCount = _gameboy->IsCgb() ? 13051516 : 23440332; - } + _state.DisableBootRom = false; + _state.CycleCount = 8; //Makes boot_sclk_align serial test pass MapRegisters(0x8000, 0x9FFF, RegisterAccess::ReadWrite); MapRegisters(0xFE00, 0xFFFF, RegisterAccess::ReadWrite); @@ -343,7 +344,7 @@ void GbMemoryManager::WriteRegister(uint16_t addr, uint8_t value) } else { //00-0F switch(addr) { - case 0xFF00: _state.InputSelect = value; break; + case 0xFF00: WriteInputPort(value); break; case 0xFF01: _state.SerialData = value; break; //FF01 - SB - Serial transfer data (R/W) case 0xFF02: //FF02 - SC - Serial Transfer Control (R/W) @@ -431,26 +432,49 @@ uint8_t GbMemoryManager::ReadInputPort() //Bit 2 - P12 Input Up or Select (0=Pressed) (Read Only) //Bit 1 - P11 Input Left or Button B (0=Pressed) (Read Only) //Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only) - BaseControlDevice* controller = (SnesController*)_controlManager->GetControlDevice(0).get(); uint8_t result = 0x0F; - if(controller && controller->GetControllerType() == ControllerType::SnesController) { - if(!(_state.InputSelect & 0x20)) { - result &= ~(controller->IsPressed(SnesController::A) ? 0x01 : 0); - result &= ~(controller->IsPressed(SnesController::B) ? 0x02 : 0); - result &= ~(controller->IsPressed(SnesController::Select) ? 0x04 : 0); - result &= ~(controller->IsPressed(SnesController::Start) ? 0x08 : 0); + + if(_gameboy->IsSgb()) { + SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); + if((_state.InputSelect & 0x30) == 0x30) { + result = sgb->GetInputIndex(); + } else { + if(!(_state.InputSelect & 0x20)) { + result &= sgb->GetInput() >> 4; + } + if(!(_state.InputSelect & 0x10)) { + result &= sgb->GetInput() & 0x0F; + } } - if(!(_state.InputSelect & 0x10)) { - result &= ~(controller->IsPressed(SnesController::Right) ? 0x01 : 0); - result &= ~(controller->IsPressed(SnesController::Left) ? 0x02 : 0); - result &= ~(controller->IsPressed(SnesController::Up) ? 0x04 : 0); - result &= ~(controller->IsPressed(SnesController::Down) ? 0x08 : 0); + } else { + BaseControlDevice* controller = (SnesController*)_controlManager->GetControlDevice(0).get(); + if(controller && controller->GetControllerType() == ControllerType::SnesController) { + if(!(_state.InputSelect & 0x20)) { + result &= ~(controller->IsPressed(SnesController::A) ? 0x01 : 0); + result &= ~(controller->IsPressed(SnesController::B) ? 0x02 : 0); + result &= ~(controller->IsPressed(SnesController::Select) ? 0x04 : 0); + result &= ~(controller->IsPressed(SnesController::Start) ? 0x08 : 0); + } + if(!(_state.InputSelect & 0x10)) { + result &= ~(controller->IsPressed(SnesController::Right) ? 0x01 : 0); + result &= ~(controller->IsPressed(SnesController::Left) ? 0x02 : 0); + result &= ~(controller->IsPressed(SnesController::Up) ? 0x04 : 0); + result &= ~(controller->IsPressed(SnesController::Down) ? 0x08 : 0); + } } } return result | (_state.InputSelect & 0x30) | 0xC0; } +void GbMemoryManager::WriteInputPort(uint8_t value) +{ + _state.InputSelect = value; + if(_gameboy->IsSgb()) { + _console->GetCartridge()->GetSuperGameboy()->ProcessInputPortWrite(value & 0x30); + } +} + void GbMemoryManager::Serialize(Serializer& s) { s.Stream( diff --git a/Core/GbMemoryManager.h b/Core/GbMemoryManager.h index 9942596..ef3f0d7 100644 --- a/Core/GbMemoryManager.h +++ b/Core/GbMemoryManager.h @@ -27,15 +27,15 @@ private: GbCart* _cart = nullptr; GbApu* _apu = nullptr; GbPpu* _ppu = nullptr; - GbTimer* _timer; - GbDmaController* _dmaController; + GbTimer* _timer = nullptr; + GbDmaController* _dmaController = nullptr; uint8_t* _highRam = nullptr; uint8_t* _reads[0x100] = {}; uint8_t* _writes[0x100] = {}; - GbMemoryManagerState _state; + GbMemoryManagerState _state = {}; public: virtual ~GbMemoryManager(); @@ -74,6 +74,7 @@ public: uint64_t GetApuCycleCount(); uint8_t ReadInputPort(); + void WriteInputPort(uint8_t value); uint8_t DebugRead(uint16_t addr); void DebugWrite(uint16_t addr, uint8_t value); diff --git a/Core/GbNoiseChannel.h b/Core/GbNoiseChannel.h index 684ab86..e5073e5 100644 --- a/Core/GbNoiseChannel.h +++ b/Core/GbNoiseChannel.h @@ -6,7 +6,7 @@ class GbApu; -class GbNoiseChannel : public ISerializable +class GbNoiseChannel final : public ISerializable { private: GbNoiseState _state = {}; diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index 5dbac3c..0d91d99 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -10,6 +10,7 @@ #include "GbDmaController.h" #include "NotificationManager.h" #include "MessageManager.h" +#include "SuperGameboy.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/Serializer.h" @@ -43,7 +44,7 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana _state.CgbEnabled = _gameboy->IsCgb(); _lastFrameTime = 0; - if(!_gameboy->IsCgb() || !_gameboy->UseBootRom()) { + if(!_gameboy->IsCgb()) { for(int i = 0; i < 4; i++) { //Init default palette for use with DMG _state.CgbBgPalettes[i] = bwRgbPalette[i]; @@ -52,20 +53,8 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana } } - 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); - } else { - Write(0xFF48, 0xFF); - Write(0xFF49, 0xFF); - } + Write(0xFF48, 0xFF); + Write(0xFF49, 0xFF); } GbPpu::~GbPpu() @@ -77,6 +66,11 @@ GbPpuState GbPpu::GetState() return _state; } +uint16_t* GbPpu::GetOutputBuffer() +{ + return _currentBuffer; +} + uint16_t* GbPpu::GetEventViewerBuffer() { return _currentEventViewerBuffer; @@ -200,8 +194,9 @@ void GbPpu::ProcessVblankScanline() _state.Scanline = 0; _state.Ly = 0; _state.LyForCompare = 0; - _console->ProcessEvent(EventType::StartFrame); + if(_console->IsDebugging()) { + _console->ProcessEvent(EventType::GbStartFrame); _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; } } else { @@ -314,7 +309,7 @@ void GbPpu::ProcessVisibleScanline() void GbPpu::ProcessPpuCycle() { if(_console->IsDebugging()) { - _console->ProcessPpuCycle(_state.Scanline, _state.Cycle); + _console->ProcessPpuCycle(); if(_state.Mode <= PpuMode::OamEvaluation) { _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = evtColors[(int)_state.Mode]; } else if(_prevDrawnPixels != _drawnPixels && _drawnPixels > 0) { @@ -373,13 +368,20 @@ void GbPpu::RunDrawCycle() _currentBuffer[outOffset] = _state.CgbObjPalettes[sprite.Color | ((sprite.Attributes & 0x07) << 2)]; } else { uint8_t colorIndex = (((sprite.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0) >> (sprite.Color * 2)) & 0x03; + if(_gameboy->IsSgb()) { + _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); + } _currentBuffer[outOffset] = _state.CgbObjPalettes[((sprite.Attributes & 0x10) ? 4 : 0) | colorIndex]; } } else { if(_state.CgbEnabled) { _currentBuffer[outOffset] = _state.CgbBgPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)]; } else { - _currentBuffer[outOffset] = _state.CgbBgPalettes[(_state.BgPalette >> (entry.Color * 2)) & 0x03]; + uint8_t colorIndex = (_state.BgPalette >> (entry.Color * 2)) & 0x03; + if(_gameboy->IsSgb()) { + _gameboy->GetSgb()->WriteLcdColor(_state.Scanline, (uint8_t)_drawnPixels, colorIndex); + } + _currentBuffer[outOffset] = _state.CgbBgPalettes[colorIndex]; } } } @@ -599,6 +601,16 @@ uint32_t GbPpu::GetFrameCount() return _state.FrameCount; } +uint8_t GbPpu::GetScanline() +{ + return _state.Scanline; +} + +uint16_t GbPpu::GetCycle() +{ + return _state.Cycle; +} + bool GbPpu::IsLcdEnabled() { return _state.LcdEnabled; @@ -611,8 +623,13 @@ PpuMode GbPpu::GetMode() void GbPpu::SendFrame() { - _console->ProcessEvent(EventType::EndFrame); + _console->ProcessEvent(EventType::GbEndFrame); _state.FrameCount++; + + if(_gameboy->IsSgb()) { + return; + } + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone); if(_isFirstFrame) { @@ -709,8 +726,9 @@ void GbPpu::Write(uint16_t addr, uint8_t value) _state.LyCoincidenceFlag = _state.LyCompare == _state.LyForCompare; UpdateStatIrq(); - _console->ProcessEvent(EventType::StartFrame); if(_console->IsDebugging()) { + _console->ProcessEvent(EventType::GbStartFrame); + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; for(int i = 0; i < 456 * 154; i++) { _currentEventViewerBuffer[i] = 0x18C6; diff --git a/Core/GbPpu.h b/Core/GbPpu.h index a1beb66..2130304 100644 --- a/Core/GbPpu.h +++ b/Core/GbPpu.h @@ -76,10 +76,13 @@ public: void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, GbDmaController* dmaController, uint8_t* vram, uint8_t* oam); GbPpuState GetState(); + uint16_t* GetOutputBuffer(); uint16_t* GetEventViewerBuffer(); uint16_t* GetPreviousEventViewerBuffer(); uint32_t GetFrameCount(); + uint8_t GetScanline(); + uint16_t GetCycle(); bool IsLcdEnabled(); PpuMode GetMode(); diff --git a/Core/GbSquareChannel.h b/Core/GbSquareChannel.h index ee24416..d628592 100644 --- a/Core/GbSquareChannel.h +++ b/Core/GbSquareChannel.h @@ -6,7 +6,7 @@ class GbApu; -class GbSquareChannel : public ISerializable +class GbSquareChannel final : public ISerializable { private: const uint8_t _dutySequences[4][8] = { @@ -25,15 +25,12 @@ public: GbSquareState GetState(); bool Enabled(); - void Disable(); - void ClockSweepUnit(); - + void ClockSweepUnit(); uint16_t GetSweepTargetFrequency(); void ClockLengthCounter(); - void ClockEnvelope(); uint8_t GetOutput(); @@ -41,7 +38,6 @@ public: void Exec(uint32_t clocksToRun); uint8_t Read(uint16_t addr); - void Write(uint16_t addr, uint8_t value); void Serialize(Serializer& s) override; diff --git a/Core/GbTimer.cpp b/Core/GbTimer.cpp index 9cd5546..6cd4314 100644 --- a/Core/GbTimer.cpp +++ b/Core/GbTimer.cpp @@ -4,7 +4,7 @@ #include "GbMemoryManager.h" #include "GbApu.h" -GbTimer::GbTimer(GbMemoryManager* memoryManager, GbApu* apu) +void GbTimer::Init(GbMemoryManager* memoryManager, GbApu* apu) { _apu = apu; _memoryManager = memoryManager; diff --git a/Core/GbTimer.h b/Core/GbTimer.h index 9e14663..ff23e98 100644 --- a/Core/GbTimer.h +++ b/Core/GbTimer.h @@ -18,9 +18,10 @@ private: void ReloadCounter(); public: - GbTimer(GbMemoryManager* memoryManager, GbApu* apu); virtual ~GbTimer(); + void Init(GbMemoryManager* memoryManager, GbApu* apu); + GbTimerState GetState(); void Exec(); diff --git a/Core/GbWaveChannel.h b/Core/GbWaveChannel.h index 463996d..9f510f9 100644 --- a/Core/GbWaveChannel.h +++ b/Core/GbWaveChannel.h @@ -6,7 +6,7 @@ class GbApu; -class GbWaveChannel : public ISerializable +class GbWaveChannel final : public ISerializable { private: GbWaveState _state = {}; diff --git a/Core/Gsu.h b/Core/Gsu.h index a3c0eaa..e8524d6 100644 --- a/Core/Gsu.h +++ b/Core/Gsu.h @@ -155,7 +155,7 @@ public: void LoadBattery() override; void SaveBattery() override; - void Run(); + void Run() override; void Reset() override; uint8_t Read(uint32_t addr) override; diff --git a/Core/GsuDebugger.cpp b/Core/GsuDebugger.cpp index 12fd5c1..9d34ccb 100644 --- a/Core/GsuDebugger.cpp +++ b/Core/GsuDebugger.cpp @@ -18,7 +18,7 @@ GsuDebugger::GsuDebugger(Debugger* debugger) { _debugger = debugger; - _codeDataLogger = debugger->GetCodeDataLogger().get(); + _codeDataLogger = debugger->GetCodeDataLogger(CpuType::Cpu).get(); _traceLogger = debugger->GetTraceLogger().get(); _disassembler = debugger->GetDisassembler().get(); _memoryAccessCounter = debugger->GetMemoryAccessCounter().get(); diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index 4872220..64b5975 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -179,6 +179,8 @@ int LuaApi::GetLibrary(lua_State *lua) lua_pushintvalue(scriptEnded, EventType::ScriptEnded); lua_pushintvalue(stateLoaded, EventType::StateLoaded); lua_pushintvalue(stateSaved, EventType::StateSaved); + lua_pushintvalue(gbStartFrame, EventType::GbStartFrame); + lua_pushintvalue(gbEndFrame, EventType::GbEndFrame); //TODO /*lua_pushintvalue(codeBreak, EventType::CodeBreak); */ diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index 84f8226..cbb532a 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -14,6 +14,7 @@ #include "Sa1.h" #include "Gsu.h" #include "Cx4.h" +#include "Gameboy.h" #include "BaseCoprocessor.h" #include "CheatManager.h" #include "../Utilities/Serializer.h" @@ -194,19 +195,6 @@ void MemoryManager::UpdateEvents() _hasEvent[_dramRefreshPosition] = true; } -void MemoryManager::SyncCoprocessors() -{ - if(_cart->GetCoprocessor()) { - if(_cart->GetGsu()) { - _cart->GetGsu()->Run(); - } else if(_cart->GetSa1()) { - _cart->GetSa1()->Run(); - } else if(_cart->GetCx4()) { - _cart->GetCx4()->Run(); - } - } -} - void MemoryManager::Exec() { _masterClock += 2; @@ -219,7 +207,7 @@ void MemoryManager::Exec() } if((_hClock & 0x03) == 0) { - _console->ProcessPpuCycle(_ppu->GetScanline(), _hClock); + _console->ProcessPpuCycle(); _regs->ProcessIrqCounters(); if(_hClock == 276 * 4 && _ppu->GetScanline() < _ppu->GetVblankStart()) { @@ -236,11 +224,11 @@ void MemoryManager::Exec() _cpu->IncreaseCycleCount<5>(); } } else if((_hClock & 0x03) == 0) { - _console->ProcessPpuCycle(_ppu->GetScanline(), _hClock); + _console->ProcessPpuCycle(); _regs->ProcessIrqCounters(); } - SyncCoprocessors(); + _cart->SyncCoprocessors(); } uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type) diff --git a/Core/MessageManager.cpp b/Core/MessageManager.cpp index d9e7bc4..c5973af 100644 --- a/Core/MessageManager.cpp +++ b/Core/MessageManager.cpp @@ -60,6 +60,8 @@ std::unordered_map MessageManager::_enResources = { { "SaveStateEmpty", u8"Slot is empty." }, { "SaveStateIncompatibleVersion", u8"Save state is incompatible with this version of Mesen-S." }, { "SaveStateInvalidFile", u8"Invalid save state file." }, + { "SaveStateWrongSystemSnes", u8"Error: State cannot be loaded (wrong console type: SNES)" }, + { "SaveStateWrongSystemGb", u8"Error: State cannot be loaded (wrong console type: Game Boy)" }, { "SaveStateLoaded", u8"State #%1 loaded." }, { "SaveStateMissingRom", u8"Missing ROM required (%1) to load save state." }, { "SaveStateNewerVersion", u8"Cannot load save states created by a more recent version of Mesen-S. Please download the latest version." }, diff --git a/Core/NecDsp.h b/Core/NecDsp.h index e40ecc5..9b2cdd7 100644 --- a/Core/NecDsp.h +++ b/Core/NecDsp.h @@ -59,7 +59,7 @@ public: static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector &embeddedFirmware); void Reset() override; - void Run(); + void Run() override; void LoadBattery() override; void SaveBattery() override; diff --git a/Core/PpuTools.cpp b/Core/PpuTools.cpp index cbb9259..77ead0d 100644 --- a/Core/PpuTools.cpp +++ b/Core/PpuTools.cpp @@ -350,10 +350,14 @@ void PpuTools::GetSpritePreview(GetSpritePreviewOptions options, PpuState state, } } -void PpuTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle) +void PpuTools::SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType) { //TODO Thread safety - _updateTimings[viewerId] = (scanline << 16) | cycle; + ViewerRefreshConfig cfg; + cfg.Scanline = scanline; + cfg.Cycle = cycle; + cfg.Type = cpuType; + _updateTimings[viewerId] = cfg; } void PpuTools::RemoveViewer(uint32_t viewerId) @@ -362,16 +366,6 @@ void PpuTools::RemoveViewer(uint32_t viewerId) _updateTimings.erase(viewerId); } -void PpuTools::UpdateViewers(uint16_t scanline, uint16_t cycle) -{ - uint32_t currentCycle = (scanline << 16) | cycle; - for(auto updateTiming : _updateTimings) { - if(updateTiming.second == currentCycle) { - _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first); - } - } -} - void PpuTools::GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offset, uint32_t* outBuffer) { bool isCgb = state.CgbEnabled; diff --git a/Core/PpuTools.h b/Core/PpuTools.h index c97fc2b..bf0a59a 100644 --- a/Core/PpuTools.h +++ b/Core/PpuTools.h @@ -1,17 +1,25 @@ #pragma once #include "stdafx.h" #include "DebugTypes.h" +#include "Console.h" +#include "NotificationManager.h" class Ppu; -class Console; struct GbPpuState; +struct ViewerRefreshConfig +{ + uint16_t Scanline; + uint16_t Cycle; + CpuType Type; +}; + class PpuTools { private: Ppu *_ppu; Console *_console; - unordered_map _updateTimings; + unordered_map _updateTimings; uint8_t GetTilePixelColor(const uint8_t* ram, const uint32_t ramMask, const uint8_t bpp, const uint32_t pixelStart, const uint8_t shift); @@ -26,9 +34,20 @@ public: void GetTilemap(GetTilemapOptions options, PpuState state, uint8_t* vram, uint8_t* cgram, uint32_t *outBuffer); void GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t* oamRam, uint8_t* cgram, uint32_t *outBuffer); - void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle); + void SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType); void RemoveViewer(uint32_t viewerId); - void UpdateViewers(uint16_t scanline, uint16_t cycle); + + __forceinline void UpdateViewers(uint16_t scanline, uint16_t cycle, CpuType cpuType) + { + if(_updateTimings.size() > 0) { + for(auto updateTiming : _updateTimings) { + ViewerRefreshConfig cfg = updateTiming.second; + if(cfg.Cycle == cycle && cfg.Scanline == scanline && cfg.Type == cpuType) { + _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ViewerRefresh, (void*)(uint64_t)updateTiming.first); + } + } + } + } void GetGameboyTilemap(uint8_t* vram, GbPpuState& state, uint16_t offset, uint32_t* outBuffer); void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* outBuffer); diff --git a/Core/Sa1.h b/Core/Sa1.h index acceb5b..4ffafd2 100644 --- a/Core/Sa1.h +++ b/Core/Sa1.h @@ -78,7 +78,7 @@ public: void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Run(); + void Run() override; void Reset() override; SnesMemoryType GetSa1MemoryType(); @@ -93,6 +93,6 @@ public: uint16_t ReadVector(uint16_t vector); MemoryMappings* GetMemoryMappings(); - void LoadBattery(); - void SaveBattery(); + void LoadBattery() override; + void SaveBattery() override; }; diff --git a/Core/SaveStateManager.cpp b/Core/SaveStateManager.cpp index 0ae94a1..84c6c6c 100644 --- a/Core/SaveStateManager.cpp +++ b/Core/SaveStateManager.cpp @@ -69,6 +69,9 @@ void SaveStateManager::GetSaveStateHeader(ostream &stream) string sha1Hash = _console->GetCartridge()->GetSha1Hash(); stream.write(sha1Hash.c_str(), sha1Hash.size()); + bool isGameboyMode = _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode); + stream.write((char*)&isGameboyMode, sizeof(bool)); + #ifndef LIBRETRO SaveScreenshotData(stream); #endif @@ -178,6 +181,15 @@ bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired) char hash[41] = {}; stream.read(hash, 40); + if(fileFormatVersion >= 8) { + bool isGameboyMode = false; + stream.read((char*)&isGameboyMode, sizeof(bool)); + if(isGameboyMode != _console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) { + MessageManager::DisplayMessage("SaveStates", isGameboyMode ? "SaveStateWrongSystemGb" : "SaveStateWrongSystemSnes"); + return false; + } + } + if(fileFormatVersion >= 7) { #ifndef LIBRETRO vector frameData; diff --git a/Core/SaveStateManager.h b/Core/SaveStateManager.h index be85d1a..fcb9f40 100644 --- a/Core/SaveStateManager.h +++ b/Core/SaveStateManager.h @@ -16,7 +16,7 @@ private: bool GetScreenshotData(vector& out, uint32_t& width, uint32_t& height, istream& stream); public: - static constexpr uint32_t FileFormatVersion = 7; + static constexpr uint32_t FileFormatVersion = 8; SaveStateManager(shared_ptr console); diff --git a/Core/ScriptManager.h b/Core/ScriptManager.h index ebaaccc..88c24ef 100644 --- a/Core/ScriptManager.h +++ b/Core/ScriptManager.h @@ -20,6 +20,7 @@ private: public: ScriptManager(Debugger *debugger); + __forceinline bool HasScript() { return _hasScript; } int32_t LoadScript(string name, string content, int32_t scriptId); void RemoveScript(int32_t scriptId); const char* GetScriptLog(int32_t scriptId); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 9f855ca..8a71314 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -275,6 +275,7 @@ enum class GameboyModel Auto = 0, Gameboy = 1, GameboyColor = 2, + SuperGameboy = 3 }; struct EmulationConfig @@ -298,7 +299,6 @@ struct EmulationConfig int64_t BsxCustomDate = -1; - bool GbUseBootRom = false; GameboyModel GbModel = GameboyModel::Auto; }; diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index 745d002..662ce15 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -8,6 +8,8 @@ #include "WaveRecorder.h" #include "Spc.h" #include "Msu1.h" +#include "BaseCartridge.h" +#include "SuperGameboy.h" #include "../Utilities/Equalizer.h" SoundMixer::SoundMixer(Console *console) @@ -73,6 +75,12 @@ void SoundMixer::PlayAudioBuffer(int16_t* samples, uint32_t sampleCount, uint32_ int16_t *out = _sampleBuffer; uint32_t count = _resampler->Resample(samples, sampleCount, sourceRate, cfg.SampleRate, out); + SuperGameboy* sgb = _console->GetCartridge()->GetSuperGameboy(); + if(sgb) { + uint32_t targetRate = (uint32_t)(cfg.SampleRate * _resampler->GetRateAdjustment()); + sgb->MixAudio(targetRate, out, count); + } + shared_ptr msu1 = _console->GetMsu1(); if(msu1) { msu1->MixAudio(out, count, cfg.SampleRate); diff --git a/Core/SpcDebugger.cpp b/Core/SpcDebugger.cpp index 3a68f97..65790d4 100644 --- a/Core/SpcDebugger.cpp +++ b/Core/SpcDebugger.cpp @@ -52,11 +52,10 @@ void SpcDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType _disassembler->BuildCache(addressInfo, 0, CpuType::Spc); if(_traceLogger->IsCpuLogged(CpuType::Spc)) { - DebugState debugState; - _debugger->GetState(debugState, true); + _debugger->GetState(_debugState, true); DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo, addr, 0, CpuType::Spc); - _traceLogger->Log(CpuType::Spc, debugState, disInfo); + _traceLogger->Log(CpuType::Spc, _debugState, disInfo); } } diff --git a/Core/SpcDebugger.h b/Core/SpcDebugger.h index 4c33f47..908f3c5 100644 --- a/Core/SpcDebugger.h +++ b/Core/SpcDebugger.h @@ -29,6 +29,8 @@ class SpcDebugger final : public IDebugger uint8_t _prevOpCode = 0xFF; uint32_t _prevProgramCounter = 0; + + DebugState _debugState; public: SpcDebugger(Debugger* debugger); diff --git a/Core/SuperGameboy.cpp b/Core/SuperGameboy.cpp new file mode 100644 index 0000000..a1bc6f9 --- /dev/null +++ b/Core/SuperGameboy.cpp @@ -0,0 +1,292 @@ +#include "stdafx.h" +#include "SuperGameboy.h" +#include "Console.h" +#include "MemoryManager.h" +#include "BaseCartridge.h" +#include "Gameboy.h" +#include "GbApu.h" +#include "GbPpu.h" +#include "MessageManager.h" +#include "../Utilities/HexUtilities.h" +#include "../Utilities/HermiteResampler.h" + +SuperGameboy::SuperGameboy(Console* console) : BaseCoprocessor(SnesMemoryType::Register) +{ + _console = console; + _memoryManager = console->GetMemoryManager().get(); + _cart = _console->GetCartridge().get(); + + _gameboy = _cart->GetGameboy(); + _gameboy->PowerOn(this); + _ppu = _gameboy->GetPpu(); + _mixBuffer = new int16_t[0x10000]; + + MemoryMappings* cpuMappings = _memoryManager->GetMemoryMappings(); + for(int i = 0; i <= 0x3F; i++) { + cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, this); + cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, this); + } +} + +SuperGameboy::~SuperGameboy() +{ + delete[] _mixBuffer; +} + +void SuperGameboy::Reset() +{ + _control = 0; + _resetClock = 0; + + memset(_input, 0, sizeof(_input)); + _inputIndex = 0; + + _listeningForPacket = false; + _waitForHigh = true; + _packetReady = false; + _inputWriteClock = 0; + _inputValue = 0; + memset(_packetData, 0, sizeof(_packetData)); + _packetByte = 0; + _packetBit = 0; + + _lcdRowSelect = 0; + _readPosition = 0; + memset(_lcdBuffer, 0, sizeof(_lcdBuffer)); +} + +uint8_t SuperGameboy::Read(uint32_t addr) +{ + addr &= 0xF80F; + + if(addr >= 0x7000 && addr <= 0x700F) { + _packetReady = false; + return _packetData[addr & 0x0F]; + } else if(addr >= 0x7800 && addr <= 0x780F) { + if(_readPosition >= 320) { + //Return 0xFF for 320..511 and then wrap to 0 + _readPosition = (_readPosition + 1) & 0x1FF; + return 0xFF; + } + + uint8_t* start = _lcdBuffer[_lcdRowSelect]; + start += ((_readPosition >> 1) & 0x07) * 160; + start += (_readPosition >> 4) * 8; + + uint8_t data = 0; + uint8_t shift = _readPosition & 0x01; + for(int i = 0; i < 8; i++) { + data |= ((start[i] >> shift) & 0x01) << (7 - i); + } + _readPosition++; + return data; + } else { + switch(addr & 0xFFFF) { + case 0x6000: return (GetLcdRow() << 3) | GetLcdBufferRow(); + case 0x6002: return _packetReady; + case 0x600F: return 0x21; //or 0x61 + } + } + + return 0; +} + +void SuperGameboy::Write(uint32_t addr, uint8_t value) +{ + addr &= 0xF80F; + + switch(addr & 0xFFFF) { + case 0x6001: + _lcdRowSelect = value & 0x03; + _readPosition = 0; + break; + + case 0x6003: { + if(!(_control & 0x80) && (value & 0x80)) { + _resetClock = _memoryManager->GetMasterClock(); + _gameboy->PowerOn(this); + _ppu = _gameboy->GetPpu(); + } + _control = value; + _inputIndex %= GetPlayerCount(); + break; + } + + case 0x6004: _input[0] = value; break; + case 0x6005: _input[1] = value; break; + case 0x6006: _input[2] = value; break; + case 0x6007: _input[3] = value; break; + } +} + +void SuperGameboy::Run() +{ + _gameboy->Run(_memoryManager->GetMasterClock()); +} + +void SuperGameboy::ProcessInputPortWrite(uint8_t value) +{ + if(_inputValue == value) { + return; + } + + if(value == 0x00) { + //Reset pulse + _waitForHigh = true; + _packetByte = 0; + _packetBit = 0; + } else if(_waitForHigh) { + if(value == 0x10 || value == 0x20) { + //Invalid sequence (should be 0x00 -> 0x30 -> 0x10/0x20 -> 0x30 -> 0x10/0x20, etc.) + _waitForHigh = false; + _listeningForPacket = false; + } else if(value == 0x30) { + _waitForHigh = false; + _listeningForPacket = true; + } + } else if(_listeningForPacket) { + if(value == 0x20) { + //0 bit + if(_packetByte >= 16 && _packetBit == 0) { + _packetReady = true; + _listeningForPacket = false; + + /*string log = HexUtilities::ToHex(_packetData[0] >> 3); + log += " Size: " + std::to_string(_packetData[0] & 0x07) + " - "; + for(int i = 0; i < 16; i++) { + log += HexUtilities::ToHex(_packetData[i]) + " "; + } + MessageManager::Log(log);*/ + } else { + _packetData[_packetByte] &= ~(1 << _packetBit); + } + _packetBit++; + if(_packetBit == 8) { + _packetBit = 0; + _packetByte++; + } + } else if(value == 0x10) { + //1 bit + if(_packetByte >= 16) { + //Invalid bit + _listeningForPacket = false; + } else { + _packetData[_packetByte] |= (1 << _packetBit); + _packetBit++; + if(_packetBit == 8) { + _packetBit = 0; + _packetByte++; + } + } + } + _waitForHigh = _listeningForPacket; + } else if(!(_inputValue & 0x20) && (value & 0x20)) { + _inputIndex = (_inputIndex + 1) % GetPlayerCount(); + } + + _inputValue = value; + _inputWriteClock = _memoryManager->GetMasterClock(); +} + +void SuperGameboy::WriteLcdColor(uint8_t scanline, uint8_t pixel, uint8_t color) +{ + _lcdBuffer[GetLcdBufferRow()][(scanline & 0x07) * 160 + pixel] = color; +} + +uint8_t SuperGameboy::GetLcdRow() +{ + uint8_t scanline = _ppu->GetScanline(); + uint8_t row = scanline / 8; + if(row >= 18) { + row = 0; + } + return row; +} + +uint8_t SuperGameboy::GetLcdBufferRow() +{ + return (_ppu->GetFrameCount() * 18 + GetLcdRow()) & 0x03; +} + +uint8_t SuperGameboy::GetPlayerCount() +{ + uint8_t playerCount = ((_control >> 4) & 0x03) + 1; + if(playerCount >= 3) { + //Unknown: 2 and 3 both mean 4 players? + return 4; + } + return playerCount; +} + +void SuperGameboy::MixAudio(uint32_t targetRate, int16_t* soundSamples, uint32_t sampleCount) +{ + int16_t* gbSamples = nullptr; + uint32_t gbSampleCount = 0; + _gameboy->GetSoundSamples(gbSamples, gbSampleCount); + _resampler.SetSampleRates(GbApu::SampleRate, targetRate); + + int32_t outCount = (int32_t)_resampler.Resample(gbSamples, gbSampleCount, _mixBuffer + _mixSampleCount) * 2; + _mixSampleCount += outCount; + + int32_t copyCount = (int32_t)std::min(_mixSampleCount, sampleCount*2); + for(int32_t i = 0; i < copyCount; i++) { + soundSamples[i] += _mixBuffer[i]; + } + + int32_t remainingSamples = (int32_t)_mixSampleCount - copyCount; + if(remainingSamples > 0) { + memmove(_mixBuffer, _mixBuffer + copyCount, remainingSamples*sizeof(int16_t)); + _mixSampleCount = remainingSamples; + } else { + _mixSampleCount = 0; + } +} + +uint8_t SuperGameboy::GetControl() +{ + return _control; +} + +uint64_t SuperGameboy::GetResetClock() +{ + return _resetClock; +} + +uint8_t SuperGameboy::GetInputIndex() +{ + return 0xF - _inputIndex; +} + +uint8_t SuperGameboy::GetInput() +{ + return _input[_inputIndex]; +} + +uint8_t SuperGameboy::Peek(uint32_t addr) +{ + return 0; +} + +void SuperGameboy::PeekBlock(uint32_t addr, uint8_t* output) +{ + memset(output, 0, 0x1000); +} + +AddressInfo SuperGameboy::GetAbsoluteAddress(uint32_t address) +{ + return { -1, SnesMemoryType::Register }; +} + +void SuperGameboy::Serialize(Serializer& s) +{ + s.Stream( + _control, _resetClock, _input[0], _input[1], _input[2], _input[3], _inputIndex, _listeningForPacket, _packetReady, + _inputWriteClock, _inputValue, _packetByte, _packetBit, _lcdRowSelect, _readPosition, _waitForHigh + ); + + s.StreamArray(_packetData, 16); + s.StreamArray(_lcdBuffer[0], 1280); + s.StreamArray(_lcdBuffer[1], 1280); + s.StreamArray(_lcdBuffer[2], 1280); + s.StreamArray(_lcdBuffer[3], 1280); +} diff --git a/Core/SuperGameboy.h b/Core/SuperGameboy.h new file mode 100644 index 0000000..84e6bbe --- /dev/null +++ b/Core/SuperGameboy.h @@ -0,0 +1,74 @@ +#pragma once +#include "stdafx.h" +#include "BaseCoprocessor.h" +#include "../Utilities/HermiteResampler.h" + +class Console; +class MemoryManager; +class BaseCartridge; +class Gameboy; +class GbPpu; + +class SuperGameboy : public BaseCoprocessor +{ +private: + Console* _console = nullptr; + MemoryManager* _memoryManager = nullptr; + BaseCartridge* _cart = nullptr; + Gameboy* _gameboy = nullptr; + GbPpu* _ppu = nullptr; + + uint8_t _control = 0; + uint64_t _resetClock = 0; + + uint8_t _input[4] = {}; + uint8_t _inputIndex = 0; + + bool _listeningForPacket = false; + bool _waitForHigh = true; + bool _packetReady = false; + uint64_t _inputWriteClock = 0; + uint8_t _inputValue = 0; + uint8_t _packetData[16] = {}; + uint8_t _packetByte = 0; + uint8_t _packetBit = 0; + + uint8_t _lcdRowSelect = 0; + uint16_t _readPosition = 0; + uint8_t _lcdBuffer[4][1280] = {}; + + HermiteResampler _resampler; + int16_t* _mixBuffer = nullptr; + uint32_t _mixSampleCount = 0; + + uint8_t GetLcdRow(); + uint8_t GetLcdBufferRow(); + uint8_t GetPlayerCount(); + +public: + SuperGameboy(Console* console); + ~SuperGameboy(); + + void Reset() override; + + uint8_t Read(uint32_t addr) override; + void Write(uint32_t addr, uint8_t value) override; + + void Run() override; + + void ProcessInputPortWrite(uint8_t value); + + void WriteLcdColor(uint8_t scanline, uint8_t pixel, uint8_t color); + + void MixAudio(uint32_t targetRate, int16_t* soundSamples, uint32_t sampleCount); + + uint8_t GetControl(); + uint64_t GetResetClock(); + uint8_t GetInputIndex(); + uint8_t GetInput(); + + uint8_t Peek(uint32_t addr) override; + void PeekBlock(uint32_t addr, uint8_t* output) override; + AddressInfo GetAbsoluteAddress(uint32_t address) override; + void Serialize(Serializer& s) override; +}; \ No newline at end of file diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp index 19a76e5..d1a88f3 100644 --- a/InteropDLL/DebugApiWrapper.cpp +++ b/InteropDLL/DebugApiWrapper.cpp @@ -84,22 +84,22 @@ extern "C" DllExport void __stdcall GetMemoryAccessCounts(uint32_t offset, uint32_t length, SnesMemoryType memoryType, AddressCounters* counts) { GetDebugger()->GetMemoryAccessCounter()->GetAccessCounts(offset, length, memoryType, counts); } DllExport void __stdcall GetCdlData(uint32_t offset, uint32_t length, SnesMemoryType memoryType, uint8_t* cdlData) { GetDebugger()->GetCdlData(offset, length, memoryType, cdlData); } - DllExport void __stdcall SetCdlData(uint8_t* cdlData, uint32_t length) { GetDebugger()->SetCdlData(cdlData, length); } - DllExport void __stdcall MarkBytesAs(uint32_t start, uint32_t end, uint8_t flags) { GetDebugger()->MarkBytesAs(start, end, flags); } + DllExport void __stdcall SetCdlData(CpuType cpuType, uint8_t* cdlData, uint32_t length) { GetDebugger()->SetCdlData(cpuType, cdlData, length); } + DllExport void __stdcall MarkBytesAs(CpuType cpuType, uint32_t start, uint32_t end, uint8_t flags) { GetDebugger()->MarkBytesAs(cpuType, start, end, flags); } DllExport void __stdcall GetTilemap(GetTilemapOptions options, PpuState state, uint8_t *vram, uint8_t *cgram, uint32_t *buffer) { GetDebugger()->GetPpuTools()->GetTilemap(options, state, vram, cgram, buffer); } DllExport void __stdcall GetTileView(GetTileViewOptions options, uint8_t *source, uint32_t srcSize, uint8_t *cgram, uint32_t *buffer) { GetDebugger()->GetPpuTools()->GetTileView(options, source, srcSize, cgram, buffer); } DllExport void __stdcall GetSpritePreview(GetSpritePreviewOptions options, PpuState state, uint8_t* vram, uint8_t *oamRam, uint8_t *cgram, uint32_t *buffer) { GetDebugger()->GetPpuTools()->GetSpritePreview(options, state, vram, oamRam, cgram, buffer); } - DllExport void __stdcall SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle) { GetDebugger()->GetPpuTools()->SetViewerUpdateTiming(viewerId, scanline, cycle); } + DllExport void __stdcall SetViewerUpdateTiming(uint32_t viewerId, uint16_t scanline, uint16_t cycle, CpuType cpuType) { GetDebugger()->GetPpuTools()->SetViewerUpdateTiming(viewerId, scanline, cycle, cpuType); } DllExport void __stdcall GetGameboyTilemap(uint8_t* vram, GbPpuState state, uint16_t offset, uint32_t* buffer) { GetDebugger()->GetPpuTools()->GetGameboyTilemap(vram, state, offset, buffer); } DllExport void __stdcall GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, uint8_t* vram, uint8_t* oamRam, uint32_t* buffer) { GetDebugger()->GetPpuTools()->GetGameboySpritePreview(options, state, vram, oamRam, buffer); } - DllExport void __stdcall GetDebugEvents(DebugEventInfo *infoArray, uint32_t &maxEventCount) { GetDebugger()->GetEventManager()->GetEvents(infoArray, maxEventCount); } - DllExport uint32_t __stdcall GetDebugEventCount(EventViewerDisplayOptions options) { return GetDebugger()->GetEventManager()->GetEventCount(options); } - DllExport void __stdcall GetEventViewerOutput(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options) { GetDebugger()->GetEventManager()->GetDisplayBuffer(buffer, bufferSize, options); } - DllExport void __stdcall GetEventViewerEvent(DebugEventInfo *evtInfo, uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions options) { *evtInfo = GetDebugger()->GetEventManager()->GetEvent(scanline, cycle, options); } - DllExport uint32_t __stdcall TakeEventSnapshot(EventViewerDisplayOptions options) { return GetDebugger()->GetEventManager()->TakeEventSnapshot(options); } + DllExport void __stdcall GetDebugEvents(CpuType cpuType, DebugEventInfo *infoArray, uint32_t &maxEventCount) { GetDebugger()->GetEventManager(cpuType)->GetEvents(infoArray, maxEventCount); } + DllExport uint32_t __stdcall GetDebugEventCount(CpuType cpuType, EventViewerDisplayOptions options) { return GetDebugger()->GetEventManager(cpuType)->GetEventCount(options); } + DllExport void __stdcall GetEventViewerOutput(CpuType cpuType, uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options) { GetDebugger()->GetEventManager(cpuType)->GetDisplayBuffer(buffer, bufferSize, options); } + DllExport void __stdcall GetEventViewerEvent(CpuType cpuType, DebugEventInfo *evtInfo, uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions options) { *evtInfo = GetDebugger()->GetEventManager(cpuType)->GetEvent(scanline, cycle, options); } + DllExport uint32_t __stdcall TakeEventSnapshot(CpuType cpuType, EventViewerDisplayOptions options) { return GetDebugger()->GetEventManager(cpuType)->TakeEventSnapshot(options); } DllExport int32_t __stdcall LoadScript(char* name, char* content, int32_t scriptId) { return GetDebugger()->GetScriptManager()->LoadScript(name, content, scriptId); } DllExport void __stdcall RemoveScript(int32_t scriptId) { GetDebugger()->GetScriptManager()->RemoveScript(scriptId); } diff --git a/InteropDLL/EmuApiWrapper.cpp b/InteropDLL/EmuApiWrapper.cpp index 3f7edd2..fd16451 100644 --- a/InteropDLL/EmuApiWrapper.cpp +++ b/InteropDLL/EmuApiWrapper.cpp @@ -269,6 +269,9 @@ extern "C" { _console.reset(new Console()); KeyManager::SetSettings(_console->GetSettings().get()); _console->Initialize(); + EmulationConfig cfg = _console->GetSettings()->GetEmulationConfig(); + cfg.GbModel = GameboyModel::GameboyColor; + _console->GetSettings()->SetEmulationConfig(cfg); _console->LoadRom((VirtualFile)testRoms[i], VirtualFile()); if(enableDebugger) { diff --git a/Libretro/Makefile.common b/Libretro/Makefile.common index 1a1c279..fe53035 100644 --- a/Libretro/Makefile.common +++ b/Libretro/Makefile.common @@ -131,6 +131,7 @@ SOURCES_CXX := $(LIBRETRO_DIR)/libretro.cpp \ $(CORE_DIR)/SPC_Filter.cpp \ $(CORE_DIR)/Spc7110.cpp \ $(CORE_DIR)/Spc7110Decomp.cpp \ + $(CORE_DIR)/SuperGameboy.cpp \ $(CORE_DIR)/stdafx.cpp \ $(CORE_DIR)/TraceLogger.cpp \ $(CORE_DIR)/VideoDecoder.cpp \ diff --git a/Libretro/libretro.cpp b/Libretro/libretro.cpp index b554f38..4d881cc 100644 --- a/Libretro/libretro.cpp +++ b/Libretro/libretro.cpp @@ -16,6 +16,7 @@ #include "../Core/EmuSettings.h" #include "../Core/SaveStateManager.h" #include "../Core/CheatManager.h" +#include "../Core/SettingTypes.h" #include "../Utilities/snes_ntsc.h" #include "../Utilities/FolderUtilities.h" #include "../Utilities/HexUtilities.h" @@ -50,6 +51,7 @@ static constexpr const char* MesenRamState = "mesen-s_ramstate"; static constexpr const char* MesenOverclock = "mesen-s_overclock"; static constexpr const char* MesenOverclockType = "mesen-s_overclock_type"; static constexpr const char* MesenSuperFxOverclock = "mesen-s_superfx_overclock"; +static constexpr const char* MesenGbModel = "mesen-s_gbmodel"; extern "C" { void logMessage(retro_log_level level, const char* message) @@ -112,6 +114,7 @@ extern "C" { static constexpr struct retro_variable vars[] = { { MesenNtscFilter, "NTSC filter; Disabled|Composite (Blargg)|S-Video (Blargg)|RGB (Blargg)|Monochrome (Blargg)" }, { MesenRegion, "Region; Auto|NTSC|PAL" }, + { MesenGbModel, "Game Boy Model; Auto|Game Boy|Game Boy Color|Super Game Boy" }, { MesenOverscanVertical, "Vertical Overscan; None|8px|16px" }, { MesenOverscanHorizontal, "Horizontal Overscan; None|8px|16px" }, { MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9" }, @@ -388,6 +391,19 @@ extern "C" { audio.EnableCubicInterpolation = (value == "enabled"); } + if(readVariable(MesenGbModel, var)) { + string value = string(var.value); + if(value == "Game Boy") { + emulation.GbModel = GameboyModel::Gameboy; + } else if(value == "Game Boy Color") { + emulation.GbModel = GameboyModel::GameboyColor; + } else if(value == "Super Game Boy") { + emulation.GbModel = GameboyModel::SuperGameboy; + } else { + emulation.GbModel = GameboyModel::Auto; + } + } + auto getKeyCode = [=](int port, int retroKey) { return (port << 8) | (retroKey + 1); }; @@ -657,7 +673,7 @@ extern "C" { info->library_name = "Mesen-S"; info->library_version = _mesenVersion.c_str(); info->need_fullpath = false; - info->valid_extensions = "sfc|smc|fig|swc"; + info->valid_extensions = "sfc|smc|fig|swc|gb|gbc"; info->block_extract = false; } @@ -669,7 +685,7 @@ extern "C" { RETRO_API void *retro_get_memory_data(unsigned id) { shared_ptr cart = _console->GetCartridge(); - if(_console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) { + if(cart->GetGameboy()) { switch(id) { case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbCartRam); case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemory(SnesMemoryType::GbWorkRam); @@ -686,7 +702,7 @@ extern "C" { RETRO_API size_t retro_get_memory_size(unsigned id) { shared_ptr cart = _console->GetCartridge(); - if(_console->GetSettings()->CheckFlag(EmulationFlags::GameboyMode)) { + if(cart->GetGameboy()) { switch(id) { case RETRO_MEMORY_SAVE_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbCartRam); case RETRO_MEMORY_SYSTEM_RAM: return cart->GetGameboy()->DebugGetMemorySize(SnesMemoryType::GbWorkRam); diff --git a/Mesen-S.sln b/Mesen-S.sln index 7f7b5a5..41031d8 100644 --- a/Mesen-S.sln +++ b/Mesen-S.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2036 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29613.14 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core\Core.vcxproj", "{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}" ProjectSection(ProjectDependencies) = postProject @@ -337,12 +337,10 @@ Global {4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x86.ActiveCfg = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.Libretro|x86.Build.0 = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|Any CPU.ActiveCfg = Libretro|Win32 - {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|Any CPU.Build.0 = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x64.ActiveCfg = Libretro|x64 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x86.ActiveCfg = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Optimize|x86.Build.0 = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|Any CPU.ActiveCfg = Libretro|Win32 - {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|Any CPU.Build.0 = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x64.ActiveCfg = Libretro|x64 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x86.ActiveCfg = Libretro|Win32 {4432139E-528B-44DE-961C-B37CD5E92E0E}.PGO Profile|x86.Build.0 = Libretro|Win32 diff --git a/PGOHelper/PGOHelper.cpp b/PGOHelper/PGOHelper.cpp index 13f903b..ca190c1 100644 --- a/PGOHelper/PGOHelper.cpp +++ b/PGOHelper/PGOHelper.cpp @@ -47,7 +47,7 @@ int main(int argc, char* argv[]) romFolder = argv[1]; } - vector testRoms = GetFilesInFolder(romFolder, { {".sfc"} }); + vector testRoms = GetFilesInFolder(romFolder, { {".sfc", ".gb", ".gbc"} }); PgoRunTest(testRoms, true); return 0; } diff --git a/UI/Config/EmulationConfig.cs b/UI/Config/EmulationConfig.cs index 7fe971e..08af538 100644 --- a/UI/Config/EmulationConfig.cs +++ b/UI/Config/EmulationConfig.cs @@ -29,7 +29,6 @@ namespace Mesen.GUI.Config public long BsxCustomDate = -1; - [MarshalAs(UnmanagedType.I1)] public bool GbUseBootRom = false; public GameboyModel GbModel = GameboyModel.Auto; public void ApplyConfig() @@ -57,5 +56,6 @@ namespace Mesen.GUI.Config Auto = 0, Gameboy = 1, GameboyColor = 2, + SuperGameboy = 3 } } diff --git a/UI/Debugger/Controls/ctrlDisassemblyView.cs b/UI/Debugger/Controls/ctrlDisassemblyView.cs index d3fea0e..a6cde84 100644 --- a/UI/Debugger/Controls/ctrlDisassemblyView.cs +++ b/UI/Debugger/Controls/ctrlDisassemblyView.cs @@ -177,7 +177,7 @@ namespace Mesen.GUI.Debugger.Controls { SelectedAddressRange range = GetSelectedAddressRange(); if(!_inSourceView && range != null && range.Start.Type == _manager.PrgMemoryType && range.End.Type == _manager.PrgMemoryType) { - DebugApi.MarkBytesAs((UInt32)range.Start.Address, (UInt32)range.End.Address, type); + DebugApi.MarkBytesAs(_manager.CpuType, (UInt32)range.Start.Address, (UInt32)range.End.Address, type); DebugWindowManager.OpenDebugger(_manager.CpuType)?.RefreshDisassembly(); } } diff --git a/UI/Debugger/DebugWindowManager.cs b/UI/Debugger/DebugWindowManager.cs index f9e3617..3b084e2 100644 --- a/UI/Debugger/DebugWindowManager.cs +++ b/UI/Debugger/DebugWindowManager.cs @@ -25,6 +25,7 @@ namespace Mesen.GUI.Debugger return existingWindow; } else { BaseForm frm = null; + switch(window) { case DebugWindow.Debugger: frm = new frmDebugger(CpuType.Cpu); frm.Icon = Properties.Resources.Debugger; break; case DebugWindow.SpcDebugger: frm = new frmDebugger(CpuType.Spc); frm.Icon = Properties.Resources.SpcDebugger; break; @@ -35,15 +36,20 @@ namespace Mesen.GUI.Debugger case DebugWindow.GbDebugger: frm = new frmDebugger(CpuType.Gameboy); frm.Icon = Properties.Resources.GbDebugger; break; case DebugWindow.TraceLogger: frm = new frmTraceLogger(); frm.Icon = Properties.Resources.LogWindow; break; case DebugWindow.MemoryTools: frm = new frmMemoryTools(); frm.Icon = Properties.Resources.CheatCode; break; - case DebugWindow.TileViewer: frm = new frmTileViewer(); frm.Icon = Properties.Resources.VerticalLayout; break; - case DebugWindow.TilemapViewer: frm = new frmTilemapViewer(); frm.Icon = Properties.Resources.VideoOptions; break; - case DebugWindow.PaletteViewer: frm = new frmPaletteViewer(); frm.Icon = Properties.Resources.VideoFilter; break; - case DebugWindow.SpriteViewer: frm = new frmSpriteViewer(); frm.Icon = Properties.Resources.PerfTracker; break; - case DebugWindow.EventViewer: frm = new frmEventViewer(); frm.Icon = Properties.Resources.NesEventViewer; break; + case DebugWindow.TileViewer: frm = new frmTileViewer(CpuType.Cpu); frm.Icon = Properties.Resources.VerticalLayout; break; + case DebugWindow.TilemapViewer: frm = new frmTilemapViewer(CpuType.Cpu); frm.Icon = Properties.Resources.VideoOptions; break; + case DebugWindow.PaletteViewer: frm = new frmPaletteViewer(CpuType.Cpu); frm.Icon = Properties.Resources.VideoFilter; break; + case DebugWindow.SpriteViewer: frm = new frmSpriteViewer(CpuType.Cpu); frm.Icon = Properties.Resources.PerfTracker; break; + case DebugWindow.EventViewer: frm = new frmEventViewer(CpuType.Cpu); frm.Icon = Properties.Resources.NesEventViewer; break; case DebugWindow.ScriptWindow: frm = new frmScript(); frm.Icon = Properties.Resources.Script; break; case DebugWindow.RegisterViewer: frm = new frmRegisterViewer(); frm.Icon = Properties.Resources.RegisterIcon; break; case DebugWindow.Profiler: frm = new frmProfiler(); frm.Icon = Properties.Resources.PerfTracker; break; case DebugWindow.Assembler: frm = new frmAssembler(); frm.Icon = Properties.Resources.Chip; break; + case DebugWindow.GbTileViewer: frm = new frmTileViewer(CpuType.Gameboy); frm.Icon = Properties.Resources.VerticalLayout; break; + case DebugWindow.GbTilemapViewer: frm = new frmTilemapViewer(CpuType.Gameboy); frm.Icon = Properties.Resources.VideoOptions; break; + case DebugWindow.GbPaletteViewer: frm = new frmPaletteViewer(CpuType.Gameboy); frm.Icon = Properties.Resources.VideoFilter; break; + case DebugWindow.GbSpriteViewer: frm = new frmSpriteViewer(CpuType.Gameboy); frm.Icon = Properties.Resources.PerfTracker; break; + case DebugWindow.GbEventViewer: frm = new frmEventViewer(CpuType.Gameboy); frm.Icon = Properties.Resources.NesEventViewer; break; } if(_openedWindows.Count == 0) { @@ -137,6 +143,16 @@ namespace Mesen.GUI.Debugger } } + public static void CloseWindows(CpuType cpuType) + { + List
openedWindows = new List(_openedWindows); + foreach(Form frm in openedWindows) { + if(frm is IDebuggerWindow && ((IDebuggerWindow)frm).CpuType == cpuType) { + frm.Close(); + } + } + } + public static void CloseAll() { List openedWindows = new List(_openedWindows); @@ -157,7 +173,8 @@ namespace Mesen.GUI.Debugger case DebugWindow.Cx4Debugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Cx4); case DebugWindow.GbDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Gameboy); case DebugWindow.TraceLogger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmTraceLogger)); - case DebugWindow.EventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer)); + case DebugWindow.EventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer) && ((frmEventViewer)form).CpuType == CpuType.Cpu); + case DebugWindow.GbEventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer) && ((frmEventViewer)form).CpuType == CpuType.Gameboy); case DebugWindow.Profiler: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmProfiler)); } @@ -191,6 +208,11 @@ namespace Mesen.GUI.Debugger } } + public interface IDebuggerWindow + { + CpuType CpuType { get; } + } + public enum DebugWindow { Debugger, @@ -210,6 +232,11 @@ namespace Mesen.GUI.Debugger ScriptWindow, RegisterViewer, Profiler, - Assembler + Assembler, + GbTileViewer, + GbTilemapViewer, + GbPaletteViewer, + GbSpriteViewer, + GbEventViewer, } } diff --git a/UI/Debugger/EventViewer/ctrlEventViewerListView.cs b/UI/Debugger/EventViewer/ctrlEventViewerListView.cs index 63da439..e6129b1 100644 --- a/UI/Debugger/EventViewer/ctrlEventViewerListView.cs +++ b/UI/Debugger/EventViewer/ctrlEventViewerListView.cs @@ -22,6 +22,8 @@ namespace Mesen.GUI.Debugger private eSortColumn _sortColumn = eSortColumn.Scanline; private bool _sortAscending = true; + public CpuType CpuType { get; set; } = CpuType.Cpu; + public ctrlEventViewerListView() { InitializeComponent(); @@ -39,7 +41,7 @@ namespace Mesen.GUI.Debugger { _breakpoints = BreakpointManager.Breakpoints; EventViewerDisplayOptions options = ConfigManager.Config.Debug.EventViewer.GetInteropOptions(); - DebugEventInfo[] eventInfoArray = DebugApi.GetDebugEvents(options); + DebugEventInfo[] eventInfoArray = DebugApi.GetDebugEvents(this.CpuType, options); lstEvents.BeginUpdate(); _debugEvents = new List(eventInfoArray); diff --git a/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs b/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs index 7869b0c..947a9e0 100644 --- a/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs +++ b/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs @@ -23,7 +23,6 @@ namespace Mesen.GUI.Debugger private int _baseWidth = 1364 / 2; private double _xRatio = 2; - private bool _isGameboy = false; private Point _lastPos = new Point(-1, -1); private bool _needUpdate = false; @@ -53,18 +52,19 @@ namespace Mesen.GUI.Debugger } } + public CpuType CpuType { get; set; } + public void RefreshViewer() { EventViewerDisplayOptions options = ConfigManager.Config.Debug.EventViewer.GetInteropOptions(); - _isGameboy = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; - if(_isGameboy) { + if(this.CpuType == CpuType.Gameboy) { _baseWidth = 456 * 2; _xRatio = 0.5; } else { _baseWidth = 1364 / 2; _xRatio = 2; } - _pictureData = DebugApi.GetEventViewerOutput(_baseWidth, ScanlineCount, options); + _pictureData = DebugApi.GetEventViewerOutput(this.CpuType, _baseWidth, ScanlineCount, options); int picHeight = (int)ScanlineCount*2; if(_screenBitmap == null || _screenBitmap.Height != picHeight || _screenBitmap.Width != _baseWidth) { @@ -179,7 +179,7 @@ namespace Mesen.GUI.Debugger EventViewerDisplayOptions options = ConfigManager.Config.Debug.EventViewer.GetInteropOptions(); DebugEventInfo evt = new DebugEventInfo(); - DebugApi.GetEventViewerEvent(ref evt, (UInt16)pos.Y, (UInt16)pos.X, options); + DebugApi.GetEventViewerEvent(this.CpuType, ref evt, (UInt16)pos.Y, (UInt16)pos.X, options); if(evt.ProgramCounter == 0xFFFFFFFF) { int[] xOffsets = new int[] { 0, 1, -1, 2, -2, 3 }; int[] yOffsets = new int[] { 0, -1, 1 }; @@ -187,7 +187,7 @@ namespace Mesen.GUI.Debugger //Check for other events near the current mouse position for(int j = 0; j < yOffsets.Length; j++) { for(int i = 0; i < xOffsets.Length; i++) { - DebugApi.GetEventViewerEvent(ref evt, (UInt16)(pos.Y + yOffsets[j]), (UInt16)(pos.X + xOffsets[i] * _xRatio), options); + DebugApi.GetEventViewerEvent(this.CpuType, ref evt, (UInt16)(pos.Y + yOffsets[j]), (UInt16)(pos.X + xOffsets[i] * _xRatio), options); if(evt.ProgramCounter != 0xFFFFFFFF) { return evt; } @@ -215,7 +215,7 @@ namespace Mesen.GUI.Debugger } Dictionary values; - if(_isGameboy) { + if(this.CpuType == CpuType.Gameboy) { values = new Dictionary() { { "Type", ResourceHelper.GetEnumText(evt.Type) }, { "Scanline", evt.Scanline.ToString() }, @@ -245,7 +245,7 @@ namespace Mesen.GUI.Debugger values["Register"] = registerText + (isWrite ? " (Write)" : " (Read)") + (isDma ? " (DMA)" : ""); values["Value"] = "$" + evt.Operation.Value.ToString("X2"); - if(isDma && !_isGameboy) { + if(isDma && this.CpuType != CpuType.Gameboy) { bool indirectHdma = false; values["Channel"] = (evt.DmaChannel & 0x07).ToString(); diff --git a/UI/Debugger/EventViewer/frmEventViewer.cs b/UI/Debugger/EventViewer/frmEventViewer.cs index e9fa541..7340f53 100644 --- a/UI/Debugger/EventViewer/frmEventViewer.cs +++ b/UI/Debugger/EventViewer/frmEventViewer.cs @@ -13,16 +13,20 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmEventViewer : BaseForm, IRefresh + public partial class frmEventViewer : BaseForm, IRefresh, IDebuggerWindow { private NotificationListener _notifListener; private WindowRefreshManager _refreshManager; - public ctrlScanlineCycleSelect ScanlineCycleSelect { get { return null; } } + public CpuType CpuType { get; private set; } - public frmEventViewer() + public frmEventViewer(CpuType cpuType) { + this.CpuType = cpuType; InitializeComponent(); + if(cpuType == CpuType.Gameboy) { + this.Text = "GB " + this.Text; + } } protected override void OnLoad(EventArgs e) @@ -41,7 +45,7 @@ namespace Mesen.GUI.Debugger _notifListener = new NotificationListener(); _notifListener.OnNotification += OnNotificationReceived; - _refreshManager = new WindowRefreshManager(this); + _refreshManager = new WindowRefreshManager(this, this.CpuType); _refreshManager.AutoRefresh = config.AutoRefresh; _refreshManager.AutoRefreshSpeed = config.AutoRefreshSpeed; mnuAutoRefresh.Checked = config.AutoRefresh; @@ -86,12 +90,14 @@ namespace Mesen.GUI.Debugger public void RefreshData() { EventViewerDisplayOptions options = ConfigManager.Config.Debug.EventViewer.GetInteropOptions(); - ctrlPpuView.ScanlineCount = DebugApi.TakeEventSnapshot(options); + ctrlPpuView.ScanlineCount = DebugApi.TakeEventSnapshot(this.CpuType, options); } public void RefreshViewer() { - ctrlFilters.SetCpuType(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy ? CpuType.Gameboy : CpuType.Cpu); + ctrlFilters.SetCpuType(this.CpuType); + ctrlPpuView.CpuType = this.CpuType; + ctrlListView.CpuType = this.CpuType; if(tabMain.SelectedTab == tpgPpuView) { ctrlPpuView.RefreshViewer(); } else { diff --git a/UI/Debugger/Integration/DbgImporter.cs b/UI/Debugger/Integration/DbgImporter.cs index 5cec94b..47b1394 100644 --- a/UI/Debugger/Integration/DbgImporter.cs +++ b/UI/Debugger/Integration/DbgImporter.cs @@ -846,7 +846,7 @@ namespace Mesen.GUI.Debugger.Integration } } - DebugApi.SetCdlData(cdlFile, cdlFile.Length); + DebugApi.SetCdlData(CpuType.Cpu, cdlFile, cdlFile.Length); } private bool IsBranchInstruction(byte opCode) diff --git a/UI/Debugger/Labels/LabelManager.cs b/UI/Debugger/Labels/LabelManager.cs index 5f8646b..9e7e459 100644 --- a/UI/Debugger/Labels/LabelManager.cs +++ b/UI/Debugger/Labels/LabelManager.cs @@ -249,9 +249,12 @@ namespace Mesen.GUI.Debugger.Labels public static void SetDefaultLabels() { - if(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy) { + CoprocessorType coproc = EmuApi.GetRomInfo().CoprocessorType; + if(coproc == CoprocessorType.Gameboy || coproc == CoprocessorType.SGB) { SetGameboyDefaultLabels(); - } else { + } + + if(coproc != CoprocessorType.Gameboy) { SetSnesDefaultLabels(); } } diff --git a/UI/Debugger/MemoryTools/ctrlHexViewer.cs b/UI/Debugger/MemoryTools/ctrlHexViewer.cs index 205fac3..f7ad108 100644 --- a/UI/Debugger/MemoryTools/ctrlHexViewer.cs +++ b/UI/Debugger/MemoryTools/ctrlHexViewer.cs @@ -548,7 +548,7 @@ namespace Mesen.GUI.Debugger.Controls } if(start >= 0 && end >= 0 && start <= end) { - DebugApi.MarkBytesAs((UInt32)start, (UInt32)end, type); + DebugApi.MarkBytesAs(_memoryType.ToCpuType(), (UInt32)start, (UInt32)end, type); DebugWindowManager.GetDebugger(_memoryType.ToCpuType())?.RefreshDisassembly(); } diff --git a/UI/Debugger/PpuViewer/WindowRefreshManager.cs b/UI/Debugger/PpuViewer/WindowRefreshManager.cs index 942c191..1bc7663 100644 --- a/UI/Debugger/PpuViewer/WindowRefreshManager.cs +++ b/UI/Debugger/PpuViewer/WindowRefreshManager.cs @@ -17,12 +17,14 @@ namespace Mesen.GUI.Debugger private Stopwatch _timer; private long _lastUpdate = 0; private long _minDelay = 0; + private CpuType _cpuType; public bool AutoRefresh { get; set; } public RefreshSpeed AutoRefreshSpeed { get; set; } - public WindowRefreshManager(IRefresh window) + public WindowRefreshManager(IRefresh window, CpuType cpuType = CpuType.Cpu) { + _cpuType = cpuType; _window = window; _notifListener = new NotificationListener(); _notifListener.OnNotification += OnNotificationReceived; @@ -66,7 +68,7 @@ namespace Mesen.GUI.Debugger break; case ConsoleNotificationType.EventViewerRefresh: - if(_window.ScanlineCycleSelect == null && this.AutoRefresh && (_timer.ElapsedTicks - _lastUpdate) > _minDelay) { + if(_window.ScanlineCycleSelect == null && this.AutoRefresh && (_timer.ElapsedTicks - _lastUpdate) > _minDelay && (CpuType)e.Parameter == _cpuType) { RefreshContent(); } break; diff --git a/UI/Debugger/PpuViewer/ctrlPaletteViewer.cs b/UI/Debugger/PpuViewer/ctrlPaletteViewer.cs index 9666b7f..3c0823d 100644 --- a/UI/Debugger/PpuViewer/ctrlPaletteViewer.cs +++ b/UI/Debugger/PpuViewer/ctrlPaletteViewer.cs @@ -112,9 +112,11 @@ namespace Mesen.GUI.Debugger get { return _cgRam; } } + public CpuType CpuType { get; set; } = CpuType.Cpu; + public void RefreshData() { - if(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy) { + if(this.CpuType == CpuType.Gameboy) { _cgRam = GetGameboyPalette(); } else { _cgRam = DebugApi.GetMemoryState(SnesMemoryType.CGRam); diff --git a/UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs b/UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs index 6126530..b0252fc 100644 --- a/UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs +++ b/UI/Debugger/PpuViewer/ctrlScanlineCycleSelect.cs @@ -18,6 +18,7 @@ namespace Mesen.GUI.Debugger.Controls private int _viewerId = 0; private int _scanline = 241; private int _cycle = 0; + private CpuType _cpuType = CpuType.Cpu; public int Scanline { get { return _scanline; } } public int Cycle { get { return _cycle; } } @@ -34,10 +35,11 @@ namespace Mesen.GUI.Debugger.Controls return _nextViewerId++; } - public void Initialize(int scanline, int cycle) + public void Initialize(int scanline, int cycle, CpuType cpuType) { _scanline = scanline; _cycle = cycle; + _cpuType = cpuType; this.nudScanline.Value = _scanline; this.nudCycle.Value = _cycle; @@ -47,8 +49,8 @@ namespace Mesen.GUI.Debugger.Controls public void RefreshSettings() { - bool isGameboy = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; - DebugApi.SetViewerUpdateTiming(_viewerId, Math.Min(_scanline, isGameboy ? 153 : 312), _cycle); + bool isGameboy = _cpuType == CpuType.Gameboy; + DebugApi.SetViewerUpdateTiming(_viewerId, Math.Min(_scanline, isGameboy ? 153 : 312), _cycle, _cpuType); } private void SetUpdateScanlineCycle(int scanline, int cycle) @@ -65,7 +67,7 @@ namespace Mesen.GUI.Debugger.Controls private void btnReset_Click(object sender, EventArgs e) { - bool isGameboy = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; + bool isGameboy = _cpuType == CpuType.Gameboy; this.nudScanline.Value = isGameboy ? 144 : 241; this.nudCycle.Value = 0; } diff --git a/UI/Debugger/PpuViewer/frmPaletteViewer.cs b/UI/Debugger/PpuViewer/frmPaletteViewer.cs index 33a0eec..3840eff 100644 --- a/UI/Debugger/PpuViewer/frmPaletteViewer.cs +++ b/UI/Debugger/PpuViewer/frmPaletteViewer.cs @@ -5,15 +5,20 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmPaletteViewer : BaseForm, IRefresh + public partial class frmPaletteViewer : BaseForm, IRefresh, IDebuggerWindow { private WindowRefreshManager _refreshManager; - + public CpuType CpuType { get; private set; } public ctrlScanlineCycleSelect ScanlineCycleSelect { get { return this.ctrlScanlineCycleSelect; } } - public frmPaletteViewer() + public frmPaletteViewer(CpuType cpuType) { + this.CpuType = cpuType; InitializeComponent(); + ctrlPaletteViewer.CpuType = cpuType; + if(cpuType == CpuType.Gameboy) { + this.Text = "GB " + this.Text; + } } protected override void OnLoad(EventArgs e) @@ -25,7 +30,7 @@ namespace Mesen.GUI.Debugger _refreshManager = new WindowRefreshManager(this); _refreshManager.AutoRefresh = true; - ctrlScanlineCycleSelect.Initialize(241, 0); + ctrlScanlineCycleSelect.Initialize(241, 0, this.CpuType); double scale = (double)ctrlPaletteViewer.Width / 256; ctrlPaletteViewer.PaletteScale = (int)(16 * scale); diff --git a/UI/Debugger/PpuViewer/frmRegisterViewer.cs b/UI/Debugger/PpuViewer/frmRegisterViewer.cs index 752cf1b..f24bc5d 100644 --- a/UI/Debugger/PpuViewer/frmRegisterViewer.cs +++ b/UI/Debugger/PpuViewer/frmRegisterViewer.cs @@ -53,7 +53,7 @@ namespace Mesen.GUI.Debugger RestoreLocation(config.WindowLocation, config.WindowSize); mnuAutoRefresh.Checked = config.AutoRefresh; - ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle); + ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle, EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy ? CpuType.Gameboy : CpuType.Cpu); _refreshManager = new WindowRefreshManager(this); _refreshManager.AutoRefresh = config.AutoRefresh; @@ -99,7 +99,7 @@ namespace Mesen.GUI.Debugger tabMain.SelectedTab = tpgCpu; } - if(_coprocessorType == CoprocessorType.SA1 || _coprocessorType == CoprocessorType.Gameboy) { + if(_coprocessorType == CoprocessorType.SA1 || _coprocessorType == CoprocessorType.Gameboy || _coprocessorType == CoprocessorType.SGB) { tpgCoprocessor = new TabPage(); tpgCoprocessor.Text = _coprocessorType == CoprocessorType.SA1 ? "SA-1" : "Gameboy"; ctrlCoprocessor = new ctrlPropertyList(); @@ -111,6 +111,9 @@ namespace Mesen.GUI.Debugger tabMain.SelectedTab = tpgCoprocessor; } } + + ctrlScanlineCycleSelect.Initialize(ctrlScanlineCycleSelect.Scanline, ctrlScanlineCycleSelect.Cycle, EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy ? CpuType.Gameboy : CpuType.Cpu); + tabMain.SelectedIndexChanged += tabMain_SelectedIndexChanged; } @@ -153,7 +156,7 @@ namespace Mesen.GUI.Debugger } else if(tabMain.SelectedTab == tpgCoprocessor) { if(_coprocessorType == CoprocessorType.SA1) { UpdateSa1Tab(); - } else if(_coprocessorType == CoprocessorType.Gameboy) { + } else if(_coprocessorType == CoprocessorType.Gameboy || _coprocessorType == CoprocessorType.SGB) { UpdateGameboyTab(); } } diff --git a/UI/Debugger/PpuViewer/frmSpriteViewer.cs b/UI/Debugger/PpuViewer/frmSpriteViewer.cs index 2dae98d..8c29eab 100644 --- a/UI/Debugger/PpuViewer/frmSpriteViewer.cs +++ b/UI/Debugger/PpuViewer/frmSpriteViewer.cs @@ -16,7 +16,7 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmSpriteViewer : BaseForm, IRefresh + public partial class frmSpriteViewer : BaseForm, IRefresh, IDebuggerWindow { private DebugState _state; private byte[] _vram; @@ -26,13 +26,17 @@ namespace Mesen.GUI.Debugger private Bitmap _previewImage; private GetSpritePreviewOptions _options = new GetSpritePreviewOptions(); private WindowRefreshManager _refreshManager; - private bool _isGameboyMode = false; - + + public CpuType CpuType { get; private set; } public ctrlScanlineCycleSelect ScanlineCycleSelect { get { return this.ctrlScanlineCycleSelect; } } - public frmSpriteViewer() + public frmSpriteViewer(CpuType cpuType) { + this.CpuType = cpuType; InitializeComponent(); + if(cpuType == CpuType.Gameboy) { + this.Text = "GB " + this.Text; + } } protected override void OnLoad(EventArgs e) @@ -58,7 +62,7 @@ namespace Mesen.GUI.Debugger mnuAutoRefresh.Checked = config.AutoRefresh; ctrlImagePanel.ImageScale = config.ImageScale; ctrlSplitContainer.SplitterDistance = config.SplitterDistance; - ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle); + ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle, this.CpuType); ctrlSpriteList.HideOffscreenSprites = config.HideOffscreenSprites; RefreshData(); @@ -98,16 +102,15 @@ namespace Mesen.GUI.Debugger public void RefreshData() { - _isGameboyMode = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; _state = DebugApi.GetState(); - _vram = DebugApi.GetMemoryState(_isGameboyMode ? SnesMemoryType.GbVideoRam : SnesMemoryType.VideoRam); - _oamRam = DebugApi.GetMemoryState(_isGameboyMode ? SnesMemoryType.GbSpriteRam : SnesMemoryType.SpriteRam); + _vram = DebugApi.GetMemoryState(this.CpuType == CpuType.Gameboy ? SnesMemoryType.GbVideoRam : SnesMemoryType.VideoRam); + _oamRam = DebugApi.GetMemoryState(this.CpuType == CpuType.Gameboy ? SnesMemoryType.GbSpriteRam : SnesMemoryType.SpriteRam); _cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam); } public void RefreshViewer() { - int height = _isGameboyMode ? 256 : 240; + int height = this.CpuType == CpuType.Gameboy ? 256 : 240; if(_previewImage == null || _previewImage.Height != height) { _previewData = new byte[256 * height * 4]; _previewImage = new Bitmap(256, height, PixelFormat.Format32bppPArgb); @@ -115,9 +118,9 @@ namespace Mesen.GUI.Debugger ctrlImagePanel.Image = _previewImage; } - ctrlSpriteList.SetData(_state, _oamRam, _state.Ppu.OamMode, _isGameboyMode); + ctrlSpriteList.SetData(_state, _oamRam, _state.Ppu.OamMode, this.CpuType == CpuType.Gameboy); - if(_isGameboyMode) { + if(this.CpuType == CpuType.Gameboy) { DebugApi.GetGameboySpritePreview(_options, _state.Gameboy.Ppu, _vram, _oamRam, _previewData); } else { DebugApi.GetSpritePreview(_options, _state.Ppu, _vram, _oamRam, _cgram, _previewData); @@ -166,7 +169,7 @@ namespace Mesen.GUI.Debugger int y = e.Y / ctrlImagePanel.ImageScale; SpriteInfo match = null; - for(int i = 0; i < (_isGameboyMode ? 40 : 128); i++) { + for(int i = 0; i < (this.CpuType == CpuType.Gameboy ? 40 : 128); i++) { SpriteInfo sprite = GetSpriteInfo(i); if(x >= sprite.X && x <= sprite.X + sprite.Width) { int endY = (sprite.Y + sprite.Height) & 0xFF; @@ -184,7 +187,7 @@ namespace Mesen.GUI.Debugger private SpriteInfo GetSpriteInfo(int index) { SpriteInfo sprite; - if(_isGameboyMode) { + if(this.CpuType == CpuType.Gameboy) { sprite = SpriteInfo.GetGbSpriteInfo(_oamRam, index, _state.Gameboy.Ppu.LargeSprites, _state.Gameboy.Ppu.CgbEnabled); } else { sprite = SpriteInfo.GetSpriteInfo(_oamRam, _state.Ppu.OamMode, index); diff --git a/UI/Debugger/PpuViewer/frmTileViewer.cs b/UI/Debugger/PpuViewer/frmTileViewer.cs index 06b42fb..cb91c1f 100644 --- a/UI/Debugger/PpuViewer/frmTileViewer.cs +++ b/UI/Debugger/PpuViewer/frmTileViewer.cs @@ -15,7 +15,7 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmTileViewer : BaseForm, IRefresh + public partial class frmTileViewer : BaseForm, IRefresh, IDebuggerWindow { private int[,] _layerBpp = new int[8, 4] { { 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 } }; @@ -32,10 +32,16 @@ namespace Mesen.GUI.Debugger private NotificationListener _notifListener; public ctrlScanlineCycleSelect ScanlineCycleSelect { get { return this.ctrlScanlineCycleSelect; } } + public CpuType CpuType { get; private set; } - public frmTileViewer() + public frmTileViewer(CpuType cpuType) { + this.CpuType = cpuType; InitializeComponent(); + ctrlPaletteViewer.CpuType = cpuType; + if(cpuType == CpuType.Gameboy) { + this.Text = "GB " + this.Text; + } } protected override void OnLoad(EventArgs evt) @@ -73,7 +79,7 @@ namespace Mesen.GUI.Debugger mnuAutoRefresh.Checked = config.AutoRefresh; chkShowTileGrid.Checked = config.ShowTileGrid; ctrlImagePanel.ImageScale = config.ImageScale; - ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle); + ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle, this.CpuType); double scale = (double)ctrlPaletteViewer.Width / 176; ctrlPaletteViewer.PaletteScale = (int)(11 * scale); @@ -197,7 +203,7 @@ namespace Mesen.GUI.Debugger { _state = DebugApi.GetState(); - if(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy) { + if(this.CpuType == CpuType.Gameboy) { _cgram = ctrlPaletteViewer.GetGameboyPalette(); } else { _cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam); @@ -251,7 +257,7 @@ namespace Mesen.GUI.Debugger btnPresetBg3.Enabled = _layerBpp[_state.Ppu.BgMode, 2] > 0; btnPresetBg4.Enabled = _layerBpp[_state.Ppu.BgMode, 3] > 0; - bool isGameboy = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; + bool isGameboy = this.CpuType == CpuType.Gameboy; lblPresets.Visible = !isGameboy; tlpPresets1.Visible = !isGameboy; tlpPresets2.Visible = !isGameboy; @@ -276,7 +282,7 @@ namespace Mesen.GUI.Debugger cboMemoryType.BeginUpdate(); cboMemoryType.Items.Clear(); - if(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy) { + if(this.CpuType == CpuType.Gameboy) { AddGameboyTypes(); } else { cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.VideoRam)); @@ -305,7 +311,6 @@ namespace Mesen.GUI.Debugger cboMemoryType.Items.Add("-"); cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.BsxMemoryPack)); } - AddGameboyTypes(); } cboMemoryType.SelectedIndex = 0; diff --git a/UI/Debugger/PpuViewer/frmTilemapViewer.cs b/UI/Debugger/PpuViewer/frmTilemapViewer.cs index 6b28db3..054a74e 100644 --- a/UI/Debugger/PpuViewer/frmTilemapViewer.cs +++ b/UI/Debugger/PpuViewer/frmTilemapViewer.cs @@ -15,7 +15,7 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmTilemapViewer : BaseForm, IRefresh + public partial class frmTilemapViewer : BaseForm, IRefresh, IDebuggerWindow { private int[,] _layerBpp = new int[8, 4] { { 2,2,2,2 }, { 4,4,2,0 }, { 4,4,0,0 }, { 8,4,0,0 }, { 8,2,0,0 }, { 4,2,0,0 }, { 4,0,0,0 }, { 8,0,0,0 } }; @@ -29,11 +29,16 @@ namespace Mesen.GUI.Debugger private int _selectedColumn = 0; private DateTime _lastUpdate = DateTime.MinValue; private WindowRefreshManager _refreshManager; - private bool _isGameboyMode = false; + + public CpuType CpuType { get; private set; } - public frmTilemapViewer() + public frmTilemapViewer(CpuType cpuType) { + this.CpuType = cpuType; InitializeComponent(); + if(cpuType == CpuType.Gameboy) { + this.Text = "GB " + this.Text; + } } protected override void OnLoad(EventArgs e) @@ -56,7 +61,7 @@ namespace Mesen.GUI.Debugger chkShowTileGrid.Checked = config.ShowTileGrid; chkShowScrollOverlay.Checked = config.ShowScrollOverlay; ctrlImagePanel.ImageScale = config.ImageScale; - ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle); + ctrlScanlineCycleSelect.Initialize(config.RefreshScanline, config.RefreshCycle, this.CpuType); _refreshManager = new WindowRefreshManager(this); _refreshManager.AutoRefresh = config.AutoRefresh; @@ -104,9 +109,8 @@ namespace Mesen.GUI.Debugger public void RefreshData() { - _isGameboyMode = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; _state = DebugApi.GetState(); - _vram = DebugApi.GetMemoryState(_isGameboyMode ? SnesMemoryType.GbVideoRam : SnesMemoryType.VideoRam); + _vram = DebugApi.GetMemoryState(this.CpuType == CpuType.Gameboy ? SnesMemoryType.GbVideoRam : SnesMemoryType.VideoRam); _cgram = DebugApi.GetMemoryState(SnesMemoryType.CGRam); } @@ -137,7 +141,7 @@ namespace Mesen.GUI.Debugger private int GetWidth() { - if(_isGameboyMode) { + if(this.CpuType == CpuType.Gameboy) { return 256; } else if(_state.Ppu.BgMode == 7) { return 1024; @@ -158,7 +162,7 @@ namespace Mesen.GUI.Debugger private int GetHeight() { - if(_isGameboyMode) { + if(this.CpuType == CpuType.Gameboy) { return 256; } else if(_state.Ppu.BgMode == 7) { return 1024; @@ -178,11 +182,12 @@ namespace Mesen.GUI.Debugger public void RefreshViewer() { + bool isGameboy = this.CpuType == CpuType.Gameboy; if(_layerBpp[_state.Ppu.BgMode, _options.Layer] == 0) { _options.Layer = 0; } - if(_isGameboyMode) { + if(isGameboy) { DebugApi.GetGameboyTilemap(_vram, _state.Gameboy.Ppu, (ushort)(_options.Layer == 0 ? 0x1800 : 0x1C00), _tilemapData); } else { DebugApi.GetTilemap(_options, _state.Ppu, _vram, _cgram, _tilemapData); @@ -211,17 +216,17 @@ namespace Mesen.GUI.Debugger btnLayer3.Enabled = _layerBpp[_state.Ppu.BgMode, 2] > 0; btnLayer4.Enabled = _layerBpp[_state.Ppu.BgMode, 3] > 0; - btnLayer1.Text = _isGameboyMode ? "BG" : "1"; - btnLayer2.Text = _isGameboyMode ? "Window" : "2"; - btnLayer2.Width = _isGameboyMode ? 64 : 32; + btnLayer1.Text = isGameboy ? "BG" : "1"; + btnLayer2.Text = isGameboy ? "Window" : "2"; + btnLayer2.Width = isGameboy ? 64 : 32; - btnLayer3.Visible = !_isGameboyMode; - btnLayer4.Visible = !_isGameboyMode; + btnLayer3.Visible = !isGameboy; + btnLayer4.Visible = !isGameboy; - lblMap.Visible = !_isGameboyMode; - txtMapNumber.Visible = !_isGameboyMode; - lblValue.Visible = !_isGameboyMode; - txtValue.Visible = !_isGameboyMode; + lblMap.Visible = !isGameboy; + txtMapNumber.Visible = !isGameboy; + lblValue.Visible = !isGameboy; + txtValue.Visible = !isGameboy; ctrlImagePanel.ImageSize = new Size(GetWidth(), GetHeight()); ctrlImagePanel.Selection = new Rectangle(_selectedColumn * 8, _selectedRow * 8, IsLargeTileWidth ? 16 : 8, IsLargeTileHeight ? 16 : 8); @@ -230,7 +235,7 @@ namespace Mesen.GUI.Debugger ctrlImagePanel.GridSizeY = chkShowTileGrid.Checked ? (IsLargeTileHeight ? 16 : 8): 0; if(chkShowScrollOverlay.Checked) { - if(_isGameboyMode) { + if(isGameboy) { if(_options.Layer == 0) { GbPpuState ppu = _state.Gameboy.Ppu; ctrlImagePanel.Overlay = new Rectangle(ppu.ScrollX, ppu.ScrollY, 160, 144); @@ -250,7 +255,7 @@ namespace Mesen.GUI.Debugger } ctrlImagePanel.Refresh(); - if(_isGameboyMode) { + if(isGameboy) { UpdateGameboyFields(); } else { UpdateFields(); diff --git a/UI/Debugger/Profiler/frmProfiler.cs b/UI/Debugger/Profiler/frmProfiler.cs index 9ad08d3..a8c9318 100644 --- a/UI/Debugger/Profiler/frmProfiler.cs +++ b/UI/Debugger/Profiler/frmProfiler.cs @@ -98,7 +98,7 @@ namespace Mesen.GUI.Debugger tabMain.SelectedTab = tpgCpu; } - if(romInfo.CoprocessorType == CoprocessorType.SA1 || romInfo.CoprocessorType == CoprocessorType.Gameboy) { + if(romInfo.CoprocessorType == CoprocessorType.SA1 || romInfo.CoprocessorType == CoprocessorType.Gameboy || romInfo.CoprocessorType == CoprocessorType.SGB) { TabPage coprocessorTab = new TabPage(ResourceHelper.GetEnumText(romInfo.CoprocessorType)); tabMain.TabPages.Add(coprocessorTab); diff --git a/UI/Debugger/Workspace/DebugWorkspaceManager.cs b/UI/Debugger/Workspace/DebugWorkspaceManager.cs index 9fd7357..7b70a19 100644 --- a/UI/Debugger/Workspace/DebugWorkspaceManager.cs +++ b/UI/Debugger/Workspace/DebugWorkspaceManager.cs @@ -163,7 +163,7 @@ namespace Mesen.GUI.Debugger.Workspace new WlaDxImporter().Import(symPath, silent); } else { RomInfo romInfo = EmuApi.GetRomInfo(); - if(romInfo.CoprocessorType == CoprocessorType.Gameboy) { + if(romInfo.CoprocessorType == CoprocessorType.Gameboy || romInfo.CoprocessorType == CoprocessorType.SGB) { if(RgbdsSymbolFile.IsValidFile(symPath)) { RgbdsSymbolFile.Import(symPath, silent); } else { diff --git a/UI/Debugger/frmAssembler.cs b/UI/Debugger/frmAssembler.cs index c8ad957..621dd58 100644 --- a/UI/Debugger/frmAssembler.cs +++ b/UI/Debugger/frmAssembler.cs @@ -297,7 +297,7 @@ namespace Mesen.GUI.Debugger AddressInfo absStart = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = _startAddress, Type = memType }); AddressInfo absEnd = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = _startAddress + bytes.Count, Type = memType }); if(absStart.Type == prgType && absEnd.Type == prgType && (absEnd.Address - absStart.Address) == bytes.Count) { - DebugApi.MarkBytesAs((uint)absStart.Address, (uint)absEnd.Address, CdlFlags.Code); + DebugApi.MarkBytesAs(_cpuType, (uint)absStart.Address, (uint)absEnd.Address, CdlFlags.Code); } frmDebugger debugger = DebugWindowManager.OpenDebugger(_cpuType); diff --git a/UI/Debugger/frmDebugger.cs b/UI/Debugger/frmDebugger.cs index 7e40134..a74033e 100644 --- a/UI/Debugger/frmDebugger.cs +++ b/UI/Debugger/frmDebugger.cs @@ -14,7 +14,7 @@ using System.Windows.Forms; namespace Mesen.GUI.Debugger { - public partial class frmDebugger : BaseForm + public partial class frmDebugger : BaseForm, IDebuggerWindow { private EntityBinder _entityBinder = new EntityBinder(); private NotificationListener _notifListener; @@ -137,7 +137,7 @@ namespace Mesen.GUI.Debugger case CpuType.Gameboy: ctrlDisassemblyView.Initialize(new GbDisassemblyManager(), new GbLineStyleProvider()); ConfigApi.SetDebuggerFlag(DebuggerFlags.GbDebuggerEnabled, true); - this.Text = "Game Boy Debugger"; + this.Text = "GB Debugger"; ctrlMemoryMapping = new ctrlMemoryMapping(); ctrlMemoryMapping.Size = new Size(this.ClientSize.Width, 33); @@ -577,16 +577,6 @@ namespace Mesen.GUI.Debugger { switch(e.NotificationType) { case ConsoleNotificationType.GameLoaded: { - if(_cpuType == CpuType.Sa1) { - CoprocessorType coprocessor = EmuApi.GetRomInfo().CoprocessorType; - if(coprocessor != CoprocessorType.SA1) { - this.Invoke((MethodInvoker)(() => { - this.Close(); - })); - return; - } - } - if(ConfigManager.Config.Debug.Debugger.BreakOnPowerCycleReset) { DebugApi.Step(_cpuType, 1, StepType.PpuStep); } @@ -737,8 +727,9 @@ namespace Mesen.GUI.Debugger private void mnuResetCdlLog_Click(object sender, EventArgs e) { - byte[] emptyCdlLog = new byte[DebugApi.GetMemorySize(SnesMemoryType.PrgRom)]; - DebugApi.SetCdlData(emptyCdlLog, emptyCdlLog.Length); + int memSize = DebugApi.GetMemorySize(_cpuType == CpuType.Gameboy ? SnesMemoryType.GbPrgRom : SnesMemoryType.PrgRom); + byte[] emptyCdlLog = new byte[memSize]; + DebugApi.SetCdlData(_cpuType, emptyCdlLog, emptyCdlLog.Length); RefreshDisassembly(); } diff --git a/UI/Debugger/frmTraceLogger.cs b/UI/Debugger/frmTraceLogger.cs index e7f0c8a..d92b585 100644 --- a/UI/Debugger/frmTraceLogger.cs +++ b/UI/Debugger/frmTraceLogger.cs @@ -182,7 +182,7 @@ namespace Mesen.GUI.Debugger chkLogSa1.Visible = coproc == CoprocessorType.SA1; chkLogGsu.Visible = coproc == CoprocessorType.GSU; chkLogCx4.Visible = coproc == CoprocessorType.CX4; - chkLogGameboy.Visible = coproc == CoprocessorType.Gameboy; + chkLogGameboy.Visible = (coproc == CoprocessorType.Gameboy || coproc == CoprocessorType.SGB); } protected void UpdateFormatOptions() diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index ce8b19a..4de9581 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -970,6 +970,7 @@ Auto Game Boy Game Boy Color + Super Game Boy 2 bpp diff --git a/UI/Forms/Config/frmEmulationConfig.Designer.cs b/UI/Forms/Config/frmEmulationConfig.Designer.cs index 04e7fdd..3d50487 100644 --- a/UI/Forms/Config/frmEmulationConfig.Designer.cs +++ b/UI/Forms/Config/frmEmulationConfig.Designer.cs @@ -49,6 +49,17 @@ this.nudRewindSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.lblRewindSpeedHint = new System.Windows.Forms.Label(); this.cboRegion = new System.Windows.Forms.ComboBox(); + 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.tpgBsx = new System.Windows.Forms.TabPage(); + this.grpBsxDateTime = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); + this.dtpBsxCustomDate = new System.Windows.Forms.DateTimePicker(); + this.radBsxLocalTime = new System.Windows.Forms.RadioButton(); + this.radBsxCustomTime = new System.Windows.Forms.RadioButton(); + this.dtpBsxCustomTime = new System.Windows.Forms.DateTimePicker(); this.tpgAdvanced = new System.Windows.Forms.TabPage(); this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); this.chkEnableRandomPowerOnState = new Mesen.GUI.Controls.ctrlRiskyOption(); @@ -68,18 +79,6 @@ this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.lblGsuClockSpeed = new System.Windows.Forms.Label(); - this.tpgBsx = new System.Windows.Forms.TabPage(); - this.grpBsxDateTime = new System.Windows.Forms.GroupBox(); - this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); - this.dtpBsxCustomDate = new System.Windows.Forms.DateTimePicker(); - 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(); @@ -87,6 +86,11 @@ this.flowLayoutPanel9.SuspendLayout(); this.flowLayoutPanel6.SuspendLayout(); this.flowLayoutPanel10.SuspendLayout(); + this.tpgGameboy.SuspendLayout(); + this.tableLayoutPanel7.SuspendLayout(); + this.tpgBsx.SuspendLayout(); + this.grpBsxDateTime.SuspendLayout(); + this.tableLayoutPanel6.SuspendLayout(); this.tpgAdvanced.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); this.tpgOverclocking.SuspendLayout(); @@ -95,11 +99,6 @@ this.grpPpuTiming.SuspendLayout(); this.tableLayoutPanel5.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); - this.tpgBsx.SuspendLayout(); - this.grpBsxDateTime.SuspendLayout(); - this.tableLayoutPanel6.SuspendLayout(); - this.tpgGameboy.SuspendLayout(); - this.tableLayoutPanel7.SuspendLayout(); this.SuspendLayout(); // // baseConfigPanel @@ -433,6 +432,146 @@ this.cboRegion.Size = new System.Drawing.Size(121, 21); this.cboRegion.TabIndex = 18; // + // 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.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel7.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel7.Name = "tableLayoutPanel7"; + this.tableLayoutPanel7.RowCount = 2; + 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.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + 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; + // + // tpgBsx + // + this.tpgBsx.Controls.Add(this.grpBsxDateTime); + this.tpgBsx.Location = new System.Drawing.Point(4, 22); + this.tpgBsx.Name = "tpgBsx"; + this.tpgBsx.Padding = new System.Windows.Forms.Padding(3); + this.tpgBsx.Size = new System.Drawing.Size(437, 264); + this.tpgBsx.TabIndex = 5; + this.tpgBsx.Text = "BS-X"; + this.tpgBsx.UseVisualStyleBackColor = true; + // + // grpBsxDateTime + // + this.grpBsxDateTime.Controls.Add(this.tableLayoutPanel6); + this.grpBsxDateTime.Dock = System.Windows.Forms.DockStyle.Fill; + this.grpBsxDateTime.Location = new System.Drawing.Point(3, 3); + this.grpBsxDateTime.Name = "grpBsxDateTime"; + this.grpBsxDateTime.Size = new System.Drawing.Size(431, 258); + this.grpBsxDateTime.TabIndex = 1; + this.grpBsxDateTime.TabStop = false; + this.grpBsxDateTime.Text = "BS-X/Satellaview Date and Time Settings"; + // + // tableLayoutPanel6 + // + this.tableLayoutPanel6.ColumnCount = 3; + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel6.Controls.Add(this.dtpBsxCustomDate, 1, 1); + this.tableLayoutPanel6.Controls.Add(this.radBsxLocalTime, 0, 0); + this.tableLayoutPanel6.Controls.Add(this.radBsxCustomTime, 0, 1); + this.tableLayoutPanel6.Controls.Add(this.dtpBsxCustomTime, 2, 1); + this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel6.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel6.Name = "tableLayoutPanel6"; + this.tableLayoutPanel6.RowCount = 3; + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel6.Size = new System.Drawing.Size(425, 239); + this.tableLayoutPanel6.TabIndex = 0; + // + // dtpBsxCustomDate + // + this.dtpBsxCustomDate.CustomFormat = ""; + this.dtpBsxCustomDate.Dock = System.Windows.Forms.DockStyle.Fill; + this.dtpBsxCustomDate.Format = System.Windows.Forms.DateTimePickerFormat.Short; + this.dtpBsxCustomDate.Location = new System.Drawing.Point(160, 26); + this.dtpBsxCustomDate.MaxDate = new System.DateTime(2100, 12, 31, 0, 0, 0, 0); + this.dtpBsxCustomDate.MinDate = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); + this.dtpBsxCustomDate.Name = "dtpBsxCustomDate"; + this.dtpBsxCustomDate.Size = new System.Drawing.Size(128, 20); + this.dtpBsxCustomDate.TabIndex = 3; + this.dtpBsxCustomDate.Value = new System.DateTime(2020, 1, 1, 0, 0, 0, 0); + this.dtpBsxCustomDate.Enter += new System.EventHandler(this.dtpBsxCustomDate_Enter); + // + // radBsxLocalTime + // + this.radBsxLocalTime.AutoSize = true; + this.radBsxLocalTime.Location = new System.Drawing.Point(3, 3); + this.radBsxLocalTime.Name = "radBsxLocalTime"; + this.radBsxLocalTime.Size = new System.Drawing.Size(127, 17); + this.radBsxLocalTime.TabIndex = 0; + this.radBsxLocalTime.TabStop = true; + this.radBsxLocalTime.Text = "Use current local time"; + this.radBsxLocalTime.UseVisualStyleBackColor = true; + // + // radBsxCustomTime + // + this.radBsxCustomTime.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.radBsxCustomTime.AutoSize = true; + this.radBsxCustomTime.Location = new System.Drawing.Point(3, 27); + this.radBsxCustomTime.Name = "radBsxCustomTime"; + this.radBsxCustomTime.Size = new System.Drawing.Size(151, 17); + this.radBsxCustomTime.TabIndex = 1; + this.radBsxCustomTime.TabStop = true; + this.radBsxCustomTime.Text = "Use custom date and time:"; + this.radBsxCustomTime.UseVisualStyleBackColor = true; + // + // dtpBsxCustomTime + // + this.dtpBsxCustomTime.CustomFormat = ""; + this.dtpBsxCustomTime.Dock = System.Windows.Forms.DockStyle.Fill; + this.dtpBsxCustomTime.Format = System.Windows.Forms.DateTimePickerFormat.Time; + this.dtpBsxCustomTime.Location = new System.Drawing.Point(294, 26); + this.dtpBsxCustomTime.MaxDate = new System.DateTime(2000, 1, 2, 0, 0, 0, 0); + this.dtpBsxCustomTime.MinDate = new System.DateTime(2000, 1, 1, 0, 0, 0, 0); + this.dtpBsxCustomTime.Name = "dtpBsxCustomTime"; + this.dtpBsxCustomTime.ShowUpDown = true; + this.dtpBsxCustomTime.Size = new System.Drawing.Size(128, 20); + this.dtpBsxCustomTime.TabIndex = 2; + this.dtpBsxCustomTime.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0); + this.dtpBsxCustomTime.Enter += new System.EventHandler(this.dtpBsxCustomTime_Enter); + // // tpgAdvanced // this.tpgAdvanced.Controls.Add(this.tableLayoutPanel2); @@ -728,158 +867,6 @@ this.lblGsuClockSpeed.TabIndex = 0; this.lblGsuClockSpeed.Text = "Super FX clock speed (%):"; // - // tpgBsx - // - this.tpgBsx.Controls.Add(this.grpBsxDateTime); - this.tpgBsx.Location = new System.Drawing.Point(4, 22); - this.tpgBsx.Name = "tpgBsx"; - this.tpgBsx.Padding = new System.Windows.Forms.Padding(3); - this.tpgBsx.Size = new System.Drawing.Size(437, 264); - this.tpgBsx.TabIndex = 5; - this.tpgBsx.Text = "BS-X"; - this.tpgBsx.UseVisualStyleBackColor = true; - // - // grpBsxDateTime - // - this.grpBsxDateTime.Controls.Add(this.tableLayoutPanel6); - this.grpBsxDateTime.Dock = System.Windows.Forms.DockStyle.Fill; - this.grpBsxDateTime.Location = new System.Drawing.Point(3, 3); - this.grpBsxDateTime.Name = "grpBsxDateTime"; - this.grpBsxDateTime.Size = new System.Drawing.Size(431, 258); - this.grpBsxDateTime.TabIndex = 1; - this.grpBsxDateTime.TabStop = false; - this.grpBsxDateTime.Text = "BS-X/Satellaview Date and Time Settings"; - // - // tableLayoutPanel6 - // - this.tableLayoutPanel6.ColumnCount = 3; - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel6.Controls.Add(this.dtpBsxCustomDate, 1, 1); - this.tableLayoutPanel6.Controls.Add(this.radBsxLocalTime, 0, 0); - this.tableLayoutPanel6.Controls.Add(this.radBsxCustomTime, 0, 1); - this.tableLayoutPanel6.Controls.Add(this.dtpBsxCustomTime, 2, 1); - this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel6.Location = new System.Drawing.Point(3, 16); - this.tableLayoutPanel6.Name = "tableLayoutPanel6"; - this.tableLayoutPanel6.RowCount = 3; - this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel6.Size = new System.Drawing.Size(425, 239); - this.tableLayoutPanel6.TabIndex = 0; - // - // dtpBsxCustomDate - // - this.dtpBsxCustomDate.CustomFormat = ""; - this.dtpBsxCustomDate.Dock = System.Windows.Forms.DockStyle.Fill; - this.dtpBsxCustomDate.Format = System.Windows.Forms.DateTimePickerFormat.Short; - this.dtpBsxCustomDate.Location = new System.Drawing.Point(160, 26); - this.dtpBsxCustomDate.MaxDate = new System.DateTime(2100, 12, 31, 0, 0, 0, 0); - this.dtpBsxCustomDate.MinDate = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); - this.dtpBsxCustomDate.Name = "dtpBsxCustomDate"; - this.dtpBsxCustomDate.Size = new System.Drawing.Size(128, 20); - this.dtpBsxCustomDate.TabIndex = 3; - this.dtpBsxCustomDate.Value = new System.DateTime(2020, 1, 1, 0, 0, 0, 0); - this.dtpBsxCustomDate.Enter += new System.EventHandler(this.dtpBsxCustomDate_Enter); - // - // radBsxLocalTime - // - this.radBsxLocalTime.AutoSize = true; - this.radBsxLocalTime.Location = new System.Drawing.Point(3, 3); - this.radBsxLocalTime.Name = "radBsxLocalTime"; - this.radBsxLocalTime.Size = new System.Drawing.Size(127, 17); - this.radBsxLocalTime.TabIndex = 0; - this.radBsxLocalTime.TabStop = true; - this.radBsxLocalTime.Text = "Use current local time"; - this.radBsxLocalTime.UseVisualStyleBackColor = true; - // - // radBsxCustomTime - // - this.radBsxCustomTime.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.radBsxCustomTime.AutoSize = true; - this.radBsxCustomTime.Location = new System.Drawing.Point(3, 27); - this.radBsxCustomTime.Name = "radBsxCustomTime"; - this.radBsxCustomTime.Size = new System.Drawing.Size(151, 17); - this.radBsxCustomTime.TabIndex = 1; - this.radBsxCustomTime.TabStop = true; - this.radBsxCustomTime.Text = "Use custom date and time:"; - this.radBsxCustomTime.UseVisualStyleBackColor = true; - // - // dtpBsxCustomTime - // - this.dtpBsxCustomTime.CustomFormat = ""; - this.dtpBsxCustomTime.Dock = System.Windows.Forms.DockStyle.Fill; - this.dtpBsxCustomTime.Format = System.Windows.Forms.DateTimePickerFormat.Time; - this.dtpBsxCustomTime.Location = new System.Drawing.Point(294, 26); - this.dtpBsxCustomTime.MaxDate = new System.DateTime(2000, 1, 2, 0, 0, 0, 0); - this.dtpBsxCustomTime.MinDate = new System.DateTime(2000, 1, 1, 0, 0, 0, 0); - this.dtpBsxCustomTime.Name = "dtpBsxCustomTime"; - this.dtpBsxCustomTime.ShowUpDown = true; - this.dtpBsxCustomTime.Size = new System.Drawing.Size(128, 20); - this.dtpBsxCustomTime.TabIndex = 2; - 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); @@ -907,6 +894,13 @@ this.flowLayoutPanel6.PerformLayout(); this.flowLayoutPanel10.ResumeLayout(false); this.flowLayoutPanel10.PerformLayout(); + this.tpgGameboy.ResumeLayout(false); + this.tableLayoutPanel7.ResumeLayout(false); + this.tableLayoutPanel7.PerformLayout(); + this.tpgBsx.ResumeLayout(false); + this.grpBsxDateTime.ResumeLayout(false); + this.tableLayoutPanel6.ResumeLayout(false); + this.tableLayoutPanel6.PerformLayout(); this.tpgAdvanced.ResumeLayout(false); this.tableLayoutPanel2.ResumeLayout(false); this.tableLayoutPanel2.PerformLayout(); @@ -919,13 +913,6 @@ this.tableLayoutPanel5.PerformLayout(); this.tableLayoutPanel1.ResumeLayout(false); this.tableLayoutPanel1.PerformLayout(); - this.tpgBsx.ResumeLayout(false); - 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(); @@ -984,6 +971,5 @@ private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7; private System.Windows.Forms.Label lblGameboy; private System.Windows.Forms.ComboBox cboGameboyModel; - private System.Windows.Forms.CheckBox chkUseBootRom; } } \ No newline at end of file diff --git a/UI/Forms/Config/frmEmulationConfig.cs b/UI/Forms/Config/frmEmulationConfig.cs index db66ce3..96e0996 100644 --- a/UI/Forms/Config/frmEmulationConfig.cs +++ b/UI/Forms/Config/frmEmulationConfig.cs @@ -39,7 +39,6 @@ namespace Mesen.GUI.Forms.Config AddBinding(nameof(EmulationConfig.GsuClockSpeed), nudGsuClockSpeed); AddBinding(nameof(EmulationConfig.GbModel), cboGameboyModel); - AddBinding(nameof(EmulationConfig.GbUseBootRom), chkUseBootRom); long customDate = ConfigManager.Config.Emulation.BsxCustomDate; if(customDate >= 0) { diff --git a/UI/Forms/frmMain.Designer.cs b/UI/Forms/frmMain.Designer.cs index fbab926..4554607 100644 --- a/UI/Forms/frmMain.Designer.cs +++ b/UI/Forms/frmMain.Designer.cs @@ -150,6 +150,11 @@ this.mnuTakeScreenshot = new System.Windows.Forms.ToolStripMenuItem(); this.mnuDebug = new System.Windows.Forms.ToolStripMenuItem(); this.mnuGbDebugger = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbEventViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbTilemapViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbTileViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbSpriteViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGbPaletteViewer = new System.Windows.Forms.ToolStripMenuItem(); this.sepGameboyDebugger = new System.Windows.Forms.ToolStripSeparator(); this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem(); this.mnuEventViewer = new System.Windows.Forms.ToolStripMenuItem(); @@ -1095,6 +1100,11 @@ // this.mnuDebug.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.mnuGbDebugger, + this.mnuGbEventViewer, + this.mnuGbTilemapViewer, + this.mnuGbTileViewer, + this.mnuGbSpriteViewer, + this.mnuGbPaletteViewer, this.sepGameboyDebugger, this.mnuDebugger, this.mnuEventViewer, @@ -1127,7 +1137,42 @@ this.mnuGbDebugger.Image = global::Mesen.GUI.Properties.Resources.GbDebugger; this.mnuGbDebugger.Name = "mnuGbDebugger"; this.mnuGbDebugger.Size = new System.Drawing.Size(183, 22); - this.mnuGbDebugger.Text = "Game Boy Debugger"; + this.mnuGbDebugger.Text = "GB Debugger"; + // + // mnuGbEventViewer + // + this.mnuGbEventViewer.Image = global::Mesen.GUI.Properties.Resources.NesEventViewer; + this.mnuGbEventViewer.Name = "mnuGbEventViewer"; + this.mnuGbEventViewer.Size = new System.Drawing.Size(183, 22); + this.mnuGbEventViewer.Text = "GB Event Viewer"; + // + // mnuGbTilemapViewer + // + this.mnuGbTilemapViewer.Image = global::Mesen.GUI.Properties.Resources.VideoOptions; + this.mnuGbTilemapViewer.Name = "mnuGbTilemapViewer"; + this.mnuGbTilemapViewer.Size = new System.Drawing.Size(183, 22); + this.mnuGbTilemapViewer.Text = "GB Tilemap Viewer"; + // + // mnuGbTileViewer + // + this.mnuGbTileViewer.Image = global::Mesen.GUI.Properties.Resources.VerticalLayout; + this.mnuGbTileViewer.Name = "mnuGbTileViewer"; + this.mnuGbTileViewer.Size = new System.Drawing.Size(183, 22); + this.mnuGbTileViewer.Text = "GB Tile Viewer"; + // + // mnuGbSpriteViewer + // + this.mnuGbSpriteViewer.Image = global::Mesen.GUI.Properties.Resources.PerfTracker; + this.mnuGbSpriteViewer.Name = "mnuGbSpriteViewer"; + this.mnuGbSpriteViewer.Size = new System.Drawing.Size(183, 22); + this.mnuGbSpriteViewer.Text = "GB Sprite Viewer"; + // + // mnuGbPaletteViewer + // + this.mnuGbPaletteViewer.Image = global::Mesen.GUI.Properties.Resources.VideoFilter; + this.mnuGbPaletteViewer.Name = "mnuGbPaletteViewer"; + this.mnuGbPaletteViewer.Size = new System.Drawing.Size(183, 22); + this.mnuGbPaletteViewer.Text = "GB Palette Viewer"; // // sepGameboyDebugger // @@ -1513,5 +1558,10 @@ private System.Windows.Forms.ToolStripMenuItem mnuCx4Debugger; private System.Windows.Forms.ToolStripMenuItem mnuGbDebugger; private System.Windows.Forms.ToolStripSeparator sepGameboyDebugger; + private System.Windows.Forms.ToolStripMenuItem mnuGbTilemapViewer; + private System.Windows.Forms.ToolStripMenuItem mnuGbTileViewer; + private System.Windows.Forms.ToolStripMenuItem mnuGbSpriteViewer; + private System.Windows.Forms.ToolStripMenuItem mnuGbPaletteViewer; + private System.Windows.Forms.ToolStripMenuItem mnuGbEventViewer; } } \ No newline at end of file diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index ee19084..4767efb 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -157,6 +157,15 @@ namespace Mesen.GUI.Forms switch(e.NotificationType) { case ConsoleNotificationType.GameLoaded: CheatCodes.ApplyCheats(); + RomInfo romInfo = EmuApi.GetRomInfo(); + + this.Invoke((Action)(() => { + if(romInfo.CoprocessorType == CoprocessorType.Gameboy) { + DebugWindowManager.CloseWindows(CpuType.Cpu); + } else if(romInfo.CoprocessorType != CoprocessorType.SGB) { + DebugWindowManager.CloseWindows(CpuType.Gameboy); + } + })); this.BeginInvoke((Action)(() => { UpdateDebuggerMenu(); @@ -164,7 +173,6 @@ namespace Mesen.GUI.Forms SaveStateManager.UpdateStateMenu(mnuLoadState, false); SaveStateManager.UpdateStateMenu(mnuSaveState, true); - RomInfo romInfo = EmuApi.GetRomInfo(); this.Text = "Mesen-S - " + romInfo.GetRomName(); if(DebugWindowManager.HasOpenedWindow) { @@ -341,7 +349,8 @@ namespace Mesen.GUI.Forms InitNetPlayMenus(); - mnuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Debugger); }; + Func isGameboyMode = () => EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; + mnuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbDebugger : DebugWindow.Debugger); }; mnuSpcDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.SpcDebugger); }; mnuSa1Debugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Sa1Debugger); }; mnuGsuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GsuDebugger); }; @@ -350,16 +359,22 @@ namespace Mesen.GUI.Forms mnuGbDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbDebugger); }; mnuTraceLogger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TraceLogger); }; mnuMemoryTools.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.MemoryTools); }; - mnuTilemapViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TilemapViewer); }; - mnuTileViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TileViewer); }; - mnuSpriteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.SpriteViewer); }; - mnuPaletteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.PaletteViewer); }; - mnuEventViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.EventViewer); }; + mnuTilemapViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbTilemapViewer : DebugWindow.TilemapViewer); }; + mnuTileViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbTileViewer : DebugWindow.TileViewer); }; + mnuSpriteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbSpriteViewer : DebugWindow.SpriteViewer); }; + mnuPaletteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbPaletteViewer : DebugWindow.PaletteViewer); }; + mnuEventViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(isGameboyMode() ? DebugWindow.GbEventViewer : DebugWindow.EventViewer); }; mnuScriptWindow.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.ScriptWindow); }; mnuRegisterViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.RegisterViewer); }; mnuProfiler.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Profiler); }; mnuAssembler.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Assembler); }; + mnuGbTilemapViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbTilemapViewer); }; + mnuGbTileViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbTileViewer); }; + mnuGbSpriteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbSpriteViewer); }; + mnuGbPaletteViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbPaletteViewer); }; + mnuGbEventViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GbEventViewer); }; + mnuTestRun.Click += (s, e) => { RomTestHelper.RunTest(); }; mnuTestRecord.Click += (s, e) => { RomTestHelper.RecordTest(); }; mnuTestStop.Click += (s, e) => { RomTestHelper.StopRecording(); }; @@ -471,14 +486,24 @@ namespace Mesen.GUI.Forms mnuAssembler.Enabled = running; bool isGameboyMode = coprocessor == CoprocessorType.Gameboy; - mnuGbDebugger.Enabled = isGameboyMode; - mnuGbDebugger.Visible = isGameboyMode; - sepGameboyDebugger.Visible = isGameboyMode; + bool isSuperGameboy = coprocessor == CoprocessorType.SGB; - //Remove/disable all tools that aren't useful when running a plain GB game - mnuGbDebugger.Text = isGameboyMode ? "Debugger" : "Game Boy Debugger"; - mnuDebugger.Enabled = running && !isGameboyMode; - mnuDebugger.Visible = !isGameboyMode; + //Only show in super gameboy mode + mnuGbDebugger.Enabled = isSuperGameboy; + mnuGbDebugger.Visible = isSuperGameboy; + mnuGbEventViewer.Enabled = isSuperGameboy; + mnuGbEventViewer.Visible = isSuperGameboy; + mnuGbPaletteViewer.Enabled = isSuperGameboy; + mnuGbPaletteViewer.Visible = isSuperGameboy; + mnuGbSpriteViewer.Enabled = isSuperGameboy; + mnuGbSpriteViewer.Visible = isSuperGameboy; + mnuGbTilemapViewer.Enabled = isSuperGameboy; + mnuGbTilemapViewer.Visible = isSuperGameboy; + mnuGbTileViewer.Enabled = isSuperGameboy; + mnuGbTileViewer.Visible = isSuperGameboy; + sepGameboyDebugger.Visible = isSuperGameboy; + + //Hide in gameboy-only mode mnuSpcDebugger.Enabled = running && !isGameboyMode; mnuSpcDebugger.Visible = !isGameboyMode; sepCoprocessors.Visible = !isGameboyMode; diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index 453b32e..6db6c6e 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -94,16 +94,16 @@ namespace Mesen.GUI [DllImport(DllPath)] public static extern void GetGameboyTilemap(byte[] vram, GbPpuState state, UInt16 offset, [In, Out] byte[] buffer); [DllImport(DllPath)] public static extern void GetGameboySpritePreview(GetSpritePreviewOptions options, GbPpuState state, byte[] vram, byte[] oamRam, [In, Out] byte[] buffer); - [DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle); + [DllImport(DllPath)] public static extern void SetViewerUpdateTiming(Int32 viewerId, Int32 scanline, Int32 cycle, CpuType cpuType); - [DllImport(DllPath)] private static extern UInt32 GetDebugEventCount(EventViewerDisplayOptions options); - [DllImport(DllPath, EntryPoint = "GetDebugEvents")] private static extern void GetDebugEventsWrapper([In, Out]DebugEventInfo[] eventArray, ref UInt32 maxEventCount); - public static DebugEventInfo[] GetDebugEvents(EventViewerDisplayOptions options) + [DllImport(DllPath)] private static extern UInt32 GetDebugEventCount(CpuType cpuType, EventViewerDisplayOptions options); + [DllImport(DllPath, EntryPoint = "GetDebugEvents")] private static extern void GetDebugEventsWrapper(CpuType cpuType, [In, Out]DebugEventInfo[] eventArray, ref UInt32 maxEventCount); + public static DebugEventInfo[] GetDebugEvents(CpuType cpuType, EventViewerDisplayOptions options) { - UInt32 maxEventCount = GetDebugEventCount(options); + UInt32 maxEventCount = GetDebugEventCount(cpuType, options); DebugEventInfo[] debugEvents = new DebugEventInfo[maxEventCount]; - DebugApi.GetDebugEventsWrapper(debugEvents, ref maxEventCount); + DebugApi.GetDebugEventsWrapper(cpuType, debugEvents, ref maxEventCount); if(maxEventCount < debugEvents.Length) { //Remove the excess from the array if needed Array.Resize(ref debugEvents, (int)maxEventCount); @@ -112,15 +112,15 @@ namespace Mesen.GUI return debugEvents; } - [DllImport(DllPath)] public static extern void GetEventViewerEvent(ref DebugEventInfo evtInfo, UInt16 scanline, UInt16 cycle, EventViewerDisplayOptions options); - [DllImport(DllPath)] public static extern UInt32 TakeEventSnapshot(EventViewerDisplayOptions options); + [DllImport(DllPath)] public static extern void GetEventViewerEvent(CpuType cpuType, ref DebugEventInfo evtInfo, UInt16 scanline, UInt16 cycle, EventViewerDisplayOptions options); + [DllImport(DllPath)] public static extern UInt32 TakeEventSnapshot(CpuType cpuType, EventViewerDisplayOptions options); - [DllImport(DllPath, EntryPoint = "GetEventViewerOutput")] private static extern void GetEventViewerOutputWrapper([In, Out]byte[] buffer, UInt32 bufferSize, EventViewerDisplayOptions options); - public static byte[] GetEventViewerOutput(int scanlineWidth, UInt32 scanlineCount, EventViewerDisplayOptions options) + [DllImport(DllPath, EntryPoint = "GetEventViewerOutput")] private static extern void GetEventViewerOutputWrapper(CpuType cpuType, [In, Out]byte[] buffer, UInt32 bufferSize, EventViewerDisplayOptions options); + public static byte[] GetEventViewerOutput(CpuType cpuType, int scanlineWidth, UInt32 scanlineCount, EventViewerDisplayOptions options) { UInt32 bufferSize = (UInt32)(scanlineWidth * scanlineCount * 2 * 4); byte[] buffer = new byte[bufferSize]; - DebugApi.GetEventViewerOutputWrapper(buffer, bufferSize, options); + DebugApi.GetEventViewerOutputWrapper(cpuType, buffer, bufferSize, options); return buffer; } @@ -173,8 +173,8 @@ namespace Mesen.GUI return cdlData; } - [DllImport(DllPath)] public static extern void SetCdlData([In]byte[] cdlData, Int32 length); - [DllImport(DllPath)] public static extern void MarkBytesAs(UInt32 start, UInt32 end, CdlFlags type); + [DllImport(DllPath)] public static extern void SetCdlData(CpuType cpuType, [In]byte[] cdlData, Int32 length); + [DllImport(DllPath)] public static extern void MarkBytesAs(CpuType cpuType, UInt32 start, UInt32 end, CdlFlags type); [DllImport(DllPath, EntryPoint = "AssembleCode")] private static extern UInt32 AssembleCodeWrapper(CpuType cpuType, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string code, UInt32 startAddress, [In, Out]Int16[] assembledCodeBuffer); public static Int16[] AssembleCode(CpuType cpuType, string code, UInt32 startAddress) diff --git a/UI/Interop/EmuApi.cs b/UI/Interop/EmuApi.cs index 310e7c2..bff8f7e 100644 --- a/UI/Interop/EmuApi.cs +++ b/UI/Interop/EmuApi.cs @@ -205,10 +205,38 @@ namespace Mesen.GUI ST011, ST018, CX4, - Gameboy + Gameboy, + SGB } - public enum FirmwareType + public static class CoprocessorTypeExtensions + { + public static CpuType? ToCpuType(this CoprocessorType type) + { + switch(type) { + case CoprocessorType.CX4: + return CpuType.Cx4; + + case CoprocessorType.DSP1: case CoprocessorType.DSP1B: case CoprocessorType.DSP2: case CoprocessorType.DSP3: case CoprocessorType.DSP4: + return CpuType.NecDsp; + + case CoprocessorType.SA1: + return CpuType.Sa1; + + case CoprocessorType.GSU: + return CpuType.Gsu; + + case CoprocessorType.Gameboy: + case CoprocessorType.SGB: + return CpuType.Gameboy; + + default: + return null; + } + } + } + + public enum FirmwareType { CX4, DSP1, @@ -221,7 +249,9 @@ namespace Mesen.GUI ST018, Satellaview, Gameboy, - GameboyColor + GameboyColor, + SgbGameboyCpu, + SGB } public struct MissingFirmwareMessage diff --git a/UI/Utilities/FirmwareHelper.cs b/UI/Utilities/FirmwareHelper.cs index e921cbb..8a3104a 100644 --- a/UI/Utilities/FirmwareHelper.cs +++ b/UI/Utilities/FirmwareHelper.cs @@ -48,6 +48,16 @@ namespace Mesen.GUI.Utilities }; case FirmwareType.Gameboy: return new List() { "CF053ECCB4CCAFFF9E67339D4E78E98DCE7D1ED59BE819D2A1BA2232C6FCE1C7", "26E71CF01E301E5DC40E987CD2ECBF6D0276245890AC829DB2A25323DA86818E" }; case FirmwareType.GameboyColor: return new List() { "B4F2E416A35EEF52CBA161B159C7C8523A92594FACB924B3EDE0D722867C50C7", "3A307A41689BEE99A9A32EA021BF45136906C86B2E4F06C806738398E4F92E45" }; + case FirmwareType.SgbGameboyCpu: return new List() { + "0E4DDFF32FC9D1EEAAE812A157DD246459B00C9E14F2F61751F661F32361E360", //SGB1 + "FD243C4FB27008986316CE3DF29E9CFBCDC0CD52704970555A8BB76EDBEC3988" //SGB2 + }; + case FirmwareType.SGB: return new List() { + "BBA9C269273BEDB9B38BD5EB23BFAA6E509B8DECC7CB80BB5513905AF04F4CEB", //Rev 0 (Japan) + "C6C4DAAB5C899B69900C460787DE6089EDABE94B760F96D9F583D30CC0A5BB30", //Rev 1 (Japan+USA) + "A75160F7B89B1F0E20FD2F6441BB86285C7378DB5035EF6885485EAFF6059376", //Rev 2 (World) + "C172498A23D1176672931BAB33B629C7D28F914A43DCA9E540B8AF1B37CCF2C6", //SGB2 (Japan) + }; } throw new Exception("Unexpected firmware type");