diff --git a/Core/BaseCartridge.cpp b/Core/BaseCartridge.cpp index 4793a81..1c990de 100644 --- a/Core/BaseCartridge.cpp +++ b/Core/BaseCartridge.cpp @@ -10,6 +10,7 @@ #include "EmuSettings.h" #include "NecDsp.h" #include "Sa1.h" +#include "Gsu.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/VirtualFile.h" #include "../Utilities/FolderUtilities.h" @@ -162,6 +163,15 @@ void BaseCartridge::Init() _coprocessorType = GetCoprocessorType(); + if(_coprocessorType != CoprocessorType::None && _cartInfo.ExpansionRamSize > 0 && _cartInfo.ExpansionRamSize <= 7) { + _coprocessorRamSize = _cartInfo.ExpansionRamSize > 0 ? 1024 * (1 << _cartInfo.ExpansionRamSize) : 0; + } + + if(_coprocessorType == CoprocessorType::GSU && _coprocessorRamSize == 0) { + //Use a min of 64kb by default for GSU games + _coprocessorRamSize = 0x10000; + } + _saveRamSize = _cartInfo.SramSize > 0 ? 1024 * (1 << _cartInfo.SramSize) : 0; _saveRam = new uint8_t[_saveRamSize]; _console->GetSettings()->InitializeRam(_saveRam, _saveRamSize); @@ -174,7 +184,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType() if((_cartInfo.RomType & 0x0F) >= 0x03) { switch((_cartInfo.RomType & 0xF0) >> 4) { case 0x00: return GetDspVersion(); break; - case 0x01: return CoprocessorType::GSU1; break; //Or mariochip1/gsu2 + case 0x01: return CoprocessorType::GSU; break; case 0x02: return CoprocessorType::OBC1; break; case 0x03: return CoprocessorType::SA1; break; case 0x04: return CoprocessorType::DD1; break; @@ -224,7 +234,9 @@ CoprocessorType BaseCartridge::GetDspVersion() void BaseCartridge::Reset() { - _coprocessor->Reset(); + if(_coprocessor) { + _coprocessor->Reset(); + } } RomInfo BaseCartridge::GetRomInfo() @@ -300,7 +312,7 @@ void BaseCartridge::Init(MemoryMappings &mm) void BaseCartridge::RegisterHandlers(MemoryMappings &mm) { - if(MapSpecificCarts(mm)) { + if(_coprocessorType == CoprocessorType::GSU || MapSpecificCarts(mm)) { return; } @@ -351,6 +363,9 @@ void BaseCartridge::InitCoprocessor() if(_coprocessorType == CoprocessorType::SA1) { _coprocessor.reset(new Sa1(_console)); _sa1 = dynamic_cast(_coprocessor.get()); + } else if(_coprocessorType == CoprocessorType::GSU) { + _coprocessor.reset(new Gsu(_console, _coprocessorRamSize)); + _gsu = dynamic_cast(_coprocessor.get()); } } @@ -459,9 +474,7 @@ void BaseCartridge::DisplayCartInfo() case CoprocessorType::DSP2: coProcMessage += "DSP2"; break; case CoprocessorType::DSP3: coProcMessage += "DSP3"; break; case CoprocessorType::DSP4: coProcMessage += "DSP4"; break; - case CoprocessorType::GSU1: coProcMessage += "Super FX (GSU1)"; break; - case CoprocessorType::GSU2: coProcMessage += "Super FX (GSU2)"; break; - case CoprocessorType::MarioChip: coProcMessage += "Super FX (Mario Chip 1)"; break; + case CoprocessorType::GSU: coProcMessage += "Super FX (GSU1/2)"; break; case CoprocessorType::OBC1: coProcMessage += "OBC1"; break; case CoprocessorType::RTC: coProcMessage += "RTC"; break; case CoprocessorType::SA1: coProcMessage += "SA1"; break; @@ -489,6 +502,9 @@ void BaseCartridge::DisplayCartInfo() if(_saveRamSize > 0) { MessageManager::Log("SRAM size: " + std::to_string(_saveRamSize / 1024) + " KB"); } + if(_coprocessorRamSize > 0) { + MessageManager::Log("Coprocessor RAM size: " + std::to_string(_coprocessorRamSize / 1024) + " KB"); + } MessageManager::Log("-----------------------------"); } @@ -502,6 +518,19 @@ Sa1* BaseCartridge::GetSa1() return _sa1; } +Gsu* BaseCartridge::GetGsu() +{ + return _gsu; +} + +void BaseCartridge::RunCoprocessors() +{ + //These coprocessors are run at the end of the frame, or as needed + if(_necDsp) { + _necDsp->Run(); + } +} + BaseCoprocessor* BaseCartridge::GetCoprocessor() { return _coprocessor.get(); diff --git a/Core/BaseCartridge.h b/Core/BaseCartridge.h index 7251bc7..e57a638 100644 --- a/Core/BaseCartridge.h +++ b/Core/BaseCartridge.h @@ -10,6 +10,7 @@ class VirtualFile; class EmuSettings; class NecDsp; class Sa1; +class Gsu; class Console; class BaseCartridge : public ISerializable @@ -24,6 +25,7 @@ private: unique_ptr _coprocessor; NecDsp *_necDsp = nullptr; Sa1 *_sa1 = nullptr; + Gsu *_gsu = nullptr; CartFlags::CartFlags _flags = CartFlags::CartFlags::None; CoprocessorType _coprocessorType = CoprocessorType::None; @@ -35,6 +37,7 @@ private: uint32_t _prgRomSize = 0; uint32_t _saveRamSize = 0; + uint32_t _coprocessorRamSize = 0; void LoadBattery(); @@ -76,6 +79,10 @@ public: NecDsp* GetDsp(); Sa1* GetSa1(); + Gsu* GetGsu(); + + void RunCoprocessors(); + BaseCoprocessor* GetCoprocessor(); vector>& GetPrgRomHandlers(); diff --git a/Core/BaseCoprocessor.h b/Core/BaseCoprocessor.h index dda218e..840b9df 100644 --- a/Core/BaseCoprocessor.h +++ b/Core/BaseCoprocessor.h @@ -6,9 +6,9 @@ class BaseCoprocessor : public ISerializable, public IMemoryHandler { public: - virtual void Run() = 0; virtual void Reset() = 0; - + + virtual void ProcessEndOfFrame() { } virtual void LoadBattery(string filePath) { } virtual void SaveBattery(string filePath) { } }; \ No newline at end of file diff --git a/Core/Breakpoint.cpp b/Core/Breakpoint.cpp index 36d1f0e..0386458 100644 --- a/Core/Breakpoint.cpp +++ b/Core/Breakpoint.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" #include "Breakpoint.h" #include "DebugTypes.h" +#include "DebugUtilities.h" bool Breakpoint::Matches(uint32_t memoryAddr, AddressInfo &info) { - if(_memoryType <= SnesMemoryType::Sa1Memory) { + if(_memoryType <= DebugUtilities::GetLastCpuMemoryType()) { if(_startAddr == -1) { return true; } else if(_endAddr == -1) { diff --git a/Core/BreakpointManager.cpp b/Core/BreakpointManager.cpp index 97956e7..c35f9e0 100644 --- a/Core/BreakpointManager.cpp +++ b/Core/BreakpointManager.cpp @@ -3,6 +3,7 @@ #include "DebugTypes.h" #include "Debugger.h" #include "Breakpoint.h" +#include "DebugUtilities.h" #include "ExpressionEvaluator.h" BreakpointManager::BreakpointManager(Debugger *debugger) @@ -12,7 +13,7 @@ BreakpointManager::BreakpointManager(Debugger *debugger) void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) { - for(int j = 0; j < (int)CpuType::Sa1 + 1; j++) { + for(int j = 0; j <= (int)DebugUtilities::GetLastCpuType(); j++) { for(int i = 0; i < BreakpointManager::BreakpointTypeCount; i++) { _breakpoints[j][i].clear(); _rpnList[j][i].clear(); @@ -22,6 +23,8 @@ void BreakpointManager::SetBreakpoints(Breakpoint breakpoints[], uint32_t count) _bpExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(_debugger, CpuType::Cpu)); _bpExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(_debugger, CpuType::Spc)); + _bpExpEval[(int)CpuType::Sa1].reset(new ExpressionEvaluator(_debugger, CpuType::Sa1)); + _bpExpEval[(int)CpuType::Gsu].reset(new ExpressionEvaluator(_debugger, CpuType::Gsu)); for(uint32_t j = 0; j < count; j++) { Breakpoint &bp = breakpoints[j]; diff --git a/Core/BreakpointManager.h b/Core/BreakpointManager.h index c550aa7..9a46a5f 100644 --- a/Core/BreakpointManager.h +++ b/Core/BreakpointManager.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "Breakpoint.h" #include "DebugTypes.h" +#include "DebugUtilities.h" class ExpressionEvaluator; class Debugger; @@ -15,11 +16,11 @@ private: Debugger *_debugger; - vector _breakpoints[(int)CpuType::Sa1 + 1][BreakpointTypeCount]; - vector _rpnList[(int)CpuType::Sa1 + 1][BreakpointTypeCount]; - bool _hasBreakpoint[(int)CpuType::Sa1 + 1][BreakpointTypeCount] = {}; + vector _breakpoints[(int)DebugUtilities::GetLastCpuType() + 1][BreakpointTypeCount]; + vector _rpnList[(int)DebugUtilities::GetLastCpuType() + 1][BreakpointTypeCount]; + bool _hasBreakpoint[(int)DebugUtilities::GetLastCpuType() + 1][BreakpointTypeCount] = {}; - unique_ptr _bpExpEval[(int)CpuType::Sa1 + 1]; + unique_ptr _bpExpEval[(int)DebugUtilities::GetLastCpuType() + 1]; BreakpointType GetBreakpointType(MemoryOperationType type); diff --git a/Core/CartTypes.h b/Core/CartTypes.h index 6d5278c..0f8f3de 100644 --- a/Core/CartTypes.h +++ b/Core/CartTypes.h @@ -33,9 +33,7 @@ enum class CoprocessorType DSP2, DSP3, DSP4, - GSU1, - GSU2, - MarioChip, + GSU, OBC1, SA1, DD1, diff --git a/Core/Console.cpp b/Core/Console.cpp index dd17e45..637dd17 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -107,9 +107,11 @@ void Console::Run() _cpu->Exec(); if(previousFrameCount != _ppu->GetFrameCount()) { + _cart->RunCoprocessors(); if(_cart->GetCoprocessor()) { - _cart->GetCoprocessor()->Run(); + _cart->GetCoprocessor()->ProcessEndOfFrame(); } + _rewindManager->ProcessEndOfFrame(); WaitForLock(); @@ -169,6 +171,11 @@ void Console::RunSingleFrame() _cpu->Exec(); } + _cart->RunCoprocessors(); + if(_cart->GetCoprocessor()) { + _cart->GetCoprocessor()->ProcessEndOfFrame(); + } + _controlManager->UpdateControlDevices(); } @@ -231,7 +238,7 @@ void Console::Reset() _spc->Reset(); _ppu->Reset(); _cpu->Reset(); - //_cart->Reset(); + _cart->Reset(); //_controlManager->Reset(); _notificationManager->SendNotification(ConsoleNotificationType::GameReset); @@ -673,9 +680,7 @@ void Console::ProcessPpuCycle() if(_debugger) { _debugger->ProcessPpuCycle(); _spc->Run(); - if(_cart->GetCoprocessor()) { - _cart->GetCoprocessor()->Run(); - } + _cart->RunCoprocessors(); } } @@ -697,10 +702,12 @@ void Console::ProcessEvent(EventType type) template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); +template void Console::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); +template void Console::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template void Console::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); \ No newline at end of file diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 4a30c63..6e1d8fb 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -51,6 +51,12 @@ + + + + + + @@ -184,6 +190,10 @@ + + + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 747f9d4..efffab3 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -329,10 +329,30 @@ Debugger\Debuggers - SNES + + SNES\Coprocessors\GSU + + + SNES\Coprocessors\GSU + + + Debugger\Debuggers + + + Debugger\Disassembler + + + SNES + + + SNES\Coprocessors\GSU + + + SNES\Coprocessors\GSU + @@ -537,6 +557,18 @@ Debugger\Debuggers + + SNES\Coprocessors\GSU + + + SNES\Coprocessors\GSU + + + Debugger\Debuggers + + + Debugger\Disassembler + @@ -581,5 +613,8 @@ {799edb31-b81c-4842-a1e5-a81d5b28459a} + + {5bda57b5-9204-46f4-85f5-3b550c589a18} + \ No newline at end of file diff --git a/Core/CpuDebugger.cpp b/Core/CpuDebugger.cpp index ee55da8..31318c3 100644 --- a/Core/CpuDebugger.cpp +++ b/Core/CpuDebugger.cpp @@ -66,7 +66,7 @@ void CpuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType } _codeDataLogger->SetFlags(addressInfo.Address, flags); } - _disassembler->BuildCache(addressInfo, state.PS, _cpuType); + _disassembler->BuildCache(addressInfo, state.PS & (ProcFlags::IndexMode8 | ProcFlags::MemoryMode8), _cpuType); } DebugState debugState; diff --git a/Core/DebugTypes.h b/Core/DebugTypes.h index 5c96f12..b17bd8a 100644 --- a/Core/DebugTypes.h +++ b/Core/DebugTypes.h @@ -4,6 +4,7 @@ #include "PpuTypes.h" #include "SpcTypes.h" #include "NecDspTypes.h" +#include "GsuTypes.h" struct DebugState { @@ -13,6 +14,7 @@ struct DebugState SpcState Spc; NecDspState Dsp; CpuState Sa1; + GsuState Gsu; }; enum class SnesMemoryType @@ -20,6 +22,7 @@ enum class SnesMemoryType CpuMemory, SpcMemory, Sa1Memory, + GsuMemory, PrgRom, WorkRam, SaveRam, @@ -32,6 +35,7 @@ enum class SnesMemoryType DspDataRom, DspDataRam, Sa1InternalRam, + GsuWorkRam, Register, }; @@ -253,5 +257,5 @@ enum class CpuType : uint8_t Spc, NecDsp, Sa1, - //SuperFx, + Gsu, }; diff --git a/Core/DebugUtilities.h b/Core/DebugUtilities.h index e4357c9..baf1a2f 100644 --- a/Core/DebugUtilities.h +++ b/Core/DebugUtilities.h @@ -11,9 +11,20 @@ public: case CpuType::Cpu: return SnesMemoryType::CpuMemory; case CpuType::Spc: return SnesMemoryType::SpcMemory; case CpuType::Sa1: return SnesMemoryType::Sa1Memory; + case CpuType::Gsu: return SnesMemoryType::GsuMemory; case CpuType::NecDsp: break; } throw std::runtime_error("Invalid CPU type"); } + + static constexpr SnesMemoryType GetLastCpuMemoryType() + { + return SnesMemoryType::GsuMemory; + } + + static constexpr CpuType GetLastCpuType() + { + return CpuType::Gsu; + } }; \ No newline at end of file diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 7e9be96..6db27b4 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -6,9 +6,11 @@ #include "Ppu.h" #include "Spc.h" #include "Sa1.h" +#include "Gsu.h" #include "NecDsp.h" #include "CpuDebugger.h" #include "SpcDebugger.h" +#include "GsuDebugger.h" #include "BaseCartridge.h" #include "MemoryManager.h" #include "EmuSettings.h" @@ -48,6 +50,7 @@ Debugger::Debugger(shared_ptr console) _watchExpEval[(int)CpuType::Cpu].reset(new ExpressionEvaluator(this, CpuType::Cpu)); _watchExpEval[(int)CpuType::Spc].reset(new ExpressionEvaluator(this, CpuType::Spc)); _watchExpEval[(int)CpuType::Sa1].reset(new ExpressionEvaluator(this, CpuType::Sa1)); + _watchExpEval[(int)CpuType::Gsu].reset(new ExpressionEvaluator(this, CpuType::Gsu)); _codeDataLogger.reset(new CodeDataLogger(_cart->DebugGetPrgRomSize(), _memoryManager.get())); _memoryDumper.reset(new MemoryDumper(_ppu, console->GetSpc(), _memoryManager, _cart)); @@ -63,6 +66,8 @@ Debugger::Debugger(shared_ptr console) _spcDebugger.reset(new SpcDebugger(this)); if(_cart->GetSa1()) { _sa1Debugger.reset(new CpuDebugger(this, CpuType::Sa1)); + } else if(_cart->GetGsu()) { + _gsuDebugger.reset(new GsuDebugger(this)); } _step.reset(new StepRequest()); @@ -106,8 +111,9 @@ void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationTy { switch(type) { case CpuType::Cpu: _cpuDebugger->ProcessRead(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); break; case CpuType::Spc: _spcDebugger->ProcessRead(addr, value, opType); break; + case CpuType::Sa1: _sa1Debugger->ProcessRead(addr, value, opType); break; + case CpuType::Gsu: _gsuDebugger->ProcessRead(addr, value, opType); break; } } @@ -116,8 +122,9 @@ void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationT { switch(type) { case CpuType::Cpu: _cpuDebugger->ProcessWrite(addr, value, opType); break; - case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); break; case CpuType::Spc: _spcDebugger->ProcessWrite(addr, value, opType); break; + case CpuType::Sa1: _sa1Debugger->ProcessWrite(addr, value, opType); break; + case CpuType::Gsu: _gsuDebugger->ProcessWrite(addr, value, opType); break; } } @@ -200,6 +207,8 @@ void Debugger::SleepUntilResume(BreakSource source, MemoryOperationInfo *operati _disassembler->Disassemble(CpuType::Spc); if(_cart->GetSa1()) { _disassembler->Disassemble(CpuType::Sa1); + } else if(_cart->GetGsu()) { + _disassembler->Disassemble(CpuType::Gsu); } _executionStopped = true; @@ -283,6 +292,9 @@ void Debugger::Run() if(_sa1Debugger) { _sa1Debugger->Run(); } + if(_gsuDebugger) { + _gsuDebugger->Run(); + } _waitForBreakResume = false; } @@ -295,6 +307,9 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type) if(_sa1Debugger) { _sa1Debugger->Run(); } + if(_gsuDebugger) { + _gsuDebugger->Run(); + } switch(type) { case StepType::PpuStep: step.PpuStepCount = stepCount; break; @@ -305,6 +320,7 @@ void Debugger::Step(CpuType cpuType, int32_t stepCount, StepType type) case CpuType::Cpu: _cpuDebugger->Step(stepCount, type); break; case CpuType::Spc: _spcDebugger->Step(stepCount, type); break; case CpuType::Sa1: _sa1Debugger->Step(stepCount, type); break; + case CpuType::Gsu: _gsuDebugger->Step(stepCount, type); break; case CpuType::NecDsp: throw std::runtime_error("Step(): Unsupported CPU type."); } break; @@ -349,6 +365,9 @@ void Debugger::GetState(DebugState &state, bool partialPpuState) if(_cart->GetSa1()) { state.Sa1 = _cart->GetSa1()->GetCpuState(); } + if(_cart->GetGsu()) { + state.Gsu = _cart->GetGsu()->GetState(); + } } AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) @@ -363,6 +382,8 @@ AddressInfo Debugger::GetAbsoluteAddress(AddressInfo relAddress) return _spc->GetAbsoluteAddress(relAddress.Address); } else if(relAddress.Type == SnesMemoryType::Sa1Memory) { return _cart->GetSa1()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); + } else if(relAddress.Type == SnesMemoryType::GsuMemory) { + return _cart->GetGsu()->GetMemoryMappings()->GetAbsoluteAddress(relAddress.Address); } throw std::runtime_error("Unsupported address type"); @@ -468,6 +489,8 @@ shared_ptr Debugger::GetCallstackManager(CpuType cpuType) case CpuType::Cpu: return _cpuDebugger->GetCallstackManager(); case CpuType::Spc: return _spcDebugger->GetCallstackManager(); case CpuType::Sa1: return _sa1Debugger->GetCallstackManager(); + + case CpuType::Gsu: case CpuType::NecDsp: break; } throw std::runtime_error("GetCallstackManager() - Unsupported CPU type"); @@ -481,10 +504,12 @@ shared_ptr Debugger::GetConsole() template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); +template void Debugger::ProcessMemoryRead(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); +template void Debugger::ProcessMemoryWrite(uint32_t addr, uint8_t value, MemoryOperationType opType); template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); template void Debugger::ProcessInterrupt(uint32_t originalPc, uint32_t currentPc, bool forNmi); diff --git a/Core/Debugger.h b/Core/Debugger.h index 728577c..798b197 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -26,6 +26,7 @@ class LabelManager; class ScriptManager; class SpcDebugger; class CpuDebugger; +class GsuDebugger; enum class EventType; enum class EvalResultType : int32_t; @@ -44,6 +45,7 @@ private: unique_ptr _spcDebugger; unique_ptr _cpuDebugger; unique_ptr _sa1Debugger; + unique_ptr _gsuDebugger; shared_ptr _scriptManager; shared_ptr _traceLogger; @@ -56,7 +58,7 @@ private: shared_ptr _eventManager; shared_ptr _labelManager; - unique_ptr _watchExpEval[(int)CpuType::Sa1 + 1]; + unique_ptr _watchExpEval[(int)CpuType::Gsu + 1]; atomic _executionStopped; atomic _breakRequestCount; diff --git a/Core/Disassembler.cpp b/Core/Disassembler.cpp index 16be8d3..5dd1866 100644 --- a/Core/Disassembler.cpp +++ b/Core/Disassembler.cpp @@ -6,6 +6,7 @@ #include "Spc.h" #include "NecDsp.h" #include "Sa1.h" +#include "Gsu.h" #include "Debugger.h" #include "MemoryManager.h" #include "LabelManager.h" @@ -49,6 +50,9 @@ Disassembler::Disassembler(shared_ptr console, shared_ptrGetCartridge()->GetSa1() ? console->GetCartridge()->GetSa1()->DebugGetInternalRam() : nullptr; _sa1InternalRamSize = console->GetCartridge()->GetSa1() ? console->GetCartridge()->GetSa1()->DebugGetInternalRamSize() : 0; + _gsuWorkRam = console->GetCartridge()->GetGsu() ? console->GetCartridge()->GetGsu()->DebugGetWorkRam() : nullptr; + _gsuWorkRamSize = console->GetCartridge()->GetGsu() ? console->GetCartridge()->GetGsu()->DebugGetWorkRamSize() : 0; + _prgCache = vector(_prgRomSize); _sramCache = vector(_sramSize); _wramCache = vector(_wramSize); @@ -56,6 +60,11 @@ Disassembler::Disassembler(shared_ptr console, shared_ptr(_spcRomSize); _necDspRomCache = vector(_necDspProgramRomSize); _sa1InternalRamCache = vector(_sa1InternalRamSize); + _gsuWorkRamCache = vector(_gsuWorkRamSize); + + for(int i = 0; i < (int)DebugUtilities::GetLastCpuType(); i++) { + _needDisassemble[i] = true; + } } void Disassembler::GetSource(AddressInfo &info, uint8_t **source, uint32_t &size, vector **cache) @@ -103,6 +112,12 @@ void Disassembler::GetSource(AddressInfo &info, uint8_t **source, uint32_t &size size = _sa1InternalRamSize; break; + case SnesMemoryType::GsuWorkRam: + *source = _gsuWorkRam; + *cache = &_gsuWorkRamCache; + size = _gsuWorkRamSize; + break; + default: throw std::runtime_error("Disassembler::GetSource() invalid memory type"); } @@ -114,6 +129,7 @@ vector& Disassembler::GetDisassemblyList(CpuType type) case CpuType::Cpu: return _disassembly; case CpuType::Spc: return _spcDisassembly; case CpuType::Sa1: return _sa1Disassembly; + case CpuType::Gsu: return _gsuDisassembly; case CpuType::NecDsp: break; } throw std::runtime_error("Disassembly::GetDisassemblyList(): Invalid cpu type"); @@ -156,9 +172,10 @@ uint32_t Disassembler::BuildCache(AddressInfo &addrInfo, uint8_t cpuFlags, CpuTy void Disassembler::SetDisassembleFlag(CpuType type) { - if(type == CpuType::Cpu || type == CpuType::Sa1) { + if(type == CpuType::Cpu || type == CpuType::Sa1 || type == CpuType::Gsu) { _needDisassemble[(int)CpuType::Cpu] = true; _needDisassemble[(int)CpuType::Sa1] = true; + _needDisassemble[(int)CpuType::Gsu] = true; } else if(type == CpuType::Spc) { _needDisassemble[(int)CpuType::Spc] = true; } else { @@ -171,6 +188,7 @@ void Disassembler::ResetPrgCache() _prgCache = vector(_prgRomSize); _needDisassemble[(int)CpuType::Cpu] = true; _needDisassemble[(int)CpuType::Sa1] = true; + _needDisassemble[(int)CpuType::Gsu] = true; } void Disassembler::InvalidateCache(AddressInfo addrInfo, CpuType type) @@ -208,7 +226,28 @@ void Disassembler::Disassemble(CpuType cpuType) auto lock = _disassemblyLock.AcquireSafe(); bool isSpc = cpuType == CpuType::Spc; - MemoryMappings *mappings = cpuType == CpuType::Sa1 ? _console->GetCartridge()->GetSa1()->GetMemoryMappings() : _memoryManager->GetMemoryMappings(); + MemoryMappings *mappings = nullptr; + switch(cpuType) { + case CpuType::Cpu: mappings = _memoryManager->GetMemoryMappings(); break; + + case CpuType::Sa1: + if(!_console->GetCartridge()->GetSa1()) { + return; + } + mappings = _console->GetCartridge()->GetSa1()->GetMemoryMappings(); + break; + + case CpuType::Gsu: + if(!_console->GetCartridge()->GetGsu()) { + return; + } + mappings = _console->GetCartridge()->GetGsu()->GetMemoryMappings(); + break; + + case CpuType::Spc: mappings = nullptr; break; + default: throw std::runtime_error("Disassemble(): Invalid cpu type"); + } + vector &results = GetDisassemblyList(cpuType); int32_t maxAddr = isSpc ? 0xFFFF : 0xFFFFFF; results.clear(); @@ -462,11 +501,12 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d vector *cache; GetSource(result.Address, &source, sourceLength, &cache); DisassemblyInfo disInfo = (*cache)[result.Address.Address]; + CpuType lineCpuType = disInfo.IsInitialized() ? disInfo.GetCpuType() : type; data.Address = result.CpuAddress; data.AbsoluteAddress = result.Address.Address; - switch(type) { + switch(lineCpuType) { case CpuType::Cpu: case CpuType::Sa1: { CpuState state = _console->GetCpu()->GetState(); @@ -511,6 +551,19 @@ bool Disassembler::GetLineData(CpuType type, uint32_t lineIndex, CodeLineData &d break; } + case CpuType::Gsu: { + if(!disInfo.IsInitialized()) { + disInfo = DisassemblyInfo(source + result.Address.Address, 0, CpuType::Gsu); + } else { + data.Flags |= LineFlags::VerifiedCode; + } + + data.OpSize = disInfo.GetOpSize(); + data.EffectiveAddress = -1; + data.ValueSize = 0; + break; + } + case CpuType::NecDsp: throw std::runtime_error("GetLineData - CPU type not supported"); } diff --git a/Core/Disassembler.h b/Core/Disassembler.h index 372fc46..8bfdf3b 100644 --- a/Core/Disassembler.h +++ b/Core/Disassembler.h @@ -2,6 +2,7 @@ #include "stdafx.h" #include "DisassemblyInfo.h" #include "DebugTypes.h" +#include "DebugUtilities.h" #include "../Utilities/SimpleLock.h" class MemoryManager; @@ -32,13 +33,15 @@ private: vector _spcRomCache; vector _necDspRomCache; vector _sa1InternalRamCache; + vector _gsuWorkRamCache; SimpleLock _disassemblyLock; vector _disassembly; vector _spcDisassembly; vector _sa1Disassembly; + vector _gsuDisassembly; - bool _needDisassemble[(int)CpuType::Sa1+1] = { true, true, true, true }; + bool _needDisassemble[(int)DebugUtilities::GetLastCpuType()+1]; uint8_t *_prgRom; uint32_t _prgRomSize; @@ -57,6 +60,9 @@ private: uint8_t *_sa1InternalRam; uint32_t _sa1InternalRamSize; + uint8_t *_gsuWorkRam; + uint32_t _gsuWorkRamSize; + void GetSource(AddressInfo &info, uint8_t **source, uint32_t &size, vector **cache); vector& GetDisassemblyList(CpuType type); void SetDisassembleFlag(CpuType type); diff --git a/Core/DisassemblyInfo.cpp b/Core/DisassemblyInfo.cpp index 13d1fbe..b414686 100644 --- a/Core/DisassemblyInfo.cpp +++ b/Core/DisassemblyInfo.cpp @@ -5,6 +5,7 @@ #include "MemoryDumper.h" #include "CpuDisUtils.h" #include "SpcDisUtils.h" +#include "GsuDisUtils.h" #include "NecDspDisUtils.h" #include "../Utilities/HexUtilities.h" #include "../Utilities/FastString.h" @@ -21,7 +22,7 @@ DisassemblyInfo::DisassemblyInfo(uint8_t *opPointer, uint8_t cpuFlags, CpuType t void DisassemblyInfo::Initialize(uint8_t *opPointer, uint8_t cpuFlags, CpuType type) { _cpuType = type; - _flags = cpuFlags & (ProcFlags::MemoryMode8 | ProcFlags::IndexMode8); + _flags = cpuFlags; _opSize = GetOpSize(opPointer[0], _flags, _cpuType); memcpy(_byteCode, opPointer, _opSize); @@ -35,7 +36,7 @@ bool DisassemblyInfo::IsInitialized() bool DisassemblyInfo::IsValid(uint8_t cpuFlags) { - return _flags == (cpuFlags & (ProcFlags::MemoryMode8 | ProcFlags::IndexMode8)); + return _flags == cpuFlags; } void DisassemblyInfo::Reset() @@ -53,6 +54,7 @@ void DisassemblyInfo::GetDisassembly(string &out, uint32_t memoryAddr, LabelMana case CpuType::Spc: SpcDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break; case CpuType::NecDsp: NecDspDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break; + case CpuType::Gsu: GsuDisUtils::GetDisassembly(*this, out, memoryAddr, labelManager); break; } } @@ -64,11 +66,18 @@ int32_t DisassemblyInfo::GetEffectiveAddress(Console *console, void *cpuState) return CpuDisUtils::GetEffectiveAddress(*this, console, *(CpuState*)cpuState); case CpuType::Spc: return SpcDisUtils::GetEffectiveAddress(*this, console, *(SpcState*)cpuState); + + case CpuType::Gsu: case CpuType::NecDsp: return -1; } return -1; } +CpuType DisassemblyInfo::GetCpuType() +{ + return _cpuType; +} + uint8_t DisassemblyInfo::GetOpCode() { return _byteCode[0]; @@ -114,6 +123,17 @@ uint8_t DisassemblyInfo::GetOpSize(uint8_t opCode, uint8_t flags, CpuType type) return CpuDisUtils::GetOpSize(opCode, flags); case CpuType::Spc: return SpcDisUtils::GetOpSize(opCode); + + case CpuType::Gsu: + if(opCode >= 0x05 && opCode <= 0x0F) { + return 2; + } else if(opCode >= 0xA0 && opCode <= 0xAF) { + return 2; + } else if(opCode >= 0xF0 && opCode <= 0xFF) { + return 3; + } + return 1; + case CpuType::NecDsp: return 4; } return 0; @@ -127,6 +147,8 @@ bool DisassemblyInfo::IsJumpToSub(uint8_t opCode, CpuType type) return opCode == 0x20 || opCode == 0x22 || opCode == 0xFC; //JSR, JSL case CpuType::Spc: return opCode == 0x3F || opCode == 0x0F; //JSR, BRK + + case CpuType::Gsu: case CpuType::NecDsp: return false; } return false; @@ -141,6 +163,8 @@ bool DisassemblyInfo::IsReturnInstruction(uint8_t opCode, CpuType type) return opCode == 0x60 || opCode == 0x6B || opCode == 0x40; case CpuType::Spc: return opCode == 0x6F || opCode == 0x7F; + + case CpuType::Gsu: case CpuType::NecDsp: return false; } @@ -170,6 +194,7 @@ bool DisassemblyInfo::UpdateCpuFlags(uint8_t &cpuFlags) } return true; + case CpuType::Gsu: case CpuType::Spc: case CpuType::NecDsp: return false; } diff --git a/Core/DisassemblyInfo.h b/Core/DisassemblyInfo.h index 7442423..015b614 100644 --- a/Core/DisassemblyInfo.h +++ b/Core/DisassemblyInfo.h @@ -28,6 +28,7 @@ public: void GetDisassembly(string &out, uint32_t memoryAddr, LabelManager *labelManager); + CpuType GetCpuType(); uint8_t GetOpCode(); uint8_t GetOpSize(); uint8_t GetFlags(); diff --git a/Core/ExpressionEvaluator.cpp b/Core/ExpressionEvaluator.cpp index 2b609ee..efdf60d 100644 --- a/Core/ExpressionEvaluator.cpp +++ b/Core/ExpressionEvaluator.cpp @@ -71,60 +71,139 @@ bool ExpressionEvaluator::CheckSpecialTokens(string expression, size_t &pos, str } } while(pos < len); - if(token == "a") { - output += std::to_string((int64_t)EvalValues::RegA); - } else if(token == "x") { - output += std::to_string((int64_t)EvalValues::RegX); - } else if(token == "y") { - output += std::to_string((int64_t)EvalValues::RegY); - } else if(token == "ps") { - output += std::to_string((int64_t)EvalValues::RegPS); - } else if(token == "sp") { - output += std::to_string((int64_t)EvalValues::RegSP); - } else if(token == "pc") { - output += std::to_string((int64_t)EvalValues::RegPC); - } else if(token == "oppc") { - output += std::to_string((int64_t)EvalValues::RegOpPC); - } else if(token == "previousoppc") { - output += std::to_string((int64_t)EvalValues::PreviousOpPC); - } else if(token == "frame") { - output += std::to_string((int64_t)EvalValues::PpuFrameCount); - } else if(token == "cycle") { - output += std::to_string((int64_t)EvalValues::PpuCycle); - } else if(token == "scanline") { - output += std::to_string((int64_t)EvalValues::PpuScanline); - } else if(token == "irq") { - output += std::to_string((int64_t)EvalValues::Irq); - } else if(token == "nmi") { - output += std::to_string((int64_t)EvalValues::Nmi); - } else if(token == "value") { - output += std::to_string((int64_t)EvalValues::Value); - } else if(token == "address") { - output += std::to_string((int64_t)EvalValues::Address); - } else if(token == "romaddress") { - output += std::to_string((int64_t)EvalValues::AbsoluteAddress); - } else if(token == "iswrite") { - output += std::to_string((int64_t)EvalValues::IsWrite); - } else if(token == "isread") { - output += std::to_string((int64_t)EvalValues::IsRead); - } else { - string originalExpression = expression.substr(initialPos, pos - initialPos); - bool validLabel = _labelManager->ContainsLabel(originalExpression); - if(!validLabel) { - //Check if a multi-byte label exists for this name - string label = originalExpression + "+0"; - validLabel = _labelManager->ContainsLabel(label); + if(_cpuType == CpuType::Gsu) { + int64_t gsuToken = ProcessGsuTokens(token); + if(gsuToken != -1) { + output += std::to_string(gsuToken); + return true; } - - if(validLabel) { - data.Labels.push_back(originalExpression); - output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1); - } else { - return false; + } else { + int64_t cpuToken = ProcessCpuSpcTokens(token); + if(cpuToken != -1) { + output += std::to_string(cpuToken); + return true; } } - return true; + int64_t sharedToken = ProcessSharedTokens(token); + if(sharedToken != -1) { + output += std::to_string(sharedToken); + return true; + } + + string originalExpression = expression.substr(initialPos, pos - initialPos); + bool validLabel = _labelManager->ContainsLabel(originalExpression); + if(!validLabel) { + //Check if a multi-byte label exists for this name + string label = originalExpression + "+0"; + validLabel = _labelManager->ContainsLabel(label); + } + + if(validLabel) { + data.Labels.push_back(originalExpression); + output += std::to_string(EvalValues::FirstLabelIndex + data.Labels.size() - 1); + return true; + } else { + return false; + } +} + +int64_t ExpressionEvaluator::ProcessCpuSpcTokens(string token) +{ + if(token == "a") { + return EvalValues::RegA; + } else if(token == "x") { + return EvalValues::RegX; + } else if(token == "y") { + return EvalValues::RegY; + } else if(token == "ps") { + return EvalValues::RegPS; + } else if(token == "sp") { + return EvalValues::RegSP; + } else if(token == "pc") { + return EvalValues::RegPC; + } else if(token == "oppc") { + return EvalValues::RegOpPC; + } else if(token == "previousoppc") { + return EvalValues::PreviousOpPC; + } else if(token == "irq") { + return EvalValues::Irq; + } else if(token == "nmi") { + return EvalValues::Nmi; + } + return -1; +} + +int64_t ExpressionEvaluator::ProcessSharedTokens(string token) +{ + if(token == "frame") { + return EvalValues::PpuFrameCount; + } else if(token == "cycle") { + return EvalValues::PpuCycle; + } else if(token == "scanline") { + return EvalValues::PpuScanline; + } else if(token == "value") { + return EvalValues::Value; + } else if(token == "address") { + return EvalValues::Address; + } else if(token == "romaddress") { + return EvalValues::AbsoluteAddress; + } else if(token == "iswrite") { + return EvalValues::IsWrite; + } else if(token == "isread") { + return EvalValues::IsRead; + } + return -1; +} + +int64_t ExpressionEvaluator::ProcessGsuTokens(string token) +{ + if(token == "r0") { + return EvalValues::R0; + } else if(token == "r1") { + return EvalValues::R1; + } else if(token == "r2") { + return EvalValues::R2; + } else if(token == "r3") { + return EvalValues::R3; + } else if(token == "r4") { + return EvalValues::R4; + } else if(token == "r5") { + return EvalValues::R5; + } else if(token == "r6") { + return EvalValues::R6; + } else if(token == "r7") { + return EvalValues::R7; + } else if(token == "r8") { + return EvalValues::R8; + } else if(token == "r9") { + return EvalValues::R9; + } else if(token == "r10") { + return EvalValues::R10; + } else if(token == "r11") { + return EvalValues::R11; + } else if(token == "r12") { + return EvalValues::R12; + } else if(token == "r13") { + return EvalValues::R13; + } else if(token == "r14") { + return EvalValues::R14; + } else if(token == "r15") { + return EvalValues::R15; + } else if(token == "srcreg") { + return EvalValues::SrcReg; + } else if(token == "dstreg") { + return EvalValues::DstReg; + } else if(token == "sfr") { + return EvalValues::SFR; + } else if(token == "pbr") { + return EvalValues::PBR; + } else if(token == "rombr") { + return EvalValues::RomBR; + } else if(token == "rambr") { + return EvalValues::RamBR; + } + return -1; } string ExpressionEvaluator::GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success) @@ -406,6 +485,35 @@ int32_t ExpressionEvaluator::Evaluate(ExpressionData &data, DebugState &state, E } break; + case CpuType::Gsu: + switch(token) { + case EvalValues::R0: token = state.Gsu.R[0]; break; + case EvalValues::R1: token = state.Gsu.R[1]; break; + case EvalValues::R2: token = state.Gsu.R[2]; break; + case EvalValues::R3: token = state.Gsu.R[3]; break; + case EvalValues::R4: token = state.Gsu.R[4]; break; + case EvalValues::R5: token = state.Gsu.R[5]; break; + case EvalValues::R6: token = state.Gsu.R[6]; break; + case EvalValues::R7: token = state.Gsu.R[7]; break; + case EvalValues::R8: token = state.Gsu.R[8]; break; + case EvalValues::R9: token = state.Gsu.R[9]; break; + case EvalValues::R10: token = state.Gsu.R[10]; break; + case EvalValues::R11: token = state.Gsu.R[11]; break; + case EvalValues::R12: token = state.Gsu.R[12]; break; + case EvalValues::R13: token = state.Gsu.R[13]; break; + case EvalValues::R14: token = state.Gsu.R[14]; break; + case EvalValues::R15: token = state.Gsu.R[15]; break; + + case EvalValues::SrcReg: token = state.Gsu.SrcReg; break; + case EvalValues::DstReg: token = state.Gsu.DestReg; break; + + case EvalValues::SFR: token = (state.Gsu.SFR.GetFlagsHigh() << 8) | state.Gsu.SFR.GetFlagsLow(); break; + case EvalValues::PBR: token = state.Gsu.ProgramBank; break; + case EvalValues::RomBR: token = state.Gsu.ProgramBank; break; + case EvalValues::RamBR: token = state.Gsu.ProgramBank; break; + } + break; + case CpuType::NecDsp: throw std::runtime_error("Invalid CPU type"); } break; diff --git a/Core/ExpressionEvaluator.h b/Core/ExpressionEvaluator.h index d8098b3..a3bb85c 100644 --- a/Core/ExpressionEvaluator.h +++ b/Core/ExpressionEvaluator.h @@ -67,6 +67,29 @@ enum EvalValues : int64_t IsRead = 20000000116, PreviousOpPC = 20000000117, + R0 = 20000000120, + R1 = 20000000121, + R2 = 20000000122, + R3 = 20000000123, + R4 = 20000000124, + R5 = 20000000125, + R6 = 20000000126, + R7 = 20000000127, + R8 = 20000000128, + R9 = 20000000129, + R10 = 20000000130, + R11 = 20000000131, + R12 = 20000000132, + R13 = 20000000133, + R14 = 20000000134, + R15 = 20000000135, + SrcReg = 20000000137, + DstReg = 20000000138, + SFR = 20000000139, + PBR = 20000000140, + RomBR = 20000000141, + RamBR = 20000000142, + FirstLabelIndex = 20000002000, }; @@ -116,6 +139,9 @@ private: bool IsOperator(string token, int &precedence, bool unaryOperator); EvalOperators GetOperator(string token, bool unaryOperator); bool CheckSpecialTokens(string expression, size_t &pos, string &output, ExpressionData &data); + int64_t ProcessCpuSpcTokens(string token); + int64_t ProcessSharedTokens(string token); + int64_t ProcessGsuTokens(string token); string GetNextToken(string expression, size_t &pos, ExpressionData &data, bool &success); bool ProcessSpecialOperator(EvalOperators evalOp, std::stack &opStack, std::stack &precedenceStack, vector &outputQueue); bool ToRpn(string expression, ExpressionData &data); diff --git a/Core/Gsu.Instructions.cpp b/Core/Gsu.Instructions.cpp new file mode 100644 index 0000000..c9ac45b --- /dev/null +++ b/Core/Gsu.Instructions.cpp @@ -0,0 +1,734 @@ +#include "stdafx.h" +#include "Gsu.h" +#include "Cpu.h" +#include "MemoryManager.h" + +void Gsu::STOP() +{ + if(!_state.IrqDisabled) { + _state.SFR.Irq = true; + _cpu->SetIrqSource(IrqSource::Coprocessor); + } + _state.ProgramReadBuffer = 0x01; //Run a NOP first when the GSU is restarted + _state.SFR.Running = false; + ResetFlags(); + + UpdateRunningState(); +} + +void Gsu::NOP() +{ + ResetFlags(); +} + +void Gsu::CACHE() +{ + if(_state.CacheBase != (_state.R[15] & 0xFFF0)) { + _state.CacheBase = _state.R[15] & 0xFFF0; + InvalidateCache(); + } + ResetFlags(); +} + +void Gsu::Branch(bool branch) +{ + int8_t offset = (int8_t)ReadOperand(); + if(branch) { + WriteRegister(15, _state.R[15] + offset); + } +} + +void Gsu::BRA() +{ + Branch(true); +} + +void Gsu::BLT() +{ + Branch(_state.SFR.Sign == _state.SFR.Overflow); +} + +void Gsu::BGE() +{ + Branch(_state.SFR.Sign != _state.SFR.Overflow); +} + +void Gsu::BNE() +{ + Branch(!_state.SFR.Zero); +} + +void Gsu::BEQ() +{ + Branch(_state.SFR.Zero); +} + +void Gsu::BPL() +{ + Branch(!_state.SFR.Sign); +} + +void Gsu::BMI() +{ + Branch(_state.SFR.Sign); +} + +void Gsu::BCC() +{ + Branch(!_state.SFR.Carry); +} + +void Gsu::BCS() +{ + Branch(_state.SFR.Carry); +} + +void Gsu::BCV() +{ + Branch(!_state.SFR.Overflow); +} + +void Gsu::BVS() +{ + Branch(_state.SFR.Overflow); +} + +void Gsu::JMP(uint8_t reg) +{ + if(_state.SFR.Alt1) { + //LJMP + _state.ProgramBank = _state.R[reg] & 0x7F; + WriteRegister(15, ReadSrcReg()); + + _state.CacheBase = _state.R[15] & 0xFFF0; + InvalidateCache(); + } else { + //JMP + WriteRegister(15, _state.R[reg]); + } + ResetFlags(); +} + +void Gsu::TO(uint8_t reg) +{ + if(_state.SFR.Prefix) { + //MOVE + WriteRegister(reg, ReadSrcReg()); + ResetFlags(); + } else { + //TO + _state.DestReg = reg; + } +} + +void Gsu::FROM(uint8_t reg) +{ + if(_state.SFR.Prefix) { + //MOVES + WriteDestReg(_state.R[reg]); + _state.SFR.Overflow = (_state.R[reg] & 0x80) != 0; + _state.SFR.Sign = (_state.R[reg] & 0x8000) != 0; + _state.SFR.Zero = (_state.R[reg] == 0); + ResetFlags(); + } else { + //FROM + _state.SrcReg = reg; + } +} + +void Gsu::WITH(uint8_t reg) +{ + _state.SrcReg = reg; + _state.DestReg = reg; + _state.SFR.Prefix = true; +} + +void Gsu::STORE(uint8_t reg) +{ + _state.RamAddress = _state.R[reg]; + WriteRam(_state.RamAddress, (uint8_t)ReadSrcReg()); + if(!_state.SFR.Alt1) { + WriteRam(_state.RamAddress ^ 0x01, ReadSrcReg() >> 8); + } + ResetFlags(); +} + +void Gsu::LOAD(uint8_t reg) +{ + _state.RamAddress = _state.R[reg]; + uint16_t value = ReadRamBuffer(_state.RamAddress); + if(!_state.SFR.Alt1) { + value |= ReadRamBuffer(_state.RamAddress ^ 0x01) << 8; + } + WriteDestReg(value); + ResetFlags(); +} + +void Gsu::LOOP() +{ + _state.R[12]--; + _state.SFR.Zero = (_state.R[12] == 0); + _state.SFR.Sign = (_state.R[12] & 0x8000) != 0; + + //Loop until counter hits zero + if(!_state.SFR.Zero) { + WriteRegister(15, _state.R[13]); + } + + ResetFlags(); +} + +void Gsu::ALT1() +{ + _state.SFR.Prefix = false; + _state.SFR.Alt1 = true; +} + +void Gsu::ALT2() +{ + _state.SFR.Prefix = false; + _state.SFR.Alt2 = true; +} + +void Gsu::ALT3() +{ + _state.SFR.Prefix = false; + _state.SFR.Alt1 = true; + _state.SFR.Alt2 = true; +} + +void Gsu::MERGE() +{ + uint16_t value = (_state.R[7] & 0xFF00) | (_state.R[8] >> 8); + WriteDestReg(value); + _state.SFR.Carry = (value & 0xE0E0) != 0; + _state.SFR.Overflow = (value & 0xC0C0) != 0; + _state.SFR.Sign = (value & 0x8080) != 0; + _state.SFR.Zero = (value & 0xF0F0) != 0; + ResetFlags(); +} + +void Gsu::SWAP() +{ + uint16_t value = (ReadSrcReg() >> 8) | (ReadSrcReg() << 8); + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::Add(uint8_t reg) +{ + uint16_t operand; + if(_state.SFR.Alt2) { + //Immediate value + operand = reg; + } else { + operand = _state.R[reg]; + } + + uint32_t result = ReadSrcReg() + operand; + if(_state.SFR.Alt1) { + //ADC - Add with carry + result += (uint8_t)_state.SFR.Carry; + } + + _state.SFR.Carry = (result & 0x10000) != 0; + _state.SFR.Overflow = ~(ReadSrcReg() ^ operand) & (operand ^ result) & 0x8000; + _state.SFR.Sign = (result & 0x8000) != 0; + _state.SFR.Zero = (result & 0xFFFF) == 0; + + WriteDestReg(result); + ResetFlags(); +} + +void Gsu::SubCompare(uint8_t reg) +{ + uint16_t operand; + if(_state.SFR.Alt2 && !_state.SFR.Alt1) { + //Immediate value, SUB #val + operand = reg; + } else { + operand = _state.R[reg]; + } + + int32_t result = ReadSrcReg() - operand; + if(!_state.SFR.Alt2 && _state.SFR.Alt1) { + //SBC - SUB with carry + result -= _state.SFR.Carry ? 0 : 1; + } + + _state.SFR.Carry = (result >= 0); + _state.SFR.Overflow = ((ReadSrcReg() ^ operand) & (ReadSrcReg() ^ result) & 0x8000) != 0; + _state.SFR.Sign = (result & 0x8000) != 0; + _state.SFR.Zero = (result & 0xFFFF) == 0; + + if(!_state.SFR.Alt2 || !_state.SFR.Alt1) { + //SUB/SBC, other CMP (and no write occurs for CMP) + WriteDestReg(result); + } + ResetFlags(); +} + +void Gsu::MULT(uint8_t reg) +{ + uint16_t operand; + if(_state.SFR.Alt2) { + //Immediate value + operand = reg; + } else { + operand = _state.R[reg]; + } + + uint16_t value; + if(_state.SFR.Alt1) { + //UMULT - Unsigned multiply + value = (uint16_t)((uint8_t)ReadSrcReg() * (uint8_t)operand); + } else { + //MULT - Signed multiply + value = (uint16_t)((int8_t)ReadSrcReg() * (int8_t)operand); + } + + WriteDestReg(value); + _state.SFR.Sign = (value & 0x8000) != 0; + _state.SFR.Zero = value == 0; + + ResetFlags(); + + Step(_state.HighSpeedMode ? 1 : 2); +} + +void Gsu::FMultLMult() +{ + uint32_t multResult = (int16_t)ReadSrcReg() * (int16_t)_state.R[6]; + + if(_state.SFR.Alt1) { + //LMULT - "16x16 signed multiply", LSB in R4, MSB in DREG + _state.R[4] = multResult; + } + + uint16_t value = multResult >> 16; + WriteDestReg(value); + + _state.SFR.Carry = (multResult & 0x8000); + _state.SFR.Sign = (value & 0x8000); + _state.SFR.Zero = (value == 0); + ResetFlags(); + + Step((_state.HighSpeedMode ? 3 : 7) * (_state.ClockSelect ? 1 : 2)); +} + +void Gsu::AndBitClear(uint8_t reg) +{ + uint16_t operand; + if(_state.SFR.Alt2) { + //Immediate value + operand = reg; + } else { + operand = _state.R[reg]; + } + + uint16_t value; + if(_state.SFR.Alt1) { + //Bit clear + value = ReadSrcReg() & ~operand; + } else { + //AND + value = ReadSrcReg() & operand; + } + + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::SBK() +{ + //"Store word data, last RAM address used" + WriteRam(_state.RamAddress, (uint8_t)ReadSrcReg()); + WriteRam(_state.RamAddress ^ 1, ReadSrcReg() >> 8); + ResetFlags(); +} + +void Gsu::LINK(uint8_t value) +{ + //"Link Return Address" + _state.R[11] = _state.R[15] + value; + ResetFlags(); +} + +void Gsu::SignExtend() +{ + int16_t value = (int8_t)ReadSrcReg(); + WriteDestReg((uint16_t)value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::NOT() +{ + uint16_t value = ~ReadSrcReg(); + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::LSR() +{ + uint16_t src = ReadSrcReg(); + _state.SFR.Carry = (src & 0x01) != 0; + + uint16_t dst = src >> 1; + WriteDestReg(dst); + _state.SFR.Zero = dst == 0; + _state.SFR.Sign = (dst & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::ROL() +{ + uint16_t src = ReadSrcReg(); + + uint16_t dst = (src << 1) | (uint8_t)_state.SFR.Carry; + _state.SFR.Carry = (src & 0x8000) != 0; + + WriteDestReg(dst); + _state.SFR.Zero = dst == 0; + _state.SFR.Sign = (dst & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::ASR() +{ + uint16_t src = ReadSrcReg(); + _state.SFR.Carry = (src & 0x01) != 0; + + uint16_t dst = (int16_t)src >> 1; + if(_state.SFR.Alt1) { + dst += (src + 1) >> 16; + } + + WriteDestReg(dst); + _state.SFR.Zero = dst == 0; + _state.SFR.Sign = (dst & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::ROR() +{ + uint16_t src = ReadSrcReg(); + + uint16_t dst = (src >> 1) | ((int)_state.SFR.Carry << 15); + _state.SFR.Carry = (src & 0x01) != 0; + + WriteDestReg(dst); + _state.SFR.Zero = dst == 0; + _state.SFR.Sign = (dst & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::LOB() +{ + //"Value of low byte of register" + uint8_t value = (uint8_t)ReadSrcReg(); + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x80) != 0; + ResetFlags(); +} + +void Gsu::HIB() +{ + //"Value of high byte of register" + uint8_t value = (uint8_t)(ReadSrcReg() >> 8); + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x80) != 0; + ResetFlags(); +} + +void Gsu::IbtSmsLms(uint8_t reg) +{ + if(_state.SFR.Alt1) { + //LMS - "Load word data from RAM, short address" + _state.RamAddress = ReadOperand() << 1; + uint8_t lsb = ReadRamBuffer(_state.RamAddress); + uint8_t msb = ReadRamBuffer(_state.RamAddress | 0x01); + + WriteRegister(reg, (msb << 8) | lsb); + } else if(_state.SFR.Alt2) { + //SMS - "Store word data to RAM, short address" + _state.RamAddress = ReadOperand() << 1; + WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); + WriteRam(_state.RamAddress | 0x01, _state.R[reg] >> 8); + } else { + //IBT - "Load immediate byte data" + WriteRegister(reg, (int8_t)ReadOperand()); + } + ResetFlags(); +} + +void Gsu::IwtLmSm(uint8_t reg) +{ + if(_state.SFR.Alt1) { + //LM - Load memory + _state.RamAddress = ReadOperand(); + _state.RamAddress |= ReadOperand() << 8; + + uint8_t lsb = ReadRamBuffer(_state.RamAddress); + uint8_t msb = ReadRamBuffer(_state.RamAddress ^ 0x01); + WriteRegister(reg, (msb << 8) | lsb); + } else if(_state.SFR.Alt2) { + //SM - Store Memory + _state.RamAddress = ReadOperand(); + _state.RamAddress |= ReadOperand() << 8; + + WriteRam(_state.RamAddress, (uint8_t)_state.R[reg]); + WriteRam(_state.RamAddress ^ 0x01, _state.R[reg] >> 8); + } else { + //IWT - Load immediate word + uint8_t lsb = ReadOperand(); + uint8_t msb = ReadOperand(); + WriteRegister(reg, (msb << 8) | lsb); + } + ResetFlags(); +} + +void Gsu::OrXor(uint8_t operand) +{ + uint16_t operandValue; + if(_state.SFR.Alt2) { + //Immediate value + operandValue = operand; + } else { + //Indirect register value + operandValue = _state.R[operand]; + } + + uint16_t value; + if(_state.SFR.Alt1) { + //XOR + value = ReadSrcReg() ^ operandValue; + } else { + //OR + value = ReadSrcReg() | operandValue; + } + WriteDestReg(value); + _state.SFR.Zero = value == 0; + _state.SFR.Sign = (value & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::INC(uint8_t reg) +{ + WriteRegister(reg, _state.R[reg] + 1); + _state.SFR.Zero = _state.R[reg] == 0; + _state.SFR.Sign = (_state.R[reg] & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::DEC(uint8_t reg) +{ + WriteRegister(reg, _state.R[reg] - 1); + _state.SFR.Zero = _state.R[reg] == 0; + _state.SFR.Sign = (_state.R[reg] & 0x8000) != 0; + ResetFlags(); +} + +void Gsu::GetCRamBRomB() +{ + if(!_state.SFR.Alt2) { + //GETC - "Get byte from ROM to color register" + _state.ColorReg = GetColor(ReadRomBuffer()); + } else if(!_state.SFR.Alt1) { + //RAMB - "Set RAM data bank" + WaitRamOperation(); + _state.RamBank = ReadSrcReg() & 0x01; + } else { + //ROMB - "Set ROM data bank" + WaitRomOperation(); + _state.RomBank = ReadSrcReg() & 0x7F; + } + ResetFlags(); +} + +void Gsu::GETB() +{ + if(_state.SFR.Alt2 && _state.SFR.Alt1) { + //GETBS - "Get signed byte from ROM buffer" + WriteDestReg((int8_t)ReadRomBuffer()); + } else if(_state.SFR.Alt2) { + //GETBL - "Get low byte from ROM buffer" + WriteDestReg((ReadSrcReg() & 0xFF00) | ReadRomBuffer()); + } else if(_state.SFR.Alt1) { + //GETBH - "Get high byte from ROM buffer" + WriteDestReg((ReadSrcReg() & 0xFF) | (ReadRomBuffer() << 8)); + } else { + //GETB - "Get byte from ROM buffer" + WriteDestReg(ReadRomBuffer()); + } + ResetFlags(); +} + +void Gsu::PlotRpix() +{ + if(_state.SFR.Alt1) { + //RPIX - "Read pixel color" + uint8_t value = ReadPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); + _state.SFR.Zero = (value == 0); + _state.SFR.Sign = (value & 0x8000); + } else { + //PLOT + DrawPixel((uint8_t)_state.R[1], (uint8_t)_state.R[2]); + _state.R[1]++; + } + ResetFlags(); +} + +void Gsu::ColorCMode() +{ + if(_state.SFR.Alt1) { + //CMODE - "Set plot mode" + uint8_t value = (uint8_t)ReadSrcReg(); + _state.PlotTransparent = (value & 0x01) != 0; + _state.PlotDither = (value & 0x02) != 0; + _state.ColorHighNibble = (value & 0x04) != 0; + _state.ColorFreezeHigh = (value & 0x08) != 0; + _state.ObjMode = (value & 0x10) != 0; + } else { + //COLOR - "Set plot color" + _state.ColorReg = GetColor((uint8_t)ReadSrcReg()); + } + ResetFlags(); +} + +uint16_t Gsu::GetTileIndex(uint8_t x, uint8_t y) +{ + switch(_state.ObjMode ? 3 : _state.ScreenHeight) { + default: + case 0: return ((x & 0xF8) << 1) + ((y & 0xF8) >> 3); break; + case 1: return ((x & 0xF8) << 1) + ((x & 0xF8) >> 1) + ((y & 0xF8) >> 3); break; + case 2: return ((x & 0xF8) << 1) + ((x & 0xF8) << 0) + ((y & 0xF8) >> 3); break; + case 3: return ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break; + } +} + +uint32_t Gsu::GetTileAddress(uint8_t x, uint8_t y) +{ + uint16_t tileIndex = GetTileIndex(x, y); + return (0x700000 | (_state.ScreenBase << 10)) + (tileIndex * (_state.PlotBpp << 3)) + ((y & 0x07) * 2); +} + +uint8_t Gsu::ReadPixel(uint8_t x, uint8_t y) +{ + WritePixelCache(_state.SecondaryCache); + WritePixelCache(_state.PrimaryCache); + + uint32_t tileAddress = GetTileAddress(x, y); + + x = (x & 7) ^ 7; + + uint8_t data = 0; + for(int i = 0; i < _state.PlotBpp; i++) { + //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) + uint8_t byteOffset = ((i >> 1) << 4) + (i & 0x01); + data |= ((ReadGsu(tileAddress + byteOffset, MemoryOperationType::Read) >> x) & 1) << i; + Step(_state.ClockSelect ? 5 : 6); + } + + return data; +} + +bool Gsu::IsTransparentPixel() +{ + uint8_t color = _state.ColorFreezeHigh ? (_state.ColorReg & 0x0F) : _state.ColorReg; + + switch(_state.PlotBpp) { + default: + case 2: return (color & 0x03) == 0; + case 4: return (color & 0x0F) == 0; + case 8: return color == 0; + } +} + +void Gsu::DrawPixel(uint8_t x, uint8_t y) +{ + if(!_state.PlotTransparent && IsTransparentPixel()) { + return; + } + + uint8_t color = _state.ColorReg; + if(_state.PlotDither && _state.PlotBpp != 8) { + if((x ^ y) & 0x01) { + color >>= 4; + } + color &= 0x0F; + } + + if(_state.PrimaryCache.X != (x & 0xF8) || _state.PrimaryCache.Y != y) { + FlushPrimaryCache(x, y); + } + + uint8_t xOffset = (x & 7) ^ 7; + _state.PrimaryCache.Pixels[xOffset] = color; + _state.PrimaryCache.ValidBits |= (1 << xOffset); + if(_state.PrimaryCache.ValidBits == 0xFF) { + FlushPrimaryCache(x, y); + } +} + +void Gsu::FlushPrimaryCache(uint8_t x, uint8_t y) +{ + WritePixelCache(_state.SecondaryCache); + _state.SecondaryCache = _state.PrimaryCache; + _state.PrimaryCache.ValidBits = 0; + _state.PrimaryCache.X = x & 0xF8; + _state.PrimaryCache.Y = y; +} + +void Gsu::WritePixelCache(GsuPixelCache &cache) +{ + if(cache.ValidBits == 0) { + return; + } + + uint32_t tileAddress = GetTileAddress(cache.X, cache.Y); + + for(int i = 0; i < _state.PlotBpp; i++) { + uint8_t value = 0; + for(int x = 0; x < 8; x++) { + value |= ((cache.Pixels[x] >> i) & 0x01) << x; + } + + //Select which byte to read/write based on the current bit (0/1, 16/17, 32/33, 48/49) + uint8_t byte = ((i >> 1) << 4) + (i & 0x01); + + if(cache.ValidBits != 0xFF) { + //Read the pixels in memory before to merge them before writing the cache's content to memory + Step(_state.ClockSelect ? 5 : 6); + value &= cache.ValidBits; + value |= ReadGsu(tileAddress + byte, MemoryOperationType::Read) & ~cache.ValidBits; + } + + Step(_state.ClockSelect ? 5 : 6); + WaitForRamAccess(); + WriteGsu(tileAddress + byte, value, MemoryOperationType::Write); + } + + cache.ValidBits = 0; +} + +uint8_t Gsu::GetColor(uint8_t value) +{ + if(_state.ColorHighNibble) { + return (_state.ColorReg & 0xF0) | (value >> 4); + } + if(_state.ColorFreezeHigh) { + return (_state.ColorReg & 0xF0) | (value & 0x0F); + } + + return value; +} \ No newline at end of file diff --git a/Core/Gsu.cpp b/Core/Gsu.cpp new file mode 100644 index 0000000..44de09a --- /dev/null +++ b/Core/Gsu.cpp @@ -0,0 +1,649 @@ +#include "stdafx.h" +#include "Gsu.h" +#include "Console.h" +#include "Cpu.h" +#include "MemoryManager.h" +#include "BaseCartridge.h" +#include "RamHandler.h" +#include "GsuRomHandler.h" +#include "GsuRamHandler.h" +#include "EmuSettings.h" +#include "MessageManager.h" +#include "../Utilities/HexUtilities.h" + +Gsu::Gsu(Console *console, uint32_t gsuRamSize) +{ + _console = console; + _memoryManager = console->GetMemoryManager().get(); + _cpu = console->GetCpu().get(); + _memoryType = SnesMemoryType::Register; + _settings = _console->GetSettings().get(); + + _clockMultiplier = _settings->GetEmulationConfig().GsuClockSpeed / 100; + + _state = {}; + _state.ProgramReadBuffer = 0x01; //Run a NOP on first cycle + + _settings->InitializeRam(_cache, 512); + + _gsuRamSize = gsuRamSize; + _gsuRam = new uint8_t[_gsuRamSize]; + _settings->InitializeRam(_gsuRam, _gsuRamSize); + + for(uint32_t i = 0; i < _gsuRamSize / 0x1000; i++) { + _gsuRamHandlers.push_back(unique_ptr(new RamHandler(_gsuRam, i * 0x1000, _gsuRamSize, SnesMemoryType::GsuWorkRam))); + _gsuCpuRamHandlers.push_back(unique_ptr(new GsuRamHandler(_state, _gsuRamHandlers.back().get()))); + } + + //CPU mappings + MemoryMappings *cpuMappings = _memoryManager->GetMemoryMappings(); + vector> &prgRomHandlers = _console->GetCartridge()->GetPrgRomHandlers(); + for(unique_ptr &handler : prgRomHandlers) { + _gsuCpuRomHandlers.push_back(unique_ptr(new GsuRomHandler(_state, handler.get()))); + } + + //GSU registers in CPU memory space + cpuMappings->RegisterHandler(0x00, 0x3F, 0x3000, 0x3FFF, this); + cpuMappings->RegisterHandler(0x80, 0xBF, 0x3000, 0x3FFF, this); + + for(int i = 0; i < 0x3F; i++) { + cpuMappings->RegisterHandler(i, i, 0x6000, 0x7FFF, _gsuCpuRamHandlers); + cpuMappings->RegisterHandler(i + 0x80, i + 0x80, 0x6000, 0x7FFF, _gsuCpuRamHandlers); + } + cpuMappings->RegisterHandler(0x70, 0x71, 0x0000, 0xFFFF, _gsuCpuRamHandlers); + cpuMappings->RegisterHandler(0xF0, 0xF1, 0x0000, 0xFFFF, _gsuCpuRamHandlers); + + cpuMappings->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, _gsuCpuRomHandlers); + cpuMappings->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, _gsuCpuRomHandlers); + + cpuMappings->RegisterHandler(0x40, 0x5F, 0x0000, 0xFFFF, _gsuCpuRomHandlers); + cpuMappings->RegisterHandler(0xC0, 0xDF, 0x0000, 0xFFFF, _gsuCpuRomHandlers); + + //GSU mappings + _mappings.RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgRomHandlers); + _mappings.RegisterHandler(0x00, 0x3F, 0x0000, 0x7FFF, prgRomHandlers); //Mirror + + _mappings.RegisterHandler(0x40, 0x5F, 0x0000, 0xFFFF, prgRomHandlers); + _mappings.RegisterHandler(0x70, 0x71, 0x0000, 0xFFFF, _gsuRamHandlers); +} + +void Gsu::ProcessEndOfFrame() +{ + uint8_t clockMultiplier = _settings->GetEmulationConfig().GsuClockSpeed / 100; + if(_clockMultiplier != clockMultiplier) { + _state.CycleCount = _state.CycleCount / _clockMultiplier * clockMultiplier; + _clockMultiplier = clockMultiplier; + } +} + +void Gsu::Run() +{ + uint64_t targetCycle = _memoryManager->GetMasterClock() * _clockMultiplier; + + while(!_stopped && _state.CycleCount < targetCycle) { + Exec(); + } + + if(targetCycle > _state.CycleCount) { + Step(targetCycle - _state.CycleCount); + } +} + +void Gsu::Exec() +{ + uint8_t opCode = ReadOpCode(); + + switch(opCode) { + case 0x00: STOP(); break; + case 0x01: NOP(); break; + case 0x02: CACHE(); break; + case 0x03: LSR(); break; + case 0x04: ROL(); break; + case 0x05: BRA(); break; + case 0x06: BLT(); break; + case 0x07: BGE(); break; + case 0x08: BNE(); break; + case 0x09: BEQ(); break; + case 0x0A: BPL(); break; + case 0x0B: BMI(); break; + case 0x0C: BCC(); break; + case 0x0D: BCS(); break; + case 0x0E: BCV(); break; + case 0x0F: BVS(); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: + TO(opCode & 0x0F); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: + WITH(opCode & 0x0F); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3A: case 0x3B: + STORE(opCode & 0x0F); + break; + + case 0x3C: LOOP(); break; + case 0x3D: ALT1(); break; + case 0x3E: ALT2(); break; + case 0x3F: ALT3(); break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + LOAD(opCode & 0x0F); + break; + + case 0x4C: PlotRpix(); break; + case 0x4D: SWAP(); break; + case 0x4E: ColorCMode(); break; + case 0x4F: NOT(); break; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: + Add(opCode & 0x0F); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: + SubCompare(opCode & 0x0F); + break; + + case 0x70: MERGE(); break; + + case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: + AndBitClear(opCode & 0x0F); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: + MULT(opCode & 0x0F); + break; + + case 0x90: SBK(); break; + + case 0x91: LINK(1); break; + case 0x92: LINK(2); break; + case 0x93: LINK(3); break; + case 0x94: LINK(4); break; + + case 0x95: SignExtend(); break; + + case 0x96: ASR(); break; + case 0x97: ROR(); break; + + case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: + JMP(opCode & 0x0F); + break; + + case 0x9E: LOB(); break; + case 0x9F: FMultLMult(); break; + + case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: + case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: + IbtSmsLms(opCode & 0x0F); + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: + case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: + FROM(opCode & 0x0F); + break; + + case 0xC0: HIB(); break; + + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: + OrXor(opCode & 0x0F); + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: + case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: + INC(opCode & 0x0F); + break; + + case 0xDF: GetCRamBRomB(); break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: + DEC(opCode & 0x0F); + break; + + case 0xEF: GETB(); break; + + case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: + case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: + IwtLmSm(opCode & 0x0F); + break; + } + + _console->ProcessMemoryRead(_lastOpAddr, _state.ProgramReadBuffer, MemoryOperationType::ExecOpCode); + + if(!_r15Changed) { + _state.R[15]++; + } else { + _r15Changed = false; + } +} + +uint8_t Gsu::ReadGsu(uint32_t addr, MemoryOperationType opType) +{ + IMemoryHandler *handler = _mappings.GetHandler(addr); + uint8_t value; + if(handler) { + value = handler->Read(addr); + } else { + //TODO: Open bus? + value = 0; + LogDebug("[Debug] GSU - Missing read handler: " + HexUtilities::ToHex(addr)); + } + _console->ProcessMemoryRead(addr, value, opType); + + return value; +} + +void Gsu::WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType) +{ + IMemoryHandler *handler = _mappings.GetHandler(addr); + if(handler) { + handler->Write(addr, value); + } else { + LogDebug("[Debug] GSU - Missing write handler: " + HexUtilities::ToHex(addr)); + } + _console->ProcessMemoryWrite(addr, value, opType); +} + +void Gsu::InitProgramCache(uint16_t cacheAddr) +{ + uint16_t dest = (cacheAddr & 0x01F0); + + if(_state.ProgramBank <= 0x5F) { + WaitRomOperation(); + WaitForRomAccess(); + } else { + WaitRamOperation(); + WaitForRamAccess(); + } + + uint32_t srcBaseAddr = (_state.ProgramBank << 16) + _state.CacheBase + dest; + for(int i = 0; i < 16; i++) { + _cache[dest + i] = ReadGsu(srcBaseAddr + i, MemoryOperationType::Read); + } + Step(_state.ClockSelect ? 5*16 : 6*16); + + _cacheValid[cacheAddr >> 4] = true; +} + +uint8_t Gsu::ReadOperand() +{ + uint8_t result = _state.ProgramReadBuffer; + _state.R[15]++; + _state.ProgramReadBuffer = ReadProgramByte(MemoryOperationType::Read); + return result; +} + +uint8_t Gsu::ReadOpCode() +{ + uint8_t result = _state.ProgramReadBuffer; + _state.ProgramReadBuffer = ReadProgramByte(MemoryOperationType::Read); + return result; +} + +uint8_t Gsu::ReadProgramByte(MemoryOperationType opType) +{ + _lastOpAddr = (_state.ProgramBank << 16) | _state.R[15]; + uint16_t cacheAddr = _state.R[15] - _state.CacheBase; + if(cacheAddr < 512) { + if(!_cacheValid[cacheAddr >> 4]) { + InitProgramCache(cacheAddr & 0xFFF0); + } + + Step(_state.ClockSelect ? 1 : 2); + _console->ProcessMemoryRead(_lastOpAddr, _cache[cacheAddr], opType); + return _cache[cacheAddr]; + } else { + if(_state.ProgramBank <= 0x5F) { + WaitRomOperation(); + WaitForRomAccess(); + } else { + WaitRamOperation(); + WaitForRamAccess(); + } + Step(_state.ClockSelect ? 5 : 6); + return ReadGsu(_lastOpAddr, opType); + } +} + +uint16_t Gsu::ReadSrcReg() +{ + return _state.R[_state.SrcReg]; +} + +void Gsu::WriteDestReg(uint16_t value) +{ + WriteRegister(_state.DestReg, value); +} + +void Gsu::WriteRegister(uint8_t reg, uint16_t value) +{ + _state.R[reg] = value; + + if(reg == 14) { + _state.SFR.RomReadPending = true; + _state.RomDelay = _state.ClockSelect ? 5 : 6; + } else if(reg == 15) { + _r15Changed = true; + } +} + +void Gsu::ResetFlags() +{ + _state.SFR.Prefix = 0; + _state.SFR.Alt1 = false; + _state.SFR.Alt2 = false; + + _state.SrcReg = 0; + _state.DestReg = 0; +} + +void Gsu::InvalidateCache() +{ + memset(_cacheValid, 0, sizeof(_cacheValid)); +} + +void Gsu::WaitRomOperation() +{ + if(_state.RomDelay) { + //Wait for existing RAM operation to complete + Step(_state.RomDelay); + } +} + +void Gsu::WaitRamOperation() +{ + if(_state.RamDelay) { + //Wait for existing RAM operation to complete + Step(_state.RamDelay); + } +} + +void Gsu::WaitForRomAccess() +{ + if(!_state.GsuRomAccess) { + _waitForRomAccess = true; + _stopped = true; + } +} + +void Gsu::WaitForRamAccess() +{ + if(!_state.GsuRamAccess) { + _waitForRamAccess = true; + _stopped = true; + } +} + +void Gsu::UpdateRunningState() +{ + _stopped = !_state.SFR.Running || _waitForRamAccess || _waitForRomAccess; +} + +uint8_t Gsu::ReadRomBuffer() +{ + WaitRomOperation(); + return _state.RomReadBuffer; +} + +uint8_t Gsu::ReadRamBuffer(uint16_t addr) +{ + WaitRamOperation(); + WaitForRamAccess(); + return ReadGsu(0x700000 | (_state.RamBank << 16) | addr, MemoryOperationType::Read); +} + +void Gsu::WriteRam(uint16_t addr, uint8_t value) +{ + WaitRamOperation(); + + _state.RamDelay = _state.ClockSelect ? 5 : 6; + _state.RamWriteAddress = addr; + _state.RamWriteValue = value; +} + +void Gsu::Step(uint64_t cycles) +{ + _state.CycleCount += cycles; + + if(_state.RomDelay) { + _state.RomDelay -= std::min((uint8_t)cycles, _state.RomDelay); + if(_state.RomDelay == 0) { + WaitForRomAccess(); + _state.RomReadBuffer = ReadGsu((_state.RomBank << 16) | _state.R[14], MemoryOperationType::Read); + _state.SFR.RomReadPending = false; + } + } + + if(_state.RamDelay) { + _state.RamDelay -= std::min((uint8_t)cycles, _state.RamDelay); + if(_state.RamDelay == 0) { + WaitForRamAccess(); + WriteGsu(0x700000 | (_state.RamBank << 16) | _state.RamWriteAddress, _state.RamWriteValue, MemoryOperationType::Write); + } + } +} + +void Gsu::Reset() +{ + _state = {}; + _state.ProgramReadBuffer = 0x01; //Run a NOP on first cycle + + _console->GetSettings()->InitializeRam(_cache, 512); + memset(_cacheValid, 0, sizeof(_cacheValid)); + _waitForRomAccess = false; + _waitForRamAccess = false; + _stopped = true; + _lastOpAddr = 0; +} + +uint8_t Gsu::Read(uint32_t addr) +{ + addr &= 0x33FF; + if(_state.SFR.Running && addr != 0x3030 && addr != 0x3031 && addr != 0x303B) { + //"During GSU operation, only SFR, SCMR, and VCR may be accessed." + return 0; + } + + switch(addr) { + case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C:case 0x300E: + case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C:case 0x301E: + return (uint8_t)_state.R[(addr >> 1) & 0x0F]; + + case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D:case 0x300F: + case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D:case 0x301F: + return _state.R[(addr >> 1) & 0x0F] >> 8; + + case 0x3030: return _state.SFR.GetFlagsLow(); + case 0x3031: { + uint8_t flags = _state.SFR.GetFlagsHigh(); + _state.SFR.Irq = false; + _cpu->ClearIrqSource(IrqSource::Coprocessor); + return flags; + } + + case 0x3034: return _state.ProgramBank; + case 0x3036: return _state.RomBank; + case 0x303B: return 0x04; //Version (can be 1 or 4?) + case 0x303C: return _state.RamBank; + case 0x303E: return (uint8_t)_state.CacheBase; + case 0x303F: return _state.CacheBase >> 8; + } + + if(addr >= 0x3100 && addr <= 0x32FF) { + return _cache[(_state.CacheBase + (addr - 0x3100)) & 0x1FF]; + } + + LogDebug("[Debug] Missing read handler: $" + HexUtilities::ToHex(addr)); + + //TODO open bus and proper mirroring? + return 0; +} + +void Gsu::Write(uint32_t addr, uint8_t value) +{ + addr &= 0x33FF; + if(_state.SFR.Running && addr != 0x3030 && addr != 0x303A) { + //"During GSU operation, only SFR, SCMR, and VCR may be accessed." + return; + } + + switch(addr) { + case 0x3000: case 0x3002: case 0x3004: case 0x3006: case 0x3008: case 0x300A: case 0x300C: case 0x300E: + case 0x3010: case 0x3012: case 0x3014: case 0x3016: case 0x3018: case 0x301A: case 0x301C: case 0x301E: + _state.RegisterLatch = value; + break; + + case 0x3001: case 0x3003: case 0x3005: case 0x3007: case 0x3009: case 0x300B: case 0x300D: case 0x300F: + case 0x3011: case 0x3013: case 0x3015: case 0x3017: case 0x3019: case 0x301B: case 0x301D: case 0x301F: { + uint8_t reg = (addr >> 1) & 0x0F; + _state.R[reg] = (value << 8) | _state.RegisterLatch; + + if(reg == 14) { + _state.SFR.RomReadPending = true; + _state.RomDelay = _state.ClockSelect ? 5 : 6; + } else if(addr == 0x301F) { + _state.SFR.Running = true; + UpdateRunningState(); + } + break; + } + + case 0x3030: { + bool running = _state.SFR.Running; + _state.SFR.Zero = (value & 0x02) != 0; + _state.SFR.Carry = (value & 0x04) != 0; + _state.SFR.Sign = (value & 0x08) != 0; + _state.SFR.Overflow = (value & 0x10) != 0; + _state.SFR.Running = (value & 0x20) != 0; + + if(running && !_state.SFR.Running) { + _state.CacheBase = 0; + InvalidateCache(); + } + UpdateRunningState(); + break; + } + + case 0x3033: _state.BackupRamEnabled = (value & 0x01); break; + case 0x3034: _state.ProgramBank = (value & 0x7F); InvalidateCache(); break; + + case 0x3037: + _state.HighSpeedMode = (value & 0x20) != 0; + _state.IrqDisabled = (value & 0x80) != 0; + break; + + case 0x3038: _state.ScreenBase = value; break; + case 0x3039: _state.ClockSelect = (value & 0x01); break; + + case 0x303A: + _state.ColorGradient = (value & 0x03); + switch(_state.ColorGradient) { + case 0: _state.PlotBpp = 2; break; + case 1: _state.PlotBpp = 4; break; + case 2: _state.PlotBpp = 4; break; + case 3: _state.PlotBpp = 8; break; + } + _state.ScreenHeight = ((value & 0x04) >> 2) | ((value & 0x20) >> 4); + _state.GsuRamAccess = (value & 0x08) != 0; + _state.GsuRomAccess = (value & 0x10) != 0; + + if(_state.GsuRamAccess) { + _waitForRamAccess = false; + } + if(_state.GsuRomAccess) { + _waitForRomAccess = false; + } + UpdateRunningState(); + break; + } + + if(addr >= 0x3100 && addr <= 0x32FF) { + uint16_t cacheAddr = (_state.CacheBase + (addr - 0x3100)) & 0x1FF; + _cache[cacheAddr] = value; + if((cacheAddr & 0x0F) == 0x0F) { + _cacheValid[cacheAddr >> 4] = true; + } + } +} + +uint8_t Gsu::Peek(uint32_t addr) +{ + return 0; +} + +void Gsu::PeekBlock(uint8_t *output) +{ + memset(output, 0, 0x1000); +} + +AddressInfo Gsu::GetAbsoluteAddress(uint32_t address) +{ + return { -1, SnesMemoryType::Register }; +} + +void Gsu::Serialize(Serializer &s) +{ + s.Stream( + _state.CycleCount, _state.RegisterLatch, _state.ProgramBank, _state.RomBank, _state.RamBank, _state.IrqDisabled, + _state.HighSpeedMode, _state.ClockSelect, _state.BackupRamEnabled, _state.ScreenBase, _state.ColorGradient, _state.PlotBpp, + _state.ScreenHeight, _state.GsuRamAccess, _state.GsuRomAccess, _state.CacheBase, _state.PlotTransparent, _state.PlotDither, + _state.ColorHighNibble, _state.ColorFreezeHigh, _state.ObjMode, _state.ColorReg, _state.SrcReg, _state.DestReg, + _state.RomReadBuffer, _state.RomDelay, _state.ProgramReadBuffer, _state.RamWriteAddress, _state.RamWriteValue, _state.RamDelay, + _state.RamAddress, _state.PrimaryCache.X, _state.PrimaryCache.Y, _state.PrimaryCache.ValidBits, _state.SecondaryCache.X, + _state.SecondaryCache.Y, _state.SecondaryCache.ValidBits, + _state.SFR.Alt1, _state.SFR.Alt2, _state.SFR.Carry, _state.SFR.ImmHigh, _state.SFR.ImmLow, _state.SFR.Irq, _state.SFR.Overflow, + _state.SFR.Prefix, _state.SFR.RomReadPending, _state.SFR.Running, _state.SFR.Sign, _state.SFR.Zero + ); + + s.StreamArray(_state.R, 16); + s.StreamArray(_state.PrimaryCache.Pixels, 8); + s.StreamArray(_state.SecondaryCache.Pixels, 8); + + s.Stream(_waitForRamAccess, _waitForRomAccess, _stopped); + s.StreamArray(_cacheValid, 32); + s.StreamArray(_cache, 512); + s.StreamArray(_gsuRam, _gsuRamSize); +} + +void Gsu::LoadBattery(string filePath) +{ + VirtualFile saveFile(filePath); + saveFile.ReadFile((uint8_t*)_gsuRam, _gsuRamSize); +} + +void Gsu::SaveBattery(string filePath) +{ + ofstream saveFile(filePath, ios::binary); + saveFile.write((char*)_gsuRam, _gsuRamSize); +} + +GsuState Gsu::GetState() +{ + return _state; +} + +MemoryMappings* Gsu::GetMemoryMappings() +{ + return &_mappings; +} + +uint8_t* Gsu::DebugGetWorkRam() +{ + return _gsuRam; +} + +uint32_t Gsu::DebugGetWorkRamSize() +{ + return _gsuRamSize; +} diff --git a/Core/Gsu.h b/Core/Gsu.h new file mode 100644 index 0000000..97a0787 --- /dev/null +++ b/Core/Gsu.h @@ -0,0 +1,172 @@ +#pragma once +#include "stdafx.h" +#include "BaseCoprocessor.h" +#include "GsuTypes.h" +#include "MemoryMappings.h" +#include "IMemoryHandler.h" + +class Console; +class Cpu; +class MemoryManager; +class EmuSettings; + +class Gsu : public BaseCoprocessor +{ +private: + Console *_console; + MemoryManager *_memoryManager; + Cpu *_cpu; + EmuSettings *_settings; + uint8_t _clockMultiplier; + + GsuState _state; + + uint8_t _cache[512]; + bool _cacheValid[32] = {}; + bool _waitForRomAccess = false; + bool _waitForRamAccess = false; + bool _stopped = true; + bool _r15Changed = false; + uint32_t _lastOpAddr = 0; + + uint32_t _gsuRamSize = 0; + uint8_t* _gsuRam = nullptr; + + MemoryMappings _mappings; + vector> _gsuRamHandlers; + vector> _gsuCpuRamHandlers; + vector> _gsuCpuRomHandlers; + + void Exec(); + + void InitProgramCache(uint16_t cacheAddr); + + uint8_t ReadOperand(); + uint8_t ReadOpCode(); + uint8_t ReadProgramByte(MemoryOperationType opType); + + uint16_t ReadSrcReg(); + void WriteDestReg(uint16_t value); + void WriteRegister(uint8_t reg, uint16_t value); + + void ResetFlags(); + void InvalidateCache(); + + void WaitRomOperation(); + void WaitRamOperation(); + + void WaitForRomAccess(); + void WaitForRamAccess(); + void UpdateRunningState(); + + uint8_t ReadRomBuffer(); + uint8_t ReadRamBuffer(uint16_t addr); + void WriteRam(uint16_t addr, uint8_t value); + void Step(uint64_t cycles); + + void STOP(); + void NOP(); + void CACHE(); + + void Branch(bool branch); + + void BRA(); + void BLT(); + void BGE(); + void BNE(); + void BEQ(); + void BPL(); + void BMI(); + void BCC(); + void BCS(); + void BCV(); + void BVS(); + void JMP(uint8_t reg); + + void TO(uint8_t reg); + void FROM(uint8_t reg); + void WITH(uint8_t reg); + + void STORE(uint8_t reg); + void LOAD(uint8_t reg); + + void LOOP(); + void ALT1(); + void ALT2(); + void ALT3(); + + void MERGE(); + void SWAP(); + + void PlotRpix(); + void ColorCMode(); + + uint16_t GetTileIndex(uint8_t x, uint8_t y); + uint32_t GetTileAddress(uint8_t x, uint8_t y); + + uint8_t ReadPixel(uint8_t x, uint8_t y); + bool IsTransparentPixel(); + void DrawPixel(uint8_t x, uint8_t y); + void FlushPrimaryCache(uint8_t x, uint8_t y); + void WritePixelCache(GsuPixelCache &cache); + + uint8_t GetColor(uint8_t source); + + void Add(uint8_t reg); + void SubCompare(uint8_t reg); + void MULT(uint8_t reg); + void FMultLMult(); + + void AndBitClear(uint8_t reg); + void SBK(); + + void LINK(uint8_t reg); + + void SignExtend(); + + void NOT(); + void LSR(); + void ROL(); + void ASR(); + void ROR(); + + void LOB(); + void HIB(); + + void IbtSmsLms(uint8_t reg); + void IwtLmSm(uint8_t reg); + + void OrXor(uint8_t reg); + void INC(uint8_t reg); + void DEC(uint8_t reg); + + void GetCRamBRomB(); + void GETB(); + +public: + Gsu(Console *console, uint32_t gsuRamSize); + + void ProcessEndOfFrame() override; + + uint8_t ReadGsu(uint32_t addr, MemoryOperationType opType); + void WriteGsu(uint32_t addr, uint8_t value, MemoryOperationType opType); + + void LoadBattery(string filePath) override; + void SaveBattery(string filePath) override; + + void Run(); + void Reset() override; + + uint8_t Read(uint32_t addr) override; + uint8_t Peek(uint32_t addr) override; + void PeekBlock(uint8_t *output) override; + void Write(uint32_t addr, uint8_t value) override; + AddressInfo GetAbsoluteAddress(uint32_t address) override; + + void Serialize(Serializer &s) override; + + GsuState GetState(); + MemoryMappings* GetMemoryMappings(); + uint8_t* DebugGetWorkRam(); + uint32_t DebugGetWorkRamSize(); +}; \ No newline at end of file diff --git a/Core/GsuDebugger.cpp b/Core/GsuDebugger.cpp new file mode 100644 index 0000000..2778c9a --- /dev/null +++ b/Core/GsuDebugger.cpp @@ -0,0 +1,95 @@ +#include "stdafx.h" +#include "GsuDebugger.h" +#include "DisassemblyInfo.h" +#include "Disassembler.h" +#include "BaseCartridge.h" +#include "Gsu.h" +#include "TraceLogger.h" +#include "CallstackManager.h" +#include "MemoryManager.h" +#include "Debugger.h" +#include "Console.h" +#include "MemoryAccessCounter.h" + +GsuDebugger::GsuDebugger(Debugger* debugger) +{ + _debugger = debugger; + _traceLogger = debugger->GetTraceLogger().get(); + _disassembler = debugger->GetDisassembler().get(); + _memoryAccessCounter = debugger->GetMemoryAccessCounter().get(); + _gsu = debugger->GetConsole()->GetCartridge()->GetGsu(); + _memoryManager = debugger->GetConsole()->GetMemoryManager().get(); + + _step.reset(new StepRequest()); +} + +void GsuDebugger::Reset() +{ + _prevOpCode = 0xFF; +} + +void GsuDebugger::ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type) +{ + if(type == MemoryOperationType::DummyRead) { + //Ignore all dummy reads for now + return; + } + + AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); + MemoryOperationInfo operation { addr, value, type }; + + if(type == MemoryOperationType::ExecOpCode) { + DebugState debugState; + _debugger->GetState(debugState, true); + + _disassembler->BuildCache(addressInfo, debugState.Gsu.SFR.GetFlagsHigh() & 0x13, CpuType::Gsu); + debugState.Gsu.R[15] = addr; + + DisassemblyInfo disInfo = _disassembler->GetDisassemblyInfo(addressInfo); + _traceLogger->Log(CpuType::Gsu, debugState, disInfo); + + _prevOpCode = value; + _prevProgramCounter = addr; + + if(_step->StepCount > 0) { + _step->StepCount--; + } + } + + _debugger->ProcessBreakConditions(_step->StepCount == 0, CpuType::Gsu, operation, addressInfo); + + _memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock()); +} + +void GsuDebugger::ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type) +{ + AddressInfo addressInfo = _gsu->GetMemoryMappings()->GetAbsoluteAddress(addr); + MemoryOperationInfo operation { addr, value, type }; + _debugger->ProcessBreakConditions(false, CpuType::Gsu, operation, addressInfo); + + _disassembler->InvalidateCache(addressInfo, CpuType::Gsu); + + _memoryAccessCounter->ProcessMemoryAccess(addressInfo, type, _memoryManager->GetMasterClock()); +} + +void GsuDebugger::Run() +{ + _step.reset(new StepRequest()); +} + +void GsuDebugger::Step(int32_t stepCount, StepType type) +{ + StepRequest step; + + switch(type) { + case StepType::StepOut: + case StepType::StepOver: + case StepType::Step: step.StepCount = stepCount; break; + + case StepType::SpecificScanline: + case StepType::PpuStep: + break; + } + + _step.reset(new StepRequest(step)); +} diff --git a/Core/GsuDebugger.h b/Core/GsuDebugger.h new file mode 100644 index 0000000..f77e101 --- /dev/null +++ b/Core/GsuDebugger.h @@ -0,0 +1,35 @@ +#pragma once +#include "stdafx.h" +#include "DebugTypes.h" + +class Disassembler; +class Debugger; +class TraceLogger; +class Gsu; +class MemoryAccessCounter; +class MemoryManager; + +class GsuDebugger +{ + Debugger* _debugger; + Disassembler* _disassembler; + TraceLogger* _traceLogger; + MemoryAccessCounter* _memoryAccessCounter; + MemoryManager* _memoryManager; + Gsu* _gsu; + + unique_ptr _step; + + uint8_t _prevOpCode = 0xFF; + uint32_t _prevProgramCounter = 0; + +public: + GsuDebugger(Debugger* debugger); + + void Reset(); + + void ProcessRead(uint32_t addr, uint8_t value, MemoryOperationType type); + void ProcessWrite(uint32_t addr, uint8_t value, MemoryOperationType type); + void Run(); + void Step(int32_t stepCount, StepType type); +}; \ No newline at end of file diff --git a/Core/GsuDisUtils.cpp b/Core/GsuDisUtils.cpp new file mode 100644 index 0000000..2e470fe --- /dev/null +++ b/Core/GsuDisUtils.cpp @@ -0,0 +1,198 @@ +#include "stdafx.h" +#include "GsuDisUtils.h" +#include "DisassemblyInfo.h" +#include "../Utilities/FastString.h" +#include "../Utilities/HexUtilities.h" + +void GsuDisUtils::GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager *labelManager) +{ + constexpr const char* registerNames[16] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; + bool alt1 = (info.GetFlags() & 0x01) != 0; + bool alt2 = (info.GetFlags() & 0x02) != 0; + bool prefix = (info.GetFlags() & 0x10) != 0; + + uint8_t opCode = info.GetOpCode(); + + FastString str; + const char* reg = registerNames[opCode & 0x0F]; + uint32_t jmpTarget = memoryAddr + (int8_t)info.GetByteCode()[1]; + + switch(opCode) { + case 0x00: str.Write("STOP"); break; + case 0x01: str.Write("NOP"); break; + case 0x02: str.Write("CACHE"); break; + case 0x03: str.Write("LSR"); break; + case 0x04: str.Write("ROL"); break; + + case 0x05: str.WriteAll("BRA $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x06: str.WriteAll("BLT $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x07: str.WriteAll("BGE $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x08: str.WriteAll("BNE $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x09: str.WriteAll("BEQ $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0A: str.WriteAll("BPL $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0B: str.WriteAll("BMI $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0C: str.WriteAll("BCC $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0D: str.WriteAll("BCS $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0E: str.WriteAll("BCV $", HexUtilities::ToHex24(jmpTarget)); break; + case 0x0F: str.WriteAll("BVS $", HexUtilities::ToHex24(jmpTarget)); break; + + case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F: + str.WriteAll(prefix ? "MOVE R" : "TO R", reg); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F: + str.WriteAll("WITH R", reg); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3A: case 0x3B: + str.WriteAll(alt1 ? "STB (R" : "STW (R", reg, ')'); + break; + + case 0x3C: str.Write("LOOP"); break; + case 0x3D: str.Write("ALT1"); break; + case 0x3E: str.Write("ALT2"); break; + case 0x3F: str.Write("ALT3"); break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + str.WriteAll(alt1 ? "LDB (R" : "LDW (R", reg, ')'); + break; + + case 0x4C: str.Write(alt1 ? "RPIX" : "PLOT"); break; + + case 0x4D: str.Write("SWAP"); break; + case 0x4E: str.Write(alt1 ? "CMODE" : "COLOR"); break; + + case 0x4F: str.Write("NOT"); break; + + case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: + str.Write(alt1 ? "ADC " : "ADD "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F: + if(alt2 && alt1) { + str.WriteAll("CMP R", reg); + } else { + if(!alt2 && alt1) { + str.Write("SBC "); + } else { + str.Write("SUB "); + } + if(alt2 && !alt1) { + str.WriteAll('#', reg); + } else { + str.WriteAll('R', reg); + } + } + break; + + case 0x70: str.Write("MERGE"); break; + + case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: + str.Write(alt1 ? "BIC " : "AND "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: + str.Write(alt1 ? "UMULT " : "MULT "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0x90: str.Write("SBK"); break; + + case 0x91: case 0x92: case 0x93: case 0x94: + str.WriteAll("LINK #", reg); + break; + + case 0x95: str.Write("SEX"); break; + + case 0x96: str.Write(alt1 ? "DIV2" : "ASR"); break; + case 0x97: str.Write("ROR"); break; + + case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: + str.WriteAll(alt1 ? "LJMP R" : "JMP R", reg); + break; + + case 0x9E: str.Write("LOB"); break; + case 0x9F: str.Write(alt1 ? "LMULT" : "FMULT"); break; + + case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: + case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF: + if(alt1) { + str.WriteAll("LMS R", reg, ", ($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } else if(alt2) { + str.WriteAll("SMS R", reg, ", ($", HexUtilities::ToHex(info.GetByteCode()[1] << 1), ')'); + } else { + str.WriteAll("IBT R", reg, ", #$", HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: + case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: + str.WriteAll(prefix ? "MOVES R" : "FROM R", reg); + break; + + case 0xC0: str.Write("HIB"); break; + + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: + str.Write(alt1 ? "XOR " : "OR "); + str.WriteAll(alt2 ? '#' : 'R', reg); + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7: + case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: + str.WriteAll("INC R", reg); + break; + + case 0xDF: + if(!alt2) { + //GETC - "Get byte from ROM to color register" + str.Write("GETC"); + } else if(!alt1) { + //RAMB - "Set RAM data bank" + str.Write("RAMB"); + } else { + str.Write("ROMB"); + } + break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: + str.WriteAll("DEC R", reg); + break; + + case 0xEF: + if(alt2 && alt1) { + str.Write("GETBS"); + } else if(alt2) { + str.Write("GETBL"); + } else if(alt1) { + str.Write("GETBH"); + } else { + str.Write("GETB"); + } + break; + + case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7: + case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF: + if(alt1) { + str.WriteAll("LM R", reg, ", ($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } else if(alt2) { + str.WriteAll("SM R", reg, ", ($", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1]), ')'); + } else { + str.WriteAll("IWT R", reg, ", #$", HexUtilities::ToHex(info.GetByteCode()[2]), HexUtilities::ToHex(info.GetByteCode()[1])); + } + break; + } + + out += str.ToString(); +} diff --git a/Core/GsuDisUtils.h b/Core/GsuDisUtils.h new file mode 100644 index 0000000..f3c59f5 --- /dev/null +++ b/Core/GsuDisUtils.h @@ -0,0 +1,11 @@ +#pragma once +#include "stdafx.h" + +class DisassemblyInfo; +class LabelManager; + +class GsuDisUtils +{ +public: + static void GetDisassembly(DisassemblyInfo &info, string &out, uint32_t memoryAddr, LabelManager* labelManager); +}; diff --git a/Core/GsuRamHandler.h b/Core/GsuRamHandler.h new file mode 100644 index 0000000..9503aba --- /dev/null +++ b/Core/GsuRamHandler.h @@ -0,0 +1,57 @@ +#pragma once +#include "stdafx.h" +#include "IMemoryHandler.h" +#include "GsuTypes.h" + +class GsuRamHandler : public IMemoryHandler +{ +private: + GsuState *_state; + IMemoryHandler *_handler; + +public: + GsuRamHandler(GsuState &state, IMemoryHandler *handler) + { + _memoryType = SnesMemoryType::GsuWorkRam; + _handler = handler; + _state = &state; + } + + uint8_t Read(uint32_t addr) override + { + if(!_state->SFR.Running || !_state->GsuRamAccess) { + return _handler->Read(addr); + } + + //TODO: open bus + return 0; + } + + uint8_t Peek(uint32_t addr) override + { + return Read(addr); + } + + void PeekBlock(uint8_t *output) override + { + for(int i = 0; i < 0x1000; i++) { + output[i] = Read(i); + } + } + + void Write(uint32_t addr, uint8_t value) override + { + if(!_state->SFR.Running || !_state->GsuRamAccess) { + _handler->Write(addr, value); + } + } + + AddressInfo GetAbsoluteAddress(uint32_t address) override + { + if(!_state->SFR.Running || !_state->GsuRamAccess) { + return _handler->GetAbsoluteAddress(address); + } else { + return { -1, SnesMemoryType::Register }; + } + } +}; \ No newline at end of file diff --git a/Core/GsuRomHandler.h b/Core/GsuRomHandler.h new file mode 100644 index 0000000..7896de7 --- /dev/null +++ b/Core/GsuRomHandler.h @@ -0,0 +1,66 @@ +#pragma once +#include "stdafx.h" +#include "IMemoryHandler.h" +#include "GsuTypes.h" + +class GsuRomHandler : public IMemoryHandler +{ +private: + GsuState *_state; + IMemoryHandler *_romHandler; + +public: + GsuRomHandler(GsuState &state, IMemoryHandler *romHandler) + { + _memoryType = SnesMemoryType::PrgRom; + _romHandler = romHandler; + _state = &state; + } + + uint8_t Read(uint32_t addr) override + { + if(!_state->SFR.Running || !_state->GsuRomAccess) { + return _romHandler->Read(addr); + } + + if(addr & 0x01) { + return 0x01; + } + + switch(addr & 0x0E) { + default: + case 2: case 6: case 8: case 0x0C: + return 0; + + case 4: return 0x04; + case 0x0A: return 0x08; + case 0x0E: return 0x0C; + } + } + + uint8_t Peek(uint32_t addr) override + { + return Read(addr); + } + + void PeekBlock(uint8_t *output) override + { + for(int i = 0; i < 0x1000; i++) { + output[i] = Read(i); + } + } + + void Write(uint32_t addr, uint8_t value) override + { + //ROM + } + + AddressInfo GetAbsoluteAddress(uint32_t address) override + { + if(!_state->SFR.Running || !_state->GsuRomAccess) { + return _romHandler->GetAbsoluteAddress(address); + } else { + return { -1, SnesMemoryType::Register }; + } + } +}; \ No newline at end of file diff --git a/Core/GsuTypes.h b/Core/GsuTypes.h new file mode 100644 index 0000000..98537a0 --- /dev/null +++ b/Core/GsuTypes.h @@ -0,0 +1,103 @@ +#pragma once +#include "stdafx.h" + +struct GsuFlags +{ + bool Zero; + bool Carry; + bool Sign; + bool Overflow; + bool Running; + bool RomReadPending; + bool Alt1; + bool Alt2; + bool ImmLow; + bool ImmHigh; + bool Prefix; + bool Irq; + + uint8_t GetFlagsLow() + { + return ( + (Zero << 1) | + (Carry << 2) | + (Sign << 3) | + (Overflow << 4) | + (Running << 5) | + (RomReadPending << 6) + ); + } + + uint8_t GetFlagsHigh() + { + return ( + (Alt1 << 0) | + (Alt2 << 1) | + (ImmLow << 2) | + (ImmHigh << 3) | + (Prefix << 4) | + (Irq << 7) + ); + } +}; + +struct GsuPixelCache +{ + uint8_t X; + uint8_t Y; + uint8_t Pixels[8]; + uint8_t ValidBits; +}; + +struct GsuState +{ + uint64_t CycleCount; + + uint16_t R[16]; + + GsuFlags SFR; + + uint8_t RegisterLatch; + + uint8_t ProgramBank; + uint8_t RomBank; + uint8_t RamBank; + + bool IrqDisabled; + bool HighSpeedMode; + bool ClockSelect; + bool BackupRamEnabled; + uint8_t ScreenBase; + + uint8_t ColorGradient; + uint8_t PlotBpp; + uint8_t ScreenHeight; + bool GsuRamAccess; + bool GsuRomAccess; + + uint16_t CacheBase; + + bool PlotTransparent; + bool PlotDither; + bool ColorHighNibble; + bool ColorFreezeHigh; + bool ObjMode; + + uint8_t ColorReg; + uint8_t SrcReg; + uint8_t DestReg; + + uint8_t RomReadBuffer; + uint8_t RomDelay; + + uint8_t ProgramReadBuffer; + + uint16_t RamWriteAddress; + uint8_t RamWriteValue; + uint8_t RamDelay; + + uint16_t RamAddress; + + GsuPixelCache PrimaryCache; + GsuPixelCache SecondaryCache; +}; \ No newline at end of file diff --git a/Core/LabelManager.cpp b/Core/LabelManager.cpp index 4a66bc5..6d888db 100644 --- a/Core/LabelManager.cpp +++ b/Core/LabelManager.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "LabelManager.h" #include "Debugger.h" +#include "DebugUtilities.h" LabelManager::LabelManager(Debugger *debugger) { @@ -49,6 +50,7 @@ int64_t LabelManager::GetLabelKey(uint32_t absoluteAddr, SnesMemoryType memType) case SnesMemoryType::SpcRam: return absoluteAddr | ((uint64_t)5 << 32); case SnesMemoryType::SpcRom: return absoluteAddr | ((uint64_t)6 << 32); case SnesMemoryType::Sa1InternalRam: return absoluteAddr | ((uint64_t)7 << 32); + case SnesMemoryType::GsuWorkRam: return absoluteAddr | ((uint64_t)8 << 32); default: return -1; } } @@ -63,6 +65,7 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) case ((uint64_t)5 << 32): return SnesMemoryType::SpcRam; break; case ((uint64_t)6 << 32): return SnesMemoryType::SpcRom; break; case ((uint64_t)7 << 32): return SnesMemoryType::Sa1InternalRam; break; + case ((uint64_t)8 << 32): return SnesMemoryType::GsuWorkRam; break; } throw std::runtime_error("Invalid label key"); @@ -70,7 +73,7 @@ SnesMemoryType LabelManager::GetKeyMemoryType(uint64_t key) string LabelManager::GetLabel(AddressInfo address) { - if(address.Type <= SnesMemoryType::Sa1Memory) { + if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { address = _debugger->GetAbsoluteAddress(address); } @@ -103,7 +106,7 @@ string LabelManager::GetComment(AddressInfo absAddress) void LabelManager::GetLabelAndComment(AddressInfo address, string &label, string &comment) { - if(address.Type <= SnesMemoryType::Sa1Memory) { + if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { address = _debugger->GetAbsoluteAddress(address); } @@ -151,7 +154,7 @@ int32_t LabelManager::GetLabelRelativeAddress(string &label) bool LabelManager::HasLabelOrComment(AddressInfo address) { - if(address.Type <= SnesMemoryType::Sa1Memory) { + if(address.Type <= DebugUtilities::GetLastCpuMemoryType()) { address = _debugger->GetAbsoluteAddress(address); } diff --git a/Core/LuaApi.cpp b/Core/LuaApi.cpp index 80d794a..ca81bde 100644 --- a/Core/LuaApi.cpp +++ b/Core/LuaApi.cpp @@ -103,6 +103,7 @@ int LuaApi::GetLibrary(lua_State *lua) lua_pushintvalue(cpu, SnesMemoryType::CpuMemory); lua_pushintvalue(spc, SnesMemoryType::SpcMemory); lua_pushintvalue(sa1, SnesMemoryType::Sa1Memory); + lua_pushintvalue(gsu, SnesMemoryType::GsuMemory); lua_pushintvalue(cgram, SnesMemoryType::CGRam); lua_pushintvalue(vram, SnesMemoryType::VideoRam); lua_pushintvalue(oam, SnesMemoryType::SpriteRam); @@ -112,6 +113,7 @@ int LuaApi::GetLibrary(lua_State *lua) lua_pushintvalue(cpuDebug, SnesMemoryType::CpuMemory | 0x100); lua_pushintvalue(spcDebug, SnesMemoryType::SpcMemory | 0x100); lua_pushintvalue(sa1Debug, SnesMemoryType::Sa1Memory | 0x100); + lua_pushintvalue(gsuDebug, SnesMemoryType::GsuMemory | 0x100); lua_settable(lua, -3); lua_pushliteral(lua, "memCallbackType"); diff --git a/Core/MemoryAccessCounter.cpp b/Core/MemoryAccessCounter.cpp index ec1b73d..3d4c453 100644 --- a/Core/MemoryAccessCounter.cpp +++ b/Core/MemoryAccessCounter.cpp @@ -6,6 +6,7 @@ #include "MemoryDumper.h" #include "Spc.h" #include "Sa1.h" +#include "Gsu.h" #include "BaseCartridge.h" MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) @@ -14,6 +15,7 @@ MemoryAccessCounter::MemoryAccessCounter(Debugger* debugger, Console *console) _memoryManager = console->GetMemoryManager().get(); _spc = console->GetSpc().get(); _sa1 = console->GetCartridge()->GetSa1(); + _gsu = console->GetCartridge()->GetGsu(); for(int i = (int)SnesMemoryType::PrgRom; i < (int)SnesMemoryType::Register; i++) { uint32_t memSize = _debugger->GetMemoryDumper()->GetMemorySize((SnesMemoryType)i); @@ -133,6 +135,15 @@ void MemoryAccessCounter::GetAccessStamps(uint32_t offset, uint32_t length, Snes } break; + case SnesMemoryType::GsuMemory: + for(uint32_t i = 0; i < length; i++) { + AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if(info.Address >= 0) { + stamps[i] = GetStampArray(operationType, info.Type)[info.Address]; + } + } + break; + default: memcpy(stamps, GetStampArray(operationType, memoryType).data() + offset, length * sizeof(uint64_t)); break; @@ -169,6 +180,15 @@ void MemoryAccessCounter::GetAccessCounts(uint32_t offset, uint32_t length, Snes } break; + case SnesMemoryType::GsuMemory: + for(uint32_t i = 0; i < length; i++) { + AddressInfo info = _gsu->GetMemoryMappings()->GetAbsoluteAddress(offset + i); + if(info.Address >= 0) { + counts[i] = GetCountArray(operationType, info.Type)[info.Address]; + } + } + break; + default: memcpy(counts, GetCountArray(operationType, memoryType).data() + offset, length * sizeof(uint32_t)); break; diff --git a/Core/MemoryAccessCounter.h b/Core/MemoryAccessCounter.h index 6827c02..ae3a5ea 100644 --- a/Core/MemoryAccessCounter.h +++ b/Core/MemoryAccessCounter.h @@ -7,6 +7,7 @@ class MemoryManager; class Spc; class Console; class Sa1; +class Gsu; class MemoryAccessCounter { @@ -25,6 +26,7 @@ private: MemoryManager* _memoryManager; Spc* _spc; Sa1* _sa1; + Gsu* _gsu; vector& GetCountArray(MemoryOperationType operationType, SnesMemoryType memType); vector& GetStampArray(MemoryOperationType operationType, SnesMemoryType memType); diff --git a/Core/MemoryDumper.cpp b/Core/MemoryDumper.cpp index 336b6ee..21d16de 100644 --- a/Core/MemoryDumper.cpp +++ b/Core/MemoryDumper.cpp @@ -5,6 +5,7 @@ #include "Spc.h" #include "NecDsp.h" #include "Sa1.h" +#include "Gsu.h" #include "MemoryDumper.h" #include "BaseCartridge.h" #include "VideoDecoder.h" @@ -29,6 +30,7 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t case SnesMemoryType::CpuMemory: case SnesMemoryType::SpcMemory: case SnesMemoryType::Sa1Memory: + case SnesMemoryType::GsuMemory: break; case SnesMemoryType::PrgRom: memcpy(_cartridge->DebugGetPrgRom(), buffer, length); break; @@ -45,6 +47,8 @@ void MemoryDumper::SetMemoryState(SnesMemoryType type, uint8_t *buffer, uint32_t case SnesMemoryType::DspDataRam: memcpy(_cartridge->GetDsp()->DebugGetDataRam(), buffer, length); break; case SnesMemoryType::Sa1InternalRam: memcpy(_cartridge->GetSa1()->DebugGetInternalRam(), buffer, length); break; + + case SnesMemoryType::GsuWorkRam: memcpy(_cartridge->GetGsu()->DebugGetWorkRam(), buffer, length); break; } } @@ -55,6 +59,7 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type) case SnesMemoryType::CpuMemory: return 0x1000000; case SnesMemoryType::SpcMemory: return 0x10000; case SnesMemoryType::Sa1Memory: return 0x1000000; + case SnesMemoryType::GsuMemory: return 0x1000000; case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRomSize(); case SnesMemoryType::WorkRam: return MemoryManager::WorkRamSize; case SnesMemoryType::SaveRam: return _cartridge->DebugGetSaveRamSize(); @@ -70,6 +75,8 @@ uint32_t MemoryDumper::GetMemorySize(SnesMemoryType type) case SnesMemoryType::DspDataRam: return _cartridge->GetDsp() ? _cartridge->GetDsp()->DebugGetDataRamSize() : 0; case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1() ? _cartridge->GetSa1()->DebugGetInternalRamSize() : 0;; + + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu() ? _cartridge->GetGsu()->DebugGetWorkRamSize() : 0;; } } @@ -96,6 +103,12 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer) } break; + case SnesMemoryType::GsuMemory: + for(int i = 0; i <= 0xFFFFFF; i += 0x1000) { + _cartridge->GetGsu()->GetMemoryMappings()->PeekBlock(i, buffer + i); + } + break; + case SnesMemoryType::PrgRom: memcpy(buffer, _cartridge->DebugGetPrgRom(), _cartridge->DebugGetPrgRomSize()); break; case SnesMemoryType::WorkRam: memcpy(buffer, _memoryManager->DebugGetWorkRam(), MemoryManager::WorkRamSize); break; case SnesMemoryType::SaveRam: memcpy(buffer, _cartridge->DebugGetSaveRam(), _cartridge->DebugGetSaveRamSize()); break; @@ -110,6 +123,8 @@ void MemoryDumper::GetMemoryState(SnesMemoryType type, uint8_t *buffer) case SnesMemoryType::DspDataRam: memcpy(buffer, _cartridge->GetDsp()->DebugGetDataRam(), _cartridge->GetDsp()->DebugGetDataRamSize()); break; case SnesMemoryType::Sa1InternalRam: memcpy(buffer, _cartridge->GetSa1()->DebugGetInternalRam(), _cartridge->GetSa1()->DebugGetInternalRamSize()); break; + + case SnesMemoryType::GsuWorkRam: memcpy(buffer, _cartridge->GetGsu()->DebugGetWorkRam(), _cartridge->GetGsu()->DebugGetWorkRamSize()); break; } } @@ -133,6 +148,7 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u case SnesMemoryType::CpuMemory: _memoryManager->Write(address, value, MemoryOperationType::Write); break; case SnesMemoryType::SpcMemory: _spc->DebugWrite(address, value); break; case SnesMemoryType::Sa1Memory: _cartridge->GetSa1()->WriteSa1(address, value, MemoryOperationType::Write); break; + case SnesMemoryType::GsuMemory: _cartridge->GetGsu()->WriteGsu(address, value, MemoryOperationType::Write); break; case SnesMemoryType::PrgRom: _cartridge->DebugGetPrgRom()[address] = value; break; case SnesMemoryType::WorkRam: _memoryManager->DebugGetWorkRam()[address] = value; break; @@ -149,6 +165,8 @@ void MemoryDumper::SetMemoryValue(SnesMemoryType memoryType, uint32_t address, u case SnesMemoryType::DspDataRam: _cartridge->GetDsp()->DebugGetDataRam()[address] = value; case SnesMemoryType::Sa1InternalRam: _cartridge->GetSa1()->DebugGetInternalRam()[address] = value; + + case SnesMemoryType::GsuWorkRam: _cartridge->GetGsu()->DebugGetWorkRam()[address] = value; } } @@ -164,6 +182,7 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address case SnesMemoryType::CpuMemory: return _memoryManager->Peek(address); case SnesMemoryType::SpcMemory: return _spc->DebugRead(address); case SnesMemoryType::Sa1Memory: return _cartridge->GetSa1()->GetMemoryMappings()->Peek(address); + case SnesMemoryType::GsuMemory: return _cartridge->GetGsu()->GetMemoryMappings()->Peek(address); case SnesMemoryType::PrgRom: return _cartridge->DebugGetPrgRom()[address]; case SnesMemoryType::WorkRam: return _memoryManager->DebugGetWorkRam()[address]; @@ -180,6 +199,8 @@ uint8_t MemoryDumper::GetMemoryValue(SnesMemoryType memoryType, uint32_t address case SnesMemoryType::DspDataRam: return _cartridge->GetDsp()->DebugGetDataRam()[address]; case SnesMemoryType::Sa1InternalRam: return _cartridge->GetSa1()->DebugGetInternalRam()[address]; + + case SnesMemoryType::GsuWorkRam: return _cartridge->GetGsu()->DebugGetWorkRam()[address]; } } diff --git a/Core/MemoryManager.cpp b/Core/MemoryManager.cpp index cf4e0dc..1009120 100644 --- a/Core/MemoryManager.cpp +++ b/Core/MemoryManager.cpp @@ -11,6 +11,8 @@ #include "MessageManager.h" #include "DebugTypes.h" #include "EmuSettings.h" +#include "Sa1.h" +#include "Gsu.h" #include "BaseCoprocessor.h" #include "../Utilities/Serializer.h" #include "../Utilities/HexUtilities.h" @@ -189,6 +191,17 @@ void MemoryManager::UpdateEvents() _hasEvent[_dramRefreshPosition] = true; } +void MemoryManager::SyncCoprocessors() +{ + if(_cart->GetCoprocessor()) { + if(_cart->GetGsu()) { + _cart->GetGsu()->Run(); + } else if(_cart->GetSa1()) { + _cart->GetSa1()->Run(); + } + } +} + void MemoryManager::Exec() { _masterClock += 2; @@ -222,9 +235,7 @@ void MemoryManager::Exec() _regs->ProcessIrqCounters(); } - if(_cart->GetCoprocessor()) { - _cart->GetCoprocessor()->Run(); - } + SyncCoprocessors(); } uint8_t MemoryManager::Read(uint32_t addr, MemoryOperationType type) diff --git a/Core/MemoryManager.h b/Core/MemoryManager.h index 173e5d6..da8c3da 100644 --- a/Core/MemoryManager.h +++ b/Core/MemoryManager.h @@ -47,6 +47,7 @@ private: uint8_t _masterClockTable[2][0x10000]; void UpdateEvents(); + __forceinline void SyncCoprocessors(); void Exec(); public: diff --git a/Core/NecDsp.cpp b/Core/NecDsp.cpp index 58ef1af..056629d 100644 --- a/Core/NecDsp.cpp +++ b/Core/NecDsp.cpp @@ -17,6 +17,7 @@ NecDsp::NecDsp(CoprocessorType type, Console* console, vector &programR _console = console; _type = type; _memoryManager = console->GetMemoryManager().get(); + _memoryType = SnesMemoryType::Register; MemoryMappings *mm = _memoryManager->GetMemoryMappings(); if(type == CoprocessorType::ST010 || type == CoprocessorType::ST011) { @@ -219,6 +220,7 @@ void NecDsp::Write(uint32_t addr, uint8_t value) uint8_t NecDsp::Peek(uint32_t addr) { + //Avoid side effects for now return 0; } @@ -229,7 +231,7 @@ void NecDsp::PeekBlock(uint8_t *output) AddressInfo NecDsp::GetAbsoluteAddress(uint32_t address) { - return { -1, SnesMemoryType::CpuMemory }; + return { -1, SnesMemoryType::Register }; } void NecDsp::RunApuOp(uint8_t aluOperation, uint16_t source) diff --git a/Core/NecDsp.h b/Core/NecDsp.h index 433ab4d..41a40ce 100644 --- a/Core/NecDsp.h +++ b/Core/NecDsp.h @@ -48,15 +48,13 @@ private: void Load(uint8_t dest, uint16_t value); uint16_t GetSourceValue(uint8_t source); - static bool LoadFirmware(Console *console, string combinedFilename, string splitFilenameProgram, string splitFilenameData, vector &programRom, vector &dataRom, uint32_t programSize, uint32_t dataSize); - NecDsp(CoprocessorType type, Console* console, vector &programRom, vector &dataRom); public: static NecDsp* InitCoprocessor(CoprocessorType type, Console* console); void Reset() override; - void Run() override; + void Run(); void LoadBattery(string filePath) override; void SaveBattery(string filePath) override; diff --git a/Core/NecDspDisUtils.h b/Core/NecDspDisUtils.h index aac2aeb..c631af1 100644 --- a/Core/NecDspDisUtils.h +++ b/Core/NecDspDisUtils.h @@ -2,9 +2,7 @@ #include "stdafx.h" class DisassemblyInfo; -class Console; class LabelManager; -struct NecDspState; class NecDspDisUtils { diff --git a/Core/Sa1.cpp b/Core/Sa1.cpp index b397979..46fdf99 100644 --- a/Core/Sa1.cpp +++ b/Core/Sa1.cpp @@ -16,6 +16,7 @@ Sa1::Sa1(Console* console) { _console = console; _memoryManager = console->GetMemoryManager().get(); + _memoryType = SnesMemoryType::Register; _lastAccessMemType = SnesMemoryType::PrgRom; _openBus = 0; _cart = _console->GetCartridge().get(); @@ -405,11 +406,14 @@ uint8_t Sa1::Read(uint32_t addr) uint8_t Sa1::Peek(uint32_t addr) { - return 0; + return Sa1RegisterRead(addr); } void Sa1::PeekBlock(uint8_t *output) { + for(int i = 0; i < 0x1000; i++) { + output[i] = Sa1RegisterRead(i); + } } void Sa1::Write(uint32_t addr, uint8_t value) diff --git a/Core/Sa1.h b/Core/Sa1.h index 865950d..fc4db8b 100644 --- a/Core/Sa1.h +++ b/Core/Sa1.h @@ -68,7 +68,7 @@ public: void Write(uint32_t addr, uint8_t value) override; AddressInfo GetAbsoluteAddress(uint32_t address) override; - void Run() override; + void Run(); void Reset() override; SnesMemoryType GetSa1MemoryType(); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index 6c937c2..bb7c91e 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -263,6 +263,7 @@ struct EmulationConfig uint32_t PpuExtraScanlinesBeforeNmi = 0; uint32_t PpuExtraScanlinesAfterNmi = 0; + uint32_t GsuClockSpeed = 0; RamState RamPowerOnState = RamState::Random; }; @@ -443,6 +444,7 @@ enum class DebuggerFlags : uint32_t ShowUnidentifiedData = 0x400, DisassembleUnidentifiedData = 0x800, + GsuDebuggerEnabled = 0x10000000, Sa1DebuggerEnabled = 0x20000000, SpcDebuggerEnabled = 0x40000000, CpuDebuggerEnabled = 0x80000000 diff --git a/Core/TraceLogger.cpp b/Core/TraceLogger.cpp index 71eab17..e957612 100644 --- a/Core/TraceLogger.cpp +++ b/Core/TraceLogger.cpp @@ -7,6 +7,7 @@ #include "Debugger.h" #include "MemoryManager.h" #include "LabelManager.h" +#include "DebugUtilities.h" #include "CpuTypes.h" #include "SpcTypes.h" #include "NecDspTypes.h" @@ -64,6 +65,7 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) _logCpu[(int)CpuType::Spc] = options.LogSpc; _logCpu[(int)CpuType::NecDsp] = options.LogNecDsp; _logCpu[(int)CpuType::Sa1] = options.LogSa1; + _logCpu[(int)CpuType::Gsu] = options.LogGsu; string condition = _options.Condition; string format = _options.Format; @@ -79,8 +81,9 @@ void TraceLogger::SetOptions(TraceLoggerOptions options) }*/ ParseFormatString(_rowParts, format); - ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,15h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); - ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,15h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_spcRowParts, "[PC,4h] [ByteCode,11h] [Disassembly][EffectiveAddress] [MemoryValue,h][Align,48] A:[A,2h] X:[X,2h] Y:[Y,2h] S:[SP,2h] P:[P,8] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_dspRowParts, "[PC,4h] [ByteCode,11h] [Disassembly] [Align,65] [A,2h] S:[SP,2h] H:[Cycle,3] V:[Scanline,3]"); + ParseFormatString(_gsuRowParts, "[PC,6h] [ByteCode,11h] [Disassembly] [Align,50] SRC:[X,2] DST:[Y,2] R0:[A,2h] H:[Cycle,3] V:[Scanline,3]"); } void TraceLogger::ParseFormatString(vector &rowParts, string format) @@ -384,6 +387,37 @@ void TraceLogger::GetTraceRow(string &output, NecDspState &cpuState, PpuState &p output += _options.UseWindowsEol ? "\r\n" : "\n"; } +void TraceLogger::GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo) +{ + int originalSize = (int)output.size(); + uint32_t pcAddress = (gsuState.ProgramBank << 16) | gsuState.R[15]; + for(RowPart& rowPart : _gsuRowParts) { + switch(rowPart.DataType) { + case RowDataType::Text: output += rowPart.Text; break; + case RowDataType::ByteCode: WriteByteCode(disassemblyInfo, rowPart, output); break; + case RowDataType::Disassembly: WriteDisassembly(disassemblyInfo, rowPart, 0, pcAddress, output); break; + case RowDataType::Align: WriteAlign(originalSize, rowPart, output); break; + + case RowDataType::PC: WriteValue(output, HexUtilities::ToHex24(pcAddress), rowPart); break; + case RowDataType::A: + WriteValue(output, gsuState.R[0], rowPart); + for(int i = 1; i < 16; i++) { + output += " R" + std::to_string(i) + ":" + HexUtilities::ToHex(gsuState.R[i]); + } + break; + case RowDataType::X: WriteValue(output, gsuState.SrcReg, rowPart); break; + case RowDataType::Y: WriteValue(output, gsuState.DestReg, rowPart); break; + + case RowDataType::Cycle: WriteValue(output, ppuState.Cycle, rowPart); break; + case RowDataType::Scanline: WriteValue(output, ppuState.Scanline, rowPart); break; + case RowDataType::HClock: WriteValue(output, ppuState.HClock, rowPart); break; + case RowDataType::FrameCount: WriteValue(output, ppuState.FrameCount, rowPart); break; + default: break; + } + } + output += _options.UseWindowsEol ? "\r\n" : "\n"; +} + /* bool TraceLogger::ConditionMatches(DebugState &state, DisassemblyInfo &disassemblyInfo, OperationInfo &operationInfo) { @@ -410,6 +444,7 @@ void TraceLogger::GetTraceRow(string &output, CpuType cpuType, DisassemblyInfo & case CpuType::Spc: GetTraceRow(output, state.Spc, state.Ppu, disassemblyInfo); break; case CpuType::NecDsp: GetTraceRow(output, state.Dsp, state.Ppu, disassemblyInfo); break; case CpuType::Sa1: GetTraceRow(output, state.Sa1, state.Ppu, disassemblyInfo, SnesMemoryType::Sa1Memory); break; + case CpuType::Gsu: GetTraceRow(output, state.Gsu, state.Ppu, disassemblyInfo); break; } } @@ -476,7 +511,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) } bool enabled = false; - for(int i = 0; i < (int)CpuType::Sa1 + 1; i++) { + for(int i = 0; i <= (int)DebugUtilities::GetLastCpuType(); i++) { enabled |= _logCpu[i]; } @@ -503,6 +538,7 @@ const char* TraceLogger::GetExecutionTrace(uint32_t lineCount) case CpuType::Spc: _executionTrace += "\x3\x1" + HexUtilities::ToHex(_stateCacheCopy[index].Spc.PC) + "\x1"; break; case CpuType::NecDsp: _executionTrace += "\x4\x1" + HexUtilities::ToHex(_stateCacheCopy[index].Dsp.PC) + "\x1"; break; case CpuType::Sa1: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((_stateCacheCopy[index].Sa1.K << 16) | _stateCacheCopy[index].Sa1.PC) + "\x1"; break; + case CpuType::Gsu: _executionTrace += "\x4\x1" + HexUtilities::ToHex24((_stateCacheCopy[index].Gsu.ProgramBank << 16) | _stateCacheCopy[index].Gsu.R[15]) + "\x1"; break; } string byteCode; diff --git a/Core/TraceLogger.h b/Core/TraceLogger.h index 899761b..3cf7e68 100644 --- a/Core/TraceLogger.h +++ b/Core/TraceLogger.h @@ -19,6 +19,7 @@ struct TraceLoggerOptions bool LogSpc; bool LogNecDsp; bool LogSa1; + bool LogGsu; bool ShowExtraInfo; bool IndentCode; @@ -80,8 +81,9 @@ private: vector _rowParts; vector _spcRowParts; vector _dspRowParts; + vector _gsuRowParts; - bool _logCpu[(int)CpuType::Sa1 + 1] = {}; + bool _logCpu[(int)CpuType::Gsu + 1] = {}; bool _pendingLog; //CpuState _lastState; @@ -116,6 +118,7 @@ private: void GetTraceRow(string &output, CpuState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo, SnesMemoryType memType); void GetTraceRow(string &output, SpcState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); void GetTraceRow(string &output, NecDspState &cpuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); + void GetTraceRow(string &output, GsuState &gsuState, PpuState &ppuState, DisassemblyInfo &disassemblyInfo); template void WriteValue(string &output, T value, RowPart& rowPart); diff --git a/Libretro/Makefile.common b/Libretro/Makefile.common index 8fda0a9..2352b4a 100644 --- a/Libretro/Makefile.common +++ b/Libretro/Makefile.common @@ -47,6 +47,10 @@ SOURCES_CXX := $(LIBRETRO_DIR)/libretro.cpp \ $(CORE_DIR)/EmuSettings.cpp \ $(CORE_DIR)/EventManager.cpp \ $(CORE_DIR)/ExpressionEvaluator.cpp \ + $(CORE_DIR)/Gsu.cpp \ + $(CORE_DIR)/Gsu.Instructions.cpp \ + $(CORE_DIR)/GsuDisUtils.cpp \ + $(CORE_DIR)/GsuDebugger.cpp \ $(CORE_DIR)/InternalRegisters.cpp \ $(CORE_DIR)/KeyManager.cpp \ $(CORE_DIR)/LabelManager.cpp \ diff --git a/Libretro/libretro.cpp b/Libretro/libretro.cpp index 94d8c26..4a59348 100644 --- a/Libretro/libretro.cpp +++ b/Libretro/libretro.cpp @@ -41,6 +41,7 @@ static constexpr const char* MesenOverscanHorizontal = "mesen-s_overscan_horizon static constexpr const char* MesenRamState = "mesen-s_ramstate"; static constexpr const char* MesenOverclock = "mesen-s_overclock"; static constexpr const char* MesenOverclockType = "mesen-s_overclock_type"; +static constexpr const char* MesenSuperFxOverclock = "mesen-s_superfx_overclock"; extern "C" { void logMessage(retro_log_level level, const char* message) @@ -105,6 +106,7 @@ extern "C" { { MesenAspectRatio, "Aspect Ratio; Auto|No Stretching|NTSC|PAL|4:3|16:9" }, { MesenOverclock, "Overclock; None|Low|Medium|High|Very High" }, { MesenOverclockType, "Overclock Type; Before NMI|After NMI" }, + { MesenSuperFxOverclock, "Super FX Clock Speed; 100%|200%|300%|400%|500%|1000%" }, { MesenRamState, "Default power-on state for RAM; Random Values (Default)|All 0s|All 1s" }, { NULL, NULL }, }; @@ -260,6 +262,24 @@ extern "C" { } } + emulation.GsuClockSpeed = 100; + if(readVariable(MesenSuperFxOverclock, var)) { + string value = string(var.value); + if(value == "100%") { + emulation.GsuClockSpeed = 100; + } else if(value == "200%") { + emulation.GsuClockSpeed = 200; + } else if(value == "300%") { + emulation.GsuClockSpeed = 300; + } else if(value == "400%") { + emulation.GsuClockSpeed = 400; + } else if(value == "500%") { + emulation.GsuClockSpeed = 500; + } else if(value == "1000%") { + emulation.GsuClockSpeed = 1000; + } + } + int overscanHorizontal = 0; int overscanVertical = 0; if(readVariable(MesenOverscanHorizontal, var)) { diff --git a/UI/Config/EmulationConfig.cs b/UI/Config/EmulationConfig.cs index 8d4519f..aeca987 100644 --- a/UI/Config/EmulationConfig.cs +++ b/UI/Config/EmulationConfig.cs @@ -21,6 +21,7 @@ namespace Mesen.GUI.Config [MinMax(0, 1000)] public UInt32 PpuExtraScanlinesBeforeNmi = 0; [MinMax(0, 1000)] public UInt32 PpuExtraScanlinesAfterNmi = 0; + [MinMax(100, 1000)] public UInt32 GsuClockSpeed = 100; public RamState RamPowerOnState = RamState.Random; diff --git a/UI/Debugger/Breakpoints/Breakpoint.cs b/UI/Debugger/Breakpoints/Breakpoint.cs index 1dba35b..8f5901a 100644 --- a/UI/Debugger/Breakpoints/Breakpoint.cs +++ b/UI/Debugger/Breakpoints/Breakpoint.cs @@ -109,6 +109,7 @@ namespace Mesen.GUI.Debugger case SnesMemoryType.CpuMemory: type = "CPU"; break; case SnesMemoryType.SpcMemory: type = "SPC"; break; case SnesMemoryType.Sa1Memory: type = "SA1"; break; + case SnesMemoryType.GsuMemory: type = "GSU"; break; case SnesMemoryType.PrgRom: type = "PRG"; break; case SnesMemoryType.WorkRam: type = "WRAM"; break; @@ -121,6 +122,7 @@ namespace Mesen.GUI.Debugger case SnesMemoryType.SpcRom: type = "ROM"; break; case SnesMemoryType.Sa1InternalRam: type = "IRAM"; break; + case SnesMemoryType.GsuWorkRam: type = "GWRAM"; break; case SnesMemoryType.Register: type = "REG"; break; } diff --git a/UI/Debugger/Breakpoints/frmBreakpoint.cs b/UI/Debugger/Breakpoints/frmBreakpoint.cs index b2479aa..93f9404 100644 --- a/UI/Debugger/Breakpoints/frmBreakpoint.cs +++ b/UI/Debugger/Breakpoints/frmBreakpoint.cs @@ -37,14 +37,14 @@ namespace Mesen.GUI.Debugger _cpuType = breakpoint.CpuType; cboBreakpointType.Items.Clear(); - if(_cpuType == CpuType.Cpu || _cpuType == CpuType.Sa1) { + if(_cpuType == CpuType.Cpu || _cpuType == CpuType.Sa1 || _cpuType == CpuType.Gsu) { cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(_cpuType.ToMemoryType())); cboBreakpointType.Items.Add("-"); if(DebugApi.GetMemorySize(SnesMemoryType.PrgRom) > 0) { cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.PrgRom)); } - if(DebugApi.GetMemorySize(SnesMemoryType.WorkRam) > 0) { + if(_cpuType == CpuType.Cpu && DebugApi.GetMemorySize(SnesMemoryType.WorkRam) > 0) { cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.WorkRam)); } if(DebugApi.GetMemorySize(SnesMemoryType.SaveRam) > 0) { @@ -53,6 +53,9 @@ namespace Mesen.GUI.Debugger if(DebugApi.GetMemorySize(SnesMemoryType.Sa1InternalRam) > 0) { cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Sa1InternalRam)); } + if(DebugApi.GetMemorySize(SnesMemoryType.GsuWorkRam) > 0) { + cboBreakpointType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GsuWorkRam)); + } if(_cpuType == CpuType.Cpu) { if(cboBreakpointType.Items.Count > 2) { diff --git a/UI/Debugger/Code/GsuDisassemblyManager.cs b/UI/Debugger/Code/GsuDisassemblyManager.cs new file mode 100644 index 0000000..490b0a1 --- /dev/null +++ b/UI/Debugger/Code/GsuDisassemblyManager.cs @@ -0,0 +1,29 @@ +using Mesen.GUI.Debugger.Controls; +using Mesen.GUI.Debugger.Integration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.GUI.Debugger.Code +{ + public class GsuDisassemblyManager : CpuDisassemblyManager + { + public override CpuType CpuType { get { return CpuType.Gsu; } } + public override SnesMemoryType RelativeMemoryType { get { return SnesMemoryType.GsuMemory; } } + public override int AddressSize { get { return 6; } } + public override int ByteCodeSize { get { return 3; } } + public override bool AllowSourceView { get { return false; } } + + public override void RefreshCode(DbgImporter symbolProvider, DbgImporter.FileInfo file) + { + this._provider = new CodeDataProvider(CpuType.Gsu); + } + + protected override int GetFullAddress(int address, int length) + { + return address; + } + } +} diff --git a/UI/Debugger/Code/GsuLineStyleProvider.cs b/UI/Debugger/Code/GsuLineStyleProvider.cs new file mode 100644 index 0000000..d3e1f2b --- /dev/null +++ b/UI/Debugger/Code/GsuLineStyleProvider.cs @@ -0,0 +1,64 @@ +using Mesen.GUI.Config; +using Mesen.GUI.Debugger.Controls; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mesen.GUI.Debugger.Code +{ + public class GsuLineStyleProvider : BaseStyleProvider + { + public GsuLineStyleProvider() + { + } + + public override string GetLineComment(int lineNumber) + { + return null; + } + + public static void ConfigureActiveStatement(LineProperties props) + { + props.FgColor = Color.Black; + props.TextBgColor = ConfigManager.Config.Debug.Debugger.CodeActiveStatementColor; + props.Symbol |= LineSymbol.Arrow; + } + + public override LineProperties GetLineStyle(CodeLineData lineData, int lineIndex) + { + DebuggerInfo cfg = ConfigManager.Config.Debug.Debugger; + LineProperties props = new LineProperties(); + + if(lineData.Address >= 0) { + GetBreakpointLineProperties(props, lineData.Address); + } + + bool isActiveStatement = ActiveAddress.HasValue && ActiveAddress.Value == lineData.Address; + if(isActiveStatement) { + ConfigureActiveStatement(props); + } + + if(lineData.Flags.HasFlag(LineFlags.VerifiedData)) { + props.LineBgColor = cfg.CodeVerifiedDataColor; + } else if(!lineData.Flags.HasFlag(LineFlags.VerifiedCode)) { + props.LineBgColor = cfg.CodeUnidentifiedDataColor; + } + + return props; + } + + private void GetBreakpointLineProperties(LineProperties props, int cpuAddress) + { + AddressInfo absAddress = DebugApi.GetAbsoluteAddress(new AddressInfo() { Address = cpuAddress, Type = SnesMemoryType.GsuMemory }); + foreach(Breakpoint breakpoint in BreakpointManager.Breakpoints) { + if(breakpoint.Matches((uint)cpuAddress, SnesMemoryType.GsuMemory, CpuType.Gsu) || (absAddress.Address >= 0 && breakpoint.Matches((uint)absAddress.Address, absAddress.Type, CpuType.Gsu))) { + SetBreakpointLineProperties(props, breakpoint); + return; + } + } + } + } +} diff --git a/UI/Debugger/Config/DebuggerShortcutsConfig.cs b/UI/Debugger/Config/DebuggerShortcutsConfig.cs index a3287dd..a3dd00b 100644 --- a/UI/Debugger/Config/DebuggerShortcutsConfig.cs +++ b/UI/Debugger/Config/DebuggerShortcutsConfig.cs @@ -77,6 +77,8 @@ namespace Mesen.GUI.Config public XmlKeys OpenSpcDebugger = Keys.Control | Keys.F; [ShortcutName("Open SA-1 Debugger")] public XmlKeys OpenSa1Debugger = Keys.None; + [ShortcutName("Open GSU Debugger")] + public XmlKeys OpenGsuDebugger = Keys.None; [ShortcutName("Open Event Viewer")] public XmlKeys OpenEventViewer = Keys.Control | Keys.E; [ShortcutName("Open Memory Tools")] diff --git a/UI/Debugger/Config/TraceLoggerInfo.cs b/UI/Debugger/Config/TraceLoggerInfo.cs index 605f106..8148395 100644 --- a/UI/Debugger/Config/TraceLoggerInfo.cs +++ b/UI/Debugger/Config/TraceLoggerInfo.cs @@ -49,6 +49,7 @@ namespace Mesen.GUI.Config public bool LogSpc; public bool LogNecDsp; public bool LogSa1; + public bool LogGsu; public bool ShowByteCode; public bool ShowRegisters; diff --git a/UI/Debugger/Controls/ctrlGsuStatus.Designer.cs b/UI/Debugger/Controls/ctrlGsuStatus.Designer.cs new file mode 100644 index 0000000..1d031cf --- /dev/null +++ b/UI/Debugger/Controls/ctrlGsuStatus.Designer.cs @@ -0,0 +1,778 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class ctrlGsuStatus + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.grpSpc = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.label1 = new System.Windows.Forms.Label(); + this.lblR0 = new System.Windows.Forms.Label(); + this.txtR0 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtR1 = new System.Windows.Forms.TextBox(); + this.txtR2 = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.txtR3 = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.txtR4 = new System.Windows.Forms.TextBox(); + this.txtR8 = new System.Windows.Forms.TextBox(); + this.txtR12 = new System.Windows.Forms.TextBox(); + this.txtR5 = new System.Windows.Forms.TextBox(); + this.txtR9 = new System.Windows.Forms.TextBox(); + this.txtR13 = new System.Windows.Forms.TextBox(); + this.txtR6 = new System.Windows.Forms.TextBox(); + this.txtR10 = new System.Windows.Forms.TextBox(); + this.txtR14 = new System.Windows.Forms.TextBox(); + this.txtR7 = new System.Windows.Forms.TextBox(); + this.txtR11 = new System.Windows.Forms.TextBox(); + this.txtR15 = new System.Windows.Forms.TextBox(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.txtSrc = new System.Windows.Forms.TextBox(); + this.txtDest = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.txtSFR = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.chkPrefix = new System.Windows.Forms.CheckBox(); + this.chkAlt2 = new System.Windows.Forms.CheckBox(); + this.chkZero = new System.Windows.Forms.CheckBox(); + this.chkCarry = new System.Windows.Forms.CheckBox(); + this.chkNegative = new System.Windows.Forms.CheckBox(); + this.chkOverflow = new System.Windows.Forms.CheckBox(); + this.chkAlt1 = new System.Windows.Forms.CheckBox(); + this.chkIrq = new System.Windows.Forms.CheckBox(); + this.chkRomRead = new System.Windows.Forms.CheckBox(); + this.chkRunning = new System.Windows.Forms.CheckBox(); + this.label19 = new System.Windows.Forms.Label(); + this.txtProgramBank = new System.Windows.Forms.TextBox(); + this.txtRamBank = new System.Windows.Forms.TextBox(); + this.txtRomBank = new System.Windows.Forms.TextBox(); + this.label20 = new System.Windows.Forms.Label(); + this.label21 = new System.Windows.Forms.Label(); + this.grpSpc.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.SuspendLayout(); + // + // grpSpc + // + this.grpSpc.Controls.Add(this.tableLayoutPanel1); + this.grpSpc.Dock = System.Windows.Forms.DockStyle.Top; + this.grpSpc.Location = new System.Drawing.Point(0, 0); + this.grpSpc.Name = "grpSpc"; + this.grpSpc.Size = new System.Drawing.Size(342, 226); + this.grpSpc.TabIndex = 0; + this.grpSpc.TabStop = false; + this.grpSpc.Text = "GSU (Super FX)"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 9; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.label1, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.lblR0, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtR0, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.label2, 4, 0); + this.tableLayoutPanel1.Controls.Add(this.txtR1, 3, 0); + this.tableLayoutPanel1.Controls.Add(this.txtR2, 5, 0); + this.tableLayoutPanel1.Controls.Add(this.label6, 6, 0); + this.tableLayoutPanel1.Controls.Add(this.txtR3, 7, 0); + this.tableLayoutPanel1.Controls.Add(this.label3, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.label4, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.label5, 2, 1); + this.tableLayoutPanel1.Controls.Add(this.label8, 4, 1); + this.tableLayoutPanel1.Controls.Add(this.label9, 6, 1); + this.tableLayoutPanel1.Controls.Add(this.label10, 2, 2); + this.tableLayoutPanel1.Controls.Add(this.label11, 4, 2); + this.tableLayoutPanel1.Controls.Add(this.label12, 6, 2); + this.tableLayoutPanel1.Controls.Add(this.label13, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.label14, 2, 3); + this.tableLayoutPanel1.Controls.Add(this.label15, 4, 3); + this.tableLayoutPanel1.Controls.Add(this.label16, 6, 3); + this.tableLayoutPanel1.Controls.Add(this.txtR4, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.txtR8, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.txtR12, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.txtR5, 3, 1); + this.tableLayoutPanel1.Controls.Add(this.txtR9, 3, 2); + this.tableLayoutPanel1.Controls.Add(this.txtR13, 3, 3); + this.tableLayoutPanel1.Controls.Add(this.txtR6, 5, 1); + this.tableLayoutPanel1.Controls.Add(this.txtR10, 5, 2); + this.tableLayoutPanel1.Controls.Add(this.txtR14, 5, 3); + this.tableLayoutPanel1.Controls.Add(this.txtR7, 7, 1); + this.tableLayoutPanel1.Controls.Add(this.txtR11, 7, 2); + this.tableLayoutPanel1.Controls.Add(this.txtR15, 7, 3); + this.tableLayoutPanel1.Controls.Add(this.label17, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.label18, 2, 4); + this.tableLayoutPanel1.Controls.Add(this.txtSrc, 1, 4); + this.tableLayoutPanel1.Controls.Add(this.txtDest, 3, 4); + this.tableLayoutPanel1.Controls.Add(this.label7, 0, 5); + this.tableLayoutPanel1.Controls.Add(this.txtSFR, 1, 5); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 1, 7); + this.tableLayoutPanel1.Controls.Add(this.label19, 6, 4); + this.tableLayoutPanel1.Controls.Add(this.txtProgramBank, 7, 4); + this.tableLayoutPanel1.Controls.Add(this.txtRamBank, 7, 5); + this.tableLayoutPanel1.Controls.Add(this.txtRomBank, 5, 5); + this.tableLayoutPanel1.Controls.Add(this.label20, 6, 5); + this.tableLayoutPanel1.Controls.Add(this.label21, 4, 5); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 10; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(336, 207); + this.tableLayoutPanel1.TabIndex = 0; + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(87, 6); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(24, 13); + this.label1.TabIndex = 2; + this.label1.Text = "R1:"; + // + // lblR0 + // + this.lblR0.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblR0.AutoSize = true; + this.lblR0.Location = new System.Drawing.Point(3, 6); + this.lblR0.Name = "lblR0"; + this.lblR0.Size = new System.Drawing.Size(24, 13); + this.lblR0.TabIndex = 0; + this.lblR0.Text = "R0:"; + // + // txtR0 + // + this.txtR0.Location = new System.Drawing.Point(41, 3); + this.txtR0.Name = "txtR0"; + this.txtR0.Size = new System.Drawing.Size(40, 20); + this.txtR0.TabIndex = 1; + this.txtR0.Text = "DDDD"; + // + // label2 + // + this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(171, 6); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(24, 13); + this.label2.TabIndex = 3; + this.label2.Text = "R2:"; + // + // txtR1 + // + this.txtR1.Location = new System.Drawing.Point(125, 3); + this.txtR1.Name = "txtR1"; + this.txtR1.Size = new System.Drawing.Size(40, 20); + this.txtR1.TabIndex = 4; + // + // txtR2 + // + this.txtR2.Location = new System.Drawing.Point(209, 3); + this.txtR2.Name = "txtR2"; + this.txtR2.Size = new System.Drawing.Size(40, 20); + this.txtR2.TabIndex = 5; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(255, 6); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(24, 13); + this.label6.TabIndex = 12; + this.label6.Text = "R3:"; + // + // txtR3 + // + this.txtR3.Location = new System.Drawing.Point(292, 3); + this.txtR3.Name = "txtR3"; + this.txtR3.Size = new System.Drawing.Size(40, 20); + this.txtR3.TabIndex = 13; + this.txtR3.Text = "DDDD"; + // + // label3 + // + this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 32); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(24, 13); + this.label3.TabIndex = 17; + this.label3.Text = "R4:"; + // + // label4 + // + this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 58); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(24, 13); + this.label4.TabIndex = 18; + this.label4.Text = "R8:"; + // + // label5 + // + this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(87, 32); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(24, 13); + this.label5.TabIndex = 19; + this.label5.Text = "R5:"; + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(171, 32); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(24, 13); + this.label8.TabIndex = 20; + this.label8.Text = "R6:"; + // + // label9 + // + this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(255, 32); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(24, 13); + this.label9.TabIndex = 21; + this.label9.Text = "R7:"; + // + // label10 + // + this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(87, 58); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(24, 13); + this.label10.TabIndex = 22; + this.label10.Text = "R9:"; + // + // label11 + // + this.label11.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(171, 58); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(30, 13); + this.label11.TabIndex = 23; + this.label11.Text = "R10:"; + // + // label12 + // + this.label12.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(255, 58); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(30, 13); + this.label12.TabIndex = 24; + this.label12.Text = "R11:"; + // + // label13 + // + this.label13.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(3, 84); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(30, 13); + this.label13.TabIndex = 25; + this.label13.Text = "R12:"; + // + // label14 + // + this.label14.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(87, 84); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(30, 13); + this.label14.TabIndex = 26; + this.label14.Text = "R13:"; + // + // label15 + // + this.label15.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(171, 84); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(30, 13); + this.label15.TabIndex = 27; + this.label15.Text = "R14:"; + // + // label16 + // + this.label16.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(255, 84); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(30, 13); + this.label16.TabIndex = 28; + this.label16.Text = "R15:"; + // + // txtR4 + // + this.txtR4.Location = new System.Drawing.Point(41, 29); + this.txtR4.Name = "txtR4"; + this.txtR4.Size = new System.Drawing.Size(40, 20); + this.txtR4.TabIndex = 29; + this.txtR4.Text = "DDDD"; + // + // txtR8 + // + this.txtR8.Location = new System.Drawing.Point(41, 55); + this.txtR8.Name = "txtR8"; + this.txtR8.Size = new System.Drawing.Size(40, 20); + this.txtR8.TabIndex = 30; + this.txtR8.Text = "DDDD"; + // + // txtR12 + // + this.txtR12.Location = new System.Drawing.Point(41, 81); + this.txtR12.Name = "txtR12"; + this.txtR12.Size = new System.Drawing.Size(40, 20); + this.txtR12.TabIndex = 31; + this.txtR12.Text = "DDDD"; + // + // txtR5 + // + this.txtR5.Location = new System.Drawing.Point(125, 29); + this.txtR5.Name = "txtR5"; + this.txtR5.Size = new System.Drawing.Size(40, 20); + this.txtR5.TabIndex = 32; + this.txtR5.Text = "DDDD"; + // + // txtR9 + // + this.txtR9.Location = new System.Drawing.Point(125, 55); + this.txtR9.Name = "txtR9"; + this.txtR9.Size = new System.Drawing.Size(40, 20); + this.txtR9.TabIndex = 33; + this.txtR9.Text = "DDDD"; + // + // txtR13 + // + this.txtR13.Location = new System.Drawing.Point(125, 81); + this.txtR13.Name = "txtR13"; + this.txtR13.Size = new System.Drawing.Size(40, 20); + this.txtR13.TabIndex = 34; + this.txtR13.Text = "DDDD"; + // + // txtR6 + // + this.txtR6.Location = new System.Drawing.Point(209, 29); + this.txtR6.Name = "txtR6"; + this.txtR6.Size = new System.Drawing.Size(40, 20); + this.txtR6.TabIndex = 35; + this.txtR6.Text = "DDDD"; + // + // txtR10 + // + this.txtR10.Location = new System.Drawing.Point(209, 55); + this.txtR10.Name = "txtR10"; + this.txtR10.Size = new System.Drawing.Size(40, 20); + this.txtR10.TabIndex = 36; + this.txtR10.Text = "DDDD"; + // + // txtR14 + // + this.txtR14.Location = new System.Drawing.Point(209, 81); + this.txtR14.Name = "txtR14"; + this.txtR14.Size = new System.Drawing.Size(40, 20); + this.txtR14.TabIndex = 37; + this.txtR14.Text = "DDDD"; + // + // txtR7 + // + this.txtR7.Location = new System.Drawing.Point(292, 29); + this.txtR7.Name = "txtR7"; + this.txtR7.Size = new System.Drawing.Size(40, 20); + this.txtR7.TabIndex = 38; + this.txtR7.Text = "DDDD"; + // + // txtR11 + // + this.txtR11.Location = new System.Drawing.Point(292, 55); + this.txtR11.Name = "txtR11"; + this.txtR11.Size = new System.Drawing.Size(40, 20); + this.txtR11.TabIndex = 39; + this.txtR11.Text = "DDDD"; + // + // txtR15 + // + this.txtR15.Location = new System.Drawing.Point(292, 81); + this.txtR15.Name = "txtR15"; + this.txtR15.Size = new System.Drawing.Size(40, 20); + this.txtR15.TabIndex = 40; + this.txtR15.Text = "DDDD"; + // + // label17 + // + this.label17.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(3, 110); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(32, 13); + this.label17.TabIndex = 41; + this.label17.Text = "SRC:"; + // + // label18 + // + this.label18.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(87, 110); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(32, 13); + this.label18.TabIndex = 42; + this.label18.Text = "DST:"; + // + // txtSrc + // + this.txtSrc.Location = new System.Drawing.Point(41, 107); + this.txtSrc.Name = "txtSrc"; + this.txtSrc.Size = new System.Drawing.Size(40, 20); + this.txtSrc.TabIndex = 43; + // + // txtDest + // + this.txtDest.Location = new System.Drawing.Point(125, 107); + this.txtDest.Name = "txtDest"; + this.txtDest.Size = new System.Drawing.Size(40, 20); + this.txtDest.TabIndex = 44; + // + // label7 + // + this.label7.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 136); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(31, 13); + this.label7.TabIndex = 14; + this.label7.Text = "SFR:"; + // + // txtSFR + // + this.txtSFR.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.txtSFR.Location = new System.Drawing.Point(41, 133); + this.txtSFR.Name = "txtSFR"; + this.txtSFR.Size = new System.Drawing.Size(40, 20); + this.txtSFR.TabIndex = 15; + this.txtSFR.Text = "DD"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 6; + this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 7); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Controls.Add(this.chkPrefix, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.chkAlt2, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.chkZero, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.chkCarry, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.chkNegative, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.chkOverflow, 3, 0); + this.tableLayoutPanel2.Controls.Add(this.chkAlt1, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.chkIrq, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.chkRomRead, 4, 0); + this.tableLayoutPanel2.Controls.Add(this.chkRunning, 4, 1); + this.tableLayoutPanel2.Location = new System.Drawing.Point(41, 159); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 2; + this.tableLayoutPanel1.SetRowSpan(this.tableLayoutPanel2, 2); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.Size = new System.Drawing.Size(288, 46); + this.tableLayoutPanel2.TabIndex = 16; + // + // chkPrefix + // + this.chkPrefix.AutoSize = true; + this.chkPrefix.Location = new System.Drawing.Point(103, 26); + this.chkPrefix.Name = "chkPrefix"; + this.chkPrefix.Size = new System.Drawing.Size(33, 17); + this.chkPrefix.TabIndex = 27; + this.chkPrefix.Text = "B"; + this.chkPrefix.UseVisualStyleBackColor = true; + // + // chkAlt2 + // + this.chkAlt2.AutoSize = true; + this.chkAlt2.Location = new System.Drawing.Point(53, 26); + this.chkAlt2.Name = "chkAlt2"; + this.chkAlt2.Size = new System.Drawing.Size(44, 17); + this.chkAlt2.TabIndex = 26; + this.chkAlt2.Text = "Alt2"; + this.chkAlt2.UseVisualStyleBackColor = true; + // + // chkZero + // + this.chkZero.AutoSize = true; + this.chkZero.Location = new System.Drawing.Point(3, 3); + this.chkZero.Name = "chkZero"; + this.chkZero.Size = new System.Drawing.Size(33, 17); + this.chkZero.TabIndex = 21; + this.chkZero.Text = "Z"; + this.chkZero.UseVisualStyleBackColor = true; + // + // chkCarry + // + this.chkCarry.AutoSize = true; + this.chkCarry.Location = new System.Drawing.Point(53, 3); + this.chkCarry.Name = "chkCarry"; + this.chkCarry.Size = new System.Drawing.Size(33, 17); + this.chkCarry.TabIndex = 23; + this.chkCarry.Text = "C"; + this.chkCarry.UseVisualStyleBackColor = true; + // + // chkNegative + // + this.chkNegative.AutoSize = true; + this.chkNegative.Location = new System.Drawing.Point(103, 3); + this.chkNegative.Name = "chkNegative"; + this.chkNegative.Size = new System.Drawing.Size(33, 17); + this.chkNegative.TabIndex = 17; + this.chkNegative.Text = "S"; + this.chkNegative.UseVisualStyleBackColor = true; + // + // chkOverflow + // + this.chkOverflow.AutoSize = true; + this.chkOverflow.Location = new System.Drawing.Point(142, 3); + this.chkOverflow.Name = "chkOverflow"; + this.chkOverflow.Size = new System.Drawing.Size(33, 17); + this.chkOverflow.TabIndex = 20; + this.chkOverflow.Text = "V"; + this.chkOverflow.UseVisualStyleBackColor = true; + // + // chkAlt1 + // + this.chkAlt1.AutoSize = true; + this.chkAlt1.Location = new System.Drawing.Point(3, 26); + this.chkAlt1.Name = "chkAlt1"; + this.chkAlt1.Size = new System.Drawing.Size(44, 17); + this.chkAlt1.TabIndex = 19; + this.chkAlt1.Text = "Alt1"; + this.chkAlt1.UseVisualStyleBackColor = true; + // + // chkIrq + // + this.chkIrq.AutoSize = true; + this.chkIrq.Location = new System.Drawing.Point(142, 26); + this.chkIrq.Name = "chkIrq"; + this.chkIrq.Size = new System.Drawing.Size(45, 17); + this.chkIrq.TabIndex = 18; + this.chkIrq.Text = "IRQ"; + this.chkIrq.UseVisualStyleBackColor = true; + // + // chkRomRead + // + this.chkRomRead.AutoSize = true; + this.chkRomRead.Location = new System.Drawing.Point(193, 3); + this.chkRomRead.Name = "chkRomRead"; + this.chkRomRead.Size = new System.Drawing.Size(80, 17); + this.chkRomRead.TabIndex = 24; + this.chkRomRead.Text = "ROM Read"; + this.chkRomRead.UseVisualStyleBackColor = true; + // + // chkRunning + // + this.chkRunning.AutoSize = true; + this.chkRunning.Location = new System.Drawing.Point(193, 26); + this.chkRunning.Name = "chkRunning"; + this.chkRunning.Size = new System.Drawing.Size(66, 17); + this.chkRunning.TabIndex = 25; + this.chkRunning.Text = "Running"; + this.chkRunning.UseVisualStyleBackColor = true; + // + // label19 + // + this.label19.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(255, 110); + this.label19.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(32, 13); + this.label19.TabIndex = 45; + this.label19.Text = "PBR:"; + // + // txtProgramBank + // + this.txtProgramBank.Location = new System.Drawing.Point(292, 107); + this.txtProgramBank.Name = "txtProgramBank"; + this.txtProgramBank.Size = new System.Drawing.Size(25, 20); + this.txtProgramBank.TabIndex = 46; + this.txtProgramBank.Text = "DD"; + // + // txtRamBank + // + this.txtRamBank.Location = new System.Drawing.Point(292, 133); + this.txtRamBank.Name = "txtRamBank"; + this.txtRamBank.Size = new System.Drawing.Size(25, 20); + this.txtRamBank.TabIndex = 49; + this.txtRamBank.Text = "DD"; + // + // txtRomBank + // + this.txtRomBank.Location = new System.Drawing.Point(209, 133); + this.txtRomBank.Name = "txtRomBank"; + this.txtRomBank.Size = new System.Drawing.Size(25, 20); + this.txtRomBank.TabIndex = 50; + this.txtRomBank.Text = "DD"; + // + // label20 + // + this.label20.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(255, 136); + this.label20.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(34, 13); + this.label20.TabIndex = 47; + this.label20.Text = "RAM:"; + // + // label21 + // + this.label21.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(171, 136); + this.label21.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(35, 13); + this.label21.TabIndex = 48; + this.label21.Text = "ROM:"; + // + // ctrlGsuStatus + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.grpSpc); + this.Name = "ctrlGsuStatus"; + this.Size = new System.Drawing.Size(342, 225); + this.grpSpc.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox grpSpc; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblR0; + private System.Windows.Forms.TextBox txtR0; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtR1; + private System.Windows.Forms.TextBox txtR2; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox txtR3; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox txtSFR; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.CheckBox chkRunning; + private System.Windows.Forms.CheckBox chkRomRead; + private System.Windows.Forms.CheckBox chkCarry; + private System.Windows.Forms.CheckBox chkZero; + private System.Windows.Forms.CheckBox chkIrq; + private System.Windows.Forms.CheckBox chkAlt1; + private System.Windows.Forms.CheckBox chkNegative; + private System.Windows.Forms.CheckBox chkOverflow; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.TextBox txtR4; + private System.Windows.Forms.TextBox txtR8; + private System.Windows.Forms.TextBox txtR12; + private System.Windows.Forms.TextBox txtR5; + private System.Windows.Forms.TextBox txtR9; + private System.Windows.Forms.TextBox txtR13; + private System.Windows.Forms.TextBox txtR6; + private System.Windows.Forms.TextBox txtR10; + private System.Windows.Forms.TextBox txtR14; + private System.Windows.Forms.TextBox txtR7; + private System.Windows.Forms.TextBox txtR11; + private System.Windows.Forms.TextBox txtR15; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.TextBox txtSrc; + private System.Windows.Forms.TextBox txtDest; + private System.Windows.Forms.CheckBox chkAlt2; + private System.Windows.Forms.CheckBox chkPrefix; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.TextBox txtProgramBank; + private System.Windows.Forms.TextBox txtRamBank; + private System.Windows.Forms.TextBox txtRomBank; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.Label label21; + } +} diff --git a/UI/Debugger/Controls/ctrlGsuStatus.cs b/UI/Debugger/Controls/ctrlGsuStatus.cs new file mode 100644 index 0000000..b0d7bdf --- /dev/null +++ b/UI/Debugger/Controls/ctrlGsuStatus.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Mesen.GUI.Controls; +using Mesen.GUI.Forms; + +namespace Mesen.GUI.Debugger.Controls +{ + public partial class ctrlGsuStatus : BaseControl + { + public ctrlGsuStatus() + { + InitializeComponent(); + if(IsDesignMode) { + return; + } + } + + public void UpdateStatus(GsuState state) + { + txtR0.Text = state.R[0].ToString("X4"); + txtR1.Text = state.R[1].ToString("X4"); + txtR2.Text = state.R[2].ToString("X4"); + txtR3.Text = state.R[3].ToString("X4"); + txtR4.Text = state.R[4].ToString("X4"); + txtR5.Text = state.R[5].ToString("X4"); + txtR6.Text = state.R[6].ToString("X4"); + txtR7.Text = state.R[7].ToString("X4"); + txtR8.Text = state.R[8].ToString("X4"); + txtR9.Text = state.R[9].ToString("X4"); + txtR10.Text = state.R[10].ToString("X4"); + txtR11.Text = state.R[11].ToString("X4"); + txtR12.Text = state.R[12].ToString("X4"); + txtR13.Text = state.R[13].ToString("X4"); + txtR14.Text = state.R[14].ToString("X4"); + txtR15.Text = state.R[15].ToString("X4"); + + txtProgramBank.Text = state.ProgramBank.ToString("X2"); + txtRamBank.Text = state.RamBank.ToString("X2"); + txtRomBank.Text = state.RomBank.ToString("X2"); + + txtSrc.Text = state.SrcReg.ToString(); + txtDest.Text = state.DestReg.ToString(); + + chkAlt1.Checked = state.SFR.Alt1; + chkAlt2.Checked = state.SFR.Alt2; + chkPrefix.Checked = state.SFR.Prefix; + chkIrq.Checked = state.SFR.Irq; + chkRunning.Checked = state.SFR.Running; + chkNegative.Checked = state.SFR.Sign; + chkZero.Checked = state.SFR.Zero; + chkOverflow.Checked = state.SFR.Overflow; + chkCarry.Checked = state.SFR.Carry; + chkRomRead.Checked = state.SFR.RomReadPending; + + txtSFR.Text = GetFlags(ref state).ToString("X4"); + } + + private UInt16 GetFlags(ref GsuState state) + { + return (UInt16)( + (state.SFR.Zero ? 2 : 0) | + (state.SFR.Carry ? 4 : 0) | + (state.SFR.Sign ? 8 : 0) | + (state.SFR.Overflow ? 0x10 : 0) | + (state.SFR.Running ? 0x20 : 0) | + (state.SFR.RomReadPending ? 0x40 : 0) | + (state.SFR.Alt1 ? 0x100 : 0) | + (state.SFR.Alt2 ? 0x200 : 0) | + (state.SFR.ImmLow ? 0x400 : 0) | + (state.SFR.ImmHigh ? 0x800 : 0) | + (state.SFR.Prefix ? 0x1000 : 0) | + (state.SFR.Irq ? 0x8000 : 0) + ); + } + } +} diff --git a/UI/Debugger/Controls/ctrlGsuStatus.resx b/UI/Debugger/Controls/ctrlGsuStatus.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/UI/Debugger/Controls/ctrlGsuStatus.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/UI/Debugger/DebugWindowManager.cs b/UI/Debugger/DebugWindowManager.cs index 6ea216c..e6216e2 100644 --- a/UI/Debugger/DebugWindowManager.cs +++ b/UI/Debugger/DebugWindowManager.cs @@ -29,6 +29,7 @@ namespace Mesen.GUI.Debugger case DebugWindow.Debugger: frm = new frmDebugger(CpuType.Cpu); frm.Icon = Properties.Resources.Debugger; break; case DebugWindow.SpcDebugger: frm = new frmDebugger(CpuType.Spc); frm.Icon = Properties.Resources.SpcDebugger; break; case DebugWindow.Sa1Debugger: frm = new frmDebugger(CpuType.Sa1); frm.Icon = Properties.Resources.Sa1Debugger; break; + case DebugWindow.GsuDebugger: frm = new frmDebugger(CpuType.Gsu); frm.Icon = Properties.Resources.GsuDebugger; break; case DebugWindow.TraceLogger: frm = new frmTraceLogger(); frm.Icon = Properties.Resources.LogWindow; break; case DebugWindow.MemoryTools: frm = new frmMemoryTools(); frm.Icon = Properties.Resources.CheatCode; break; case DebugWindow.TileViewer: frm = new frmTileViewer(); frm.Icon = Properties.Resources.VerticalLayout; break; @@ -82,6 +83,7 @@ namespace Mesen.GUI.Debugger case CpuType.Cpu: return (frmDebugger)OpenDebugWindow(DebugWindow.Debugger); case CpuType.Spc: return (frmDebugger)OpenDebugWindow(DebugWindow.SpcDebugger); case CpuType.Sa1: return (frmDebugger)OpenDebugWindow(DebugWindow.Sa1Debugger); + case CpuType.Gsu: return (frmDebugger)OpenDebugWindow(DebugWindow.GsuDebugger); } throw new Exception("Invalid CPU type"); } @@ -114,6 +116,7 @@ namespace Mesen.GUI.Debugger case DebugWindow.Debugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Cpu); case DebugWindow.SpcDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Spc); case DebugWindow.Sa1Debugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Sa1); + case DebugWindow.GsuDebugger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmDebugger) && ((frmDebugger)form).CpuType == CpuType.Gsu); case DebugWindow.TraceLogger: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmTraceLogger)); case DebugWindow.EventViewer: return _openedWindows.ToList().Find((form) => form.GetType() == typeof(frmEventViewer)); } @@ -153,6 +156,7 @@ namespace Mesen.GUI.Debugger Debugger, SpcDebugger, Sa1Debugger, + GsuDebugger, MemoryTools, TraceLogger, TileViewer, diff --git a/UI/Debugger/Labels/LabelManager.cs b/UI/Debugger/Labels/LabelManager.cs index 0a00fa8..85a5fae 100644 --- a/UI/Debugger/Labels/LabelManager.cs +++ b/UI/Debugger/Labels/LabelManager.cs @@ -68,9 +68,9 @@ namespace Mesen.GUI.Debugger.Labels return _labels.Where((lbl) => lbl.Matches(cpu)).ToList(); } - private static UInt64 GetKey(UInt32 address, SnesMemoryType SnesMemoryType) + private static UInt64 GetKey(UInt32 address, SnesMemoryType memType) { - switch(SnesMemoryType) { + switch(memType) { case SnesMemoryType.PrgRom: return address | ((ulong)1 << 32); case SnesMemoryType.WorkRam: return address | ((ulong)2 << 32); case SnesMemoryType.SaveRam: return address | ((ulong)3 << 32); @@ -78,6 +78,7 @@ namespace Mesen.GUI.Debugger.Labels case SnesMemoryType.SpcRam: return address | ((ulong)5 << 32); case SnesMemoryType.SpcRom: return address | ((ulong)6 << 32); case SnesMemoryType.Sa1InternalRam: return address | ((ulong)7 << 32); + case SnesMemoryType.GsuWorkRam: return address | ((ulong)8 << 32); } throw new Exception("Invalid type"); } diff --git a/UI/Debugger/MemoryTools/frmMemoryTools.cs b/UI/Debugger/MemoryTools/frmMemoryTools.cs index 410d38a..f319852 100644 --- a/UI/Debugger/MemoryTools/frmMemoryTools.cs +++ b/UI/Debugger/MemoryTools/frmMemoryTools.cs @@ -173,6 +173,12 @@ namespace Mesen.GUI.Debugger cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.Sa1InternalRam)); } + if(DebugApi.GetMemorySize(SnesMemoryType.GsuWorkRam) > 0) { + cboMemoryType.Items.Add("-"); + cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GsuMemory)); + cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GsuWorkRam)); + } + cboMemoryType.SelectedIndex = 0; cboMemoryType.SetEnumValue(originalValue); cboMemoryType.SelectedIndexChanged += this.cboMemoryType_SelectedIndexChanged; diff --git a/UI/Debugger/PpuViewer/frmTileViewer.cs b/UI/Debugger/PpuViewer/frmTileViewer.cs index 6a14605..0b16c24 100644 --- a/UI/Debugger/PpuViewer/frmTileViewer.cs +++ b/UI/Debugger/PpuViewer/frmTileViewer.cs @@ -266,6 +266,10 @@ namespace Mesen.GUI.Debugger cboMemoryType.Items.Add("-"); cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.PrgRom)); cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.WorkRam)); + if(DebugApi.GetMemorySize(SnesMemoryType.GsuWorkRam) > 0) { + cboMemoryType.Items.Add("-"); + cboMemoryType.Items.Add(ResourceHelper.GetEnumText(SnesMemoryType.GsuWorkRam)); + } cboMemoryType.SelectedIndex = 0; cboMemoryType.EndUpdate(); diff --git a/UI/Debugger/Workspace/DebugWorkspace.cs b/UI/Debugger/Workspace/DebugWorkspace.cs index f07fe89..6034a5d 100644 --- a/UI/Debugger/Workspace/DebugWorkspace.cs +++ b/UI/Debugger/Workspace/DebugWorkspace.cs @@ -18,6 +18,7 @@ namespace Mesen.GUI.Debugger.Workspace public List WatchValues = new List(); public List SpcWatchValues = new List(); public List Sa1WatchValues = new List(); + public List GsuWatchValues = new List(); public List CpuLabels = new List(); public List SpcLabels = new List(); public List TblMappings = null; diff --git a/UI/Debugger/Workspace/DebugWorkspaceManager.cs b/UI/Debugger/Workspace/DebugWorkspaceManager.cs index 239c026..aa2dead 100644 --- a/UI/Debugger/Workspace/DebugWorkspaceManager.cs +++ b/UI/Debugger/Workspace/DebugWorkspaceManager.cs @@ -26,6 +26,7 @@ namespace Mesen.GUI.Debugger.Workspace _workspace.WatchValues = new List(WatchManager.GetWatchManager(CpuType.Cpu).WatchEntries); _workspace.SpcWatchValues = new List(WatchManager.GetWatchManager(CpuType.Spc).WatchEntries); _workspace.Sa1WatchValues = new List(WatchManager.GetWatchManager(CpuType.Sa1).WatchEntries); + _workspace.GsuWatchValues = new List(WatchManager.GetWatchManager(CpuType.Gsu).WatchEntries); _workspace.Breakpoints = new List(BreakpointManager.Breakpoints); _workspace.CpuLabels = new List(LabelManager.GetLabels(CpuType.Cpu)); _workspace.SpcLabels = new List(LabelManager.GetLabels(CpuType.Spc)); @@ -47,11 +48,13 @@ namespace Mesen.GUI.Debugger.Workspace _workspace.WatchValues = new List(); _workspace.SpcWatchValues = new List(); _workspace.Sa1WatchValues = new List(); + _workspace.GsuWatchValues = new List(); _workspace.CpuLabels = new List(); _workspace.SpcLabels = new List(); WatchManager.GetWatchManager(CpuType.Cpu).WatchEntries = _workspace.WatchValues; WatchManager.GetWatchManager(CpuType.Spc).WatchEntries = _workspace.SpcWatchValues; WatchManager.GetWatchManager(CpuType.Sa1).WatchEntries = _workspace.Sa1WatchValues; + WatchManager.GetWatchManager(CpuType.Gsu).WatchEntries = _workspace.GsuWatchValues; BreakpointManager.SetBreakpoints(_workspace.Breakpoints); LabelManager.SetDefaultLabels(); LabelManager.RefreshLabels(); @@ -85,6 +88,7 @@ namespace Mesen.GUI.Debugger.Workspace WatchManager.GetWatchManager(CpuType.Cpu).WatchEntries = _workspace.WatchValues; WatchManager.GetWatchManager(CpuType.Spc).WatchEntries = _workspace.SpcWatchValues; WatchManager.GetWatchManager(CpuType.Sa1).WatchEntries = _workspace.Sa1WatchValues; + WatchManager.GetWatchManager(CpuType.Gsu).WatchEntries = _workspace.GsuWatchValues; LabelManager.ResetLabels(); LabelManager.SetLabels(_workspace.CpuLabels); diff --git a/UI/Debugger/frmDbgPreferences.cs b/UI/Debugger/frmDbgPreferences.cs index 6fbc493..e4fb5f5 100644 --- a/UI/Debugger/frmDbgPreferences.cs +++ b/UI/Debugger/frmDbgPreferences.cs @@ -59,6 +59,7 @@ namespace Mesen.GUI.Debugger GetMember(nameof(DebuggerShortcutsConfig.OpenSpcDebugger)), GetMember(nameof(DebuggerShortcutsConfig.OpenSa1Debugger)), + GetMember(nameof(DebuggerShortcutsConfig.OpenGsuDebugger)), }; ctrlDbgShortcutsMemoryViewer.Shortcuts = new FieldInfo[] { diff --git a/UI/Debugger/frmDebugger.Designer.cs b/UI/Debugger/frmDebugger.Designer.cs index 9cd517b..5de0692 100644 --- a/UI/Debugger/frmDebugger.Designer.cs +++ b/UI/Debugger/frmDebugger.Designer.cs @@ -116,9 +116,10 @@ this.panel1 = new System.Windows.Forms.Panel(); this.ctrlLabelList = new Mesen.GUI.Debugger.Controls.ctrlLabelList(); this.ctrlPpuStatus = new Mesen.GUI.Debugger.Controls.ctrlPpuStatus(); + this.ctrlGsuStatus = new Mesen.GUI.Debugger.Controls.ctrlGsuStatus(); this.ctrlSpcStatus = new Mesen.GUI.Debugger.Controls.ctrlSpcStatus(); this.ctrlCpuStatus = new Mesen.GUI.Debugger.Controls.ctrlCpuStatus(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tlpBottomPanel = new System.Windows.Forms.TableLayoutPanel(); this.grpWatch = new System.Windows.Forms.GroupBox(); this.picWatchHelp = new System.Windows.Forms.PictureBox(); this.ctrlWatch = new Mesen.GUI.Debugger.ctrlWatch(); @@ -133,7 +134,7 @@ this.ctrlSplitContainer.Panel2.SuspendLayout(); this.ctrlSplitContainer.SuspendLayout(); this.panel1.SuspendLayout(); - this.tableLayoutPanel1.SuspendLayout(); + this.tlpBottomPanel.SuspendLayout(); this.grpWatch.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).BeginInit(); this.grpBreakpoints.SuspendLayout(); @@ -208,7 +209,7 @@ // this.mnuResetCdlLog.Image = global::Mesen.GUI.Properties.Resources.Refresh; this.mnuResetCdlLog.Name = "mnuResetCdlLog"; - this.mnuResetCdlLog.Size = new System.Drawing.Size(152, 22); + this.mnuResetCdlLog.Size = new System.Drawing.Size(122, 22); this.mnuResetCdlLog.Text = "Reset log"; this.mnuResetCdlLog.Click += new System.EventHandler(this.mnuResetCdlLog_Click); // @@ -766,7 +767,7 @@ // // ctrlSplitContainer.Panel2 // - this.ctrlSplitContainer.Panel2.Controls.Add(this.tableLayoutPanel1); + this.ctrlSplitContainer.Panel2.Controls.Add(this.tlpBottomPanel); this.ctrlSplitContainer.Panel2MinSize = 100; this.ctrlSplitContainer.Size = new System.Drawing.Size(832, 595); this.ctrlSplitContainer.SplitterDistance = 433; @@ -776,6 +777,7 @@ // this.panel1.Controls.Add(this.ctrlLabelList); this.panel1.Controls.Add(this.ctrlPpuStatus); + this.panel1.Controls.Add(this.ctrlGsuStatus); this.panel1.Controls.Add(this.ctrlSpcStatus); this.panel1.Controls.Add(this.ctrlCpuStatus); this.panel1.Dock = System.Windows.Forms.DockStyle.Right; @@ -788,20 +790,29 @@ // this.ctrlLabelList.CpuType = Mesen.GUI.CpuType.Cpu; this.ctrlLabelList.Dock = System.Windows.Forms.DockStyle.Fill; - this.ctrlLabelList.Location = new System.Drawing.Point(0, 315); + this.ctrlLabelList.Location = new System.Drawing.Point(0, 551); this.ctrlLabelList.Name = "ctrlLabelList"; - this.ctrlLabelList.Size = new System.Drawing.Size(348, 118); + this.ctrlLabelList.Size = new System.Drawing.Size(348, 0); this.ctrlLabelList.TabIndex = 4; // // ctrlPpuStatus // this.ctrlPpuStatus.Dock = System.Windows.Forms.DockStyle.Top; - this.ctrlPpuStatus.Location = new System.Drawing.Point(0, 268); + this.ctrlPpuStatus.Location = new System.Drawing.Point(0, 504); this.ctrlPpuStatus.Name = "ctrlPpuStatus"; this.ctrlPpuStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.ctrlPpuStatus.Size = new System.Drawing.Size(348, 47); this.ctrlPpuStatus.TabIndex = 3; // + // ctrlGsuStatus + // + this.ctrlGsuStatus.Dock = System.Windows.Forms.DockStyle.Top; + this.ctrlGsuStatus.Location = new System.Drawing.Point(0, 268); + this.ctrlGsuStatus.Name = "ctrlGsuStatus"; + this.ctrlGsuStatus.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.ctrlGsuStatus.Size = new System.Drawing.Size(348, 236); + this.ctrlGsuStatus.TabIndex = 5; + // // ctrlSpcStatus // this.ctrlSpcStatus.Dock = System.Windows.Forms.DockStyle.Top; @@ -820,22 +831,22 @@ this.ctrlCpuStatus.Size = new System.Drawing.Size(348, 148); this.ctrlCpuStatus.TabIndex = 1; // - // tableLayoutPanel1 + // tlpBottomPanel // - this.tableLayoutPanel1.ColumnCount = 3; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); - this.tableLayoutPanel1.Controls.Add(this.grpWatch, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.grpBreakpoints, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.grpCallstack, 2, 0); - this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 1; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.Size = new System.Drawing.Size(832, 158); - this.tableLayoutPanel1.TabIndex = 0; + this.tlpBottomPanel.ColumnCount = 3; + this.tlpBottomPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tlpBottomPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tlpBottomPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tlpBottomPanel.Controls.Add(this.grpWatch, 0, 0); + this.tlpBottomPanel.Controls.Add(this.grpBreakpoints, 1, 0); + this.tlpBottomPanel.Controls.Add(this.grpCallstack, 2, 0); + this.tlpBottomPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpBottomPanel.Location = new System.Drawing.Point(0, 0); + this.tlpBottomPanel.Name = "tlpBottomPanel"; + this.tlpBottomPanel.RowCount = 1; + this.tlpBottomPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpBottomPanel.Size = new System.Drawing.Size(832, 158); + this.tlpBottomPanel.TabIndex = 0; // // grpWatch // @@ -937,7 +948,7 @@ ((System.ComponentModel.ISupportInitialize)(this.ctrlSplitContainer)).EndInit(); this.ctrlSplitContainer.ResumeLayout(false); this.panel1.ResumeLayout(false); - this.tableLayoutPanel1.ResumeLayout(false); + this.tlpBottomPanel.ResumeLayout(false); this.grpWatch.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.picWatchHelp)).EndInit(); this.grpBreakpoints.ResumeLayout(false); @@ -973,7 +984,7 @@ private System.Windows.Forms.ToolStripMenuItem mnuBreakIn; private System.Windows.Forms.ToolStripMenuItem mnuBreakOn; private GUI.Controls.ctrlSplitContainer ctrlSplitContainer; - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.TableLayoutPanel tlpBottomPanel; private ctrlWatch ctrlWatch; private System.Windows.Forms.GroupBox grpWatch; private System.Windows.Forms.GroupBox grpBreakpoints; @@ -1045,5 +1056,6 @@ private System.Windows.Forms.ToolStripMenuItem mnuResetCdlLog; private System.Windows.Forms.ToolStripSeparator toolStripMenuItem13; private System.Windows.Forms.ToolStripMenuItem mnuExit; + private Controls.ctrlGsuStatus ctrlGsuStatus; } } \ No newline at end of file diff --git a/UI/Debugger/frmDebugger.cs b/UI/Debugger/frmDebugger.cs index cd702c4..9485336 100644 --- a/UI/Debugger/frmDebugger.cs +++ b/UI/Debugger/frmDebugger.cs @@ -63,6 +63,18 @@ namespace Mesen.GUI.Debugger ConfigApi.SetDebuggerFlag(DebuggerFlags.Sa1DebuggerEnabled, true); this.Text = "SA-1 Debugger"; break; + + case CpuType.Gsu: + ctrlDisassemblyView.Initialize(new GsuDisassemblyManager(), new GsuLineStyleProvider()); + ConfigApi.SetDebuggerFlag(DebuggerFlags.GsuDebuggerEnabled, true); + this.Text = "GSU Debugger"; + ctrlCallstack.Visible = false; + ctrlLabelList.Visible = false; + mnuStepOver.Visible = false; + mnuStepOut.Visible = false; + mnuStepInto.Text = "Step"; + tlpBottomPanel.ColumnCount = 2; + break; } ctrlBreakpoints.CpuType = _cpuType; @@ -94,6 +106,7 @@ namespace Mesen.GUI.Debugger case CpuType.Cpu: ConfigApi.SetDebuggerFlag(DebuggerFlags.CpuDebuggerEnabled, false); break; case CpuType.Spc: ConfigApi.SetDebuggerFlag(DebuggerFlags.SpcDebuggerEnabled, false); break; case CpuType.Sa1: ConfigApi.SetDebuggerFlag(DebuggerFlags.Sa1DebuggerEnabled, false); break; + case CpuType.Gsu: ConfigApi.SetDebuggerFlag(DebuggerFlags.GsuDebuggerEnabled, false); break; } BreakpointManager.RemoveCpuType(_cpuType); @@ -248,9 +261,15 @@ namespace Mesen.GUI.Debugger private void InitToolbar() { + tsToolbar.AddItemsToToolbar(mnuContinue, mnuBreak, null); + + if(_cpuType != CpuType.Gsu) { + tsToolbar.AddItemsToToolbar(mnuStepInto, mnuStepOver, mnuStepOut, null); + } else { + tsToolbar.AddItemsToToolbar(mnuStepInto, null); + } + tsToolbar.AddItemsToToolbar( - mnuContinue, mnuBreak, null, - mnuStepInto, mnuStepOver, mnuStepOut, null, mnuRunPpuCycle, mnuRunScanline, mnuRunOneFrame, null, mnuToggleBreakpoint, mnuEnableDisableBreakpoint, null, mnuBreakIn, null, mnuBreakOn @@ -338,11 +357,20 @@ namespace Mesen.GUI.Debugger ctrlSpcStatus.Visible = false; } + if(_cpuType == CpuType.Gsu) { + ctrlGsuStatus.UpdateStatus(state.Gsu); + } else { + ctrlGsuStatus.Visible = false; + } + ctrlPpuStatus.UpdateStatus(state); ctrlDisassemblyView.UpdateCode(); ctrlDisassemblyView.SetActiveAddress(activeAddress); ctrlWatch.UpdateWatch(true); - ctrlCallstack.UpdateCallstack(_cpuType); + + if(_cpuType != CpuType.Gsu) { + ctrlCallstack.UpdateCallstack(_cpuType); + } } void ProcessBreakEvent(BreakEvent evt, DebugState state, int activeAddress) @@ -414,6 +442,7 @@ namespace Mesen.GUI.Debugger case CpuType.Cpu: activeAddress = (int)((state.Cpu.K << 16) | state.Cpu.PC); break; case CpuType.Spc: activeAddress = (int)state.Spc.PC; break; case CpuType.Sa1: activeAddress = (int)((state.Sa1.K << 16) | state.Sa1.PC); break; + case CpuType.Gsu: activeAddress = (int)((state.Gsu.ProgramBank << 16) | state.Gsu.R[15]); break; default: throw new Exception("Unsupported cpu type"); } diff --git a/UI/Debugger/frmTraceLogger.Designer.cs b/UI/Debugger/frmTraceLogger.Designer.cs index c70fbf7..10e9105 100644 --- a/UI/Debugger/frmTraceLogger.Designer.cs +++ b/UI/Debugger/frmTraceLogger.Designer.cs @@ -61,9 +61,11 @@ namespace Mesen.GUI.Debugger this.cboStatusFlagFormat = new System.Windows.Forms.ComboBox(); this.chkUseWindowsEol = new System.Windows.Forms.CheckBox(); this.chkExtendZeroPage = new System.Windows.Forms.CheckBox(); + this.lblTarget = new System.Windows.Forms.Label(); + this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); + this.chkLogSa1 = new System.Windows.Forms.CheckBox(); this.chkLogCpu = new System.Windows.Forms.CheckBox(); this.chkLogSpc = new System.Windows.Forms.CheckBox(); - this.lblTarget = new System.Windows.Forms.Label(); this.chkLogNecDsp = new System.Windows.Forms.CheckBox(); this.btnClearLog = new System.Windows.Forms.Button(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); @@ -91,8 +93,7 @@ namespace Mesen.GUI.Debugger this.mnuAutoRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.mnuRefresh = new System.Windows.Forms.ToolStripMenuItem(); - this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); - this.chkLogSa1 = new System.Windows.Forms.CheckBox(); + this.chkLogGsu = new System.Windows.Forms.CheckBox(); this.tableLayoutPanel1.SuspendLayout(); this.grpLogOptions.SuspendLayout(); this.tableLayoutPanel2.SuspendLayout(); @@ -101,11 +102,11 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel4.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.picHelp)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).BeginInit(); + this.tableLayoutPanel6.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); this.grpExecutionLog.SuspendLayout(); this.ctxMenu.SuspendLayout(); this.menuStrip1.SuspendLayout(); - this.tableLayoutPanel6.SuspendLayout(); this.SuspendLayout(); // // tableLayoutPanel1 @@ -541,6 +542,51 @@ namespace Mesen.GUI.Debugger this.chkExtendZeroPage.Visible = false; this.chkExtendZeroPage.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged); // + // lblTarget + // + this.lblTarget.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblTarget.AutoSize = true; + this.lblTarget.Location = new System.Drawing.Point(3, 4); + this.lblTarget.Name = "lblTarget"; + this.lblTarget.Size = new System.Drawing.Size(46, 13); + this.lblTarget.TabIndex = 23; + this.lblTarget.Text = "Targets:"; + // + // tableLayoutPanel6 + // + this.tableLayoutPanel6.ColumnCount = 5; + this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel6, 5); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel6.Controls.Add(this.chkLogSa1, 3, 0); + this.tableLayoutPanel6.Controls.Add(this.chkLogCpu, 0, 0); + this.tableLayoutPanel6.Controls.Add(this.chkLogSpc, 1, 0); + this.tableLayoutPanel6.Controls.Add(this.chkLogNecDsp, 2, 0); + this.tableLayoutPanel6.Controls.Add(this.chkLogGsu, 4, 0); + this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel6.Location = new System.Drawing.Point(81, 0); + this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel6.Name = "tableLayoutPanel6"; + this.tableLayoutPanel6.RowCount = 1; + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel6.Size = new System.Drawing.Size(589, 22); + this.tableLayoutPanel6.TabIndex = 25; + // + // chkLogSa1 + // + this.chkLogSa1.AutoSize = true; + this.chkLogSa1.Checked = true; + this.chkLogSa1.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkLogSa1.Location = new System.Drawing.Point(212, 3); + this.chkLogSa1.Name = "chkLogSa1"; + this.chkLogSa1.Size = new System.Drawing.Size(49, 16); + this.chkLogSa1.TabIndex = 25; + this.chkLogSa1.Text = "SA-1"; + this.chkLogSa1.UseVisualStyleBackColor = true; + // // chkLogCpu // this.chkLogCpu.AutoSize = true; @@ -567,16 +613,6 @@ namespace Mesen.GUI.Debugger this.chkLogSpc.UseVisualStyleBackColor = true; this.chkLogSpc.CheckedChanged += new System.EventHandler(this.chkOptions_CheckedChanged); // - // lblTarget - // - this.lblTarget.Anchor = System.Windows.Forms.AnchorStyles.Left; - this.lblTarget.AutoSize = true; - this.lblTarget.Location = new System.Drawing.Point(3, 4); - this.lblTarget.Name = "lblTarget"; - this.lblTarget.Size = new System.Drawing.Size(46, 13); - this.lblTarget.TabIndex = 23; - this.lblTarget.Text = "Targets:"; - // // chkLogNecDsp // this.chkLogNecDsp.AutoSize = true; @@ -824,39 +860,17 @@ namespace Mesen.GUI.Debugger this.mnuRefresh.Text = "Refresh"; this.mnuRefresh.Click += new System.EventHandler(this.mnuRefresh_Click); // - // tableLayoutPanel6 + // chkLogGsu // - this.tableLayoutPanel6.ColumnCount = 5; - this.tableLayoutPanel2.SetColumnSpan(this.tableLayoutPanel6, 5); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel6.Controls.Add(this.chkLogSa1, 3, 0); - this.tableLayoutPanel6.Controls.Add(this.chkLogCpu, 0, 0); - this.tableLayoutPanel6.Controls.Add(this.chkLogSpc, 1, 0); - this.tableLayoutPanel6.Controls.Add(this.chkLogNecDsp, 2, 0); - this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel6.Location = new System.Drawing.Point(81, 0); - this.tableLayoutPanel6.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0); - this.tableLayoutPanel6.Name = "tableLayoutPanel6"; - this.tableLayoutPanel6.RowCount = 1; - this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel6.Size = new System.Drawing.Size(589, 22); - this.tableLayoutPanel6.TabIndex = 25; - // - // chkLogSa1 - // - this.chkLogSa1.AutoSize = true; - this.chkLogSa1.Checked = true; - this.chkLogSa1.CheckState = System.Windows.Forms.CheckState.Checked; - this.chkLogSa1.Location = new System.Drawing.Point(212, 3); - this.chkLogSa1.Name = "chkLogSa1"; - this.chkLogSa1.Size = new System.Drawing.Size(49, 16); - this.chkLogSa1.TabIndex = 25; - this.chkLogSa1.Text = "SA-1"; - this.chkLogSa1.UseVisualStyleBackColor = true; + this.chkLogGsu.AutoSize = true; + this.chkLogGsu.Checked = true; + this.chkLogGsu.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkLogGsu.Location = new System.Drawing.Point(267, 3); + this.chkLogGsu.Name = "chkLogGsu"; + this.chkLogGsu.Size = new System.Drawing.Size(49, 16); + this.chkLogGsu.TabIndex = 26; + this.chkLogGsu.Text = "GSU"; + this.chkLogGsu.UseVisualStyleBackColor = true; // // frmTraceLogger // @@ -882,13 +896,13 @@ namespace Mesen.GUI.Debugger this.tableLayoutPanel4.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.picHelp)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.picExpressionWarning)).EndInit(); + this.tableLayoutPanel6.ResumeLayout(false); + this.tableLayoutPanel6.PerformLayout(); this.tableLayoutPanel3.ResumeLayout(false); this.grpExecutionLog.ResumeLayout(false); this.ctxMenu.ResumeLayout(false); this.menuStrip1.ResumeLayout(false); this.menuStrip1.PerformLayout(); - this.tableLayoutPanel6.ResumeLayout(false); - this.tableLayoutPanel6.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -959,5 +973,6 @@ namespace Mesen.GUI.Debugger private System.Windows.Forms.CheckBox chkLogNecDsp; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6; private System.Windows.Forms.CheckBox chkLogSa1; + private System.Windows.Forms.CheckBox chkLogGsu; } } \ No newline at end of file diff --git a/UI/Debugger/frmTraceLogger.cs b/UI/Debugger/frmTraceLogger.cs index 7b400c4..abbebc9 100644 --- a/UI/Debugger/frmTraceLogger.cs +++ b/UI/Debugger/frmTraceLogger.cs @@ -49,6 +49,7 @@ namespace Mesen.GUI.Debugger _entityBinder.AddBinding(nameof(TraceLoggerOptions.LogSpc), chkLogSpc); _entityBinder.AddBinding(nameof(TraceLoggerOptions.LogNecDsp), chkLogNecDsp); _entityBinder.AddBinding(nameof(TraceLoggerOptions.LogSa1), chkLogSa1); + _entityBinder.AddBinding(nameof(TraceLoggerOptions.LogGsu), chkLogGsu); _entityBinder.AddBinding(nameof(TraceLoggerOptions.ShowByteCode), chkShowByteCode); //_entityBinder.AddBinding(nameof(TraceLoggerOptions.ShowCpuCycles), chkShowCpuCycles); @@ -221,6 +222,7 @@ namespace Mesen.GUI.Debugger interopOptions.LogSpc = !disableLogging && options.LogSpc; interopOptions.LogNecDsp = !disableLogging && options.LogNecDsp; interopOptions.LogSa1 = !disableLogging && options.LogSa1; + interopOptions.LogGsu = !disableLogging && options.LogGsu; interopOptions.IndentCode = options.IndentCode; interopOptions.ShowExtraInfo = options.ShowExtraInfo; interopOptions.UseLabels = options.UseLabels; diff --git a/UI/Dependencies/resources.en.xml b/UI/Dependencies/resources.en.xml index add6009..e856f1e 100644 --- a/UI/Dependencies/resources.en.xml +++ b/UI/Dependencies/resources.en.xml @@ -948,6 +948,7 @@ CPU Memory SPC Memory SA-1 Memory + GSU Memory PRG ROM Work RAM Save RAM @@ -956,10 +957,11 @@ CG RAM (Palette) SPC RAM SPC ROM (IPL) - DSP-n - Program ROM - DSP-n - Data ROM - DSP-n - Data RAM + DSP-n Program ROM + DSP-n Data ROM + DSP-n Data RAM SA-1 IRAM + GSU Work RAM Register diff --git a/UI/Forms/Config/frmEmulationConfig.Designer.cs b/UI/Forms/Config/frmEmulationConfig.Designer.cs index 1a91f3c..93e86c3 100644 --- a/UI/Forms/Config/frmEmulationConfig.Designer.cs +++ b/UI/Forms/Config/frmEmulationConfig.Designer.cs @@ -59,6 +59,9 @@ this.nudExtraScanlinesBeforeNmi = new Mesen.GUI.Controls.MesenNumericUpDown(); this.lblExtraScanlinesBeforeNmi = new System.Windows.Forms.Label(); this.lblExtraScanlinesAfterNmi = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); + this.lblGsuClockSpeed = new System.Windows.Forms.Label(); this.tabMain.SuspendLayout(); this.tpgGeneral.SuspendLayout(); this.tableLayoutPanel4.SuspendLayout(); @@ -72,6 +75,7 @@ this.tableLayoutPanel3.SuspendLayout(); this.grpPpuTiming.SuspendLayout(); this.tableLayoutPanel5.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); this.SuspendLayout(); // // baseConfigPanel @@ -405,18 +409,15 @@ this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel3.Controls.Add(this.lblOverclockHint, 0, 0); this.tableLayoutPanel3.Controls.Add(this.grpPpuTiming, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel1, 0, 2); this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 0); this.tableLayoutPanel3.Name = "tableLayoutPanel3"; - this.tableLayoutPanel3.RowCount = 3; + this.tableLayoutPanel3.RowCount = 4; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel3.Size = new System.Drawing.Size(406, 264); this.tableLayoutPanel3.TabIndex = 1; // @@ -542,6 +543,64 @@ this.lblExtraScanlinesAfterNmi.TabIndex = 1; this.lblExtraScanlinesAfterNmi.Text = "Additional scanlines after NMI:"; // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.nudGsuClockSpeed, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblGsuClockSpeed, 0, 0); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 131); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(406, 25); + this.tableLayoutPanel1.TabIndex = 8; + // + // nudGsuClockSpeed + // + this.nudGsuClockSpeed.DecimalPlaces = 0; + this.nudGsuClockSpeed.Increment = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.nudGsuClockSpeed.Location = new System.Drawing.Point(138, 3); + this.nudGsuClockSpeed.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3); + this.nudGsuClockSpeed.Maximum = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.nudGsuClockSpeed.MaximumSize = new System.Drawing.Size(10000, 20); + this.nudGsuClockSpeed.Minimum = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.nudGsuClockSpeed.MinimumSize = new System.Drawing.Size(0, 21); + this.nudGsuClockSpeed.Name = "nudGsuClockSpeed"; + this.nudGsuClockSpeed.Size = new System.Drawing.Size(46, 21); + this.nudGsuClockSpeed.TabIndex = 4; + this.nudGsuClockSpeed.Value = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.nudGsuClockSpeed.Leave += new System.EventHandler(this.nudGsuClockSpeed_Leave); + // + // lblGsuClockSpeed + // + this.lblGsuClockSpeed.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.lblGsuClockSpeed.AutoSize = true; + this.lblGsuClockSpeed.Location = new System.Drawing.Point(3, 6); + this.lblGsuClockSpeed.Name = "lblGsuClockSpeed"; + this.lblGsuClockSpeed.Size = new System.Drawing.Size(132, 13); + this.lblGsuClockSpeed.TabIndex = 0; + this.lblGsuClockSpeed.Text = "Super FX clock speed (%):"; + // // frmEmulationConfig // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -577,6 +636,8 @@ this.grpPpuTiming.ResumeLayout(false); this.tableLayoutPanel5.ResumeLayout(false); this.tableLayoutPanel5.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -615,5 +676,8 @@ private System.Windows.Forms.Label lblExtraScanlinesBeforeNmi; private System.Windows.Forms.Label lblExtraScanlinesAfterNmi; private System.Windows.Forms.PictureBox picHint; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private Controls.MesenNumericUpDown nudGsuClockSpeed; + private System.Windows.Forms.Label lblGsuClockSpeed; } } \ No newline at end of file diff --git a/UI/Forms/Config/frmEmulationConfig.cs b/UI/Forms/Config/frmEmulationConfig.cs index ff6126d..97c4d34 100644 --- a/UI/Forms/Config/frmEmulationConfig.cs +++ b/UI/Forms/Config/frmEmulationConfig.cs @@ -31,6 +31,7 @@ namespace Mesen.GUI.Forms.Config AddBinding(nameof(EmulationConfig.PpuExtraScanlinesBeforeNmi), nudExtraScanlinesBeforeNmi); AddBinding(nameof(EmulationConfig.PpuExtraScanlinesAfterNmi), nudExtraScanlinesAfterNmi); + AddBinding(nameof(EmulationConfig.GsuClockSpeed), nudGsuClockSpeed); } protected override void OnApply() @@ -38,5 +39,10 @@ namespace Mesen.GUI.Forms.Config ConfigManager.Config.Emulation = (EmulationConfig)this.Entity; ConfigManager.ApplyChanges(); } + + private void nudGsuClockSpeed_Leave(object sender, EventArgs e) + { + nudGsuClockSpeed.Value = Math.Ceiling(nudGsuClockSpeed.Value / 100) * 100; + } } } diff --git a/UI/Forms/frmMain.Designer.cs b/UI/Forms/frmMain.Designer.cs index 2d90c96..4d97a9b 100644 --- a/UI/Forms/frmMain.Designer.cs +++ b/UI/Forms/frmMain.Designer.cs @@ -123,8 +123,7 @@ this.mnuTakeScreenshot = new System.Windows.Forms.ToolStripMenuItem(); this.mnuDebug = new System.Windows.Forms.ToolStripMenuItem(); this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuSpcDebugger = new System.Windows.Forms.ToolStripMenuItem(); - this.mnuSa1Debugger = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuEventViewer = new System.Windows.Forms.ToolStripMenuItem(); this.mnuMemoryTools = new System.Windows.Forms.ToolStripMenuItem(); this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem(); this.mnuScriptWindow = new System.Windows.Forms.ToolStripMenuItem(); @@ -134,7 +133,9 @@ this.mnuSpriteViewer = new System.Windows.Forms.ToolStripMenuItem(); this.mnuPaletteViewer = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem22 = new System.Windows.Forms.ToolStripSeparator(); - this.mnuEventViewer = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSpcDebugger = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuSa1Debugger = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuGsuDebugger = new System.Windows.Forms.ToolStripMenuItem(); this.mnuHelp = new System.Windows.Forms.ToolStripMenuItem(); this.mnuCheckForUpdates = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem20 = new System.Windows.Forms.ToolStripSeparator(); @@ -868,7 +869,8 @@ this.mnuPaletteViewer, this.toolStripMenuItem22, this.mnuSpcDebugger, - this.mnuSa1Debugger}); + this.mnuSa1Debugger, + this.mnuGsuDebugger}); this.mnuDebug.Name = "mnuDebug"; this.mnuDebug.Size = new System.Drawing.Size(54, 20); this.mnuDebug.Text = "Debug"; @@ -882,19 +884,12 @@ this.mnuDebugger.Size = new System.Drawing.Size(155, 22); this.mnuDebugger.Text = "Debugger"; // - // mnuSpcDebugger + // mnuEventViewer // - this.mnuSpcDebugger.Image = global::Mesen.GUI.Properties.Resources.SpcDebugger; - this.mnuSpcDebugger.Name = "mnuSpcDebugger"; - this.mnuSpcDebugger.Size = new System.Drawing.Size(155, 22); - this.mnuSpcDebugger.Text = "SPC Debugger"; - // - // mnuSa1Debugger - // - this.mnuSa1Debugger.Image = global::Mesen.GUI.Properties.Resources.Sa1Debugger; - this.mnuSa1Debugger.Name = "mnuSa1Debugger"; - this.mnuSa1Debugger.Size = new System.Drawing.Size(155, 22); - this.mnuSa1Debugger.Text = "SA-1 Debugger"; + this.mnuEventViewer.Image = global::Mesen.GUI.Properties.Resources.NesEventViewer; + this.mnuEventViewer.Name = "mnuEventViewer"; + this.mnuEventViewer.Size = new System.Drawing.Size(155, 22); + this.mnuEventViewer.Text = "Event Viewer"; // // mnuMemoryTools // @@ -955,12 +950,26 @@ this.toolStripMenuItem22.Name = "toolStripMenuItem22"; this.toolStripMenuItem22.Size = new System.Drawing.Size(152, 6); // - // mnuEventViewer + // mnuSpcDebugger // - this.mnuEventViewer.Image = global::Mesen.GUI.Properties.Resources.NesEventViewer; - this.mnuEventViewer.Name = "mnuEventViewer"; - this.mnuEventViewer.Size = new System.Drawing.Size(155, 22); - this.mnuEventViewer.Text = "Event Viewer"; + this.mnuSpcDebugger.Image = global::Mesen.GUI.Properties.Resources.SpcDebugger; + this.mnuSpcDebugger.Name = "mnuSpcDebugger"; + this.mnuSpcDebugger.Size = new System.Drawing.Size(155, 22); + this.mnuSpcDebugger.Text = "SPC Debugger"; + // + // mnuSa1Debugger + // + this.mnuSa1Debugger.Image = global::Mesen.GUI.Properties.Resources.Sa1Debugger; + this.mnuSa1Debugger.Name = "mnuSa1Debugger"; + this.mnuSa1Debugger.Size = new System.Drawing.Size(155, 22); + this.mnuSa1Debugger.Text = "SA-1 Debugger"; + // + // mnuGsuDebugger + // + this.mnuGsuDebugger.Image = global::Mesen.GUI.Properties.Resources.GsuDebugger; + this.mnuGsuDebugger.Name = "mnuGsuDebugger"; + this.mnuGsuDebugger.Size = new System.Drawing.Size(155, 22); + this.mnuGsuDebugger.Text = "GSU Debugger"; // // mnuHelp // @@ -1171,5 +1180,6 @@ private System.Windows.Forms.ToolStripMenuItem mnuSpriteViewer; private System.Windows.Forms.ToolStripMenuItem mnuScriptWindow; private System.Windows.Forms.ToolStripMenuItem mnuSa1Debugger; + private System.Windows.Forms.ToolStripMenuItem mnuGsuDebugger; } } \ No newline at end of file diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index c365170..4f2ef06 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -247,6 +247,7 @@ namespace Mesen.GUI.Forms mnuDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenDebugger)); mnuSpcDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenSpcDebugger)); mnuSa1Debugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenSa1Debugger)); + mnuGsuDebugger.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenGsuDebugger)); mnuMemoryTools.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenMemoryTools)); mnuEventViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenEventViewer)); mnuTilemapViewer.InitShortcut(this, nameof(DebuggerShortcutsConfig.OpenTilemapViewer)); @@ -293,6 +294,7 @@ namespace Mesen.GUI.Forms mnuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Debugger); }; mnuSpcDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.SpcDebugger); }; mnuSa1Debugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.Sa1Debugger); }; + mnuGsuDebugger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.GsuDebugger); }; mnuTraceLogger.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TraceLogger); }; mnuMemoryTools.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.MemoryTools); }; mnuTilemapViewer.Click += (s, e) => { DebugWindowManager.OpenDebugWindow(DebugWindow.TilemapViewer); }; @@ -313,6 +315,11 @@ namespace Mesen.GUI.Forms CoprocessorType coprocessor = EmuApi.GetRomInfo().CoprocessorType; mnuSa1Debugger.Enabled = coprocessor == CoprocessorType.SA1; + mnuSa1Debugger.Visible = coprocessor == CoprocessorType.SA1; + + mnuGsuDebugger.Enabled = coprocessor == CoprocessorType.GSU; + mnuGsuDebugger.Visible = coprocessor == CoprocessorType.GSU; + mnuTraceLogger.Enabled = running; mnuScriptWindow.Enabled = running; diff --git a/UI/Interop/ConfigApi.cs b/UI/Interop/ConfigApi.cs index 686722f..ac1f246 100644 --- a/UI/Interop/ConfigApi.cs +++ b/UI/Interop/ConfigApi.cs @@ -57,6 +57,7 @@ namespace Mesen.GUI ShowUnidentifiedData = 0x400, DisassembleUnidentifiedData = 0x800, + GsuDebuggerEnabled = 0x10000000, Sa1DebuggerEnabled = 0x20000000, SpcDebuggerEnabled = 0x40000000, CpuDebuggerEnabled = 0x80000000 diff --git a/UI/Interop/DebugApi.cs b/UI/Interop/DebugApi.cs index ad71ce6..8018d05 100644 --- a/UI/Interop/DebugApi.cs +++ b/UI/Interop/DebugApi.cs @@ -162,6 +162,7 @@ namespace Mesen.GUI CpuMemory, SpcMemory, Sa1Memory, + GsuMemory, PrgRom, WorkRam, SaveRam, @@ -174,6 +175,7 @@ namespace Mesen.GUI DspDataRom, DspDataRam, Sa1InternalRam, + GsuWorkRam, Register, } @@ -422,6 +424,85 @@ namespace Mesen.GUI public byte SP; } + public struct GsuFlags + { + [MarshalAs(UnmanagedType.I1)] public bool Zero; + [MarshalAs(UnmanagedType.I1)] public bool Carry; + [MarshalAs(UnmanagedType.I1)] public bool Sign; + [MarshalAs(UnmanagedType.I1)] public bool Overflow; + [MarshalAs(UnmanagedType.I1)] public bool Running; + [MarshalAs(UnmanagedType.I1)] public bool RomReadPending; + [MarshalAs(UnmanagedType.I1)] public bool Alt1; + [MarshalAs(UnmanagedType.I1)] public bool Alt2; + [MarshalAs(UnmanagedType.I1)] public bool ImmLow; + [MarshalAs(UnmanagedType.I1)] public bool ImmHigh; + [MarshalAs(UnmanagedType.I1)] public bool Prefix; + [MarshalAs(UnmanagedType.I1)] public bool Irq; + }; + + public struct GsuPixelCache + { + public byte X; + public byte Y; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] Pixels; + public byte ValidBits; + }; + + public struct GsuState + { + public UInt64 CycleCount; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public UInt16[] R; + + public GsuFlags SFR; + + public byte RegisterLatch; + + public byte ProgramBank; + public byte RomBank; + public byte RamBank; + + [MarshalAs(UnmanagedType.I1)] public bool IrqDisabled; + [MarshalAs(UnmanagedType.I1)] public bool HighSpeedMode; + [MarshalAs(UnmanagedType.I1)] public bool ClockSelect; + [MarshalAs(UnmanagedType.I1)] public bool BackupRamEnabled; + public byte ScreenBase; + + public byte ColorGradient; + public byte PlotBpp; + public byte ScreenHeight; + [MarshalAs(UnmanagedType.I1)] public bool GsuRamAccess; + [MarshalAs(UnmanagedType.I1)] public bool GsuRomAccess; + + public UInt16 CacheBase; + + [MarshalAs(UnmanagedType.I1)] public bool PlotTransparent; + [MarshalAs(UnmanagedType.I1)] public bool PlotDither; + [MarshalAs(UnmanagedType.I1)] public bool ColorHighNibble; + [MarshalAs(UnmanagedType.I1)] public bool ColorFreezeHigh; + [MarshalAs(UnmanagedType.I1)] public bool ObjMode; + + public byte ColorReg; + public byte SrcReg; + public byte DestReg; + + public byte RomReadBuffer; + public byte RomDelay; + + public byte ProgramReadBuffer; + + public UInt16 RamWriteAddress; + public byte RamWriteValue; + public byte RamDelay; + + public UInt16 RamAddress; + + public GsuPixelCache PrimaryCache; + public GsuPixelCache SecondaryCache; + }; + public struct DebugState { public UInt64 MasterClock; @@ -430,6 +511,7 @@ namespace Mesen.GUI public SpcState Spc; public NecDspState NecDsp; public CpuState Sa1; + public GsuState Gsu; } public enum MemoryOperationType @@ -570,6 +652,7 @@ namespace Mesen.GUI [MarshalAs(UnmanagedType.I1)] public bool LogSpc; [MarshalAs(UnmanagedType.I1)] public bool LogNecDsp; [MarshalAs(UnmanagedType.I1)] public bool LogSa1; + [MarshalAs(UnmanagedType.I1)] public bool LogGsu; [MarshalAs(UnmanagedType.I1)] public bool ShowExtraInfo; [MarshalAs(UnmanagedType.I1)] public bool IndentCode; @@ -614,6 +697,7 @@ namespace Mesen.GUI Spc, NecDsp, Sa1, + Gsu } public static class CpuTypeExtensions @@ -624,6 +708,7 @@ namespace Mesen.GUI case CpuType.Cpu: return SnesMemoryType.CpuMemory; case CpuType.Spc: return SnesMemoryType.SpcMemory; case CpuType.Sa1: return SnesMemoryType.Sa1Memory; + case CpuType.Gsu: return SnesMemoryType.GsuMemory; default: throw new Exception("Invalid CPU type"); @@ -636,6 +721,7 @@ namespace Mesen.GUI case CpuType.Cpu: return 6; case CpuType.Spc: return 4; case CpuType.Sa1: return 6; + case CpuType.Gsu: return 6; default: throw new Exception("Invalid CPU type"); diff --git a/UI/Interop/EmuApi.cs b/UI/Interop/EmuApi.cs index 04433b6..486fef1 100644 --- a/UI/Interop/EmuApi.cs +++ b/UI/Interop/EmuApi.cs @@ -166,9 +166,7 @@ namespace Mesen.GUI DSP2, DSP3, DSP4, - GSU1, - GSU2, - MarioChip, + GSU, OBC1, SA1, DD1, diff --git a/UI/Properties/Resources.Designer.cs b/UI/Properties/Resources.Designer.cs index cee77a9..572df51 100644 --- a/UI/Properties/Resources.Designer.cs +++ b/UI/Properties/Resources.Designer.cs @@ -460,6 +460,16 @@ namespace Mesen.GUI.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap GsuDebugger { + get { + object obj = ResourceManager.GetObject("GsuDebugger", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/UI/Properties/Resources.resx b/UI/Properties/Resources.resx index d85bf96..4571964 100644 --- a/UI/Properties/Resources.resx +++ b/UI/Properties/Resources.resx @@ -457,4 +457,7 @@ ..\Resources\Sa1Debugger.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\GsuDebugger.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/UI/Resources/GsuDebugger.png b/UI/Resources/GsuDebugger.png new file mode 100644 index 0000000..50a7ebb Binary files /dev/null and b/UI/Resources/GsuDebugger.png differ diff --git a/UI/UI.csproj b/UI/UI.csproj index 32dd333..361aa58 100644 --- a/UI/UI.csproj +++ b/UI/UI.csproj @@ -248,6 +248,8 @@ + + @@ -269,6 +271,12 @@ ctrlPpuStatus.cs + + UserControl + + + ctrlGsuStatus.cs + UserControl @@ -822,6 +830,7 @@ + Always @@ -874,6 +883,9 @@ ctrlPpuStatus.cs + + ctrlGsuStatus.cs + ctrlSpcStatus.cs