diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 2149e102..b81b8f3f 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "093.07"; + static const char Version[] = "093.08"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; diff --git a/gb/apu/apu.cpp b/gb/apu/apu.cpp index 4176a5f4..9ba2b7ff 100644 --- a/gb/apu/apu.cpp +++ b/gb/apu/apu.cpp @@ -46,6 +46,10 @@ void APU::main() { noise.run(); master.run(); + hipass(master.center, master.center_bias); + hipass(master.left, master.left_bias); + hipass(master.right, master.right_bias); + interface->audioSample(master.left, master.right); clock += cpu.frequency; @@ -53,6 +57,11 @@ void APU::main() { } } +void APU::hipass(int16& sample, int64& bias) { + bias += ((((int64)sample << 16) - (bias >> 16)) * 57593) >> 16; + sample = sclamp<16>(sample - (bias >> 32)); +} + void APU::power() { create(Main, 2 * 1024 * 1024); for(unsigned n = 0xff10; n <= 0xff3f; n++) bus.mmio[n] = this; diff --git a/gb/apu/apu.hpp b/gb/apu/apu.hpp index aefe2301..14a01434 100644 --- a/gb/apu/apu.hpp +++ b/gb/apu/apu.hpp @@ -17,6 +17,7 @@ struct APU : Thread, MMIO { static void Main(); void main(); + void hipass(int16& sample, int64& bias); void power(); uint8 mmio_read(uint16 addr); diff --git a/gb/apu/master/master.cpp b/gb/apu/master/master.cpp index 0505af41..9b601f44 100644 --- a/gb/apu/master/master.cpp +++ b/gb/apu/master/master.cpp @@ -5,6 +5,8 @@ void APU::Master::run() { center = 0; left = 0; right = 0; + +center_bias = left_bias = right_bias = 0; return; } @@ -81,6 +83,10 @@ void APU::Master::power() { center = 0; left = 0; right = 0; + + center_bias = 0; + left_bias = 0; + right_bias = 0; } void APU::Master::serialize(serializer& s) { @@ -101,6 +107,10 @@ void APU::Master::serialize(serializer& s) { s.integer(center); s.integer(left); s.integer(right); + + s.integer(center_bias); + s.integer(left_bias); + s.integer(right_bias); } #endif diff --git a/gb/apu/master/master.hpp b/gb/apu/master/master.hpp index 31a1e9f0..8b4be76a 100644 --- a/gb/apu/master/master.hpp +++ b/gb/apu/master/master.hpp @@ -17,6 +17,10 @@ struct Master { int16 left; int16 right; + int64 center_bias; + int64 left_bias; + int64 right_bias; + void run(); void write(unsigned r, uint8 data); void power(); diff --git a/gb/ppu/cgb.cpp b/gb/ppu/cgb.cpp index a718107c..86aab56f 100644 --- a/gb/ppu/cgb.cpp +++ b/gb/ppu/cgb.cpp @@ -1,34 +1,24 @@ #ifdef PPU_CPP -void PPU::cgb_render() { - for(auto& pixel : pixels) { - pixel.color = 0x7fff; - pixel.palette = 0; - pixel.origin = Pixel::Origin::None; - } - - if(status.display_enable) { - cgb_render_bg(); - if(status.window_display_enable) cgb_render_window(); - if(status.ob_enable) cgb_render_ob(); - } - - uint32* output = screen + status.ly * 160; - for(unsigned n = 0; n < 160; n++) output[n] = video.palette[pixels[n].color]; - interface->lcdScanline(); -} - -//Attributes: +//BG attributes: //0x80: 0 = OAM priority, 1 = BG priority //0x40: vertical flip //0x20: horizontal flip //0x08: VRAM bank# //0x07: palette# -void PPU::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& tile, unsigned& attr, unsigned& data) { + +//OB attributes: +//0x80: 0 = OBJ above BG, 1 = BG above OBJ +//0x40: vertical flip +//0x20: horizontal flip +//0x08: VRAM bank# +//0x07: palette# + +void PPU::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& attr, unsigned& data) { unsigned tmaddr = 0x1800 + (select << 10); tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; - tile = vram[0x0000 + tmaddr]; + unsigned tile = vram[0x0000 + tmaddr]; attr = vram[0x2000 + tmaddr]; unsigned tdaddr = attr & 0x08 ? 0x2000 : 0x0000; @@ -47,127 +37,127 @@ void PPU::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& tile, uns if(attr & 0x20) data = hflip(data); } -void PPU::cgb_render_bg() { - unsigned iy = (status.ly + status.scy) & 255; - unsigned ix = status.scx, tx = ix & 7; +void PPU::cgb_scanline() { + px = 0; - unsigned tile, attr, data; - cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data); - - for(unsigned ox = 0; ox < 160; ox++) { - unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - unsigned palette = ((attr & 0x07) << 2) + index; - unsigned color = 0; - color |= bgpd[(palette << 1) + 0] << 0; - color |= bgpd[(palette << 1) + 1] << 8; - color &= 0x7fff; - - pixels[ox].color = color; - pixels[ox].palette = index; - pixels[ox].origin = (attr & 0x80 ? Pixel::Origin::BGP : Pixel::Origin::BG); - - ix = (ix + 1) & 255; - tx = (tx + 1) & 7; - if(tx == 0) cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data); - } -} - -void PPU::cgb_render_window() { - if(status.ly - status.wy >= 144u) return; - if(status.wx >= 167u) return; - unsigned iy = status.wyc++; - unsigned ix = (7 - status.wx) & 255, tx = ix & 7; - - unsigned tile, attr, data; - cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data); - - for(unsigned ox = 0; ox < 160; ox++) { - unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - unsigned palette = ((attr & 0x07) << 2) + index; - unsigned color = 0; - color |= bgpd[(palette << 1) + 0] << 0; - color |= bgpd[(palette << 1) + 1] << 8; - color &= 0x7fff; - - if(ox - (status.wx - 7) < 160u) { - pixels[ox].color = color; - pixels[ox].palette = index; - pixels[ox].origin = (attr & 0x80 ? Pixel::Origin::BGP : Pixel::Origin::BG); - } - - ix = (ix + 1) & 255; - tx = (tx + 1) & 7; - if(tx == 0) cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data); - } -} - -//Attributes: -//0x80: 0 = OBJ above BG, 1 = BG above OBJ -//0x40: vertical flip -//0x20: horizontal flip -//0x08: VRAM bank# -//0x07: palette# -void PPU::cgb_render_ob() { const unsigned Height = (status.ob_size == 0 ? 8 : 16); - unsigned sprite[10], sprites = 0; + 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; + for(unsigned n = 0; n < 40 * 4; n += 4) { + Sprite& s = sprite[sprites]; + s.y = oam[n + 0] - 16; + s.x = oam[n + 1] - 8; + s.tile = oam[n + 2] & ~status.ob_size; + s.attr = oam[n + 3]; - sy = status.ly - sy; - if(sy >= Height) continue; + s.y = status.ly - s.y; + if(s.y >= Height) continue; - sprite[sprites++] = s; - if(sprites == 10) break; + if(s.attr & 0x40) s.y ^= (Height - 1); + unsigned tdaddr = (s.attr & 0x08 ? 0x2000 : 0x0000) + (s.tile << 4) + (s.y << 1); + s.data = vram[tdaddr + 0] << 0; + s.data |= vram[tdaddr + 1] << 8; + if(s.attr & 0x20) s.data = hflip(s.data); + + if(++sprites == 10) break; + } +} + +void PPU::cgb_run() { + ob.color = 0; + ob.palette = 0; + ob.priority = 0; + + unsigned color = 0x7fff; + if(status.display_enable) { + cgb_run_bg(); + if(status.window_display_enable) cgb_run_window(); + if(status.ob_enable) cgb_run_ob(); + + if(ob.palette == 0) { + color = bg.color; + } else if(bg.palette == 0) { + color = ob.color; + } else if(status.bg_enable == 0) { + color = ob.color; + } else if(bg.priority) { + color = bg.color; + } else if(ob.priority) { + color = ob.color; + } else { + color = bg.color; + } } - //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] & ~status.ob_size; - unsigned attr = oam[n + 3]; + uint32* output = screen + status.ly * 160 + px++; + *output = video.palette[color]; +} - sy = status.ly - sy; - if(sy >= Height) continue; - if(attr & 0x40) sy ^= (Height - 1); +void PPU::cgb_run_bg() { + unsigned scrolly = (status.ly + status.scy) & 255; + unsigned scrollx = (px + status.scx) & 255; + unsigned tx = scrollx & 7; + if(tx == 0 || px == 0) cgb_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.attr, background.data); - unsigned tdaddr = (attr & 0x08 ? 0x2000 : 0x0000) + (tile << 4) + (sy << 1), data = 0; - data |= vram[tdaddr++] << 0; - data |= vram[tdaddr++] << 8; - if(attr & 0x20) data = hflip(data); + unsigned index = 0; + index |= (background.data & (0x0080 >> tx)) ? 1 : 0; + index |= (background.data & (0x8000 >> tx)) ? 2 : 0; + unsigned palette = ((background.attr & 0x07) << 2) + index; + unsigned color = 0; + color |= bgpd[(palette << 1) + 0] << 0; + color |= bgpd[(palette << 1) + 1] << 8; + color &= 0x7fff; - for(unsigned tx = 0; tx < 8; tx++) { - unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - if(index == 0) continue; + bg.color = color; + bg.palette = index; + bg.priority = background.attr & 0x80; +} - unsigned palette = ((attr & 0x07) << 2) + index; - unsigned color = 0; - color |= obpd[(palette << 1) + 0] << 0; - color |= obpd[(palette << 1) + 1] << 8; - color &= 0x7fff; +void PPU::cgb_run_window() { + if(status.ly - status.wy >= 144u) return; + if(status.wx >= 167u) return; + unsigned scrolly = (status.ly - status.wy) & 255; + unsigned scrollx = (px + 7 - status.wx) & 255; + unsigned tx = scrollx & 7; + if(tx == 0 || px == 0) cgb_read_tile(status.window_tilemap_select, scrollx, scrolly, window.attr, window.data); - unsigned ox = sx + tx; - if(ox < 160) { - //When LCDC.D0 (BG enable) is off, OB is always rendered above BG+Window - if(status.bg_enable) { - if(attr & 0x80) { - if(pixels[ox].origin == Pixel::Origin::BG || pixels[ox].origin == Pixel::Origin::BGP) { - if(pixels[ox].palette > 0) continue; - } - } - } - pixels[ox].color = color; - pixels[ox].palette = index; - pixels[ox].origin = Pixel::Origin::OB; - } - } + unsigned index = 0; + index |= (window.data & (0x0080 >> tx)) ? 1 : 0; + index |= (window.data & (0x8000 >> tx)) ? 2 : 0; + unsigned palette = ((window.attr & 0x07) << 2) + index; + unsigned color = 0; + color |= bgpd[(palette << 1) + 0] << 0; + color |= bgpd[(palette << 1) + 1] << 8; + color &= 0x7fff; + + bg.color = color; + bg.palette = index; + bg.priority = window.attr & 0x80; +} + +void PPU::cgb_run_ob() { + //render backwards, so that first sprite has priority + for(signed n = sprites - 1; n >= 0; n--) { + Sprite& s = sprite[n]; + + signed tx = px - s.x; + if(tx < 0 || tx > 7) continue; + + unsigned index = 0; + index |= (s.data & (0x0080 >> tx)) ? 1 : 0; + index |= (s.data & (0x8000 >> tx)) ? 2 : 0; + if(index == 0) continue; + + unsigned palette = ((s.attr & 0x07) << 2) + index; + unsigned color = 0; + color |= obpd[(palette << 1) + 0] << 0; + color |= obpd[(palette << 1) + 1] << 8; + color &= 0x7fff; + + ob.color = color; + ob.palette = index; + ob.priority = !(s.attr & 0x80); } } diff --git a/gb/ppu/dmg.cpp b/gb/ppu/dmg.cpp index 107f29a4..48e34b20 100644 --- a/gb/ppu/dmg.cpp +++ b/gb/ppu/dmg.cpp @@ -1,24 +1,12 @@ #ifdef PPU_CPP -void PPU::dmg_render() { - for(auto& pixel : pixels) { - pixel.color = 0; - pixel.palette = 0; - pixel.origin = Pixel::Origin::None; - } +//OB attributes: +//0x80: 0 = OBJ above BG, 1 = BG above OBJ +//0x40: vertical flip +//0x20: horizontal flip +//0x10: palette# - if(status.display_enable) { - if(status.bg_enable) dmg_render_bg(); - if(status.window_display_enable) dmg_render_window(); - if(status.ob_enable) dmg_render_ob(); - } - - uint32* output = screen + status.ly * 160; - for(unsigned n = 0; n < 160; n++) output[n] = video.palette[pixels[n].color]; - interface->lcdScanline(); -} - -uint16 PPU::dmg_read_tile(bool select, unsigned x, unsigned y) { +void PPU::dmg_read_tile(bool select, unsigned x, unsigned y, unsigned& data) { unsigned tmaddr = 0x1800 + (select << 10), tdaddr; tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; if(status.bg_tiledata_select == 0) { @@ -27,117 +15,118 @@ uint16 PPU::dmg_read_tile(bool select, unsigned x, unsigned y) { tdaddr = 0x0000 + (vram[tmaddr] << 4); } tdaddr += (y & 7) << 1; - return (vram[tdaddr + 0] << 0) | (vram[tdaddr + 1] << 8); + data = vram[tdaddr + 0] << 0; + data |= vram[tdaddr + 1] << 8; } -void PPU::dmg_render_bg() { - unsigned iy = (status.ly + status.scy) & 255; - unsigned ix = status.scx, tx = ix & 7; - unsigned data = dmg_read_tile(status.bg_tilemap_select, ix, iy); +void PPU::dmg_scanline() { + px = 0; - for(unsigned ox = 0; ox < 160; ox++) { - uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - - pixels[ox].color = bgp[palette]; - pixels[ox].palette = palette; - pixels[ox].origin = Pixel::Origin::BG; - - ix = (ix + 1) & 255; - tx = (tx + 1) & 7; - - if(tx == 0) data = dmg_read_tile(status.bg_tilemap_select, ix, iy); - } -} - -void PPU::dmg_render_window() { - if(status.ly - status.wy >= 144u) return; - if(status.wx >= 167u) return; - unsigned iy = status.wyc++; - unsigned ix = (7 - status.wx) & 255, tx = ix & 7; - unsigned data = dmg_read_tile(status.window_tilemap_select, ix, iy); - - for(unsigned ox = 0; ox < 160; ox++) { - uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - - if(ox - (status.wx - 7) < 160u) { - pixels[ox].color = bgp[palette]; - pixels[ox].palette = palette; - pixels[ox].origin = Pixel::Origin::BG; - } - - ix = (ix + 1) & 255; - tx = (tx + 1) & 7; - - if(tx == 0) data = dmg_read_tile(status.window_tilemap_select, ix, iy); - } -} - -//Attributes: -//0x80: 0 = OBJ above BG, 1 = BG above OBJ -//0x40: vertical flip -//0x20: horizontal flip -//0x10: palette# -void PPU::dmg_render_ob() { const unsigned Height = (status.ob_size == 0 ? 8 : 16); - unsigned sprite[10], sprites = 0; + 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; + for(unsigned n = 0; n < 40 * 4; n += 4) { + Sprite& s = sprite[sprites]; + s.y = oam[n + 0] - 16; + s.x = oam[n + 1] - 8; + s.tile = oam[n + 2] & ~status.ob_size; + s.attr = oam[n + 3]; - sy = status.ly - sy; - if(sy >= Height) continue; + s.y = status.ly - s.y; + if(s.y >= Height) continue; - sprite[sprites++] = s; - if(sprites == 10) break; + if(s.attr & 0x40) s.y ^= (Height - 1); + unsigned tdaddr = (s.tile << 4) + (s.y << 1); + s.data = vram[tdaddr + 0] << 0; + s.data |= vram[tdaddr + 1] << 8; + if(s.attr & 0x20) s.data = hflip(s.data); + + 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) std::swap(sprite[x], sprite[y]); + //sort by X-coordinate + for(unsigned lo = 0; lo < sprites; lo++) { + for(unsigned hi = lo + 1; hi < sprites; hi++) { + if(sprite[hi].x < sprite[lo].x) std::swap(sprite[lo], sprite[hi]); + } + } +} + +void PPU::dmg_run() { + bg.color = 0; + bg.palette = 0; + + ob.color = 0; + ob.palette = 0; + + unsigned color = 0; + if(status.display_enable) { + if(status.bg_enable) dmg_run_bg(); + if(status.window_display_enable) dmg_run_window(); + if(status.ob_enable) dmg_run_ob(); + + if(ob.palette == 0) { + color = bg.color; + } else if(bg.palette == 0) { + color = ob.color; + } else if(ob.priority) { + color = ob.color; + } else { + color = bg.color; } } - //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] & ~status.ob_size; - unsigned attr = oam[n + 3]; + uint32* output = screen + status.ly * 160 + px++; + *output = video.palette[color]; +} - sy = status.ly - sy; - if(sy >= Height) continue; - if(attr & 0x40) sy ^= (Height - 1); +void PPU::dmg_run_bg() { + unsigned scrolly = (status.ly + status.scy) & 255; + unsigned scrollx = (px + status.scx) & 255; + unsigned tx = scrollx & 7; + if(tx == 0 || px == 0) dmg_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.data); - unsigned tdaddr = (tile << 4) + (sy << 1), data = 0; - data |= vram[tdaddr++] << 0; - data |= vram[tdaddr++] << 8; - if(attr & 0x20) data = hflip(data); + unsigned index = 0; + index |= (background.data & (0x0080 >> tx)) ? 1 : 0; + index |= (background.data & (0x8000 >> tx)) ? 2 : 0; - for(unsigned tx = 0; tx < 8; tx++) { - uint8 palette = ((data & (0x0080 >> tx)) ? 1 : 0) - | ((data & (0x8000 >> tx)) ? 2 : 0); - if(palette == 0) continue; + bg.color = bgp[index]; + bg.palette = index; +} - unsigned ox = sx + tx; - if(ox < 160) { - if(attr & 0x80) { - if(pixels[ox].origin == Pixel::Origin::BG) { - if(pixels[ox].palette > 0) continue; - } - } - pixels[ox].color = obp[(bool)(attr & 0x10)][palette]; - pixels[ox].palette = palette; - pixels[ox].origin = Pixel::Origin::OB; - } - } +void PPU::dmg_run_window() { + if(status.ly - status.wy >= 144u) return; + if(status.wx >= 167u) return; + unsigned scrolly = (status.ly - status.wy) & 255; + unsigned scrollx = (px + 7 - status.wx) & 255; + unsigned tx = scrollx & 7; + if(tx == 0 || px == 0) dmg_read_tile(status.window_tilemap_select, scrollx, scrolly, window.data); + + unsigned index = 0; + index |= (window.data & (0x0080 >> tx)) ? 1 : 0; + index |= (window.data & (0x8000 >> tx)) ? 2 : 0; + + bg.color = bgp[index]; + bg.palette = index; +} + +void PPU::dmg_run_ob() { + //render backwards, so that first sprite has priority + for(signed n = sprites - 1; n >= 0; n--) { + Sprite& s = sprite[n]; + + signed tx = px - s.x; + if(tx < 0 || tx > 7) continue; + + unsigned index = 0; + index |= (s.data & (0x0080 >> tx)) ? 1 : 0; + index |= (s.data & (0x8000 >> tx)) ? 2 : 0; + if(index == 0) continue; + + ob.color = obp[(bool)(s.attr & 0x10)][index]; + ob.palette = index; + ob.priority = !(s.attr & 0x80); } } diff --git a/gb/ppu/ppu.cpp b/gb/ppu/ppu.cpp index a9734c2a..2b2e44cc 100644 --- a/gb/ppu/ppu.cpp +++ b/gb/ppu/ppu.cpp @@ -25,22 +25,36 @@ void PPU::main() { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } - add_clocks(4); - status.lx += 4; - if(status.lx >= 456) scanline(); - - if(status.display_enable && status.lx == 0) { + //X = 0 + if(status.display_enable) { if(status.interrupt_oam) cpu.interrupt_raise(CPU::Interrupt::Stat); } - if(status.display_enable && status.lx == 252) { + add_clocks(92); + + if(status.ly < 144) { + for(unsigned n = 0; n < 160; n++) { + system.cgb() ? cgb_run() : dmg_run(); + add_clocks(1); + } + } else { + //Vblank + add_clocks(160); + } + + //X = 252 + if(status.display_enable) { if(status.interrupt_hblank) cpu.interrupt_raise(CPU::Interrupt::Stat); cpu.hblank(); } + + add_clocks(204); + scanline(); } } void PPU::add_clocks(unsigned clocks) { + status.lx += clocks; clock += clocks * cpu.frequency; if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) { co_switch(scheduler.active_thread = cpu.thread); @@ -48,17 +62,17 @@ void PPU::add_clocks(unsigned clocks) { } void PPU::scanline() { - status.lx -= 456; + status.lx = 0; if(++status.ly == 154) frame(); + if(status.ly < 144) { + system.cgb() ? cgb_scanline() : dmg_scanline(); + } + if(status.display_enable && status.interrupt_lyc == true) { if(status.ly == status.lyc) cpu.interrupt_raise(CPU::Interrupt::Stat); } - if(status.ly < 144) { - system.cgb() == false ? dmg_render() : cgb_render(); - } - if(status.display_enable && status.ly == 144) { cpu.interrupt_raise(CPU::Interrupt::Vblank); if(status.interrupt_vblank) cpu.interrupt_raise(CPU::Interrupt::Stat); @@ -69,7 +83,6 @@ void PPU::frame() { cpu.mmio_joyp_poll(); status.ly = 0; - status.wyc = 0; scheduler.exit(Scheduler::ExitReason::FrameEvent); } @@ -106,13 +119,6 @@ void PPU::power() { bus.mmio[0xff6b] = this; //OBPD } - for(auto& n : screen) n = 0x0000; - for(auto& n : pixels) { - n.color = 0; - n.palette = 0; - n.origin = Pixel::Origin::None; - } - for(auto& n : vram) n = 0x00; for(auto& n : oam) n = 0x00; for(auto& n : bgp) n = 0x00; @@ -122,7 +128,6 @@ void PPU::power() { for(auto& n : obpd) n = 0x0000; status.lx = 0; - status.wyc = 0; status.display_enable = 0; status.window_tilemap_select = 0; @@ -152,6 +157,31 @@ void PPU::power() { status.obpi_increment = 0; status.obpi = 0; + + for(auto& n : screen) n = 0x0000; + + bg.color = 0; + bg.palette = 0; + bg.priority = 0; + + ob.color = 0; + ob.palette = 0; + ob.priority = 0; + + for(auto& s : sprite) { + s.x = 0; + s.y = 0; + s.tile = 0; + s.attr = 0; + s.data = 0; + } + sprites = 0; + + background.attr = 0; + background.data = 0; + + window.attr = 0; + window.data = 0; } PPU::PPU() { diff --git a/gb/ppu/ppu.hpp b/gb/ppu/ppu.hpp index d970d7cb..436a62f2 100644 --- a/gb/ppu/ppu.hpp +++ b/gb/ppu/ppu.hpp @@ -1,7 +1,13 @@ struct PPU : Thread, MMIO { + uint8 vram[16384]; //GB = 8192, GBC = 16384 + uint8 oam[160]; + uint8 bgp[4]; + uint8 obp[2][4]; + uint8 bgpd[64]; + uint8 obpd[64]; + struct Status { unsigned lx; - unsigned wyc; //$ff40 LCDC bool display_enable; @@ -50,19 +56,33 @@ struct PPU : Thread, MMIO { } status; uint32 screen[160 * 144]; + struct Pixel { - enum class Origin : unsigned { None, BG, BGP, OB }; uint16 color; uint8 palette; - Origin origin; - } pixels[160]; + bool priority; + }; + Pixel bg; + Pixel ob; - uint8 vram[16384]; //GB = 8192, GBC = 16384 - uint8 oam[160]; - uint8 bgp[4]; - uint8 obp[2][4]; - uint8 bgpd[64]; - uint8 obpd[64]; + struct Sprite { + unsigned x; + unsigned y; + unsigned tile; + unsigned attr; + unsigned data; + }; + Sprite sprite[10]; + unsigned sprites; + + unsigned px; + + struct Background { + unsigned attr; + unsigned data; + }; + Background background; + Background window; static void Main(); void main(); @@ -78,18 +98,20 @@ struct PPU : Thread, MMIO { void mmio_write(uint16 addr, uint8 data); //dmg.cpp - void dmg_render(); - uint16 dmg_read_tile(bool select, unsigned x, unsigned y); - void dmg_render_bg(); - void dmg_render_window(); - void dmg_render_ob(); + void dmg_read_tile(bool select, unsigned x, unsigned y, unsigned& data); + void dmg_scanline(); + void dmg_run(); + void dmg_run_bg(); + void dmg_run_window(); + void dmg_run_ob(); //cgb.cpp - void cgb_render(); - void cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& tile, unsigned& attr, unsigned& data); - void cgb_render_bg(); - void cgb_render_window(); - void cgb_render_ob(); + void cgb_read_tile(bool select, unsigned x, unsigned y, unsigned& attr, unsigned& data); + void cgb_scanline(); + void cgb_run(); + void cgb_run_bg(); + void cgb_run_window(); + void cgb_run_ob(); void power(); diff --git a/gb/ppu/serialization.cpp b/gb/ppu/serialization.cpp index 362ae539..3845de65 100644 --- a/gb/ppu/serialization.cpp +++ b/gb/ppu/serialization.cpp @@ -3,13 +3,6 @@ void PPU::serialize(serializer& s) { Thread::serialize(s); - s.array(screen); - for(auto& pixel : pixels) { - s.integer(pixel.color); - s.integer(pixel.palette); - s.integer((unsigned&)pixel.origin); - } - s.array(vram); s.array(oam); s.array(bgp); @@ -19,7 +12,6 @@ void PPU::serialize(serializer& s) { s.array(obpd); s.integer(status.lx); - s.integer(status.wyc); s.integer(status.display_enable); s.integer(status.window_tilemap_select); @@ -51,6 +43,30 @@ void PPU::serialize(serializer& s) { s.integer(status.obpi_increment); s.integer(status.obpi); + + s.array(screen); + + s.integer(bg.color); + s.integer(bg.palette); + s.integer(bg.priority); + + s.integer(ob.color); + s.integer(ob.palette); + s.integer(ob.priority); + + for(auto& o : sprite) { + s.integer(o.x); + s.integer(o.y); + s.integer(o.tile); + s.integer(o.attr); + } + s.integer(sprites); + + s.integer(background.attr); + s.integer(background.data); + + s.integer(window.attr); + s.integer(window.data); } #endif diff --git a/gb/video/video.cpp b/gb/video/video.cpp index fb5451dd..ade0a00b 100644 --- a/gb/video/video.cpp +++ b/gb/video/video.cpp @@ -26,9 +26,9 @@ unsigned Video::palette_dmg(unsigned color) const { return interface->videoColor(color, L, L, L); } - unsigned R = monochrome[color][0] * 65535.0; - unsigned G = monochrome[color][1] * 65535.0; - unsigned B = monochrome[color][2] * 65535.0; + unsigned R = monochrome[color][0]; + unsigned G = monochrome[color][1]; + unsigned B = monochrome[color][2]; return interface->videoColor(color, R, G, B); } @@ -68,11 +68,27 @@ unsigned Video::palette_cgb(unsigned color) const { return interface->videoColor(color, R, G, B); } -const double Video::monochrome[4][3] = { - {0.605, 0.734, 0.059}, - {0.543, 0.672, 0.059}, - {0.188, 0.383, 0.188}, - {0.059, 0.219, 0.059}, +#define DMG_PALETTE_GREEN +//#define DMG_PALETTE_YELLOW +//#define DMG_PALETTE_WHITE + +const uint16 Video::monochrome[4][3] = { + #if defined(DMG_PALETTE_GREEN) + {0x9a9a, 0xbbbb, 0x0505}, + {0x7878, 0x8484, 0x0505}, + {0x1d1d, 0x5555, 0x1d1d}, + {0x0505, 0x2525, 0x0505}, + #elif defined(DMG_PALETTE_YELLOW) + {0xffff, 0xf7f7, 0x7b7b}, + {0xb5b5, 0xaeae, 0x4a4a}, + {0x6b6b, 0x6969, 0x3131}, + {0x2121, 0x2020, 0x1010}, + #else //DMG_PALETTE_WHITE + {0xffff, 0xffff, 0xffff}, + {0xaaaa, 0xaaaa, 0xaaaa}, + {0x5555, 0x5555, 0x5555}, + {0x0000, 0x0000, 0x0000}, + #endif }; } diff --git a/gb/video/video.hpp b/gb/video/video.hpp index a4fab2c0..e980e8f0 100644 --- a/gb/video/video.hpp +++ b/gb/video/video.hpp @@ -7,7 +7,7 @@ struct Video { private: bool color_emulation; - static const double monochrome[4][3]; + static const uint16 monochrome[4][3]; uint32_t palette_dmg(unsigned color) const; uint32_t palette_sgb(unsigned color) const; uint32_t palette_cgb(unsigned color) const; diff --git a/phoenix/gtk/widget/list-view.cpp b/phoenix/gtk/widget/list-view.cpp index 54e3b121..88cba71a 100644 --- a/phoenix/gtk/widget/list-view.cpp +++ b/phoenix/gtk/widget/list-view.cpp @@ -104,18 +104,12 @@ void pListView::setSelected(bool selected) { void pListView::setSelection(unsigned selection) { GtkTreeSelection* treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget)); - GtkTreeModel* model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget)); gtk_tree_selection_unselect_all(treeSelection); - GtkTreeIter iter; - if(gtk_tree_model_get_iter_from_string(model, &iter, string(selection)) == false) return; - gtk_tree_selection_select_iter(treeSelection, &iter); - - //scroll window to selected item - char* path = gtk_tree_model_get_string_from_iter(model, &iter); - GtkTreePath* treePath = gtk_tree_path_new_from_string(path); - gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(subWidget), treePath, nullptr, true, 0.5, 0.0); - gtk_tree_path_free(treePath); - g_free(path); + GtkTreePath* path = gtk_tree_path_new_from_string(string{selection}); + gtk_tree_selection_select_path(treeSelection, path); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(subWidget), path, nullptr, false); + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(subWidget), path, nullptr, true, 0.5, 0.0); + gtk_tree_path_free(path); } void pListView::setText(unsigned selection, unsigned position, string text) { diff --git a/phoenix/windows/widget/combo-button.cpp b/phoenix/windows/widget/combo-button.cpp index 3455a4ad..48dbec46 100644 --- a/phoenix/windows/widget/combo-button.cpp +++ b/phoenix/windows/widget/combo-button.cpp @@ -24,7 +24,8 @@ void pComboButton::reset() { } void pComboButton::setGeometry(Geometry geometry) { - pWidget::setGeometry(geometry); + //height = minimum drop-down list height; use CB_SETITEMHEIGHT to control actual widget height + pWidget::setGeometry({geometry.x, geometry.y, geometry.width, 1}); RECT rc; GetWindowRect(hwnd, &rc); unsigned adjustedHeight = geometry.height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); diff --git a/sfc/chip/icd2/icd2.cpp b/sfc/chip/icd2/icd2.cpp index 75ed702a..6493b55a 100644 --- a/sfc/chip/icd2/icd2.cpp +++ b/sfc/chip/icd2/icd2.cpp @@ -46,7 +46,7 @@ void ICD2::unload() { void ICD2::power() { audio.coprocessor_enable(true); - audio.coprocessor_frequency(4 * 1024 * 1024); + audio.coprocessor_frequency(2 * 1024 * 1024); } void ICD2::reset() { diff --git a/target-ethos/utility/utility.cpp b/target-ethos/utility/utility.cpp index 52f99b51..0212b08c 100644 --- a/target-ethos/utility/utility.cpp +++ b/target-ethos/utility/utility.cpp @@ -128,7 +128,7 @@ void Utility::saveState(unsigned slot) { if(s.size() == 0) return; directory::create({pathname[0], "bsnes/"}); if(file::write({pathname[0], "bsnes/state-", slot, ".bsa"}, s.data(), s.size()) == false); - showMessage({"Save to slot ", slot}); + showMessage({"Saved to slot ", slot}); } void Utility::loadState(unsigned slot) {