mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v063r10 release.
With this release, the final last-generation holdout, the scanline-based PPU renderer, has been replaced with a true, accurate, cycle-level PPU that renders one dot at a time. Finally, this fulfills the greatest milestone remaining in the SNES emulation scene. With every processor emulated at the lowest possible level, SNES emulation finally rivals the accuracy levels that NES emulators have offered for years. Now, please do understand that this release is not a beta, nor is it even an alpha. It is simply a preview of things to come, and as such you can consider it a pre-alpha. There are many caveats at this time. First, it is very slow. More than twice as slow as v063 official. There have been absolutely no optimizations whatsoever to the new dot-based renderer. I do expect to be able to speed this up significantly in future releases. Second, this may lock up on Windows Vista and later for unknown reasons. I haven't had a chance to look into it; so stick with Windows XP or Linux for now. Third, save states are not supported yet. If you try and use them anyway, bad things will happen. Fourth, and most importantly, this isn't 100% bit-perfect by any stretch of the imagination. Off the top of my head, memory is accessed far too often, the OAM and CGRAM address lines are not controlled by the S-PPU during active display, none of the various glitches are supported, and the OAM renderer does not pre-cache the next scanline's sprites, it happens on the same line for now. I will obviously be doing my best to improve the accuracy of the aforementioned things. But even with those missing, this is still leaps and bounds above a pure scanline-based renderer. It essentially provides 682 times the parallelism. It is enough to finally properly emulate the shadow effect in Air Strike Patrol, and it finally eliminates the "PPU Hclock render position" hack once and for all. Lastly, you'll need the DLLs from v063 official. I didn't bother to include them this time. Enjoy!
This commit is contained in:
parent
0a3fdc404d
commit
c33f70a8c6
Binary file not shown.
|
@ -13,7 +13,7 @@ objects :=
|
|||
# link += -lgcov
|
||||
|
||||
# profile-guided optimization
|
||||
# flags += -fprofile-use
|
||||
flags += -fprofile-use
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#ifdef SPPU_CPP
|
||||
|
||||
#include "mode7.cpp"
|
||||
|
||||
void sPPU::Background::scanline() {
|
||||
if(self.vcounter() == 1) {
|
||||
regs.mosaic_y = 1;
|
||||
|
@ -9,20 +11,26 @@ void sPPU::Background::scanline() {
|
|||
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic + 1;
|
||||
regs.mosaic_countdown--;
|
||||
}
|
||||
|
||||
state.x = 0;
|
||||
}
|
||||
|
||||
void sPPU::Background::run() {
|
||||
output.main.valid = false;
|
||||
output.sub.valid = false;
|
||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||
|
||||
if((self.hcounter() & 2) == 0) {
|
||||
output.main.valid = false;
|
||||
output.sub.valid = false;
|
||||
} else if(hires == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(regs.mode == Mode::Inactive) return;
|
||||
if(regs.main_enabled == false && regs.sub_enabled == false) return;
|
||||
|
||||
if(self.hcounter() < 88) return;
|
||||
if(self.hcounter() >= 1112) return;
|
||||
if(self.hcounter() & 2) return;
|
||||
|
||||
unsigned x = (self.hcounter() - 88) >> 2;
|
||||
unsigned x = state.x++;
|
||||
unsigned y = regs.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);
|
||||
unsigned palette_offset = (self.regs.bgmode == 0 ? (id << 5) : 0);
|
||||
|
@ -30,12 +38,10 @@ void sPPU::Background::run() {
|
|||
unsigned tile_mask = 0x0fff >> color_depth;
|
||||
unsigned tiledata_index = regs.tiledata_addr >> (4 + color_depth);
|
||||
|
||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||
unsigned width = (!hires ? 256 : 512);
|
||||
|
||||
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
||||
unsigned tile_width = (!hires ? tile_height : 4);
|
||||
|
||||
unsigned width = (!hires ? 256 : 512);
|
||||
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
||||
unsigned mask_y = mask_x;
|
||||
if(regs.screen_size & 1) mask_x <<= 1;
|
||||
|
@ -51,11 +57,68 @@ void sPPU::Background::run() {
|
|||
unsigned vscroll = regs.voffset;
|
||||
if(hires) {
|
||||
hscroll <<= 1;
|
||||
if(self.regs.interlace) y = (y << 1) + self.field();
|
||||
}
|
||||
|
||||
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) {
|
||||
uint16 opt_x = (x + (hscroll & 7));
|
||||
|
||||
//tile 0 is unaffected by offset-per-tile mode
|
||||
if(opt_x >= 8) {
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
if(self.regs.bgmode == 4) {
|
||||
if(hval & opt_valid_bit) {
|
||||
if(!(hval & 0x8000)) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
} else {
|
||||
voffset = y + hval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(hval & opt_valid_bit) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
}
|
||||
if(vval & opt_valid_bit) {
|
||||
voffset = y + vval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hoffset &= mask_x;
|
||||
voffset &= mask_y;
|
||||
|
||||
|
@ -89,19 +152,38 @@ void sPPU::Background::run() {
|
|||
unsigned color = get_color(hoffset, voffset, tile_number);
|
||||
if(color == 0) return;
|
||||
|
||||
unsigned palette_addr = (palette_index + color) << 1;
|
||||
unsigned output_color = memory::cgram[palette_addr + 0] + (memory::cgram[palette_addr + 1] << 8);
|
||||
color += palette_index;
|
||||
|
||||
if(regs.main_enabled) {
|
||||
output.main.valid = true;
|
||||
output.main.color = output_color;
|
||||
output.main.priority = priority;
|
||||
}
|
||||
if(hires == false) {
|
||||
if(regs.main_enabled) {
|
||||
output.main.valid = true;
|
||||
output.main.palette = color;
|
||||
output.main.palette_number = palette_number;
|
||||
output.main.priority = priority;
|
||||
}
|
||||
|
||||
if(regs.sub_enabled) {
|
||||
output.sub.valid = true;
|
||||
output.sub.color = output_color;
|
||||
output.sub.priority = priority;
|
||||
if(regs.sub_enabled) {
|
||||
output.sub.valid = true;
|
||||
output.sub.palette = color;
|
||||
output.sub.palette_number = palette_number;
|
||||
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.priority = priority;
|
||||
}
|
||||
} else {
|
||||
if(regs.sub_enabled) {
|
||||
output.sub.valid = true;
|
||||
output.sub.palette = color;
|
||||
output.sub.palette_number = palette_number;
|
||||
output.sub.priority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,6 +239,32 @@ unsigned sPPU::Background::get_color(unsigned x, unsigned y, uint16 offset) {
|
|||
};
|
||||
}
|
||||
|
||||
void sPPU::Background::reset() {
|
||||
state.x = 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;
|
||||
regs.priority1 = 0;
|
||||
regs.main_enabled = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
sPPU::Background::Background(sPPU &self, unsigned id) : self(self), id(id) {
|
||||
//generate mosaic table
|
||||
for(unsigned m = 0; m < 16; m++) {
|
||||
|
|
|
@ -8,6 +8,10 @@ public:
|
|||
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
struct TileSize { enum { Size8x8, Size16x16 }; };
|
||||
|
||||
struct {
|
||||
unsigned x;
|
||||
} state;
|
||||
|
||||
struct {
|
||||
unsigned tiledata_addr;
|
||||
unsigned screen_addr;
|
||||
|
@ -31,17 +35,22 @@ public:
|
|||
struct {
|
||||
struct {
|
||||
bool valid;
|
||||
uint16 color;
|
||||
unsigned priority;
|
||||
uint8 palette;
|
||||
uint8 palette_number;
|
||||
uint8 priority;
|
||||
} main, sub;
|
||||
} output;
|
||||
|
||||
void scanline();
|
||||
void run();
|
||||
unsigned get_color(unsigned x, unsigned y, uint16 offset);
|
||||
|
||||
void reset();
|
||||
Background(sPPU &self, unsigned id);
|
||||
|
||||
private:
|
||||
static uint16 mosaic_table[16][4096];
|
||||
|
||||
//mode7.cpp
|
||||
signed clip(signed n);
|
||||
void run_mode7(unsigned x, unsigned y);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
#ifdef SPPU_CPP
|
||||
|
||||
signed sPPU::Background::clip(signed n) {
|
||||
//13-bit sign extend: --s---nnnnnnnnnn -> ssssssnnnnnnnnnn
|
||||
return n & 0x2000 ? (n | ~1023) : (n & 1023);
|
||||
}
|
||||
|
||||
void sPPU::Background::run_mode7(unsigned x, unsigned y) {
|
||||
signed a = sclip<16>(self.regs.m7a);
|
||||
signed b = sclip<16>(self.regs.m7b);
|
||||
signed c = sclip<16>(self.regs.m7c);
|
||||
signed d = sclip<16>(self.regs.m7d);
|
||||
|
||||
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);
|
||||
|
||||
if(self.regs.mode7_hflip) x = 255 - x;
|
||||
if(self.regs.mode7_vflip) y = 255 - y;
|
||||
|
||||
unsigned mosaic_x;
|
||||
unsigned mosaic_y;
|
||||
if(id == ID::BG1) {
|
||||
mosaic_x = mosaic_table[self.bg1.regs.mosaic][x];
|
||||
mosaic_y = mosaic_table[self.bg1.regs.mosaic][y];
|
||||
} else if(id == ID::BG2) {
|
||||
mosaic_x = mosaic_table[self.bg2.regs.mosaic][x];
|
||||
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 px = psx + (a * mosaic_x);
|
||||
signed py = psy + (c * mosaic_x);
|
||||
|
||||
//mask pseudo-FP bits
|
||||
px >>= 8;
|
||||
py >>= 8;
|
||||
|
||||
unsigned tile;
|
||||
unsigned palette;
|
||||
switch(self.regs.mode7_repeat) {
|
||||
//screen repetition outside of screen area
|
||||
case 0:
|
||||
case 1: {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
|
||||
//palette color 0 outside of screen area
|
||||
case 2: {
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
palette = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
}
|
||||
} break;
|
||||
|
||||
//character 0 repetition outside of screen area
|
||||
case 3: {
|
||||
if(px < 0 || px > 1023 || py < 0 || py > 1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = memory::vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
}
|
||||
palette = memory::vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
} break;
|
||||
}
|
||||
|
||||
unsigned priority;
|
||||
if(id == ID::BG1) {
|
||||
priority = regs.priority0;
|
||||
} else if(id == ID::BG2) {
|
||||
priority = (palette & 0x80 ? regs.priority1 : regs.priority0);
|
||||
palette &= 0x7f;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
#ifdef SPPU_CPP
|
||||
|
||||
bool sPPUDebugger::interlace() { return false; }
|
||||
bool sPPUDebugger::overscan() { return false; }
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
class sPPUDebugger : public sPPU, public PPUDebugger {
|
||||
public:
|
||||
bool bg1_enabled[2];
|
||||
bool bg2_enabled[2];
|
||||
bool bg3_enabled[2];
|
||||
bool bg4_enabled[2];
|
||||
bool oam_enabled[4];
|
||||
|
||||
bool interlace();
|
||||
bool overscan();
|
||||
};
|
|
@ -18,20 +18,27 @@ uint16 sPPU::get_vram_address() {
|
|||
}
|
||||
|
||||
uint8 sPPU::vram_read(unsigned addr) {
|
||||
return memory::vram[addr];
|
||||
if(regs.display_disabled || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
||||
return memory::vram[addr];
|
||||
}
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void sPPU::vram_write(unsigned addr, uint8 data) {
|
||||
memory::vram[addr] = data;
|
||||
if(regs.display_disabled || vcounter() >= (!regs.overscan ? 225 : 240)) {
|
||||
memory::vram[addr] = data;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 sPPU::oam_read(unsigned addr) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disabled && vcounter() < (!regs.overscan ? 225 : 240)) addr = 0x0218;
|
||||
return memory::oam[addr];
|
||||
}
|
||||
|
||||
void sPPU::oam_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x0200) addr &= 0x021f;
|
||||
if(!regs.display_disabled && vcounter() < (!regs.overscan ? 225 : 240)) addr = 0x0218;
|
||||
memory::oam[addr] = data;
|
||||
}
|
||||
|
||||
|
@ -44,11 +51,11 @@ void sPPU::cgram_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
|
||||
bool sPPU::interlace() const {
|
||||
return false;
|
||||
return display.interlace;
|
||||
}
|
||||
|
||||
bool sPPU::overscan() const {
|
||||
return false;
|
||||
return regs.overscan;
|
||||
}
|
||||
|
||||
bool sPPU::hires() const {
|
||||
|
@ -185,6 +192,22 @@ void sPPU::mmio_w2105(uint8 data) {
|
|||
} break;
|
||||
|
||||
case 7: {
|
||||
if(regs.mode7_extbg == false) {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Inactive;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 2; bg1.regs.priority1 = 2;
|
||||
oam.regs.priority0 = 1; oam.regs.priority1 = 3; oam.regs.priority2 = 4; oam.regs.priority3 = 5;
|
||||
} else {
|
||||
bg1.regs.mode = Background::Mode::Mode7;
|
||||
bg2.regs.mode = Background::Mode::Mode7;
|
||||
bg3.regs.mode = Background::Mode::Inactive;
|
||||
bg4.regs.mode = Background::Mode::Inactive;
|
||||
bg1.regs.priority0 = 3; bg1.regs.priority1 = 3;
|
||||
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
|
||||
oam.regs.priority0 = 2; oam.regs.priority1 = 4; oam.regs.priority2 = 6; oam.regs.priority3 = 7;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
@ -236,12 +259,18 @@ void sPPU::mmio_w210c(uint8 data) {
|
|||
|
||||
//BG1HOFS
|
||||
void sPPU::mmio_w210d(uint8 data) {
|
||||
regs.m7hofs = (data << 8) | regs.m7_latchdata;
|
||||
regs.m7_latchdata = data;
|
||||
|
||||
bg1.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg1.regs.hoffset >> 8) & 7);
|
||||
regs.bgofs_latchdata = data;
|
||||
}
|
||||
|
||||
//BG1VOFS
|
||||
void sPPU::mmio_w210e(uint8 data) {
|
||||
regs.m7vofs = (data << 8) | regs.m7_latchdata;
|
||||
regs.m7_latchdata = data;
|
||||
|
||||
bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
|
||||
regs.bgofs_latchdata = data;
|
||||
}
|
||||
|
@ -326,7 +355,11 @@ void sPPU::mmio_w2119(uint8 data) {
|
|||
if(regs.vram_incmode == 1) regs.vram_addr += regs.vram_incsize;
|
||||
}
|
||||
|
||||
//M7SEL
|
||||
void sPPU::mmio_w211a(uint8 data) {
|
||||
regs.mode7_repeat = (data >> 6) & 3;
|
||||
regs.mode7_vflip = data & 0x02;
|
||||
regs.mode7_hflip = data & 0x01;
|
||||
}
|
||||
|
||||
//M7A
|
||||
|
@ -517,7 +550,11 @@ void sPPU::mmio_w2132(uint8 data) {
|
|||
|
||||
//SETINI
|
||||
void sPPU::mmio_w2133(uint8 data) {
|
||||
regs.mode7_extbg = data & 0x40;
|
||||
regs.pseudo_hires = data & 0x08;
|
||||
regs.overscan = data & 0x04;
|
||||
oam.regs.interlace = data & 0x02;
|
||||
regs.interlace = data & 0x01;
|
||||
}
|
||||
|
||||
//MPYL
|
||||
|
@ -671,6 +708,12 @@ void sPPU::mmio_reset() {
|
|||
regs.bg3_priority = false;
|
||||
regs.bgmode = 0;
|
||||
|
||||
//$210d BG1HOFS
|
||||
regs.m7hofs = 0x0000;
|
||||
|
||||
//$210e BG1VOFS
|
||||
regs.m7vofs = 0x0000;
|
||||
|
||||
//$2115 VMAIN
|
||||
regs.vram_incmode = 1;
|
||||
regs.vram_mapping = 0;
|
||||
|
@ -680,6 +723,11 @@ void sPPU::mmio_reset() {
|
|||
//$2117 VMADDH
|
||||
regs.vram_addr = 0x0000;
|
||||
|
||||
//$211a M7SEL
|
||||
regs.mode7_repeat = 0;
|
||||
regs.mode7_vflip = false;
|
||||
regs.mode7_hflip = false;
|
||||
|
||||
//$211b M7A
|
||||
regs.m7a = 0x0000;
|
||||
|
||||
|
@ -701,6 +749,12 @@ void sPPU::mmio_reset() {
|
|||
//$2121 CGADD
|
||||
regs.cgram_addr = 0x0000;
|
||||
|
||||
//$2133 SETINI
|
||||
regs.mode7_extbg = false;
|
||||
regs.pseudo_hires = false;
|
||||
regs.overscan = false;
|
||||
regs.interlace = false;
|
||||
|
||||
//$213c OPHCT
|
||||
regs.hcounter = 0;
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@ struct {
|
|||
bool bg3_priority;
|
||||
uint8 bgmode;
|
||||
|
||||
//$210d BG1HOFS
|
||||
uint16 m7hofs;
|
||||
|
||||
//$210e BG1VOFS
|
||||
uint16 m7vofs;
|
||||
|
||||
//$2115 VMAIN
|
||||
bool vram_incmode;
|
||||
uint8 vram_mapping;
|
||||
|
@ -34,6 +40,11 @@ struct {
|
|||
//$2117 VMADDH
|
||||
uint16 vram_addr;
|
||||
|
||||
//$211a M7SEL
|
||||
uint8 mode7_repeat;
|
||||
bool mode7_vflip;
|
||||
bool mode7_hflip;
|
||||
|
||||
//$211b M7A
|
||||
uint16 m7a;
|
||||
|
||||
|
@ -55,6 +66,12 @@ struct {
|
|||
//$2121 CGADD
|
||||
uint16 cgram_addr;
|
||||
|
||||
//$2133 SETINI
|
||||
bool mode7_extbg;
|
||||
bool pseudo_hires;
|
||||
bool overscan;
|
||||
bool interlace;
|
||||
|
||||
//$213c OPHCT
|
||||
uint16 hcounter;
|
||||
|
||||
|
|
|
@ -2,109 +2,156 @@
|
|||
|
||||
void sPPU::Screen::scanline() {
|
||||
output = self.output + self.vcounter() * 1024;
|
||||
if(self.display.interlace && self.field() == 1) output += 512;
|
||||
}
|
||||
|
||||
void sPPU::Screen::run() {
|
||||
uint16 color;
|
||||
if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
color = get_pixel(false);
|
||||
*output++ = color;
|
||||
*output++ = color;
|
||||
} else {
|
||||
color = get_pixel(true);
|
||||
*output++ = color;
|
||||
color = get_pixel(false);
|
||||
*output++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 sPPU::Screen::get_pixel(bool swap) {
|
||||
enum source_t { BG1, BG2, BG3, BG4, OAM, BACK };
|
||||
bool color_enable[] = { regs.bg1_color_enable, regs.bg2_color_enable, regs.bg3_color_enable, regs.bg4_color_enable, regs.oam_color_enable, regs.back_color_enable };
|
||||
|
||||
//===========
|
||||
//main screen
|
||||
//===========
|
||||
|
||||
unsigned priority_main = 0;
|
||||
unsigned color_main;
|
||||
unsigned source_main;
|
||||
|
||||
if(self.bg1.output.main.valid) {
|
||||
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);
|
||||
} 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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
priority_main = self.oam.output.main.priority;
|
||||
color_main = get_color(self.oam.output.main.palette);
|
||||
source_main = OAM;
|
||||
}
|
||||
if(priority_main == 0) {
|
||||
color_main = get_color(0);
|
||||
source_main = BACK;
|
||||
}
|
||||
|
||||
//==========
|
||||
//sub screen
|
||||
//==========
|
||||
|
||||
unsigned priority_sub = 0;
|
||||
uint16 color_sub;
|
||||
source_t source_sub;
|
||||
unsigned color_sub;
|
||||
unsigned source_sub;
|
||||
|
||||
if(self.bg1.output.sub.valid) {
|
||||
priority_sub = self.bg1.output.sub.priority;
|
||||
color_sub = self.bg1.output.sub.color;
|
||||
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);
|
||||
} 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) {
|
||||
priority_sub = self.bg2.output.sub.priority;
|
||||
color_sub = self.bg2.output.sub.color;
|
||||
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) {
|
||||
priority_sub = self.bg3.output.sub.priority;
|
||||
color_sub = self.bg3.output.sub.color;
|
||||
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) {
|
||||
priority_sub = self.bg4.output.sub.priority;
|
||||
color_sub = self.bg4.output.sub.color;
|
||||
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) {
|
||||
priority_sub = self.oam.output.sub.priority;
|
||||
color_sub = self.oam.output.sub.color;
|
||||
color_sub = get_color(self.oam.output.sub.palette);
|
||||
source_sub = OAM;
|
||||
}
|
||||
if(priority_sub == 0) {
|
||||
if(self.regs.bgmode == 5 || self.regs.bgmode == 6) {
|
||||
color_sub = memory::cgram[0] + (memory::cgram[1] << 8);
|
||||
color_sub = get_color(0);
|
||||
} else {
|
||||
color_sub = regs.color_rgb;
|
||||
}
|
||||
source_sub = BACK;
|
||||
}
|
||||
|
||||
unsigned priority_main = 0;
|
||||
uint16 color_main;
|
||||
source_t source_main;
|
||||
if(swap == true) {
|
||||
nall::swap(priority_main, priority_sub);
|
||||
nall::swap(color_main, color_sub);
|
||||
nall::swap(source_main, source_sub);
|
||||
}
|
||||
|
||||
if(self.bg1.output.main.valid) {
|
||||
priority_main = self.bg1.output.main.priority;
|
||||
color_main = self.bg1.output.main.color;
|
||||
source_main = BG1;
|
||||
if(regs.bg1_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub);
|
||||
}
|
||||
if(self.bg2.output.main.valid && self.bg2.output.main.priority > priority_main) {
|
||||
priority_main = self.bg2.output.main.priority;
|
||||
color_main = self.bg2.output.main.color;
|
||||
source_main = BG2;
|
||||
if(regs.bg2_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub);
|
||||
}
|
||||
if(self.bg3.output.main.valid && self.bg3.output.main.priority > priority_main) {
|
||||
priority_main = self.bg3.output.main.priority;
|
||||
color_main = self.bg3.output.main.color;
|
||||
source_main = BG3;
|
||||
if(regs.bg3_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub);
|
||||
}
|
||||
if(self.bg4.output.main.valid && self.bg4.output.main.priority > priority_main) {
|
||||
priority_main = self.bg4.output.main.priority;
|
||||
color_main = self.bg4.output.main.color;
|
||||
source_main = BG4;
|
||||
if(regs.bg4_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub);
|
||||
}
|
||||
if(self.oam.output.main.valid && self.oam.output.main.priority > priority_main) {
|
||||
priority_main = self.oam.output.main.priority;
|
||||
color_main = self.oam.output.main.color;
|
||||
source_main = OAM;
|
||||
if(self.oam.output.main.palette >= 192) {
|
||||
if(regs.oam_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub);
|
||||
}
|
||||
}
|
||||
if(priority_main == 0) {
|
||||
color_main = memory::cgram[0] + (memory::cgram[1] << 8);
|
||||
source_main = BACK;
|
||||
if(regs.back_color_enable && self.window.output.sub.color_enable) color_main = addsub(color_main, color_sub, !regs.addsub_mode || source_sub != BACK);
|
||||
uint16 output;
|
||||
if(!regs.addsub_mode) {
|
||||
source_sub = BACK;
|
||||
color_sub = regs.color_rgb;
|
||||
}
|
||||
|
||||
if(self.window.output.main.color_enable == false) {
|
||||
if(self.window.output.sub.color_enable == false) {
|
||||
color_main = 0x0000;
|
||||
goto plot;
|
||||
return 0x0000;
|
||||
}
|
||||
color_main = 0x0000;
|
||||
}
|
||||
|
||||
color_main = light_table[self.regs.display_brightness][color_main];
|
||||
if(self.regs.display_disabled) color_main = 0;
|
||||
plot:
|
||||
*output++ = color_main;
|
||||
*output++ = color_main;
|
||||
bool color_exempt = (source_main == OAM && self.oam.output.main.palette < 192);
|
||||
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;
|
||||
}
|
||||
output = addsub(color_main, color_sub, halve);
|
||||
} else {
|
||||
output = color_main;
|
||||
}
|
||||
|
||||
//========
|
||||
//lighting
|
||||
//========
|
||||
|
||||
output = light_table[self.regs.display_brightness][output];
|
||||
if(self.regs.display_disabled) output = 0x0000;
|
||||
return output;
|
||||
}
|
||||
|
||||
uint16 sPPU::Screen::addsub(unsigned x, unsigned y, bool allow_halve) {
|
||||
bool halve = allow_halve && regs.color_halve && self.window.output.main.color_enable;
|
||||
|
||||
uint16 sPPU::Screen::addsub(unsigned x, unsigned y, bool halve) {
|
||||
if(!regs.color_mode) {
|
||||
if(!halve) {
|
||||
unsigned sum = x + y;
|
||||
|
@ -124,6 +171,36 @@ uint16 sPPU::Screen::addsub(unsigned x, unsigned y, bool allow_halve) {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void sPPU::Screen::reset() {
|
||||
regs.addsub_mode = 0;
|
||||
regs.direct_color = 0;
|
||||
regs.color_mode = 0;
|
||||
regs.color_halve = 0;
|
||||
regs.bg1_color_enable = 0;
|
||||
regs.bg2_color_enable = 0;
|
||||
regs.bg3_color_enable = 0;
|
||||
regs.bg4_color_enable = 0;
|
||||
regs.oam_color_enable = 0;
|
||||
regs.back_color_enable = 0;
|
||||
regs.color_r = 0;
|
||||
regs.color_g = 0;
|
||||
regs.color_b = 0;
|
||||
regs.color_rgb = 0;
|
||||
}
|
||||
|
||||
sPPU::Screen::Screen(sPPU &self) : self(self) {
|
||||
//generate light table
|
||||
for(unsigned l = 0; l < 16; l++) {
|
||||
|
|
|
@ -24,10 +24,14 @@ public:
|
|||
|
||||
void scanline();
|
||||
void run();
|
||||
void reset();
|
||||
|
||||
Screen(sPPU &self);
|
||||
|
||||
private:
|
||||
uint16 light_table[16][32768];
|
||||
uint16 addsub(unsigned x, unsigned y, bool allow_halve = true);
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -9,10 +9,11 @@ namespace SNES {
|
|||
#include "sprite/sprite.cpp"
|
||||
#include "window/window.cpp"
|
||||
|
||||
#if !defined(DEBUGGER)
|
||||
sPPU ppu;
|
||||
#else
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.cpp"
|
||||
sPPUDebugger ppu;
|
||||
#else
|
||||
sPPU ppu;
|
||||
#endif
|
||||
|
||||
void sPPU::enter() {
|
||||
|
@ -21,8 +22,14 @@ void sPPU::enter() {
|
|||
|
||||
add_clocks(88);
|
||||
|
||||
if(vcounter() >= 1 && vcounter() <= 224) {
|
||||
if(vcounter() >= 1 && vcounter() <= (!regs.overscan ? 224 : 239)) {
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
bg1.run();
|
||||
bg2.run();
|
||||
bg3.run();
|
||||
bg4.run();
|
||||
add_clocks(2);
|
||||
|
||||
bg1.run();
|
||||
bg2.run();
|
||||
bg3.run();
|
||||
|
@ -30,7 +37,7 @@ void sPPU::enter() {
|
|||
oam.run();
|
||||
window.run();
|
||||
screen.run();
|
||||
add_clocks(4);
|
||||
add_clocks(2);
|
||||
}
|
||||
} else {
|
||||
add_clocks(1024);
|
||||
|
@ -51,6 +58,10 @@ void sPPU::add_clocks(unsigned clocks) {
|
|||
|
||||
void sPPU::power() {
|
||||
PPU::power();
|
||||
memset(memory::vram.data(), 0x00, memory::vram.size());
|
||||
memset(memory::oam.data(), 0x00, memory::oam.size());
|
||||
memset(memory::cgram.data(), 0x00, memory::cgram.size());
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -60,6 +71,13 @@ void sPPU::reset() {
|
|||
|
||||
memset(output, 0x00, 512 * 480 * sizeof(uint16));
|
||||
mmio_reset();
|
||||
bg1.reset();
|
||||
bg2.reset();
|
||||
bg3.reset();
|
||||
bg4.reset();
|
||||
oam.reset();
|
||||
window.reset();
|
||||
screen.reset();
|
||||
}
|
||||
|
||||
void sPPU::scanline() {
|
||||
|
@ -77,6 +95,8 @@ void sPPU::frame() {
|
|||
PPU::frame();
|
||||
system.frame();
|
||||
oam.frame();
|
||||
|
||||
display.interlace = regs.interlace;
|
||||
}
|
||||
|
||||
sPPU::sPPU() :
|
||||
|
|
|
@ -14,6 +14,10 @@ public:
|
|||
Window window;
|
||||
Screen screen;
|
||||
|
||||
struct {
|
||||
bool interlace;
|
||||
} display;
|
||||
|
||||
void enter();
|
||||
void add_clocks(unsigned);
|
||||
|
||||
|
@ -26,19 +30,9 @@ public:
|
|||
sPPU();
|
||||
};
|
||||
|
||||
#if !defined(DEBUGGER)
|
||||
extern sPPU ppu;
|
||||
#if defined(DEBUGGER)
|
||||
#include "debugger/debugger.hpp"
|
||||
extern sPPUDebugger ppu;
|
||||
#else
|
||||
class sPPUDebugger : public sPPU, public PPUDebugger {
|
||||
public:
|
||||
bool bg1_enabled[2];
|
||||
bool bg2_enabled[2];
|
||||
bool bg3_enabled[2];
|
||||
bool bg4_enabled[2];
|
||||
bool oam_enabled[4];
|
||||
|
||||
inline bool interlace() { return false; }
|
||||
inline bool overscan() { return false; }
|
||||
};
|
||||
extern sPPUDebugger ppu;
|
||||
extern sPPU ppu;
|
||||
#endif
|
||||
|
|
|
@ -45,9 +45,11 @@ void sPPU::Sprite::scanline() {
|
|||
break;
|
||||
case 6: list[i].width = (!size ? 16 : 32);
|
||||
list[i].height = (!size ? 32 : 64);
|
||||
if(regs.interlace && !size) list[i].height = 16;
|
||||
break;
|
||||
case 7: list[i].width = (!size ? 16 : 32);
|
||||
list[i].height = (!size ? 32 : 32);
|
||||
if(regs.interlace && !size) list[i].height = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -100,21 +102,17 @@ void sPPU::Sprite::run() {
|
|||
|
||||
if(state.output_priority[x] != 0xff) {
|
||||
unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
|
||||
unsigned priority = priority_table[state.output_priority[x]];
|
||||
unsigned palette = state.output_palette[x] << 1;
|
||||
|
||||
if(regs.main_enabled) {
|
||||
output.main.valid = true;
|
||||
output.main.color = memory::cgram[palette + 0] + (memory::cgram[palette + 1] << 8);
|
||||
output.main.palette = state.output_palette[x];
|
||||
output.main.priority = priority;
|
||||
output.main.priority = priority_table[state.output_priority[x]];
|
||||
}
|
||||
|
||||
if(regs.sub_enabled) {
|
||||
output.sub.valid = true;
|
||||
output.sub.color = memory::cgram[palette + 0] + (memory::cgram[palette + 1] << 8);
|
||||
output.sub.palette = state.output_palette[x];
|
||||
output.sub.priority = priority;
|
||||
output.sub.priority = priority_table[state.output_priority[x]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +132,7 @@ void sPPU::Sprite::load_tiles() {
|
|||
unsigned tile_width = sprite.width >> 3;
|
||||
signed x = sprite.x;
|
||||
signed y = (state.y - sprite.y) & 0xff;
|
||||
if(regs.interlace) y <<= 1;
|
||||
|
||||
if(sprite.vflip) {
|
||||
if(sprite.width == sprite.height) {
|
||||
|
@ -210,6 +209,56 @@ void sPPU::Sprite::render_tile(unsigned tile) {
|
|||
}
|
||||
}
|
||||
|
||||
void sPPU::Sprite::reset() {
|
||||
regs.main_enabled = 0;
|
||||
regs.sub_enabled = 0;
|
||||
regs.interlace = 0;
|
||||
regs.base_size = 0;
|
||||
regs.nameselect = 0;
|
||||
regs.tiledata_addr = 0;
|
||||
regs.first_sprite = 0;
|
||||
regs.priority0 = 0;
|
||||
regs.priority1 = 0;
|
||||
regs.priority2 = 0;
|
||||
regs.priority3 = 0;
|
||||
regs.time_over = 0;
|
||||
regs.range_over = 0;
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
list[i].width = 0;
|
||||
list[i].height = 0;
|
||||
list[i].x = 0;
|
||||
list[i].y = 0;
|
||||
list[i].character = 0;
|
||||
list[i].nameselect = 0;
|
||||
list[i].vflip = 0;
|
||||
list[i].hflip = 0;
|
||||
list[i].palette = 0;
|
||||
list[i].priority = 0;
|
||||
}
|
||||
state.x = 0;
|
||||
state.y = 0;
|
||||
state.item_count = 0;
|
||||
state.tile_count = 0;
|
||||
memset(state.output_palette, 0, 256);
|
||||
memset(state.output_priority, 0, 256);
|
||||
memset(state.item_list, 0, 32);
|
||||
for(unsigned i = 0; i < 34; i++) {
|
||||
state.tile_list[i].x = 0;
|
||||
state.tile_list[i].y = 0;
|
||||
state.tile_list[i].priority = 0;
|
||||
state.tile_list[i].palette = 0;
|
||||
state.tile_list[i].tile = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
sPPU::Sprite::Sprite(sPPU &self) : self(self) {
|
||||
}
|
||||
|
||||
|
|
|
@ -59,9 +59,8 @@ public:
|
|||
struct {
|
||||
struct {
|
||||
bool valid;
|
||||
uint16 color;
|
||||
unsigned palette;
|
||||
unsigned priority;
|
||||
uint8 palette;
|
||||
uint8 priority;
|
||||
} main, sub;
|
||||
} output;
|
||||
|
||||
|
@ -69,6 +68,7 @@ public:
|
|||
void frame();
|
||||
void scanline();
|
||||
void run();
|
||||
void reset();
|
||||
|
||||
Sprite(sPPU &self);
|
||||
|
||||
|
|
|
@ -109,6 +109,58 @@ void sPPU::Window::test(
|
|||
sub = sub_enable ? output : false;
|
||||
}
|
||||
|
||||
void sPPU::Window::reset() {
|
||||
regs.bg1_one_enable = false;
|
||||
regs.bg1_one_invert = false;
|
||||
regs.bg1_two_enable = false;
|
||||
regs.bg1_two_invert = false;
|
||||
regs.bg2_one_enable = false;
|
||||
regs.bg2_one_invert = false;
|
||||
regs.bg2_two_enable = false;
|
||||
regs.bg2_two_invert = false;
|
||||
regs.bg3_one_enable = false;
|
||||
regs.bg3_one_invert = false;
|
||||
regs.bg3_two_enable = false;
|
||||
regs.bg3_two_invert = false;
|
||||
regs.bg4_one_enable = false;
|
||||
regs.bg4_one_invert = false;
|
||||
regs.bg4_two_enable = false;
|
||||
regs.bg4_two_invert = false;
|
||||
regs.oam_one_enable = false;
|
||||
regs.oam_one_invert = false;
|
||||
regs.oam_two_enable = false;
|
||||
regs.oam_two_invert = false;
|
||||
regs.col_one_enable = false;
|
||||
regs.col_one_invert = false;
|
||||
regs.col_two_enable = false;
|
||||
regs.col_two_invert = false;
|
||||
regs.one_left = 0;
|
||||
regs.one_right = 0;
|
||||
regs.two_left = 0;
|
||||
regs.two_right = 0;
|
||||
regs.bg1_mask = 0;
|
||||
regs.bg2_mask = 0;
|
||||
regs.bg3_mask = 0;
|
||||
regs.bg4_mask = 0;
|
||||
regs.oam_mask = 0;
|
||||
regs.col_mask = 0;
|
||||
regs.bg1_main_enable = 0;
|
||||
regs.bg1_sub_enable = 0;
|
||||
regs.bg2_main_enable = 0;
|
||||
regs.bg2_sub_enable = 0;
|
||||
regs.bg3_main_enable = 0;
|
||||
regs.bg3_sub_enable = 0;
|
||||
regs.bg4_main_enable = 0;
|
||||
regs.bg4_sub_enable = 0;
|
||||
regs.oam_main_enable = 0;
|
||||
regs.oam_sub_enable = 0;
|
||||
regs.col_main_mask = 0;
|
||||
regs.col_sub_mask = 0;
|
||||
state.x = 0;
|
||||
output.main.color_enable = 0;
|
||||
output.sub.color_enable = 0;
|
||||
}
|
||||
|
||||
sPPU::Window::Window(sPPU &self) : self(self) {
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
|
||||
void scanline();
|
||||
void run();
|
||||
void reset();
|
||||
|
||||
Window(sPPU &self);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
static const char bsnesVersion[] = "063.09";
|
||||
static const char bsnesVersion[] = "063.10";
|
||||
static const char bsnesTitle[] = "bsnes";
|
||||
static const unsigned bsnesSerializerVersion = 9;
|
||||
|
||||
|
|
Loading…
Reference in New Issue