Update to bsnes v063r08 release.

No binary, this is just a point release.

I have basic lores BG1-4 rendering with mosaic added. No offset-per-
tile, no windowing, no color math (requires windowing), no sprites, no
hires, no interlace, no mode7.

It's enough to see how powerful the concept is already, though.
- Battle Blaze intro looks just fine (can't beat a battle because I
can't see my sprites or save states yet)
- Dai Kaijuu Monogatari II stat bar looks fine (no duplicated line)
- Super Metroid looks fine (no extra status bar line)
- Air Strike Patrol shows the translucent shadow for your plane (but
the left-hand scrolling is glitchy ... not sure what's up yet)

Speed is ... yeah, it's bad. About 50-60% speed. But it can get
better, I'm being really lazy and completely recomputing everything
for each pixel. A very large number of these operations can be cached.
I'm going to wait until the renderer matches the quality of the
scanline-renderer before optimizing; and I'm not going to push too far
on optimizing this (eg I probably won't bring back the tiledata
planar->packed conversion cache.)

I'm designing this similar to MooglyGuy's N64 renderer, putting each
component in its own class. So far I'm really liking the concept.
This commit is contained in:
byuu 2010-04-05 13:28:36 +00:00
parent b11f22f517
commit efa7879c6d
13 changed files with 485 additions and 38 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
snes_core = sMemory sCPU sSMP sDSP bPPU
snes_core = sMemory sCPU sSMP sDSP sPPU
snes_objects := libco
snes_objects += snes-system

View File

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

View File

@ -0,0 +1,174 @@
#ifdef SPPU_CPP
void sPPU::Background::run() {
output.main.valid = false;
output.sub.valid = false;
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 y = regs.mosaic_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);
unsigned palette_size = 2 << color_depth;
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 mask_x = (tile_height == 3 ? width : (width << 1));
unsigned mask_y = mask_x;
if(regs.screen_size & 1) mask_x <<= 1;
if(regs.screen_size & 2) mask_y <<= 1;
mask_x--;
mask_y--;
unsigned screen_y = (regs.screen_size & 2 ? (32 << 5) : 0);
unsigned screen_x = (regs.screen_size & 1 ? (32 << 5) : 0);
if(regs.screen_size == 3) screen_y <<= 1;
unsigned hscroll = regs.hoffset;
unsigned vscroll = regs.voffset;
if(hires) {
hscroll <<= 1;
}
unsigned hoffset = hscroll + mosaic_table[regs.mosaic][x];
unsigned voffset = vscroll + y;
hoffset &= mask_x;
voffset &= mask_y;
unsigned tile_number; {
unsigned tx = hoffset >> tile_width;
unsigned ty = voffset >> tile_height;
uint16 pos = ((ty & 0x1f) << 5) + (tx & 0x1f);
if(ty & 0x20) pos += screen_y;
if(tx & 0x20) pos += screen_x;
uint16 addr = regs.screen_addr + (pos << 1);
tile_number = memory::vram[addr + 0] + (memory::vram[addr + 1] << 8);
}
bool mirror_y = tile_number & 0x8000;
bool mirror_x = tile_number & 0x4000;
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;
if(tile_height == 4 && (bool)(voffset & 8) != mirror_y) tile_number += 16;
tile_number &= 0x03ff;
tile_number += tiledata_index;
tile_number &= tile_mask;
if(mirror_y) voffset ^= 7;
if(mirror_x) hoffset ^= 7;
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);
if(regs.main_enabled) {
output.main.valid = true;
output.main.color = output_color;
output.main.priority = priority;
}
if(regs.sub_enabled) {
output.sub.valid = true;
output.sub.color = output_color;
output.sub.priority = priority;
}
}
unsigned sPPU::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);
}
};
}
sPPU::Background::Background(sPPU &self, unsigned id) : self(self), id(id) {
//generate mosaic table
for(unsigned m = 0; m < 16; m++) {
for(unsigned x = 0; x < 4096; x++) {
mosaic_table[m][x] = (x / (m + 1)) * (m + 1);
}
}
regs.tiledata_addr = 0x0000;
regs.screen_addr = 0x0000;
regs.screen_size = ScreenSize::Size32x32;
regs.mosaic = 0;
regs.mosaic_y = 0;
regs.tile_size = TileSize::Size8x8;
regs.mode = Mode::BPP2;
regs.priority0 = 0;
regs.priority1 = 0;
regs.main_enabled = false;
regs.sub_enabled = false;
}
uint16 sPPU::Background::mosaic_table[16][4096];
#endif

View File

@ -0,0 +1,45 @@
class Background {
public:
sPPU &self;
struct ID { enum { BG1, BG2, BG3, BG4 }; };
unsigned id;
struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; };
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
struct TileSize { enum { Size8x8, Size16x16 }; };
struct {
unsigned tiledata_addr;
unsigned screen_addr;
unsigned screen_size;
unsigned mosaic;
unsigned mosaic_y;
bool tile_size;
unsigned mode;
unsigned priority0;
unsigned priority1;
bool main_enabled;
bool sub_enabled;
unsigned hoffset;
unsigned voffset;
} regs;
struct {
struct {
bool valid;
uint16 color;
unsigned priority;
} main, sub;
} output;
void run();
unsigned get_color(unsigned x, unsigned y, uint16 offset);
Background(sPPU &self, unsigned id);
private:
static uint16 mosaic_table[16][4096];
};

View File

@ -1,8 +1,8 @@
#ifdef SPPU_CPP
void sPPU::latch_counters() {
regs.hcounter = cpu.hdot();
regs.vcounter = cpu.vcounter();
regs.hcounter = hdot();
regs.vcounter = vcounter();
regs.counters_latched = true;
}
@ -96,52 +96,179 @@ void sPPU::mmio_w2104(uint8 data) {
regs.oam_firstsprite = (regs.oam_priority == false ? 0 : (regs.oam_addr >> 2) & 127);
}
//BGMODE
void sPPU::mmio_w2105(uint8 data) {
bg4.regs.tile_size = (data & 0x80);
bg3.regs.tile_size = (data & 0x40);
bg2.regs.tile_size = (data & 0x20);
bg1.regs.tile_size = (data & 0x10);
regs.bg3_priority = (data & 0x08);
regs.bgmode = (data & 0x07);
switch(regs.bgmode) {
case 0: {
bg1.regs.mode = Background::Mode::BPP2; bg1.regs.priority0 = 8; bg1.regs.priority1 = 11;
bg2.regs.mode = Background::Mode::BPP2; bg2.regs.priority0 = 7; bg2.regs.priority1 = 10;
bg3.regs.mode = Background::Mode::BPP2; bg3.regs.priority0 = 2; bg3.regs.priority1 = 5;
bg4.regs.mode = Background::Mode::BPP2; bg4.regs.priority0 = 1; bg4.regs.priority1 = 4;
} break;
case 1: {
bg1.regs.mode = Background::Mode::BPP4;
bg2.regs.mode = Background::Mode::BPP4;
bg3.regs.mode = Background::Mode::BPP2;
bg4.regs.mode = Background::Mode::Inactive;
if(regs.bg3_priority) {
bg1.regs.priority0 = 5; bg1.regs.priority1 = 8;
bg2.regs.priority0 = 4; bg2.regs.priority1 = 7;
bg3.regs.priority0 = 1; bg3.regs.priority1 = 10;
} else {
bg1.regs.priority0 = 6; bg1.regs.priority1 = 9;
bg2.regs.priority0 = 5; bg2.regs.priority1 = 8;
bg3.regs.priority0 = 1; bg3.regs.priority1 = 3;
}
} break;
case 2: {
bg1.regs.mode = Background::Mode::BPP4;
bg2.regs.mode = Background::Mode::BPP4;
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
} break;
case 3: {
bg1.regs.mode = Background::Mode::BPP8;
bg2.regs.mode = Background::Mode::BPP4;
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
} break;
case 4: {
bg1.regs.mode = Background::Mode::BPP8;
bg2.regs.mode = Background::Mode::BPP2;
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
} break;
case 5: {
bg1.regs.mode = Background::Mode::BPP4;
bg2.regs.mode = Background::Mode::BPP2;
bg3.regs.mode = Background::Mode::Inactive;
bg4.regs.mode = Background::Mode::Inactive;
bg1.regs.priority0 = 3; bg1.regs.priority1 = 7;
bg2.regs.priority0 = 1; bg2.regs.priority1 = 5;
} break;
case 6: {
bg1.regs.mode = Background::Mode::BPP4;
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 = 5;
} break;
case 7: {
} break;
}
}
//MOSAIC
void sPPU::mmio_w2106(uint8 data) {
regs.mosaic_size = (data >> 4) & 15;
bg4.regs.mosaic = (data & 0x08 ? regs.mosaic_size : 0);
bg3.regs.mosaic = (data & 0x04 ? regs.mosaic_size : 0);
bg2.regs.mosaic = (data & 0x02 ? regs.mosaic_size : 0);
bg1.regs.mosaic = (data & 0x01 ? regs.mosaic_size : 0);
}
//BG1SC
void sPPU::mmio_w2107(uint8 data) {
bg1.regs.screen_addr = (data & 0x7c) << 9;
bg1.regs.screen_size = data & 3;
}
//BG2SC
void sPPU::mmio_w2108(uint8 data) {
bg2.regs.screen_addr = (data & 0x7c) << 9;
bg2.regs.screen_size = data & 3;
}
//BG3SC
void sPPU::mmio_w2109(uint8 data) {
bg3.regs.screen_addr = (data & 0x7c) << 9;
bg3.regs.screen_size = data & 3;
}
//BG4SC
void sPPU::mmio_w210a(uint8 data) {
bg4.regs.screen_addr = (data & 0x7c) << 9;
bg4.regs.screen_size = data & 3;
}
//BG12NBA
void sPPU::mmio_w210b(uint8 data) {
bg1.regs.tiledata_addr = (data & 0x07) << 13;
bg2.regs.tiledata_addr = (data & 0x70) << 9;
}
//BG34NBA
void sPPU::mmio_w210c(uint8 data) {
bg3.regs.tiledata_addr = (data & 0x07) << 13;
bg4.regs.tiledata_addr = (data & 0x70) << 9;
}
//BG1HOFS
void sPPU::mmio_w210d(uint8 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) {
bg1.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_latchdata = data;
}
//BG2HOFS
void sPPU::mmio_w210f(uint8 data) {
bg2.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg2.regs.hoffset >> 8) & 7);
regs.bgofs_latchdata = data;
}
//BG2VOFS
void sPPU::mmio_w2110(uint8 data) {
bg2.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_latchdata = data;
}
//BG3HOFS
void sPPU::mmio_w2111(uint8 data) {
bg3.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg3.regs.hoffset >> 8) & 7);
regs.bgofs_latchdata = data;
}
//BG3VOFS
void sPPU::mmio_w2112(uint8 data) {
bg3.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_latchdata = data;
}
//BG4HOFS
void sPPU::mmio_w2113(uint8 data) {
bg4.regs.hoffset = (data << 8) | (regs.bgofs_latchdata & ~7) | ((bg4.regs.hoffset >> 8) & 7);
regs.bgofs_latchdata = data;
}
//BG4VOFS
void sPPU::mmio_w2114(uint8 data) {
bg4.regs.voffset = (data << 8) | regs.bgofs_latchdata;
regs.bgofs_latchdata = data;
}
//VMAIN
@ -270,10 +397,20 @@ void sPPU::mmio_w212a(uint8 data) {
void sPPU::mmio_w212b(uint8 data) {
}
//TM
void sPPU::mmio_w212c(uint8 data) {
bg4.regs.main_enabled = data & 0x08;
bg3.regs.main_enabled = data & 0x04;
bg2.regs.main_enabled = data & 0x02;
bg1.regs.main_enabled = data & 0x01;
}
//TS
void sPPU::mmio_w212d(uint8 data) {
bg4.regs.sub_enabled = data & 0x08;
bg3.regs.sub_enabled = data & 0x04;
bg2.regs.sub_enabled = data & 0x02;
bg1.regs.sub_enabled = data & 0x01;
}
void sPPU::mmio_w212e(uint8 data) {
@ -405,7 +542,7 @@ uint8 sPPU::mmio_r213f() {
regs.latch_vcounter = 0;
regs.ppu2_mdr &= 0x20;
regs.ppu2_mdr |= cpu.field() << 7;
regs.ppu2_mdr |= field() << 7;
if((cpu.pio() & 0x80) == 0) {
regs.ppu2_mdr |= 0x40;
} else if(regs.counters_latched) {
@ -421,9 +558,11 @@ void sPPU::mmio_reset() {
regs.ppu1_mdr = 0xff;
regs.ppu2_mdr = 0xff;
regs.mosaic_countdown = 0;
regs.vram_readbuffer = 0x0000;
regs.oam_latchdata = 0x00;
regs.cgram_latchdata = 0x00;
regs.bgofs_latchdata = 0x00;
regs.m7_latchdata = 0x00;
regs.counters_latched = false;
regs.latch_hcounter = 0;
@ -440,6 +579,13 @@ void sPPU::mmio_reset() {
regs.oam_priority = false;
regs.oam_firstsprite = 0;
//$2105 BGMODE
regs.bg3_priority = false;
regs.bgmode = 0;
//$2106 MOSAIC
regs.mosaic_size = 0;
//$2115 VMAIN
regs.vram_incmode = 1;
regs.vram_mapping = 0;

View File

@ -2,9 +2,11 @@ struct {
uint8 ppu1_mdr;
uint8 ppu2_mdr;
unsigned mosaic_countdown;
uint16 vram_readbuffer;
uint8 oam_latchdata;
uint8 cgram_latchdata;
uint8 bgofs_latchdata;
uint8 m7_latchdata;
bool counters_latched;
bool latch_hcounter;
@ -21,6 +23,13 @@ struct {
bool oam_priority;
uint8 oam_firstsprite;
//$2105 BGMODE
bool bg3_priority;
uint8 bgmode;
//$2106 MOSAIC
uint8 mosaic_size;
//$2115 VMAIN
bool vram_incmode;
uint8 vram_mapping;

View File

@ -0,0 +1,54 @@
#ifdef SPPU_CPP
void sPPU::Screen::scanline() {
output = self.output + self.vcounter() * 1024;
}
void sPPU::Screen::run() {
unsigned priority = 0;
uint16 color;
if(self.bg1.output.main.valid) {
priority = self.bg1.output.main.priority;
color = self.bg1.output.main.color;
}
if(self.bg2.output.main.valid && self.bg2.output.main.priority > priority) {
priority = self.bg2.output.main.priority;
color = self.bg2.output.main.color;
}
if(self.bg3.output.main.valid && self.bg3.output.main.priority > priority) {
priority = self.bg3.output.main.priority;
color = self.bg3.output.main.color;
}
if(self.bg4.output.main.valid && self.bg4.output.main.priority > priority) {
priority = self.bg4.output.main.priority;
color = self.bg4.output.main.color;
}
if(priority == 0) {
color = (memory::cgram[1] << 8) + (memory::cgram[0] << 0);
}
color = light_table[self.regs.display_brightness][color];
if(self.regs.display_disabled) color = 0;
*output++ = color;
*output++ = color;
}
sPPU::Screen::Screen(sPPU &self) : self(self) {
//generate light table
for(unsigned l = 0; l < 16; l++) {
for(unsigned r = 0; r < 32; r++) {
for(unsigned g = 0; g < 32; g++) {
for(unsigned b = 0; b < 32; b++) {
double luma = (double)l / 15.0;
unsigned ar = (luma * r + 0.5);
unsigned ag = (luma * g + 0.5);
unsigned ab = (luma * b + 0.5);
light_table[l][(b << 10) + (g << 5) + r] = (ab << 10) + (ag << 5) + ar;
}
}
}
}
}
#endif

View File

@ -0,0 +1,13 @@
class Screen {
public:
sPPU &self;
uint16 *output;
void scanline();
void run();
Screen(sPPU &self);
private:
uint16 light_table[16][32768];
};

View File

@ -3,7 +3,9 @@
#define SPPU_CPP
namespace SNES {
#include "background/background.cpp"
#include "mmio/mmio.cpp"
#include "screen/screen.cpp"
#if !defined(DEBUGGER)
sPPU ppu;
@ -17,14 +19,29 @@ void sPPU::enter() {
add_clocks(88);
//mosaic
if(vcounter() == 1) {
bg1.regs.mosaic_y = 1;
bg2.regs.mosaic_y = 1;
bg3.regs.mosaic_y = 1;
bg4.regs.mosaic_y = 1;
} else {
if(!bg1.regs.mosaic || !regs.mosaic_countdown) bg1.regs.mosaic_y = vcounter();
if(!bg2.regs.mosaic || !regs.mosaic_countdown) bg2.regs.mosaic_y = vcounter();
if(!bg3.regs.mosaic || !regs.mosaic_countdown) bg3.regs.mosaic_y = vcounter();
if(!bg4.regs.mosaic || !regs.mosaic_countdown) bg4.regs.mosaic_y = vcounter();
if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1;
regs.mosaic_countdown--;
}
if(vcounter() >= 1 && vcounter() <= 224) {
uint16_t *buffer = output + vcounter() * 1024;
screen.scanline();
for(unsigned n = 0; n < 256; n++) {
uint16 color = (memory::cgram[1] << 8) + (memory::cgram[0] << 0);
color = light_table[regs.display_brightness][color];
if(regs.display_disabled) color = 0;
*buffer++ = color;
*buffer++ = color;
bg1.run();
bg2.run();
bg3.run();
bg4.run();
screen.run();
add_clocks(4);
}
} else {
@ -36,20 +53,12 @@ void sPPU::enter() {
}
void sPPU::add_clocks(unsigned clocks) {
#if 0
//asynchronous execution
tick(clocks);
scheduler.addclocks_ppu(clocks);
scheduler.sync_ppucpu();
#else
//synchronous execution
clocks >>= 1;
while(clocks--) {
tick(2);
scheduler.addclocks_ppu(2);
scheduler.sync_ppucpu();
}
#endif
}
void sPPU::power() {
@ -74,21 +83,12 @@ void sPPU::frame() {
system.frame();
}
sPPU::sPPU() {
//generate light table for INIDISP::d3-d0
for(unsigned l = 0; l < 16; l++) {
for(unsigned r = 0; r < 32; r++) {
for(unsigned g = 0; g < 32; g++) {
for(unsigned b = 0; b < 32; b++) {
double luma = (double)l / 15.0;
unsigned ar = (luma * r + 0.5);
unsigned ag = (luma * g + 0.5);
unsigned ab = (luma * b + 0.5);
light_table[l][(b << 10) + (g << 5) + r] = (ab << 10) + (ag << 5) + ar;
}
}
}
}
sPPU::sPPU() :
bg1(*this, Background::ID::BG1),
bg2(*this, Background::ID::BG2),
bg3(*this, Background::ID::BG3),
bg4(*this, Background::ID::BG4),
screen(*this) {
}
}

View File

@ -1,6 +1,14 @@
class sPPU : public PPU {
public:
#include "background/background.hpp"
#include "mmio/mmio.hpp"
#include "screen/screen.hpp"
Background bg1;
Background bg2;
Background bg3;
Background bg4;
Screen screen;
void enter();
void add_clocks(unsigned);
@ -12,9 +20,6 @@ public:
void frame();
sPPU();
private:
uint16 light_table[16][32768];
};
#if !defined(DEBUGGER)

View File

@ -1,4 +1,4 @@
static const char bsnesVersion[] = "063.07";
static const char bsnesVersion[] = "063.08";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSerializerVersion = 9;
@ -6,7 +6,7 @@ static const unsigned bsnesSerializerVersion = 9;
#define CORE_SCPU
#define CORE_SSMP
#define CORE_SDSP
#define CORE_BPPU
#define CORE_SPPU
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)