diff --git a/gameboy/cartridge/cartridge.cpp b/gameboy/cartridge/cartridge.cpp index f7e47556..aaf2c30d 100755 --- a/gameboy/cartridge/cartridge.cpp +++ b/gameboy/cartridge/cartridge.cpp @@ -6,6 +6,7 @@ namespace GameBoy { #include "mbc0/mbc0.cpp" #include "mbc1/mbc1.cpp" #include "mbc2/mbc2.cpp" +#include "mbc3/mbc3.cpp" #include "mbc5/mbc5.cpp" Cartridge cartridge; @@ -34,6 +35,13 @@ void Cartridge::load(uint8_t *data, unsigned size) { case 0x03: info.mapper = Mapper::MBC1; info.ram = true; info.battery = true; break; case 0x05: info.mapper = Mapper::MBC2; info.ram = true; break; case 0x06: info.mapper = Mapper::MBC2; info.ram = true; info.battery = true; break; + case 0x08: info.mapper = Mapper::MBC0; info.ram = true; break; + case 0x09: info.mapper = Mapper::MBC0; info.ram = true; info.battery = true; break; + case 0x0f: info.mapper = Mapper::MBC3; info.rtc = true; info.battery = true; break; + case 0x10: info.mapper = Mapper::MBC3; info.rtc = true; info.ram = true; info.battery = true; break; + case 0x11: info.mapper = Mapper::MBC3; break; + case 0x12: info.mapper = Mapper::MBC3; info.ram = true; break; + case 0x13: info.mapper = Mapper::MBC3; info.ram = true; info.battery = true; break; case 0x19: info.mapper = Mapper::MBC5; break; case 0x1a: info.mapper = Mapper::MBC5; info.ram = true; break; case 0x1b: info.mapper = Mapper::MBC5; info.ram = true; info.battery = true; break; @@ -64,7 +72,7 @@ void Cartridge::load(uint8_t *data, unsigned size) { case 0x03: info.ramsize = 32 * 1024; break; } - if(info.mapper == Mapper::MBC2) info.ramsize = 256; //512 x 4-bit + if(info.mapper == Mapper::MBC2) info.ramsize = 512; //512 x 4-bit ramdata = new uint8_t[ramsize = info.ramsize](); @@ -105,6 +113,7 @@ void Cartridge::power() { mbc0.power(); mbc1.power(); mbc2.power(); + mbc3.power(); mbc5.power(); MMIO *mapper = 0; @@ -112,6 +121,7 @@ void Cartridge::power() { case Mapper::MBC0: mapper = &mbc0; break; case Mapper::MBC1: mapper = &mbc1; break; case Mapper::MBC2: mapper = &mbc2; break; + case Mapper::MBC3: mapper = &mbc3; break; case Mapper::MBC5: mapper = &mbc5; break; } diff --git a/gameboy/cartridge/cartridge.hpp b/gameboy/cartridge/cartridge.hpp index 05eb052b..b04d16a0 100755 --- a/gameboy/cartridge/cartridge.hpp +++ b/gameboy/cartridge/cartridge.hpp @@ -2,12 +2,14 @@ struct Cartridge : property { #include "mbc0/mbc0.hpp" #include "mbc1/mbc1.hpp" #include "mbc2/mbc2.hpp" + #include "mbc3/mbc3.hpp" #include "mbc5/mbc5.hpp" enum Mapper : unsigned { MBC0, MBC1, MBC2, + MBC3, MBC5, Unknown, }; diff --git a/gameboy/cartridge/mbc0/mbc0.cpp b/gameboy/cartridge/mbc0/mbc0.cpp index fa9d616d..46461b77 100755 --- a/gameboy/cartridge/mbc0/mbc0.cpp +++ b/gameboy/cartridge/mbc0/mbc0.cpp @@ -1,11 +1,22 @@ #ifdef CARTRIDGE_CPP uint8 Cartridge::MBC0::mmio_read(uint16 addr) { - if(addr >= 0x0000 && addr <= 0x7fff) return cartridge.rom_read(addr); + if((addr & 0x8000) == 0x0000) { //0000-7fff + return cartridge.rom_read(addr); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + return cartridge.ram_read(addr & 0x1fff); + } + return 0x00; } void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0xa000) { //a000-bfff + cartridge.ram_write(addr & 0x1fff, data); + return; + } } void Cartridge::MBC0::power() { diff --git a/gameboy/cartridge/mbc1/mbc1.cpp b/gameboy/cartridge/mbc1/mbc1.cpp index e31997dc..50622e82 100755 --- a/gameboy/cartridge/mbc1/mbc1.cpp +++ b/gameboy/cartridge/mbc1/mbc1.cpp @@ -1,48 +1,62 @@ #ifdef CARTRIDGE_CPP uint8 Cartridge::MBC1::mmio_read(uint16 addr) { - if(addr >= 0x0000 && addr <= 0x3fff) { + if((addr & 0xc000) == 0x0000) { //0000-3fff return cartridge.rom_read(addr); } - if(addr >= 0x4000 && addr <= 0x7fff) { - return cartridge.rom_read(rom_bank | (addr & 0x3fff)); + if((addr & 0xc000) == 0x4000) { //4000-7fff + if(mode_select == 0) { + return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff)); + } else { + return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); + } } - if(addr >= 0xa000 && addr <= 0xbfff) { - if(ram_enable) return cartridge.ram_read(ram_bank | (addr & 0x1fff)); + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(mode_select == 0) { + return cartridge.ram_read(addr & 0x1fff); + } else { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + } return 0x00; } + + return 0x00; } void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) { - if(addr >= 0x0000 && addr <= 0x1fff) { + if((addr & 0xe000) == 0x0000) { //0000-1fff ram_enable = (data & 0x0f) == 0x0a; + return; } - if(addr >= 0x2000 && addr <= 0x3fff) { - rom_select = data & 0x1f; - if(rom_select == 0) rom_select = 1; + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = (data & 0x1f) + ((data & 0x1f) == 0); + return; } - if(addr >= 0x4000 && addr <= 0x5fff) { + if((addr & 0xe000) == 0x4000) { //4000-5fff ram_select = data & 0x03; + return; } - if(addr >= 0x6000 && addr <= 0x7fff) { + if((addr & 0xe000) == 0x6000) { //6000-7fff mode_select = data & 0x01; + return; } - if(mode_select == 0) { - rom_bank = (ram_select << 19) | (rom_select << 14); - ram_bank = 0x00; - } else { - rom_bank = (rom_select << 14); - ram_bank = (ram_select << 13); - } - - if(addr >= 0xa000 && addr <= 0xbfff) { - if(ram_enable) cartridge.ram_write(ram_bank | (addr & 0x1fff), data); + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(mode_select == 0) { + cartridge.ram_write(addr & 0x1fff, data); + } else { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } + } + return; } } @@ -51,9 +65,6 @@ void Cartridge::MBC1::power() { rom_select = 0x01; ram_select = 0x00; mode_select = 0; - - rom_bank = 0x4000; - ram_bank = 0x0000; } #endif diff --git a/gameboy/cartridge/mbc1/mbc1.hpp b/gameboy/cartridge/mbc1/mbc1.hpp index ccbb1bf3..099cf43d 100755 --- a/gameboy/cartridge/mbc1/mbc1.hpp +++ b/gameboy/cartridge/mbc1/mbc1.hpp @@ -4,9 +4,6 @@ struct MBC1 : MMIO { uint8 ram_select; //4000-5fff bool mode_select; //6000-7fff - unsigned rom_bank; - unsigned ram_bank; - uint8 mmio_read(uint16 addr); void mmio_write(uint16 addr, uint8 data); void power(); diff --git a/gameboy/cartridge/mbc2/mbc2.cpp b/gameboy/cartridge/mbc2/mbc2.cpp index 491b21d6..3b952c78 100755 --- a/gameboy/cartridge/mbc2/mbc2.cpp +++ b/gameboy/cartridge/mbc2/mbc2.cpp @@ -1,19 +1,16 @@ #ifdef CARTRIDGE_CPP uint8 Cartridge::MBC2::mmio_read(uint16 addr) { - if(addr >= 0x0000 && addr <= 0x3fff) { + if((addr & 0xc000) == 0x0000) { //0000-3fff return cartridge.rom_read(addr); } - if(addr >= 0x4000 && addr <= 0x7fff) { + if((addr & 0xc000) == 0x4000) { //4000-7fff return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); } - if(addr >= 0xa000 && addr <= 0xa1ff) { - if(ram_enable) { - uint8 data = cartridge.ram_read(addr & 0x1ff); - return (addr & 1) == 0 ? ((data >> 4) & 0x0f) : ((data >> 0) & 0x0f); - } + if((addr & 0xfe00) == 0xa000) { //a000-a1ff + if(ram_enable) return cartridge.ram_read(addr & 0x1ff); return 0x00; } @@ -21,29 +18,19 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) { } void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) { - if(addr >= 0x0000 && addr <= 0x1fff) { - if((addr & 0x100) == 0) { - ram_enable = (data & 0x0f) == 0x0a; - } + if((addr & 0xe100) == 0x0000) { //0000-1fff [d8=0] + ram_enable = (data & 0x0f) == 0x0a; + return; } - if(addr >= 0x2000 && addr <= 0x3fff) { - if(addr & 0x100) { - rom_select = data & 0x0f; - if(rom_select == 0) rom_select = 1; - } + if((addr & 0xe100) == 0x2100) { //2000-3fff [d8=1] + rom_select = (data & 0x0f) + ((data & 0x0f) == 0); + return; } - if(addr >= 0xa000 && addr <= 0xa1ff) { - if(ram_enable) { - addr &= 511; - if((addr & 1) == 0) { - cartridge.ram_write(addr, (cartridge.ram_read(addr) & 0x0f) | (data << 4)); - } else { - cartridge.ram_write(addr, (cartridge.ram_read(addr) & 0xf0) | (data << 0)); - } - return; - } + if((addr & 0xfe00) == 0xa000) { //a000-a1ff + if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f); + return; } } diff --git a/gameboy/cartridge/mbc3/mbc3.cpp b/gameboy/cartridge/mbc3/mbc3.cpp new file mode 100755 index 00000000..709970dc --- /dev/null +++ b/gameboy/cartridge/mbc3/mbc3.cpp @@ -0,0 +1,120 @@ +#ifdef CARTRIDGE_CPP + +void Cartridge::MBC3::second() { + if(rtc_halt == false) { + if(++rtc_second >= 60) { + rtc_second = 0; + if(++rtc_minute >= 60) { + rtc_minute = 0; + if(++rtc_hour >= 24) { + rtc_hour = 0; + if(++rtc_day >= 512) { + rtc_day = 0; + rtc_day_carry = true; + } + } + } + } + } +} + +uint8 Cartridge::MBC3::mmio_read(uint16 addr) { + if((addr & 0xc000) == 0x0000) { //0000-3fff + return cartridge.rom_read(addr); + } + + if((addr & 0xc000) == 0x4000) { //4000-7fff + return cartridge.rom_read((rom_select << 13) | (addr & 0x3fff)); + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); + } + if(ram_select == 0x08) return rtc_latch_second; + if(ram_select == 0x09) return rtc_latch_minute; + if(ram_select == 0x0a) return rtc_latch_hour; + if(ram_select == 0x0b) return rtc_latch_day; + if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8); + } + return 0x00; + } + + return 0x00; +} + +void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) { + if((addr & 0xe000) == 0x0000) { //0000-1fff + ram_enable = (data & 0x0f) == 0x0a; + return; + } + + if((addr & 0xe000) == 0x2000) { //2000-3fff + rom_select = (data & 0x7f) + ((data & 0x7f) == 0); + return; + } + + if((addr & 0xe000) == 0x4000) { //4000-5fff + ram_select = data; + return; + } + + if((addr & 0xe000) == 0x6000) { //6000-7fff + if(rtc_latch == 0 && data == 1) { + rtc_latch_second = rtc_second; + rtc_latch_minute = rtc_minute; + rtc_latch_hour = rtc_hour; + rtc_latch_day = rtc_day; + rtc_latch_day_carry = rtc_day_carry; + } + rtc_latch = data; + return; + } + + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) { + if(ram_select >= 0x00 && ram_select <= 0x03) { + cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + } else if(ram_select == 0x08) { + if(data >= 60) data = 0; + rtc_second = data; + } else if(ram_select == 0x09) { + if(data >= 60) data = 0; + rtc_minute = data; + } else if(ram_select == 0x0a) { + if(data >= 24) data = 0; + rtc_hour = data; + } else if(ram_select == 0x0b) { + rtc_day = (rtc_day & 0x0100) | data; + } else if(ram_select == 0x0c) { + rtc_day = ((data & 1) << 8) | (rtc_day & 0xff); + rtc_halt = data & 0x40; + rtc_day_carry = data & 0x80; + } + } + return; + } +} + +void Cartridge::MBC3::power() { + ram_enable = false; + rom_select = 0x01; + ram_select = 0x00; + rtc_latch = 0; + + rtc_halt = true; + rtc_second = 0; + rtc_minute = 0; + rtc_hour = 0; + rtc_day = 0; + rtc_day_carry = false; + + rtc_latch_second = 0; + rtc_latch_minute = 0; + rtc_latch_hour = 0; + rtc_latch_day = 0; + rtc_latch_day_carry = false; +} + +#endif diff --git a/gameboy/cartridge/mbc3/mbc3.hpp b/gameboy/cartridge/mbc3/mbc3.hpp new file mode 100755 index 00000000..d83ba182 --- /dev/null +++ b/gameboy/cartridge/mbc3/mbc3.hpp @@ -0,0 +1,24 @@ +struct MBC3 : MMIO { + bool ram_enable; //0000-1fff + uint8 rom_select; //2000-3fff + uint8 ram_select; //4000-5fff + bool rtc_latch; //6000-7fff + + bool rtc_halt; + unsigned rtc_second; + unsigned rtc_minute; + unsigned rtc_hour; + unsigned rtc_day; + bool rtc_day_carry; + + unsigned rtc_latch_second; + unsigned rtc_latch_minute; + unsigned rtc_latch_hour; + unsigned rtc_latch_day; + unsigned rtc_latch_day_carry; + + void second(); + uint8 mmio_read(uint16 addr); + void mmio_write(uint16 addr, uint8 data); + void power(); +} mbc3; diff --git a/gameboy/cartridge/mbc5/mbc5.cpp b/gameboy/cartridge/mbc5/mbc5.cpp index 0d209edf..263e5125 100755 --- a/gameboy/cartridge/mbc5/mbc5.cpp +++ b/gameboy/cartridge/mbc5/mbc5.cpp @@ -1,18 +1,16 @@ #ifdef CARTRIDGE_CPP uint8 Cartridge::MBC5::mmio_read(uint16 addr) { - if(addr >= 0x0000 && addr <= 0x3fff) { + if((addr & 0xc000) == 0x0000) { //0000-3fff return cartridge.rom_read(addr); } - if(addr >= 0x4000 && addr <= 0x7fff) { + if((addr & 0xc000) == 0x4000) { //4000-7fff return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff)); } - if(addr >= 0xa000 && addr <= 0xbfff) { - if(ram_enable) { - return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); - } + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff)); return 0x00; } @@ -20,26 +18,29 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) { } void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) { - if(addr >= 0x0000 && addr <= 0x1fff) { + if((addr & 0xe000) == 0x0000) { //0000-1fff ram_enable = (data & 0x0f) == 0x0a; + return; } - if(addr >= 0x2000 && addr <= 0x2fff) { + if((addr & 0xf000) == 0x2000) { //2000-2fff rom_select = (rom_select & 0x0100) | data; + return; } - if(addr >= 0x3000 && addr <= 0x3fff) { + if((addr & 0xf000) == 0x3000) { //3000-3fff rom_select = ((data & 1) << 8) | (rom_select & 0x00ff); + return; } - if(addr >= 0x4000 && addr <= 0x5fff) { + if((addr & 0xe000) == 0x4000) { //4000-5fff ram_select = data & 0x0f; + return; } - if(addr >= 0xa000 && addr <= 0xbfff) { - if(ram_enable) { - cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); - } + if((addr & 0xe000) == 0xa000) { //a000-bfff + if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data); + return; } } diff --git a/gameboy/cpu/cpu.cpp b/gameboy/cpu/cpu.cpp index e6739fc8..6978f965 100755 --- a/gameboy/cpu/cpu.cpp +++ b/gameboy/cpu/cpu.cpp @@ -14,7 +14,7 @@ void CPU::Main() { void CPU::main() { while(true) { - //print(disassemble(r[PC]), "\n"); + if(trace) print(disassemble(r[PC]), "\n"); interrupt_test(); uint8 opcode = op_read(r[PC]++); (this->*opcode_table[opcode])(); @@ -27,7 +27,7 @@ void CPU::interrupt_raise(CPU::Interrupt id) { case Interrupt::Stat : status.interrupt_request_stat = 1; break; case Interrupt::Timer : status.interrupt_request_timer = 1; break; case Interrupt::Serial: status.interrupt_request_serial = 1; break; - case Interrupt::Joypad: status.interrupt_request_joypad = 1; break; + case Interrupt::Joypad: status.interrupt_request_joypad = 1; status.stop = false; break; } status.halt = false; } @@ -89,6 +89,7 @@ void CPU::power() { r[DE] = 0x0000; r[HL] = 0x0000; + status.clock = 0; status.halt = false; status.stop = false; @@ -124,7 +125,7 @@ void CPU::power() { status.interrupt_enable_vblank = 0; } -CPU::CPU() { +CPU::CPU() : trace(false) { initialize_opcode_table(); } diff --git a/gameboy/cpu/cpu.hpp b/gameboy/cpu/cpu.hpp index dc92a37c..23b632da 100755 --- a/gameboy/cpu/cpu.hpp +++ b/gameboy/cpu/cpu.hpp @@ -3,6 +3,8 @@ struct CPU : Processor, MMIO { #include "mmio/mmio.hpp" #include "timing/timing.hpp" + bool trace; + enum class Interrupt : unsigned { Vblank, Stat, @@ -12,6 +14,7 @@ struct CPU : Processor, MMIO { }; struct Status { + unsigned clock; bool halt; bool stop; diff --git a/gameboy/cpu/timing/timing.cpp b/gameboy/cpu/timing/timing.cpp index b62c5995..987dc9ea 100755 --- a/gameboy/cpu/timing/timing.cpp +++ b/gameboy/cpu/timing/timing.cpp @@ -13,6 +13,12 @@ #include "opcode.cpp" void CPU::add_clocks(unsigned clocks) { + status.clock += clocks; + if(status.clock >= 4 * 1024 * 1024) { + status.clock -= 4 * 1024 * 1024; + cartridge.mbc3.second(); + } + status.timer0 += clocks; if(status.timer0 >= 16) timer_stage0(); diff --git a/gameboy/gameboy.hpp b/gameboy/gameboy.hpp index 777a7980..1a51634b 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.07"; + static const char Version[] = "000.08"; } } diff --git a/gameboy/lcd/lcd.cpp b/gameboy/lcd/lcd.cpp index f29efea3..f555e40e 100755 --- a/gameboy/lcd/lcd.cpp +++ b/gameboy/lcd/lcd.cpp @@ -82,13 +82,11 @@ uint16 LCD::read_tile(bool select, unsigned x, unsigned y) { void LCD::render_bg() { unsigned iy = (status.ly + status.scy) & 255; unsigned ix = status.scx, tx = ix & 7; - uint8 mask = 0x80 >> tx; - unsigned data = read_tile(status.bg_tilemap_select, ix, iy), palette; + unsigned data = read_tile(status.bg_tilemap_select, ix, iy); for(unsigned ox = 0; ox < 160; ox++) { - palette = ((data & (mask << 0)) ? 1 : 0); - palette |= ((data & (mask << 8)) ? 2 : 0); - mask = (mask >> 1) | (mask << 7); + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); line[ox] = status.bgp[palette]; ix = (ix + 1) & 255; @@ -102,13 +100,11 @@ void LCD::render_window() { if(status.ly - status.wy >= 144U) return; unsigned iy = status.ly - status.wy; unsigned ix = (status.wx - 7) & 255, tx = ix & 7; - uint8 mask = 0x80 >> tx; - unsigned data = read_tile(status.window_tilemap_select, ix, iy), palette; + unsigned data = read_tile(status.window_tilemap_select, ix, iy); for(unsigned ox = 0; ox < 160; ox++) { - palette = ((data & (mask << 0)) ? 1 : 0); - palette |= ((data & (mask << 8)) ? 2 : 0); - mask = (mask >> 1) | (mask << 7); + uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) + | ((data & (0x8000 >> tx)) ? 2 : 0); if(ox - (status.wx - 7) < 160U) line[ox] = status.bgp[palette]; ix = (ix + 1) & 255; @@ -121,25 +117,53 @@ void LCD::render_window() { void LCD::render_obj() { unsigned obj_size = (status.obj_size == 0 ? 8 : 16); + unsigned sprite[10], sprites = 0; + + //find first ten sprites on this scanline for(unsigned s = 0; s < 40; s++) { unsigned sy = oam[(s << 2) + 0] - 16; unsigned sx = oam[(s << 2) + 1] - 8; - unsigned tile = oam[(s << 2) + 2]; - unsigned attribute = oam[(s << 2) + 3]; + + sy = status.ly - sy; + if(sy >= obj_size) continue; + + sprite[sprites++] = s; + if(sprites == 10) break; + } + + //sort by X-coordinate, when equal, lower address comes first + for(unsigned x = 0; x < sprites; x++) { + for(unsigned y = x + 1; y < sprites; y++) { + signed sx = oam[(sprite[x] << 2) + 1] - 8; + signed sy = oam[(sprite[y] << 2) + 1] - 8; + if(sy < sx) { + sprite[x] ^= sprite[y]; + sprite[y] ^= sprite[x]; + sprite[x] ^= sprite[y]; + } + } + } + + //render backwards, so that first sprite has highest priority + for(signed s = sprites - 1; s >= 0; s--) { + unsigned n = sprite[s] << 2; + unsigned sy = oam[n + 0] - 16; + unsigned sx = oam[n + 1] - 8; + unsigned tile = oam[n + 2]; + unsigned attribute = oam[n + 3]; sy = status.ly - sy; if(sy >= obj_size) continue; if(attribute & 0x40) sy ^= (obj_size - 1); - unsigned tdaddr = tile * 16 + sy * 2; - + unsigned tdaddr = (tile << 4) + (sy << 1); uint8 d0 = vram[tdaddr + 0]; uint8 d1 = vram[tdaddr + 1]; unsigned xflip = attribute & 0x20 ? 7 : 0; for(unsigned tx = 0; tx < 8; tx++) { - uint8 palette = ((d0 & 0x80) >> 7) + ((d1 & 0x80) >> 6); - d0 <<= 1, d1 <<= 1; + uint8 palette = ((d0 & (0x80 >> tx)) ? 1 : 0) + | ((d1 & (0x80 >> tx)) ? 2 : 0); if(palette == 0) continue; palette = status.obp[(bool)(attribute & 0x10)][palette]; diff --git a/ui/general/main-window.cpp b/ui/general/main-window.cpp index 0fc97cf8..d20d9d11 100755 --- a/ui/general/main-window.cpp +++ b/ui/general/main-window.cpp @@ -15,7 +15,7 @@ void MainWindow::create() { settingsVideoSync.setChecked(true); tools.create(*this, "Tools"); -//tools.setEnabled(false); + toolsTraceCPU.create(tools, "Trace CPU"); help.create(*this, "Help"); helpAbout.create(help, "About ..."); @@ -43,6 +43,10 @@ void MainWindow::create() { video.set(Video::Synchronize, mainWindow.settingsVideoSync.checked()); }; + toolsTraceCPU.onTick = []() { + GameBoy::cpu.trace = mainWindow.toolsTraceCPU.checked(); + }; + helpAbout.onTick = []() { MessageWindow::information(mainWindow, { "bgameboy\n\n", diff --git a/ui/general/main-window.hpp b/ui/general/main-window.hpp index f8ca8de5..57b8084f 100755 --- a/ui/general/main-window.hpp +++ b/ui/general/main-window.hpp @@ -8,6 +8,7 @@ struct MainWindow : Window { MenuCheckItem settingsVideoSync; Menu tools; + MenuCheckItem toolsTraceCPU; Menu help; MenuItem helpAbout;