Update to bsnes v064rc1 release.

I'm posting a release candidate for v064, for which I am looking for beta testers. If you would like to help out, please give it a try and report any bugs or regressions on the forum. If all goes well, this will be posted as v064 official shortly.
Note that you will need the Qt run-times from bsnes v063 official to use this. Also, this build does not use the new cycle-based PPU. Official builds are going to continue using the scanline-based renderer. This build should be about 10% faster than v063 was, which should lower the system requirements further.
This commit is contained in:
byuu 2010-04-12 15:25:39 +00:00
parent 717aa69d42
commit 65ff00e28a
41 changed files with 537 additions and 200 deletions

BIN
bsnes.exe

Binary file not shown.

View File

@ -2,7 +2,7 @@ include nall/Makefile
ui := ui_qt
# compiler
c := $(compiler) --std=gnu99
c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
flags := -O3 -fomit-frame-pointer -I.
link :=

View File

@ -85,18 +85,6 @@ namespace nall {
data.callback_global = (R (*)(P...))callback;
}
};
//bind functions to ease construction and assignment of function() with more than one argument
template<typename C, typename R, typename... P>
function<R (P...)> bind(R (C::*callback)(P...), C *object) {
return function<R (P...)>(callback, object);
}
template<typename C, typename R, typename... P>
function<R (P...)> bind(R (C::*callback)(P...) const, C *object) {
return function<R (P...)>(callback, object);
}
}
#endif

View File

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

View File

@ -37,8 +37,8 @@ void SuperFX::enter() {
void SuperFX::init() {
initialize_opcode_table();
regs.r[14].on_modify = bind(&SuperFX::r14_modify, this);
regs.r[15].on_modify = bind(&SuperFX::r15_modify, this);
regs.r[14].on_modify = { &SuperFX::r14_modify, this };
regs.r[15].on_modify = { &SuperFX::r15_modify, this };
}
void SuperFX::enable() {

View File

@ -12,11 +12,11 @@ void CPU::power() {
}
void CPU::reset() {
PPUcounter::reset();
PPUCounter::reset();
}
void CPU::serialize(serializer &s) {
PPUcounter::serialize(s);
PPUCounter::serialize(s);
s.integer(cpu_version);
}

View File

@ -2,7 +2,7 @@
#include "cpu-debugger.hpp"
#endif
class CPU : public PPUcounter, public MMIO {
class CPU : public PPUCounter, public MMIO {
public:
virtual void enter() = 0;

View File

@ -161,7 +161,6 @@ void sCPU::dma_run() {
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
void sCPU::hdma_update(unsigned i) {
@ -223,7 +222,6 @@ void sCPU::hdma_run() {
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
void sCPU::hdma_init_reset() {
@ -247,7 +245,6 @@ void sCPU::hdma_init() {
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
//==============

View File

@ -103,8 +103,8 @@ void sCPU::reset() {
apu_port[3] = 0x00;
}
sCPU::sCPU() : event(512, bind(&sCPU::queue_event, this)) {
PPUcounter::scanline = bind(&sCPU::scanline, this);
sCPU::sCPU() {
PPUCounter::scanline = { &sCPU::scanline, this };
}
sCPU::~sCPU() {

View File

@ -10,8 +10,6 @@ public:
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
priority_queue<unsigned> event;
struct Status {
bool interrupt_pending;
uint16 interrupt_vector;
@ -24,7 +22,15 @@ public:
//======
bool irq_lock;
unsigned dram_refresh_position;
bool dram_refreshed;
unsigned hdma_init_position;
bool hdma_init_triggered;
unsigned hdma_position;
bool hdma_triggered;
bool nmi_valid;
bool nmi_line;

View File

@ -4,8 +4,6 @@ void sCPU::serialize(serializer &s) {
CPU::serialize(s);
CPUcore::core_serialize(s);
event.serialize(s);
s.integer(status.interrupt_pending);
s.integer(status.interrupt_vector);
@ -13,7 +11,15 @@ void sCPU::serialize(serializer &s) {
s.integer(status.line_clocks);
s.integer(status.irq_lock);
s.integer(status.dram_refresh_position);
s.integer(status.dram_refreshed);
s.integer(status.hdma_init_position);
s.integer(status.hdma_init_triggered);
s.integer(status.hdma_position);
s.integer(status.hdma_triggered);
s.integer(status.nmi_valid);
s.integer(status.nmi_line);
@ -105,8 +111,6 @@ void sCPU::serialize(serializer &s) {
s.integer(apu_port[1]);
s.integer(apu_port[2]);
s.integer(apu_port[3]);
s.integer(cycle_edge_state);
}
#endif

View File

@ -1,28 +0,0 @@
#ifdef SCPU_CPP
void sCPU::queue_event(unsigned id) {
switch(id) {
//interrupts triggered during (H)DMA do not trigger immediately after
case EventIrqLockRelease: {
status.irq_lock = false;
} break;
//S-CPU WRAM consists of two 64kbyte DRAM chips, which must be refreshed
//once per scanline to avoid memory decay.
case EventDramRefresh: {
add_clocks(40);
} break;
//HDMA init routine; occurs once per frame
case EventHdmaInit: {
cycle_edge_state |= EventFlagHdmaInit;
} break;
//HDMA run routine; occurs once per scanline
case EventHdmaRun: {
cycle_edge_state |= EventFlagHdmaRun;
} break;
}
}
#endif

View File

@ -70,7 +70,6 @@ void sCPU::nmitimen_update(uint8 data) {
}
status.irq_lock = true;
event.enqueue(2, EventIrqLockRelease);
}
bool sCPU::rdnmi() {

View File

@ -1,6 +1,5 @@
#ifdef SCPU_CPP
#include "event.cpp"
#include "irq.cpp"
#include "joypad.cpp"
@ -9,7 +8,6 @@ unsigned sCPU::dma_counter() {
}
void sCPU::add_clocks(unsigned clocks) {
event.tick(clocks);
unsigned ticks = clocks >> 1;
while(ticks--) {
tick();
@ -19,6 +17,11 @@ void sCPU::add_clocks(unsigned clocks) {
}
}
scheduler.addclocks_cpu(clocks);
if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) {
status.dram_refreshed = true;
add_clocks(40);
}
}
//called by ppu.tick() when Hcounter=0
@ -33,17 +36,19 @@ void sCPU::scanline() {
system.scanline();
if(vcounter() == 0) {
//hdma init triggers once every frame
event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit);
//HDMA init triggers once every frame
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
status.hdma_init_triggered = false;
}
//dram refresh occurs once every scanline
//DRAM refresh occurs once every scanline
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter();
event.enqueue(status.dram_refresh_position, EventDramRefresh);
status.dram_refreshed = false;
//hdma triggers once every visible scanline
//HDMA triggers once every visible scanline
if(vcounter() <= (ppu.overscan() == false ? 224 : 239)) {
event.enqueue(1104, EventHdmaRun);
status.hdma_position = 1104;
status.hdma_triggered = false;
}
if(status.auto_joypad_poll == true && vcounter() == (ppu.overscan() == false ? 227 : 242)) {
@ -106,25 +111,21 @@ void sCPU::dma_edge() {
}
}
while(cycle_edge_state) {
switch(bit::lowest(cycle_edge_state)) {
case EventFlagHdmaInit: {
hdma_init_reset();
if(hdma_enabled_channels()) {
status.hdma_pending = true;
status.hdma_mode = 0;
}
} break;
case EventFlagHdmaRun: {
if(hdma_active_channels()) {
status.hdma_pending = true;
status.hdma_mode = 1;
}
} break;
if(status.hdma_init_triggered == false && hcounter() >= status.hdma_init_position) {
status.hdma_init_triggered = true;
hdma_init_reset();
if(hdma_enabled_channels()) {
status.hdma_pending = true;
status.hdma_mode = 0;
}
}
cycle_edge_state = bit::clear_lowest(cycle_edge_state);
if(status.hdma_triggered == false && hcounter() >= status.hdma_position) {
status.hdma_triggered = true;
if(hdma_active_channels()) {
status.hdma_pending = true;
status.hdma_mode = 1;
}
}
if(status.dma_active == false) {
@ -141,7 +142,9 @@ void sCPU::dma_edge() {
//status.irq_lock is used to simulate hardware delay before interrupts can
//trigger during certain events (immediately after DMA, writes to $4200, etc)
void sCPU::last_cycle() {
if(!status.irq_lock) {
if(status.irq_lock) {
status.irq_lock = false;
} else {
status.nmi_pending |= nmi_test();
status.irq_pending |= irq_test();
@ -153,14 +156,18 @@ void sCPU::timing_power() {
}
void sCPU::timing_reset() {
event.reset();
status.clock_count = 0;
status.line_clocks = lineclocks();
status.irq_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
event.enqueue(status.dram_refresh_position, EventDramRefresh);
status.dram_refreshed = false;
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
status.hdma_init_triggered = false;
status.hdma_position = 1104;
status.hdma_triggered = false;
status.nmi_valid = false;
status.nmi_line = false;
@ -184,8 +191,6 @@ void sCPU::timing_reset() {
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
cycle_edge_state = 0;
}
#endif

View File

@ -1,16 +1,3 @@
enum {
EventNone,
EventIrqLockRelease,
EventDramRefresh,
EventHdmaInit,
EventHdmaRun,
//cycle edge
EventFlagHdmaInit = 1 << 0,
EventFlagHdmaRun = 1 << 1,
};
unsigned cycle_edge_state;
//timing.cpp
unsigned dma_counter();
@ -35,6 +22,3 @@ alwaysinline bool irq_test();
//joypad.cpp
void run_auto_joypad_poll();
//event.cpp
void queue_event(unsigned); //priorityqueue callback function

View File

@ -3,15 +3,27 @@
#define ADSP_CPP
namespace SNES {
aDSP dsp;
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
aDSPDebugger dsp;
#else
aDSP dsp;
#endif
#include "tables.cpp"
#include "serialization.cpp"
void aDSP::enter() {
#if !defined(DSP_STATE_MACHINE)
while(true)
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
#endif
run();
#if !defined(DSP_STATE_MACHINE)
}
#endif
run();
}
uint8 aDSP::readb(uint16 addr) {

View File

@ -100,8 +100,8 @@ private:
int16 envx;
uint16 env_ctr, env_rate, env_sustain;
enum EnvelopeStates env_state;
enum EnvelopeModes env_mode;
uint32 env_state;
uint32 env_mode;
int16 outx;
@ -167,8 +167,16 @@ public:
void power();
void reset();
void serialize(serializer&);
aDSP();
~aDSP();
friend class aDSPDebug;
};
extern aDSP dsp;
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern aDSPDebugger dsp;
#else
extern aDSP dsp;
#endif

View File

@ -0,0 +1,3 @@
#ifdef ADSP_CPP
#endif

View File

@ -0,0 +1,3 @@
class aDSPDebugger : public aDSP, public DSPDebugger {
public:
};

View File

@ -0,0 +1,71 @@
#ifdef ADSP_CPP
void aDSP::serialize(serializer &s) {
DSP::serialize(s);
s.array(dspram);
s.integer(dsp_counter);
s.integer(status.MVOLL);
s.integer(status.MVOLR);
s.integer(status.EVOLL);
s.integer(status.EVOLR);
s.integer(status.KON);
s.integer(status.KOFF);
s.integer(status.FLG);
s.integer(status.ENDX);
s.integer(status.EFB);
s.integer(status.PMON);
s.integer(status.NON);
s.integer(status.EON);
s.integer(status.DIR);
s.integer(status.ESA);
s.integer(status.EDL);
s.array(status.FIR);
s.integer(status.kon);
s.integer(status.esa);
s.integer(status.noise_ctr);
s.integer(status.noise_rate);
s.integer(status.noise_sample);
s.integer(status.echo_index);
s.integer(status.echo_length);
s.array(status.fir_buffer[0]);
s.array(status.fir_buffer[1]);
s.integer(status.fir_buffer_index);
for(unsigned i = 0; i < 8; i++) {
s.integer(voice[i].VOLL);
s.integer(voice[i].VOLR);
s.integer(voice[i].PITCH);
s.integer(voice[i].SRCN);
s.integer(voice[i].ADSR1);
s.integer(voice[i].ADSR2);
s.integer(voice[i].GAIN);
s.integer(voice[i].ENVX);
s.integer(voice[i].OUTX);
s.integer(voice[i].pitch_ctr);
s.integer(voice[i].brr_index);
s.integer(voice[i].brr_ptr);
s.integer(voice[i].brr_header);
s.integer(voice[i].brr_looped);
s.array(voice[i].brr_data);
s.integer(voice[i].brr_data_index);
s.integer(voice[i].envx);
s.integer(voice[i].env_ctr);
s.integer(voice[i].env_rate);
s.integer(voice[i].env_sustain);
s.integer(voice[i].env_state);
s.integer(voice[i].env_mode);
s.integer(voice[i].outx);
}
}
#endif

View File

@ -36,6 +36,22 @@ unsigned snes_library_revision() {
return 1;
}
void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
interface.pvideo_refresh = video_refresh;
}
void snes_set_audio_sample(snes_audio_sample_t audio_sample) {
interface.paudio_sample = audio_sample;
}
void snes_set_input_poll(snes_input_poll_t input_poll) {
interface.pinput_poll = input_poll;
}
void snes_set_input_state(snes_input_state_t input_state) {
interface.pinput_state = input_state;
}
void snes_init() {
SNES::system.init(&interface);
SNES::input.port_set_device(0, SNES::Input::Device::Joypad);
@ -54,24 +70,39 @@ void snes_run() {
SNES::system.run();
}
void snes_runtosave() {
SNES::system.runtosave();
}
void snes_set_controller_port_device(bool port, unsigned device) {
SNES::input.port_set_device(port, (SNES::Input::Device)device);
}
void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
interface.pvideo_refresh = video_refresh;
unsigned snes_serialize_size() {
return SNES::system.serialize_size();
}
void snes_set_audio_sample(snes_audio_sample_t audio_sample) {
interface.paudio_sample = audio_sample;
bool snes_serialize(uint8_t *data, unsigned size) {
serializer s = SNES::system.serialize();
if(s.size() > size) return false;
memcpy(data, s.data(), s.size());
return true;
}
void snes_set_input_poll(snes_input_poll_t input_poll) {
interface.pinput_poll = input_poll;
bool snes_unserialize(const uint8_t *data, unsigned size) {
serializer s(data, size);
return SNES::system.unserialize(s);
}
void snes_set_input_state(snes_input_state_t input_state) {
interface.pinput_state = input_state;
void snes_cheat_reset() {
SNES::cheat.reset();
SNES::cheat.synchronize();
}
void snes_cheat_set(unsigned index, bool enabled, const char *code) {
SNES::cheat[index] = code;
SNES::cheat[index].enabled = enabled;
SNES::cheat.synchronize();
}
void snes_load_cartridge_normal(

View File

@ -5,11 +5,6 @@ extern "C" {
#endif
unsigned snes_library_revision();
void snes_init();
void snes_term();
void snes_unload();
void snes_run();
void snes_set_controller_port_device(bool port, unsigned device);
typedef void (*snes_video_refresh_t)(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height);
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
@ -21,6 +16,21 @@ void snes_set_audio_sample(snes_audio_sample_t);
void snes_set_input_poll(snes_input_poll_t);
void snes_set_input_state(snes_input_state_t);
void snes_init();
void snes_term();
void snes_unload();
void snes_run();
void snes_runtosave();
void snes_set_controller_port_device(bool port, unsigned device);
unsigned snes_serialize_size();
bool snes_serialize(uint8_t *data, unsigned size);
bool snes_unserialize(const uint8_t *data, unsigned size);
void snes_cheat_reset();
void snes_cheat_set(unsigned index, bool enabled, const char *code);
void snes_load_cartridge_normal(
const char *rom_xml, uint8_t *rom_data, unsigned rom_size
);

View File

@ -89,11 +89,6 @@ void bPPU::scanline() {
}
void bPPU::render_scanline() {
#ifdef FAST_FRAMESKIP
//note: this bypasses RTO status flag calculations, which is observable by software
if(status.render_output == false) return;
#endif
if(line >= 1 && line < (!overscan() ? 225 : 240)) {
render_line_oam_rto();
render_line();

View File

@ -1,6 +1,6 @@
//this should only be called by CPU::PPUcounter::tick();
//keeps track of previous counter positions in history table
void PPUcounter::tick() {
void PPUCounter::tick() {
status.hcounter += 2; //increment by smallest unit of time
if(status.hcounter >= 1360 && status.hcounter == lineclocks()) {
status.hcounter = 0;
@ -15,7 +15,7 @@ void PPUcounter::tick() {
//this should only be called by PPU::PPUcounter::tick(n);
//allows stepping by more than the smallest unit of time
void PPUcounter::tick(unsigned clocks) {
void PPUCounter::tick(unsigned clocks) {
status.hcounter += clocks;
if(status.hcounter >= lineclocks()) {
status.hcounter -= lineclocks();
@ -24,7 +24,7 @@ void PPUcounter::tick(unsigned clocks) {
}
//internal
void PPUcounter::vcounter_tick() {
void PPUCounter::vcounter_tick() {
if(++status.vcounter == 128) status.interlace = ppu.interlace();
if((system.region() == System::Region::NTSC && status.interlace == false && status.vcounter == 262)
@ -40,13 +40,13 @@ void PPUcounter::vcounter_tick() {
if(scanline) scanline();
}
bool PPUcounter::field () const { return status.field; }
uint16 PPUcounter::vcounter() const { return status.vcounter; }
uint16 PPUcounter::hcounter() const { return status.hcounter; }
bool PPUCounter::field () const { return status.field; }
uint16 PPUCounter::vcounter() const { return status.vcounter; }
uint16 PPUCounter::hcounter() const { return status.hcounter; }
bool PPUcounter::field (unsigned offset) const { return history.field [(history.index - (offset >> 1)) & 2047]; }
uint16 PPUcounter::vcounter(unsigned offset) const { return history.vcounter[(history.index - (offset >> 1)) & 2047]; }
uint16 PPUcounter::hcounter(unsigned offset) const { return history.hcounter[(history.index - (offset >> 1)) & 2047]; }
bool PPUCounter::field (unsigned offset) const { return history.field [(history.index - (offset >> 1)) & 2047]; }
uint16 PPUCounter::vcounter(unsigned offset) const { return history.vcounter[(history.index - (offset >> 1)) & 2047]; }
uint16 PPUCounter::hcounter(unsigned offset) const { return history.hcounter[(history.index - (offset >> 1)) & 2047]; }
//one PPU dot = 4 CPU clocks
//
@ -57,7 +57,7 @@ uint16 PPUcounter::hcounter(unsigned offset) const { return history.hcounter[(hi
//dot 323 range = { 1292, 1294, 1296 }
//dot 327 range = { 1310, 1312, 1314 }
uint16 PPUcounter::hdot() const {
uint16 PPUCounter::hdot() const {
if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) {
return (hcounter() >> 2);
} else {
@ -65,12 +65,12 @@ uint16 PPUcounter::hdot() const {
}
}
uint16 PPUcounter::lineclocks() const {
uint16 PPUCounter::lineclocks() const {
if(system.region() == System::Region::NTSC && status.interlace == false && vcounter() == 240 && field() == 1) return 1360;
return 1364;
}
void PPUcounter::reset() {
void PPUCounter::reset() {
status.interlace = false;
status.field = 0;
status.vcounter = 0;

View File

@ -9,25 +9,18 @@ namespace SNES {
#include "serialization.cpp"
void PPU::enable_renderer(bool r) { status.render_output = r; }
bool PPU::renderer_enabled() { return status.render_output; }
void PPU::frame() {
status.frame_executed = true;
static int32 fr = 0, fe = 0;
static signed framecount = 0;
static time_t prev, curr;
fe++;
if(status.render_output)fr++;
framecount++;
time(&curr);
if(curr != prev) {
status.frames_updated = true;
status.frames_rendered = fr;
status.frames_executed = fe;
fr = fe = 0;
status.frames_updated = true;
status.frames_executed = framecount;
framecount = 0;
prev = curr;
}
prev = curr;
}
void PPU::power() {
@ -36,16 +29,14 @@ void PPU::power() {
}
void PPU::reset() {
PPUcounter::reset();
PPUCounter::reset();
memset(output, 0, 512 * 480 * sizeof(uint16));
}
PPU::PPU() {
output = new uint16[512 * 480];
status.render_output = true;
status.frames_updated = false;
status.frames_rendered = 0;
status.frames_updated = false;
status.frames_executed = 0;
}

View File

@ -2,7 +2,7 @@
#include "ppu-debugger.hpp"
#endif
//PPUcounter emulates the H/V latch counters of the S-PPU2.
//PPUCounter emulates the H/V latch counters of the S-PPU2.
//
//real hardware has the S-CPU maintain its own copy of these counters that are
//updated based on the state of the S-PPU Vblank and Hblank pins. emulating this
@ -14,7 +14,7 @@
//point before this in the frame, which is handled internally by this class at
//V=128.
class PPUcounter {
class PPUCounter {
public:
alwaysinline void tick();
alwaysinline void tick(unsigned clocks);
@ -52,17 +52,14 @@ private:
} history;
};
class PPU : public PPUcounter, public MMIO {
class PPU : public PPUCounter, public MMIO {
public:
virtual void enter() = 0;
uint16 *output;
struct {
bool render_output;
bool frame_executed;
bool frames_updated;
unsigned frames_rendered;
unsigned frames_executed;
} status;
@ -78,8 +75,6 @@ public:
virtual void frame();
virtual void power();
virtual void reset();
virtual void enable_renderer(bool r);
virtual bool renderer_enabled();
virtual void serialize(serializer&);
PPU();

View File

@ -1,6 +1,6 @@
#ifdef PPU_CPP
void PPUcounter::serialize(serializer &s) {
void PPUCounter::serialize(serializer &s) {
s.integer(status.interlace);
s.integer(status.field);
s.integer(status.vcounter);
@ -13,12 +13,9 @@ void PPUcounter::serialize(serializer &s) {
}
void PPU::serialize(serializer &s) {
PPUcounter::serialize(s);
PPUCounter::serialize(s);
s.integer(status.render_output);
s.integer(status.frame_executed);
s.integer(status.frames_updated);
s.integer(status.frames_rendered);
s.integer(status.frames_executed);
s.integer(ppu1_version);

View File

@ -35,7 +35,7 @@ public:
struct {
struct {
unsigned priority; //0 = none (transparent)
unsigned palette; //(direct_color_bits << 8) + index
unsigned palette;
unsigned tile;
} main, sub;
} output;
@ -45,6 +45,8 @@ public:
unsigned get_tile(unsigned x, unsigned y);
unsigned get_color(unsigned x, unsigned y, uint16 offset);
void reset();
void serialize(serializer&);
Background(sPPU &self, unsigned id);
private:

View File

@ -25,6 +25,7 @@ public:
void run();
void reset();
void serialize(serializer&);
Screen(sPPU &self);
private:

View File

@ -0,0 +1,239 @@
#ifdef SPPU_CPP
void sPPU::serialize(serializer &s) {
PPU::serialize(s);
s.integer(display.interlace);
s.integer(display.overscan);
s.integer(regs.ppu1_mdr);
s.integer(regs.ppu2_mdr);
s.integer(regs.vram_readbuffer);
s.integer(regs.oam_latchdata);
s.integer(regs.cgram_latchdata);
s.integer(regs.bgofs_latchdata);
s.integer(regs.mode7_latchdata);
s.integer(regs.counters_latched);
s.integer(regs.latch_hcounter);
s.integer(regs.latch_vcounter);
s.integer(regs.display_disabled);
s.integer(regs.display_brightness);
s.integer(regs.oam_baseaddr);
s.integer(regs.oam_addr);
s.integer(regs.oam_priority);
s.integer(regs.bg3_priority);
s.integer(regs.bgmode);
s.integer(regs.mode7_hoffset);
s.integer(regs.mode7_voffset);
s.integer(regs.vram_incmode);
s.integer(regs.vram_mapping);
s.integer(regs.vram_incsize);
s.integer(regs.vram_addr);
s.integer(regs.mode7_repeat);
s.integer(regs.mode7_vflip);
s.integer(regs.mode7_hflip);
s.integer(regs.m7a);
s.integer(regs.m7b);
s.integer(regs.m7c);
s.integer(regs.m7d);
s.integer(regs.m7x);
s.integer(regs.m7y);
s.integer(regs.cgram_addr);
s.integer(regs.mode7_extbg);
s.integer(regs.pseudo_hires);
s.integer(regs.overscan);
s.integer(regs.interlace);
s.integer(regs.hcounter);
s.integer(regs.vcounter);
bg1.serialize(s);
bg2.serialize(s);
bg3.serialize(s);
bg4.serialize(s);
oam.serialize(s);
window.serialize(s);
screen.serialize(s);
}
void sPPU::Background::serialize(serializer &s) {
s.integer(id);
s.integer(t.x);
s.integer(t.mosaic_y);
s.integer(t.mosaic_countdown);
s.integer(regs.tiledata_addr);
s.integer(regs.screen_addr);
s.integer(regs.screen_size);
s.integer(regs.mosaic);
s.integer(regs.tile_size);
s.integer(regs.mode);
s.integer(regs.priority0);
s.integer(regs.priority1);
s.integer(regs.main_enabled);
s.integer(regs.sub_enabled);
s.integer(regs.hoffset);
s.integer(regs.voffset);
s.integer(output.main.priority);
s.integer(output.main.palette);
s.integer(output.main.tile);
s.integer(output.sub.priority);
s.integer(output.sub.palette);
s.integer(output.sub.tile);
}
void sPPU::Sprite::serialize(serializer &s) {
for(unsigned i = 0; i < 128; i++) {
s.integer(list[i].width);
s.integer(list[i].height);
s.integer(list[i].x);
s.integer(list[i].y);
s.integer(list[i].character);
s.integer(list[i].nameselect);
s.integer(list[i].vflip);
s.integer(list[i].hflip);
s.integer(list[i].priority);
s.integer(list[i].palette);
}
s.integer(t.x);
s.integer(t.y);
s.integer(t.item_count);
s.integer(t.tile_count);
s.array(t.output_palette);
s.array(t.output_priority);
s.array(t.item_list);
for(unsigned i = 0; i < 34; i++) {
s.integer(t.tile_list[i].x);
s.integer(t.tile_list[i].y);
s.integer(t.tile_list[i].priority);
s.integer(t.tile_list[i].palette);
s.integer(t.tile_list[i].tile);
s.integer(t.tile_list[i].hflip);
}
s.integer(t.active_sprite);
s.integer(regs.main_enabled);
s.integer(regs.sub_enabled);
s.integer(regs.interlace);
s.integer(regs.base_size);
s.integer(regs.nameselect);
s.integer(regs.tiledata_addr);
s.integer(regs.first_sprite);
s.integer(regs.priority0);
s.integer(regs.priority1);
s.integer(regs.priority2);
s.integer(regs.priority3);
s.integer(regs.time_over);
s.integer(regs.range_over);
s.integer(output.main.priority);
s.integer(output.main.palette);
s.integer(output.sub.priority);
s.integer(output.sub.palette);
}
void sPPU::Window::serialize(serializer &s) {
s.integer(t.x);
s.integer(regs.bg1_one_enable);
s.integer(regs.bg1_one_invert);
s.integer(regs.bg1_two_enable);
s.integer(regs.bg1_two_invert);
s.integer(regs.bg2_one_enable);
s.integer(regs.bg2_one_invert);
s.integer(regs.bg2_two_enable);
s.integer(regs.bg2_two_invert);
s.integer(regs.bg3_one_enable);
s.integer(regs.bg3_one_invert);
s.integer(regs.bg3_two_enable);
s.integer(regs.bg3_two_invert);
s.integer(regs.bg4_one_enable);
s.integer(regs.bg4_one_invert);
s.integer(regs.bg4_two_enable);
s.integer(regs.bg4_two_invert);
s.integer(regs.oam_one_enable);
s.integer(regs.oam_one_invert);
s.integer(regs.oam_two_enable);
s.integer(regs.oam_two_invert);
s.integer(regs.col_one_enable);
s.integer(regs.col_one_invert);
s.integer(regs.col_two_enable);
s.integer(regs.col_two_invert);
s.integer(regs.one_left);
s.integer(regs.one_right);
s.integer(regs.two_left);
s.integer(regs.two_right);
s.integer(regs.bg1_mask);
s.integer(regs.bg2_mask);
s.integer(regs.bg3_mask);
s.integer(regs.bg4_mask);
s.integer(regs.oam_mask);
s.integer(regs.col_mask);
s.integer(regs.bg1_main_enable);
s.integer(regs.bg1_sub_enable);
s.integer(regs.bg2_main_enable);
s.integer(regs.bg2_sub_enable);
s.integer(regs.bg3_main_enable);
s.integer(regs.bg3_sub_enable);
s.integer(regs.bg4_main_enable);
s.integer(regs.bg4_sub_enable);
s.integer(regs.oam_main_enable);
s.integer(regs.oam_sub_enable);
s.integer(regs.col_main_mask);
s.integer(regs.col_sub_mask);
s.integer(output.main.color_enable);
s.integer(output.sub.color_enable);
}
void sPPU::Screen::serialize(serializer &s) {
s.integer(regs.addsub_mode);
s.integer(regs.direct_color);
s.integer(regs.color_mode);
s.integer(regs.color_halve);
s.integer(regs.bg1_color_enable);
s.integer(regs.bg2_color_enable);
s.integer(regs.bg3_color_enable);
s.integer(regs.bg4_color_enable);
s.integer(regs.oam_color_enable);
s.integer(regs.back_color_enable);
s.integer(regs.color_b);
s.integer(regs.color_g);
s.integer(regs.color_r);
}
#endif

View File

@ -3,12 +3,6 @@
#define SPPU_CPP
namespace SNES {
#include "background/background.cpp"
#include "mmio/mmio.cpp"
#include "screen/screen.cpp"
#include "sprite/sprite.cpp"
#include "window/window.cpp"
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sPPUDebugger ppu;
@ -16,10 +10,20 @@ namespace SNES {
sPPU ppu;
#endif
#include "background/background.cpp"
#include "mmio/mmio.cpp"
#include "screen/screen.cpp"
#include "sprite/sprite.cpp"
#include "window/window.cpp"
#include "serialization.cpp"
void sPPU::enter() {
while(true) {
scanline();
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
scanline();
add_clocks(88);
if(vcounter() >= 1 && vcounter() <= (!regs.overscan ? 224 : 239)) {

View File

@ -28,6 +28,7 @@ public:
void scanline();
void frame();
void serialize(serializer&);
sPPU();
};

View File

@ -20,8 +20,8 @@ public:
bool nameselect;
bool vflip;
bool hflip;
uint8 palette;
uint8 priority;
uint8 palette;
} list[128];
struct State {
@ -59,7 +59,7 @@ public:
struct {
struct {
unsigned priority; //0 = none (transparent)
unsigned palette; //index
unsigned palette;
} main, sub;
} output;
@ -69,6 +69,7 @@ public:
void run();
void reset();
void serialize(serializer&);
Sprite(sPPU &self);
private:

View File

@ -74,6 +74,7 @@ public:
void run();
void reset();
void serialize(serializer&);
Window(sPPU &self);
private:

View File

@ -1,12 +1,12 @@
static const char bsnesVersion[] = "063.12";
static const char bsnesVersion[] = "063.13";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSerializerVersion = 9;
static const unsigned bsnesSerializerVersion = 10;
#define CORE_SMEMORY
#define CORE_SCPU
#define CORE_SSMP
#define CORE_SDSP
#define CORE_SPPU
#define CORE_ADSP
#define CORE_BPPU
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
@ -23,7 +23,6 @@ static const unsigned bsnesSerializerVersion = 9;
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/bit.hpp>
#include <nall/detect.hpp>
#include <nall/dl.hpp>
#include <nall/endian.hpp>
@ -32,7 +31,6 @@ static const unsigned bsnesSerializerVersion = 9;
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/platform.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>

View File

@ -8,9 +8,9 @@ void FileBrowser::chooseFolder() {
void FileBrowser::loadCartridge(CartridgeMode mode, signed filterIndex) {
cartridgeMode = mode;
onChange = bind(&FileBrowser::onChangeCartridge, this);
onActivate = bind(&FileBrowser::onAcceptCartridge, this);
onAccept = bind(&FileBrowser::onAcceptCartridge, this);
onChange = { &FileBrowser::onChangeCartridge, this };
onActivate = { &FileBrowser::onAcceptCartridge, this };
onAccept = { &FileBrowser::onAcceptCartridge, this };
setPath(config().path.rom == "" ? config().path.current.cartridge : config().path.rom);
setNameFilters(string()

View File

@ -27,8 +27,8 @@ Reader::Reader() {
}
if(!supported || !load) {
supported = bind(&Reader::direct_supported, this);
load = bind(&Reader::direct_load, this);
supported = { &Reader::direct_supported, this };
load = { &Reader::direct_load, this };
}
compressionList = supported();

View File

@ -4,8 +4,8 @@ Movie movie;
void Movie::chooseFile() {
fileBrowser->onChange.reset();
fileBrowser->onActivate = bind(&Movie::play, this);
fileBrowser->onAccept = bind(&Movie::play, this);
fileBrowser->onActivate = { &Movie::play, this };
fileBrowser->onAccept = { &Movie::play, this };
fileBrowser->setWindowTitle("Select Movie");
fileBrowser->setPath(config().path.current.movie);
fileBrowser->setNameFilters("bsnes Movies (*.bsv)");

View File

@ -52,7 +52,7 @@ void PathSettingWidget::updatePath() {
void PathSettingWidget::selectPath() {
fileBrowser->onChange.reset();
fileBrowser->onActivate.reset();
fileBrowser->onAccept = bind(&PathSettingWidget::acceptPath, this);
fileBrowser->onAccept = { &PathSettingWidget::acceptPath, this };
fileBrowser->setWindowTitle(pathBrowseLabel);
fileBrowser->setPath(config().path.current.folder);
fileBrowser->chooseFolder();

View File

@ -303,8 +303,8 @@ void VideoSettingsWindow::cropBottomAdjust(int state) {
void VideoSettingsWindow::selectFragmentShader() {
fileBrowser->onChange.reset();
fileBrowser->onActivate = bind(&VideoSettingsWindow::assignFragmentShader, this);
fileBrowser->onAccept = bind(&VideoSettingsWindow::assignFragmentShader, this);
fileBrowser->onActivate = { &VideoSettingsWindow::assignFragmentShader, this };
fileBrowser->onAccept = { &VideoSettingsWindow::assignFragmentShader, this };
fileBrowser->setWindowTitle("Select Fragment Shader");
fileBrowser->setPath(config().path.current.shader);
fileBrowser->setNameFilters("All files (*)");
@ -313,8 +313,8 @@ void VideoSettingsWindow::selectFragmentShader() {
void VideoSettingsWindow::selectVertexShader() {
fileBrowser->onChange.reset();
fileBrowser->onActivate = bind(&VideoSettingsWindow::assignVertexShader, this);
fileBrowser->onAccept = bind(&VideoSettingsWindow::assignVertexShader, this);
fileBrowser->onActivate = { &VideoSettingsWindow::assignVertexShader, this };
fileBrowser->onAccept = { &VideoSettingsWindow::assignVertexShader, this };
fileBrowser->setWindowTitle("Select Vertex Shader");
fileBrowser->setPath(config().path.current.shader);
fileBrowser->setNameFilters("All files (*)");

View File

@ -86,13 +86,32 @@ int main(int argc, char *argv[]) {
snes_load_cartridge_normal(0, rom_data, rom_size);
delete[] rom_data;
unsigned serial_size = snes_serialize_size();
uint8_t *serial_data = new uint8_t[serial_size];
snes_runtosave();
snes_serialize(serial_data, serial_size);
snes_cheat_reset();
//snes_cheat_set(0, true, "DD32-6DAD");
while(true) {
SDL_Event event;
SDL_PollEvent(&event);
if(event.type == SDL_QUIT) break;
if(event.type == SDL_KEYDOWN) {
if(event.key.keysym.sym == SDLK_ESCAPE) {
break;
} else if(event.key.keysym.sym == SDLK_F2) {
snes_runtosave();
snes_serialize(serial_data, serial_size);
} else if(event.key.keysym.sym == SDLK_F4) {
snes_unserialize(serial_data, serial_size);
}
}
snes_run();
}
delete[] serial_data;
snes_unload();
snes_term();
return 0;