From 2a7f248cd8e4b0a1aadf9fbb2e72d0aaead9368f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Czeka=C5=84ski?= Date: Sun, 11 Aug 2019 22:46:01 +0200 Subject: [PATCH] debug: added timers debug window slight timer device refactor (not templated anymore) --- src/device/timer.cpp | 19 +- src/device/timer.h | 6 +- src/platform/windows/gui/debug.cpp | 33 --- .../windows/gui/debug/timers/timers.cpp | 200 ++++++++++++++++++ .../windows/gui/debug/timers/timers.h | 16 ++ src/platform/windows/gui/gui.cpp | 9 +- src/platform/windows/gui/tools.cpp | 7 +- src/system.cpp | 42 ++-- src/system.h | 4 +- 9 files changed, 255 insertions(+), 81 deletions(-) create mode 100644 src/platform/windows/gui/debug/timers/timers.cpp create mode 100644 src/platform/windows/gui/debug/timers/timers.h diff --git a/src/device/timer.cpp b/src/device/timer.cpp index 7741d79e..80973ee2 100644 --- a/src/device/timer.cpp +++ b/src/device/timer.cpp @@ -3,11 +3,9 @@ using namespace timer; -template -Timer::Timer(System* sys) : sys(sys) {} +Timer::Timer(System* sys, int which) : which(which), sys(sys) {} -template -void Timer::step(int cycles) { +void Timer::step(int cycles) { if (paused) return; cnt += cycles; @@ -66,8 +64,7 @@ void Timer::step(int cycles) { current._reg = (uint16_t)tval; } -template -void Timer::checkIrq() { +void Timer::checkIrq() { if (mode.irqPulseMode == CounterMode::IrqPulseMode::toggle) { mode.interruptRequest = !mode.interruptRequest; } else { @@ -83,8 +80,7 @@ void Timer::checkIrq() { mode.interruptRequest = true; // low only for few cycles } -template -uint8_t Timer::read(uint32_t address) { +uint8_t Timer::read(uint32_t address) { if (address < 2) { return current.read(address); } @@ -102,8 +98,7 @@ uint8_t Timer::read(uint32_t address) { return 0; } -template -void Timer::write(uint32_t address, uint8_t data) { +void Timer::write(uint32_t address, uint8_t data) { if (address < 2) { current.write(address, data); } else if (address >= 4 && address < 6) { @@ -142,7 +137,3 @@ void Timer::write(uint32_t address, uint8_t data) { target.write(address - 8, data); } } - -template class Timer<0>; -template class Timer<1>; -template class Timer<2>; \ No newline at end of file diff --git a/src/device/timer.h b/src/device/timer.h index ecb41b3c..8b629d4d 100644 --- a/src/device/timer.h +++ b/src/device/timer.h @@ -65,11 +65,11 @@ union CounterMode { }; } // namespace timer -template class Timer { + public: const int baseAddress = 0x1f801100; - public: + int which; Reg16 current; timer::CounterMode mode; Reg16 target; @@ -92,7 +92,7 @@ class Timer { } public: - Timer(System* sys); + Timer(System* sys, int which); void step() { step(1); } void step(int cycles); uint8_t read(uint32_t address); diff --git a/src/platform/windows/gui/debug.cpp b/src/platform/windows/gui/debug.cpp index cc9f92a8..fea22a61 100644 --- a/src/platform/windows/gui/debug.cpp +++ b/src/platform/windows/gui/debug.cpp @@ -402,39 +402,6 @@ void gpuLogWindow(System *sys) { } } -void ioWindow(System *sys) { - if (!showIo) { - return; - } - ImGui::Begin("IO", &showIo, ImVec2(300, 200)); - - ImGui::Columns(1, nullptr, false); - ImGui::Text("Timer 0"); - - ImGui::Columns(2, nullptr, false); - dumpRegister("current", sys->timer0->current._reg); - dumpRegister("target", sys->timer0->target._reg); - dumpRegister("mode", sys->timer0->mode._reg); - - ImGui::Columns(1, nullptr, false); - ImGui::Text("Timer 1"); - - ImGui::Columns(2, nullptr, false); - dumpRegister("current", sys->timer1->current._reg); - dumpRegister("target", sys->timer1->target._reg); - dumpRegister("mode", sys->timer1->mode._reg); - - ImGui::Columns(1, nullptr, false); - ImGui::Text("Timer 2"); - - ImGui::Columns(2, nullptr, false); - dumpRegister("current", sys->timer2->current._reg); - dumpRegister("target", sys->timer2->target._reg); - dumpRegister("mode", sys->timer2->mode._reg); - - ImGui::End(); -} - void ioLogWindow(System *sys) { #ifdef ENABLE_IO_LOG if (!ioLogEnabled) { diff --git a/src/platform/windows/gui/debug/timers/timers.cpp b/src/platform/windows/gui/debug/timers/timers.cpp new file mode 100644 index 00000000..2c1bacbe --- /dev/null +++ b/src/platform/windows/gui/debug/timers/timers.cpp @@ -0,0 +1,200 @@ +#include "timers.h" +#include +#include +#include "platform/windows/gui/tools.h" +#include "system.h" +#include "utils/string.h" + +namespace gui::debug::timers { + +std::string getSyncMode(Timer* timer) { + int which = timer->which; + timer::CounterMode mode = timer->mode; + + if (which == 0) { + using modes = timer::CounterMode::SyncMode0; + auto mode0 = static_cast(mode.syncMode); + + switch (mode0) { + case modes::pauseDuringHblank: return "pauseDuringHblank"; + case modes::resetAtHblank: return "resetAtHblank"; + case modes::resetAtHblankAndPauseOutside: return "resetAtHblankAndPauseOutside"; + case modes::pauseUntilHblankAndFreerun: return "pauseUntilHblankAndFreerun"; + } + } + if (which == 1) { + using modes = timer::CounterMode::SyncMode1; + auto mode1 = static_cast(mode.syncMode); + + switch (mode1) { + case modes::pauseDuringVblank: return "pauseDuringVblank"; + case modes::resetAtVblank: return "resetAtVblank"; + case modes::resetAtVblankAndPauseOutside: return "resetAtVblankAndPauseOutside"; + case modes::pauseUntilVblankAndFreerun: return "pauseUntilVblankAndFreerun"; + } + } + if (which == 2) { + using modes = timer::CounterMode::SyncMode2; + auto mode2 = static_cast(mode.syncMode); + + switch (mode2) { + case modes::stopCounter: + case modes::stopCounter_: return "stopCounter"; + case modes::freeRun: + case modes::freeRun_: return "freeRun"; + } + } + return ""; +} + +std::string getClockSource(Timer* timer) { + int which = timer->which; + timer::CounterMode mode = timer->mode; + if (which == 0) { + using modes = timer::CounterMode::ClockSource0; + auto clock = static_cast(mode.clockSource & 1); + + if (clock == modes::dotClock) { + return "Dotclock"; + } else { + return "Sysclock"; + } + } else if (which == 1) { + using modes = timer::CounterMode::ClockSource1; + auto clock = static_cast(mode.clockSource & 1); + + if (clock == modes::hblank) { + return "HBlank"; + } else { + return "Sysclock"; + } + } else if (which == 2) { + using modes = timer::CounterMode::ClockSource2; + auto clock = static_cast((mode.clockSource >> 1) & 1); + + if (clock == modes::systemClock_8) { + return "Sysclock/8"; + } else { + return "Sysclock"; + } + } + return ""; +} + +struct Field { + std::string bits; + std::string name; + std::string value; +}; + +void drawRegisterFields(const char* name, const std::vector& fields) { + const int colNum = 3; + ImVec2 charSize = ImGui::CalcTextSize("_"); + std::vector columnsWidth(colNum); + + for (int i = 0; i < fields.size(); i++) { + auto& f = fields[i]; + if (f.bits.size() > columnsWidth[0]) { + columnsWidth[0] = f.bits.size(); + } + if (f.name.size() > columnsWidth[1]) { + columnsWidth[1] = f.name.size(); + } + if (f.value.size() > columnsWidth[2]) { + columnsWidth[2] = f.value.size(); + } + } + + ImVec2 padding(2, 2); + ImVec2 spacing(4, 0); + + int width = 0; + for (auto w : columnsWidth) { + width += w * charSize.x + spacing.x; + } + ImVec2 windowSize(width, fields.size() * charSize.y + padding.y * 2); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, spacing); + if (ImGui::BeginChild(name, windowSize, true)) { + ImGui::Columns(3, name, true); + + for (int i = 0; i < colNum; i++) { + ImGui::SetColumnWidth(i, columnsWidth[i] * charSize.x + spacing.x); + } + + for (auto& f : fields) { + ImGui::TextUnformatted(f.bits.c_str()); + ImGui::NextColumn(); + + ImGui::TextUnformatted(f.name.c_str()); + ImGui::NextColumn(); + + ImGui::TextUnformatted(f.value.c_str()); + ImGui::NextColumn(); + } + + ImGui::Columns(1); + } + ImGui::EndChild(); + ImGui::PopStyleVar(3); +} + +void Timers::timersWindow(System* sys) { + ImGui::Begin("Timers", &timersWindowOpen, ImVec2(600, 300), ImGuiWindowFlags_NoScrollbar); + + ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); + + std::array timers = {sys->timer[0].get(), sys->timer[1].get(), sys->timer[2].get()}; + + ImGui::Columns(3); + for (auto* timer : timers) { + int which = timer->which; + ImGui::Text("Timer%d", which); + ImGui::Text("Value: 0x%04x", timer->current._reg); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("0x%08x", timer->baseAddress + which * 0x10 + 0); + } + + ImGui::Text("Target: 0x%04x", timer->target._reg); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("0x%08x", timer->baseAddress + which * 0x10 + 8); + } + + ImGui::Text("Mode: 0x%04x", timer->mode._reg); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("0x%08x", timer->baseAddress + which * 0x10 + 4); + } + + const std::vector fields = { + {"0", "Sync", timer->mode.syncEnabled ? "On" : "Off"}, + {"1-2", "SyncMode", getSyncMode(timer)}, + {"3", "Reset counter", timer->mode.resetToZero == timer::CounterMode::ResetToZero::whenFFFF ? "after 0xffff" : "after target"}, + {"4", "IRQ on target", timer->mode.irqWhenTarget ? "On" : "Off"}, + {"5", "IRQ on 0xFFFF", timer->mode.irqWhenFFFF ? "On" : "Off"}, + {"6", "IRQ repeat mode", + timer->mode.irqRepeatMode == timer::CounterMode::IrqRepeatMode::repeatedly ? "Repeatedly" : "One-shot"}, + {"7", "IRQ pulse mode", timer->mode.irqPulseMode == timer::CounterMode::IrqPulseMode::toggle ? "Toggle bit10" : "Pulse bit10"}, + {"8-9", "Clock source", getClockSource(timer)}, + {"10", "IRQ request", timer->mode.interruptRequest ? "No" : "Pending"}, + {"11", "Reached target", timer->mode.reachedTarget ? "Yes" : "No"}, + {"12", "Reached 0xFFFF", timer->mode.reachedFFFF ? "Yes" : "No"}, + }; + + drawRegisterFields(string_format("flags##timer%d", which).c_str(), fields); + + ImGui::NextColumn(); + } + + ImGui::Columns(1); + + ImGui::PopFont(); + + ImGui::End(); +} + +void Timers::displayWindows(System* sys) { + if (timersWindowOpen) timersWindow(sys); +} +} // namespace gui::debug::timers \ No newline at end of file diff --git a/src/platform/windows/gui/debug/timers/timers.h b/src/platform/windows/gui/debug/timers/timers.h new file mode 100644 index 00000000..57630005 --- /dev/null +++ b/src/platform/windows/gui/debug/timers/timers.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include +#include + +struct System; + +namespace gui::debug::timers { +class Timers { + void timersWindow(System* sys); + + public: + bool timersWindowOpen = false; + void displayWindows(System* sys); +}; +} // namespace gui::debug::timers \ No newline at end of file diff --git a/src/platform/windows/gui/gui.cpp b/src/platform/windows/gui/gui.cpp index 952f1fa4..f125b5f6 100644 --- a/src/platform/windows/gui/gui.cpp +++ b/src/platform/windows/gui/gui.cpp @@ -5,6 +5,7 @@ #include "debug/cpu/cpu.h" #include "debug/gpu/gpu.h" #include "debug/kernel/kernel.h" +#include "debug/timers/timers.h" #include "imgui/imgui_impl_sdl_gl3.h" #include "options.h" #include "platform/windows/input/key.h" @@ -16,7 +17,6 @@ void gteRegistersWindow(GTE& gte); void ioLogWindow(System* sys); void gteLogWindow(System* sys); void gpuLogWindow(System* sys); -void ioWindow(System* sys); void vramWindow(gpu::GPU* gpu); void watchWindow(System* sys); void ramWindow(System* sys); @@ -30,7 +30,6 @@ bool ioLogEnabled = false; bool gteLogEnabled = false; bool gpuLogEnabled = false; bool singleFrame = false; -bool showIo = false; bool notInitializedWindowShown = false; bool showVramWindow = false; @@ -42,6 +41,7 @@ bool showSpuWindow = false; bool showAboutWindow = false; gui::debug::cpu::CPU cpuDebug; +gui::debug::timers::Timers timersDebug; void aboutWindow() { ImGui::Begin("About", &showAboutWindow); @@ -112,7 +112,8 @@ void renderImgui(System* sys) { ImGui::Separator(); ImGui::MenuItem("GTE registers", nullptr, >eRegistersEnabled); - ImGui::MenuItem("IO", nullptr, &showIo); + ImGui::MenuItem("Timers", nullptr, &timersDebug.timersWindowOpen); + ; ImGui::MenuItem("Memory", nullptr, &showRamWindow); ImGui::MenuItem("VRAM", nullptr, &showVramWindow); ImGui::MenuItem("Debugger", nullptr, &cpuDebug.debuggerWindowOpen); @@ -145,7 +146,6 @@ void renderImgui(System* sys) { if (ioLogEnabled) ioLogWindow(sys); if (gteLogEnabled) gteLogWindow(sys); if (gpuLogEnabled) gpuLogWindow(sys); - if (showIo) ioWindow(sys); if (showRamWindow) ramWindow(sys); if (showVramWindow) vramWindow(sys->gpu.get()); if (showWatchWindow) watchWindow(sys); @@ -154,6 +154,7 @@ void renderImgui(System* sys) { if (showGpuWindow) gpuWindow(sys); if (showSpuWindow) spuWindow(sys->spu.get()); + timersDebug.displayWindows(sys); cpuDebug.displayWindows(sys); // Options diff --git a/src/platform/windows/gui/tools.cpp b/src/platform/windows/gui/tools.cpp index 9323699f..75edaddd 100644 --- a/src/platform/windows/gui/tools.cpp +++ b/src/platform/windows/gui/tools.cpp @@ -15,13 +15,14 @@ void Columns(const std::vector& list, int col_num) { }; ImGui::Columns(col_num, nullptr, true); + for (int c = 0; c < col_num; c++) { + ImGui::SetColumnWidth(c, columnsWidth[c]); + } + for (auto item : list) { column(item); } - for (int c = 0; c < col_num; c++) { - ImGui::SetColumnWidth(c, columnsWidth[c]); - } ImGui::Columns(1); } }; // namespace gui::tools \ No newline at end of file diff --git a/src/system.cpp b/src/system.cpp index 68fbcb68..f8f2e162 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -27,9 +27,9 @@ System::System() { interrupt = std::make_unique(this); memoryControl = std::make_unique(); serial = std::make_unique(); - timer0 = std::make_unique>(this); - timer1 = std::make_unique>(this); - timer2 = std::make_unique>(this); + for (int t : {0, 1, 2}) { + timer[t] = std::make_unique(this, t); + } debugOutput = config["debug"]["log"]["system"].get(); biosLog = config["debug"]["log"]["bios"]; @@ -161,9 +161,9 @@ INLINE T System::readMemory(uint32_t address) { READ_IO(0x1f801060, 0x1f801064, memoryControl); READ_IO(0x1f801070, 0x1f801078, interrupt); READ_IO(0x1f801080, 0x1f801100, dma); - READ_IO(0x1f801100, 0x1f801110, timer0); - READ_IO(0x1f801110, 0x1f801120, timer1); - READ_IO(0x1f801120, 0x1f801130, timer2); + READ_IO(0x1f801100, 0x1f801110, timer[0]); + READ_IO(0x1f801110, 0x1f801120, timer[1]); + READ_IO(0x1f801120, 0x1f801130, timer[2]); READ_IO(0x1f801800, 0x1f801804, cdrom); READ_IO32(0x1f801810, 0x1f801818, gpu); READ_IO32(0x1f801820, 0x1f801828, mdec); @@ -203,9 +203,9 @@ INLINE void System::writeMemory(uint32_t address, T data) { WRITE_IO(0x1f801060, 0x1f801064, memoryControl); WRITE_IO(0x1f801070, 0x1f801078, interrupt); WRITE_IO(0x1f801080, 0x1f801100, dma); - WRITE_IO(0x1f801100, 0x1f801110, timer0); - WRITE_IO(0x1f801110, 0x1f801120, timer1); - WRITE_IO(0x1f801120, 0x1f801130, timer2); + WRITE_IO(0x1f801100, 0x1f801110, timer[0]); + WRITE_IO(0x1f801110, 0x1f801120, timer[1]); + WRITE_IO(0x1f801120, 0x1f801130, timer[2]); WRITE_IO(0x1f801800, 0x1f801804, cdrom); WRITE_IO32(0x1f801810, 0x1f801818, gpu); WRITE_IO32(0x1f801820, 0x1f801828, mdec); @@ -318,9 +318,9 @@ void System::singleStep() { dma->step(); cdrom->step(); - timer0->step(3); - timer1->step(3); - timer2->step(3); + timer[0]->step(3); + timer[1]->step(3); + timer[2]->step(3); controller->step(); spu->step(cdrom.get()); @@ -346,9 +346,9 @@ void System::emulateFrame() { dma->step(); cdrom->step(); - timer0->step(systemCycles); - timer1->step(systemCycles); - timer2->step(systemCycles); + timer[0]->step(systemCycles); + timer[1]->step(systemCycles); + timer[2]->step(systemCycles); static float spuCounter = 0; // TODO: Yey, magic numbers! @@ -370,15 +370,15 @@ void System::emulateFrame() { return; // frame emulated } - if (gpu->gpuLine >= gpu::LINE_VBLANK_START_NTSC) { - if (timer1->mode.syncEnabled) { - auto mode1 = static_cast(timer1->mode.syncMode); + if (gpu->gpuLine > gpu::LINE_VBLANK_START_NTSC) { + if (timer[1]->mode.syncEnabled) { + auto mode1 = static_cast(timer[1]->mode.syncMode); using modes = timer::CounterMode::SyncMode1; if (mode1 == modes::resetAtVblank || mode1 == modes::resetAtVblankAndPauseOutside) { - timer1->current._reg = 0; + timer[1]->current._reg = 0; } else if (mode1 == modes::pauseUntilVblankAndFreerun) { - timer1->paused = false; - timer1->mode.syncEnabled = false; + timer[1]->paused = false; + timer[1]->mode.syncEnabled = false; } } } diff --git a/src/system.h b/src/system.h index 9a18815b..b4c90b44 100644 --- a/src/system.h +++ b/src/system.h @@ -93,9 +93,7 @@ struct System { std::unique_ptr memoryControl; std::unique_ptr spu; std::unique_ptr serial; - std::unique_ptr> timer0; - std::unique_ptr> timer1; - std::unique_ptr> timer2; + std::array, 3> timer; template INLINE T readMemory(uint32_t address);