GB: Replace scanline renderer with pixel renderer

Probably still not very accurate
This commit is contained in:
Sour 2020-05-21 20:57:00 -04:00
parent 435051f73d
commit 134c28ed9f
30 changed files with 907 additions and 297 deletions

80
Core/BaseEventManager.h Normal file
View file

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

View file

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

View file

@ -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<Breakpoint> _breakpoints[BreakpointTypeCount];
vector<ExpressionData> _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);

View file

@ -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<CpuType::Cx4>(uint32_t addr, uint8_t v
template void Console::ProcessMemoryWrite<CpuType::Gameboy>(uint32_t addr, uint8_t value, MemoryOperationType opType);
template void Console::ProcessInterrupt<CpuType::Cpu>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Console::ProcessInterrupt<CpuType::Sa1>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Console::ProcessInterrupt<CpuType::Sa1>(uint32_t originalPc, uint32_t currentPc, bool forNmi);
template void Console::ProcessInterrupt<CpuType::Gameboy>(uint32_t originalPc, uint32_t currentPc, bool forNmi);

View file

@ -48,6 +48,7 @@
<ClInclude Include="BaseCartridge.h" />
<ClInclude Include="BaseControlDevice.h" />
<ClInclude Include="BaseCoprocessor.h" />
<ClInclude Include="BaseEventManager.h" />
<ClInclude Include="BatteryManager.h" />
<ClInclude Include="BsxCart.h" />
<ClInclude Include="BsxMemoryPack.h" />
@ -72,6 +73,7 @@
<ClInclude Include="GbCartFactory.h" />
<ClInclude Include="GbCpu.h" />
<ClInclude Include="GbDebugger.h" />
<ClInclude Include="GbEventManager.h" />
<ClInclude Include="GbMbc1.h" />
<ClInclude Include="GbMbc2.h" />
<ClInclude Include="GbMbc3.h" />
@ -278,6 +280,7 @@
<ClCompile Include="GbApu.cpp" />
<ClCompile Include="GbCpu.cpp" />
<ClCompile Include="GbDebugger.cpp" />
<ClCompile Include="GbEventManager.cpp" />
<ClCompile Include="GbMemoryManager.cpp" />
<ClCompile Include="GbPpu.cpp" />
<ClCompile Include="GbTimer.cpp" />

View file

@ -176,9 +176,6 @@
<ClInclude Include="PpuTools.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="EventManager.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="EventType.h">
<Filter>Misc</Filter>
</ClInclude>
@ -581,6 +578,15 @@
<ClInclude Include="GbMbc3.h">
<Filter>GB\Carts</Filter>
</ClInclude>
<ClInclude Include="EventManager.h">
<Filter>Debugger\EventManager</Filter>
</ClInclude>
<ClInclude Include="GbEventManager.h">
<Filter>Debugger\EventManager</Filter>
</ClInclude>
<ClInclude Include="BaseEventManager.h">
<Filter>Debugger\EventManager</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -668,9 +674,6 @@
<ClCompile Include="BreakpointManager.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="EventManager.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="PpuTools.cpp">
<Filter>Debugger</Filter>
</ClCompile>
@ -923,6 +926,12 @@
<ClCompile Include="GbCpu.cpp">
<Filter>GB</Filter>
</ClCompile>
<ClCompile Include="EventManager.cpp">
<Filter>Debugger\EventManager</Filter>
</ClCompile>
<ClCompile Include="GbEventManager.cpp">
<Filter>Debugger\EventManager</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
@ -1009,5 +1018,8 @@
<Filter Include="GB\APU">
<UniqueIdentifier>{c020f128-b5e1-4f6c-9849-ff098fe93d39}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\EventManager">
<UniqueIdentifier>{b1753ff0-0c73-4acf-978b-1964222e01c6}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -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<EventManager> CpuDebugger::GetEventManager()
{
return _eventManager;
}
shared_ptr<CallstackManager> CpuDebugger::GetCallstackManager()
{
return _callstackManager;

View file

@ -27,10 +27,10 @@ class CpuDebugger final : public IDebugger
MemoryManager* _memoryManager;
EmuSettings* _settings;
CodeDataLogger* _codeDataLogger;
EventManager* _eventManager;
Cpu* _cpu;
Sa1* _sa1;
shared_ptr<EventManager> _eventManager;
shared_ptr<CallstackManager> _callstackManager;
unique_ptr<BreakpointManager> _breakpointManager;
unique_ptr<StepRequest> _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<EventManager> GetEventManager();
shared_ptr<CallstackManager> GetCallstackManager();
BreakpointManager* GetBreakpointManager();
};

View file

@ -212,6 +212,14 @@ struct StackFrameInfo
StackFrameFlags Flags;
};
enum class DebugEventType
{
Register,
Nmi,
Irq,
Breakpoint
};
enum class BreakSource
{
Unspecified = -1,

View file

@ -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> 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> 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<PpuTools> Debugger::GetPpuTools()
return _ppuTools;
}
shared_ptr<EventManager> Debugger::GetEventManager()
shared_ptr<IEventManager> Debugger::GetEventManager()
{
return _eventManager;
if(_settings->CheckFlag(EmulationFlags::GameboyMode)) {
return std::dynamic_pointer_cast<IEventManager>(_gbDebugger->GetEventManager());
} else {
return std::dynamic_pointer_cast<IEventManager>(_cpuDebugger->GetEventManager());
}
}
shared_ptr<LabelManager> Debugger::GetLabelManager()
@ -729,3 +735,4 @@ 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);

View file

@ -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> _codeDataLogger;
shared_ptr<Disassembler> _disassembler;
shared_ptr<PpuTools> _ppuTools;
shared_ptr<EventManager> _eventManager;
shared_ptr<LabelManager> _labelManager;
shared_ptr<Assembler> _assembler;
@ -139,7 +139,7 @@ public:
shared_ptr<CodeDataLogger> GetCodeDataLogger();
shared_ptr<Disassembler> GetDisassembler();
shared_ptr<PpuTools> GetPpuTools();
shared_ptr<EventManager> GetEventManager();
shared_ptr<IEventManager> GetEventManager();
shared_ptr<LabelManager> GetLabelManager();
shared_ptr<ScriptManager> GetScriptManager();
shared_ptr<CallstackManager> GetCallstackManager(CpuType cpuType);

View file

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

View file

@ -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<DebugEventInfo> _sentEvents;
vector<DebugEventInfo> _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];
};

View file

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

View file

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

View file

@ -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<CpuType::Gameboy>(oldPc, _state.PC, false);
}
_state.Halted = false;
}

View file

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

View file

@ -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<GbEventManager> GbDebugger::GetEventManager()
{
return _eventManager;
}
shared_ptr<CallstackManager> GbDebugger::GetCallstackManager()
{
return _callstackManager;

View file

@ -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<GbEventManager> _eventManager;
shared_ptr<CallstackManager> _callstackManager;
unique_ptr<BreakpointManager> _breakpointManager;
unique_ptr<StepRequest> _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<GbEventManager> GetEventManager();
shared_ptr<CallstackManager> GetCallstackManager();
BreakpointManager* GetBreakpointManager();
};

257
Core/GbEventManager.cpp Normal file
View file

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

54
Core/GbEventManager.h Normal file
View file

@ -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<DebugEventInfo> _debugEvents;
vector<DebugEventInfo> _prevDebugEvents;
vector<DebugEventInfo> _sentEvents;
vector<DebugEventInfo> _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);
};

View file

@ -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<true>();
} else {
RenderScanline<false>();
}
}
}
}
}
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<bool isCgb>
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);
}
}

View file

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

View file

@ -16,6 +16,7 @@
#include "../Core/ScriptManager.h"
#include "../Core/Profiler.h"
#include "../Core/Assembler.h"
#include "../Core/BaseEventManager.h"
extern shared_ptr<Console> _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); }

View file

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

View file

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

View file

@ -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<string, string> values = new Dictionary<string, string>() {
{ "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<string, string> values;
if(_isGameboy) {
values = new Dictionary<string, string>() {
{ "Type", ResourceHelper.GetEnumText(evt.Type) },
{ "Scanline", evt.Scanline.ToString() },
{ "Cycle", evt.Cycle.ToString() },
{ "PC", "$" + evt.ProgramCounter.ToString("X4") },
};
} else {
values = new Dictionary<string, string>() {
{ "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);

View file

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

View file

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

View file

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