Update to bsnes v063r11 release.

Writing to SETINI will update video mode priorities for EXTBG mode.
Merged pixel output { main, sub { valid, priority } } into just
priority. A priority of zero is considered invalid now.
Merged pixel output { main, sub { palette_index, palette_number } }
into just palette with the tiledata bits for direct color mode at
d8-d10.
This cuts a lot of copying and extra comparisons out of the final
screen rendering pass, though it doesn't really help speed.
Output is always 512x448 now. Having trouble deciding on how to do
video for that, but I'll post more on that later.
Really need to figure out how offset-per-tile fetches in regards to
lores v hires and SC size, tile size and wrapping.
For now, I simplified it to constants; whereas the scanline-renderer
uses the BG3 settings.
I also made it not perform OPT lookup on BG3 and BG4 anymore. Skips a
pointless trickery of setting the OPT valid bit to zero for BG3,BG4
and is faster.
Forgot an overscan check in sprite drawing, should draw sprites
properly to V=225-239 now.
Made the mode7 variable names more consistent.
This commit is contained in:
byuu 2010-04-09 16:00:03 +00:00
parent c33f70a8c6
commit 35fdb71f3d
16 changed files with 264 additions and 306 deletions

Binary file not shown.

BIN
bsnes.exe Normal file

Binary file not shown.

View File

@ -13,7 +13,7 @@ objects :=
# link += -lgcov
# profile-guided optimization
flags += -fprofile-use
# flags += -fprofile-use
# platform
ifeq ($(platform),x)

View File

@ -75,7 +75,6 @@ void sCPU::mmio_w4200(uint8 data) {
//WRIO
void sCPU::mmio_w4201(uint8 data) {
scheduler.sync_cpuppu();
if((status.pio & 0x80) && !(data & 0x80)) {
ppu.latch_counters();
}

View File

@ -66,14 +66,7 @@ public:
unsigned frames_executed;
} status;
//PPU1 version number
//* 1 is known
//* reported by $213e
uint8 ppu1_version;
//PPU2 version number
//* 1 and 3 are known
//* reported by $213f
uint8 ppu2_version;
virtual bool interlace() const = 0;

View File

@ -4,12 +4,12 @@
void sPPU::Background::scanline() {
if(self.vcounter() == 1) {
regs.mosaic_y = 1;
regs.mosaic_countdown = 0;
state.mosaic_y = 1;
state.mosaic_countdown = 0;
} else {
if(!regs.mosaic || !regs.mosaic_countdown) regs.mosaic_y = self.vcounter();
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic + 1;
regs.mosaic_countdown--;
if(!regs.mosaic || !state.mosaic_countdown) state.mosaic_y = self.vcounter();
if(!state.mosaic_countdown) state.mosaic_countdown = regs.mosaic + 1;
state.mosaic_countdown--;
}
state.x = 0;
@ -19,8 +19,8 @@ void sPPU::Background::run() {
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
if((self.hcounter() & 2) == 0) {
output.main.valid = false;
output.sub.valid = false;
output.main.priority = 0;
output.sub.priority = 0;
} else if(hires == false) {
return;
}
@ -29,7 +29,7 @@ void sPPU::Background::run() {
if(regs.main_enabled == false && regs.sub_enabled == false) return;
unsigned x = state.x++;
unsigned y = regs.mosaic_y;
unsigned y = state.mosaic_y;
if(regs.mode == Mode::Mode7) return run_mode7(x, y);
unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
@ -63,7 +63,10 @@ void sPPU::Background::run() {
unsigned hoffset = hscroll + mosaic_table[regs.mosaic][x];
unsigned voffset = vscroll + y;
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
bool offset_per_tile = (self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6);
if(id != ID::BG1 && id != ID::BG2) offset_per_tile = false;
if(offset_per_tile) {
uint16 opt_x = (x + (hscroll & 7));
//tile 0 is unaffected by offset-per-tile mode
@ -71,14 +74,9 @@ void sPPU::Background::run() {
uint16 hval; {
unsigned px = (opt_x - 8) + (self.bg3.regs.hoffset & ~7);
unsigned py = self.bg3.regs.voffset;
unsigned tx = (px & mask_x) >> tile_width;
unsigned ty = (py & mask_y) >> tile_height;
unsigned tx = (px & (width - 1)) >> tile_width;
unsigned ty = (py & (width - 1)) >> tile_height;
uint16 pos = ((ty & 0x1f) << 5) + (tx & 0x1f);
if(ty & 0x20) pos += screen_y;
if(tx & 0x20) pos += screen_x;
uint16 addr = self.bg3.regs.screen_addr + (pos << 1);
hval = memory::vram[addr + 0] + (memory::vram[addr + 1] << 8);
}
@ -86,19 +84,14 @@ void sPPU::Background::run() {
uint16 vval; if(self.regs.bgmode != 4) {
unsigned px = (opt_x - 8) + (self.bg3.regs.hoffset & ~7);
unsigned py = self.bg3.regs.voffset + 8;
unsigned tx = (px & mask_x) >> tile_width;
unsigned ty = (py & mask_y) >> tile_height;
unsigned tx = (px & (width - 1)) >> tile_width;
unsigned ty = (py & (width - 1)) >> tile_height;
uint16 pos = ((ty & 0x1f) << 5) + (tx & 0x1f);
if(ty & 0x20) pos += screen_y;
if(tx & 0x20) pos += screen_x;
uint16 addr = self.bg3.regs.screen_addr + (pos << 1);
vval = memory::vram[addr + 0] + (memory::vram[addr + 1] << 8);
}
unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : id == ID::BG2 ? 0x4000 : 0x0000);
unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : 0x4000);
if(self.regs.bgmode == 4) {
if(hval & opt_valid_bit) {
@ -125,11 +118,9 @@ void sPPU::Background::run() {
unsigned tile_number; {
unsigned tx = hoffset >> tile_width;
unsigned ty = voffset >> tile_height;
uint16 pos = ((ty & 0x1f) << 5) + (tx & 0x1f);
if(ty & 0x20) pos += screen_y;
if(tx & 0x20) pos += screen_x;
uint16 addr = regs.screen_addr + (pos << 1);
tile_number = memory::vram[addr + 0] + (memory::vram[addr + 1] << 8);
}
@ -149,38 +140,30 @@ void sPPU::Background::run() {
if(mirror_y) voffset ^= 7;
if(mirror_x) hoffset ^= 7;
unsigned color = get_color(hoffset, voffset, tile_number);
uint8 color = get_color(hoffset, voffset, tile_number);
if(color == 0) return;
color += palette_index;
if(hires == false) {
if(regs.main_enabled) {
output.main.valid = true;
output.main.palette = color;
output.main.palette_number = palette_number;
output.main.palette = color | (palette_number << 8);
output.main.priority = priority;
}
if(regs.sub_enabled) {
output.sub.valid = true;
output.sub.palette = color;
output.sub.palette_number = palette_number;
output.sub.palette = color | (palette_number << 8);
output.sub.priority = priority;
}
} else {
if(x & 1) {
if(regs.main_enabled) {
output.main.valid = true;
output.main.palette = color;
output.main.palette_number = palette_number;
output.main.palette = color | (palette_number << 8);
output.main.priority = priority;
}
} else {
if(regs.sub_enabled) {
output.sub.valid = true;
output.sub.palette = color;
output.sub.palette_number = palette_number;
output.sub.palette = color | (palette_number << 8);
output.sub.priority = priority;
}
}
@ -241,12 +224,12 @@ unsigned sPPU::Background::get_color(unsigned x, unsigned y, uint16 offset) {
void sPPU::Background::reset() {
state.x = 0;
state.mosaic_y = 0;
state.mosaic_countdown = 0;
regs.tiledata_addr = 0;
regs.screen_addr = 0;
regs.screen_size = 0;
regs.mosaic = 0;
regs.mosaic_y = 0;
regs.mosaic_countdown = 0;
regs.tile_size = 0;
regs.mode = 0;
regs.priority0 = 0;
@ -255,13 +238,9 @@ void sPPU::Background::reset() {
regs.sub_enabled = 0;
regs.hoffset = 0;
regs.voffset = 0;
output.main.valid = 0;
output.main.palette = 0;
output.main.palette_number = 0;
output.main.priority = 0;
output.sub.valid = 0;
output.sub.palette = 0;
output.sub.palette_number = 0;
output.sub.priority = 0;
}
@ -272,20 +251,6 @@ sPPU::Background::Background(sPPU &self, unsigned id) : self(self), id(id) {
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
}
}
regs.tiledata_addr = 0x0000;
regs.screen_addr = 0x0000;
regs.screen_size = ScreenSize::Size32x32;
regs.mosaic = 0;
regs.mosaic_y = 0;
regs.tile_size = TileSize::Size8x8;
regs.mode = Mode::BPP2;
regs.priority0 = 0;
regs.priority1 = 0;
regs.main_enabled = false;
regs.sub_enabled = false;
}
uint16 sPPU::Background::mosaic_table[16][4096];

View File

@ -10,6 +10,8 @@ public:
struct {
unsigned x;
unsigned mosaic_y;
unsigned mosaic_countdown;
} state;
struct {
@ -17,8 +19,6 @@ public:
unsigned screen_addr;
unsigned screen_size;
unsigned mosaic;
unsigned mosaic_y;
unsigned mosaic_countdown;
bool tile_size;
unsigned mode;
@ -34,10 +34,8 @@ public:
struct {
struct {
bool valid;
uint8 palette;
uint8 palette_number;
uint8 priority;
unsigned priority; //0 = none (transparent)
unsigned palette; //(direct_color_bits << 8) + index
} main, sub;
} output;

View File

@ -13,8 +13,8 @@ void sPPU::Background::run_mode7(unsigned x, unsigned y) {
signed cx = sclip<13>(self.regs.m7x);
signed cy = sclip<13>(self.regs.m7y);
signed hofs = sclip<13>(self.regs.m7hofs);
signed vofs = sclip<13>(self.regs.m7vofs);
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
signed voffset = sclip<13>(self.regs.mode7_voffset);
if(self.regs.mode7_hflip) x = 255 - x;
if(self.regs.mode7_vflip) y = 255 - y;
@ -29,8 +29,8 @@ void sPPU::Background::run_mode7(unsigned x, unsigned y) {
mosaic_y = mosaic_table[self.bg1.regs.mosaic][y]; //BG2 vertical mosaic uses BG1 mosaic size
}
signed psx = ((a * clip(hofs - cx)) & ~63) + ((b * clip(vofs - cy)) & ~63) + ((b * mosaic_y) & ~63) + (cx << 8);
signed psy = ((c * clip(hofs - cx)) & ~63) + ((d * clip(vofs - cy)) & ~63) + ((d * mosaic_y) & ~63) + (cy << 8);
signed psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * mosaic_y) & ~63) + (cx << 8);
signed psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * mosaic_y) & ~63) + (cy << 8);
signed px = psx + (a * mosaic_x);
signed py = psy + (c * mosaic_x);
@ -87,16 +87,12 @@ void sPPU::Background::run_mode7(unsigned x, unsigned y) {
if(palette == 0) return;
if(regs.main_enabled) {
output.main.valid = true;
output.main.palette = palette;
output.main.palette_number = 0;
output.main.priority = priority;
}
if(regs.sub_enabled) {
output.sub.valid = true;
output.sub.palette = palette;
output.sub.palette_number = 0;
output.sub.priority = priority;
}
}

View File

@ -1,6 +1,7 @@
#ifdef SPPU_CPP
void sPPU::latch_counters() {
scheduler.sync_cpuppu();
regs.hcounter = hdot();
regs.vcounter = vcounter();
regs.counters_latched = true;
@ -51,6 +52,7 @@ void sPPU::cgram_write(unsigned addr, uint8 data) {
}
bool sPPU::interlace() const {
//return true;
return display.interlace;
}
@ -62,59 +64,7 @@ bool sPPU::hires() const {
return true;
}
//INIDISP
void sPPU::mmio_w2100(uint8 data) {
if(regs.display_disabled && vcounter() == 225) oam.address_reset();
regs.display_disabled = data & 0x80;
regs.display_brightness = data & 0x0f;
}
//OBSEL
void sPPU::mmio_w2101(uint8 data) {
oam.regs.base_size = (data >> 5) & 7;
oam.regs.nameselect = (data >> 3) & 3;
oam.regs.tiledata_addr = (data & 3) << 14;
}
//OAMADDL
void sPPU::mmio_w2102(uint8 data) {
regs.oam_baseaddr &= 0x0100;
regs.oam_baseaddr |= (data << 0);
oam.address_reset();
}
//OAMADDH
void sPPU::mmio_w2103(uint8 data) {
regs.oam_priority = data & 0x80;
regs.oam_baseaddr &= 0x00ff;
regs.oam_baseaddr |= (data & 1) << 8;
oam.address_reset();
}
//OAMDATA
void sPPU::mmio_w2104(uint8 data) {
if(regs.oam_addr & 0x0200) {
oam_write(regs.oam_addr, data);
} else if((regs.oam_addr & 1) == 0) {
regs.oam_latchdata = data;
} else {
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
oam_write((regs.oam_addr & ~1) + 1, data);
}
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
oam.regs.first_sprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
}
//BGMODE
void sPPU::mmio_w2105(uint8 data) {
bg4.regs.tile_size = (data & 0x80);
bg3.regs.tile_size = (data & 0x40);
bg2.regs.tile_size = (data & 0x20);
bg1.regs.tile_size = (data & 0x10);
regs.bg3_priority = (data & 0x08);
regs.bgmode = (data & 0x07);
void sPPU::mmio_update_video_mode() {
switch(regs.bgmode) {
case 0: {
bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11;
@ -212,6 +162,61 @@ void sPPU::mmio_w2105(uint8 data) {
}
}
//INIDISP
void sPPU::mmio_w2100(uint8 data) {
if(regs.display_disabled && vcounter() == 225) oam.address_reset();
regs.display_disabled = data & 0x80;
regs.display_brightness = data & 0x0f;
}
//OBSEL
void sPPU::mmio_w2101(uint8 data) {
oam.regs.base_size = (data >> 5) & 7;
oam.regs.nameselect = (data >> 3) & 3;
oam.regs.tiledata_addr = (data & 3) << 14;
}
//OAMADDL
void sPPU::mmio_w2102(uint8 data) {
regs.oam_baseaddr &= 0x0100;
regs.oam_baseaddr |= (data << 0);
oam.address_reset();
}
//OAMADDH
void sPPU::mmio_w2103(uint8 data) {
regs.oam_priority = data & 0x80;
regs.oam_baseaddr &= 0x00ff;
regs.oam_baseaddr |= (data & 1) << 8;
oam.address_reset();
}
//OAMDATA
void sPPU::mmio_w2104(uint8 data) {
if(regs.oam_addr & 0x0200) {
oam_write(regs.oam_addr, data);
} else if((regs.oam_addr & 1) == 0) {
regs.oam_latchdata = data;
} else {
oam_write((regs.oam_addr & ~1) + 0, regs.oam_latchdata);
oam_write((regs.oam_addr & ~1) + 1, data);
}
regs.oam_addr = (regs.oam_addr + 1) & 0x03ff;
oam.regs.first_sprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
}
//BGMODE
void sPPU::mmio_w2105(uint8 data) {
bg4.regs.tile_size = (data & 0x80);
bg3.regs.tile_size = (data & 0x40);
bg2.regs.tile_size = (data & 0x20);
bg1.regs.tile_size = (data & 0x10);
regs.bg3_priority = (data & 0x08);
regs.bgmode = (data & 0x07);
mmio_update_video_mode();
}
//MOSAIC
void sPPU::mmio_w2106(uint8 data) {
unsigned mosaic_size = (data >> 4) & 15;
@ -259,8 +264,8 @@ void sPPU::mmio_w210c(uint8 data) {
//BG1HOFS
void sPPU::mmio_w210d(uint8 data) {
regs.m7hofs = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.mode7_hoffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7);
regs.bgofs_latchdata = data;
@ -268,8 +273,8 @@ void sPPU::mmio_w210d(uint8 data) {
//BG1VOFS
void sPPU::mmio_w210e(uint8 data) {
regs.m7vofs = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.mode7_voffset = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_latchdata = data;
@ -364,38 +369,38 @@ void sPPU::mmio_w211a(uint8 data) {
//M7A
void sPPU::mmio_w211b(uint8 data) {
regs.m7a = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7a = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//M7B
void sPPU::mmio_w211c(uint8 data) {
regs.m7b = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7b = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//M7C
void sPPU::mmio_w211d(uint8 data) {
regs.m7c = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7c = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//M7D
void sPPU::mmio_w211e(uint8 data) {
regs.m7d = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7d = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//M7X
void sPPU::mmio_w211f(uint8 data) {
regs.m7x = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7x = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//M7Y
void sPPU::mmio_w2120(uint8 data) {
regs.m7y = (data << 8) | regs.m7_latchdata;
regs.m7_latchdata = data;
regs.m7y = (data << 8) | regs.mode7_latchdata;
regs.mode7_latchdata = data;
}
//CGADD
@ -545,7 +550,6 @@ void sPPU::mmio_w2132(uint8 data) {
if(data & 0x80) screen.regs.color_b = data & 0x1f;
if(data & 0x40) screen.regs.color_g = data & 0x1f;
if(data & 0x20) screen.regs.color_r = data & 0x1f;
screen.regs.color_rgb = (screen.regs.color_b << 10) + (screen.regs.color_g << 5) + screen.regs.color_r;
}
//SETINI
@ -555,6 +559,7 @@ void sPPU::mmio_w2133(uint8 data) {
regs.overscan = data & 0x04;
oam.regs.interlace = data & 0x02;
regs.interlace = data & 0x01;
mmio_update_video_mode();
}
//MPYL
@ -689,7 +694,7 @@ void sPPU::mmio_reset() {
regs.oam_latchdata = 0x00;
regs.cgram_latchdata = 0x00;
regs.bgofs_latchdata = 0x00;
regs.m7_latchdata = 0x00;
regs.mode7_latchdata = 0x00;
regs.counters_latched = false;
regs.latch_hcounter = 0;
regs.latch_vcounter = 0;
@ -709,10 +714,10 @@ void sPPU::mmio_reset() {
regs.bgmode = 0;
//$210d BG1HOFS
regs.m7hofs = 0x0000;
regs.mode7_hoffset = 0x0000;
//$210e BG1VOFS
regs.m7vofs = 0x0000;
regs.mode7_voffset = 0x0000;
//$2115 VMAIN
regs.vram_incmode = 1;

View File

@ -6,7 +6,7 @@ struct {
uint8 oam_latchdata;
uint8 cgram_latchdata;
uint8 bgofs_latchdata;
uint8 m7_latchdata;
uint8 mode7_latchdata;
bool counters_latched;
bool latch_hcounter;
bool latch_vcounter;
@ -26,10 +26,10 @@ struct {
uint8 bgmode;
//$210d BG1HOFS
uint16 m7hofs;
uint16 mode7_hoffset;
//$210e BG1VOFS
uint16 m7vofs;
uint16 mode7_voffset;
//$2115 VMAIN
bool vram_incmode;
@ -95,70 +95,72 @@ bool interlace() const;
bool overscan() const;
bool hires() const;
void mmio_w2100(uint8);
void mmio_w2101(uint8);
void mmio_w2102(uint8);
void mmio_w2103(uint8);
void mmio_w2104(uint8);
void mmio_w2105(uint8);
void mmio_w2106(uint8);
void mmio_w2107(uint8);
void mmio_w2108(uint8);
void mmio_w2109(uint8);
void mmio_w210a(uint8);
void mmio_w210b(uint8);
void mmio_w210c(uint8);
void mmio_w210d(uint8);
void mmio_w210e(uint8);
void mmio_w210f(uint8);
void mmio_w2110(uint8);
void mmio_w2111(uint8);
void mmio_w2112(uint8);
void mmio_w2113(uint8);
void mmio_w2114(uint8);
void mmio_w2115(uint8);
void mmio_w2116(uint8);
void mmio_w2117(uint8);
void mmio_w2118(uint8);
void mmio_w2119(uint8);
void mmio_w211a(uint8);
void mmio_w211b(uint8);
void mmio_w211c(uint8);
void mmio_w211d(uint8);
void mmio_w211e(uint8);
void mmio_w211f(uint8);
void mmio_w2120(uint8);
void mmio_w2121(uint8);
void mmio_w2122(uint8);
void mmio_w2123(uint8);
void mmio_w2124(uint8);
void mmio_w2125(uint8);
void mmio_w2126(uint8);
void mmio_w2127(uint8);
void mmio_w2128(uint8);
void mmio_w2129(uint8);
void mmio_w212a(uint8);
void mmio_w212b(uint8);
void mmio_w212c(uint8);
void mmio_w212d(uint8);
void mmio_w212e(uint8);
void mmio_w212f(uint8);
void mmio_w2130(uint8);
void mmio_w2131(uint8);
void mmio_w2132(uint8);
void mmio_w2133(uint8);
uint8 mmio_r2134();
uint8 mmio_r2135();
uint8 mmio_r2136();
uint8 mmio_r2137();
uint8 mmio_r2138();
uint8 mmio_r2139();
uint8 mmio_r213a();
uint8 mmio_r213b();
uint8 mmio_r213c();
uint8 mmio_r213d();
uint8 mmio_r213e();
uint8 mmio_r213f();
void mmio_update_video_mode();
void mmio_w2100(uint8); //INIDISP
void mmio_w2101(uint8); //OBSEL
void mmio_w2102(uint8); //OAMADDL
void mmio_w2103(uint8); //OAMADDH
void mmio_w2104(uint8); //OAMDATA
void mmio_w2105(uint8); //BGMODE
void mmio_w2106(uint8); //MOSAIC
void mmio_w2107(uint8); //BG1SC
void mmio_w2108(uint8); //BG2SC
void mmio_w2109(uint8); //BG3SC
void mmio_w210a(uint8); //BG4SC
void mmio_w210b(uint8); //BG12NBA
void mmio_w210c(uint8); //BG34NBA
void mmio_w210d(uint8); //BG1HOFS
void mmio_w210e(uint8); //BG1VOFS
void mmio_w210f(uint8); //BG2HOFS
void mmio_w2110(uint8); //BG2VOFS
void mmio_w2111(uint8); //BG3HOFS
void mmio_w2112(uint8); //BG3VOFS
void mmio_w2113(uint8); //BG4HOFS
void mmio_w2114(uint8); //BG4VOFS
void mmio_w2115(uint8); //VMAIN
void mmio_w2116(uint8); //VMADDL
void mmio_w2117(uint8); //VMADDH
void mmio_w2118(uint8); //VMDATAL
void mmio_w2119(uint8); //VMDATAH
void mmio_w211a(uint8); //M7SEL
void mmio_w211b(uint8); //M7A
void mmio_w211c(uint8); //M7B
void mmio_w211d(uint8); //M7C
void mmio_w211e(uint8); //M7D
void mmio_w211f(uint8); //M7X
void mmio_w2120(uint8); //M7Y
void mmio_w2121(uint8); //CGADD
void mmio_w2122(uint8); //CGDATA
void mmio_w2123(uint8); //W12SEL
void mmio_w2124(uint8); //W34SEL
void mmio_w2125(uint8); //WOBJSEL
void mmio_w2126(uint8); //WH0
void mmio_w2127(uint8); //WH1
void mmio_w2128(uint8); //WH2
void mmio_w2129(uint8); //WH3
void mmio_w212a(uint8); //WBGLOG
void mmio_w212b(uint8); //WOBJLOG
void mmio_w212c(uint8); //TM
void mmio_w212d(uint8); //TS
void mmio_w212e(uint8); //TMW
void mmio_w212f(uint8); //TSW
void mmio_w2130(uint8); //CGWSEL
void mmio_w2131(uint8); //CGADDSUB
void mmio_w2132(uint8); //COLDATA
void mmio_w2133(uint8); //SETINI
uint8 mmio_r2134(); //MPYL
uint8 mmio_r2135(); //MPYM
uint8 mmio_r2136(); //MPYH
uint8 mmio_r2137(); //SLHV
uint8 mmio_r2138(); //OAMDATAREAD
uint8 mmio_r2139(); //VMDATALREAD
uint8 mmio_r213a(); //VMDATAHREAD
uint8 mmio_r213b(); //CGDATAREAD
uint8 mmio_r213c(); //OPHCT
uint8 mmio_r213d(); //OPVCT
uint8 mmio_r213e(); //STAT77
uint8 mmio_r213f(); //STAT78
void mmio_reset();
uint8 mmio_read(unsigned addr);

View File

@ -1,8 +1,13 @@
#ifdef SPPU_CPP
void sPPU::Screen::scanline() {
output = self.output + self.vcounter() * 1024;
if(self.display.interlace && self.field() == 1) output += 512;
if(self.display.interlace == false || self.field() == 0) {
output = self.output + self.vcounter() * 1024;
fade = output + 512;
} else {
output = self.output + self.vcounter() * 1024 + 512;
fade = output - 512;
}
}
void sPPU::Screen::run() {
@ -17,6 +22,9 @@ void sPPU::Screen::run() {
color = get_pixel(false);
*output++ = color;
}
*fade++ = light_table[10][*fade];
*fade++ = light_table[10][*fade];
}
uint16 sPPU::Screen::get_pixel(bool swap) {
@ -31,31 +39,31 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
unsigned color_main;
unsigned source_main;
if(self.bg1.output.main.valid) {
if(self.bg1.output.main.priority) {
priority_main = self.bg1.output.main.priority;
if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) {
color_main = get_direct_color(self.bg1.output.main.palette, self.bg1.output.main.palette_number);
color_main = get_direct_color(self.bg1.output.main.palette);
} else {
color_main = get_color(self.bg1.output.main.palette);
}
source_main = BG1;
}
if(self.bg2.output.main.valid && self.bg2.output.main.priority > priority_main) {
if(self.bg2.output.main.priority > priority_main) {
priority_main = self.bg2.output.main.priority;
color_main = get_color(self.bg2.output.main.palette);
source_main = BG2;
}
if(self.bg3.output.main.valid && self.bg3.output.main.priority > priority_main) {
if(self.bg3.output.main.priority > priority_main) {
priority_main = self.bg3.output.main.priority;
color_main = get_color(self.bg3.output.main.palette);
source_main = BG3;
}
if(self.bg4.output.main.valid && self.bg4.output.main.priority > priority_main) {
if(self.bg4.output.main.priority > priority_main) {
priority_main = self.bg4.output.main.priority;
color_main = get_color(self.bg4.output.main.palette);
source_main = BG4;
}
if(self.oam.output.main.valid && self.oam.output.main.priority > priority_main) {
if(self.oam.output.main.priority > priority_main) {
priority_main = self.oam.output.main.priority;
color_main = get_color(self.oam.output.main.palette);
source_main = OAM;
@ -73,31 +81,31 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
unsigned color_sub;
unsigned source_sub;
if(self.bg1.output.sub.valid) {
if(self.bg1.output.sub.priority) {
priority_sub = self.bg1.output.sub.priority;
if(regs.direct_color && (self.regs.bgmode == 3 || self.regs.bgmode == 4 || self.regs.bgmode == 7)) {
color_sub = get_direct_color(self.bg1.output.sub.palette, self.bg1.output.sub.palette_number);
color_sub = get_direct_color(self.bg1.output.sub.palette);
} else {
color_sub = get_color(self.bg1.output.sub.palette);
}
source_sub = BG1;
}
if(self.bg2.output.sub.valid && self.bg2.output.sub.priority > priority_sub) {
if(self.bg2.output.sub.priority > priority_sub) {
priority_sub = self.bg2.output.sub.priority;
color_sub = get_color(self.bg2.output.sub.palette);
source_sub = BG2;
}
if(self.bg3.output.sub.valid && self.bg3.output.sub.priority > priority_sub) {
if(self.bg3.output.sub.priority > priority_sub) {
priority_sub = self.bg3.output.sub.priority;
color_sub = get_color(self.bg3.output.sub.palette);
source_sub = BG3;
}
if(self.bg4.output.sub.valid && self.bg4.output.sub.priority > priority_sub) {
if(self.bg4.output.sub.priority > priority_sub) {
priority_sub = self.bg4.output.sub.priority;
color_sub = get_color(self.bg4.output.sub.palette);
source_sub = BG4;
}
if(self.oam.output.sub.valid && self.oam.output.sub.priority > priority_sub) {
if(self.oam.output.sub.priority > priority_sub) {
priority_sub = self.oam.output.sub.priority;
color_sub = get_color(self.oam.output.sub.palette);
source_sub = OAM;
@ -106,7 +114,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
if(self.regs.bgmode == 5 || self.regs.bgmode == 6) {
color_sub = get_color(0);
} else {
color_sub = regs.color_rgb;
color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0);
}
source_sub = BACK;
}
@ -120,7 +128,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
uint16 output;
if(!regs.addsub_mode) {
source_sub = BACK;
color_sub = regs.color_rgb;
color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0);
}
if(self.window.output.main.color_enable == false) {
@ -134,8 +142,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
if(!color_exempt && color_enable[source_main] && self.window.output.sub.color_enable) {
bool halve = false;
if(regs.color_halve && self.window.output.main.color_enable) {
if(regs.addsub_mode && source_sub == BACK);
else halve = true;
if(!regs.addsub_mode || source_sub != BACK) halve = true;
}
output = addsub(color_main, color_sub, halve);
} else {
@ -175,13 +182,12 @@ uint16 sPPU::Screen::get_color(uint8 n) {
return memory::cgram[(n << 1) + 0] + (memory::cgram[(n << 1) + 1] << 8);
}
//color = BBBGGGRR (from tiledata)
//palette = 00000bgr (from tilemap)
//result = 0BBb00GGGg0RRRr0
uint16 sPPU::Screen::get_direct_color(uint8 color, uint8 palette) {
return ((color & 7) << 2) | ((palette & 1) << 1)
| (((color >> 3) & 7) << 7) | (((palette >> 1) & 1) << 6)
| ((color >> 6) << 13) | ((palette >> 2) << 12);
uint16 sPPU::Screen::get_direct_color(unsigned n) {
//input = 00000bgrBBGGGRRR (BGR = palette index [tiledata], bgr = palette number [tilemap])
//output = 0BBb00GGGg0RRRr0
return ((n << 7) & 0x6000) + ((n << 2) & 0x1000)
+ ((n << 4) & 0x0380) + ((n >> 3) & 0x0040)
+ ((n << 2) & 0x001c) + ((n >> 7) & 0x0002);
}
void sPPU::Screen::reset() {
@ -198,7 +204,6 @@ void sPPU::Screen::reset() {
regs.color_r = 0;
regs.color_g = 0;
regs.color_b = 0;
regs.color_rgb = 0;
}
sPPU::Screen::Screen(sPPU &self) : self(self) {

View File

@ -2,6 +2,7 @@ class Screen {
public:
sPPU &self;
uint16 *output;
uint16 *fade;
struct {
bool addsub_mode;
@ -19,7 +20,6 @@ public:
uint8 color_b;
uint8 color_g;
uint8 color_r;
uint16 color_rgb;
} regs;
void scanline();
@ -33,5 +33,5 @@ private:
uint16 get_pixel(bool swap);
uint16 addsub(unsigned x, unsigned y, bool halve);
uint16 get_color(uint8 n);
uint16 get_direct_color(uint8 color, uint8 palette);
uint16 get_direct_color(unsigned n);
};

View File

@ -15,7 +15,7 @@ void sPPU::Sprite::scanline() {
state.y = self.vcounter();
if(state.y == 225 && self.regs.display_disabled == false) address_reset();
if(state.y < 1 || state.y > 224) return;
if(state.y < 1 || state.y > (!self.regs.overscan ? 224 : 239)) return;
const uint8 *tableA = memory::oam.data();
const uint8 *tableB = memory::oam.data() + 512;
@ -95,8 +95,8 @@ void sPPU::Sprite::scanline() {
}
void sPPU::Sprite::run() {
output.main.valid = false;
output.sub.valid = false;
output.main.priority = 0;
output.sub.priority = 0;
unsigned x = state.x++;
@ -104,13 +104,11 @@ void sPPU::Sprite::run() {
unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
if(regs.main_enabled) {
output.main.valid = true;
output.main.palette = state.output_palette[x];
output.main.priority = priority_table[state.output_priority[x]];
}
if(regs.sub_enabled) {
output.sub.valid = true;
output.sub.palette = state.output_palette[x];
output.sub.priority = priority_table[state.output_priority[x]];
}
@ -251,10 +249,8 @@ void sPPU::Sprite::reset() {
state.tile_list[i].hflip = 0;
}
state.active_sprite = 0;
output.main.valid = 0;
output.main.palette = 0;
output.main.priority = 0;
output.sub.valid = 0;
output.sub.palette = 0;
output.sub.priority = 0;
}

View File

@ -2,6 +2,41 @@ class Sprite {
public:
sPPU &self;
struct TileItem {
uint16 x;
uint16 y;
uint16 priority;
uint16 palette;
uint16 tile;
bool hflip;
};
struct SpriteItem {
uint8 width;
uint8 height;
uint16 x;
uint16 y;
uint8 character;
bool nameselect;
bool vflip;
bool hflip;
uint8 palette;
uint8 priority;
} list[128];
struct State {
unsigned x;
unsigned y;
unsigned item_count;
unsigned tile_count;
uint8 output_palette[256];
uint8 output_priority[256];
uint8 item_list[32];
TileItem tile_list[34];
unsigned active_sprite;
} state;
struct {
bool main_enabled;
bool sub_enabled;
@ -21,46 +56,10 @@ public:
bool range_over;
} regs;
struct SpriteItem {
uint8 width;
uint8 height;
uint16 x;
uint16 y;
uint8 character;
bool nameselect;
bool vflip;
bool hflip;
uint8 palette;
uint8 priority;
} list[128];
struct TileItem {
uint16 x;
uint16 y;
uint16 priority;
uint16 palette;
uint16 tile;
bool hflip;
};
struct State {
unsigned x;
unsigned y;
unsigned item_count;
unsigned tile_count;
uint8 output_palette[256];
uint8 output_priority[256];
uint8 item_list[32];
TileItem tile_list[34];
unsigned active_sprite;
} state;
struct {
struct {
bool valid;
uint8 palette;
uint8 priority;
unsigned priority; //0 = none (transparent)
unsigned palette; //index
} main, sub;
} output;

View File

@ -13,8 +13,8 @@ void sPPU::Window::run() {
regs.bg1_two_enable, regs.bg1_two_invert,
regs.bg1_mask, regs.bg1_main_enable, regs.bg1_sub_enable
);
if(main) self.bg1.output.main.valid = false;
if(sub) self.bg1.output.sub.valid = false;
if(main) self.bg1.output.main.priority = 0;
if(sub) self.bg1.output.sub.priority = 0;
test(
main, sub,
@ -22,8 +22,8 @@ void sPPU::Window::run() {
regs.bg2_two_enable, regs.bg2_two_invert,
regs.bg2_mask, regs.bg2_main_enable, regs.bg2_sub_enable
);
if(main) self.bg2.output.main.valid = false;
if(sub) self.bg2.output.sub.valid = false;
if(main) self.bg2.output.main.priority = 0;
if(sub) self.bg2.output.sub.priority = 0;
test(
main, sub,
@ -31,8 +31,8 @@ void sPPU::Window::run() {
regs.bg3_two_enable, regs.bg3_two_invert,
regs.bg3_mask, regs.bg3_main_enable, regs.bg3_sub_enable
);
if(main) self.bg3.output.main.valid = false;
if(sub) self.bg3.output.sub.valid = false;
if(main) self.bg3.output.main.priority = 0;
if(sub) self.bg3.output.sub.priority = 0;
test(
main, sub,
@ -40,8 +40,8 @@ void sPPU::Window::run() {
regs.bg4_two_enable, regs.bg4_two_invert,
regs.bg4_mask, regs.bg4_main_enable, regs.bg4_sub_enable
);
if(main) self.bg4.output.main.valid = false;
if(sub) self.bg4.output.sub.valid = false;
if(main) self.bg4.output.main.priority = 0;
if(sub) self.bg4.output.sub.priority = 0;
test(
main, sub,
@ -49,8 +49,8 @@ void sPPU::Window::run() {
regs.oam_two_enable, regs.oam_two_invert,
regs.oam_mask, regs.oam_main_enable, regs.oam_sub_enable
);
if(main) self.oam.output.main.valid = false;
if(sub) self.oam.output.sub.valid = false;
if(main) self.oam.output.main.priority = 0;
if(sub) self.oam.output.sub.priority = 0;
test(
main, sub,

View File

@ -1,4 +1,4 @@
static const char bsnesVersion[] = "063.10";
static const char bsnesVersion[] = "063.11";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSerializerVersion = 9;