From 134c28ed9f9987d62b2e4da8d5b11f74fc110ad8 Mon Sep 17 00:00:00 2001 From: Sour Date: Thu, 21 May 2020 20:57:00 -0400 Subject: [PATCH] GB: Replace scanline renderer with pixel renderer Probably still not very accurate --- Core/BaseEventManager.h | 80 ++++ Core/BreakpointManager.cpp | 4 +- Core/BreakpointManager.h | 6 +- Core/Console.cpp | 17 +- Core/Core.vcxproj | 3 + Core/Core.vcxproj.filters | 24 +- Core/CpuDebugger.cpp | 11 +- Core/CpuDebugger.h | 4 +- Core/DebugTypes.h | 8 + Core/Debugger.cpp | 19 +- Core/Debugger.h | 4 +- Core/EventManager.cpp | 7 +- Core/EventManager.h | 77 +--- Core/Gameboy.cpp | 7 +- Core/Gameboy.h | 2 + Core/GbCpu.cpp | 6 +- Core/GbCpu.h | 4 +- Core/GbDebugger.cpp | 26 +- Core/GbDebugger.h | 5 + Core/GbEventManager.cpp | 257 ++++++++++++ Core/GbEventManager.h | 54 +++ Core/GbPpu.cpp | 390 ++++++++++++------ Core/GbPpu.h | 43 +- InteropDLL/DebugApiWrapper.cpp | 3 +- .../ctrlEventViewerFilters.Designer.cs | 24 +- .../EventViewer/ctrlEventViewerFilters.cs | 24 ++ .../EventViewer/ctrlEventViewerPpuView.cs | 58 ++- UI/Debugger/EventViewer/frmEventViewer.cs | 1 + UI/Forms/frmMain.cs | 27 +- UI/Interop/DebugApi.cs | 9 +- 30 files changed, 907 insertions(+), 297 deletions(-) create mode 100644 Core/BaseEventManager.h create mode 100644 Core/GbEventManager.cpp create mode 100644 Core/GbEventManager.h diff --git a/Core/BaseEventManager.h b/Core/BaseEventManager.h new file mode 100644 index 0000000..41e73b9 --- /dev/null +++ b/Core/BaseEventManager.h @@ -0,0 +1,80 @@ +#pragma once +#include "stdafx.h" +#include "DebugTypes.h" + +struct DebugEventInfo +{ + MemoryOperationInfo Operation; + DebugEventType Type; + uint32_t ProgramCounter; + uint16_t Scanline; + uint16_t Cycle; + int16_t BreakpointId; + int8_t DmaChannel; + DmaChannelConfig DmaChannelInfo; +}; + +struct EventViewerDisplayOptions +{ + uint32_t IrqColor; + uint32_t NmiColor; + uint32_t BreakpointColor; + + uint32_t PpuRegisterReadColor; + uint32_t PpuRegisterWriteCgramColor; + uint32_t PpuRegisterWriteVramColor; + uint32_t PpuRegisterWriteOamColor; + uint32_t PpuRegisterWriteMode7Color; + uint32_t PpuRegisterWriteBgOptionColor; + uint32_t PpuRegisterWriteBgScrollColor; + uint32_t PpuRegisterWriteWindowColor; + uint32_t PpuRegisterWriteOtherColor; + + uint32_t ApuRegisterReadColor; + uint32_t ApuRegisterWriteColor; + uint32_t CpuRegisterReadColor; + uint32_t CpuRegisterWriteColor; + uint32_t WorkRamRegisterReadColor; + uint32_t WorkRamRegisterWriteColor; + + bool ShowPpuRegisterCgramWrites; + bool ShowPpuRegisterVramWrites; + bool ShowPpuRegisterOamWrites; + bool ShowPpuRegisterMode7Writes; + bool ShowPpuRegisterBgOptionWrites; + bool ShowPpuRegisterBgScrollWrites; + bool ShowPpuRegisterWindowWrites; + bool ShowPpuRegisterOtherWrites; + + bool ShowPpuRegisterReads; + bool ShowCpuRegisterWrites; + bool ShowCpuRegisterReads; + + bool ShowApuRegisterWrites; + bool ShowApuRegisterReads; + bool ShowWorkRamRegisterWrites; + bool ShowWorkRamRegisterReads; + + bool ShowNmi; + bool ShowIrq; + + bool ShowMarkedBreakpoints; + bool ShowPreviousFrameEvents; + + bool ShowDmaChannels[8]; +}; + +class IEventManager +{ +public: + virtual void AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId = -1) = 0; + virtual void AddEvent(DebugEventType type) = 0; + + virtual void GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount) = 0; + virtual uint32_t GetEventCount(EventViewerDisplayOptions options) = 0; + virtual void ClearFrameEvents() = 0; + + virtual uint32_t TakeEventSnapshot(EventViewerDisplayOptions options) = 0; + virtual void GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options) = 0; + virtual DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options) = 0; +}; diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index ab27ce0..d66e6c0 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -7,12 +7,12 @@ #include "ExpressionEvaluator.h" #include "EventManager.h" -BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType) +BreakpointManager::BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager) { _debugger = debugger; _cpuType = cpuType; _hasBreakpoint = false; - _eventManager = debugger->GetEventManager().get(); + _eventManager = eventManager ? eventManager : debugger->GetEventManager().get(); } void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h index ecaac50..770b33f 100644 --- a/Core/BreakpointManager.h +++ b/Core/BreakpointManager.h @@ -6,7 +6,7 @@ class ExpressionEvaluator; class Debugger; -class EventManager; +class IEventManager; struct ExpressionData; enum class MemoryOperationType; @@ -17,7 +17,7 @@ private: Debugger *_debugger; CpuType _cpuType; - EventManager *_eventManager; + IEventManager *_eventManager; vector _breakpoints[BreakpointTypeCount]; vector _rpnList[BreakpointTypeCount]; @@ -30,7 +30,7 @@ private: int InternalCheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); public: - BreakpointManager(Debugger *debugger, CpuType cpuType); + BreakpointManager(Debugger *debugger, CpuType cpuType, IEventManager* eventManager = nullptr); void SetBreakpoints(Breakpoint breakpoints[], uint32_t count); __forceinline int CheckBreakpoint(MemoryOperationInfo operationInfo, AddressInfo &address); diff --git a/Core/Console.cpp b/Core/Console.cpp index a15e4c6..69bb3af 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -429,13 +429,6 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _memoryManager->Initialize(this); _internalRegisters->Initialize(this); - if(debuggerActive) { - GetDebugger(); - } - - _ppu->PowerOn(); - _cpu->PowerOn(); - if(_cart->GetGameboy()) { _cart->GetGameboy()->PowerOn(); _settings->SetFlag(EmulationFlags::GameboyMode); @@ -443,6 +436,13 @@ bool Console::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom, _settings->ClearFlag(EmulationFlags::GameboyMode); } + if(debuggerActive) { + GetDebugger(); + } + + _ppu->PowerOn(); + _cpu->PowerOn(); + _rewindManager.reset(new RewindManager(shared_from_this())); _notificationManager->RegisterNotificationListener(_rewindManager); @@ -970,4 +970,5 @@ template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t v template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); -template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); \ No newline at end of file +template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); +template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 81e7eb0..a481c61 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -48,6 +48,7 @@ + @@ -72,6 +73,7 @@ + @@ -278,6 +280,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 2578e39..34cb734 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -176,9 +176,6 @@ Debugger - - Debugger - Misc @@ -581,6 +578,15 @@ GB\Carts + + Debugger\EventManager + + + Debugger\EventManager + + + Debugger\EventManager + @@ -668,9 +674,6 @@ Debugger - - Debugger - Debugger @@ -923,6 +926,12 @@ GB + + Debugger\EventManager + + + Debugger\EventManager + @@ -1009,5 +1018,8 @@ {c020f128-b5e1-4f6c-9849-ff098fe93d39} + + {b1753ff0-0c73-4acf-978b-1964222e01c6} + \ No newline at end of file diff --git a/Core/CpuDebugger.cpp b/Core/CpuDebugger.cpp index 69418d8..d9dc610 100644 --- a/Core/CpuDebugger.cpp +++ b/Core/CpuDebugger.cpp @@ -33,11 +33,11 @@ CpuDebugger::CpuDebugger(Debugger* debugger, CpuType cpuType) _sa1 = debugger->GetConsole()->GetCartridge()->GetSa1(); _codeDataLogger = debugger->GetCodeDataLogger().get(); _settings = debugger->GetConsole()->GetSettings().get(); - _eventManager = debugger->GetEventManager().get(); _memoryManager = debugger->GetConsole()->GetMemoryManager().get(); - + + _eventManager.reset(new EventManager(debugger, _cpu, _debugger->GetConsole()->GetPpu().get(), _memoryManager, _debugger->GetConsole()->GetDmaController().get())); _callstackManager.reset(new CallstackManager(debugger)); - _breakpointManager.reset(new BreakpointManager(debugger, cpuType)); + _breakpointManager.reset(new BreakpointManager(debugger, cpuType, _eventManager.get())); _step.reset(new StepRequest()); if(GetState().PC == 0) { @@ -235,6 +235,11 @@ bool CpuDebugger::IsRegister(uint32_t addr) return _cpuType == CpuType::Cpu && _memoryManager->IsRegister(addr); } +shared_ptr CpuDebugger::GetEventManager() +{ + return _eventManager; +} + shared_ptr CpuDebugger::GetCallstackManager() { return _callstackManager; diff --git a/Core/CpuDebugger.h b/Core/CpuDebugger.h index d2ee645..2de234a 100644 --- a/Core/CpuDebugger.h +++ b/Core/CpuDebugger.h @@ -27,10 +27,10 @@ class CpuDebugger final : public IDebugger MemoryManager* _memoryManager; EmuSettings* _settings; CodeDataLogger* _codeDataLogger; - EventManager* _eventManager; Cpu* _cpu; Sa1* _sa1; + shared_ptr _eventManager; shared_ptr _callstackManager; unique_ptr _breakpointManager; unique_ptr _step; @@ -53,6 +53,8 @@ public: void Run(); void Step(int32_t stepCount, StepType type); void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); + + shared_ptr GetEventManager(); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); }; \ No newline at end of file diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index e3dd3ac..a36f361 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -212,6 +212,14 @@ struct StackFrameInfo StackFrameFlags Flags; }; +enum class DebugEventType +{ + Register, + Nmi, + Irq, + Breakpoint +}; + enum class BreakSource { Unspecified = -1, diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 1212893..e756583 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -32,6 +32,7 @@ #include "BreakpointManager.h" #include "PpuTools.h" #include "EventManager.h" +#include "GbEventManager.h" #include "EventType.h" #include "DebugBreakHelper.h" #include "LabelManager.h" @@ -72,10 +73,12 @@ Debugger::Debugger(shared_ptr console) _traceLogger.reset(new TraceLogger(this, _console)); _memoryAccessCounter.reset(new MemoryAccessCounter(this, console.get())); _ppuTools.reset(new PpuTools(_console.get(), _ppu.get())); - _eventManager.reset(new EventManager(this, _cpu.get(), _ppu.get(), _memoryManager.get(), _console->GetDmaController().get())); _scriptManager.reset(new ScriptManager(this)); _assembler.reset(new Assembler(_labelManager)); + if(_cart->GetGameboy()) { + _gbDebugger.reset(new GbDebugger(this)); + } _cpuDebugger.reset(new CpuDebugger(this, CpuType::Cpu)); _spcDebugger.reset(new SpcDebugger(this)); if(_cart->GetSa1()) { @@ -86,8 +89,6 @@ Debugger::Debugger(shared_ptr console) _necDspDebugger.reset(new NecDspDebugger(this)); } else if(_cart->GetCx4()) { _cx4Debugger.reset(new Cx4Debugger(this)); - } else if(_cart->GetGameboy()) { - _gbDebugger.reset(new GbDebugger(this)); } _step.reset(new StepRequest()); @@ -282,6 +283,7 @@ void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool fo switch(type) { case CpuType::Cpu: _cpuDebugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; case CpuType::Sa1: _sa1Debugger->ProcessInterrupt(originalPc, currentPc, forNmi); break; + case CpuType::Gameboy: _gbDebugger->ProcessInterrupt(originalPc, currentPc); break; } } @@ -294,7 +296,7 @@ void Debugger::ProcessEvent(EventType type) case EventType::StartFrame: _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerRefresh); - _eventManager->ClearFrameEvents(); + GetEventManager()->ClearFrameEvents(); break; case EventType::Reset: @@ -670,9 +672,13 @@ shared_ptr Debugger::GetPpuTools() return _ppuTools; } -shared_ptr Debugger::GetEventManager() +shared_ptr Debugger::GetEventManager() { - return _eventManager; + if(_settings->CheckFlag(EmulationFlags::GameboyMode)) { + return std::dynamic_pointer_cast(_gbDebugger->GetEventManager()); + } else { + return std::dynamic_pointer_cast(_cpuDebugger->GetEventManager()); + } } shared_ptr Debugger::GetLabelManager() @@ -729,3 +735,4 @@ template void Debugger::ProcessMemoryWrite(uint32_t addr, uint template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); +template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); diff --git a/Core/Debugger.h b/Core/Debugger.h index afdc4e7..151beb5 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -35,6 +35,7 @@ class Cx4Debugger; class GbDebugger; class Breakpoint; class Assembler; +class IEventManager; enum class EventType; enum class EvalResultType : int32_t; @@ -67,7 +68,6 @@ private: shared_ptr _codeDataLogger; shared_ptr _disassembler; shared_ptr _ppuTools; - shared_ptr _eventManager; shared_ptr _labelManager; shared_ptr _assembler; @@ -139,7 +139,7 @@ public: shared_ptr GetCodeDataLogger(); shared_ptr GetDisassembler(); shared_ptr GetPpuTools(); - shared_ptr GetEventManager(); + shared_ptr GetEventManager(); shared_ptr GetLabelManager(); shared_ptr GetScriptManager(); shared_ptr GetCallstackManager(CpuType cpuType); diff --git a/Core/EventManager.cpp b/Core/EventManager.cpp index 491f25d..5be0198 100644 --- a/Core/EventManager.cpp +++ b/Core/EventManager.cpp @@ -8,6 +8,7 @@ #include "Debugger.h" #include "DebugBreakHelper.h" #include "DefaultVideoFilter.h" +#include "BaseEventManager.h" EventManager::EventManager(Debugger *debugger, Cpu *cpu, Ppu *ppu, MemoryManager *memoryManager, DmaController *dmaController) { @@ -263,10 +264,14 @@ uint32_t EventManager::TakeEventSnapshot(EventViewerDisplayOptions options) return _scanlineCount; } -void EventManager::GetDisplayBuffer(uint32_t *buffer, EventViewerDisplayOptions options) +void EventManager::GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options) { auto lock = _lock.AcquireSafe(); + if(bufferSize < _scanlineCount * 2 * EventManager::ScanlineWidth * 4) { + return; + } + for(int i = 0; i < EventManager::ScanlineWidth * (int)_scanlineCount * 2; i++) { buffer[i] = 0xFF555555; } diff --git a/Core/EventManager.h b/Core/EventManager.h index b51200e..421650d 100644 --- a/Core/EventManager.h +++ b/Core/EventManager.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "DmaController.h" #include "DebugTypes.h" +#include "BaseEventManager.h" #include "../Utilities/SimpleLock.h" enum class DebugEventType; @@ -13,7 +14,7 @@ class Debugger; class DmaController; class MemoryManager; -class EventManager +class EventManager final : public IEventManager { private: static constexpr int ScanlineWidth = 1364 / 2; @@ -28,7 +29,7 @@ private: vector _sentEvents; vector _snapshot; - uint16_t _snapshotScanline = 0; + int16_t _snapshotScanline = -1; uint16_t _snapshotCycle = 0; SimpleLock _lock; @@ -52,76 +53,6 @@ public: void ClearFrameEvents(); uint32_t TakeEventSnapshot(EventViewerDisplayOptions options); - void GetDisplayBuffer(uint32_t *buffer, EventViewerDisplayOptions options); + void GetDisplayBuffer(uint32_t *buffer, uint32_t bufferSize, EventViewerDisplayOptions options); DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions &options); }; - -enum class DebugEventType -{ - Register, - Nmi, - Irq, - Breakpoint -}; - -struct DebugEventInfo -{ - MemoryOperationInfo Operation; - DebugEventType Type; - uint32_t ProgramCounter; - uint16_t Scanline; - uint16_t Cycle; - int16_t BreakpointId; - int8_t DmaChannel; - DmaChannelConfig DmaChannelInfo; -}; - -struct EventViewerDisplayOptions -{ - uint32_t IrqColor; - uint32_t NmiColor; - uint32_t BreakpointColor; - - uint32_t PpuRegisterReadColor; - uint32_t PpuRegisterWriteCgramColor; - uint32_t PpuRegisterWriteVramColor; - uint32_t PpuRegisterWriteOamColor; - uint32_t PpuRegisterWriteMode7Color; - uint32_t PpuRegisterWriteBgOptionColor; - uint32_t PpuRegisterWriteBgScrollColor; - uint32_t PpuRegisterWriteWindowColor; - uint32_t PpuRegisterWriteOtherColor; - - uint32_t ApuRegisterReadColor; - uint32_t ApuRegisterWriteColor; - uint32_t CpuRegisterReadColor; - uint32_t CpuRegisterWriteColor; - uint32_t WorkRamRegisterReadColor; - uint32_t WorkRamRegisterWriteColor; - - bool ShowPpuRegisterCgramWrites; - bool ShowPpuRegisterVramWrites; - bool ShowPpuRegisterOamWrites; - bool ShowPpuRegisterMode7Writes; - bool ShowPpuRegisterBgOptionWrites; - bool ShowPpuRegisterBgScrollWrites; - bool ShowPpuRegisterWindowWrites; - bool ShowPpuRegisterOtherWrites; - - bool ShowPpuRegisterReads; - bool ShowCpuRegisterWrites; - bool ShowCpuRegisterReads; - - bool ShowApuRegisterWrites; - bool ShowApuRegisterReads; - bool ShowWorkRamRegisterWrites; - bool ShowWorkRamRegisterReads; - - bool ShowNmi; - bool ShowIrq; - - bool ShowMarkedBreakpoints; - bool ShowPreviousFrameEvents; - - bool ShowDmaChannels[8]; -}; \ No newline at end of file diff --git a/Core/Gameboy.cpp b/Core/Gameboy.cpp index b0c3833..20ba667 100644 --- a/Core/Gameboy.cpp +++ b/Core/Gameboy.cpp @@ -98,7 +98,7 @@ void Gameboy::PowerOn() _cart->Init(this, _memoryManager.get()); _memoryManager->Init(_console, this, _cart.get(), _ppu.get(), _apu.get(), _timer.get()); - _cpu.reset(new GbCpu(this, _memoryManager.get())); + _cpu.reset(new GbCpu(_console, this, _memoryManager.get())); _ppu->Init(_console, this, _memoryManager.get(), _videoRam, _spriteRam); } @@ -174,6 +174,11 @@ GbPpu* Gameboy::GetPpu() return _ppu.get(); } +GbCpu* Gameboy::GetCpu() +{ + return _cpu.get(); +} + AddressInfo Gameboy::GetAbsoluteAddress(uint16_t addr) { AddressInfo addrInfo = { -1, SnesMemoryType::Register }; diff --git a/Core/Gameboy.h b/Core/Gameboy.h index a15a09a..5669c0c 100644 --- a/Core/Gameboy.h +++ b/Core/Gameboy.h @@ -58,7 +58,9 @@ public: void SaveBattery(); GbPpu* GetPpu(); + GbCpu* GetCpu(); GbState GetState(); + uint32_t DebugGetMemorySize(SnesMemoryType type); uint8_t* DebugGetMemory(SnesMemoryType type); GbMemoryManager* GetMemoryManager(); diff --git a/Core/GbCpu.cpp b/Core/GbCpu.cpp index 612513c..4db52a9 100644 --- a/Core/GbCpu.cpp +++ b/Core/GbCpu.cpp @@ -1,11 +1,13 @@ #include "stdafx.h" +#include "Console.h" #include "GbCpu.h" #include "Gameboy.h" #include "GbMemoryManager.h" #include "../Utilities/Serializer.h" -GbCpu::GbCpu(Gameboy* gameboy, GbMemoryManager* memoryManager) +GbCpu::GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager) { + _console = console; _gameboy = gameboy; _memoryManager = memoryManager; _state = {}; @@ -46,6 +48,7 @@ void GbCpu::Exec() uint8_t irqVector = _memoryManager->ProcessIrqRequests(); if(irqVector) { if(_state.IME) { + uint16_t oldPc = _state.PC; _memoryManager->ClearIrqRequest(irqVector); IncCycleCount(); IncCycleCount(); @@ -59,6 +62,7 @@ void GbCpu::Exec() case GbIrqSource::Joypad: _state.PC = 0x60; break; } _state.IME = false; + _console->ProcessInterrupt(oldPc, _state.PC, false); } _state.Halted = false; } diff --git a/Core/GbCpu.h b/Core/GbCpu.h index 65b2447..bc62958 100644 --- a/Core/GbCpu.h +++ b/Core/GbCpu.h @@ -5,6 +5,7 @@ class GbMemoryManager; class Gameboy; +class Console; class GbCpu : public ISerializable { @@ -16,10 +17,11 @@ private: Register16 _regHL = Register16(&_state.H, &_state.L); GbMemoryManager* _memoryManager; + Console* _console; Gameboy* _gameboy; public: - GbCpu(Gameboy* gameboy, GbMemoryManager* memoryManager); + GbCpu(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager); virtual ~GbCpu(); GbCpuState GetState(); diff --git a/Core/GbDebugger.cpp b/Core/GbDebugger.cpp index 9ee00d8..76bae34 100644 --- a/Core/GbDebugger.cpp +++ b/Core/GbDebugger.cpp @@ -14,6 +14,8 @@ #include "EmuSettings.h" #include "BaseCartridge.h" #include "GameboyDisUtils.h" +#include "GbEventManager.h" +#include "BaseEventManager.h" GbDebugger::GbDebugger(Debugger* debugger) { @@ -25,8 +27,9 @@ GbDebugger::GbDebugger(Debugger* debugger) _memoryManager = debugger->GetConsole()->GetMemoryManager().get(); _settings = debugger->GetConsole()->GetSettings().get(); + _eventManager.reset(new GbEventManager(debugger, _gameboy->GetCpu(), _gameboy->GetPpu())); _callstackManager.reset(new CallstackManager(debugger)); - _breakpointManager.reset(new BreakpointManager(debugger, CpuType::Gameboy)); + _breakpointManager.reset(new BreakpointManager(debugger, CpuType::Gameboy, _eventManager.get())); _step.reset(new StepRequest()); } @@ -88,6 +91,9 @@ void GbDebugger::ProcessRead(uint16_t addr, uint8_t value, MemoryOperationType t _memoryAccessCounter->ProcessMemoryExec(addressInfo, _memoryManager->GetMasterClock()); } else { _memoryAccessCounter->ProcessMemoryRead(addressInfo, _memoryManager->GetMasterClock()); + if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + _eventManager->AddEvent(DebugEventType::Register, operation); + } } _debugger->ProcessBreakConditions(_step->StepCount == 0, GetBreakpointManager(), operation, addressInfo, breakSource); @@ -103,6 +109,10 @@ void GbDebugger::ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType _disassembler->InvalidateCache(addressInfo, CpuType::Gameboy); } + if(addr == 0xFFFF || (addr >= 0xFE00 && addr < 0xFF80) || (addr >= 0x8000 && addr <= 0x9FFF)) { + _eventManager->AddEvent(DebugEventType::Register, operation); + } + _memoryAccessCounter->ProcessMemoryWrite(addressInfo, _memoryManager->GetMasterClock()); } @@ -135,6 +145,20 @@ void GbDebugger::Step(int32_t stepCount, StepType type) _step.reset(new StepRequest(step)); } +void GbDebugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc) +{ + AddressInfo src = _gameboy->GetAbsoluteAddress(_prevProgramCounter); + AddressInfo ret = _gameboy->GetAbsoluteAddress(originalPc); + AddressInfo dest = _gameboy->GetAbsoluteAddress(currentPc); + _callstackManager->Push(src, _prevProgramCounter, dest, currentPc, ret, originalPc, StackFrameFlags::Irq); + _eventManager->AddEvent(DebugEventType::Irq); +} + +shared_ptr GbDebugger::GetEventManager() +{ + return _eventManager; +} + shared_ptr GbDebugger::GetCallstackManager() { return _callstackManager; diff --git a/Core/GbDebugger.h b/Core/GbDebugger.h index 42c2812..e9755cb 100644 --- a/Core/GbDebugger.h +++ b/Core/GbDebugger.h @@ -12,6 +12,7 @@ class MemoryAccessCounter; class MemoryManager; class BreakpointManager; class EmuSettings; +class GbEventManager; class GbDebugger final : public IDebugger { @@ -23,6 +24,7 @@ class GbDebugger final : public IDebugger Gameboy* _gameboy; EmuSettings* _settings; + shared_ptr _eventManager; shared_ptr _callstackManager; unique_ptr _breakpointManager; unique_ptr _step; @@ -39,6 +41,9 @@ public: void ProcessWrite(uint16_t addr, uint8_t value, MemoryOperationType type); void Run(); void Step(int32_t stepCount, StepType type); + void ProcessInterrupt(uint32_t originalPc, uint32_t currentPc); + + shared_ptr GetEventManager(); shared_ptr GetCallstackManager(); BreakpointManager* GetBreakpointManager(); }; \ No newline at end of file diff --git a/Core/GbEventManager.cpp b/Core/GbEventManager.cpp new file mode 100644 index 0000000..bfabc88 --- /dev/null +++ b/Core/GbEventManager.cpp @@ -0,0 +1,257 @@ +#include "stdafx.h" +#include "GbEventManager.h" +#include "DebugTypes.h" +#include "GbCpu.h" +#include "GbPpu.h" +#include "Debugger.h" +#include "DebugBreakHelper.h" +#include "DefaultVideoFilter.h" +#include "Gameboy.h" +#include "Console.h" +#include "BaseCartridge.h" +#include "BaseEventManager.h" + +GbEventManager::GbEventManager(Debugger* debugger, GbCpu* cpu, GbPpu* ppu) +{ + _debugger = debugger; + _cpu = cpu; + _ppu = ppu; + + _ppuBuffer = new uint16_t[456*GbEventManager::ScreenHeight]; + memset(_ppuBuffer, 0, 456*GbEventManager::ScreenHeight * sizeof(uint16_t)); +} + +GbEventManager::~GbEventManager() +{ + delete[] _ppuBuffer; +} + +void GbEventManager::AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId) +{ + DebugEventInfo evt = {}; + evt.Type = type; + evt.Operation = operation; + evt.Scanline = _ppu->GetState().Scanline; + evt.Cycle = _ppu->GetState().Cycle; + evt.BreakpointId = breakpointId; + evt.DmaChannel = -1; + evt.ProgramCounter = _cpu->GetState().PC; + _debugEvents.push_back(evt); +} + +void GbEventManager::AddEvent(DebugEventType type) +{ + DebugEventInfo evt = {}; + evt.Type = type; + evt.Scanline = _ppu->GetState().Scanline; + evt.Cycle = _ppu->GetState().Cycle; + evt.BreakpointId = -1; + evt.DmaChannel = -1; + evt.ProgramCounter = _cpu->GetState().PC; + _debugEvents.push_back(evt); +} + +void GbEventManager::GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount) +{ + auto lock = _lock.AcquireSafe(); + uint32_t eventCount = std::min(maxEventCount, (uint32_t)_sentEvents.size()); + memcpy(eventArray, _sentEvents.data(), eventCount * sizeof(DebugEventInfo)); + maxEventCount = eventCount; +} + +DebugEventInfo GbEventManager::GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options) +{ + auto lock = _lock.AcquireSafe(); + + for(DebugEventInfo& evt : _sentEvents) { + if(evt.Cycle == cycle && evt.Scanline == scanline) { + return evt; + } + } + + DebugEventInfo empty = {}; + empty.ProgramCounter = 0xFFFFFFFF; + return empty; +} + +uint32_t GbEventManager::GetEventCount(EventViewerDisplayOptions options) +{ + auto lock = _lock.AcquireSafe(); + FilterEvents(options); + return (uint32_t)_sentEvents.size(); +} + +void GbEventManager::ClearFrameEvents() +{ + _prevDebugEvents = _debugEvents; + _debugEvents.clear(); +} + +void GbEventManager::FilterEvents(EventViewerDisplayOptions& options) +{ + auto lock = _lock.AcquireSafe(); + _sentEvents.clear(); + + vector events = _snapshot; + if(options.ShowPreviousFrameEvents && _snapshotScanline != 0) { + uint32_t key = (_snapshotScanline << 16) + _snapshotCycle; + for(DebugEventInfo& evt : _prevDebugEvents) { + uint32_t evtKey = (evt.Scanline << 16) + evt.Cycle; + if(evtKey > key) { + events.push_back(evt); + } + } + } + + for(DebugEventInfo& evt : events) { + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; + bool showEvent = false; + switch(evt.Type) { + default: break; + case DebugEventType::Breakpoint: showEvent = options.ShowMarkedBreakpoints; break; + case DebugEventType::Irq: showEvent = options.ShowIrq; break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if(reg >= 0xFE00 && reg <= 0xFE9F) { + showEvent = isWrite ? options.ShowPpuRegisterOamWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0xFF42 && reg <= 0xFF43) { + showEvent = isWrite ? options.ShowPpuRegisterBgScrollWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0x8000 && reg <= 0x9FFF) { + showEvent = isWrite ? options.ShowPpuRegisterVramWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0xFF47 && reg <= 0xFF49 || (reg >= 0xFF68 && reg <= 0xFF6B)) { + showEvent = isWrite ? options.ShowPpuRegisterCgramWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0xFF4A && reg <= 0xFF4B) { + showEvent = isWrite ? options.ShowPpuRegisterWindowWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0xFF40 && reg <= 0xFF70) { + showEvent = isWrite ? options.ShowPpuRegisterOtherWrites : options.ShowPpuRegisterReads; + } else if(reg >= 0xFF10 && reg <= 0xFF3F) { + showEvent = isWrite ? options.ShowApuRegisterWrites : options.ShowApuRegisterReads; + } else { + showEvent = isWrite ? options.ShowCpuRegisterWrites : options.ShowCpuRegisterReads; + } + break; + } + + if(showEvent) { + _sentEvents.push_back(evt); + } + } +} + +void GbEventManager::DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options) +{ + bool isWrite = evt.Operation.Type == MemoryOperationType::Write || evt.Operation.Type == MemoryOperationType::DmaWrite; + uint32_t color = 0; + uint32_t ppuReadColor = options.PpuRegisterReadColor; + switch(evt.Type) { + default: break; + case DebugEventType::Breakpoint: color = options.BreakpointColor; break; + case DebugEventType::Irq: color = options.IrqColor; break; + case DebugEventType::Register: + uint16_t reg = evt.Operation.Address & 0xFFFF; + if(reg >= 0xFE00 && reg <= 0xFE9F) { + color = isWrite ? options.PpuRegisterWriteOamColor : ppuReadColor; + } else if(reg >= 0xFF42 && reg <= 0xFF43) { + color = isWrite ? options.PpuRegisterWriteBgScrollColor : ppuReadColor; + } else if(reg >= 0x8000 && reg <= 0x9FFF) { + color = isWrite ? options.PpuRegisterWriteVramColor : ppuReadColor; + } else if(reg >= 0xFF47 && reg <= 0xFF49 || (reg >= 0xFF68 && reg <= 0xFF6B)) { + color = isWrite ? options.PpuRegisterWriteCgramColor : ppuReadColor; + } else if(reg >= 0xFF4A && reg <= 0xFF4B) { + color = isWrite ? options.PpuRegisterWriteWindowColor : ppuReadColor; + } else if(reg >= 0xFF40 && reg <= 0xFF70) { + color = isWrite ? options.PpuRegisterWriteOtherColor : ppuReadColor; + } else if(reg >= 0xFF10 && reg <= 0xFF3F) { + color = isWrite ? options.ApuRegisterWriteColor : options.ApuRegisterReadColor; + } else { + color = isWrite ? options.CpuRegisterWriteColor : options.CpuRegisterReadColor; + } + break; + } + + if(drawBackground) { + color = 0xFF000000 | ((color >> 1) & 0x7F7F7F); + } else { + color |= 0xFF000000; + } + + int iMin = drawBackground ? -2 : 0; + int iMax = drawBackground ? 3 : 1; + int jMin = drawBackground ? -2 : 0; + int jMax = drawBackground ? 3 : 1; + uint32_t y = std::min(evt.Scanline * 2, _scanlineCount * 2); + uint32_t x = evt.Cycle * 2; + + for(int i = iMin; i <= iMax; i++) { + for(int j = jMin; j <= jMax; j++) { + int32_t pos = (y + i) * GbEventManager::ScanlineWidth + x + j; + if(pos < 0 || pos >= GbEventManager::ScanlineWidth * (int)_scanlineCount * 2) { + continue; + } + buffer[pos] = color; + } + } +} + +uint32_t GbEventManager::TakeEventSnapshot(EventViewerDisplayOptions options) +{ + DebugBreakHelper breakHelper(_debugger); + auto lock = _lock.AcquireSafe(); + _snapshot.clear(); + + uint16_t cycle = _ppu->GetState().Cycle; + uint16_t scanline = _ppu->GetState().Scanline; + + if(scanline >= GbEventManager::VBlankScanline || scanline == 0) { + memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), 456 * GbEventManager::ScreenHeight * sizeof(uint16_t)); + } else { + uint32_t size = 456 * GbEventManager::ScreenHeight; + uint32_t offset = 456 * scanline; + memcpy(_ppuBuffer, _ppu->GetEventViewerBuffer(), offset * sizeof(uint16_t)); + memcpy(_ppuBuffer + offset, _ppu->GetPreviousEventViewerBuffer() + offset, (size - offset) * sizeof(uint16_t)); + } + + _snapshot = _debugEvents; + _snapshotScanline = scanline; + _snapshotCycle = cycle; + _scanlineCount = GbEventManager::ScreenHeight; + return _scanlineCount; +} + +void GbEventManager::GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options) +{ + auto lock = _lock.AcquireSafe(); + + if(bufferSize < _scanlineCount * 2 * GbEventManager::ScanlineWidth * 4) { + return; + } + + uint16_t *src = _ppuBuffer; + for(uint32_t y = 0, len = GbEventManager::ScreenHeight*2; y < len; y++) { + for(uint32_t x = 0; x < GbEventManager::ScanlineWidth; x++) { + int srcOffset = (y >> 1) * 456 + (x >> 1); + buffer[y*GbEventManager::ScanlineWidth + x] = DefaultVideoFilter::ToArgb(src[srcOffset]); + } + } + + constexpr uint32_t vblankScanlineColor = 0xFF55FFFF; + constexpr uint32_t currentScanlineColor = 0xFFFFFF55; + int vblankScanline = GbEventManager::VBlankScanline * 2 * GbEventManager::ScanlineWidth; + uint32_t scanlineOffset = _snapshotScanline * 2 * GbEventManager::ScanlineWidth; + for(int i = 0; i < GbEventManager::ScanlineWidth; i++) { + buffer[vblankScanline + i] = vblankScanlineColor; + buffer[vblankScanline + GbEventManager::ScanlineWidth + i] = vblankScanlineColor; + if(_snapshotScanline != 0) { + buffer[scanlineOffset + i] = currentScanlineColor; + buffer[scanlineOffset + GbEventManager::ScanlineWidth + i] = currentScanlineColor; + } + } + + FilterEvents(options); + for(DebugEventInfo &evt : _sentEvents) { + DrawEvent(evt, true, buffer, options); + } + for(DebugEventInfo &evt : _sentEvents) { + DrawEvent(evt, false, buffer, options); + } +} diff --git a/Core/GbEventManager.h b/Core/GbEventManager.h new file mode 100644 index 0000000..0ecc107 --- /dev/null +++ b/Core/GbEventManager.h @@ -0,0 +1,54 @@ +#pragma once +#include "stdafx.h" +#include "DebugTypes.h" +#include "BaseEventManager.h" +#include "../Utilities/SimpleLock.h" + +enum class DebugEventType; +struct DebugEventInfo; +struct EventViewerDisplayOptions; +class GbCpu; +class GbPpu; +class Debugger; + +class GbEventManager final : public IEventManager +{ +private: + static constexpr int ScanlineWidth = 456*2; + static constexpr int ScreenHeight = 154; + static constexpr int VBlankScanline = 144; + + GbPpu* _ppu; + GbCpu* _cpu; + Debugger* _debugger; + + vector _debugEvents; + vector _prevDebugEvents; + vector _sentEvents; + + vector _snapshot; + uint16_t _snapshotScanline = 0; + uint16_t _snapshotCycle = 0; + SimpleLock _lock; + + uint32_t _scanlineCount = 262; + uint16_t* _ppuBuffer = nullptr; + + void DrawEvent(DebugEventInfo& evt, bool drawBackground, uint32_t* buffer, EventViewerDisplayOptions& options); + void FilterEvents(EventViewerDisplayOptions& options); + +public: + GbEventManager(Debugger* debugger, GbCpu* cpu, GbPpu* ppu); + ~GbEventManager(); + + void AddEvent(DebugEventType type, MemoryOperationInfo& operation, int32_t breakpointId = -1); + void AddEvent(DebugEventType type); + + void GetEvents(DebugEventInfo* eventArray, uint32_t& maxEventCount); + uint32_t GetEventCount(EventViewerDisplayOptions options); + void ClearFrameEvents(); + + uint32_t TakeEventSnapshot(EventViewerDisplayOptions options); + void GetDisplayBuffer(uint32_t* buffer, uint32_t bufferSize, EventViewerDisplayOptions options); + DebugEventInfo GetEvent(uint16_t scanline, uint16_t cycle, EventViewerDisplayOptions& options); +}; diff --git a/Core/GbPpu.cpp b/Core/GbPpu.cpp index 43b9ead..b94d596 100644 --- a/Core/GbPpu.cpp +++ b/Core/GbPpu.cpp @@ -22,7 +22,6 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana _state = {}; _state.Mode = PpuMode::HBlank; - _drawModeLength = (_state.ScrollX & 0x07) + 160 + 8 * 5; _lastFrameTime = 0; _outputBuffers[0] = new uint16_t[256 * 240]; @@ -31,6 +30,12 @@ void GbPpu::Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryMana memset(_outputBuffers[1], 0, 256 * 240 * sizeof(uint16_t)); _currentBuffer = _outputBuffers[0]; + _eventViewerBuffers[0] = new uint16_t[456 * 154]; + _eventViewerBuffers[1] = new uint16_t[456 * 154]; + memset(_eventViewerBuffers[0], 0, 456 * 154 * sizeof(uint16_t)); + memset(_eventViewerBuffers[1], 0, 456 * 154 * sizeof(uint16_t)); + _currentEventViewerBuffer = _eventViewerBuffers[0]; + #ifndef USEBOOTROM Write(0xFF40, 0x91); Write(0xFF42, 0x00); @@ -53,6 +58,16 @@ GbPpuState GbPpu::GetState() return _state; } +uint16_t* GbPpu::GetEventViewerBuffer() +{ + return _currentEventViewerBuffer; +} + +uint16_t* GbPpu::GetPreviousEventViewerBuffer() +{ + return _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; +} + void GbPpu::Exec() { if(!_state.LcdEnabled) { @@ -81,6 +96,7 @@ void GbPpu::ExecCycle() _state.Cycle = 0; _state.Scanline++; + _spriteCount = 0; if(_state.Scanline == 144) { _state.Mode = PpuMode::VBlank; @@ -92,13 +108,18 @@ void GbPpu::ExecCycle() SendFrame(); } else if(_state.Scanline == 154) { - _console->ProcessEvent(EventType::StartFrame); _state.Scanline = 0; + _console->ProcessEvent(EventType::StartFrame); + if(_console->IsDebugging()) { + _currentEventViewerBuffer = _currentEventViewerBuffer == _eventViewerBuffers[0] ? _eventViewerBuffers[1] : _eventViewerBuffers[0]; + for(int i = 0; i < 456 * 154; i++) { + _currentEventViewerBuffer[i] = 0x18C6; + } + } } if(_state.Scanline < 144) { _state.Mode = PpuMode::OamEvaluation; - _drawModeLength = (_state.ScrollX & 0x07) + 160 + 8 * 5; if(_state.Status & GbPpuStatusFlags::OamIrq) { _memoryManager->RequestIrq(GbIrqSource::LcdStat); @@ -115,27 +136,230 @@ void GbPpu::ExecCycle() //TODO: Dot-based renderer, currently draws at the end of the scanline if(_state.Scanline < 144) { if(_state.Cycle < 80) { - if(_state.Cycle == 79) { - _state.Mode = PpuMode::Drawing; - } + RunSpriteEvaluation(); } else if(_state.Mode == PpuMode::Drawing) { - _drawModeLength--; - if(_drawModeLength == 0) { + bool fetchWindow = _state.WindowEnabled && _shiftedPixels >= _state.WindowX - 7 && _state.Scanline >= _state.WindowY; + if(_fetchWindow != fetchWindow) { + //Switched between window & background, reset fetcher & pixel FIFO + _fetchWindow = fetchWindow; + _fetchColumn = 0; + _fetcherStep = 0; + _fifoPosition = 0; + _fifoSize = 0; + } + + ClockTileFetcher(); + + if(_fetchSprite == -1 && _fifoSize > 8) { + if(!fetchWindow && _shiftedPixels < (_state.ScrollX & 0x07)) { + //Throw away pixels that are outside the screen due to the ScrollX value + _fifoPosition = (_fifoPosition + 1) & 0x0F; + } else { + uint16_t outOffset = _state.Scanline * 256 + _drawnPixels; + + FifoEntry& entry = _fifoContent[_fifoPosition]; + + uint16_t rgbColor; + if(_gameboy->IsCgb()) { + if(entry.Attributes & 0x40) { + rgbColor = _state.CgbObjPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)]; + } else { + rgbColor = _state.CgbBgPalettes[entry.Color | ((entry.Attributes & 0x07) << 2)]; + } + } else { + uint16_t palette[4]; + if(entry.Attributes & 0x40) { + GetPalette(palette, (entry.Attributes & 0x10) ? _state.ObjPalette1 : _state.ObjPalette0); + } else { + GetPalette(palette, _state.BgPalette); + } + rgbColor = palette[entry.Color]; + } + _currentBuffer[outOffset] = rgbColor; + _fifoPosition = (_fifoPosition + 1) & 0x0F; + + if(_console->IsDebugging()) { + _currentEventViewerBuffer[456 * _state.Scanline + _state.Cycle] = rgbColor; + } + + _drawnPixels++; + } + _fifoSize--; + _shiftedPixels++; + } + + if(_drawnPixels >= 160) { _state.Mode = PpuMode::HBlank; if(_state.Status & GbPpuStatusFlags::HBlankIrq) { _memoryManager->RequestIrq(GbIrqSource::LcdStat); } - - if(_gameboy->IsCgb()) { - RenderScanline(); - } else { - RenderScanline(); - } } } } } +void GbPpu::RunSpriteEvaluation() +{ + if(_state.Cycle & 0x01) { + if(_spriteCount < 10) { + uint8_t spriteIndex = (_state.Cycle >> 1) * 4; + int16_t sprY = (int16_t)_oam[spriteIndex] - 16; + if(_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) { + _spriteCountersX[_spriteCount] = _oam[spriteIndex + 1]; + _spriteIndexes[_spriteCount] = spriteIndex; + _spriteCount++; + } + } + + if(_state.Cycle == 79) { + _state.Mode = PpuMode::Drawing; + + //Reset fetcher & pixel FIFO + _fetcherStep = 0; + _fifoPosition = 0; + _fifoSize = 0; + _shiftedPixels = 0; + _drawnPixels = 0; + _fetchSprite = -1; + _fetchWindow = false; + _fetchColumn = _state.ScrollX / 8; + } + } else { + //Hardware probably reads sprite Y and loads the X counter with the value on the next cycle + } +} + +void GbPpu::ResetTileFetcher() +{ + _fetcherStep = 0; +} + +void GbPpu::ClockTileFetcher() +{ + if(_fetchSprite < 0 && _fifoSize >= 8) { + for(int i = 0; i < _spriteCount; i++) { + if((int)_spriteCountersX[i] - 8 <= _drawnPixels) { + _fetchSprite = _spriteIndexes[i]; + _spriteCountersX[i] = 0xFF; //prevent processing this sprite again + ResetTileFetcher(); + break; + } + } + } + + switch(_fetcherStep++) { + case 0: { + //Fetch tile index + if(_fetchSprite >= 0) { + int16_t sprY = (int16_t)_oam[_fetchSprite] - 16; + uint8_t sprTile = _oam[_fetchSprite + 2]; + uint8_t sprAttr = _oam[_fetchSprite + 3]; + bool vMirror = (sprAttr & 0x40) != 0; + uint16_t tileBank = (sprAttr & 0x08) ? 0x2000 : 0x0000; + + uint8_t sprOffsetY = vMirror ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) : (_state.Scanline - sprY); + if(_state.LargeSprites) { + sprTile &= 0xFE; + } + + uint16_t sprTileAddr = (sprTile * 16 + sprOffsetY * 2) | tileBank; + _fetcherTileAddr = sprTileAddr; + _fetcherAttributes = (sprAttr & 0xBF) | 0x40; //Use 0x40 as a marker to designate this pixel as a sprite pixel + } else { + uint16_t tilemapAddr; + uint8_t yOffset; + if(_fetchWindow) { + tilemapAddr = _state.WindowTilemapSelect ? 0x1C00 : 0x1800; + yOffset = _state.Scanline - _state.WindowY; + } else { + tilemapAddr = _state.BgTilemapSelect ? 0x1C00 : 0x1800; + yOffset = _state.ScrollY + _state.Scanline; + } + + uint8_t row = yOffset >> 3; + uint16_t tileAddr = tilemapAddr + _fetchColumn + row * 32; + uint8_t tileIndex = _vram[tileAddr]; + + uint8_t attributes = _gameboy->IsCgb() ? _vram[tileAddr | 0x2000] : 0; + bool vMirror = (attributes & 0x40) != 0; + uint16_t tileBank = (attributes & 0x08) ? 0x2000 : 0x0000; + + uint16_t baseTile = _state.BgTileSelect ? 0 : 0x1000; + uint8_t tileY = vMirror ? (7 - (yOffset & 0x07)) : (yOffset & 0x07); + uint16_t tileRowAddr = baseTile + (baseTile ? (int8_t)tileIndex * 16 : tileIndex * 16) + tileY * 2; + tileRowAddr |= tileBank; + _fetcherTileAddr = tileRowAddr; + _fetcherAttributes = (attributes & 0xBF); + } + break; + } + + case 2: { + //Fetch tile data (low byte) + _fetcherTileLowByte = _vram[_fetcherTileAddr]; + break; + } + + case 4: { + //Fetch tile data (high byte) + _fetcherTileHighByte = _vram[_fetcherTileAddr + 1]; + break; + } + } + + if(_fetcherStep > 4) { + if(_fetchSprite >= 0) { + PushSpriteToPixelFifo(); + } else if(_fifoSize <= 8) { + PushTileToPixelFifo(); + } + } +} + +void GbPpu::PushSpriteToPixelFifo() +{ + _fetchSprite = -1; + ResetTileFetcher(); + + if(!_state.SpritesEnabled) { + return; + } + + //Overlap sprite + for(int i = 0; i < 8; i++) { + uint8_t shift = (_fetcherAttributes & 0x20) ? i : (7 - i); + uint8_t bits = ((_fetcherTileLowByte >> shift) & 0x01); + bits |= ((_fetcherTileHighByte >> shift) & 0x01) << 1; + + if(bits > 0) { + uint8_t pos = (_fifoPosition + i) & 0x0F; + if(!(_fifoContent[pos].Attributes & 0x40) && (_fifoContent[pos].Color == 0 || !(_fetcherAttributes & 0x80))) { + //Draw pixel if the current pixel is a BG pixel, and the color is 0, or the sprite is NOT background priority + _fifoContent[pos].Color = bits; + _fifoContent[pos].Attributes = _fetcherAttributes; + } + } + } +} + +void GbPpu::PushTileToPixelFifo() +{ + //Add new tile to fifo + for(int i = 0; i < 8; i++) { + uint8_t shift = (_fetcherAttributes & 0x20) ? i : (7 - i); + uint8_t bits = ((_fetcherTileLowByte >> shift) & 0x01); + bits |= ((_fetcherTileHighByte >> shift) & 0x01) << 1; + + uint8_t pos = (_fifoPosition + _fifoSize + i) & 0x0F; + _fifoContent[pos].Color = _state.BgEnabled ? bits : 0; + _fifoContent[pos].Attributes = _fetcherAttributes; + } + + _fetchColumn = (_fetchColumn + 1) & 0x1F; + _fifoSize += 8; + ResetTileFetcher(); +} + void GbPpu::GetPalette(uint16_t out[4], uint8_t palCfg) { constexpr uint16_t rgbPalette[4] = { 0x7FFF, 0x6318, 0x318C, 0x0000 }; @@ -145,120 +369,6 @@ void GbPpu::GetPalette(uint16_t out[4], uint8_t palCfg) out[3] = rgbPalette[(palCfg >> 6) & 0x03]; } -template -void GbPpu::RenderScanline() -{ - uint16_t bgColors[4]; - uint16_t oamColors[2][4]; - if(!isCgb) { - GetPalette(bgColors, _state.BgPalette); - GetPalette(oamColors[0], _state.ObjPalette0); - GetPalette(oamColors[1], _state.ObjPalette1); - } - - uint8_t visibleSprites[10] = {}; - uint8_t spriteCount = 0; - for(uint8_t i = 0; i < 0xA0; i += 4) { - int16_t sprY = (int16_t)_oam[i] - 16; - if(_state.Scanline >= sprY && _state.Scanline < sprY + (_state.LargeSprites ? 16 : 8)) { - visibleSprites[spriteCount] = i; - spriteCount++; - if(spriteCount == 10) { - break; - } - } - } - - //TODO option toggle for CGB - if(spriteCount > 1) { - //Sort sprites by their X position first, and then by their index when X values are equal - std::sort(visibleSprites, visibleSprites + spriteCount, [=](uint8_t a, uint8_t b) { - if(_oam[a + 1] == _oam[b + 1]) { - return a < b; - } else { - return _oam[a + 1] < _oam[b + 1]; - } - }); - } - - uint8_t xOffset; - uint8_t yOffset; - uint16_t tilemapAddr; - uint16_t baseTile = _state.BgTileSelect ? 0 : 0x1000; - - for(int x = 0; x < 160; x++) { - uint8_t bgColor = 0; - uint8_t bgPalette = 0; - bool bgPriority = false; - uint16_t outOffset = _state.Scanline * 256 + x; - if(_state.BgEnabled) { - if(_state.WindowEnabled && x >= _state.WindowX - 7 && _state.Scanline >= _state.WindowY) { - //Draw window content instead - tilemapAddr = _state.WindowTilemapSelect ? 0x1C00 : 0x1800; - xOffset = x - (_state.WindowX - 7); - yOffset = _state.Scanline - _state.WindowY; - } else { - //Draw regular tilemap - tilemapAddr = _state.BgTilemapSelect ? 0x1C00 : 0x1800; - xOffset = _state.ScrollX + x; - yOffset = _state.ScrollY + _state.Scanline; - } - - uint8_t row = yOffset >> 3; - uint8_t column = xOffset >> 3; - uint16_t tileAddr = tilemapAddr + column + row * 32; - uint8_t tileIndex = _vram[tileAddr]; - - uint8_t attributes = isCgb ? _vram[tileAddr | 0x2000] : 0; - bgPalette = (attributes & 0x07) << 2; - uint16_t tileBank = (attributes & 0x08) ? 0x2000 : 0x0000; - bool hMirror = (attributes & 0x20) != 0; - bool vMirror = (attributes & 0x40) != 0; - bgPriority = (attributes & 0x80) != 0; - - uint8_t tileY = vMirror ? (7 - (yOffset & 0x07)) : (yOffset & 0x07); - uint16_t tileRowAddr = baseTile + (baseTile ? (int8_t)tileIndex * 16 : tileIndex * 16) + tileY * 2; - tileRowAddr |= tileBank; - - uint8_t shift = hMirror ? (xOffset & 0x07) : (7 - (xOffset & 0x07)); - bgColor = ((_vram[tileRowAddr] >> shift) & 0x01) | (((_vram[tileRowAddr + 1] >> shift) & 0x01) << 1); - } - - _currentBuffer[outOffset] = isCgb ? _state.CgbBgPalettes[bgColor | bgPalette] : bgColors[bgColor]; - - if(!bgPriority && _state.SpritesEnabled && spriteCount) { - for(int i = 0; i < spriteCount; i++) { - uint8_t sprIndex = visibleSprites[i]; - int16_t sprX = (int16_t)_oam[sprIndex + 1] - 8; - if(x >= sprX && x < sprX + 8) { - int16_t sprY = (int16_t)_oam[sprIndex] - 16; - uint8_t sprTile = _oam[sprIndex + 2]; - uint8_t sprAttr = _oam[sprIndex + 3]; - bool bgPriority = (sprAttr & 0x80) != 0; - bool vMirror = (sprAttr & 0x40) != 0; - bool hMirror = (sprAttr & 0x20) != 0; - - uint8_t sprPalette = (sprAttr & 0x07) << 2; - uint16_t tileBank = (sprAttr & 0x08) ? 0x2000 : 0x0000; - - uint8_t sprOffsetY = vMirror ? (_state.LargeSprites ? 15 : 7) - (_state.Scanline - sprY) : (_state.Scanline - sprY); - if(_state.LargeSprites) { - sprTile &= 0xFE; - } - uint8_t sprShiftX = hMirror ? (x - sprX) : 7 - (x - sprX); - - uint16_t sprTileAddr = (sprTile * 16 + sprOffsetY * 2) | tileBank; - uint8_t sprColor = ((_vram[sprTileAddr] >> sprShiftX) & 0x01) | (((_vram[sprTileAddr + 1] >> sprShiftX) & 0x01) << 1); - if(sprColor > 0 && (bgColor == 0 || !bgPriority)) { - _currentBuffer[outOffset] = isCgb ? _state.CgbObjPalettes[sprColor | sprPalette] : oamColors[(int)sprPalette][sprColor]; - break; - } - } - } - } - } -} - void GbPpu::SendFrame() { _console->ProcessEvent(EventType::EndFrame); @@ -349,9 +459,11 @@ void GbPpu::Write(uint16_t addr, uint8_t value) case 0xFF45: _state.LyCompare = value; break; case 0xFF46: - //OAM DMA - TODO, restrict CPU accesses to high ram during this? + //OAM DMA + //TODO restrict CPU accesses to high ram during this + //TODO timing for(int i = 0; i < 0xA0; i++) { - WriteOam(i, _memoryManager->Read((value << 8) | i, MemoryOperationType::DmaRead)); + _memoryManager->Write(0xFE00 | i, _memoryManager->Read((value << 8) | i, MemoryOperationType::DmaRead)); } break; @@ -434,8 +546,10 @@ void GbPpu::WriteCgbRegister(uint16_t addr, uint8_t value) if(!_state.CgbHdmaMode) { //TODO check invalid dma sources/etc. + //TODO timing for(int i = 0; i < _state.CgbDmaLength * 16; i++) { - WriteVram((_state.CgbDmaDest & 0xFFF0) + i, _memoryManager->Read((_state.CgbDmaSource & 0xFFF0) + i, MemoryOperationType::DmaRead)); + uint16_t dst = 0x8000 | (((_state.CgbDmaDest & 0x1FF0) + i) & 0x1FFF); + _memoryManager->Write(dst, _memoryManager->Read((_state.CgbDmaSource & 0xFFF0) + i, MemoryOperationType::DmaRead)); } _state.CgbDmaLength = 0x7F; } else { @@ -500,4 +614,18 @@ void GbPpu::Serialize(Serializer& s) s.StreamArray(_state.CgbBgPalettes, 4 * 8); s.StreamArray(_state.CgbObjPalettes, 4 * 8); + + s.Stream( + _fifoPosition, _fifoSize, _shiftedPixels, _drawnPixels, + _fetcherAttributes, _fetcherStep, _fetchColumn, _fetcherTileAddr, + _fetcherTileLowByte, _fetcherTileHighByte, _fetchWindow, _fetchSprite, + _spriteCount + ); + + s.StreamArray(_spriteCountersX, 10); + s.StreamArray(_spriteIndexes, 10); + + for(int i = 0; i < 16; i++) { + s.Stream(_fifoContent[i].Color, _fifoContent[i].Attributes); + } } diff --git a/Core/GbPpu.h b/Core/GbPpu.h index 6c02716..4d23926 100644 --- a/Core/GbPpu.h +++ b/Core/GbPpu.h @@ -7,6 +7,12 @@ class Console; class Gameboy; class GbMemoryManager; +struct FifoEntry +{ + uint8_t Color; + uint8_t Attributes; +}; + class GbPpu : public ISerializable { private: @@ -15,18 +21,41 @@ private: GbPpuState _state = {}; GbMemoryManager* _memoryManager = nullptr; uint16_t* _outputBuffers[2] = {}; - uint16_t* _currentBuffer; + uint16_t* _currentBuffer = nullptr; + + uint16_t* _eventViewerBuffers[2] = {}; + uint16_t* _currentEventViewerBuffer = nullptr; + uint8_t* _vram = nullptr; uint8_t* _oam = nullptr; uint64_t _lastFrameTime = 0; - uint16_t _drawModeLength = 140; + + uint8_t _fifoPosition = 0; + uint8_t _fifoSize = 0; + FifoEntry _fifoContent[16]; + uint8_t _shiftedPixels = 0; + uint8_t _drawnPixels = 0; + + uint8_t _fetcherAttributes = 0; + uint8_t _fetcherStep = 0; + uint8_t _fetchColumn = 0; + uint16_t _fetcherTileAddr = 0; + uint8_t _fetcherTileLowByte = 0; + uint8_t _fetcherTileHighByte = 0; + bool _fetchWindow = false; + + int16_t _fetchSprite = -1; + uint8_t _spriteCount = 0; + uint8_t _spriteCountersX[10] = {}; + uint8_t _spriteIndexes[10] = {}; void ExecCycle(); - void RenderScanline(); - - template - void RenderScanline(); + void RunSpriteEvaluation(); + void ResetTileFetcher(); + void ClockTileFetcher(); + void PushSpriteToPixelFifo(); + void PushTileToPixelFifo(); void WriteCgbPalette(uint8_t& pos, uint16_t* pal, bool autoInc, uint8_t value); @@ -36,6 +65,8 @@ public: void Init(Console* console, Gameboy* gameboy, GbMemoryManager* memoryManager, uint8_t* vram, uint8_t* oam); GbPpuState GetState(); + uint16_t* GetEventViewerBuffer(); + uint16_t* GetPreviousEventViewerBuffer(); void GetPalette(uint16_t out[4], uint8_t palCfg); void Exec(); diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp index 8fe196d..70e55e6 100644 --- a/InteropDLL/DebugApiWrapper.cpp +++ b/InteropDLL/DebugApiWrapper.cpp @@ -16,6 +16,7 @@ #include "../Core/ScriptManager.h" #include "../Core/Profiler.h" #include "../Core/Assembler.h" +#include "../Core/BaseEventManager.h" extern shared_ptr _console; @@ -95,7 +96,7 @@ extern "C" 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, EventViewerDisplayOptions options) { GetDebugger()->GetEventManager()->GetDisplayBuffer(buffer, 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); } diff --git a/UI/Debugger/EventViewer/ctrlEventViewerFilters.Designer.cs b/UI/Debugger/EventViewer/ctrlEventViewerFilters.Designer.cs index 5c3be4e..776f7d5 100644 --- a/UI/Debugger/EventViewer/ctrlEventViewerFilters.Designer.cs +++ b/UI/Debugger/EventViewer/ctrlEventViewerFilters.Designer.cs @@ -41,7 +41,7 @@ this.chkShowWorkRamRegisterWrites = new System.Windows.Forms.CheckBox(); this.picWramReads = new Mesen.GUI.Debugger.ctrlColorPicker(); this.chkShowWorkRamRegisterReads = new System.Windows.Forms.CheckBox(); - this.label3 = new System.Windows.Forms.Label(); + this.lblWorkRam = new System.Windows.Forms.Label(); this.picCpuWrites = new Mesen.GUI.Debugger.ctrlColorPicker(); this.chkShowCpuRegisterWrites = new System.Windows.Forms.CheckBox(); this.picCpuReads = new Mesen.GUI.Debugger.ctrlColorPicker(); @@ -139,7 +139,7 @@ this.tableLayoutPanel1.Controls.Add(this.chkShowWorkRamRegisterWrites, 4, 9); this.tableLayoutPanel1.Controls.Add(this.picWramReads, 2, 9); this.tableLayoutPanel1.Controls.Add(this.chkShowWorkRamRegisterReads, 1, 9); - this.tableLayoutPanel1.Controls.Add(this.label3, 0, 9); + this.tableLayoutPanel1.Controls.Add(this.lblWorkRam, 0, 9); this.tableLayoutPanel1.Controls.Add(this.picCpuWrites, 5, 8); this.tableLayoutPanel1.Controls.Add(this.chkShowCpuRegisterWrites, 4, 8); this.tableLayoutPanel1.Controls.Add(this.picCpuReads, 2, 8); @@ -333,16 +333,16 @@ this.chkShowWorkRamRegisterReads.UseVisualStyleBackColor = true; this.chkShowWorkRamRegisterReads.Click += new System.EventHandler(this.chkOption_Click); // - // label3 + // lblWorkRam // - this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(3, 196); - this.label3.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(45, 13); - this.label3.TabIndex = 16; - this.label3.Text = "WRAM:"; + this.lblWorkRam.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblWorkRam.AutoSize = true; + this.lblWorkRam.Location = new System.Drawing.Point(3, 196); + this.lblWorkRam.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.lblWorkRam.Name = "lblWorkRam"; + this.lblWorkRam.Size = new System.Drawing.Size(45, 13); + this.lblWorkRam.TabIndex = 16; + this.lblWorkRam.Text = "WRAM:"; // // picCpuWrites // @@ -886,7 +886,7 @@ private System.Windows.Forms.CheckBox chkShowWorkRamRegisterWrites; private ctrlColorPicker picWramReads; private System.Windows.Forms.CheckBox chkShowWorkRamRegisterReads; - private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label lblWorkRam; private ctrlColorPicker picCpuWrites; private System.Windows.Forms.CheckBox chkShowCpuRegisterWrites; private ctrlColorPicker picCpuReads; diff --git a/UI/Debugger/EventViewer/ctrlEventViewerFilters.cs b/UI/Debugger/EventViewer/ctrlEventViewerFilters.cs index 6d9d887..87aeba7 100644 --- a/UI/Debugger/EventViewer/ctrlEventViewerFilters.cs +++ b/UI/Debugger/EventViewer/ctrlEventViewerFilters.cs @@ -102,5 +102,29 @@ namespace Mesen.GUI.Debugger this.OptionsChanged?.Invoke(this, e); } } + + public void SetCpuType(CpuType cpu) + { + bool isGb = cpu == CpuType.Gameboy; + + chkCgramWrites.Text = isGb ? "Palette" : "CGRAM"; + + chkMode7Writes.Visible = !isGb; + picPpuMode7Writes.Visible = !isGb; + + chkShowPpuBgOptionWrites.Visible = !isGb; + picPpuBgOptionWrites.Visible = !isGb; + + grpDmaFilters.Visible = !isGb; + + chkShowWorkRamRegisterReads.Visible = !isGb; + picWramReads.Visible = !isGb; + chkShowWorkRamRegisterWrites.Visible = !isGb; + picWramWrites.Visible = !isGb; + lblWorkRam.Visible = !isGb; + + chkShowNmi.Visible = !isGb; + picNmi.Visible = !isGb; + } } } diff --git a/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs b/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs index f5fac3e..56045af 100644 --- a/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs +++ b/UI/Debugger/EventViewer/ctrlEventViewerPpuView.cs @@ -22,6 +22,8 @@ namespace Mesen.GUI.Debugger public const int HdmaChannelFlag = 0x40; private int _baseWidth = 1364 / 2; + private double _xRatio = 2; + private bool _isGameboy = false; private Point _lastPos = new Point(-1, -1); private bool _needUpdate = false; @@ -54,10 +56,18 @@ namespace Mesen.GUI.Debugger public void RefreshViewer() { EventViewerDisplayOptions options = ConfigManager.Config.Debug.EventViewer.GetInteropOptions(); - _pictureData = DebugApi.GetEventViewerOutput(ScanlineCount, options); + _isGameboy = EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy; + if(_isGameboy) { + _baseWidth = 456 * 2; + _xRatio = 0.5; + } else { + _baseWidth = 1364 / 2; + _xRatio = 2; + } + _pictureData = DebugApi.GetEventViewerOutput(_baseWidth, ScanlineCount, options); int picHeight = (int)ScanlineCount*2; - if(_screenBitmap == null || _screenBitmap.Height != picHeight) { + if(_screenBitmap == null || _screenBitmap.Height != picHeight || _screenBitmap.Width != _baseWidth) { _screenBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb); _overlayBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb); _displayBitmap = new Bitmap(_baseWidth, picHeight, PixelFormat.Format32bppPArgb); @@ -92,20 +102,20 @@ namespace Mesen.GUI.Debugger if(_lastPos.X >= 0) { string location = _lastPos.X + ", " + _lastPos.Y; SizeF size = g.MeasureString(location, _overlayFont); - int x = _lastPos.X + 5; + int x = (int)(_lastPos.X / _xRatio) + 5; int y = _lastPos.Y - (int)size.Height / 2 - 5; - if(x/2 - picViewer.ScrollOffsets.X / picViewer.ImageScale + size.Width > (picViewer.Width / picViewer.ImageScale) - 5) { - x -= (int)size.Width * 2 + 10; + if(x - picViewer.ScrollOffsets.X / picViewer.ImageScale + size.Width > (picViewer.Width / picViewer.ImageScale) - 5) { + x -= (int)size.Width + 5; } if(y*2 - picViewer.ScrollOffsets.Y / picViewer.ImageScale < size.Height + 5) { y = _lastPos.Y + 5; } - g.DrawOutlinedString(location, _overlayFont, Brushes.Black, Brushes.White, x/2, y*2); + g.DrawOutlinedString(location, _overlayFont, Brushes.Black, Brushes.White, x, y*2); location = GetCycle(_lastPos.X).ToString(); - g.DrawOutlinedString(location, _smallOverlayFont, Brushes.Black, Brushes.White, x/2, y*2 + (int)size.Height - 5); + g.DrawOutlinedString(location, _smallOverlayFont, Brushes.Black, Brushes.White, x, y*2 + (int)size.Height - 5); } } @@ -126,7 +136,7 @@ namespace Mesen.GUI.Debugger using(Graphics g = Graphics.FromImage(_overlayBitmap)) { g.Clear(Color.Transparent); using(Pen bg = new Pen(Color.FromArgb(128, Color.LightGray))) { - g.DrawRectangle(bg, pos.X / 2 - 1, 0, 3, _overlayBitmap.Height); + g.DrawRectangle(bg, (int)(pos.X / _xRatio) - 1, 0, 3, _overlayBitmap.Height); g.DrawRectangle(bg, 0, pos.Y * 2 - 1, _overlayBitmap.Width, 3); } } @@ -147,7 +157,7 @@ namespace Mesen.GUI.Debugger private Point GetHClockAndScanline(Point location) { return new Point( - (location.X / this.ImageScale) * 2, + (int)((location.X / this.ImageScale) * _xRatio), ((location.Y & ~0x01) / this.ImageScale) / 2 ); } @@ -171,13 +181,13 @@ namespace Mesen.GUI.Debugger DebugEventInfo evt = new DebugEventInfo(); DebugApi.GetEventViewerEvent(ref evt, (UInt16)pos.Y, (UInt16)pos.X, options); if(evt.ProgramCounter == 0xFFFFFFFF) { - int[] xOffsets = new int[] { 0, 2, -2, 4, -4, 6 }; + int[] xOffsets = new int[] { 0, 1, -1, 2, -2, 3 }; int[] yOffsets = new int[] { 0, -1, 1 }; //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]), options); + DebugApi.GetEventViewerEvent(ref evt, (UInt16)(pos.Y + yOffsets[j]), (UInt16)(pos.X + xOffsets[i] * _xRatio), options); if(evt.ProgramCounter != 0xFFFFFFFF) { return evt; } @@ -204,12 +214,24 @@ namespace Mesen.GUI.Debugger return; } - Dictionary values = new Dictionary() { - { "Type", ResourceHelper.GetEnumText(evt.Type) }, - { "Scanline", evt.Scanline.ToString() }, - { "H-Clock", evt.Cycle.ToString() + " (" + GetCycle(evt.Cycle) + ")" }, - { "PC", "$" + evt.ProgramCounter.ToString("X6") }, - }; + EmuApi.WriteLogEntry("Old: " + _lastPos.ToString() + " new: " + newPos.ToString()); + + Dictionary values; + if(_isGameboy) { + values = new Dictionary() { + { "Type", ResourceHelper.GetEnumText(evt.Type) }, + { "Scanline", evt.Scanline.ToString() }, + { "Cycle", evt.Cycle.ToString() }, + { "PC", "$" + evt.ProgramCounter.ToString("X4") }, + }; + } else { + values = new Dictionary() { + { "Type", ResourceHelper.GetEnumText(evt.Type) }, + { "Scanline", evt.Scanline.ToString() }, + { "H-Clock", evt.Cycle.ToString() + " (" + GetCycle(evt.Cycle) + ")" }, + { "PC", "$" + evt.ProgramCounter.ToString("X6") }, + }; + } switch(evt.Type) { case DebugEventType.Register: @@ -266,7 +288,7 @@ namespace Mesen.GUI.Debugger break; } - UpdateOverlay(new Point((int)(evt.Cycle / 2 * this.ImageScale), (int)(evt.Scanline * 2 * this.ImageScale))); + UpdateOverlay(new Point((int)(evt.Cycle / _xRatio * this.ImageScale), (int)(evt.Scanline * 2 * this.ImageScale))); Form parentForm = this.FindForm(); Point location = parentForm.PointToClient(Control.MousePosition); diff --git a/UI/Debugger/EventViewer/frmEventViewer.cs b/UI/Debugger/EventViewer/frmEventViewer.cs index d69671f..e9fa541 100644 --- a/UI/Debugger/EventViewer/frmEventViewer.cs +++ b/UI/Debugger/EventViewer/frmEventViewer.cs @@ -91,6 +91,7 @@ namespace Mesen.GUI.Debugger public void RefreshViewer() { + ctrlFilters.SetCpuType(EmuApi.GetRomInfo().CoprocessorType == CoprocessorType.Gameboy ? CpuType.Gameboy : CpuType.Cpu); if(tabMain.SelectedTab == tpgPpuView) { ctrlPpuView.RefreshViewer(); } else { diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index e5abb46..c294673 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -475,22 +475,17 @@ namespace Mesen.GUI.Forms mnuGbDebugger.Visible = isGameboyMode; sepGameboyDebugger.Visible = isGameboyMode; - if(isGameboyMode) { - //Remove/disable all tools that aren't useful when running a plain GB game - mnuGbDebugger.Text = "Debugger"; - - mnuDebugger.Enabled = false; - mnuDebugger.Visible = false; - mnuSpcDebugger.Enabled = false; - mnuSpcDebugger.Visible = false; - mnuSpriteViewer.Enabled = false; - mnuSpriteViewer.Visible = false; - mnuEventViewer.Enabled = false; - mnuEventViewer.Visible = false; - mnuAssembler.Enabled = false; - mnuAssembler.Visible = false; - sepCoprocessors.Visible = false; - } + //Remove/disable all tools that aren't useful when running a plain GB game + mnuGbDebugger.Text = isGameboyMode ? "Debugger" : "Game Boy Debugger"; + mnuDebugger.Enabled = !isGameboyMode; + mnuDebugger.Visible = !isGameboyMode; + mnuSpcDebugger.Enabled = !isGameboyMode; + mnuSpcDebugger.Visible = !isGameboyMode; + mnuSpriteViewer.Enabled = !isGameboyMode; + mnuSpriteViewer.Visible = !isGameboyMode; + mnuAssembler.Enabled = !isGameboyMode; + mnuAssembler.Visible = !isGameboyMode; + sepCoprocessors.Visible = !isGameboyMode; } private void ResizeRecentGames() diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index fcc8bb7..fa3ea99 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -113,11 +113,12 @@ namespace Mesen.GUI [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, EntryPoint = "GetEventViewerOutput")] private static extern void GetEventViewerOutputWrapper([In, Out]byte[] buffer, EventViewerDisplayOptions options); - public static byte[] GetEventViewerOutput(UInt32 scanlineCount, 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) { - byte[] buffer = new byte[1364/2 * scanlineCount*2 * 4]; - DebugApi.GetEventViewerOutputWrapper(buffer, options); + UInt32 bufferSize = (UInt32)(scanlineWidth * scanlineCount * 2 * 4); + byte[] buffer = new byte[bufferSize]; + DebugApi.GetEventViewerOutputWrapper(buffer, bufferSize, options); return buffer; }