diff --git a/bsnes.exe b/bsnes.exe index 69c84606..41af013f 100644 Binary files a/bsnes.exe and b/bsnes.exe differ diff --git a/src/snes/ppu/sppu/screen/screen.cpp b/src/snes/ppu/sppu/screen/screen.cpp index 697d8913..2bf0ed82 100644 --- a/src/snes/ppu/sppu/screen/screen.cpp +++ b/src/snes/ppu/sppu/screen/screen.cpp @@ -103,7 +103,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) { source_sub = OAM; } if(priority_sub == 0) { - if(self.regs.bgmode == 5 || self.regs.bgmode == 6) { + if(self.regs.pseudo_hires == true || self.regs.bgmode == 5 || self.regs.bgmode == 6) { color_sub = get_color(0); } else { color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0); diff --git a/src/snes/ppu/sppu/serialization.cpp b/src/snes/ppu/sppu/serialization.cpp index 73efc62c..0a6a0a54 100644 --- a/src/snes/ppu/sppu/serialization.cpp +++ b/src/snes/ppu/sppu/serialization.cpp @@ -118,7 +118,6 @@ void sPPU::Sprite::serialize(serializer &s) { s.integer(t.x); s.integer(t.y); - s.integer(t.active_sprite); s.integer(t.item_count); s.integer(t.tile_count); @@ -127,11 +126,13 @@ void sPPU::Sprite::serialize(serializer &s) { s.array(t.item[n]); for(unsigned i = 0; i < 34; i++) { s.integer(t.tile[n][i].x); - s.integer(t.tile[n][i].y); s.integer(t.tile[n][i].priority); s.integer(t.tile[n][i].palette); - s.integer(t.tile[n][i].tile); s.integer(t.tile[n][i].hflip); + s.integer(t.tile[n][i].d0); + s.integer(t.tile[n][i].d1); + s.integer(t.tile[n][i].d2); + s.integer(t.tile[n][i].d3); } } diff --git a/src/snes/ppu/sppu/sppu.cpp b/src/snes/ppu/sppu/sppu.cpp index dfcf0dd7..acb2bc4e 100644 --- a/src/snes/ppu/sppu/sppu.cpp +++ b/src/snes/ppu/sppu/sppu.cpp @@ -26,7 +26,7 @@ void sPPU::enter() { scanline(); add_clocks(88); - if(vcounter() >= 1 && vcounter() <= (!regs.overscan ? 224 : 239)) { + if(vcounter() <= (!regs.overscan ? 224 : 239)) { for(unsigned n = 0; n < 256; n++) { bg1.run(); bg2.run(); @@ -43,11 +43,14 @@ void sPPU::enter() { screen.run(); add_clocks(2); } + + add_clocks(22); + oam.tilefetch(); } else { - add_clocks(1024); + add_clocks(1024 + 22 + 136); } - add_clocks(lineclocks() - 88 - 1024); + add_clocks(lineclocks() - 88 - 1024 - 22 - 136); } } diff --git a/src/snes/ppu/sppu/sprite/sprite.cpp b/src/snes/ppu/sppu/sprite/sprite.cpp index ba3c8ced..341ae433 100644 --- a/src/snes/ppu/sppu/sprite/sprite.cpp +++ b/src/snes/ppu/sppu/sprite/sprite.cpp @@ -26,136 +26,135 @@ void sPPU::Sprite::scanline() { auto oam_item = t.item[t.active]; auto oam_tile = t.tile[t.active]; - memset(oam_item, 0xff, 32); - for(unsigned i = 0; i < 34; i++) oam_tile[i].tile = 0xffff; + memset(oam_item, 0xff, 32); //default to invalid + for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid for(unsigned i = 0; i < 128; i++) { - t.active_sprite = (i + regs.first_sprite) & 127; - if(on_scanline() == false) continue; + unsigned sprite = (regs.first_sprite + i) & 127; + if(on_scanline(list[sprite]) == false) continue; if(t.item_count++ >= 32) break; - oam_item[t.item_count - 1] = (i + regs.first_sprite) & 127; + oam_item[t.item_count - 1] = sprite; } if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) { ppu.regs.ioamaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2); } - - for(signed i = 31; i >= 0; i--) { - if(oam_item[i] == 0xff) continue; - t.active_sprite = oam_item[i]; - load_tiles(); - } - - regs.time_over |= (t.tile_count > 34); - regs.range_over |= (t.item_count > 32); } -bool sPPU::Sprite::on_scanline() { - SpriteItem &sprite = list[t.active_sprite]; +bool sPPU::Sprite::on_scanline(SpriteItem &sprite) { if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false; - signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1)); if(t.y >= sprite.y && t.y < (sprite.y + height)) return true; if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true; return false; } -void sPPU::Sprite::load_tiles() { - SpriteItem &sprite = list[t.active_sprite]; - unsigned tile_width = sprite.width() >> 3; - signed x = sprite.x; - signed y = (t.y - sprite.y) & 0xff; - if(regs.interlace) y <<= 1; - - if(sprite.vflip) { - if(sprite.width() == sprite.height()) { - y = (sprite.height() - 1) - y; - } else { - y = (y < sprite.width()) ? ((sprite.width() - 1) - y) : (sprite.width() + ((sprite.width() - 1) - (y - sprite.width()))); - } - } - - if(regs.interlace) { - y = (sprite.vflip == false ? y + self.field() : y - self.field()); - } - - x &= 511; - y &= 255; - - uint16 tiledata_addr = regs.tiledata_addr; - uint16 chrx = (sprite.character >> 0) & 15; - uint16 chry = (sprite.character >> 4) & 15; - if(sprite.nameselect) { - tiledata_addr += (256 * 32) + (regs.nameselect << 13); - } - chry += (y >> 3); - chry &= 15; - chry <<= 4; - - auto oam_tile = t.tile[t.active]; - - for(unsigned tx = 0; tx < tile_width; tx++) { - unsigned sx = (x + (tx << 3)) & 511; - if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; - - if(t.tile_count++ >= 34) break; - unsigned n = t.tile_count - 1; - oam_tile[n].x = sx; - oam_tile[n].y = y; - oam_tile[n].priority = sprite.priority; - oam_tile[n].palette = 128 + (sprite.palette << 4); - oam_tile[n].hflip = sprite.hflip; - - unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx); - unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5); - oam_tile[n].tile = (pos >> 5) & 0x07ff; - } -} - void sPPU::Sprite::run() { output.main.priority = 0; output.sub.priority = 0; + auto oam_tile = t.tile[!t.active]; unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 }; unsigned x = t.x++; for(unsigned n = 0; n < 34; n++) { - TileItem &item = t.tile[!t.active][n]; - if(item.tile == 0xffff) break; + auto tile = oam_tile[n]; + if(tile.x == 0xffff) break; - int px = x - sclip<9>(item.x); + int px = x - sclip<9>(tile.x); if(px & ~7) continue; - uint16 addr = (item.tile << 5) + ((item.y & 7) * 2); - unsigned mask = 0x80 >> (item.hflip == false ? px : 7 - px); - - uint8 d0 = memory::vram[addr + 0]; - uint8 d1 = memory::vram[addr + 1]; - uint8 d2 = memory::vram[addr + 16]; - uint8 d3 = memory::vram[addr + 17]; - + unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px); unsigned color; - color = ((bool)(d0 & mask)) << 0; - color |= ((bool)(d1 & mask)) << 1; - color |= ((bool)(d2 & mask)) << 2; - color |= ((bool)(d3 & mask)) << 3; + color = ((bool)(tile.d0 & mask)) << 0; + color |= ((bool)(tile.d1 & mask)) << 1; + color |= ((bool)(tile.d2 & mask)) << 2; + color |= ((bool)(tile.d3 & mask)) << 3; if(color) { - color += item.palette; - if(regs.main_enabled) { - output.main.palette = color; - output.main.priority = priority_table[item.priority]; + output.main.palette = tile.palette + color; + output.main.priority = priority_table[tile.priority]; } if(regs.sub_enabled) { - output.sub.palette = color; - output.sub.priority = priority_table[item.priority]; + output.sub.palette = tile.palette + color; + output.sub.priority = priority_table[tile.priority]; } } } } +void sPPU::Sprite::tilefetch() { + auto oam_item = t.item[t.active]; + auto oam_tile = t.tile[t.active]; + + for(signed i = 31; i >= 0; i--) { + if(oam_item[i] == 0xff) continue; + auto sprite = list[oam_item[i]]; + + unsigned tile_width = sprite.width() >> 3; + signed x = sprite.x; + signed y = (t.y - sprite.y) & 0xff; + if(regs.interlace) y <<= 1; + + if(sprite.vflip) { + if(sprite.width() == sprite.height()) { + y = (sprite.height() - 1) - y; + } else if(y < sprite.width()) { + y = (sprite.width() - 1) - y; + } else { + y = sprite.width() + ((sprite.width() - 1) - (y - sprite.width())); + } + } + + if(regs.interlace) { + y = (sprite.vflip == false ? y + self.field() : y - self.field()); + } + + x &= 511; + y &= 255; + + uint16 tiledata_addr = regs.tiledata_addr; + uint16 chrx = (sprite.character >> 0) & 15; + uint16 chry = (sprite.character >> 4) & 15; + if(sprite.nameselect) { + tiledata_addr += (256 * 32) + (regs.nameselect << 13); + } + chry += (y >> 3); + chry &= 15; + chry <<= 4; + + for(unsigned tx = 0; tx < tile_width; tx++) { + unsigned sx = (x + (tx << 3)) & 511; + if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; + if(t.tile_count++ >= 34) break; + + unsigned n = t.tile_count - 1; + oam_tile[n].x = sx; + oam_tile[n].priority = sprite.priority; + oam_tile[n].palette = 128 + (sprite.palette << 4); + oam_tile[n].hflip = sprite.hflip; + + unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx); + unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5); + uint16 addr = (pos & 0xffe0) + ((y & 7) * 2); + + oam_tile[n].d0 = memory::vram[addr + 0]; + oam_tile[n].d1 = memory::vram[addr + 1]; + self.add_clocks(2); + + oam_tile[n].d2 = memory::vram[addr + 16]; + oam_tile[n].d3 = memory::vram[addr + 17]; + self.add_clocks(2); + } + } + + if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4); + regs.time_over |= (t.tile_count > 34); + regs.range_over |= (t.item_count > 32); +} + void sPPU::Sprite::reset() { for(unsigned i = 0; i < 128; i++) { list[i].x = 0; @@ -172,7 +171,6 @@ void sPPU::Sprite::reset() { t.x = 0; t.y = 0; - t.active_sprite = 0; t.item_count = 0; t.tile_count = 0; @@ -181,11 +179,13 @@ void sPPU::Sprite::reset() { memset(t.item[n], 0, 32); for(unsigned i = 0; i < 34; i++) { t.tile[n][i].x = 0; - t.tile[n][i].y = 0; t.tile[n][i].priority = 0; t.tile[n][i].palette = 0; - t.tile[n][i].tile = 0; t.tile[n][i].hflip = 0; + t.tile[n][i].d0 = 0; + t.tile[n][i].d1 = 0; + t.tile[n][i].d2 = 0; + t.tile[n][i].d3 = 0; } } diff --git a/src/snes/ppu/sppu/sprite/sprite.hpp b/src/snes/ppu/sppu/sprite/sprite.hpp index daa77b4e..2bf95711 100644 --- a/src/snes/ppu/sppu/sprite/sprite.hpp +++ b/src/snes/ppu/sppu/sprite/sprite.hpp @@ -18,18 +18,16 @@ public: struct TileItem { uint16 x; - uint16 y; uint16 priority; uint16 palette; - uint16 tile; bool hflip; + uint8 d0, d1, d2, d3; }; struct State { unsigned x; unsigned y; - unsigned active_sprite; unsigned item_count; unsigned tile_count; @@ -72,12 +70,12 @@ public: void frame(); void scanline(); void run(); + void tilefetch(); void reset(); void serialize(serializer&); Sprite(sPPU &self); private: - bool on_scanline(); - void load_tiles(); + bool on_scanline(SpriteItem&); }; diff --git a/src/snes/snes.hpp b/src/snes/snes.hpp index 96baa8a4..0b4da2cb 100644 --- a/src/snes/snes.hpp +++ b/src/snes/snes.hpp @@ -1,4 +1,4 @@ -static const char bsnesVersion[] = "067.03"; +static const char bsnesVersion[] = "067.04"; static const char bsnesTitle[] = "bsnes"; static const unsigned bsnesSerializerVersion = 12;