diff --git a/core/ARM/cpu.h b/core/ARM/cpu.h index 1323bf1..d94754e 100644 --- a/core/ARM/cpu.h +++ b/core/ARM/cpu.h @@ -40,9 +40,4 @@ struct CPU { LOG_INFO(ARM, "X{} = {}", reg, x(reg)); // X0 = 0... } } - - void get_state(u64* out_regs, u64& out_pc) const { - std::memcpy(out_regs, regs, sizeof(regs)); - out_pc = pc; - } }; diff --git a/core/main.cpp b/core/main.cpp index 09c0d90..335c331 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -14,106 +14,76 @@ #include "gui/panels/CPUPanel.h" #include "gui/panels/PerformancePanel.h" -std::shared_ptr console_panel; -std::shared_ptr cpu_panel; -std::shared_ptr performance_panel; // CPU test function -void cpuTest() -{ +void cpuTest() { CPU cpu; cpu.pc = 0; + // Simple ARMv8 program in memory (MOVZ X0, #5; ADD X0, X0, #3; RET) + // These are placeholders; real encoding will be parsed later cpu.write_byte(0, 0x05); // MOVZ placeholder cpu.write_byte(4, 0x03); // ADD placeholder cpu.write_byte(8, 0xFF); // RET placeholder + LOG_INFO(ARM, "{}", cpu.read_byte(0)); + JIT jit; jit.translate_and_run(cpu); + cpu.print_debug_information(); + LOG_INFO(ARM, "X0 = {}", cpu.x(0)); - - if (cpu_panel) - cpu_panel->UpdateState(cpu); } -void initGUI(Pound::GUI::GUIManager *gui_manager) -{ - gui_manager->AddPanel(console_panel); - gui_manager->AddPanel(cpu_panel); - gui_manager->AddPanel(performance_panel); - - Pound::GUI::TabBar *file_menu = gui_manager->AddTabs("File"); - Pound::GUI::TabBar *emulation_menu = gui_manager->AddTabs("Emulation"); - Pound::GUI::TabBar *view_menu = gui_manager->AddTabs("View"); - Pound::GUI::TabBar *help_menu = gui_manager->AddTabs("Help"); - - gui_manager->AddSubTab(file_menu, "Open ROM...", []() {}); - gui_manager->AddSubTab(file_menu, "Exit", []() - { - LOG_INFO(Render, "Exiting Pound Emulator"); - std::exit(0); }); - - gui_manager->AddSubTab(emulation_menu, "Run CPU Test", []() - { cpuTest(); }); - gui_manager->AddSubTab(emulation_menu, "Pause", []() - { LOG_INFO(Render, "Pausing emulation (not implemented yet)"); }); - gui_manager->AddSubTab(emulation_menu, "Resume", []() - { LOG_INFO(Render, "Resuming emulation (not implemented yet)"); }); - - gui_manager->AddSubTab(view_menu, "Console", console_panel->IsVisible(), - [console_panel](bool is_checked) - { - console_panel->SetVisible(is_checked); - }); - - gui_manager->AddSubTab(view_menu, "CPU State", cpu_panel->IsVisible(), - [cpu_panel](bool is_checked) - { - cpu_panel->SetVisible(is_checked); - }); - - gui_manager->AddSubTab(view_menu, "Performance", performance_panel->IsVisible(), - [performance_panel](bool is_checked) - { - performance_panel->SetVisible(is_checked); - }); - - gui_manager->AddSubTab(help_menu, "About", []() - { LOG_INFO(Render, "Pound Emulator is a pre-alpha project. Visit our GitHub for more information."); }); - - - cpu_panel->SetCPUTestCallback(cpuTest); - console_panel->AddLog("[INFO] Pound Emulator started"); - console_panel->AddLog("[INFO] Version: Pre-Alpha"); -} - -int main() -{ +int main() { Base::Log::Initialize(); Base::Log::Start(); const auto config_dir = Base::FS::GetUserPath(Base::FS::PathType::BinaryDir); Config::Load(config_dir / "config.toml"); + // Create GUI manager auto gui_manager = std::make_unique(); - if (!gui_manager->Initialize("Pound Emulator", Config::windowWidth(), Config::windowHeight())) - { + + // Initialize GUI + if (!gui_manager->Initialize("Pound Emulator", Config::windowWidth(), Config::windowHeight())) { LOG_ERROR(Render, "Failed to initialize GUI"); return -1; } - console_panel = std::make_shared(); - cpu_panel = std::make_shared(); - performance_panel = std::make_shared(); - - initGUI(gui_manager.get()); - - while (gui_manager->IsRunning()) - { + // Create and add panels + auto console_panel = std::make_shared(); + auto cpu_panel = std::make_shared(); + auto performance_panel = std::make_shared(); + + gui_manager->AddPanel(console_panel); + gui_manager->AddPanel(cpu_panel); + gui_manager->AddPanel(performance_panel); + + // Set up callbacks + auto cpu_test_callback = [console_panel]() { + console_panel->AddLog("[INFO] Running CPU test..."); + cpuTest(); + console_panel->AddLog("[INFO] CPU test completed. Check terminal for details."); + }; + + gui_manager->SetCPUTestCallback(cpu_test_callback); + cpu_panel->SetCPUTestCallback(cpu_test_callback); + + // Add initial console message + console_panel->AddLog("[INFO] Pound Emulator started"); + console_panel->AddLog("[INFO] Version: Pre-Alpha"); + + // Main loop + while (gui_manager->IsRunning()) { gui_manager->RunFrame(); + + // Small delay to prevent excessive CPU usage std::this_thread::sleep_for(std::chrono::milliseconds(5)); } - gui_manager->Shutdown(); + // Cleanup + gui_manager->Shutdown(); + return 0; -} +} \ No newline at end of file diff --git a/gui/GUIManager.cpp b/gui/GUIManager.cpp index 3d1225d..39f50f7 100644 --- a/gui/GUIManager.cpp +++ b/gui/GUIManager.cpp @@ -34,7 +34,6 @@ namespace Pound::GUI ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - // io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Setup style ApplyTheme(); @@ -70,8 +69,11 @@ namespace Pound::GUI window->ProcessEvents(); BeginFrame(); - RenderTabBars(); + // Render menu bar + RenderMainMenuBar(); + + // Render all panels for (auto &panel : panels) { if (panel->IsVisible()) @@ -80,6 +82,7 @@ namespace Pound::GUI } } + // Demo window for debugging if (show_demo_window) { ImGui::ShowDemoWindow(&show_demo_window); @@ -109,6 +112,85 @@ namespace Pound::GUI window->SwapBuffers(); } + void GUIManager::RenderMainMenuBar() + { + if (ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("Load ROM...", "Ctrl+O")) + { + // TODO: Implement ROM loading + } + ImGui::Separator(); + if (ImGui::MenuItem("Exit", "Alt+F4")) + { + window->SetShouldClose(true); + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Emulation")) + { + if (ImGui::MenuItem("Run CPU Test")) + { + if (cpu_test_callback) + { + cpu_test_callback(); + } + } + ImGui::Separator(); + if (ImGui::MenuItem("Pause", "F5")) + { + // TODO: Implement pause + } + if (ImGui::MenuItem("Reset", "F6")) + { + // TODO: Implement reset + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("View")) + { + for (auto &panel : panels) + { + bool visible = panel->IsVisible(); + if (ImGui::MenuItem(panel->GetName().c_str(), nullptr, &visible)) + { + panel->SetVisible(visible); + } + } + ImGui::Separator(); + if (ImGui::MenuItem("ImGui Demo", nullptr, &show_demo_window)) + { + // Toggle handled by flag + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Tools")) + { + if (ImGui::MenuItem("Settings", "Ctrl+,")) + { + // TODO: Open settings panel + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Help")) + { + if (ImGui::MenuItem("About")) + { + // TODO: Show about dialog + } + ImGui::EndMenu(); + } + + ImGui::EndMainMenuBar(); + } + } + void GUIManager::ApplyTheme() { ImGuiStyle &style = ImGui::GetStyle(); @@ -190,114 +272,4 @@ namespace Pound::GUI }), panels.end()); } - - TabBar *GUIManager::AddTabs(const std::string &name) - { - auto new_bar = std::make_unique(); - new_bar->id = name; - m_tab_bars.push_back(std::move(new_bar)); - return m_tab_bars.back().get(); - } - - void GUIManager::AddSubTab(TabBar *parent_bar, const std::string &name, std::function callback) - { - if (!parent_bar) - { - LOG_WARNING(Render, "Trying to add a sub-tab to a null TabBar."); - return; - } - - TabItem new_item; - new_item.name = name; - new_item.render_callback = std::move(callback); - parent_bar->items.push_back(std::move(new_item)); - } - - void GUIManager::AddSubTab(TabBar *parent_bar, const std::string &name, const std::string &shortcut, std::function callback) - { - if (!parent_bar) - { - LOG_WARNING(Render, "Trying to add a sub-tab to a null TabBar."); - return; - } - - TabItem new_item; - new_item.name = name; - new_item.shortcut = shortcut; - new_item.render_callback = std::move(callback); - parent_bar->items.push_back(std::move(new_item)); - } - - void GUIManager::AddSubTab(TabBar *parent_bar, const std::string &name, bool *p_selected, std::function callback) - { - if (!parent_bar) - { - LOG_WARNING(Render, "Trying to add a sub-tab to a null TabBar."); - return; - } - - TabItem new_item; - new_item.name = name; - new_item.p_selected = p_selected; - new_item.checked_callback = std::move(callback); - parent_bar->items.push_back(std::move(new_item)); - } - - void GUIManager::AddSubTab(TabBar *parent_bar, const std::string &name, bool *p_selected, const std::string &shortcut, std::function callback) - { - if (!parent_bar) - { - LOG_WARNING(Render, "Trying to add a sub-tab to a null TabBar."); - return; - } - - TabItem new_item; - new_item.name = name; - new_item.shortcut = shortcut; - new_item.p_selected = p_selected; - new_item.checked_callback = std::move(callback); - parent_bar->items.push_back(std::move(new_item)); - } - - void GUIManager::RenderTabBarContents(TabBar &bar) - { - for (const auto &item : bar.items) - { - if (item.nested_tabs) - { - if (ImGui::BeginMenu(item.name.c_str())) - { - RenderTabBarContents(*item.nested_tabs); - ImGui::EndMenu(); - } - } - else - { - const char *shortcut = item.shortcut.empty() ? nullptr : item.shortcut.c_str(); - if (ImGui::MenuItem(item.name.c_str(), shortcut, item.p_selected)) - { - if (item.p_selected && item.checked_callback) - { - item.checked_callback(*item.p_selected); - } - } - } - } - } - - void GUIManager::RenderTabBars() - { - if (ImGui::BeginMainMenuBar()) - { - for (const auto &bar_ptr : m_tab_bars) - { - if (ImGui::BeginMenu(bar_ptr->id.c_str())) - { - RenderTabBarContents(*bar_ptr); - ImGui::EndMenu(); - } - } - ImGui::EndMainMenuBar(); - } - } } \ No newline at end of file diff --git a/gui/GUIManager.h b/gui/GUIManager.h index b8e2512..5a8ec67 100644 --- a/gui/GUIManager.h +++ b/gui/GUIManager.h @@ -7,63 +7,38 @@ #include "Window.h" #include "Panel.h" -namespace Pound::GUI -{ +namespace Pound::GUI { - struct TabBar; +class GUIManager { +public: + GUIManager(); + ~GUIManager(); - struct TabItem - { - std::string name; - std::string shortcut; - bool *p_selected = nullptr; - std::function render_callback; - std::function checked_callback; - std::unique_ptr nested_tabs = nullptr; - }; - - struct TabBar - { - std::string id; - std::vector items; - bool is_visible = true; - }; - - class GUIManager - { - public: - GUIManager(); - ~GUIManager(); - - bool Initialize(const std::string &title, int width, int height); - void Shutdown(); - - void RunFrame(); - bool IsRunning() const { return running && window && !window->ShouldClose(); } - - Window *GetWindow() const { return window.get(); } - - void AddPanel(std::shared_ptr panel); - void RemovePanel(const std::string &name); - - TabBar *AddTabs(const std::string &name); - void AddSubTab(TabBar *parent_bar, const std::string &name, std::function callback = nullptr); - void AddSubTab(TabBar *parent_bar, const std::string &name, const std::string &shortcut, std::function callback); - void AddSubTab(TabBar *parent_bar, const std::string &name, bool *p_selected, std::function callback = nullptr); - void AddSubTab(TabBar *parent_bar, const std::string &name, bool *p_selected, const std::string &shortcut, std::function callback = nullptr); - - private: - void BeginFrame(); - void EndFrame(); - void ApplyTheme(); - void RenderTabBars(); - void RenderTabBarContents(TabBar &bar); - - std::unique_ptr window; - std::vector> panels; - bool running = false; - bool show_demo_window = false; - std::vector> m_tab_bars; - }; + bool Initialize(const std::string& title, int width, int height); + void Shutdown(); + + void RunFrame(); + bool IsRunning() const { return running && window && !window->ShouldClose(); } + + void AddPanel(std::shared_ptr panel); + void RemovePanel(const std::string& name); + + // Callback for external systems + void SetCPUTestCallback(std::function callback) { cpu_test_callback = callback; } + +private: + void BeginFrame(); + void EndFrame(); + void RenderMainMenuBar(); + void ApplyTheme(); + + std::unique_ptr window; + std::vector> panels; + bool running = false; + bool show_demo_window = false; + + // Callbacks + std::function cpu_test_callback; +}; } // namespace Pound::GUI \ No newline at end of file diff --git a/gui/Panel.h b/gui/Panel.h index cd2ddc6..87c6269 100644 --- a/gui/Panel.h +++ b/gui/Panel.h @@ -16,7 +16,7 @@ namespace Pound::GUI virtual void Render() = 0; const std::string &GetName() const { return name; } - bool* IsVisible() { return &visible; } + bool IsVisible() const { return visible; } void SetVisible(bool vis) { visible = vis; } protected: diff --git a/gui/panels/CPUPanel.cpp b/gui/panels/CPUPanel.cpp index 75f939c..3a8f057 100644 --- a/gui/panels/CPUPanel.cpp +++ b/gui/panels/CPUPanel.cpp @@ -1,86 +1,143 @@ -// In gui/panels/CPUPanel.cpp +// Copyright 2025 Pound Emulator Project. All rights reserved. #include "CPUPanel.h" #include "../Colors.h" -#include -#include +#include +#include -namespace Pound::GUI -{ - CPUPanel::CPUPanel() : Panel("CPU Debug") {} +namespace Pound::GUI { - void CPUPanel::UpdateState(const CPU& cpu) - { - cpu.get_state(cpu_state.registers.data(), cpu_state.pc); - } +CPUPanel::CPUPanel() : Panel("CPU Debug") {} - void CPUPanel::SetCPUTestCallback(std::function callback) - { - cpu_test_callback = std::move(callback); - } - - void CPUPanel::Render() - { - if (!visible) { - return; - } - if (!ImGui::Begin(name.c_str(), &visible, ImGuiWindowFlags_NoCollapse)) - { - ImGui::End(); - return; - } - - ImGui::PushStyleColor(ImGuiCol_Button, Colors::WithAlpha(Colors::Primary, 0.40f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, Colors::PrimaryHover); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, Colors::PrimaryActive); - if (ImGui::Button("Run CPU Test", ImVec2(120, 0))) - { - if (cpu_test_callback) { - cpu_test_callback(); - show_test_result = true; - } - } - ImGui::PopStyleColor(3); - ImGui::Separator(); - if (ImGui::BeginTabBar("CPUTabBar")) - { - if (ImGui::BeginTabItem("Registers")) - { - ImGui::Text("General Purpose Registers:"); - ImGui::Separator(); - if (ImGui::BeginTable("RegisterTable", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) - { - ImGui::TableSetupColumn("Register"); ImGui::TableSetupColumn("Value"); - ImGui::TableSetupColumn("Register"); ImGui::TableSetupColumn("Value"); - ImGui::TableHeadersRow(); - - for (int i = 0; i < 16; i++) - { - ImGui::TableNextRow(); - ImGui::TableSetColumnIndex(0); ImGui::Text("X%d", i); - ImGui::TableSetColumnIndex(1); ImGui::Text("0x%016" PRIX64, cpu_state.registers[i]); - - if (i + 16 < 31) - { - ImGui::TableSetColumnIndex(2); ImGui::Text("X%d", i + 16); - ImGui::TableSetColumnIndex(3); ImGui::Text("0x%016" PRIX64, cpu_state.registers[i + 16]); - } - } - ImGui::EndTable(); - } - - ImGui::Spacing(); - ImGui::Text("Program Counter: 0x%016" PRIX64, cpu_state.pc); - ImGui::Text("Flags (PState): 0x%08X", cpu_state.flags); - ImGui::EndTabItem(); - } - - if (ImGui::BeginTabItem("Memory")) { /*...*/ ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Disassembly")) { /*...*/ ImGui::EndTabItem(); } - - ImGui::EndTabBar(); - } +void CPUPanel::Render() { + if (!ImGui::Begin(name.c_str(), &visible, ImGuiWindowFlags_NoCollapse)) { ImGui::End(); + return; } + + // Control buttons with custom colors + ImGui::PushStyleColor(ImGuiCol_Button, Colors::WithAlpha(Colors::Primary, 0.40f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, Colors::PrimaryHover); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, Colors::PrimaryActive); + + if (ImGui::Button("Run CPU Test", ImVec2(120, 0))) { + if (cpu_test_callback) { + cpu_test_callback(); + show_test_result = true; + } + } + + ImGui::SameLine(); + if (ImGui::Button("Step", ImVec2(60, 0))) { + // TODO: Implement step functionality + } + + ImGui::SameLine(); + + // Reset button with secondary color + ImGui::PushStyleColor(ImGuiCol_Button, Colors::WithAlpha(Colors::Secondary, 0.40f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, Colors::SecondaryHover); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, Colors::SecondaryActive); + + if (ImGui::Button("Reset", ImVec2(60, 0))) { + // TODO: Implement reset functionality + } + + ImGui::PopStyleColor(6); // Pop all 6 color changes + + ImGui::Separator(); + + // Tabs for different views + if (ImGui::BeginTabBar("CPUTabBar")) { + if (ImGui::BeginTabItem("Registers")) { + // General purpose registers + ImGui::Text("General Purpose Registers:"); + ImGui::Separator(); + + if (ImGui::BeginTable("RegisterTable", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 60.0f); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 120.0f); + ImGui::TableSetupColumn("Register", ImGuiTableColumnFlags_WidthFixed, 60.0f); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, 120.0f); + ImGui::TableHeadersRow(); + + for (int i = 0; i < 16; i++) { + ImGui::TableNextRow(); + + // Left column + ImGui::TableSetColumnIndex(0); + ImGui::Text("X%d", i); + ImGui::TableSetColumnIndex(1); + ImGui::Text("0x%016llX", cpu_state.registers[i]); + + // Right column + if (i + 16 < 32) { + ImGui::TableSetColumnIndex(2); + ImGui::Text("X%d", i + 16); + ImGui::TableSetColumnIndex(3); + ImGui::Text("0x%016llX", cpu_state.registers[i + 16]); + } + } + + ImGui::EndTable(); + } + + ImGui::Spacing(); + ImGui::Text("Program Counter: 0x%016llX", cpu_state.pc); + ImGui::Text("Flags: 0x%08X", cpu_state.flags); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Memory")) { + static char addr_input[17] = "0000000000000000"; + ImGui::Text("Memory Viewer"); + ImGui::Separator(); + + ImGui::InputText("Address", addr_input, sizeof(addr_input), + ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + + // TODO: Implement memory viewer + ImGui::Text("Memory viewer will be implemented here"); + + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Disassembly")) { + ImGui::Text("Disassembly View"); + ImGui::Separator(); + + // TODO: Implement disassembly view + ImGui::Text("Disassembly will be shown here"); + + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + + // Test result popup + if (show_test_result) { + ImGui::OpenPopup("CPU Test Result"); + } + + if (ImGui::BeginPopupModal("CPU Test Result", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("The CPU test has been executed successfully!"); + ImGui::Text("Check the console for detailed output."); + ImGui::Separator(); + ImGui::Text("Note: Pound is still in pre-alpha state."); + + ImGui::Spacing(); + + if (ImGui::Button("OK", ImVec2(120, 0))) { + show_test_result = false; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + ImGui::End(); +} } // namespace Pound::GUI \ No newline at end of file diff --git a/gui/panels/CPUPanel.h b/gui/panels/CPUPanel.h index 605567b..2e92f03 100644 --- a/gui/panels/CPUPanel.h +++ b/gui/panels/CPUPanel.h @@ -1,31 +1,32 @@ +// Copyright 2025 Pound Emulator Project. All rights reserved. #pragma once #include "../Panel.h" -#include "ARM/cpu.h" #include -#include -#include namespace Pound::GUI { - struct CPUState - { - std::array registers{}; - uint64_t pc = 0; - uint32_t flags = 0; - }; class CPUPanel : public Panel { public: CPUPanel(); + void Render() override; - void SetCPUTestCallback(std::function callback); - void UpdateState(const CPU& cpu); + void SetCPUTestCallback(std::function callback) { cpu_test_callback = callback; } + void ShowTestResult(bool show = true) { show_test_result = show; } private: - CPUState cpu_state; - bool show_test_result = false; std::function cpu_test_callback; + bool show_test_result = false; + + // CPU state display (placeholder for future integration) + struct CPUState + { + uint64_t registers[32] = {0}; + uint64_t pc = 0; + uint32_t flags = 0; + } cpu_state; }; -} \ No newline at end of file + +} // namespace Pound::GUI \ No newline at end of file diff --git a/gui/panels/ConsolePanel.cpp b/gui/panels/ConsolePanel.cpp index 2cf63d4..31b9e28 100644 --- a/gui/panels/ConsolePanel.cpp +++ b/gui/panels/ConsolePanel.cpp @@ -14,10 +14,6 @@ namespace Pound::GUI void ConsolePanel::Render() { - if (!visible) { - return; - } - if (!ImGui::Begin(name.c_str(), &visible)) { ImGui::End(); diff --git a/gui/panels/PerformancePanel.cpp b/gui/panels/PerformancePanel.cpp index a02cf4c..80cb0e8 100644 --- a/gui/panels/PerformancePanel.cpp +++ b/gui/panels/PerformancePanel.cpp @@ -13,10 +13,6 @@ namespace Pound::GUI void PerformancePanel::Render() { - if (!visible) { - return; - } - if (!ImGui::Begin(name.c_str(), &visible)) { ImGui::End();