Update to bsnes v067r04 release.

This build simplifies the tile cache significantly, and it now builds
the cache and fetches the VRAM data during Hblank, the VRAM reads are
modeled after real hardware.
This fixes Mega lo Mania without regressing Winter Gold or Adventures
of Dr. Franken.
I also fixed a pseudo-hires back color glitch in Super Buster Bros.
This commit is contained in:
byuu 2010-08-06 14:06:31 +00:00
parent dcc661cb28
commit 254a5016e1
7 changed files with 108 additions and 106 deletions

BIN
bsnes.exe

Binary file not shown.

View File

@ -103,7 +103,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
source_sub = OAM; source_sub = OAM;
} }
if(priority_sub == 0) { 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); color_sub = get_color(0);
} else { } else {
color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0); color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0);

View File

@ -118,7 +118,6 @@ void sPPU::Sprite::serialize(serializer &s) {
s.integer(t.x); s.integer(t.x);
s.integer(t.y); s.integer(t.y);
s.integer(t.active_sprite);
s.integer(t.item_count); s.integer(t.item_count);
s.integer(t.tile_count); s.integer(t.tile_count);
@ -127,11 +126,13 @@ void sPPU::Sprite::serialize(serializer &s) {
s.array(t.item[n]); s.array(t.item[n]);
for(unsigned i = 0; i < 34; i++) { for(unsigned i = 0; i < 34; i++) {
s.integer(t.tile[n][i].x); 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].priority);
s.integer(t.tile[n][i].palette); 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].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);
} }
} }

View File

@ -26,7 +26,7 @@ void sPPU::enter() {
scanline(); scanline();
add_clocks(88); add_clocks(88);
if(vcounter() >= 1 && vcounter() <= (!regs.overscan ? 224 : 239)) { if(vcounter() <= (!regs.overscan ? 224 : 239)) {
for(unsigned n = 0; n < 256; n++) { for(unsigned n = 0; n < 256; n++) {
bg1.run(); bg1.run();
bg2.run(); bg2.run();
@ -43,11 +43,14 @@ void sPPU::enter() {
screen.run(); screen.run();
add_clocks(2); add_clocks(2);
} }
add_clocks(22);
oam.tilefetch();
} else { } else {
add_clocks(1024); add_clocks(1024 + 22 + 136);
} }
add_clocks(lineclocks() - 88 - 1024); add_clocks(lineclocks() - 88 - 1024 - 22 - 136);
} }
} }

View File

@ -26,136 +26,135 @@ void sPPU::Sprite::scanline() {
auto oam_item = t.item[t.active]; auto oam_item = t.item[t.active];
auto oam_tile = t.tile[t.active]; auto oam_tile = t.tile[t.active];
memset(oam_item, 0xff, 32); memset(oam_item, 0xff, 32); //default to invalid
for(unsigned i = 0; i < 34; i++) oam_tile[i].tile = 0xffff; for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid
for(unsigned i = 0; i < 128; i++) { for(unsigned i = 0; i < 128; i++) {
t.active_sprite = (i + regs.first_sprite) & 127; unsigned sprite = (regs.first_sprite + i) & 127;
if(on_scanline() == false) continue; if(on_scanline(list[sprite]) == false) continue;
if(t.item_count++ >= 32) break; 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) { if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) {
ppu.regs.ioamaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2); 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() { bool sPPU::Sprite::on_scanline(SpriteItem &sprite) {
SpriteItem &sprite = list[t.active_sprite];
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false; if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1)); signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1));
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true; 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; if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
return false; 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() { void sPPU::Sprite::run() {
output.main.priority = 0; output.main.priority = 0;
output.sub.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 priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
unsigned x = t.x++; unsigned x = t.x++;
for(unsigned n = 0; n < 34; n++) { for(unsigned n = 0; n < 34; n++) {
TileItem &item = t.tile[!t.active][n]; auto tile = oam_tile[n];
if(item.tile == 0xffff) break; if(tile.x == 0xffff) break;
int px = x - sclip<9>(item.x); int px = x - sclip<9>(tile.x);
if(px & ~7) continue; if(px & ~7) continue;
uint16 addr = (item.tile << 5) + ((item.y & 7) * 2); unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px);
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 color; unsigned color;
color = ((bool)(d0 & mask)) << 0; color = ((bool)(tile.d0 & mask)) << 0;
color |= ((bool)(d1 & mask)) << 1; color |= ((bool)(tile.d1 & mask)) << 1;
color |= ((bool)(d2 & mask)) << 2; color |= ((bool)(tile.d2 & mask)) << 2;
color |= ((bool)(d3 & mask)) << 3; color |= ((bool)(tile.d3 & mask)) << 3;
if(color) { if(color) {
color += item.palette;
if(regs.main_enabled) { if(regs.main_enabled) {
output.main.palette = color; output.main.palette = tile.palette + color;
output.main.priority = priority_table[item.priority]; output.main.priority = priority_table[tile.priority];
} }
if(regs.sub_enabled) { if(regs.sub_enabled) {
output.sub.palette = color; output.sub.palette = tile.palette + color;
output.sub.priority = priority_table[item.priority]; 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() { void sPPU::Sprite::reset() {
for(unsigned i = 0; i < 128; i++) { for(unsigned i = 0; i < 128; i++) {
list[i].x = 0; list[i].x = 0;
@ -172,7 +171,6 @@ void sPPU::Sprite::reset() {
t.x = 0; t.x = 0;
t.y = 0; t.y = 0;
t.active_sprite = 0;
t.item_count = 0; t.item_count = 0;
t.tile_count = 0; t.tile_count = 0;
@ -181,11 +179,13 @@ void sPPU::Sprite::reset() {
memset(t.item[n], 0, 32); memset(t.item[n], 0, 32);
for(unsigned i = 0; i < 34; i++) { for(unsigned i = 0; i < 34; i++) {
t.tile[n][i].x = 0; t.tile[n][i].x = 0;
t.tile[n][i].y = 0;
t.tile[n][i].priority = 0; t.tile[n][i].priority = 0;
t.tile[n][i].palette = 0; t.tile[n][i].palette = 0;
t.tile[n][i].tile = 0;
t.tile[n][i].hflip = 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;
} }
} }

View File

@ -18,18 +18,16 @@ public:
struct TileItem { struct TileItem {
uint16 x; uint16 x;
uint16 y;
uint16 priority; uint16 priority;
uint16 palette; uint16 palette;
uint16 tile;
bool hflip; bool hflip;
uint8 d0, d1, d2, d3;
}; };
struct State { struct State {
unsigned x; unsigned x;
unsigned y; unsigned y;
unsigned active_sprite;
unsigned item_count; unsigned item_count;
unsigned tile_count; unsigned tile_count;
@ -72,12 +70,12 @@ public:
void frame(); void frame();
void scanline(); void scanline();
void run(); void run();
void tilefetch();
void reset(); void reset();
void serialize(serializer&); void serialize(serializer&);
Sprite(sPPU &self); Sprite(sPPU &self);
private: private:
bool on_scanline(); bool on_scanline(SpriteItem&);
void load_tiles();
}; };

View File

@ -1,4 +1,4 @@
static const char bsnesVersion[] = "067.03"; static const char bsnesVersion[] = "067.04";
static const char bsnesTitle[] = "bsnes"; static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSerializerVersion = 12; static const unsigned bsnesSerializerVersion = 12;