Add fonts + gdb stub WIP

This commit is contained in:
CocoSimone
2022-08-25 23:47:52 +02:00
parent 7c338f4f0c
commit 477e8b7884
13 changed files with 954 additions and 107 deletions

View File

@@ -9,7 +9,9 @@ find_package(fmt REQUIRED)
add_library(frontend-imgui STATIC
Window.cpp
Window.hpp)
Window.hpp
widgets.cpp
debugger.hpp debugger.cpp)
target_include_directories(frontend-imgui PUBLIC
.
@@ -24,4 +26,4 @@ target_include_directories(frontend-imgui PUBLIC
../../../external/parallel-rdp/parallel-rdp-standalone/vulkan
../../../external/parallel-rdp/parallel-rdp-standalone/util
../../../external/parallel-rdp/parallel-rdp-standalone/volk)
target_link_libraries(frontend-imgui PUBLIC SDL2main SDL2 imgui nfd fmt)
target_link_libraries(frontend-imgui PUBLIC ws2_32 SDL2main SDL2 imgui nfd fmt)

View File

@@ -48,12 +48,9 @@ void Window::InitImgui() {
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
instance = GetVkInstance();
physicalDevice = GetVkPhysicalDevice();
@@ -110,50 +107,19 @@ void Window::InitImgui() {
initInfo.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&initInfo, GetVkRenderPass());
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != NULL);
io.Fonts->AddFontDefault();
uiFont = io.Fonts->AddFontFromFileTTF("resources/OpenSans.ttf", 15.f);
codeFont = io.Fonts->AddFontFromFileTTF("resources/Sweet16.ttf", 15.f);
// Upload Fonts
{
VkCommandBuffer commandBuffer = GetVkCommandBuffer();
ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
SubmitRequestedVkCommandBuffer();
}
VkSamplerCreateInfo samplerCreateInfo {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_NEAREST,
.minFilter = VK_FILTER_NEAREST,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.maxAnisotropy = 1.0f,
.minLod = -1000,
.maxLod = 1000,
};
VkSampler sampler;
err = vkCreateSampler(device, &samplerCreateInfo, allocator, &sampler);
check_vk_result(err);
}
Window::~Window() {
VkResult err = vkDeviceWaitIdle(device);
check_vk_result(err);
vkDestroySampler(device, screenSampler, nullptr);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
@@ -162,73 +128,17 @@ Window::~Window() {
SDL_Quit();
}
ImDrawData* Window::Present(const Util::IntrusivePtr<Vulkan::Image>& image, n64::Core& core) {
ImDrawData* Window::Present(n64::Core& core) {
ImGui_ImplVulkan_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
Render(image, core);
Render(core);
ImGui::Render();
return ImGui::GetDrawData();
}
void Window::Render(const Util::IntrusivePtr<Vulkan::Image>& image, n64::Core& core) {
if(windowID == SDL_GetWindowID(SDL_GetMouseFocus())) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open", "O")) {
nfdchar_t *outpath;
const nfdu8filteritem_t filter{"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
}
if (ImGui::MenuItem("Exit")) {
core.done = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Emulation")) {
if (ImGui::MenuItem("Reset")) {
core.Reset();
}
if (ImGui::MenuItem("Stop")) {
core.Stop();
}
if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", nullptr, false, core.romLoaded)) {
core.TogglePause();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
ImGui::Begin("Screen");
if(core.romLoaded && !core.pause) {
auto size = ImGui::GetContentRegionAvail();
float current_aspect_ratio = size.x / size.y;
if (ASPECT_RATIO > current_aspect_ratio) {
size.y = size.x / ASPECT_RATIO;
}
else {
size.x = size.y * ASPECT_RATIO;
}
ImGui::SetCursorPos({
(ImGui::GetContentRegionAvail().x / 2) - (size.x / 2),
(ImGui::GetContentRegionAvail().y / 2) - (size.y / 2) + 24
});
ImGui::Image(
ImGui_ImplVulkan_AddTexture(
screenSampler,
image->get_view().get_view(),
image->get_layout(VK_IMAGE_LAYOUT_GENERAL)
),
size
);
}
ImGui::End();
void Window::Render(n64::Core& core) {
MainMenuBar(core);
}

View File

@@ -10,19 +10,20 @@
struct Window {
explicit Window(n64::Core& core);
~Window();
ImDrawData* Present(const Util::IntrusivePtr<Vulkan::Image>&, n64::Core& core);
ImDrawData* Present(n64::Core& core);
[[nodiscard]] bool gotClosed(SDL_Event event);
ImFont *uiFont, *codeFont;
u32 windowID;
private:
SDL_Window* window;
u32 windowID;
void InitSDL();
void InitImgui();
void Render(const Util::IntrusivePtr<Vulkan::Image>&, n64::Core& core);
void Render(n64::Core& core);
void MainMenuBar(n64::Core& core);
void DebuggerWindow(n64::Core& core);
VkPhysicalDevice physicalDevice{};
VkSampler screenSampler{};
VkDescriptorSet screenTexture{};
VkDevice device{};
uint32_t queueFamily{uint32_t(-1)};
VkQueue queue{};

View File

@@ -0,0 +1,115 @@
#include <Core.hpp>
#include <debugger.hpp>
void DebugStart(void* user_data) {
auto* core = (n64::Core*)user_data;
core->debuggerState.broken = false;
}
void DebugStop(void* user_data) {
auto* core = (n64::Core*)user_data;
core->debuggerState.broken = true;
}
void DebugStep(void* user_data) {
auto* core = (n64::Core*)user_data;
bool old_broken = core->debuggerState.broken;
core->debuggerState.broken = false;
core->Step();
core->debuggerState.broken = old_broken;
core->debuggerState.steps += 2;
}
void DebugSetBreakpoint(void* user_data, u32 address) {
auto* core = (n64::Core*)user_data;
auto* breakpoint = (Breakpoint*)malloc(sizeof(Breakpoint));
breakpoint->addr = address;
breakpoint->next = NULL;
// Special case for this being the first breakpoint
if (core->debuggerState.breakpoints == NULL) {
core->debuggerState.breakpoints = breakpoint;
} else {
// Find end of the list
Breakpoint* tail = core->debuggerState.breakpoints;
while (tail->next != NULL) {
tail = tail->next;
}
tail->next = breakpoint;
}
}
void DebugClearBreakpoint(void* user_data, u32 address) {
auto* core = (n64::Core*)user_data;
if (core->debuggerState.breakpoints == NULL) {
return; // No breakpoints set at all
} else if (core->debuggerState.breakpoints->addr == address) {
// Special case for the first breakpoint being the one we want to clear
Breakpoint* next = core->debuggerState.breakpoints->next;
free(core->debuggerState.breakpoints);
core->debuggerState.breakpoints = next;
} else {
// Find the breakpoint somewhere in the list and free it
Breakpoint* iter = core->debuggerState.breakpoints;
while (iter->next != NULL) {
if (iter->next->addr == address) {
Breakpoint* next = iter->next->next;
free(iter->next);
iter->next = next;
}
}
}
}
ssize_t DebugGetMemory(void* user_data, char* buffer, size_t length, u32 address, size_t bytes) {
auto* core = (n64::Core*)user_data;
printf("Checking memory at address 0x%08X\n", address);
int printed = 0;
for (int i = 0; i < bytes; i++) {
u8 value = core->mem.Read<u8>(core->cpu.regs, address + i, core->cpu.regs.pc);
printed += snprintf(buffer + (i*2), length, "%02X", value);
}
printf("Get memory: %ld bytes from 0x%08X: %d\n", bytes, address, printed);
return printed + 1;
}
ssize_t DebugGetRegisterValue(void* user_data, char * buffer, size_t buffer_length, int reg) {
auto* core = (n64::Core*)user_data;
switch (reg) {
case 0 ... 31:
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.gpr[reg]);
case 32:
return snprintf(buffer, buffer_length, "%08x", core->cpu.regs.cop0.status.raw);
case 33:
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.lo);
case 34:
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.hi);
case 35:
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.cop0.badVaddr);
case 36:
return snprintf(buffer, buffer_length, "%08x", core->cpu.regs.cop0.cause.raw);
case 37:
printf("Sending PC: 0x%016llX\n", core->cpu.regs.pc);
return snprintf(buffer, buffer_length, "%016llx", core->cpu.regs.pc);
case 38 ... 71: // TODO FPU stuff
return snprintf(buffer, buffer_length, "%08x", 0);
default:
util::panic("debug get register {} value", reg);
}
}
ssize_t DebugGetGeneralRegisters(void* user_data, char * buffer, size_t buffer_length) {
auto* core = (n64::Core*)user_data;
printf("The buffer length is %zu!\n", buffer_length);
ssize_t printed = 0;
for (int i = 0; i < 32; i++) {
int ofs = i * 16; // 64 bit regs take up 16 ascii chars to print in hex
if (ofs + 16 > buffer_length) {
util::panic("Too big!");
}
u64 reg = core->cpu.regs.gpr[i];
printed += snprintf(buffer + ofs, buffer_length - ofs, "%016llx", reg);
}
return printed;
}

View File

@@ -0,0 +1,149 @@
#pragma once
#define GDBSTUB_IMPLEMENTATION
#include <gdbstub.h>
#include <util.hpp>
struct Core;
#define GDB_CPU_PORT 1337
struct Breakpoint {
u32 addr;
Breakpoint* next;
};
struct DebuggerState {
gdbstub_t* gdb;
bool broken;
int steps;
Breakpoint* breakpoints;
bool enabled;
};
inline bool CheckBreakpoint(DebuggerState& state, u32 addr) {
Breakpoint* cur = state.breakpoints;
while (cur != NULL) {
if (cur->addr == addr) {
util::print("Hit breakpoint at 0x{:08X}\n", addr);
return true;
}
cur = cur->next;
}
return false;
}
const char* target_xml =
"<?xml version=\"1.0\"?>"
"<!DOCTYPE feature SYSTEM \"gdb-target.dtd\">"
"<target version=\"1.0\">"
"<architecture>mips:4000</architecture>"
"<osabi>none</osabi>"
"<feature name=\"org.gnu.gdb.mips.cpu\">"
" <reg name=\"r0\" bitsize=\"64\" regnum=\"0\"/>"
" <reg name=\"r1\" bitsize=\"64\"/>"
" <reg name=\"r2\" bitsize=\"64\"/>"
" <reg name=\"r3\" bitsize=\"64\"/>"
" <reg name=\"r4\" bitsize=\"64\"/>"
" <reg name=\"r5\" bitsize=\"64\"/>"
" <reg name=\"r6\" bitsize=\"64\"/>"
" <reg name=\"r7\" bitsize=\"64\"/>"
" <reg name=\"r8\" bitsize=\"64\"/>"
" <reg name=\"r9\" bitsize=\"64\"/>"
" <reg name=\"r10\" bitsize=\"64\"/>"
" <reg name=\"r11\" bitsize=\"64\"/>"
" <reg name=\"r12\" bitsize=\"64\"/>"
" <reg name=\"r13\" bitsize=\"64\"/>"
" <reg name=\"r14\" bitsize=\"64\"/>"
" <reg name=\"r15\" bitsize=\"64\"/>"
" <reg name=\"r16\" bitsize=\"64\"/>"
" <reg name=\"r17\" bitsize=\"64\"/>"
" <reg name=\"r18\" bitsize=\"64\"/>"
" <reg name=\"r19\" bitsize=\"64\"/>"
" <reg name=\"r20\" bitsize=\"64\"/>"
" <reg name=\"r21\" bitsize=\"64\"/>"
" <reg name=\"r22\" bitsize=\"64\"/>"
" <reg name=\"r23\" bitsize=\"64\"/>"
" <reg name=\"r24\" bitsize=\"64\"/>"
" <reg name=\"r25\" bitsize=\"64\"/>"
" <reg name=\"r26\" bitsize=\"64\"/>"
" <reg name=\"r27\" bitsize=\"64\"/>"
" <reg name=\"r28\" bitsize=\"64\"/>"
" <reg name=\"r29\" bitsize=\"64\"/>"
" <reg name=\"r30\" bitsize=\"64\"/>"
" <reg name=\"r31\" bitsize=\"64\"/>"
" <reg name=\"lo\" bitsize=\"64\" regnum=\"33\"/>"
" <reg name=\"hi\" bitsize=\"64\" regnum=\"34\"/>"
" <reg name=\"pc\" bitsize=\"64\" regnum=\"37\"/>"
"</feature>"
"<feature name=\"org.gnu.gdb.mips.cp0\">"
" <reg name=\"status\" bitsize=\"32\" regnum=\"32\"/>"
" <reg name=\"badvaddr\" bitsize=\"32\" regnum=\"35\"/>"
" <reg name=\"cause\" bitsize=\"32\" regnum=\"36\"/>"
" </feature>"
"<!-- TODO fix the sizes here. How do we deal with configurable sizes? -->"
"<feature name=\"org.gnu.gdb.mips.fpu\">"
" <reg name=\"f0\" bitsize=\"32\" type=\"ieee_single\" regnum=\"38\"/>"
" <reg name=\"f1\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f2\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f3\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f4\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f5\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f6\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f7\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f8\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f9\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f10\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f11\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f12\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f13\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f14\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f15\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f16\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f17\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f18\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f19\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f20\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f21\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f22\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f23\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f24\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f25\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f26\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f27\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f28\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f29\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f30\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"f31\" bitsize=\"32\" type=\"ieee_single\"/>"
" <reg name=\"fcsr\" bitsize=\"32\" group=\"float\"/>"
" <reg name=\"fir\" bitsize=\"32\" group=\"float\"/>"
"</feature>"
"</target>";
const char* memory_map =
"<?xml version=\"1.0\"?>"
"<memory-map>"
"<!-- KUSEG - TLB mapped, treat it as a giant block of RAM. Not ideal, but not sure how else to deal with it -->"
"<memory type=\"ram\" start=\"0x0000000000000000\" length=\"0x80000000\"/>"
"<!-- KSEG0 hardware mapped, full copy of the memory map goes here -->" // TODO finish
"<memory type=\"ram\" start=\"0xffffffff80000000\" length=\"0x800000\"/>" // RDRAM
"<memory type=\"ram\" start=\"0xffffffff84000000\" length=\"0x1000\"/>" // RSP DMEM
"<memory type=\"ram\" start=\"0xffffffff84001000\" length=\"0x1000\"/>" // RSP IMEM
"<memory type=\"rom\" start=\"0xffffffff9fc00000\" length=\"0x7c0\"/>" // PIF ROM
"<!-- KSEG1 hardware mapped, full copy of the memory map goes here -->" // TODO finish
"<memory type=\"ram\" start=\"0xffffffffa0000000\" length=\"0x800000\"/>" // RDRAM
"<memory type=\"ram\" start=\"0xffffffffa4000000\" length=\"0x1000\"/>" // RSP DMEM
"<memory type=\"ram\" start=\"0xffffffffa4001000\" length=\"0x1000\"/>" // RSP IMEM
"<memory type=\"rom\" start=\"0xffffffffbfc00000\" length=\"0x7c0\"/>" // PIF ROM
"</memory-map>";
void DebugStart(void* user_data);
void DebugStop(void* user_data);
void DebugStep(void* user_data);
void DebugSetBreakpoint(void* user_data, u32 address);
void DebugClearBreakpoint(void* user_data, u32 address);
ssize_t DebugGetMemory(void* user_data, char* buffer, size_t length, u32 address, size_t bytes);
ssize_t DebugGetRegisterValue(void* user_data, char * buffer, size_t buffer_length, int reg);
ssize_t DebugGetGeneralRegisters(void* user_data, char * buffer, size_t buffer_length);

View File

@@ -0,0 +1,49 @@
#include <Window.hpp>
#include <nfd.h>
#include <debugger.hpp>
void Window::MainMenuBar(n64::Core& core) {
ImGui::PushFont(uiFont);
if(windowID == SDL_GetWindowID(SDL_GetMouseFocus())) {
ImGui::BeginMainMenuBar();
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open", "O")) {
nfdchar_t *outpath;
const nfdu8filteritem_t filter{"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
}
if (ImGui::MenuItem("Exit")) {
core.done = true;
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Emulation")) {
if (ImGui::MenuItem("Reset")) {
core.Reset();
}
if (ImGui::MenuItem("Stop")) {
core.Stop();
}
if (ImGui::MenuItem(core.pause ? "Resume" : "Pause", nullptr, false, core.romLoaded)) {
core.TogglePause();
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
ImGui::PopFont();
}
void Window::DebuggerWindow(n64::Core& core) {
ImGui::PushFont(uiFont);
ImGui::Begin("Debugger");
if(ImGui::Button("Step")) {
core.debuggerState.gdb->config.step(&core);
}
ImGui::End();
ImGui::PopFont();
}

View File

@@ -3,10 +3,12 @@
#include <Window.hpp>
#include <algorithm>
#include <util.hpp>
#include <debugger.hpp>
namespace n64 {
Core::Core() {
Stop();
DebuggerInit();
}
void Core::Stop() {
@@ -15,6 +17,7 @@ void Core::Stop() {
pause = true;
romLoaded = false;
rom.clear();
DebuggerCleanup();
}
void Core::Reset() {
@@ -22,6 +25,8 @@ void Core::Reset() {
mem.Reset();
pause = true;
romLoaded = false;
DebuggerCleanup();
DebuggerInit();
if(!rom.empty()) {
LoadROM(rom);
}
@@ -34,6 +39,12 @@ void Core::LoadROM(const std::string& rom_) {
romLoaded = true;
}
void Core::Step() {
MMIO& mmio = mem.mmio;
cpu.Step(mem);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
}
void Core::Run(Window& window) {
MMIO& mmio = mem.mmio;
int cycles = 0;
@@ -45,6 +56,16 @@ void Core::Run(Window& window) {
}
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++) {
#ifndef NDEBUG
if (debuggerState.enabled && CheckBreakpoint(debuggerState, cpu.regs.pc)) {
DebuggerBreakpointHit();
}
while (debuggerState.broken) {
SDL_Delay(1000);
DebuggerTick();
}
#endif
cpu.Step(mem);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
@@ -149,4 +170,49 @@ void Core::UpdateController(const u8* state) {
}
}
}
void Core::DebuggerInit() {
gdbstub_config_t config;
memset(&config, 0, sizeof(gdbstub_config_t));
config.port = GDB_CPU_PORT;
config.user_data = this;
config.start = (gdbstub_start_t) DebugStart;
config.stop = (gdbstub_stop_t) DebugStop;
config.step = (gdbstub_step_t) DebugStep;
config.set_breakpoint = (gdbstub_set_breakpoint_t) DebugSetBreakpoint;
config.clear_breakpoint = (gdbstub_clear_breakpoint_t) DebugClearBreakpoint;
config.get_memory = (gdbstub_get_memory_t) DebugGetMemory;
config.get_register_value = (gdbstub_get_register_value_t) DebugGetRegisterValue;
config.get_general_registers = (gdbstub_get_general_registers_t) DebugGetGeneralRegisters;
config.target_config = target_xml;
config.target_config_length = strlen(target_xml);
printf("Sizeof target: %zu\n", config.target_config_length);
config.memory_map = memory_map;
config.memory_map_length = strlen(memory_map);
printf("Sizeof memory map: %zu\n", config.memory_map_length);
debuggerState.gdb = gdbstub_init(config);
if (!debuggerState.gdb) {
util::panic("Failed to initialize GDB stub!");
}
}
void Core::DebuggerTick() const {
gdbstub_tick(debuggerState.gdb);
}
void Core::DebuggerBreakpointHit() {
debuggerState.broken = true;
gdbstub_breakpoint_hit(debuggerState.gdb);
}
void Core::DebuggerCleanup() const {
if (debuggerState.enabled) {
gdbstub_term(debuggerState.gdb);
}
}
}

View File

@@ -3,27 +3,34 @@
#include <Cpu.hpp>
#include <Mem.hpp>
#include <string>
#include <debugger.hpp>
struct Window;
namespace n64 {
struct Core {
~Core() = default;
~Core() { Stop(); }
Core();
void Stop();
void Reset();
void Step();
void LoadROM(const std::string&);
void Run(Window&);
void UpdateController(const u8*);
void TogglePause() { pause = !pause; }
VI& GetVI() { return mem.mmio.vi; }
void DebuggerInit();
void DebuggerTick() const;
void DebuggerBreakpointHit();
void DebuggerCleanup() const;
bool pause = true;
bool romLoaded = false;
SDL_GameController* gamepad;
bool gamepadConnected = false;
DebuggerState debuggerState;
bool done = false;
std::string rom;
private:
friend struct ::Window;
Mem mem;
Cpu cpu;
};