From 261bb40563a1a0a91c7ac28969a8cf886ad2eed6 Mon Sep 17 00:00:00 2001 From: Matthew Laux Date: Thu, 14 Jul 2022 00:48:18 -0500 Subject: [PATCH] first output: nintendo logo --- cli/CMakeLists.txt | 2 +- cli/imgui_example.cpp | 130 ++++++++++++++++++++++-------------------- src/cpu.c | 62 ++++++++++++++++---- src/dmg.c | 44 ++++++++------ 4 files changed, 144 insertions(+), 94 deletions(-) diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 11ee297..b80293f 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -11,7 +11,7 @@ execute_process(COMMAND sdl2-config --libs OUTPUT_VARIABLE SDL_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) -set(CMAKE_CXX_FLAGS "-std=c++14 ${SDL_CFLAGS}") +set(CMAKE_CXX_FLAGS "-std=c++14 -g -DGB6_DEBUG ${SDL_CFLAGS}") add_executable(gb6 ../src/bootstrap.c diff --git a/cli/imgui_example.cpp b/cli/imgui_example.cpp index 1ba310d..2492669 100644 --- a/cli/imgui_example.cpp +++ b/cli/imgui_example.cpp @@ -9,6 +9,7 @@ #include "imgui/imgui_memory_editor.h" #include #include +#include #if defined(IMGUI_IMPL_OPENGL_ES2) #include #else @@ -57,9 +58,9 @@ void convert_output(struct lcd *lcd) { for (x = 0; x < 256; x++) { int val = lcd->buf[y * 256 + x]; int fill = val ? 255 : 0; - output_image[out_index++] = val; - output_image[out_index++] = val; - output_image[out_index++] = val; + output_image[out_index++] = fill; + output_image[out_index++] = fill; + output_image[out_index++] = fill; output_image[out_index++] = 255; } } @@ -102,7 +103,7 @@ int main(int argc, char *argv[]) dmg_new(&dmg, &cpu, &rom, &lcd); cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write); - cpu.pc = 0x100; + cpu.pc = 0;//0x100; // Setup SDL // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems, @@ -173,6 +174,7 @@ int main(int argc, char *argv[]) // Main loop bool done = false; + unsigned int lastDrawTime = 0, currentTime; while (!done) { // Poll and handle events (inputs, window resize, etc.) @@ -190,71 +192,75 @@ int main(int argc, char *argv[]) done = true; } - // Start the Dear ImGui frame - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplSDL2_NewFrame(); - ImGui::NewFrame(); - dmg_step(&dmg); - z_flag = flag_isset(dmg.cpu, FLAG_ZERO); - n_flag = flag_isset(dmg.cpu, FLAG_SIGN); - h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY); - c_flag = flag_isset(dmg.cpu, FLAG_CARRY); + currentTime = SDL_GetTicks(); + if (currentTime >= lastDrawTime + 16) { + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + ImGui::NewFrame(); - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. - { - ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it. + z_flag = flag_isset(dmg.cpu, FLAG_ZERO); + n_flag = flag_isset(dmg.cpu, FLAG_SIGN); + h_flag = flag_isset(dmg.cpu, FLAG_HALF_CARRY); + c_flag = flag_isset(dmg.cpu, FLAG_CARRY); - ImGui::Text(A_FORMAT, dmg.cpu->a); - ImGui::Text(B_FORMAT, dmg.cpu->b); - ImGui::SameLine(); - ImGui::Text(C_FORMAT, dmg.cpu->c); - ImGui::Text(D_FORMAT, dmg.cpu->d); - ImGui::SameLine(); - ImGui::Text(E_FORMAT, dmg.cpu->e); - ImGui::Text(H_FORMAT, dmg.cpu->h); - ImGui::SameLine(); - ImGui::Text(L_FORMAT, dmg.cpu->l); - ImGui::Text(SP_FORMAT, dmg.cpu->sp); - ImGui::SameLine(); - ImGui::Text(PC_FORMAT, dmg.cpu->pc); + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. + { + ImGui::Begin("State"); // Create a window called "Hello, world!" and append into it. - ImGui::Checkbox("Z", &z_flag); - ImGui::SameLine(); - ImGui::Checkbox("N", &n_flag); - ImGui::SameLine(); - ImGui::Checkbox("H", &h_flag); - ImGui::SameLine(); - ImGui::Checkbox("C", &c_flag); + ImGui::Text(A_FORMAT, dmg.cpu->a); + ImGui::Text(B_FORMAT, dmg.cpu->b); + ImGui::SameLine(); + ImGui::Text(C_FORMAT, dmg.cpu->c); + ImGui::Text(D_FORMAT, dmg.cpu->d); + ImGui::SameLine(); + ImGui::Text(E_FORMAT, dmg.cpu->e); + ImGui::Text(H_FORMAT, dmg.cpu->h); + ImGui::SameLine(); + ImGui::Text(L_FORMAT, dmg.cpu->l); + ImGui::Text(SP_FORMAT, dmg.cpu->sp); + ImGui::SameLine(); + ImGui::Text(PC_FORMAT, dmg.cpu->pc); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::End(); + ImGui::Checkbox("Z", &z_flag); + ImGui::SameLine(); + ImGui::Checkbox("N", &n_flag); + ImGui::SameLine(); + ImGui::Checkbox("H", &h_flag); + ImGui::SameLine(); + ImGui::Checkbox("C", &c_flag); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::End(); + } + + { + ImGui::Begin("Output"); + + convert_output(dmg.lcd); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, output_image); + ImGui::Image((void*)(intptr_t) texture, ImVec2(256, 256)); + + ImGui::End(); + } + + fill_memory_editor(&dmg); + + editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000); + + // Rendering + ImGui::Render(); + glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); + glClearColor(0.45f, 0.55f, 0.60f, 1.00f); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + SDL_GL_SwapWindow(window); + + lastDrawTime = currentTime; } - - { - ImGui::Begin("Output"); - - convert_output(dmg.lcd); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, output_image); - ImGui::Image((void*)(intptr_t) texture, ImVec2(256, 256)); - - ImGui::End(); - } - - fill_memory_editor(&dmg); - - editor.DrawWindow("Memory", full_address_space, 0x10000, 0x0000); - editor.DrawWindow("LCD", dmg.lcd->buf, 0x2000, 0); - - // Rendering - ImGui::Render(); - glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y); - glClearColor(0.45f, 0.55f, 0.60f, 1.00f); - glClear(GL_COLOR_BUFFER_BIT); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - SDL_GL_SwapWindow(window); } rom_free(&rom); diff --git a/src/cpu.c b/src/cpu.c index 53df1c3..4f5905e 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -110,19 +110,34 @@ static void dec_with_carry(struct cpu *regs, u8 *reg) static u8 rotate_left(struct cpu *regs, u8 reg) { - // copy old leftmost bit to carry flag - regs->f = (reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY); + int old_carry = flag_isset(regs, FLAG_CARRY); + // copy old leftmost bit to carry flag, clear Z, N, H + regs->f = (reg & 0x80) >> 3; // rotate - int result = reg << 1; - // restore leftmost (now rightmost) bit - result |= (regs->f & FLAG_CARRY) >> 4; + int result = reg << 1 | old_carry; + if (!result) set_flag(regs, FLAG_ZERO); + return result; +} + +static u8 rlc(struct cpu *cpu, u8 val) +{ + int old_msb = (val & 0x80) >> 7; + int result = (val & 0x7f) << 1 | old_msb; + if (!result) + set_flag(cpu, FLAG_ZERO); + else clear_flag(cpu, FLAG_ZERO); + clear_flag(cpu, FLAG_SIGN); + clear_flag(cpu, FLAG_HALF_CARRY); + if (old_msb) + set_flag(cpu, FLAG_CARRY); + else clear_flag(cpu, FLAG_CARRY); return result; } static u8 rotate_right(struct cpu *regs, u8 reg) { // copy old rightmost bit to carry flag - regs->f = (reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY); + regs->f = (reg & 0x01) << 4; // rotate int result = reg >> 1; // restore rightmost bit to left @@ -130,6 +145,21 @@ static u8 rotate_right(struct cpu *regs, u8 reg) return result; } +static u8 rrc(struct cpu *cpu, u8 val) +{ + int old_lsb = (val & 1) << 7; + int result = old_lsb | (val & 0xfe) >> 1; + if (!result) + set_flag(cpu, FLAG_ZERO); + else clear_flag(cpu, FLAG_ZERO); + clear_flag(cpu, FLAG_SIGN); + clear_flag(cpu, FLAG_HALF_CARRY); + if (old_lsb) + set_flag(cpu, FLAG_CARRY); + else clear_flag(cpu, FLAG_CARRY); + return result; +} + static u8 shift_left(struct cpu *cpu, u8 value) { return 0; @@ -202,10 +232,18 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare if (with_carry && flag_isset(cpu, FLAG_CARRY)) { sum_full--; } - sum_trunc = (u8) sum_full; - set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0); + sum_trunc = (u8) (sum_full & 0xff); + if (!sum_trunc) { + set_flag(cpu, FLAG_ZERO); + } else { + clear_flag(cpu, FLAG_ZERO); + } set_flag(cpu, FLAG_SIGN); - set_flag(cpu, sum_full < sum_trunc ? FLAG_CARRY : 0); + if (sum_full < sum_trunc) { + set_flag(cpu, FLAG_CARRY); + } else { + clear_flag(cpu, FLAG_CARRY); + } // TODO H if (!just_compare) { @@ -296,10 +334,10 @@ static void extended_insn(struct cpu *cpu, u8 insn) int reg = insn & 0x7; u8 (*funcs[8])(struct cpu *, u8) = { + rlc, + rrc, rotate_left, rotate_right, - rotate_left, // TODO non-carry version - rotate_right, shift_left, shift_right, swap, @@ -356,7 +394,7 @@ void cpu_step(struct cpu *cpu) cpu->pc += 2; break; case 0x07: // RLCA - cpu->a = rotate_left(cpu, cpu->a); + cpu->a = rlc(cpu, cpu->a); break; case 0x08: // LD (a16),SP write16(cpu, read16(cpu, cpu->pc), cpu->sp); diff --git a/src/dmg.c b/src/dmg.c index 985c733..0ef5225 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -68,6 +68,7 @@ void dmg_write(void *_dmg, u16 address, u8 data) // not sure about any of this yet } } +void exit(int); void dmg_step(void *_dmg) { @@ -89,26 +90,31 @@ void dmg_step(void *_dmg) int use_unsigned = lcdc & LCDC_BG_TILE_DATA; int tilebase = use_unsigned ? 0x8000 : 0x9000; - printf("base is %04x\n", bg_base); + printf("bg_base %04x, tilebase %04x\n", bg_base, tilebase); - int k, off = 0; - for (k = 0; k < 1024; k++) { - int tile = dmg_read(dmg, bg_base + k); - int eff_addr; - if (use_unsigned) { - eff_addr = tilebase + 16 * tile; - } else { - eff_addr = tilebase + 16 * (signed char) tile; - } - int b, i; - for (b = 0; b < 16; b += 2) { - int data1 = dmg_read(dmg, eff_addr + b); - int data2 = dmg_read(dmg, eff_addr + b + 1); - for (i = 0; i < 8; i++) { - // monochrome for now - dmg->lcd->buf[off] |= (data1 & (1 << i)) ? 1 : 0; - dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0; - off++; + int k = 0, off = 0; + int tile_y = 0, tile_x = 0; + for (tile_y = 0; tile_y < 32; tile_y++) { + for (tile_x = 0; tile_x < 32; tile_x++) { + off = 256 * 8 * tile_y + 8 * tile_x; + int tile = dmg_read(dmg, bg_base + (tile_y * 32 + tile_x)); + int eff_addr; + if (use_unsigned) { + eff_addr = tilebase + 16 * tile; + } else { + eff_addr = tilebase + 16 * (signed char) tile; + } + int b, i; + for (b = 0; b < 16; b += 2) { + int data1 = dmg_read(dmg, eff_addr + b); + int data2 = dmg_read(dmg, eff_addr + b + 1); + for (i = 7; i >= 0; i--) { + // monochrome for now + dmg->lcd->buf[off] = (data1 & (1 << i)) ? 1 : 0; + //dmg->lcd->buf[off] |= (data2 & (1 << i)) ? 1 : 0; + off++; + } + off += 248; } } }