14#include "imgui/imgui.h"
15#include "imgui_memory_editor.h"
23 if (filter[0] ==
'\0') {
28 if (entry.
operands.find(filter) != std::string::npos) {
32 if (absl::StrFormat(
"%06X", entry.
address).find(filter) !=
46using ImGui::NextColumn;
48using ImGui::Separator;
49using ImGui::TableNextColumn;
53 static bool loaded =
false;
56 SDL_PIXELFORMAT_ARGB8888,
57 SDL_TEXTUREACCESS_STREAMING, 512, 480);
59 printf(
"Failed to create texture: %s\n", SDL_GetError());
78 uint64_t current_count = SDL_GetPerformanceCounter();
100 if (SDL_LockTexture(
ppu_texture_, NULL, &ppu_pixels_, &ppu_pitch_) !=
102 printf(
"Failed to lock texture: %s\n", SDL_GetError());
115 ImVec2 size = ImVec2(512, 480);
117 ImGui::BeginChild(
"EmulatorOutput", ImVec2(0, 480),
true,
118 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
119 ImGui::SetCursorPosX((ImGui::GetWindowSize().x - size.x) * 0.5f);
120 ImGui::SetCursorPosY((ImGui::GetWindowSize().y - size.y) * 0.5f);
121 ImGui::Image((ImTextureID)(intptr_t)
ppu_texture_, size, ImVec2(0, 0),
126 ImGui::Text(
"Emulator output not available.");
127 ImGui::BeginChild(
"EmulatorOutput", ImVec2(0, 480),
true,
128 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar);
129 ImGui::SetCursorPosX(((ImGui::GetWindowSize().x * 0.5f) - size.x) * 0.5f);
130 ImGui::SetCursorPosY(((ImGui::GetWindowSize().y * 0.5f) - size.y) * 0.5f);
138 std::string navbar_layout = R
"(
140 BeginMenu title="Options" {
141 MenuItem title="Input" {}
142 MenuItem title="Audio" {}
143 MenuItem title="Video" {}
154 if (ImGui::IsItemHovered()) {
155 ImGui::SetTooltip(
"Start Emulation");
162 if (ImGui::IsItemHovered()) {
163 ImGui::SetTooltip(
"Pause Emulation");
171 if (ImGui::IsItemHovered()) {
172 ImGui::SetTooltip(
"Step Through Code");
180 if (ImGui::IsItemHovered()) {
181 ImGui::SetTooltip(
"Reset Emulator");
189 if (ImGui::IsItemHovered()) {
190 ImGui::SetTooltip(
"Stop Emulation");
197 if (ImGui::IsItemHovered()) {
198 ImGui::SetTooltip(
"Save State");
204 if (ImGui::IsItemHovered()) {
205 ImGui::SetTooltip(
"Load State");
213 if (ImGui::IsItemHovered()) {
214 ImGui::SetTooltip(
"Settings");
217 static bool open_file =
false;
224 if (ImGui::IsItemHovered()) {
225 ImGui::SetTooltip(
"About Debugger");
228 ImGui::Checkbox(
"Logging",
snes_.
cpu().mutable_log_instructions());
233 static bool show_memory_viewer =
false;
237 show_memory_viewer = !show_memory_viewer;
239 if (ImGui::IsItemHovered()) {
240 ImGui::SetTooltip(
"Memory Viewer");
243 if (show_memory_viewer) {
244 ImGui::Begin(
"Memory Viewer", &show_memory_viewer);
251 if (!file_name.empty()) {
252 std::ifstream file(file_name, std::ios::binary);
254 rom_data_.assign(std::istreambuf_iterator<char>(file),
255 std::istreambuf_iterator<char>());
362 if (ImGui::Button(
"Set SPC PC")) {
368 static char breakpoint_input[10] =
"";
369 static int current_memory_mode = 0;
371 static bool read_mode =
false;
372 static bool write_mode =
false;
373 static bool execute_mode =
false;
375 if (ImGui::Combo(
"##TypeOfMemory", ¤t_memory_mode,
"PRG\0RAM\0")) {
378 ImGui::Checkbox(
"Read", &read_mode);
380 ImGui::Checkbox(
"Write", &write_mode);
382 ImGui::Checkbox(
"Execute", &execute_mode);
385 if (ImGui::InputText(
"##BreakpointInput", breakpoint_input, 10,
386 ImGuiInputTextFlags_EnterReturnsTrue)) {
387 int breakpoint = std::stoi(breakpoint_input,
nullptr, 16);
388 snes_.
cpu().SetBreakpoint(breakpoint);
389 memset(breakpoint_input, 0,
sizeof(breakpoint_input));
392 if (ImGui::Button(
"Add")) {
393 int breakpoint = std::stoi(breakpoint_input,
nullptr, 16);
394 snes_.
cpu().SetBreakpoint(breakpoint);
395 memset(breakpoint_input, 0,
sizeof(breakpoint_input));
398 if (ImGui::Button(
"Clear")) {
402 auto breakpoints =
snes_.
cpu().GetBreakpoints();
403 if (!breakpoints.empty()) {
404 Text(
"Breakpoints:");
405 ImGui::BeginChild(
"BreakpointsList", ImVec2(0, 100),
true);
406 for (
auto breakpoint : breakpoints) {
407 if (ImGui::Selectable(absl::StrFormat(
"0x%04X", breakpoint).c_str())) {
417 if (ImGui::Button(
"Set Current Address")) {
424 static MemoryEditor ram_edit;
425 static MemoryEditor aram_edit;
426 static MemoryEditor mem_edit;
428 if (ImGui::BeginTable(
"MemoryViewerTable", 4,
429 ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) {
430 ImGui::TableSetupColumn(
"Bookmarks");
431 ImGui::TableSetupColumn(
"RAM");
432 ImGui::TableSetupColumn(
"ARAM");
433 ImGui::TableSetupColumn(
"ROM");
434 ImGui::TableHeadersRow();
437 if (ImGui::CollapsingHeader(
"Bookmarks", ImGuiTreeNodeFlags_DefaultOpen)) {
439 static char nameBuf[256];
440 static uint64_t uint64StringBuf;
441 ImGui::InputText(
"Name", nameBuf, IM_ARRAYSIZE(nameBuf));
443 if (ImGui::Button(
"Add Bookmark")) {
444 bookmarks.push_back({nameBuf, uint64StringBuf});
445 memset(nameBuf, 0,
sizeof(nameBuf));
451 if (ImGui::TreeNode(bookmark.name.c_str(),
ICON_MD_STAR)) {
452 auto bookmark_string = absl::StrFormat(
453 "%s: 0x%08X", bookmark.name.c_str(), bookmark.value);
454 if (ImGui::Selectable(bookmark_string.c_str())) {
455 mem_edit.GotoAddrAndHighlight(
static_cast<ImU64
>(bookmark.value),
459 if (ImGui::Button(
"Delete")) {
463 return b.name == bookmark.name &&
464 b.value == bookmark.value;
474 if (ImGui::BeginChild(
"RAM", ImVec2(0, 0),
true,
475 ImGuiWindowFlags_NoMove |
476 ImGuiWindowFlags_NoScrollbar |
477 ImGuiWindowFlags_NoScrollWithMouse)) {
483 if (ImGui::BeginChild(
"ARAM", ImVec2(0, 0),
true,
484 ImGuiWindowFlags_NoMove |
485 ImGuiWindowFlags_NoScrollbar |
486 ImGuiWindowFlags_NoScrollWithMouse)) {
487 aram_edit.DrawContents((
void*)
snes_.
apu().ram.data(),
493 if (ImGui::BeginChild(
"ROM", ImVec2(0, 0),
true,
494 ImGuiWindowFlags_NoMove |
495 ImGuiWindowFlags_NoScrollbar |
496 ImGuiWindowFlags_NoScrollWithMouse)) {
497 mem_edit.DrawContents((
void*)
snes_.
Memory().rom_.data(),
507 const std::vector<InstructionEntry>& instruction_log) {
508 if (ImGui::CollapsingHeader(
"Instruction Log",
509 ImGuiTreeNodeFlags_DefaultOpen)) {
511 static char filter[256];
512 ImGui::InputText(
"Filter", filter, IM_ARRAYSIZE(filter));
515 ImGui::BeginChild(
"InstructionList", ImVec2(0, 0), ImGuiChildFlags_None);
516 for (
const auto& entry : instruction_log) {
517 if (ShouldDisplay(entry, filter)) {
518 if (ImGui::Selectable(
519 absl::StrFormat(
"%06X:", entry.address).c_str())) {
525 ImVec4 color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
526 ImGui::TextColored(color,
"%s",
528 ImVec4 operand_color = ImVec4(0.7f, 0.5f, 0.3f, 1.0f);
530 ImGui::TextColored(operand_color,
"%s", entry.operands.c_str());
534 if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) {
535 ImGui::SetScrollHereY(1.0f);
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath.
static Renderer & GetInstance()
SDL_AudioDeviceID audio_device_
std::vector< uint8_t > rom_data_
std::vector< Bookmark > bookmarks
void RenderBreakpointList()
void RenderCpuInstructionLog(const std::vector< InstructionEntry > &instructionLog)
EmulatorKeybindings keybindings_
gui::zeml::Node emulator_node_
SDL_Texture * ppu_texture_
void RenderMemoryViewer()
auto apu() -> audio::Apu &
void Init(std::vector< uint8_t > &rom_data)
auto Memory() -> memory::MemoryImpl &
void SetSamples(int16_t *sample_data, int wanted_samples)
void SetButtonState(int player, int button, bool pressed)
auto get_ram() -> uint8_t *
void SetPixels(uint8_t *pixel_data)
void Reset(bool hard=false)
const std::unordered_map< uint8_t, std::string > opcode_to_mnemonic
#define ICON_MD_PLAY_ARROW
#define ICON_MD_SYSTEM_UPDATE_ALT
#define ICON_MD_SKIP_NEXT
bool ShouldDisplay(const InstructionEntry &entry, const char *filter)
Node Parse(const std::string &yazon_input, const std::map< std::string, void * > &data_bindings)
Parse a zeml string.
void Render(Node &node)
Render a zeml tree.
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
bool InputHex(const char *label, uint64_t *data)
bool InputHexWord(const char *label, uint16_t *data, float input_width, bool no_step)