diff --git a/gameboy/cpu/core/core.cpp b/gameboy/cpu/core/core.cpp index b401ec18..317b936b 100755 --- a/gameboy/cpu/core/core.cpp +++ b/gameboy/cpu/core/core.cpp @@ -61,6 +61,10 @@ void CPU::op_ld_ffn_a() { op_write(0xff00 + op_read(r[PC]++), r[A]); } +void CPU::op_ld_a_ffc() { + r[A] = op_read(0xff00 + r[C]); +} + void CPU::op_ld_ffc_a() { op_write(0xff00 + r[C], r[A]); } @@ -101,6 +105,7 @@ void CPU::op_ld_nn_sp() { void CPU::op_ld_sp_hl() { r[SP] = r[HL]; + op_io(); } template void CPU::op_push_rr() { @@ -137,7 +142,7 @@ void CPU::opi_adc_a(uint8 x) { r.f.z = (uint8)rh == 0; r.f.n = 0; r.f.h = rl > 0x0f; - r.f.c = rh > 0x0f; + r.f.c = rh > 0xff; } template void CPU::op_adc_a_r() { opi_adc_a(r[x]); } @@ -214,7 +219,7 @@ void CPU::opi_cp_a(uint8 x) { r.f.z = (uint8)rh == 0; r.f.n = 1; r.f.h = rl > 0x0f; - r.f.c = rh > 0x0f; + r.f.c = rh > 0xff; } template void CPU::op_cp_a_r() { opi_cp_a(r[x]); } @@ -252,10 +257,10 @@ void CPU::op_dec_hl() { } void CPU::op_daa() { - signed a = r[A]; + uint16 a = r[A]; if(r.f.n == 0) { if(r.f.h || (a & 0x0f) > 0x09) a += 0x06; - if(r.f.c || (a & 0xff) > 0x9f) a += 0x60; + if(r.f.c || (a ) > 0x9f) a += 0x60; } else { if(r.f.h) { a -= 0x06; @@ -266,7 +271,7 @@ void CPU::op_daa() { r[A] = a; r.f.z = r[A] == 0; r.f.h = 0; - r.f.c = a & 0x100; + r.f.c |= a & 0x100; } void CPU::op_cpl() { @@ -278,6 +283,7 @@ void CPU::op_cpl() { //16-bit arithmetic commands template void CPU::op_add_hl_rr() { + op_io(); uint32 rb = (r[HL] + r[x]); uint32 rn = (r[HL] & 0xfff) + (r[x] & 0xfff); r[HL] = rb; @@ -287,14 +293,18 @@ template void CPU::op_add_hl_rr() { } template void CPU::op_inc_rr() { + op_io(); r[x]++; } template void CPU::op_dec_rr() { + op_io(); r[x]--; } void CPU::op_add_sp_n() { + op_io(); + op_io(); signed n = (int8)op_read(r[PC]++); r.f.z = 0; r.f.n = 0; @@ -304,6 +314,7 @@ void CPU::op_add_sp_n() { } void CPU::op_ld_hl_sp_n() { + op_io(); signed n = (int8)op_read(r[PC]++); r.f.z = 0; r.f.n = 0; diff --git a/gameboy/cpu/core/core.hpp b/gameboy/cpu/core/core.hpp index 16444966..85ebeb1d 100755 --- a/gameboy/cpu/core/core.hpp +++ b/gameboy/cpu/core/core.hpp @@ -18,6 +18,7 @@ template void op_ld_rr_a(); void op_ld_nn_a(); void op_ld_a_ffn(); void op_ld_ffn_a(); +void op_ld_a_ffc(); void op_ld_ffc_a(); void op_ldi_hl_a(); void op_ldi_a_hl(); diff --git a/gameboy/cpu/core/disassembler.cpp b/gameboy/cpu/core/disassembler.cpp index 9c67f444..dbcee7ee 100755 --- a/gameboy/cpu/core/disassembler.cpp +++ b/gameboy/cpu/core/disassembler.cpp @@ -270,7 +270,7 @@ string CPU::disassemble_opcode(uint16 pc) { case 0xef: return { "rst $0028" }; case 0xf0: return { "ld a,($ff", hex<2>(p0), ")" }; case 0xf1: return { "pop af" }; - case 0xf2: return { "xx" }; + case 0xf2: return { "ld a,($ff00+c)" }; case 0xf3: return { "di" }; case 0xf4: return { "xx" }; case 0xf5: return { "push af" }; diff --git a/gameboy/cpu/core/table.cpp b/gameboy/cpu/core/table.cpp index 2c885591..fa2f1112 100755 --- a/gameboy/cpu/core/table.cpp +++ b/gameboy/cpu/core/table.cpp @@ -127,7 +127,7 @@ void CPU::initialize_opcode_table() { opcode_table[0x7b] = &CPU::op_ld_r_r; opcode_table[0x7c] = &CPU::op_ld_r_r; opcode_table[0x7d] = &CPU::op_ld_r_r; - opcode_table[0x7e] = &CPU::op_ld_r_hl; + opcode_table[0x7e] = &CPU::op_ld_r_hl; opcode_table[0x7f] = &CPU::op_ld_r_r; opcode_table[0x80] = &CPU::op_add_a_r; opcode_table[0x81] = &CPU::op_add_a_r; @@ -243,7 +243,7 @@ void CPU::initialize_opcode_table() { opcode_table[0xef] = &CPU::op_rst_n<0x28>; opcode_table[0xf0] = &CPU::op_ld_a_ffn; opcode_table[0xf1] = &CPU::op_pop_rr; - opcode_table[0xf2] = &CPU::op_xx; + opcode_table[0xf2] = &CPU::op_ld_a_ffc; opcode_table[0xf3] = &CPU::op_di; opcode_table[0xf4] = &CPU::op_xx; opcode_table[0xf5] = &CPU::op_push_rr; diff --git a/gameboy/cpu/cpu.cpp b/gameboy/cpu/cpu.cpp index 5a0bc001..70b4130f 100755 --- a/gameboy/cpu/cpu.cpp +++ b/gameboy/cpu/cpu.cpp @@ -88,6 +88,7 @@ void CPU::reset() { status.p15 = 0; status.p14 = 0; + status.joyp = 0; status.div = 0; diff --git a/gameboy/cpu/cpu.hpp b/gameboy/cpu/cpu.hpp index dc66e90f..28f4d211 100755 --- a/gameboy/cpu/cpu.hpp +++ b/gameboy/cpu/cpu.hpp @@ -13,6 +13,7 @@ struct CPU : Processor, MMIO { //$ff00 JOYP bool p15; bool p14; + uint8 joyp; //$ff04 DIV uint8 div; diff --git a/gameboy/cpu/mmio/mmio.cpp b/gameboy/cpu/mmio/mmio.cpp index 4d6322b0..e18b1e5e 100755 --- a/gameboy/cpu/mmio/mmio.cpp +++ b/gameboy/cpu/mmio/mmio.cpp @@ -1,30 +1,33 @@ #ifdef CPU_CPP +void CPU::mmio_joyp_poll() { + unsigned button = 0, dpad = 0; + + button |= system.interface->input_poll((unsigned)Input::Start) << 3; + button |= system.interface->input_poll((unsigned)Input::Select) << 2; + button |= system.interface->input_poll((unsigned)Input::B) << 1; + button |= system.interface->input_poll((unsigned)Input::A) << 0; + + dpad |= system.interface->input_poll((unsigned)Input::Down) << 3; + dpad |= system.interface->input_poll((unsigned)Input::Up) << 2; + dpad |= system.interface->input_poll((unsigned)Input::Left) << 1; + dpad |= system.interface->input_poll((unsigned)Input::Right) << 0; + + status.joyp = 0x0f; + if(status.p15 == 0) status.joyp &= button ^ 0x0f; + if(status.p14 == 0) status.joyp &= dpad ^ 0x0f; + if(status.joyp != 0x0f) status.interrupt_request_joypad = 1; +} + uint8 CPU::mmio_read(uint16 addr) { if(addr >= 0xc000 && addr <= 0xdfff) return wram[addr & 0x1fff]; if(addr >= 0xe000 && addr <= 0xfdff) return wram[addr & 0x1fff]; if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f]; if(addr == 0xff00) { //JOYP - unsigned keys = 0x0f; - - if(status.p15 == 0 && status.p14 == 1) { - keys = !system.interface->input_poll((unsigned)Input::Down) << 3; - keys |= !system.interface->input_poll((unsigned)Input::Up) << 2; - keys |= !system.interface->input_poll((unsigned)Input::Left) << 1; - keys |= !system.interface->input_poll((unsigned)Input::Right) << 0; - } - - if(status.p15 == 1 && status.p14 == 0) { - keys = !system.interface->input_poll((unsigned)Input::Start) << 3; - keys |= !system.interface->input_poll((unsigned)Input::Select) << 2; - keys |= !system.interface->input_poll((unsigned)Input::B) << 1; - keys |= !system.interface->input_poll((unsigned)Input::A) << 0; - } - return (status.p15 << 5) | (status.p14 << 4) - | (keys << 0); + | (status.joyp << 0); } if(addr == 0xff04) { //DIV @@ -71,6 +74,7 @@ void CPU::mmio_write(uint16 addr, uint8 data) { if(addr == 0xff00) { //JOYP status.p15 = data & 0x20; status.p14 = data & 0x10; + mmio_joyp_poll(); return; } diff --git a/gameboy/cpu/mmio/mmio.hpp b/gameboy/cpu/mmio/mmio.hpp index 92b8f614..bc9eb8ba 100755 --- a/gameboy/cpu/mmio/mmio.hpp +++ b/gameboy/cpu/mmio/mmio.hpp @@ -1,2 +1,3 @@ +void mmio_joyp_poll(); uint8 mmio_read(uint16 addr); void mmio_write(uint16 addr, uint8 data); diff --git a/gameboy/gameboy.hpp b/gameboy/gameboy.hpp index f51da8c0..4c131b7f 100755 --- a/gameboy/gameboy.hpp +++ b/gameboy/gameboy.hpp @@ -5,7 +5,7 @@ namespace GameBoy { namespace Info { static const char Name[] = "bgameboy"; - static const char Version[] = "000.04"; + static const char Version[] = "000.05"; } } diff --git a/gameboy/lcd/lcd.cpp b/gameboy/lcd/lcd.cpp index 11686b29..be9818bc 100755 --- a/gameboy/lcd/lcd.cpp +++ b/gameboy/lcd/lcd.cpp @@ -38,6 +38,7 @@ void LCD::scanline() { void LCD::frame() { system.interface->video_refresh(screen); system.interface->input_poll(); + cpu.mmio_joyp_poll(); status.ly = 0; scheduler.exit(); @@ -68,6 +69,32 @@ void LCD::render() { *output++ = (3 - status.bgp[palette]) * 0x55; } } + + output = screen + status.ly * 160; + for(unsigned s = 0; s < 40; s++) { + unsigned sy = oam[(s << 2) + 0] - 9; + unsigned sx = oam[(s << 2) + 1] - 8; + unsigned tile = oam[(s << 2) + 2]; + unsigned attribute = oam[(s << 2) + 3]; + + sy -= status.ly; + if(sy >= 8) continue; + if(attribute & 0x40||1) sy ^= 7; + + unsigned addr = tile * 16 + sy * 2; + + uint8 d0 = vram[addr + 0]; + uint8 d1 = vram[addr + 1]; + unsigned xflip = attribute & 0x20 ? -7 : 0; + + for(unsigned x = 0; x < 8; x++) { + uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6); + d0 <<= 1, d1 <<= 1; + if(palette == 0) continue; + palette = status.obp[(bool)(attribute & 0x10)][palette]; + output[sx + (x ^ xflip)] = (3 - palette) * 0x55; + } + } } void LCD::power() { @@ -113,8 +140,8 @@ void LCD::reset() { for(unsigned n = 0; n < 4; n++) { status.bgp[n] = n; - status.obp0[n] = n; - status.obp1[n] = n; + status.obp[0][n] = n; + status.obp[1][n] = n; } status.wy = 0; diff --git a/gameboy/lcd/lcd.hpp b/gameboy/lcd/lcd.hpp index 70056c8c..d819b3b0 100755 --- a/gameboy/lcd/lcd.hpp +++ b/gameboy/lcd/lcd.hpp @@ -38,10 +38,8 @@ struct LCD : Processor, MMIO { uint8 bgp[4]; //$ff48 OBP0 - uint8 obp0[4]; - //$ff49 OBP1 - uint8 obp1[4]; + uint8 obp[2][4]; //$ff4a WY uint8 wy; diff --git a/gameboy/lcd/mmio/mmio.cpp b/gameboy/lcd/mmio/mmio.cpp index bff31ada..230ba463 100755 --- a/gameboy/lcd/mmio/mmio.cpp +++ b/gameboy/lcd/mmio/mmio.cpp @@ -48,17 +48,17 @@ uint8 LCD::mmio_read(uint16 addr) { } if(addr == 0xff48) { //OBP0 - return (status.obp0[3] << 6) - | (status.obp0[2] << 4) - | (status.obp0[1] << 2) - | (status.obp0[0] << 0); + return (status.obp[0][3] << 6) + | (status.obp[0][2] << 4) + | (status.obp[0][1] << 2) + | (status.obp[0][0] << 0); } if(addr == 0xff49) { //OBP1 - return (status.obp1[3] << 6) - | (status.obp1[2] << 4) - | (status.obp1[1] << 2) - | (status.obp1[0] << 0); + return (status.obp[1][3] << 6) + | (status.obp[1][2] << 4) + | (status.obp[1][1] << 2) + | (status.obp[1][0] << 0); } if(addr == 0xff4a) { //WY @@ -117,7 +117,7 @@ void LCD::mmio_write(uint16 addr, uint8 data) { } if(addr == 0xff46) { //DMA - //TODO + for(unsigned n = 0x00; n <= 0x9f; n++) bus.write(0xfe00 + n, bus.read((data << 8) + n)); return; } @@ -130,18 +130,18 @@ void LCD::mmio_write(uint16 addr, uint8 data) { } if(addr == 0xff48) { //OBP0 - status.obp0[3] = (data >> 6) & 3; - status.obp0[2] = (data >> 4) & 3; - status.obp0[1] = (data >> 2) & 3; - status.obp0[0] = (data >> 0) & 3; + status.obp[0][3] = (data >> 6) & 3; + status.obp[0][2] = (data >> 4) & 3; + status.obp[0][1] = (data >> 2) & 3; + status.obp[0][0] = (data >> 0) & 3; return; } if(addr == 0xff49) { //OBP1 - status.obp1[3] = (data >> 6) & 3; - status.obp1[2] = (data >> 4) & 3; - status.obp1[1] = (data >> 2) & 3; - status.obp1[0] = (data >> 0) & 3; + status.obp[1][3] = (data >> 6) & 3; + status.obp[1][2] = (data >> 4) & 3; + status.obp[1][1] = (data >> 2) & 3; + status.obp[1][0] = (data >> 0) & 3; return; } diff --git a/ui/main.cpp b/ui/main.cpp index 6f65651e..f617896d 100755 --- a/ui/main.cpp +++ b/ui/main.cpp @@ -24,7 +24,7 @@ void Application::main(int argc, char **argv) { video.driver("OpenGL"); video.set(Video::Handle, (uintptr_t)mainWindow.viewport.handle()); - video.set(Video::Synchronize, false); + video.set(Video::Synchronize, true); video.set(Video::Filter, (unsigned)0); video.init();