mirror of
https://github.com/JaCzekanski/Avocado.git
synced 2024-06-02 03:07:39 -04:00
fb7997fc16
gui: fixes
168 lines
5.9 KiB
C++
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
|