Avocado/src/platform/windows/gui/debug/timers.cpp
Jakub Czekański fb7997fc16 externals: Update submodules
gui: fixes
2019-12-05 22:35:34 +01:00

168 lines
5.9 KiB
C++

#include "timers.h"
#include <fmt/core.h>
#include <imgui.h>
#include <magic_enum.hpp>
#include <numeric>
#include "device/timer.h"
#include "system.h"
namespace gui::debug {
struct Field {
std::string bits;
std::string name;
std::string value;
bool active = true;
};
#define ENUM_NAME(x) (std::string(magic_enum::enum_name(x)))
using namespace device::timer;
std::string Timers::getSyncMode(Timer* timer) {
CounterMode mode = timer->mode;
switch (timer->which) {
case 0: return ENUM_NAME(static_cast<CounterMode::SyncMode0>(mode.syncMode));
case 1: return ENUM_NAME(static_cast<CounterMode::SyncMode1>(mode.syncMode));
case 2: return ENUM_NAME(static_cast<CounterMode::SyncMode2>(mode.syncMode));
default: return "";
}
}
std::string Timers::getClockSource(Timer* timer) {
CounterMode mode = timer->mode;
switch (timer->which) {
case 0: return ENUM_NAME(static_cast<CounterMode::ClockSource0>(mode.clockSource & 1));
case 1: return ENUM_NAME(static_cast<CounterMode::ClockSource1>(mode.clockSource & 1));
case 2: return ENUM_NAME(static_cast<CounterMode::ClockSource2>((mode.clockSource >> 1) & 1));
default: return "";
}
}
void drawRegisterFields(const char* name, const std::vector<Field>& fields) {
const size_t colNum = 3;
ImVec2 charSize = ImGui::CalcTextSize("_");
std::vector<size_t> columnsWidth(colNum);
for (size_t 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 (size_t 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();
ImVec4 color(1, 1, 1, 1);
if (!f.active) color.w = 0.25;
ImGui::TextColored(color, "%s", f.value.c_str());
ImGui::NextColumn();
}
ImGui::Columns(1);
}
ImGui::EndChild();
ImGui::PopStyleVar(3);
}
void Timers::timersWindow(System* sys) {
const int baseAddress = 0x1f801100;
ImGui::SetNextWindowSize(ImVec2(600, 300), ImGuiCond_FirstUseEver);
ImGui::Begin("Timers", &timersWindowOpen, ImGuiWindowFlags_NoScrollbar);
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
std::array<Timer*, 3> timers = {sys->timer[0].get(), sys->timer[1].get(), sys->timer[2].get()};
ImGui::Columns(3);
for (auto* timer : timers) {
int which = timer->which;
const bool syncEnabled = timer->mode.syncEnabled;
const bool resetAfterTarget = timer->mode.resetToZero == CounterMode::ResetToZero::whenTarget;
const bool irqWhenTarget = timer->mode.irqWhenTarget;
const bool irqOneShot = timer->mode.irqRepeatMode == CounterMode::IrqRepeatMode::oneShot;
const bool irqPulseMode = timer->mode.irqPulseMode == CounterMode::IrqPulseMode::shortPulse;
const auto clockSource = getClockSource(timer);
ImGui::Text("Timer%d", which);
ImGui::Text("Value: 0x%04x", timer->current._reg);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("0x%08x", baseAddress + which * 0x10 + 0);
}
ImVec4 color(1, 1, 1, 1);
if (!irqWhenTarget && !resetAfterTarget) color.w = 0.25;
ImGui::TextColored(color, "Target: 0x%04x", timer->target._reg);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("0x%08x", baseAddress + which * 0x10 + 8);
}
ImGui::Text("Mode: 0x%04x", timer->mode._reg);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("0x%08x", baseAddress + which * 0x10 + 4);
}
const std::vector<Field> fields = {
{"0", "Sync", syncEnabled ? "On" : "Off", syncEnabled},
{"1-2", "SyncMode", getSyncMode(timer), syncEnabled},
{"3", "Reset counter", resetAfterTarget ? "after target" : "after 0xffff", resetAfterTarget},
{"4", "IRQ on target", timer->mode.irqWhenTarget ? "On" : "Off", (bool)timer->mode.irqWhenTarget},
{"5", "IRQ on 0xFFFF", timer->mode.irqWhenFFFF ? "On" : "Off", (bool)timer->mode.irqWhenFFFF},
{"6", "IRQ repeat mode", irqOneShot ? "One-shot" : "Repeatedly", !irqOneShot},
{"7", "IRQ pulse mode", irqPulseMode ? "Pulse bit10" : "Toggle bit10", !irqPulseMode},
{"8-9", "Clock source", clockSource, clockSource.compare("Sysclock") != 0},
{"10", "IRQ request", timer->mode.interruptRequest ? "No" : "Pending", (bool)!timer->mode.interruptRequest},
{"11", "Reached target", timer->mode.reachedTarget ? "Yes" : "No", (bool)timer->mode.reachedTarget},
{"12", "Reached 0xFFFF", timer->mode.reachedFFFF ? "Yes" : "No", (bool)timer->mode.reachedFFFF},
};
drawRegisterFields(fmt::format("flags##timer{}", 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