Added Super Game Boy support

Missing support for SGB2's timings and still needs a few tweaks and more testing
This commit is contained in:
Sour 2020-06-18 00:58:22 -04:00
parent 01dd319c9a
commit d204485153
94 changed files with 1789 additions and 679 deletions

2
.gitignore vendored
View file

@ -161,6 +161,8 @@ $RECYCLE.BIN/
.DS_Store
*.nes
*.sfc
*.gb
*.gbc
*.sav
*.svs
*.trt

View file

@ -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<Sa1*>(_coprocessor.get());
_needCoprocSync = true;
} else if(_coprocessorType == CoprocessorType::GSU) {
_coprocessor.reset(new Gsu(_console, _coprocessorRamSize));
_gsu = dynamic_cast<Gsu*>(_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<Cx4*>(_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<SuperGameboy*>(_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;

View file

@ -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<BaseCoprocessor> _coprocessor;
NecDsp *_necDsp = nullptr;
Sa1 *_sa1 = nullptr;
Gsu *_gsu = nullptr;
Cx4 *_cx4 = nullptr;
SuperGameboy *_sgb = nullptr;
BsxCart* _bsx = nullptr;
unique_ptr<BsxMemoryPack> _bsxMemPack;
unique_ptr<Gameboy> _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();

View file

@ -9,7 +9,8 @@ public:
using IMemoryHandler::IMemoryHandler;
virtual void Reset() = 0;
virtual void Run() { }
virtual void ProcessEndOfFrame() { }
virtual void LoadBattery() { }
virtual void SaveBattery() { }

View file

@ -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)

View file

@ -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

View file

@ -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<CpuType type>
void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryRead<type>(addr, value, opType);
}
}
template<CpuType type>
void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryWrite<type>(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<CpuType type>
void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi)
{

View file

@ -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<CpuType type> void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType);
template<CpuType type> 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<CpuType type> __forceinline void ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryRead<type>(addr, value, opType);
}
}
template<CpuType type> __forceinline void ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType)
{
if(_debugger) {
_debugger->ProcessMemoryWrite<type>(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<CpuType cpuType> __forceinline void ProcessPpuCycle()
{
if(_debugger) {
_debugger->ProcessPpuCycle<cpuType>();
}
}
template<CpuType type> void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi);
void ProcessEvent(EventType type);
void BreakImmediately(BreakSource source);

View file

@ -70,6 +70,7 @@
<ClInclude Include="GameboyHeader.h" />
<ClInclude Include="GbApu.h" />
<ClInclude Include="GbAssembler.h" />
<ClInclude Include="GbBootRom.h" />
<ClInclude Include="GbCart.h" />
<ClInclude Include="GbCartFactory.h" />
<ClInclude Include="GbCpu.h" />
@ -236,6 +237,7 @@
<ClInclude Include="SPC_DSP.h" />
<ClInclude Include="SPC_Filter.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="SuperGameboy.h" />
<ClInclude Include="SuperScope.h" />
<ClInclude Include="SystemActionManager.h" />
<ClInclude Include="TraceLogger.h" />
@ -371,6 +373,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='PGO Optimize|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="SuperGameboy.cpp" />
<ClCompile Include="TraceLogger.cpp" />
<ClCompile Include="VideoDecoder.cpp" />
<ClCompile Include="VideoRenderer.cpp" />

View file

@ -596,6 +596,12 @@
<ClInclude Include="IAssembler.h">
<Filter>Debugger\Assembler</Filter>
</ClInclude>
<ClInclude Include="SuperGameboy.h">
<Filter>SNES\Coprocessors\SuperGameboy</Filter>
</ClInclude>
<ClInclude Include="GbBootRom.h">
<Filter>GB</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -956,6 +962,9 @@
<ClCompile Include="GbWaveChannel.cpp">
<Filter>GB\APU</Filter>
</ClCompile>
<ClCompile Include="SuperGameboy.cpp">
<Filter>SNES\Coprocessors\SuperGameboy</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
@ -1048,5 +1057,8 @@
<Filter Include="Debugger\Assembler">
<UniqueIdentifier>{8abb14c6-e2ee-48cb-ad91-38402cb8510c}</UniqueIdentifier>
</Filter>
<Filter Include="SNES\Coprocessors\SuperGameboy">
<UniqueIdentifier>{50d3ab3e-f393-4fa3-a8a6-8ec593089f1b}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -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) {

View file

@ -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<EventManager> GetEventManager();
shared_ptr<Assembler> GetAssembler();

View file

@ -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;

View file

@ -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();

View file

@ -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> 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> 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> 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<CpuType type>
@ -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<CpuType cpuType>
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<CodeDataLogger> cdl = GetCodeDataLogger(cpuType);
if(!cdl) {
return;
}
shared_ptr<CodeDataLogger> 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<CodeDataLogger> cdl = GetCodeDataLogger();
CpuType cpuType = DebugUtilities::ToCpuType(memoryType);
shared_ptr<CodeDataLogger> 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<MemoryAccessCounter> Debugger::GetMemoryAccessCounter()
return _memoryAccessCounter;
}
shared_ptr<CodeDataLogger> Debugger::GetCodeDataLogger()
shared_ptr<CodeDataLogger> 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<PpuTools> Debugger::GetPpuTools()
return _ppuTools;
}
shared_ptr<IEventManager> Debugger::GetEventManager()
shared_ptr<IEventManager> Debugger::GetEventManager(CpuType cpuType)
{
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
if(cpuType == CpuType::Gameboy) {
return std::dynamic_pointer_cast<IEventManager>(_gbDebugger->GetEventManager());
} else {
return std::dynamic_pointer_cast<IEventManager>(_cpuDebugger->GetEventManager());
@ -776,3 +807,6 @@ template void Debugger::ProcessMemoryWrite<CpuType::Gameboy>(uint32_t addr, uint
template void Debugger::ProcessInterrupt<CpuType::Cpu>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Debugger::ProcessInterrupt<CpuType::Sa1>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Debugger::ProcessInterrupt<CpuType::Gameboy>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Debugger::ProcessPpuCycle<CpuType::Cpu>();
template void Debugger::ProcessPpuCycle<CpuType::Gameboy>();

View file

@ -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<BaseCartridge> _cart;
shared_ptr<InternalRegisters> _internalRegs;
shared_ptr<DmaController> _dmaController;
Gameboy* _gameboy = nullptr;
shared_ptr<EmuSettings> _settings;
unique_ptr<SpcDebugger> _spcDebugger;
unique_ptr<CpuDebugger> _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> 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<CpuType cpuType>
void ProcessPpuCycle();
template<CpuType type>
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<TraceLogger> GetTraceLogger();
shared_ptr<MemoryDumper> GetMemoryDumper();
shared_ptr<MemoryAccessCounter> GetMemoryAccessCounter();
shared_ptr<CodeDataLogger> GetCodeDataLogger();
shared_ptr<CodeDataLogger> GetCodeDataLogger(CpuType cpuType);
shared_ptr<Disassembler> GetDisassembler();
shared_ptr<PpuTools> GetPpuTools();
shared_ptr<IEventManager> GetEventManager();
shared_ptr<IEventManager> GetEventManager(CpuType cpuType);
shared_ptr<LabelManager> GetLabelManager();
shared_ptr<ScriptManager> GetScriptManager();
shared_ptr<CallstackManager> GetCallstackManager(CpuType cpuType);

View file

@ -125,7 +125,7 @@ Disassembler::Disassembler(shared_ptr<Console> console, shared_ptr<CodeDataLogge
}
}
DisassemblerSource Disassembler::GetSource(SnesMemoryType type)
DisassemblerSource& Disassembler::GetSource(SnesMemoryType type)
{
if(_sources[(int)type].Data == nullptr) {
throw std::runtime_error("Disassembler::GetSource() invalid memory type");
@ -150,7 +150,7 @@ vector<DisassemblyResult>& 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;

View file

@ -109,7 +109,7 @@ private:
uint8_t* _gbBootRom;
uint32_t _gbBootRomSize;
DisassemblerSource GetSource(SnesMemoryType type);
DisassemblerSource& GetSource(SnesMemoryType type);
vector<DisassemblyResult>& GetDisassemblyList(CpuType type);
void SetDisassembleFlag(CpuType type);

View file

@ -11,5 +11,7 @@ enum class EventType
InputPolled,
StateLoaded,
StateSaved,
GbStartFrame,
GbEndFrame,
EventTypeSize
};

View file

@ -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;
}
};

View file

@ -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<EmuSettings> settings = console->GetSettings();
EmulationConfig cfg = settings->GetEmulationConfig();
switch(cfg.GbModel) {
default:
case GameboyModel::Auto: gb->_cgbMode = (header.CgbFlag & 0x80) != 0; break;
case GameboyModel::Gameboy: gb->_cgbMode = false; break;
case GameboyModel::GameboyColor: gb->_cgbMode = true; break;
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<EmuSettings> 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()

View file

@ -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<GbMemoryManager> _memoryManager;
unique_ptr<GbCpu> _cpu;
@ -30,9 +33,9 @@ private:
unique_ptr<GbTimer> _timer;
unique_ptr<GbDmaController> _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();

View file

@ -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<uint32_t>({ clocksToRun, _square1.GetState().Timer, _square2.GetState().Timer, _wave.GetState().Timer, _noise.GetState().Timer });
uint32_t minTimer = std::min<uint32_t>({ 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>(uint8_t value, uint8_t& length, bool& lengthEnabled, bool& enabled);

View file

@ -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<GbSquareChannel> _square1;
unique_ptr<GbSquareChannel> _square2;
unique_ptr<GbWaveChannel> _wave;
unique_ptr<GbNoiseChannel> _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);

View file

@ -14,6 +14,10 @@ GbAssembler::GbAssembler(shared_ptr<LabelManager> 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<strin
}
} else {
//Decimal
for(int i = 0; i < operand.size(); i++) {
for(size_t i = 0; i < operand.size(); i++) {
if(operand[i] != '-' && (operand[i] < '0' || operand[i] > '9')) {
return -1;
}
@ -218,6 +222,9 @@ void GbAssembler::PushWord(uint16_t operand, vector<int16_t>& output, uint32_t&
void GbAssembler::ProcessOperand(ParamEntry& entry, string operand, vector<int16_t>& output, uint32_t& address, unordered_map<string, uint16_t>& localLabels, bool firstPass)
{
switch(entry.Type) {
default:
break;
case ParamType::Byte:
PushByte((uint8_t)ReadValue(operand, -128, 255, localLabels, firstPass), output, address);
break;

View file

@ -50,6 +50,7 @@ private:
public:
GbAssembler(shared_ptr<LabelManager> labelManager);
virtual ~GbAssembler();
uint32_t AssembleCode(string code, uint32_t startAddress, int16_t* assembledCode);
};

250
Core/GbBootRom.h Normal file
View file

@ -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
};

View file

@ -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()

View file

@ -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();

View file

@ -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<GbEventManager> GbDebugger::GetEventManager()
{
return _eventManager;

View file

@ -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<GbEventManager> GetEventManager();
shared_ptr<GbAssembler> GetAssembler();

View file

@ -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(

View file

@ -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);

View file

@ -6,7 +6,7 @@
class GbApu;
class GbNoiseChannel : public ISerializable
class GbNoiseChannel final : public ISerializable
{
private:
GbNoiseState _state = {};

View file

@ -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<CpuType::Gameboy>();
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;

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -6,7 +6,7 @@
class GbApu;
class GbWaveChannel : public ISerializable
class GbWaveChannel final : public ISerializable
{
private:
GbWaveState _state = {};

View file

@ -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;

View file

@ -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();

View file

@ -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);
*/

View file

@ -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<CpuType::Cpu>();
_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<CpuType::Cpu>();
_regs->ProcessIrqCounters();
}
SyncCoprocessors();
_cart->SyncCoprocessors();
}
uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type)

View file

@ -60,6 +60,8 @@ std::unordered_map<string, string> 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." },

View file

@ -59,7 +59,7 @@ public:
static NecDsp* InitCoprocessor(CoprocessorType type, Console* console, vector<uint8_t> &embeddedFirmware);
void Reset() override;
void Run();
void Run() override;
void LoadBattery() override;
void SaveBattery() override;

View file

@ -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;

View file

@ -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<uint32_t, uint32_t> _updateTimings;
unordered_map<uint32_t, ViewerRefreshConfig> _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);

View file

@ -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;
};

View file

@ -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<uint8_t> frameData;

View file

@ -16,7 +16,7 @@ private:
bool GetScreenshotData(vector<uint8_t>& 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> console);

View file

@ -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);

View file

@ -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;
};

View file

@ -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> msu1 = _console->GetMsu1();
if(msu1) {
msu1->MixAudio(out, count, cfg.SampleRate);

View file

@ -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);
}
}

View file

@ -29,6 +29,8 @@ class SpcDebugger final : public IDebugger
uint8_t _prevOpCode = 0xFF;
uint32_t _prevProgramCounter = 0;
DebugState _debugState;
public:
SpcDebugger(Debugger* debugger);

292
Core/SuperGameboy.cpp Normal file
View file

@ -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);
}

74
Core/SuperGameboy.h Normal file
View file

@ -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;
};

View file

@ -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); }

View file

@ -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) {

View file

@ -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 \

View file

@ -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<BaseCartridge> 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<BaseCartridge> 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);

View file

@ -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

View file

@ -47,7 +47,7 @@ int main(int argc, char* argv[])
romFolder = argv[1];
}
vector<string> testRoms = GetFilesInFolder(romFolder, { {".sfc"} });
vector<string> testRoms = GetFilesInFolder(romFolder, { {".sfc", ".gb", ".gbc"} });
PgoRunTest(testRoms, true);
return 0;
}

View file

@ -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
}
}

View file

@ -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();
}
}

View file

@ -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<Form> openedWindows = new List<Form>(_openedWindows);
foreach(Form frm in openedWindows) {
if(frm is IDebuggerWindow && ((IDebuggerWindow)frm).CpuType == cpuType) {
frm.Close();
}
}
}
public static void CloseAll()
{
List<Form> openedWindows = new List<Form>(_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,
}
}

View file

@ -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<DebugEventInfo>(eventInfoArray);

View file

@ -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<string, string> values;
if(_isGameboy) {
if(this.CpuType == CpuType.Gameboy) {
values = new Dictionary<string, string>() {
{ "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();

View file

@ -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 {

View file

@ -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)

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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);

View file

@ -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 {

View file

@ -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);

View file

@ -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();
}

View file

@ -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()

View file

@ -970,6 +970,7 @@
<Value ID="Auto">Auto</Value>
<Value ID="Gameboy">Game Boy</Value>
<Value ID="GameboyColor">Game Boy Color</Value>
<Value ID="SuperGameboy">Super Game Boy</Value>
</Enum>
<Enum ID="TileFormat">
<Value ID="Bpp2">2 bpp</Value>

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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;
}
}

View file

@ -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<bool> 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;

View file

@ -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)

View file

@ -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

View file

@ -48,6 +48,16 @@ namespace Mesen.GUI.Utilities
};
case FirmwareType.Gameboy: return new List<string>() { "CF053ECCB4CCAFFF9E67339D4E78E98DCE7D1ED59BE819D2A1BA2232C6FCE1C7", "26E71CF01E301E5DC40E987CD2ECBF6D0276245890AC829DB2A25323DA86818E" };
case FirmwareType.GameboyColor: return new List<string>() { "B4F2E416A35EEF52CBA161B159C7C8523A92594FACB924B3EDE0D722867C50C7", "3A307A41689BEE99A9A32EA021BF45136906C86B2E4F06C806738398E4F92E45" };
case FirmwareType.SgbGameboyCpu: return new List<string>() {
"0E4DDFF32FC9D1EEAAE812A157DD246459B00C9E14F2F61751F661F32361E360", //SGB1
"FD243C4FB27008986316CE3DF29E9CFBCDC0CD52704970555A8BB76EDBEC3988" //SGB2
};
case FirmwareType.SGB: return new List<string>() {
"BBA9C269273BEDB9B38BD5EB23BFAA6E509B8DECC7CB80BB5513905AF04F4CEB", //Rev 0 (Japan)
"C6C4DAAB5C899B69900C460787DE6089EDABE94B760F96D9F583D30CC0A5BB30", //Rev 1 (Japan+USA)
"A75160F7B89B1F0E20FD2F6441BB86285C7378DB5035EF6885485EAFF6059376", //Rev 2 (World)
"C172498A23D1176672931BAB33B629C7D28F914A43DCA9E540B8AF1B37CCF2C6", //SGB2 (Japan)
};
}
throw new Exception("Unexpected firmware type");