mirror of https://github.com/bsnes-emu/bsnes.git
Update to v068r12 release.
(there was no r11 release posted to the WIP thread) byuu says: This took ten hours of mind boggling insanity to pull off. It upgrades the S-PPU dot-based renderer to fetch one tile, and then output all of its pixels before fetching again. It sounds easy enough, but it's insanely difficult. I ended up taking one small shortcut, in that rather than fetch at -7, I fetch at the first instance where a tile is needed to plot to x=0. So if you have {-3 to +4 } as a tile, it fetches at -3. That won't work so well on hardware, if two BGs fetch at the same X offset, they won't have time. I have had no luck staggering the reads at BG1=-7, BG3=-5, etc. While I can shift and fetch just fine, what happens is that when a new tile is fetched in, that gives a new palette, priority, etc; and this ends up happening between two tiles which results in the right-most edges of the screen ending up with the wrong colors and such. Offset-per-tile is cheap as always. Although looking at it, I'm not sure how BG3 could pre-fetch, especially with the way one or two OPT modes can fetch two tiles. There's no magic in Hoffset caching yet, so the SMW1 pixel issue is still there. Mode 7 got a bugfix, it was off-by-one horizontally from the mosaic code. After re-designing the BG mosaic, I ended up needing a separate mosaic for Mode7, and in the process I fixed that bug. The obvious change is that the Chrono Trigger Mode7->Mode2 transition doesn't cause the pendulum to jump anymore. Windows were simplified just a tad. The range testing is shared for all modes now. Ironically, it's a bit slower, but I'll take less code over more speed for the accuracy core. Speaking of speed, because there's so much less calculations per pixel for BGs, performance for the entire emulator has gone up by 30% in the accuracy core. Pretty neat overall, I can maintain 60fps in all but, yeah you can guess can't you?
This commit is contained in:
parent
7df9157abd
commit
5b4702afc4
|
@ -1,6 +1,6 @@
|
||||||
include nall/Makefile
|
include nall/Makefile
|
||||||
snes := snes
|
snes := snes
|
||||||
profile := performance
|
profile := accuracy
|
||||||
ui := qt
|
ui := qt
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
|
|
|
@ -6,40 +6,27 @@ void PPU::Background::frame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Background::scanline() {
|
void PPU::Background::scanline() {
|
||||||
|
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||||
|
x = -8 << hires;
|
||||||
|
y = self.vcounter();
|
||||||
|
edge = 7 - (regs.hoffset & 7);
|
||||||
|
for(unsigned n = 0; n < 8; n++) data[n] = 0;
|
||||||
|
|
||||||
if(self.vcounter() == 1) {
|
if(self.vcounter() == 1) {
|
||||||
t.mosaic_vcounter = regs.mosaic + 1;
|
mosaic_vcounter = regs.mosaic + 1;
|
||||||
t.mosaic_y = 1;
|
mosaic_voffset = 1;
|
||||||
} else if(--t.mosaic_vcounter == 0) {
|
} else if(--mosaic_vcounter == 0) {
|
||||||
t.mosaic_vcounter = regs.mosaic + 1;
|
mosaic_vcounter = regs.mosaic + 1;
|
||||||
t.mosaic_y += regs.mosaic + 1;
|
mosaic_voffset += regs.mosaic + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
t.mosaic_x = 0;
|
mosaic_hcounter = 0;
|
||||||
t.mosaic_hcounter = regs.mosaic + 1;
|
mosaic_hoffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Background::run() {
|
void PPU::Background::get_tile() {
|
||||||
if(self.vcounter() == 0) return;
|
|
||||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||||
|
|
||||||
if((self.hcounter() & 2) == 0) {
|
|
||||||
output.main.priority = 0;
|
|
||||||
output.sub.priority = 0;
|
|
||||||
} else if(hires == false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(regs.mode == Mode::Inactive) return;
|
|
||||||
if(regs.main_enabled == false && regs.sub_enabled == false) return;
|
|
||||||
|
|
||||||
unsigned x = t.mosaic_x;
|
|
||||||
unsigned y = t.mosaic_y;
|
|
||||||
if(--t.mosaic_hcounter == 0) {
|
|
||||||
t.mosaic_hcounter = regs.mosaic + 1;
|
|
||||||
t.mosaic_x += regs.mosaic + 1;
|
|
||||||
}
|
|
||||||
if(regs.mode == Mode::Mode7) return run_mode7();
|
|
||||||
|
|
||||||
unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
|
unsigned color_depth = (regs.mode == Mode::BPP2 ? 0 : regs.mode == Mode::BPP4 ? 1 : 2);
|
||||||
unsigned palette_offset = (self.regs.bgmode == 0 ? (id << 5) : 0);
|
unsigned palette_offset = (self.regs.bgmode == 0 ? (id << 5) : 0);
|
||||||
unsigned palette_size = 2 << color_depth;
|
unsigned palette_size = 2 << color_depth;
|
||||||
|
@ -47,9 +34,10 @@ void PPU::Background::run() {
|
||||||
unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth);
|
unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth);
|
||||||
|
|
||||||
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
||||||
unsigned tile_width = (!hires ? tile_height : 4);
|
unsigned tile_width = (!hires ? tile_height : 4);
|
||||||
|
|
||||||
unsigned width = (!hires ? 256 : 512);
|
unsigned width = (!hires ? 256 : 512);
|
||||||
|
|
||||||
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
||||||
unsigned mask_y = mask_x;
|
unsigned mask_y = mask_x;
|
||||||
if(regs.screen_size & 1) mask_x <<= 1;
|
if(regs.screen_size & 1) mask_x <<= 1;
|
||||||
|
@ -57,15 +45,18 @@ void PPU::Background::run() {
|
||||||
mask_x--;
|
mask_x--;
|
||||||
mask_y--;
|
mask_y--;
|
||||||
|
|
||||||
|
unsigned px = x;
|
||||||
|
unsigned py = mosaic_voffset;
|
||||||
|
|
||||||
unsigned hscroll = regs.hoffset;
|
unsigned hscroll = regs.hoffset;
|
||||||
unsigned vscroll = regs.voffset;
|
unsigned vscroll = regs.voffset;
|
||||||
if(hires) {
|
if(hires) {
|
||||||
hscroll <<= 1;
|
hscroll <<= 1;
|
||||||
if(self.regs.interlace) y = (y << 1) + self.field();
|
if(self.regs.interlace) py = (py << 1) + self.field();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned hoffset = hscroll + x;
|
unsigned hoffset = hscroll + px;
|
||||||
unsigned voffset = vscroll + y;
|
unsigned voffset = vscroll + py;
|
||||||
|
|
||||||
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
|
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
|
||||||
uint16 opt_x = (x + (hscroll & 7));
|
uint16 opt_x = (x + (hscroll & 7));
|
||||||
|
@ -93,60 +84,167 @@ void PPU::Background::run() {
|
||||||
hoffset &= mask_x;
|
hoffset &= mask_x;
|
||||||
voffset &= mask_y;
|
voffset &= mask_y;
|
||||||
|
|
||||||
unsigned tile_number = get_tile(hoffset, voffset);
|
unsigned screen_x = (regs.screen_size & 1 ? (32 << 5) : 0);
|
||||||
bool mirror_y = tile_number & 0x8000;
|
unsigned screen_y = (regs.screen_size & 2 ? (32 << 5) : 0);
|
||||||
bool mirror_x = tile_number & 0x4000;
|
if(regs.screen_size == 3) screen_y <<= 1;
|
||||||
unsigned priority = (tile_number & 0x2000 ? regs.priority1 : regs.priority0);
|
|
||||||
unsigned palette_number = (tile_number >> 10) & 7;
|
|
||||||
unsigned palette_index = palette_offset + (palette_number << palette_size);
|
|
||||||
|
|
||||||
if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile_number += 1;
|
unsigned tx = hoffset >> tile_width;
|
||||||
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_number += 16;
|
unsigned ty = voffset >> tile_height;
|
||||||
tile_number &= 0x03ff;
|
|
||||||
tile_number += tiledata_index;
|
uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
|
||||||
tile_number &= tile_mask;
|
if(tx & 0x20) offset += screen_x;
|
||||||
|
if(ty & 0x20) offset += screen_y;
|
||||||
|
|
||||||
|
uint16 addr = regs.screen_addr + (offset << 1);
|
||||||
|
tile = (memory::vram[addr + 0] << 0) + (memory::vram[addr + 1] << 8);
|
||||||
|
bool mirror_y = tile & 0x8000;
|
||||||
|
bool mirror_x = tile & 0x4000;
|
||||||
|
priority = (tile & 0x2000 ? regs.priority1 : regs.priority0);
|
||||||
|
palette_number = (tile >> 10) & 7;
|
||||||
|
palette_index = palette_offset + (palette_number << palette_size);
|
||||||
|
|
||||||
|
if(tile_width == 4 && (bool)(hoffset & 8) != mirror_x) tile += 1;
|
||||||
|
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile += 16;
|
||||||
|
uint16 character = ((tile & 0x03ff) + tiledata_index) & tile_mask;
|
||||||
|
|
||||||
if(mirror_x) hoffset ^= 7;
|
|
||||||
if(mirror_y) voffset ^= 7;
|
if(mirror_y) voffset ^= 7;
|
||||||
|
offset = (character << (4 + color_depth)) + ((voffset & 7) << 1);
|
||||||
|
|
||||||
uint8 color = get_color(hoffset, voffset, tile_number);
|
if(regs.mode >= Mode::BPP2) {
|
||||||
if(color == 0) return;
|
data[0] = memory::vram[offset + 0];
|
||||||
|
data[1] = memory::vram[offset + 1];
|
||||||
|
}
|
||||||
|
if(regs.mode >= Mode::BPP4) {
|
||||||
|
data[2] = memory::vram[offset + 16];
|
||||||
|
data[3] = memory::vram[offset + 17];
|
||||||
|
}
|
||||||
|
if(regs.mode >= Mode::BPP8) {
|
||||||
|
data[4] = memory::vram[offset + 32];
|
||||||
|
data[5] = memory::vram[offset + 33];
|
||||||
|
data[6] = memory::vram[offset + 48];
|
||||||
|
data[7] = memory::vram[offset + 49];
|
||||||
|
}
|
||||||
|
|
||||||
color += palette_index;
|
if(mirror_x) for(unsigned n = 0; n < 8; n++) {
|
||||||
|
data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0);
|
||||||
|
data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc);
|
||||||
|
data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPU::Background::run() {
|
||||||
|
if(self.vcounter() == 0) return;
|
||||||
|
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||||
|
|
||||||
|
if((self.hcounter() & 2) == 0) {
|
||||||
|
output.main.priority = 0;
|
||||||
|
output.sub.priority = 0;
|
||||||
|
} else if(hires == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regs.mode == Mode::Inactive) return;
|
||||||
|
if(regs.main_enable == false && regs.sub_enable == false) return;
|
||||||
|
|
||||||
|
if(regs.mode == Mode::Mode7) return run_mode7();
|
||||||
|
|
||||||
|
if((x++ & 7) == edge) get_tile();
|
||||||
|
|
||||||
|
uint8 palette = get_tile_color();
|
||||||
|
if(x >= 0 && mosaic_hcounter++ >= regs.mosaic) {
|
||||||
|
mosaic_hcounter = 0;
|
||||||
|
mosaic_palette = palette;
|
||||||
|
}
|
||||||
|
if(mosaic_palette == 0) return;
|
||||||
|
|
||||||
if(hires == false) {
|
if(hires == false) {
|
||||||
if(regs.main_enabled) {
|
if(regs.main_enable) {
|
||||||
output.main.priority = priority;
|
output.main.priority = priority;
|
||||||
output.main.palette = color;
|
output.main.palette = palette_index + mosaic_palette;
|
||||||
output.main.tile = tile_number;
|
output.main.tile = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.sub_enabled) {
|
if(regs.sub_enable) {
|
||||||
output.sub.priority = priority;
|
output.sub.priority = priority;
|
||||||
output.sub.palette = color;
|
output.sub.palette = palette_index + mosaic_palette;
|
||||||
output.sub.tile = tile_number;
|
output.sub.tile = tile;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(x & 1) {
|
if(x & 1) {
|
||||||
if(regs.main_enabled) {
|
if(regs.main_enable) {
|
||||||
output.main.priority = priority;
|
output.main.priority = priority;
|
||||||
output.main.palette = color;
|
output.main.palette = palette_index + mosaic_palette;
|
||||||
output.main.tile = tile_number;
|
output.main.tile = tile;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(regs.sub_enabled) {
|
if(regs.sub_enable) {
|
||||||
output.sub.priority = priority;
|
output.sub.priority = priority;
|
||||||
output.sub.palette = color;
|
output.sub.palette = palette_index + mosaic_palette;
|
||||||
output.sub.tile = tile_number;
|
output.sub.tile = tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned PPU::Background::get_tile_color() {
|
||||||
|
unsigned color = 0;
|
||||||
|
if(regs.mode >= Mode::BPP2) {
|
||||||
|
color += (data[0] & 0x80) ? 0x01 : 0; data[0] <<= 1;
|
||||||
|
color += (data[1] & 0x80) ? 0x02 : 0; data[1] <<= 1;
|
||||||
|
}
|
||||||
|
if(regs.mode >= Mode::BPP4) {
|
||||||
|
color += (data[2] & 0x80) ? 0x04 : 0; data[2] <<= 1;
|
||||||
|
color += (data[3] & 0x80) ? 0x08 : 0; data[3] <<= 1;
|
||||||
|
}
|
||||||
|
if(regs.mode >= Mode::BPP8) {
|
||||||
|
color += (data[4] & 0x80) ? 0x10 : 0; data[4] <<= 1;
|
||||||
|
color += (data[5] & 0x80) ? 0x20 : 0; data[5] <<= 1;
|
||||||
|
color += (data[6] & 0x80) ? 0x40 : 0; data[6] <<= 1;
|
||||||
|
color += (data[7] & 0x80) ? 0x80 : 0; data[7] <<= 1;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPU::Background::reset() {
|
||||||
|
regs.tiledata_addr = 0;
|
||||||
|
regs.screen_addr = 0;
|
||||||
|
regs.screen_size = 0;
|
||||||
|
regs.mosaic = 0;
|
||||||
|
regs.tile_size = 0;
|
||||||
|
regs.mode = 0;
|
||||||
|
regs.priority0 = 0;
|
||||||
|
regs.priority1 = 0;
|
||||||
|
regs.main_enable = 0;
|
||||||
|
regs.sub_enable = 0;
|
||||||
|
regs.hoffset = 0;
|
||||||
|
regs.voffset = 0;
|
||||||
|
|
||||||
|
output.main.palette = 0;
|
||||||
|
output.main.priority = 0;
|
||||||
|
output.sub.palette = 0;
|
||||||
|
output.sub.priority = 0;
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
edge = 0;
|
||||||
|
|
||||||
|
mosaic_vcounter = 0;
|
||||||
|
mosaic_voffset = 0;
|
||||||
|
mosaic_hcounter = 0;
|
||||||
|
mosaic_hoffset = 0;
|
||||||
|
mosaic_palette = 0;
|
||||||
|
|
||||||
|
tile = 0;
|
||||||
|
priority = 0;
|
||||||
|
palette_number = 0;
|
||||||
|
palette_index = 0;
|
||||||
|
for(unsigned n = 0; n < 8; n++) data[n] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned PPU::Background::get_tile(unsigned x, unsigned y) {
|
unsigned PPU::Background::get_tile(unsigned x, unsigned y) {
|
||||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||||
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
||||||
unsigned tile_width = (!hires ? tile_height : 4);
|
unsigned tile_width = (!hires ? tile_height : 4);
|
||||||
unsigned width = (!hires ? 256 : 512);
|
unsigned width = (!hires ? 256 : 512);
|
||||||
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
||||||
unsigned mask_y = mask_x;
|
unsigned mask_y = mask_x;
|
||||||
|
@ -162,89 +260,12 @@ unsigned PPU::Background::get_tile(unsigned x, unsigned y) {
|
||||||
x = (x & mask_x) >> tile_width;
|
x = (x & mask_x) >> tile_width;
|
||||||
y = (y & mask_y) >> tile_height;
|
y = (y & mask_y) >> tile_height;
|
||||||
|
|
||||||
uint16 pos = ((y & 0x1f) << 5) + (x & 0x1f);
|
uint16 offset = ((y & 0x1f) << 5) + (x & 0x1f);
|
||||||
if(x & 0x20) pos += screen_x;
|
if(x & 0x20) offset += screen_x;
|
||||||
if(y & 0x20) pos += screen_y;
|
if(y & 0x20) offset += screen_y;
|
||||||
|
|
||||||
uint16 addr = regs.screen_addr + (pos << 1);
|
uint16 addr = regs.screen_addr + (offset << 1);
|
||||||
return memory::vram[addr + 0] + (memory::vram[addr + 1] << 8);
|
return (memory::vram[addr + 0] << 0) + (memory::vram[addr + 1] << 8);
|
||||||
}
|
|
||||||
|
|
||||||
unsigned PPU::Background::get_color(unsigned x, unsigned y, uint16 offset) {
|
|
||||||
unsigned mask = 0x80 >> (x & 7);
|
|
||||||
|
|
||||||
switch(regs.mode) {
|
|
||||||
case Background::Mode::BPP2: {
|
|
||||||
offset = (offset * 16) + ((y & 7) * 2);
|
|
||||||
|
|
||||||
unsigned d0 = memory::vram[offset + 0];
|
|
||||||
unsigned d1 = memory::vram[offset + 1];
|
|
||||||
|
|
||||||
return (((bool)(d0 & mask)) << 0)
|
|
||||||
+ (((bool)(d1 & mask)) << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Background::Mode::BPP4: {
|
|
||||||
offset = (offset * 32) + ((y & 7) * 2);
|
|
||||||
|
|
||||||
unsigned d0 = memory::vram[offset + 0];
|
|
||||||
unsigned d1 = memory::vram[offset + 1];
|
|
||||||
unsigned d2 = memory::vram[offset + 16];
|
|
||||||
unsigned d3 = memory::vram[offset + 17];
|
|
||||||
|
|
||||||
return (((bool)(d0 & mask)) << 0)
|
|
||||||
+ (((bool)(d1 & mask)) << 1)
|
|
||||||
+ (((bool)(d2 & mask)) << 2)
|
|
||||||
+ (((bool)(d3 & mask)) << 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Background::Mode::BPP8: {
|
|
||||||
offset = (offset * 64) + ((y & 7) * 2);
|
|
||||||
|
|
||||||
unsigned d0 = memory::vram[offset + 0];
|
|
||||||
unsigned d1 = memory::vram[offset + 1];
|
|
||||||
unsigned d2 = memory::vram[offset + 16];
|
|
||||||
unsigned d3 = memory::vram[offset + 17];
|
|
||||||
unsigned d4 = memory::vram[offset + 32];
|
|
||||||
unsigned d5 = memory::vram[offset + 33];
|
|
||||||
unsigned d6 = memory::vram[offset + 48];
|
|
||||||
unsigned d7 = memory::vram[offset + 49];
|
|
||||||
|
|
||||||
return (((bool)(d0 & mask)) << 0)
|
|
||||||
+ (((bool)(d1 & mask)) << 1)
|
|
||||||
+ (((bool)(d2 & mask)) << 2)
|
|
||||||
+ (((bool)(d3 & mask)) << 3)
|
|
||||||
+ (((bool)(d4 & mask)) << 4)
|
|
||||||
+ (((bool)(d5 & mask)) << 5)
|
|
||||||
+ (((bool)(d6 & mask)) << 6)
|
|
||||||
+ (((bool)(d7 & mask)) << 7);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void PPU::Background::reset() {
|
|
||||||
t.mosaic_x = 0;
|
|
||||||
t.mosaic_y = 0;
|
|
||||||
t.mosaic_hcounter = 0;
|
|
||||||
t.mosaic_vcounter = 0;
|
|
||||||
|
|
||||||
regs.tiledata_addr = 0;
|
|
||||||
regs.screen_addr = 0;
|
|
||||||
regs.screen_size = 0;
|
|
||||||
regs.mosaic = 0;
|
|
||||||
regs.tile_size = 0;
|
|
||||||
regs.mode = 0;
|
|
||||||
regs.priority0 = 0;
|
|
||||||
regs.priority1 = 0;
|
|
||||||
regs.main_enabled = 0;
|
|
||||||
regs.sub_enabled = 0;
|
|
||||||
regs.hoffset = 0;
|
|
||||||
regs.voffset = 0;
|
|
||||||
|
|
||||||
output.main.palette = 0;
|
|
||||||
output.main.priority = 0;
|
|
||||||
output.sub.palette = 0;
|
|
||||||
output.sub.priority = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) {
|
PPU::Background::Background(PPU &self, unsigned id) : self(self), id(id) {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
class Background {
|
class Background {
|
||||||
public:
|
|
||||||
PPU &self;
|
|
||||||
struct ID { enum { BG1, BG2, BG3, BG4 }; };
|
struct ID { enum { BG1, BG2, BG3, BG4 }; };
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
|
||||||
|
@ -8,14 +6,7 @@ public:
|
||||||
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||||
struct TileSize { enum { Size8x8, Size16x16 }; };
|
struct TileSize { enum { Size8x8, Size16x16 }; };
|
||||||
|
|
||||||
struct {
|
struct Regs {
|
||||||
unsigned mosaic_x;
|
|
||||||
unsigned mosaic_y;
|
|
||||||
unsigned mosaic_hcounter;
|
|
||||||
unsigned mosaic_vcounter;
|
|
||||||
} t;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned tiledata_addr;
|
unsigned tiledata_addr;
|
||||||
unsigned screen_addr;
|
unsigned screen_addr;
|
||||||
unsigned screen_size;
|
unsigned screen_size;
|
||||||
|
@ -26,33 +17,53 @@ public:
|
||||||
unsigned priority0;
|
unsigned priority0;
|
||||||
unsigned priority1;
|
unsigned priority1;
|
||||||
|
|
||||||
bool main_enabled;
|
bool main_enable;
|
||||||
bool sub_enabled;
|
bool sub_enable;
|
||||||
|
|
||||||
unsigned hoffset;
|
unsigned hoffset;
|
||||||
unsigned voffset;
|
unsigned voffset;
|
||||||
} regs;
|
} regs;
|
||||||
|
|
||||||
struct {
|
struct Output {
|
||||||
struct {
|
struct Pixel {
|
||||||
unsigned priority; //0 = none (transparent)
|
unsigned priority; //0 = none (transparent)
|
||||||
unsigned palette;
|
unsigned palette;
|
||||||
unsigned tile;
|
unsigned tile;
|
||||||
} main, sub;
|
} main, sub;
|
||||||
} output;
|
} output;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
signed x;
|
||||||
|
signed y;
|
||||||
|
signed edge;
|
||||||
|
|
||||||
|
unsigned mosaic_vcounter;
|
||||||
|
unsigned mosaic_voffset;
|
||||||
|
unsigned mosaic_hcounter;
|
||||||
|
unsigned mosaic_hoffset;
|
||||||
|
unsigned mosaic_palette;
|
||||||
|
|
||||||
|
unsigned tile;
|
||||||
|
unsigned priority;
|
||||||
|
unsigned palette_number;
|
||||||
|
unsigned palette_index;
|
||||||
|
uint8 data[8];
|
||||||
|
};
|
||||||
|
|
||||||
void frame();
|
void frame();
|
||||||
void scanline();
|
void scanline();
|
||||||
void run();
|
void run();
|
||||||
unsigned get_tile(unsigned x, unsigned y);
|
|
||||||
unsigned get_color(unsigned x, unsigned y, uint16 offset);
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
void get_tile();
|
||||||
|
unsigned get_tile_color();
|
||||||
|
unsigned get_tile(unsigned x, unsigned y);
|
||||||
|
signed clip(signed n);
|
||||||
|
void run_mode7();
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
Background(PPU &self, unsigned id);
|
Background(PPU &self, unsigned id);
|
||||||
|
|
||||||
private:
|
PPU &self;
|
||||||
//mode7.cpp
|
friend class PPU;
|
||||||
signed clip(signed n);
|
|
||||||
void run_mode7();
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,15 @@ void PPU::Background::run_mode7() {
|
||||||
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
|
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
|
||||||
signed voffset = sclip<13>(self.regs.mode7_voffset);
|
signed voffset = sclip<13>(self.regs.mode7_voffset);
|
||||||
|
|
||||||
unsigned x = t.mosaic_x;
|
if(++Background::x & ~255) return;
|
||||||
unsigned y = self.bg1.t.mosaic_y; //BG2 vertical mosaic uses BG1 mosaic size
|
unsigned x = mosaic_hoffset;
|
||||||
|
unsigned y = self.bg1.mosaic_voffset; //BG2 vertical mosaic uses BG1 mosaic size
|
||||||
|
|
||||||
|
if(mosaic_hcounter++ == regs.mosaic) {
|
||||||
|
mosaic_hcounter = 0;
|
||||||
|
mosaic_hoffset += regs.mosaic + 1;
|
||||||
|
}
|
||||||
|
|
||||||
if(self.regs.mode7_hflip) x = 255 - x;
|
if(self.regs.mode7_hflip) x = 255 - x;
|
||||||
if(self.regs.mode7_vflip) y = 255 - y;
|
if(self.regs.mode7_vflip) y = 255 - y;
|
||||||
|
|
||||||
|
@ -41,11 +48,12 @@ void PPU::Background::run_mode7() {
|
||||||
py &= 1023;
|
py &= 1023;
|
||||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//palette color 0 outside of screen area
|
//palette color 0 outside of screen area
|
||||||
case 2: {
|
case 2: {
|
||||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
if((px | py) & ~1023) {
|
||||||
palette = 0;
|
palette = 0;
|
||||||
} else {
|
} else {
|
||||||
px &= 1023;
|
px &= 1023;
|
||||||
|
@ -53,11 +61,12 @@ void PPU::Background::run_mode7() {
|
||||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||||
}
|
}
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//character 0 repetition outside of screen area
|
//character 0 repetition outside of screen area
|
||||||
case 3: {
|
case 3: {
|
||||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
if((px & py) & ~1023) {
|
||||||
tile = 0;
|
tile = 0;
|
||||||
} else {
|
} else {
|
||||||
px &= 1023;
|
px &= 1023;
|
||||||
|
@ -65,7 +74,8 @@ void PPU::Background::run_mode7() {
|
||||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||||
}
|
}
|
||||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||||
} break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned priority;
|
unsigned priority;
|
||||||
|
@ -78,14 +88,16 @@ void PPU::Background::run_mode7() {
|
||||||
|
|
||||||
if(palette == 0) return;
|
if(palette == 0) return;
|
||||||
|
|
||||||
if(regs.main_enabled) {
|
if(regs.main_enable) {
|
||||||
output.main.palette = palette;
|
output.main.palette = palette;
|
||||||
output.main.priority = priority;
|
output.main.priority = priority;
|
||||||
|
output.main.tile = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.sub_enabled) {
|
if(regs.sub_enable) {
|
||||||
output.sub.palette = palette;
|
output.sub.palette = palette;
|
||||||
output.sub.priority = priority;
|
output.sub.priority = priority;
|
||||||
|
output.sub.tile = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,26 +19,26 @@ uint16 PPU::get_vram_address() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 PPU::vram_read(unsigned addr) {
|
uint8 PPU::vram_read(unsigned addr) {
|
||||||
if(regs.display_disabled || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
||||||
return memory::vram[addr];
|
return memory::vram[addr];
|
||||||
}
|
}
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::vram_write(unsigned addr, uint8 data) {
|
void PPU::vram_write(unsigned addr, uint8 data) {
|
||||||
if(regs.display_disabled || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
if(regs.display_disable || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
||||||
memory::vram[addr] = data;
|
memory::vram[addr] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 PPU::oam_read(unsigned addr) {
|
uint8 PPU::oam_read(unsigned addr) {
|
||||||
if(!regs.display_disabled && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.ioamaddr;
|
if(!regs.display_disable && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.ioamaddr;
|
||||||
if(addr & 0x0200) addr &= 0x021f;
|
if(addr & 0x0200) addr &= 0x021f;
|
||||||
return memory::oam[addr];
|
return memory::oam[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::oam_write(unsigned addr, uint8 data) {
|
void PPU::oam_write(unsigned addr, uint8 data) {
|
||||||
if(!regs.display_disabled && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.ioamaddr;
|
if(!regs.display_disable && vcounter() < (!regs.overscan ? 225 : 240)) addr = regs.ioamaddr;
|
||||||
if(addr & 0x0200) addr &= 0x021f;
|
if(addr & 0x0200) addr &= 0x021f;
|
||||||
memory::oam[addr] = data;
|
memory::oam[addr] = data;
|
||||||
oam.update(addr, data);
|
oam.update(addr, data);
|
||||||
|
@ -164,8 +164,8 @@ void PPU::mmio_update_video_mode() {
|
||||||
|
|
||||||
//INIDISP
|
//INIDISP
|
||||||
void PPU::mmio_w2100(uint8 data) {
|
void PPU::mmio_w2100(uint8 data) {
|
||||||
if(regs.display_disabled && vcounter() == (!regs.overscan ? 225 : 240)) oam.address_reset();
|
if(regs.display_disable && vcounter() == (!regs.overscan ? 225 : 240)) oam.address_reset();
|
||||||
regs.display_disabled = data & 0x80;
|
regs.display_disable = data & 0x80;
|
||||||
regs.display_brightness = data & 0x0f;
|
regs.display_brightness = data & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,20 +491,20 @@ void PPU::mmio_w212b(uint8 data) {
|
||||||
|
|
||||||
//TM
|
//TM
|
||||||
void PPU::mmio_w212c(uint8 data) {
|
void PPU::mmio_w212c(uint8 data) {
|
||||||
oam.regs.main_enabled = data & 0x10;
|
oam.regs.main_enable = data & 0x10;
|
||||||
bg4.regs.main_enabled = data & 0x08;
|
bg4.regs.main_enable = data & 0x08;
|
||||||
bg3.regs.main_enabled = data & 0x04;
|
bg3.regs.main_enable = data & 0x04;
|
||||||
bg2.regs.main_enabled = data & 0x02;
|
bg2.regs.main_enable = data & 0x02;
|
||||||
bg1.regs.main_enabled = data & 0x01;
|
bg1.regs.main_enable = data & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TS
|
//TS
|
||||||
void PPU::mmio_w212d(uint8 data) {
|
void PPU::mmio_w212d(uint8 data) {
|
||||||
oam.regs.sub_enabled = data & 0x10;
|
oam.regs.sub_enable = data & 0x10;
|
||||||
bg4.regs.sub_enabled = data & 0x08;
|
bg4.regs.sub_enable = data & 0x08;
|
||||||
bg3.regs.sub_enabled = data & 0x04;
|
bg3.regs.sub_enable = data & 0x04;
|
||||||
bg2.regs.sub_enabled = data & 0x02;
|
bg2.regs.sub_enable = data & 0x02;
|
||||||
bg1.regs.sub_enabled = data & 0x01;
|
bg1.regs.sub_enable = data & 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TMW
|
//TMW
|
||||||
|
@ -703,7 +703,7 @@ void PPU::mmio_reset() {
|
||||||
regs.icgramaddr = 0;
|
regs.icgramaddr = 0;
|
||||||
|
|
||||||
//$2100 INIDISP
|
//$2100 INIDISP
|
||||||
regs.display_disabled = true;
|
regs.display_disable = true;
|
||||||
regs.display_brightness = 0;
|
regs.display_brightness = 0;
|
||||||
|
|
||||||
//$2102 OAMADDL
|
//$2102 OAMADDL
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct {
|
||||||
uint16 icgramaddr;
|
uint16 icgramaddr;
|
||||||
|
|
||||||
//$2100 INIDISP
|
//$2100 INIDISP
|
||||||
bool display_disabled;
|
bool display_disable;
|
||||||
unsigned display_brightness;
|
unsigned display_brightness;
|
||||||
|
|
||||||
//$2102 OAMADDL
|
//$2102 OAMADDL
|
||||||
|
|
|
@ -38,10 +38,11 @@ void PPU::enter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
scanline();
|
scanline();
|
||||||
add_clocks(88);
|
add_clocks(56);
|
||||||
|
|
||||||
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
|
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
|
||||||
for(unsigned n = 0; n < 256; n++) {
|
add_clocks(4);
|
||||||
|
for(unsigned pixel = 1; pixel < 8 + 256; pixel++) {
|
||||||
bg1.run();
|
bg1.run();
|
||||||
bg2.run();
|
bg2.run();
|
||||||
bg3.run();
|
bg3.run();
|
||||||
|
@ -52,19 +53,21 @@ void PPU::enter() {
|
||||||
bg2.run();
|
bg2.run();
|
||||||
bg3.run();
|
bg3.run();
|
||||||
bg4.run();
|
bg4.run();
|
||||||
oam.run();
|
if(pixel >= 8) {
|
||||||
window.run();
|
oam.run();
|
||||||
screen.run();
|
window.run();
|
||||||
|
screen.run();
|
||||||
|
}
|
||||||
add_clocks(2);
|
add_clocks(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_clocks(22);
|
add_clocks(22);
|
||||||
oam.tilefetch();
|
oam.tilefetch();
|
||||||
} else {
|
} else {
|
||||||
add_clocks(1024 + 22 + 136);
|
add_clocks(1056 + 22 + 136);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_clocks(lineclocks() - 88 - 1024 - 22 - 136);
|
add_clocks(lineclocks() - 56 - 1056 - 22 - 136);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,17 @@ public:
|
||||||
~PPU();
|
~PPU();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint16 *surface;
|
||||||
|
uint16 *output;
|
||||||
|
|
||||||
|
uint8 ppu1_version;
|
||||||
|
uint8 ppu2_version;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
bool interlace;
|
||||||
|
bool overscan;
|
||||||
|
} display;
|
||||||
|
|
||||||
#include "background/background.hpp"
|
#include "background/background.hpp"
|
||||||
#include "mmio/mmio.hpp"
|
#include "mmio/mmio.hpp"
|
||||||
#include "screen/screen.hpp"
|
#include "screen/screen.hpp"
|
||||||
|
@ -32,17 +43,6 @@ private:
|
||||||
Window window;
|
Window window;
|
||||||
Screen screen;
|
Screen screen;
|
||||||
|
|
||||||
uint16 *surface;
|
|
||||||
uint16 *output;
|
|
||||||
|
|
||||||
uint8 ppu1_version;
|
|
||||||
uint8 ppu2_version;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
bool interlace;
|
|
||||||
bool overscan;
|
|
||||||
} display;
|
|
||||||
|
|
||||||
static void Enter();
|
static void Enter();
|
||||||
void add_clocks(unsigned);
|
void add_clocks(unsigned);
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@ void PPU::Screen::run() {
|
||||||
*output++ = color;
|
*output++ = color;
|
||||||
*output++ = color;
|
*output++ = color;
|
||||||
} else {
|
} else {
|
||||||
color = get_pixel(true);
|
|
||||||
*output++ = color;
|
|
||||||
color = get_pixel(false);
|
color = get_pixel(false);
|
||||||
*output++ = color;
|
*output++ = color;
|
||||||
|
color = get_pixel(true);
|
||||||
|
*output++ = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ uint16 PPU::Screen::get_pixel(bool swap) {
|
||||||
//========
|
//========
|
||||||
|
|
||||||
output = light_table[self.regs.display_brightness][output];
|
output = light_table[self.regs.display_brightness][output];
|
||||||
if(self.regs.display_disabled) output = 0x0000;
|
if(self.regs.display_disable) output = 0x0000;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
class Screen {
|
class Screen {
|
||||||
public:
|
|
||||||
PPU &self;
|
|
||||||
uint16 *output;
|
uint16 *output;
|
||||||
|
|
||||||
struct {
|
struct Regs {
|
||||||
bool addsub_mode;
|
bool addsub_mode;
|
||||||
bool direct_color;
|
bool direct_color;
|
||||||
|
|
||||||
|
@ -25,13 +23,15 @@ public:
|
||||||
void run();
|
void run();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void serialize(serializer&);
|
|
||||||
Screen(PPU &self);
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint16 light_table[16][32768];
|
uint16 light_table[16][32768];
|
||||||
uint16 get_pixel(bool swap);
|
uint16 get_pixel(bool swap);
|
||||||
uint16 addsub(unsigned x, unsigned y, bool halve);
|
uint16 addsub(unsigned x, unsigned y, bool halve);
|
||||||
uint16 get_color(unsigned palette);
|
uint16 get_color(unsigned palette);
|
||||||
uint16 get_direct_color(unsigned palette, unsigned tile);
|
uint16 get_direct_color(unsigned palette, unsigned tile);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
Screen(PPU &self);
|
||||||
|
|
||||||
|
PPU &self;
|
||||||
|
friend class PPU;
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,7 @@ void PPU::serialize(serializer &s) {
|
||||||
s.integer(regs.ioamaddr);
|
s.integer(regs.ioamaddr);
|
||||||
s.integer(regs.icgramaddr);
|
s.integer(regs.icgramaddr);
|
||||||
|
|
||||||
s.integer(regs.display_disabled);
|
s.integer(regs.display_disable);
|
||||||
s.integer(regs.display_brightness);
|
s.integer(regs.display_brightness);
|
||||||
|
|
||||||
s.integer(regs.oam_baseaddr);
|
s.integer(regs.oam_baseaddr);
|
||||||
|
@ -89,11 +89,6 @@ void PPU::serialize(serializer &s) {
|
||||||
void PPU::Background::serialize(serializer &s) {
|
void PPU::Background::serialize(serializer &s) {
|
||||||
s.integer(id);
|
s.integer(id);
|
||||||
|
|
||||||
s.integer(t.mosaic_x);
|
|
||||||
s.integer(t.mosaic_y);
|
|
||||||
s.integer(t.mosaic_hcounter);
|
|
||||||
s.integer(t.mosaic_vcounter);
|
|
||||||
|
|
||||||
s.integer(regs.tiledata_addr);
|
s.integer(regs.tiledata_addr);
|
||||||
s.integer(regs.screen_addr);
|
s.integer(regs.screen_addr);
|
||||||
s.integer(regs.screen_size);
|
s.integer(regs.screen_size);
|
||||||
|
@ -104,8 +99,8 @@ void PPU::Background::serialize(serializer &s) {
|
||||||
s.integer(regs.priority0);
|
s.integer(regs.priority0);
|
||||||
s.integer(regs.priority1);
|
s.integer(regs.priority1);
|
||||||
|
|
||||||
s.integer(regs.main_enabled);
|
s.integer(regs.main_enable);
|
||||||
s.integer(regs.sub_enabled);
|
s.integer(regs.sub_enable);
|
||||||
|
|
||||||
s.integer(regs.hoffset);
|
s.integer(regs.hoffset);
|
||||||
s.integer(regs.voffset);
|
s.integer(regs.voffset);
|
||||||
|
@ -117,6 +112,22 @@ void PPU::Background::serialize(serializer &s) {
|
||||||
s.integer(output.sub.priority);
|
s.integer(output.sub.priority);
|
||||||
s.integer(output.sub.palette);
|
s.integer(output.sub.palette);
|
||||||
s.integer(output.sub.tile);
|
s.integer(output.sub.tile);
|
||||||
|
|
||||||
|
s.integer(x);
|
||||||
|
s.integer(y);
|
||||||
|
s.integer(edge);
|
||||||
|
|
||||||
|
s.integer(mosaic_vcounter);
|
||||||
|
s.integer(mosaic_voffset);
|
||||||
|
s.integer(mosaic_hcounter);
|
||||||
|
s.integer(mosaic_hoffset);
|
||||||
|
s.integer(mosaic_palette);
|
||||||
|
|
||||||
|
s.integer(tile);
|
||||||
|
s.integer(priority);
|
||||||
|
s.integer(palette_number);
|
||||||
|
s.integer(palette_index);
|
||||||
|
s.array(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Sprite::serialize(serializer &s) {
|
void PPU::Sprite::serialize(serializer &s) {
|
||||||
|
@ -153,8 +164,8 @@ void PPU::Sprite::serialize(serializer &s) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.integer(regs.main_enabled);
|
s.integer(regs.main_enable);
|
||||||
s.integer(regs.sub_enabled);
|
s.integer(regs.sub_enable);
|
||||||
s.integer(regs.interlace);
|
s.integer(regs.interlace);
|
||||||
|
|
||||||
s.integer(regs.base_size);
|
s.integer(regs.base_size);
|
||||||
|
@ -178,8 +189,6 @@ void PPU::Sprite::serialize(serializer &s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Window::serialize(serializer &s) {
|
void PPU::Window::serialize(serializer &s) {
|
||||||
s.integer(t.x);
|
|
||||||
|
|
||||||
s.integer(regs.bg1_one_enable);
|
s.integer(regs.bg1_one_enable);
|
||||||
s.integer(regs.bg1_one_invert);
|
s.integer(regs.bg1_one_invert);
|
||||||
s.integer(regs.bg1_two_enable);
|
s.integer(regs.bg1_two_enable);
|
||||||
|
@ -239,6 +248,9 @@ void PPU::Window::serialize(serializer &s) {
|
||||||
s.integer(output.main.color_enable);
|
s.integer(output.main.color_enable);
|
||||||
s.integer(output.sub.color_enable);
|
s.integer(output.sub.color_enable);
|
||||||
|
|
||||||
|
s.integer(x);
|
||||||
|
s.integer(one);
|
||||||
|
s.integer(two);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Screen::serialize(serializer &s) {
|
void PPU::Screen::serialize(serializer &s) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ void PPU::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];
|
||||||
|
|
||||||
if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disabled == false) address_reset();
|
if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disable == false) address_reset();
|
||||||
if(t.y >= (!self.regs.overscan ? 224 : 239)) return;
|
if(t.y >= (!self.regs.overscan ? 224 : 239)) return;
|
||||||
|
|
||||||
memset(oam_item, 0xff, 32); //default to invalid
|
memset(oam_item, 0xff, 32); //default to invalid
|
||||||
|
@ -72,12 +72,12 @@ void PPU::Sprite::run() {
|
||||||
color |= ((bool)(tile.d3 & mask)) << 3;
|
color |= ((bool)(tile.d3 & mask)) << 3;
|
||||||
|
|
||||||
if(color) {
|
if(color) {
|
||||||
if(regs.main_enabled) {
|
if(regs.main_enable) {
|
||||||
output.main.palette = tile.palette + color;
|
output.main.palette = tile.palette + color;
|
||||||
output.main.priority = priority_table[tile.priority];
|
output.main.priority = priority_table[tile.priority];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.sub_enabled) {
|
if(regs.sub_enable) {
|
||||||
output.sub.palette = tile.palette + color;
|
output.sub.palette = tile.palette + color;
|
||||||
output.sub.priority = priority_table[tile.priority];
|
output.sub.priority = priority_table[tile.priority];
|
||||||
}
|
}
|
||||||
|
@ -189,8 +189,8 @@ void PPU::Sprite::reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.main_enabled = 0;
|
regs.main_enable = 0;
|
||||||
regs.sub_enabled = 0;
|
regs.sub_enable = 0;
|
||||||
regs.interlace = 0;
|
regs.interlace = 0;
|
||||||
|
|
||||||
regs.base_size = 0;
|
regs.base_size = 0;
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
class Sprite {
|
class Sprite {
|
||||||
public:
|
|
||||||
PPU &self;
|
|
||||||
|
|
||||||
struct SpriteItem {
|
struct SpriteItem {
|
||||||
uint16 x;
|
uint16 x;
|
||||||
uint16 y;
|
uint16 y;
|
||||||
|
@ -36,9 +33,9 @@ public:
|
||||||
TileItem tile[2][34];
|
TileItem tile[2][34];
|
||||||
} t;
|
} t;
|
||||||
|
|
||||||
struct {
|
struct Regs {
|
||||||
bool main_enabled;
|
bool main_enable;
|
||||||
bool sub_enabled;
|
bool sub_enable;
|
||||||
bool interlace;
|
bool interlace;
|
||||||
|
|
||||||
uint8 base_size;
|
uint8 base_size;
|
||||||
|
@ -55,8 +52,8 @@ public:
|
||||||
bool range_over;
|
bool range_over;
|
||||||
} regs;
|
} regs;
|
||||||
|
|
||||||
struct {
|
struct Output {
|
||||||
struct {
|
struct Pixel {
|
||||||
unsigned priority; //0 = none (transparent)
|
unsigned priority; //0 = none (transparent)
|
||||||
unsigned palette;
|
unsigned palette;
|
||||||
} main, sub;
|
} main, sub;
|
||||||
|
@ -73,9 +70,11 @@ public:
|
||||||
void tilefetch();
|
void tilefetch();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
bool on_scanline(SpriteItem&);
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
Sprite(PPU &self);
|
Sprite(PPU &self);
|
||||||
|
|
||||||
private:
|
PPU &self;
|
||||||
bool on_scanline(SpriteItem&);
|
friend class PPU;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#ifdef PPU_CPP
|
#ifdef PPU_CPP
|
||||||
|
|
||||||
void PPU::Window::scanline() {
|
void PPU::Window::scanline() {
|
||||||
t.x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Window::run() {
|
void PPU::Window::run() {
|
||||||
bool main, sub;
|
bool main, sub;
|
||||||
|
one = (x >= regs.one_left && x <= regs.one_right);
|
||||||
|
two = (x >= regs.two_left && x <= regs.two_right);
|
||||||
|
x++;
|
||||||
|
|
||||||
test(
|
test(
|
||||||
main, sub,
|
main, sub,
|
||||||
|
@ -75,8 +78,6 @@ void PPU::Window::run() {
|
||||||
|
|
||||||
output.main.color_enable = main;
|
output.main.color_enable = main;
|
||||||
output.sub.color_enable = sub;
|
output.sub.color_enable = sub;
|
||||||
|
|
||||||
t.x++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Window::test(
|
void PPU::Window::test(
|
||||||
|
@ -85,24 +86,21 @@ void PPU::Window::test(
|
||||||
bool two_enable, bool two_invert,
|
bool two_enable, bool two_invert,
|
||||||
uint8 mask, bool main_enable, bool sub_enable
|
uint8 mask, bool main_enable, bool sub_enable
|
||||||
) {
|
) {
|
||||||
unsigned x = t.x;
|
bool one = Window::one ^ one_invert;
|
||||||
|
bool two = Window::two ^ two_invert;
|
||||||
bool output;
|
bool output;
|
||||||
|
|
||||||
if(one_enable == false && two_enable == false) {
|
if(one_enable == false && two_enable == false) {
|
||||||
output = false;
|
output = false;
|
||||||
} else if(one_enable == true && two_enable == false) {
|
} else if(one_enable == true && two_enable == false) {
|
||||||
output = (x >= regs.one_left && x <= regs.one_right) ^ one_invert;
|
output = one;
|
||||||
} else if(one_enable == false && two_enable == true) {
|
} else if(one_enable == false && two_enable == true) {
|
||||||
output = (x >= regs.two_left && x <= regs.two_right) ^ two_invert;
|
output = two;
|
||||||
} else {
|
} else switch(mask) {
|
||||||
bool one = (x >= regs.one_left && x <= regs.one_right) ^ one_invert;
|
case 0: output = (one | two) == 1; break;
|
||||||
bool two = (x >= regs.two_left && x <= regs.two_right) ^ two_invert;
|
case 1: output = (one & two) == 1; break;
|
||||||
switch(mask) {
|
case 2: output = (one ^ two) == 1; break;
|
||||||
case 0: output = (one | two) == 1; break;
|
case 3: output = (one ^ two) == 0; break;
|
||||||
case 1: output = (one & two) == 1; break;
|
|
||||||
case 2: output = (one ^ two) == 1; break;
|
|
||||||
case 3: output = (one ^ two) == 0; break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main = main_enable ? output : false;
|
main = main_enable ? output : false;
|
||||||
|
@ -110,7 +108,6 @@ void PPU::Window::test(
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Window::reset() {
|
void PPU::Window::reset() {
|
||||||
t.x = 0;
|
|
||||||
regs.bg1_one_enable = false;
|
regs.bg1_one_enable = false;
|
||||||
regs.bg1_one_invert = false;
|
regs.bg1_one_invert = false;
|
||||||
regs.bg1_two_enable = false;
|
regs.bg1_two_enable = false;
|
||||||
|
@ -157,8 +154,13 @@ void PPU::Window::reset() {
|
||||||
regs.oam_sub_enable = 0;
|
regs.oam_sub_enable = 0;
|
||||||
regs.col_main_mask = 0;
|
regs.col_main_mask = 0;
|
||||||
regs.col_sub_mask = 0;
|
regs.col_sub_mask = 0;
|
||||||
|
|
||||||
output.main.color_enable = 0;
|
output.main.color_enable = 0;
|
||||||
output.sub.color_enable = 0;
|
output.sub.color_enable = 0;
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
one = 0;
|
||||||
|
two = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
PPU::Window::Window(PPU &self) : self(self) {
|
PPU::Window::Window(PPU &self) : self(self) {
|
||||||
|
|
|
@ -1,11 +1,4 @@
|
||||||
class Window {
|
class Window {
|
||||||
public:
|
|
||||||
PPU &self;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
unsigned x;
|
|
||||||
} t;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool bg1_one_enable;
|
bool bg1_one_enable;
|
||||||
bool bg1_one_invert;
|
bool bg1_one_invert;
|
||||||
|
@ -64,24 +57,32 @@ public:
|
||||||
uint8 col_sub_mask;
|
uint8 col_sub_mask;
|
||||||
} regs;
|
} regs;
|
||||||
|
|
||||||
struct {
|
struct Output {
|
||||||
struct {
|
struct Pixel {
|
||||||
bool color_enable;
|
bool color_enable;
|
||||||
} main, sub;
|
} main, sub;
|
||||||
} output;
|
} output;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
unsigned x;
|
||||||
|
bool one;
|
||||||
|
bool two;
|
||||||
|
};
|
||||||
|
|
||||||
void scanline();
|
void scanline();
|
||||||
void run();
|
void run();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void serialize(serializer&);
|
|
||||||
Window(PPU &self);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void test(
|
void test(
|
||||||
bool &main, bool &sub,
|
bool &main, bool &sub,
|
||||||
bool one_enable, bool one_invert,
|
bool one_enable, bool one_invert,
|
||||||
bool two_enable, bool two_invert,
|
bool two_enable, bool two_invert,
|
||||||
uint8 mask, bool main_enable, bool sub_enable
|
uint8 mask, bool main_enable, bool sub_enable
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void serialize(serializer&);
|
||||||
|
Window(PPU &self);
|
||||||
|
|
||||||
|
PPU &self;
|
||||||
|
friend class PPU;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "068.10";
|
static const char Version[] = "068.12";
|
||||||
static const unsigned SerializerVersion = 13;
|
static const unsigned SerializerVersion = 13;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue