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;
}
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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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&);
};

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 unsigned bsnesSerializerVersion = 12;