diff --git a/cli/imgui_example.cpp b/cli/imgui_example.cpp index 8f6ba22..64a5e77 100644 --- a/cli/imgui_example.cpp +++ b/cli/imgui_example.cpp @@ -13,6 +13,7 @@ extern "C" { #include "cpu.h" #include "rom.h" #include "lcd.h" +#include "instructions.h" } static const char *A_FORMAT = "A: 0x%02x"; @@ -24,8 +25,10 @@ static const char *H_FORMAT = "H: 0x%02x"; static const char *L_FORMAT = "L: 0x%02x"; static const char *SP_FORMAT = "SP: 0x%02x"; static const char *PC_FORMAT = "PC: 0x%02x"; +static const char *INSN_FORMAT = "Next instruction: %s"; unsigned char output_image[256 * 256 * 4]; +unsigned char visible_pixels[160 * 144 * 4]; unsigned char vram_tiles[256 * 96 * 4]; struct key_input { @@ -75,6 +78,17 @@ void convert_output(struct lcd *lcd) { output_image[out_index++] = 255; } } + out_index = 0; + for (y = 0; y < 144; y++) { + for (x = 0; x < 160; x++) { + int val = lcd->pixels[y * 160 + x]; + int fill = default_palette[val]; + visible_pixels[out_index++] = fill; + visible_pixels[out_index++] = fill; + visible_pixels[out_index++] = fill; + visible_pixels[out_index++] = 255; + } + } } void convert_vram(struct dmg *dmg) { @@ -194,6 +208,7 @@ int main(int argc, char *argv[]) // setup output GLuint texture = make_output_texture(); + GLuint vis_texture = make_output_texture(); GLuint vram_texture = make_output_texture(); editor.ReadFn = read_mem; @@ -276,6 +291,9 @@ int main(int argc, char *argv[]) ImGui::SameLine(); ImGui::Text(PC_FORMAT, dmg.cpu->pc); + u8 opc = dmg_read(&dmg, dmg.cpu->pc); + ImGui::Text(INSN_FORMAT, instructions[opc].format); + ImGui::Checkbox("Z", &z_flag); ImGui::SameLine(); ImGui::Checkbox("N", &n_flag); @@ -302,10 +320,10 @@ int main(int argc, char *argv[]) ImGui::End(); } + convert_output(dmg.lcd); { 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(512, 512)); @@ -313,6 +331,16 @@ int main(int argc, char *argv[]) ImGui::End(); } + { + ImGui::Begin("LCD"); + + glBindTexture(GL_TEXTURE_2D, vis_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 160, 144, 0, GL_RGBA, GL_UNSIGNED_BYTE, visible_pixels); + ImGui::Image((void*)(intptr_t) vis_texture, ImVec2(320, 288)); + + ImGui::End(); + } + { ImGui::Begin("VRAM"); diff --git a/src/cpu.c b/src/cpu.c index fff4b21..4e07831 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -269,7 +269,8 @@ static void add(struct cpu *cpu, u8 value, int with_carry) { u8 sum_trunc; int sum_full = cpu->a + value; - if (with_carry && flag_isset(cpu, FLAG_CARRY)) { + int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0; + if (carry) { sum_full++; } sum_trunc = (u8) sum_full; @@ -279,12 +280,12 @@ static void add(struct cpu *cpu, u8 value, int with_carry) clear_flag(cpu, FLAG_ZERO); } clear_flag(cpu, FLAG_SIGN); - if (sum_full > sum_trunc) { + if (sum_full > 0xff) { set_flag(cpu, FLAG_CARRY); } else { clear_flag(cpu, FLAG_CARRY); } - if (((cpu->a & 0xf) + (value & 0xf)) & 0x10) { + if (((cpu->a & 0xf) + (value & 0xf) + carry) & 0x10) { set_flag(cpu, FLAG_HALF_CARRY); } else { clear_flag(cpu, FLAG_HALF_CARRY); @@ -296,10 +297,11 @@ static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare { u8 sum_trunc; int sum_full = cpu->a - value; - if (with_carry && flag_isset(cpu, FLAG_CARRY)) { + int carry = (with_carry && flag_isset(cpu, FLAG_CARRY)) ? 1 : 0; + if (carry) { sum_full--; } - sum_trunc = (u8) (sum_full & 0xff); + sum_trunc = (u8) sum_full; if (!sum_trunc) { set_flag(cpu, FLAG_ZERO); } else { @@ -508,9 +510,6 @@ static u16 check_interrupts(struct cpu *cpu) return 0; } -/* -*/ - void cpu_step(struct cpu *cpu) { u8 temp; @@ -570,6 +569,13 @@ void cpu_step(struct cpu *cpu) cpu->a = rotate_right(cpu, cpu->a); break; + case 0x37: // SCF + set_flag(cpu, FLAG_CARRY); + break; + case 0x3f: // CCF + clear_flag(cpu, FLAG_CARRY); + break; + // incs and decs case 0x03: write_bc(cpu, read_bc(cpu) + 1); break; case 0x04: inc_with_carry(cpu, &cpu->b); break; @@ -864,7 +870,7 @@ void cpu_step(struct cpu *cpu) break; case 0xde: // SBC A, u8 - subtract(cpu, read8(cpu, cpu->pc), 0, 1); + subtract(cpu, read8(cpu, cpu->pc), 1, 0); cpu->pc++; break; @@ -992,6 +998,7 @@ void cpu_step(struct cpu *cpu) break; case 0xf1: // POP AF write_af(cpu, pop(cpu)); + cpu->f &= 0xf0; break; case 0xf2: // LD A,(C) cpu->a = read8(cpu, 0xff00 + cpu->c); diff --git a/src/dmg.c b/src/dmg.c index 0fde300..8bca6f6 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -67,13 +67,12 @@ u8 dmg_read(void *_dmg, u16 address) if (address < 0x4000) { return dmg->rom->data[address]; } else if (address < 0x8000) { - // TODO switchable rom bank return dmg->rom->data[address]; } else if (address < 0xa000) { return dmg->video_ram[address - 0x8000]; } else if (address < 0xc000) { - // TODO switchable ram bank - return 0; + printf("RAM bank not handled by MBC\n"); + return 0xff; } else if (address < 0xe000) { return dmg->main_ram[address - 0xc000]; } else if (lcd_is_valid_addr(address)) { @@ -182,6 +181,23 @@ static void render_background(struct dmg *dmg, int lcdc) } } +static void scroll(struct dmg *dmg) +{ + int scroll_y = lcd_read(dmg->lcd, REG_SCY); + int scroll_x = lcd_read(dmg->lcd, REG_SCX); + + int lines; + for (lines = 0; lines < 144; lines++) { + int src_y = (scroll_y + lines) & 0xff; + int cols; + for (cols = 0; cols < 160; cols++) { + int src_off = (src_y << 8) + ((scroll_x + cols) & 0xff); + + dmg->lcd->pixels[lines * 160 + cols] = dmg->lcd->buf[src_off]; + } + } +} + struct oam_entry { u8 pos_y; u8 pos_x; @@ -272,6 +288,8 @@ void dmg_step(void *_dmg) render_objs(dmg); } + scroll(dmg); + // now copy 256x256 buf to 160x144 based on window registers lcd_copy(dmg->lcd); lcd_draw(dmg->lcd); diff --git a/src/mbc.c b/src/mbc.c index 2601820..f556152 100644 --- a/src/mbc.c +++ b/src/mbc.c @@ -19,7 +19,10 @@ static int mbc_noop_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data) static int mbc1_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data) { if (addr >= 0x4000 && addr <= 0x7fff) { - int use_bank = mbc->rom_bank || 1; + int use_bank = mbc->rom_bank; + if (!use_bank) { + use_bank = 1; + } *out_data = dmg->rom->data[0x4000 * use_bank + (addr & 0x3fff)]; return 1; } else if (addr >= 0xa000 && addr <= 0xbfff) {