Update to v068r14 release.

byuu says:

Holy hell, that was a total brain twister. After hours of crazy bit
twiddling and debug printf's, I finally figured out how to allow both
lores and hires scrolling in the accurate PPU renderer. In the process,
I modified the main loop to run from -7 to 255, regardless of the hires
setting, and perform X adjustment inside the tile fetching. This fixed
a strange main/subscreen misalignment issue, so I was able to restore
the proper sub-then-main rendering for the final screen output stage.
Code looks a good bit cleaner this way overall.

I also added load state and save state menus to the tools menu, so you
can use the menubar to load and save to ten slots. I am thinking that
I should nuke the icons. As pretty as they are, it's getting tiresome
trying to find icons for everything, I have no pictures to represent
loading or saving a slot, nor to represent individual slots. I'll just
stick to radios and checkboxes.
This commit is contained in:
Tim Allen
2010-09-06 09:08:03 +10:00
parent 3f43747474
commit 3a81ac94a5
10 changed files with 91 additions and 52 deletions

View File

@@ -1,6 +1,6 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
profile := performance profile := accuracy
ui := qt ui := qt
# compiler # compiler

View File

@@ -174,6 +174,24 @@ MainWindow::MainWindow() {
tools->addSeparator(); tools->addSeparator();
tools_loadState = tools->addMenu("Load Quick State");
for(unsigned i = 0; i < 10; i++) {
QAction *loadAction = new QAction(string("Slot ", i + 1), 0);
loadAction->setData(i);
connect(loadAction, SIGNAL(triggered()), this, SLOT(loadState()));
tools_loadState->addAction(loadAction);
}
tools_saveState = tools->addMenu("Save Quick State");
for(unsigned i = 0; i < 10; i++) {
QAction *saveAction = new QAction(string("Slot ", i + 1), 0);
saveAction->setData(i);
connect(saveAction, SIGNAL(triggered()), this, SLOT(saveState()));
tools_saveState->addAction(saveAction);
}
tools->addSeparator();
tools_cheatEditor = tools->addAction("Cheat &Editor ..."); tools_cheatEditor = tools->addAction("Cheat &Editor ...");
tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png")); tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
@@ -581,6 +599,20 @@ void MainWindow::saveScreenshot() {
interface.saveScreenshot = true; interface.saveScreenshot = true;
} }
void MainWindow::loadState() {
QAction *action = dynamic_cast<QAction*>(sender());
if(action == 0) return;
unsigned slot = action->data().toUInt();
state.load(slot);
}
void MainWindow::saveState() {
QAction *action = dynamic_cast<QAction*>(sender());
if(action == 0) return;
unsigned slot = action->data().toUInt();
state.save(slot);
}
void MainWindow::showCheatEditor() { toolsWindow->tab->setCurrentIndex(0); toolsWindow->show(); } void MainWindow::showCheatEditor() { toolsWindow->tab->setCurrentIndex(0); toolsWindow->show(); }
void MainWindow::showCheatFinder() { toolsWindow->tab->setCurrentIndex(1); toolsWindow->show(); } void MainWindow::showCheatFinder() { toolsWindow->tab->setCurrentIndex(1); toolsWindow->show(); }
void MainWindow::showStateManager() { toolsWindow->tab->setCurrentIndex(2); toolsWindow->show(); } void MainWindow::showStateManager() { toolsWindow->tab->setCurrentIndex(2); toolsWindow->show(); }

View File

@@ -80,6 +80,8 @@ public:
QAction *tools_movies_recordFromPowerOn; QAction *tools_movies_recordFromPowerOn;
QAction *tools_movies_recordFromHere; QAction *tools_movies_recordFromHere;
QAction *tools_captureScreenshot; QAction *tools_captureScreenshot;
QMenu *tools_loadState;
QMenu *tools_saveState;
QAction *tools_cheatEditor; QAction *tools_cheatEditor;
QAction *tools_cheatFinder; QAction *tools_cheatFinder;
QAction *tools_stateManager; QAction *tools_stateManager;
@@ -150,6 +152,8 @@ public slots:
void recordMovieFromPowerOn(); void recordMovieFromPowerOn();
void recordMovieFromHere(); void recordMovieFromHere();
void saveScreenshot(); void saveScreenshot();
void loadState();
void saveState();
void showCheatEditor(); void showCheatEditor();
void showCheatFinder(); void showCheatFinder();
void showStateManager(); void showStateManager();

View File

@@ -7,9 +7,9 @@ void PPU::Background::frame() {
void PPU::Background::scanline() { void PPU::Background::scanline() {
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6); bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
x = -8 << hires; x = -7;
y = self.vcounter(); y = self.vcounter();
edge = 7 - (regs.hoffset & 7); tile_counter = (7 - (regs.hoffset & 7)) << hires;
for(unsigned n = 0; n < 8; n++) data[n] = 0; for(unsigned n = 0; n < 8; n++) data[n] = 0;
if(self.vcounter() == 1) { if(self.vcounter() == 1) {
@@ -36,7 +36,7 @@ void PPU::Background::get_tile() {
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 = 256 << hires;
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;
@@ -45,7 +45,7 @@ void PPU::Background::get_tile() {
mask_x--; mask_x--;
mask_y--; mask_y--;
unsigned px = x; unsigned px = x << hires;
unsigned py = mosaic_voffset; unsigned py = mosaic_voffset;
unsigned hscroll = regs.hoffset; unsigned hscroll = regs.hoffset;
@@ -59,24 +59,24 @@ void PPU::Background::get_tile() {
unsigned voffset = vscroll + py; 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 offset_x = (x + (hscroll & 7));
if(opt_x >= 8) { if(offset_x >= 8) {
unsigned hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0); unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
unsigned vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8); unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : 0x4000); unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);
if(self.regs.bgmode == 4) { if(self.regs.bgmode == 4) {
if(hval & opt_valid_bit) { if(hval & valid_mask) {
if(!(hval & 0x8000)) { if((hval & 0x8000) == 0) {
hoffset = opt_x + (hval & ~7); hoffset = offset_x + (hval & ~7);
} else { } else {
voffset = y + hval; voffset = y + hval;
} }
} }
} else { } else {
if(hval & opt_valid_bit) hoffset = opt_x + (hval & ~7); if(hval & valid_mask) hoffset = offset_x + (hval & ~7);
if(vval & opt_valid_bit) voffset = y + vval; if(vval & valid_mask) voffset = y + vval;
} }
} }
} }
@@ -84,8 +84,8 @@ void PPU::Background::get_tile() {
hoffset &= mask_x; hoffset &= mask_x;
voffset &= mask_y; voffset &= mask_y;
unsigned screen_x = (regs.screen_size & 1 ? (32 << 5) : 0); unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0);
unsigned screen_y = (regs.screen_size & 2 ? (32 << 5) : 0); unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0);
if(regs.screen_size == 3) screen_y <<= 1; if(regs.screen_size == 3) screen_y <<= 1;
unsigned tx = hoffset >> tile_width; unsigned tx = hoffset >> tile_width;
@@ -126,21 +126,21 @@ void PPU::Background::get_tile() {
} }
if(mirror_x) for(unsigned n = 0; n < 8; n++) { if(mirror_x) for(unsigned n = 0; n < 8; n++) {
//reverse data bits in data[n]: 01234567 -> 76543210
data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0); data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0);
data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc); data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc);
data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa); data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa);
} }
} }
void PPU::Background::run() { void PPU::Background::run(bool screen) {
if(self.vcounter() == 0) return; 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) { if(screen == Screen::Sub) {
output.main.priority = 0; output.main.priority = 0;
output.sub.priority = 0; output.sub.priority = 0;
} else if(hires == false) { if(hires == false) return;
return;
} }
if(regs.mode == Mode::Inactive) return; if(regs.mode == Mode::Inactive) return;
@@ -148,7 +148,11 @@ void PPU::Background::run() {
if(regs.mode == Mode::Mode7) return run_mode7(); if(regs.mode == Mode::Mode7) return run_mode7();
if((x++ & 7) == edge) get_tile(); if(tile_counter-- == 0) {
tile_counter = 7;
get_tile();
}
if(screen == Screen::Main) x++;
uint8 palette = get_tile_color(); uint8 palette = get_tile_color();
if(x >= 0 && mosaic_hcounter++ >= regs.mosaic) { if(x >= 0 && mosaic_hcounter++ >= regs.mosaic) {
@@ -169,14 +173,13 @@ void PPU::Background::run() {
output.sub.palette = palette_index + mosaic_palette; output.sub.palette = palette_index + mosaic_palette;
output.sub.tile = tile; output.sub.tile = tile;
} }
} else { } else if(screen == Screen::Main) {
if(x & 1) {
if(regs.main_enable) { if(regs.main_enable) {
output.main.priority = priority; output.main.priority = priority;
output.main.palette = palette_index + mosaic_palette; output.main.palette = palette_index + mosaic_palette;
output.main.tile = tile; output.main.tile = tile;
} }
} else { } else if(screen == Screen::Sub) {
if(regs.sub_enable) { if(regs.sub_enable) {
output.sub.priority = priority; output.sub.priority = priority;
output.sub.palette = palette_index + mosaic_palette; output.sub.palette = palette_index + mosaic_palette;
@@ -184,7 +187,6 @@ void PPU::Background::run() {
} }
} }
} }
}
unsigned PPU::Background::get_tile_color() { unsigned PPU::Background::get_tile_color() {
unsigned color = 0; unsigned color = 0;
@@ -226,7 +228,6 @@ void PPU::Background::reset() {
x = 0; x = 0;
y = 0; y = 0;
edge = 0;
mosaic_vcounter = 0; mosaic_vcounter = 0;
mosaic_voffset = 0; mosaic_voffset = 0;
@@ -234,6 +235,7 @@ void PPU::Background::reset() {
mosaic_hoffset = 0; mosaic_hoffset = 0;
mosaic_palette = 0; mosaic_palette = 0;
tile_counter = 0;
tile = 0; tile = 0;
priority = 0; priority = 0;
palette_number = 0; palette_number = 0;

View File

@@ -5,6 +5,7 @@ class Background {
struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; }; struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; };
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 Screen { enum { Main, Sub }; };
struct Regs { struct Regs {
unsigned tiledata_addr; unsigned tiledata_addr;
@@ -35,7 +36,6 @@ class Background {
struct { struct {
signed x; signed x;
signed y; signed y;
signed edge;
unsigned mosaic_vcounter; unsigned mosaic_vcounter;
unsigned mosaic_voffset; unsigned mosaic_voffset;
@@ -43,6 +43,7 @@ class Background {
unsigned mosaic_hoffset; unsigned mosaic_hoffset;
unsigned mosaic_palette; unsigned mosaic_palette;
unsigned tile_counter;
unsigned tile; unsigned tile;
unsigned priority; unsigned priority;
unsigned palette_number; unsigned palette_number;
@@ -52,7 +53,7 @@ class Background {
void frame(); void frame();
void scanline(); void scanline();
void run(); void run(bool screen);
void reset(); void reset();
void get_tile(); void get_tile();

View File

@@ -16,7 +16,7 @@ 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);
if(++Background::x & ~255) return; if(Background::x++ & ~255) return;
unsigned x = mosaic_hoffset; unsigned x = mosaic_hoffset;
unsigned y = self.bg1.mosaic_voffset; //BG2 vertical mosaic uses BG1 mosaic size unsigned y = self.bg1.mosaic_voffset; //BG2 vertical mosaic uses BG1 mosaic size

View File

@@ -43,16 +43,16 @@ void PPU::enter() {
if(vcounter() <= (!regs.overscan ? 224 : 239)) { if(vcounter() <= (!regs.overscan ? 224 : 239)) {
add_clocks(4); add_clocks(4);
for(unsigned pixel = 1; pixel < 8 + 256; pixel++) { for(unsigned pixel = 1; pixel < 8 + 256; pixel++) {
bg1.run(); bg1.run(1);
bg2.run(); bg2.run(1);
bg3.run(); bg3.run(1);
bg4.run(); bg4.run(1);
add_clocks(2); add_clocks(2);
bg1.run(); bg1.run(0);
bg2.run(); bg2.run(0);
bg3.run(); bg3.run(0);
bg4.run(); bg4.run(0);
if(pixel >= 8) { if(pixel >= 8) {
oam.run(); oam.run();
window.run(); window.run();

View File

@@ -8,13 +8,13 @@ void PPU::Screen::scanline() {
void PPU::Screen::run() { void PPU::Screen::run() {
uint16 color; uint16 color;
if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) { if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
color = get_pixel(false); color = get_pixel(0);
*output++ = color; *output++ = color;
*output++ = color; *output++ = color;
} else { } else {
color = get_pixel(false); color = get_pixel(1);
*output++ = color; *output++ = color;
color = get_pixel(true); color = get_pixel(0);
*output++ = color; *output++ = color;
} }
} }

View File

@@ -115,7 +115,6 @@ void PPU::Background::serialize(serializer &s) {
s.integer(x); s.integer(x);
s.integer(y); s.integer(y);
s.integer(edge);
s.integer(mosaic_vcounter); s.integer(mosaic_vcounter);
s.integer(mosaic_voffset); s.integer(mosaic_voffset);
@@ -123,6 +122,7 @@ void PPU::Background::serialize(serializer &s) {
s.integer(mosaic_hoffset); s.integer(mosaic_hoffset);
s.integer(mosaic_palette); s.integer(mosaic_palette);
s.integer(tile_counter);
s.integer(tile); s.integer(tile);
s.integer(priority); s.integer(priority);
s.integer(palette_number); s.integer(palette_number);

View File

@@ -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.13"; static const char Version[] = "068.14";
static const unsigned SerializerVersion = 13; static const unsigned SerializerVersion = 13;
} }
} }