Emulator debugger GUI updates
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
#include "app/emu/emulator.h"
|
#include "app/emu/emulator.h"
|
||||||
|
|
||||||
|
#include <imgui/imgui.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -11,8 +13,22 @@ namespace yaze {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool ShouldDisplay(const InstructionEntry& entry, const char* filter,
|
||||||
|
bool showAll) {
|
||||||
|
// Implement logic to determine if the entry should be displayed based on the
|
||||||
|
// filter and showAll flag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
using ImGui::NextColumn;
|
||||||
|
using ImGui::SameLine;
|
||||||
|
using ImGui::Separator;
|
||||||
|
using ImGui::TableNextColumn;
|
||||||
|
using ImGui::Text;
|
||||||
|
|
||||||
void Emulator::Run() {
|
void Emulator::Run() {
|
||||||
// Initialize the emulator if a ROM is loaded
|
|
||||||
if (!snes_.running() && loading_) {
|
if (!snes_.running() && loading_) {
|
||||||
if (rom()->isLoaded()) {
|
if (rom()->isLoaded()) {
|
||||||
snes_.Init(*rom());
|
snes_.Init(*rom());
|
||||||
@@ -20,15 +36,11 @@ void Emulator::Run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the emulator output
|
|
||||||
RenderNavBar();
|
RenderNavBar();
|
||||||
|
|
||||||
if (running_) {
|
if (running_) {
|
||||||
// Handle user input events
|
|
||||||
HandleEvents();
|
HandleEvents();
|
||||||
// Update the emulator state
|
|
||||||
UpdateEmulator();
|
UpdateEmulator();
|
||||||
|
|
||||||
RenderEmulator();
|
RenderEmulator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,10 +50,6 @@ void Emulator::Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::RenderEmulator() {
|
void Emulator::RenderEmulator() {
|
||||||
// Get the emulator output and render it to the child window
|
|
||||||
// You can use the ImGui::Image function to display the emulator output as a
|
|
||||||
// texture
|
|
||||||
// ...
|
|
||||||
ImVec2 size = ImVec2(320, 240);
|
ImVec2 size = ImVec2(320, 240);
|
||||||
if (snes_.running()) {
|
if (snes_.running()) {
|
||||||
ImGui::Image((void*)snes_.Ppu().GetScreen()->texture(), size, ImVec2(0, 0),
|
ImGui::Image((void*)snes_.Ppu().GetScreen()->texture(), size, ImVec2(0, 0),
|
||||||
@@ -77,7 +85,6 @@ void Emulator::RenderNavBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Debug")) {
|
if (ImGui::BeginMenu("Debug")) {
|
||||||
ImGui::MenuItem("PPU Register Viewer", nullptr, &show_ppu_reg_viewer_);
|
|
||||||
MENU_ITEM("Debugger") { debugger_ = !debugger_; }
|
MENU_ITEM("Debugger") { debugger_ = !debugger_; }
|
||||||
if (ImGui::MenuItem("Integrated Debugger", nullptr,
|
if (ImGui::MenuItem("Integrated Debugger", nullptr,
|
||||||
&integrated_debugger_mode_)) {
|
&integrated_debugger_mode_)) {
|
||||||
@@ -93,8 +100,8 @@ void Emulator::RenderNavBar() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Options")) {
|
if (ImGui::BeginMenu("Options")) {
|
||||||
MENU_ITEM("Audio") {}
|
|
||||||
MENU_ITEM("Input") {}
|
MENU_ITEM("Input") {}
|
||||||
|
MENU_ITEM("Audio") {}
|
||||||
MENU_ITEM("Video") {}
|
MENU_ITEM("Video") {}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@@ -116,14 +123,16 @@ void Emulator::RenderDebugger() {
|
|||||||
// Define a lambda with the actual debugger
|
// Define a lambda with the actual debugger
|
||||||
auto debugger = [&]() {
|
auto debugger = [&]() {
|
||||||
if (ImGui::BeginTable(
|
if (ImGui::BeginTable(
|
||||||
"DebugTable", 2,
|
"DebugTable", 3,
|
||||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) {
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) {
|
||||||
ImGui::TableNextColumn();
|
TableNextColumn();
|
||||||
RenderCpuState(snes_.Cpu());
|
RenderCpuState(snes_.Cpu());
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
TableNextColumn();
|
||||||
RenderCPUInstructionLog(snes_.Cpu().instruction_log_);
|
RenderCPUInstructionLog(snes_.Cpu().instruction_log_);
|
||||||
|
|
||||||
|
TableNextColumn();
|
||||||
|
RenderBreakpointList();
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -137,47 +146,100 @@ void Emulator::RenderDebugger() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::RenderCpuState(CPU& cpu) {
|
void Emulator::RenderBreakpointList() {
|
||||||
ImGui::Columns(2, "RegistersColumns");
|
Text("Breakpoints");
|
||||||
ImGui::Separator();
|
Separator();
|
||||||
ImGui::Text("A: 0x%04X", cpu.A);
|
static char breakpoint_input[10] = "";
|
||||||
ImGui::NextColumn();
|
static int current_memory_mode = 0;
|
||||||
ImGui::Text("D: 0x%04X", cpu.D);
|
|
||||||
ImGui::NextColumn();
|
static bool read_mode = false;
|
||||||
ImGui::Text("X: 0x%04X", cpu.X);
|
static bool write_mode = false;
|
||||||
ImGui::NextColumn();
|
static bool execute_mode = false;
|
||||||
ImGui::Text("DB: 0x%02X", cpu.DB);
|
|
||||||
ImGui::NextColumn();
|
if (ImGui::Combo("##TypeOfMemory", ¤t_memory_mode, "PRG\0RAM\0")) {
|
||||||
ImGui::Text("Y: 0x%04X", cpu.Y);
|
|
||||||
ImGui::NextColumn();
|
|
||||||
ImGui::Text("PB: 0x%02X", cpu.PB);
|
|
||||||
ImGui::NextColumn();
|
|
||||||
ImGui::Text("PC: 0x%04X", cpu.PC);
|
|
||||||
ImGui::NextColumn();
|
|
||||||
ImGui::Text("E: %d", cpu.E);
|
|
||||||
ImGui::NextColumn();
|
|
||||||
ImGui::Columns(1);
|
|
||||||
ImGui::Separator();
|
|
||||||
// Call Stack
|
|
||||||
if (ImGui::CollapsingHeader("Call Stack")) {
|
|
||||||
// For each return address in the call stack:
|
|
||||||
ImGui::Text("Return Address: 0x%08X", 0xFFFFFF); // Placeholder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::Checkbox("Read", &read_mode);
|
||||||
|
SameLine();
|
||||||
|
ImGui::Checkbox("Write", &write_mode);
|
||||||
|
SameLine();
|
||||||
|
ImGui::Checkbox("Execute", &execute_mode);
|
||||||
|
|
||||||
|
// Breakpoint input fields and buttons
|
||||||
|
if (ImGui::InputText("##BreakpointInput", breakpoint_input, 10,
|
||||||
|
ImGuiInputTextFlags_EnterReturnsTrue)) {
|
||||||
|
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
||||||
|
snes_.Cpu().SetBreakpoint(breakpoint);
|
||||||
|
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
||||||
|
}
|
||||||
|
SameLine();
|
||||||
|
if (ImGui::Button("Add")) {
|
||||||
|
int breakpoint = std::stoi(breakpoint_input, nullptr, 16);
|
||||||
|
snes_.Cpu().SetBreakpoint(breakpoint);
|
||||||
|
memset(breakpoint_input, 0, sizeof(breakpoint_input));
|
||||||
|
}
|
||||||
|
SameLine();
|
||||||
|
if (ImGui::Button("Clear")) {
|
||||||
|
snes_.Cpu().ClearBreakpoints();
|
||||||
|
}
|
||||||
|
Separator();
|
||||||
|
auto breakpoints = snes_.Cpu().GetBreakpoints();
|
||||||
|
if (!breakpoints.empty()) {
|
||||||
|
Text("Breakpoints:");
|
||||||
|
ImGui::BeginChild("BreakpointsList", ImVec2(0, 100), true);
|
||||||
|
for (auto breakpoint : breakpoints) {
|
||||||
|
if (ImGui::Selectable(absl::StrFormat("0x%04X", breakpoint).c_str())) {
|
||||||
|
// Jump to breakpoint
|
||||||
|
// snes_.Cpu().JumpToBreakpoint(breakpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::RenderCpuState(CPU& cpu) {
|
||||||
|
if (ImGui::CollapsingHeader("Register Values",
|
||||||
|
ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
ImGui::Columns(2, "RegistersColumns");
|
||||||
|
Separator();
|
||||||
|
Text("A: 0x%04X", cpu.A);
|
||||||
|
NextColumn();
|
||||||
|
Text("D: 0x%04X", cpu.D);
|
||||||
|
NextColumn();
|
||||||
|
Text("X: 0x%04X", cpu.X);
|
||||||
|
NextColumn();
|
||||||
|
Text("DB: 0x%02X", cpu.DB);
|
||||||
|
NextColumn();
|
||||||
|
Text("Y: 0x%04X", cpu.Y);
|
||||||
|
NextColumn();
|
||||||
|
Text("PB: 0x%02X", cpu.PB);
|
||||||
|
NextColumn();
|
||||||
|
Text("PC: 0x%04X", cpu.PC);
|
||||||
|
NextColumn();
|
||||||
|
Text("E: %d", cpu.E);
|
||||||
|
NextColumn();
|
||||||
|
ImGui::Columns(1);
|
||||||
|
Separator();
|
||||||
|
}
|
||||||
|
// Call Stack
|
||||||
|
if (ImGui::CollapsingHeader("Call Stack", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
// For each return address in the call stack:
|
||||||
|
Text("Return Address: 0x%08X", 0xFFFFFF); // Placeholder
|
||||||
|
}
|
||||||
|
|
||||||
|
static int debugger_mode_ = 0;
|
||||||
|
const char* debugger_modes_[] = {"Run", "Step", "Pause"};
|
||||||
|
Text("Mode");
|
||||||
|
ImGui::ListBox("##DebuggerMode", &debugger_mode_, debugger_modes_,
|
||||||
|
IM_ARRAYSIZE(debugger_modes_));
|
||||||
|
|
||||||
|
snes_.SetCpuMode(debugger_mode_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Emulator::RenderMemoryViewer() {
|
void Emulator::RenderMemoryViewer() {
|
||||||
// Render memory viewer
|
// Render memory viewer
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool ShouldDisplay(const InstructionEntry& entry, const char* filter,
|
|
||||||
bool showAll) {
|
|
||||||
// Implement logic to determine if the entry should be displayed based on the
|
|
||||||
// filter and showAll flag
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void Emulator::RenderCPUInstructionLog(
|
void Emulator::RenderCPUInstructionLog(
|
||||||
const std::vector<InstructionEntry>& instructionLog) {
|
const std::vector<InstructionEntry>& instructionLog) {
|
||||||
if (ImGui::CollapsingHeader("CPU Instruction Log")) {
|
if (ImGui::CollapsingHeader("CPU Instruction Log")) {
|
||||||
@@ -193,7 +255,8 @@ void Emulator::RenderCPUInstructionLog(
|
|||||||
ImGui::Checkbox("Show All Opcodes", &showAllOpcodes);
|
ImGui::Checkbox("Show All Opcodes", &showAllOpcodes);
|
||||||
|
|
||||||
// Instruction list
|
// Instruction list
|
||||||
ImGui::BeginChild("InstructionList");
|
ImGui::BeginChild("InstructionList", ImVec2(0, 0),
|
||||||
|
ImGuiChildFlags_AlwaysAutoResize);
|
||||||
for (const auto& entry : instructionLog) {
|
for (const auto& entry : instructionLog) {
|
||||||
if (ShouldDisplay(entry, filterBuf, showAllOpcodes)) {
|
if (ShouldDisplay(entry, filterBuf, showAllOpcodes)) {
|
||||||
if (ImGui::Selectable(absl::StrFormat("%04X: %02X %s %s", entry.address,
|
if (ImGui::Selectable(absl::StrFormat("%04X: %02X %s %s", entry.address,
|
||||||
|
|||||||
@@ -30,19 +30,18 @@ class Emulator : public SharedROM {
|
|||||||
void UpdateEmulator();
|
void UpdateEmulator();
|
||||||
|
|
||||||
void RenderDebugger();
|
void RenderDebugger();
|
||||||
|
void RenderBreakpointList();
|
||||||
void RenderCpuState(CPU& cpu);
|
void RenderCpuState(CPU& cpu);
|
||||||
void RenderMemoryViewer();
|
void RenderMemoryViewer();
|
||||||
|
|
||||||
void RenderCPUInstructionLog(
|
void RenderCPUInstructionLog(
|
||||||
const std::vector<InstructionEntry>& instructionLog);
|
const std::vector<InstructionEntry>& instructionLog);
|
||||||
|
|
||||||
// Member variables to store internal state and resources
|
|
||||||
SNES snes_;
|
SNES snes_;
|
||||||
|
|
||||||
bool running_ = false;
|
bool running_ = false;
|
||||||
bool debugger_ = false;
|
bool debugger_ = true;
|
||||||
bool loading_ = false;
|
bool loading_ = false;
|
||||||
bool show_ppu_reg_viewer_ = false;
|
|
||||||
bool integrated_debugger_mode_ = true;
|
bool integrated_debugger_mode_ = true;
|
||||||
bool separate_debugger_mode_ = false;
|
bool separate_debugger_mode_ = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ void SNES::Run() {
|
|||||||
|
|
||||||
// Update the CPU
|
// Update the CPU
|
||||||
cpu.UpdateClock(delta_time);
|
cpu.UpdateClock(delta_time);
|
||||||
cpu.Update();
|
cpu.Update(GetCpuMode());
|
||||||
|
|
||||||
// Update the PPU
|
// Update the PPU
|
||||||
ppu.UpdateClock(delta_time);
|
ppu.UpdateClock(delta_time);
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ class SNES : public DMA {
|
|||||||
auto Cpu() -> CPU& { return cpu; }
|
auto Cpu() -> CPU& { return cpu; }
|
||||||
auto Ppu() -> PPU& { return ppu; }
|
auto Ppu() -> PPU& { return ppu; }
|
||||||
|
|
||||||
|
void SetCpuMode(int mode) { cpu_mode_ = mode; }
|
||||||
|
CPU::UpdateMode GetCpuMode() const {
|
||||||
|
return static_cast<CPU::UpdateMode>(cpu_mode_);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WriteToRegister(uint16_t address, uint8_t value) {
|
void WriteToRegister(uint16_t address, uint8_t value) {
|
||||||
memory_.WriteByte(address, value);
|
memory_.WriteByte(address, value);
|
||||||
@@ -96,6 +101,7 @@ class SNES : public DMA {
|
|||||||
// Other private member variables
|
// Other private member variables
|
||||||
bool running_ = false;
|
bool running_ = false;
|
||||||
int scanline;
|
int scanline;
|
||||||
|
int cpu_mode_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emu
|
} // namespace emu
|
||||||
|
|||||||
Reference in New Issue
Block a user