diff --git a/src/core/dma.cpp b/src/core/dma.cpp index e4168e88b..0f943dc41 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -11,6 +11,9 @@ #include "mdec.h" #include "spu.h" #include "system.h" +#ifdef WITH_IMGUI +#include "imgui.h" +#endif Log_SetChannel(DMA); DMA g_dma; @@ -551,3 +554,84 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen CPU::CodeCache::InvalidateCodePages(address, word_count); return Bus::GetDMARAMTickCount(word_count); } + +void DMA::DrawDebugStateWindow() +{ +#ifdef WITH_IMGUI + static constexpr u32 NUM_COLUMNS = 10; + static constexpr std::array column_names = { + {"#", "Req", "Direction", "Chopping", "Mode", "Busy", "Enable", "Priority", "IRQ", "Flag"}}; + static constexpr std::array channel_names = { + {"MDECin", "MDECout", "GPU", "CDROM", "SPU", "PIO", "OTC"}}; + static constexpr std::array sync_mode_names = {{"Manual", "Request", "LinkedList", "Reserved"}}; + + const float framebuffer_scale = ImGui::GetIO().DisplayFramebufferScale.x; + + ImGui::SetNextWindowSize(ImVec2(850.0f * framebuffer_scale, 250.0f * framebuffer_scale), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("DMA State", &g_settings.debugging.show_dma_state)) + { + ImGui::End(); + return; + } + + ImGui::Columns(NUM_COLUMNS); + ImGui::SetColumnWidth(0, 100.0f * framebuffer_scale); + ImGui::SetColumnWidth(1, 50.0f * framebuffer_scale); + ImGui::SetColumnWidth(2, 100.0f * framebuffer_scale); + ImGui::SetColumnWidth(3, 150.0f * framebuffer_scale); + ImGui::SetColumnWidth(4, 80.0f * framebuffer_scale); + ImGui::SetColumnWidth(5, 80.0f * framebuffer_scale); + ImGui::SetColumnWidth(6, 80.0f * framebuffer_scale); + ImGui::SetColumnWidth(7, 80.0f * framebuffer_scale); + ImGui::SetColumnWidth(8, 80.0f * framebuffer_scale); + ImGui::SetColumnWidth(9, 80.0f * framebuffer_scale); + + for (const char* title : column_names) + { + ImGui::TextUnformatted(title); + ImGui::NextColumn(); + } + + const ImVec4 active(1.0f, 1.0f, 1.0f, 1.0f); + const ImVec4 inactive(0.5f, 0.5f, 0.5f, 1.0f); + + for (u32 i = 0; i < NUM_CHANNELS; i++) + { + const ChannelState& cs = m_state[i]; + + ImGui::TextColored(cs.channel_control.enable_busy ? active : inactive, "%u[%s]", i, channel_names[i]); + ImGui::NextColumn(); + ImGui::TextColored(cs.request ? active : inactive, cs.request ? "Yes" : "No"); + ImGui::NextColumn(); + ImGui::Text("%s%s", cs.channel_control.copy_to_device ? "FromRAM" : "ToRAM", + cs.channel_control.address_step_reverse ? " Addr+" : " Addr-"); + ImGui::NextColumn(); + ImGui::TextColored(cs.channel_control.chopping_enable ? active : inactive, "%s/%u/%u", + cs.channel_control.chopping_enable ? "Yes" : "No", + cs.channel_control.chopping_cpu_window_size.GetValue(), + cs.channel_control.chopping_dma_window_size.GetValue()); + ImGui::NextColumn(); + ImGui::Text("%s", sync_mode_names[static_cast(cs.channel_control.sync_mode.GetValue())]); + ImGui::NextColumn(); + ImGui::TextColored(cs.channel_control.enable_busy ? active : inactive, "%s%s", + cs.channel_control.enable_busy ? "Busy" : "Idle", + cs.channel_control.start_trigger ? " (Trigger)" : ""); + ImGui::NextColumn(); + ImGui::TextColored(m_DPCR.GetMasterEnable(static_cast(i)) ? active : inactive, + m_DPCR.GetMasterEnable(static_cast(i)) ? "Enabled" : "Disabled"); + ImGui::NextColumn(); + ImGui::TextColored(m_DPCR.GetMasterEnable(static_cast(i)) ? active : inactive, "%u", + m_DPCR.GetPriority(static_cast(i))); + ImGui::NextColumn(); + ImGui::TextColored(m_DICR.IsIRQEnabled(static_cast(i)) ? active : inactive, + m_DICR.IsIRQEnabled(static_cast(i)) ? "Enabled" : "Disabled"); + ImGui::NextColumn(); + ImGui::TextColored(m_DICR.GetIRQFlag(static_cast(i)) ? active : inactive, + m_DICR.GetIRQFlag(static_cast(i)) ? "IRQ" : ""); + ImGui::NextColumn(); + } + + ImGui::Columns(1); + ImGui::End(); +#endif +} diff --git a/src/core/dma.h b/src/core/dma.h index d7d9ca5aa..b04b7dfc9 100644 --- a/src/core/dma.h +++ b/src/core/dma.h @@ -45,6 +45,8 @@ public: void SetMaxSliceTicks(TickCount ticks) { m_max_slice_ticks = ticks; } void SetHaltTicks(TickCount ticks) { m_halt_ticks = ticks; } + void DrawDebugStateWindow(); + private: static constexpr PhysicalMemoryAddress BASE_ADDRESS_MASK = UINT32_C(0x00FFFFFF); static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x001FFFFC); diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 8b4e4c3e1..b645df282 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -505,6 +505,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si) si.SetBoolValue("Debug", "ShowSPUState", false); si.SetBoolValue("Debug", "ShowTimersState", false); si.SetBoolValue("Debug", "ShowMDECState", false); + si.SetBoolValue("Debug", "ShowDMAState", false); si.SetIntValue("Hacks", "DMAMaxSliceTicks", static_cast(Settings::DEFAULT_DMA_MAX_SLICE_TICKS)); si.SetIntValue("Hacks", "DMAHaltTicks", static_cast(Settings::DEFAULT_DMA_HALT_TICKS)); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3fd49cbe3..064976efa 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -236,6 +236,7 @@ void Settings::Load(SettingsInterface& si) debugging.show_spu_state = si.GetBoolValue("Debug", "ShowSPUState"); debugging.show_timers_state = si.GetBoolValue("Debug", "ShowTimersState"); debugging.show_mdec_state = si.GetBoolValue("Debug", "ShowMDECState"); + debugging.show_dma_state = si.GetBoolValue("Debug", "ShowDMAState"); } void Settings::Save(SettingsInterface& si) const @@ -349,6 +350,7 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Debug", "ShowSPUState", debugging.show_spu_state); si.SetBoolValue("Debug", "ShowTimersState", debugging.show_timers_state); si.SetBoolValue("Debug", "ShowMDECState", debugging.show_mdec_state); + si.SetBoolValue("Debug", "ShowDMAState", debugging.show_dma_state); } static std::array s_log_level_names = { diff --git a/src/core/settings.h b/src/core/settings.h index b919bdcde..53e41517c 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -152,6 +152,7 @@ struct Settings mutable bool show_spu_state = false; mutable bool show_timers_state = false; mutable bool show_mdec_state = false; + mutable bool show_dma_state = false; } debugging; // TODO: Controllers, memory cards, etc. diff --git a/src/duckstation-sdl/sdl_host_interface.cpp b/src/duckstation-sdl/sdl_host_interface.cpp index bcbf1d580..d32688d1a 100644 --- a/src/duckstation-sdl/sdl_host_interface.cpp +++ b/src/duckstation-sdl/sdl_host_interface.cpp @@ -1073,6 +1073,7 @@ void SDLHostInterface::DrawDebugMenu() settings_changed |= ImGui::MenuItem("Show SPU State", nullptr, &debug_settings.show_spu_state); settings_changed |= ImGui::MenuItem("Show Timers State", nullptr, &debug_settings.show_timers_state); settings_changed |= ImGui::MenuItem("Show MDEC State", nullptr, &debug_settings.show_mdec_state); + settings_changed |= ImGui::MenuItem("Show DMA State", nullptr, &debug_settings.show_dma_state); if (settings_changed) { @@ -1086,6 +1087,7 @@ void SDLHostInterface::DrawDebugMenu() debug_settings_copy.show_spu_state = debug_settings.show_spu_state; debug_settings_copy.show_timers_state = debug_settings.show_timers_state; debug_settings_copy.show_mdec_state = debug_settings.show_mdec_state; + debug_settings_copy.show_dma_state = debug_settings.show_dma_state; RunLater([this]() { SaveAndUpdateSettings(); }); } } diff --git a/src/frontend-common/common_host_interface.cpp b/src/frontend-common/common_host_interface.cpp index d820192a1..b3d66b69f 100644 --- a/src/frontend-common/common_host_interface.cpp +++ b/src/frontend-common/common_host_interface.cpp @@ -936,6 +936,8 @@ void CommonHostInterface::DrawDebugWindows() g_spu.DrawDebugStateWindow(); if (g_settings.debugging.show_mdec_state) g_mdec.DrawDebugStateWindow(); + if (g_settings.debugging.show_dma_state) + g_dma.DrawDebugStateWindow(); } void CommonHostInterface::DoFrameStep()