GB: Replace scanline renderer with pixel renderer
Probably still not very accurate
This commit is contained in:
parent
435051f73d
commit
134c28ed9f
30 changed files with 907 additions and 297 deletions
80
Core/BaseEventManager.h
Normal file
80
Core/BaseEventManager.h
Normal 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;
|
||||
};
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
|
@ -212,6 +212,14 @@ struct StackFrameInfo
|
|||
StackFrameFlags Flags;
|
||||
};
|
||||
|
||||
enum class DebugEventType
|
||||
{
|
||||
Register,
|
||||
Nmi,
|
||||
Irq,
|
||||
Breakpoint
|
||||
};
|
||||
|
||||
enum class BreakSource
|
||||
{
|
||||
Unspecified = -1,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
};
|
|
@ -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 };
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
257
Core/GbEventManager.cpp
Normal 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
54
Core/GbEventManager.h
Normal 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);
|
||||
};
|
390
Core/GbPpu.cpp
390
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<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);
|
||||
}
|
||||
}
|
||||
|
|
43
Core/GbPpu.h
43
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<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();
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue