Add Debugger interface, RoomObject class

- Log instructions to debugger using experiment flag
- Use BitmapManager for more functionality
- Draw framebuffer and integrated debugger
This commit is contained in:
scawful
2023-11-13 14:51:01 -05:00
parent 75ef4fd9b0
commit 299770922c
27 changed files with 740 additions and 234 deletions

View File

@@ -13,7 +13,7 @@ namespace emu {
void Emulator::Run() {
// Initialize the emulator if a ROM is loaded
if (!snes_.running()) {
if (!snes_.running() && loading_) {
if (rom()->isLoaded()) {
snes_.Init(*rom());
running_ = true;
@@ -23,13 +23,17 @@ void Emulator::Run() {
// Render the emulator output
RenderNavBar();
RenderEmulator();
if (running_) {
// Handle user input events
HandleEvents();
// Update the emulator state
UpdateEmulator();
RenderEmulator();
}
if (debugger_) {
RenderDebugger();
}
}
@@ -38,14 +42,32 @@ void Emulator::RenderEmulator() {
// You can use the ImGui::Image function to display the emulator output as a
// texture
// ...
ImVec2 size = ImVec2(320, 240);
if (snes_.running()) {
ImGui::Image((void*)snes_.Ppu().GetScreen()->texture(), size, ImVec2(0, 0),
ImVec2(1, 1));
ImGui::Separator();
} else {
ImGui::Dummy(size);
ImGui::Separator();
ImGui::Text("Emulator output not available.");
}
}
void Emulator::RenderNavBar() {
MENU_BAR()
if (ImGui::BeginMenu("Game")) {
MENU_ITEM("Power Off") {}
MENU_ITEM("Pause") {}
MENU_ITEM("Load ROM") { loading_ = true; }
MENU_ITEM("Power Off") {
running_ = false;
loading_ = false;
debugger_ = false;
}
MENU_ITEM("Pause") {
running_ = false;
debugger_ = false;
}
MENU_ITEM("Reset") {}
MENU_ITEM("Save State") {}
@@ -56,7 +78,15 @@ void Emulator::RenderNavBar() {
if (ImGui::BeginMenu("Debug")) {
ImGui::MenuItem("PPU Register Viewer", nullptr, &show_ppu_reg_viewer_);
MENU_ITEM("Debugger") {}
MENU_ITEM("Debugger") { debugger_ = !debugger_; }
if (ImGui::MenuItem("Integrated Debugger", nullptr,
&integrated_debugger_mode_)) {
separate_debugger_mode_ = !integrated_debugger_mode_;
}
if (ImGui::MenuItem("Separate Debugger Windows", nullptr,
&separate_debugger_mode_)) {
integrated_debugger_mode_ = !separate_debugger_mode_;
}
MENU_ITEM("Memory Viewer") {}
MENU_ITEM("Tile Viewer") {}
ImGui::EndMenu();
@@ -82,6 +112,102 @@ void Emulator::UpdateEmulator() {
snes_.Run();
}
void Emulator::RenderDebugger() {
// Define a lambda with the actual debugger
auto debugger = [&]() {
if (ImGui::BeginTable(
"DebugTable", 2,
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) {
ImGui::TableNextColumn();
RenderCpuState(snes_.Cpu());
ImGui::TableNextColumn();
RenderCPUInstructionLog(snes_.Cpu().instruction_log_);
ImGui::EndTable();
}
};
if (integrated_debugger_mode_) {
debugger();
} else if (separate_debugger_mode_) {
ImGui::Begin("Debugger");
debugger();
ImGui::End();
}
}
void Emulator::RenderCpuState(CPU& cpu) {
ImGui::Columns(2, "RegistersColumns");
ImGui::Separator();
ImGui::Text("A: 0x%04X", cpu.A);
ImGui::NextColumn();
ImGui::Text("D: 0x%04X", cpu.D);
ImGui::NextColumn();
ImGui::Text("X: 0x%04X", cpu.X);
ImGui::NextColumn();
ImGui::Text("DB: 0x%02X", cpu.DB);
ImGui::NextColumn();
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
}
}
void Emulator::RenderMemoryViewer() {
// 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(
const std::vector<InstructionEntry>& instructionLog) {
if (ImGui::CollapsingHeader("CPU Instruction Log")) {
// Filtering options
static char filterBuf[256];
ImGui::InputText("Filter", filterBuf, IM_ARRAYSIZE(filterBuf));
ImGui::SameLine();
if (ImGui::Button("Clear")) { /* Clear filter logic */
}
// Toggle for showing all opcodes
static bool showAllOpcodes = false;
ImGui::Checkbox("Show All Opcodes", &showAllOpcodes);
// Instruction list
ImGui::BeginChild("InstructionList");
for (const auto& entry : instructionLog) {
if (ShouldDisplay(entry, filterBuf, showAllOpcodes)) {
if (ImGui::Selectable(absl::StrFormat("%04X: %02X %s %s", entry.address,
entry.opcode, entry.operands,
entry.instruction)
.c_str())) {
// Logic to handle click (e.g., jump to address, set breakpoint)
}
}
}
ImGui::EndChild();
}
}
} // namespace emu
} // namespace app
} // namespace yaze