Update to bsnes v014 release.

This version adds speed regulation, greatly improves PPU rendering, and increases speed by ~30% over the previous version.
Changelog:
    - Rewrote offset-per-tile mode emulation, should be correct now. Fixes Chrono Trigger, Contra III, Tetris Attack, etc.
    - Fixed a bug with HDMA occuring during interrupts. Fixes Tales of Phantasia souond test screen
    - Updated compiler to Visual Studio 2005, and enabled profile guided optimizations
    - Added conditional compilation of debugging functions (faster without them)
    - Added conditional compilation of core classes as pointers (allowing polymorphism) or objects (allowing inlining). The latter results in a speed increase
    - Small fixes to BG and OAM rendering routines
    - Corrected sprite tile bounds wrapping
    - Corrected sprite rendering in hires video modes
    - Rewrote color add/sub routines, should be correct now. Fixes Illusion of Gaia menu, etc.
    - Optimized video blitting routines, will temporarilly break mixed video mode screenshots
    - Prevented selecting menu options via return key from being recognized as keypresses by the emulator
    - Added system speed regulation (60hz/NTSC or 50hz/PAL)! Many thanks to kode54, GIGO, and Richard Bannister for their assistance
I disabled the debugger and polymorphism, and enabled profile guided optimizations for this build, to maximize speed. The debugger and polymorphism can be re-enabled via uncommenting the respective #defines in src/base.h and recompiling, or bsnes v0.013 can be used. I may start releasing two separate builds in the future... not sure yet.
This commit is contained in:
byuu
2005-11-12 16:49:26 +00:00
parent f288280ceb
commit 7dec0b2a3c
73 changed files with 1106 additions and 1337 deletions

View File

@@ -14,7 +14,11 @@ snes.video_color_adjust_mode = 0
# Mutes SNES audio output when enabled # Mutes SNES audio output when enabled
# (default = true) # (default = true)
snes.mute = true snes.mute = false
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
# (default = true)
system.regulate_speed = true
# Video mode # Video mode
# 0 = 256x224w # 0 = 256x224w

BIN
bsnes.exe

Binary file not shown.

View File

@@ -24,13 +24,13 @@ uint8 r;
break; break;
case 0xf3: //DSPDATA case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f //0x80-0xff is a read-only mirror of 0x00-0x7f
r = dsp->read(status.dsp_addr & 0x7f); r = r_dsp->read(status.dsp_addr & 0x7f);
break; break;
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
case 0xf5: //CPUIO1 case 0xf5: //CPUIO1
case 0xf6: //CPUIO2 case 0xf6: //CPUIO2
case 0xf7: //CPUIO3 case 0xf7: //CPUIO3
r = cpu->port_read(addr & 3); r = r_cpu->port_read(addr & 3);
break; break;
case 0xf8: //??? case 0xf8: //???
case 0xf9: //??? -- Mapped to SPCRAM case 0xf9: //??? -- Mapped to SPCRAM
@@ -63,7 +63,10 @@ uint8 r;
r = spcram[addr]; r = spcram[addr];
} }
} }
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_READ, addr, r); snes->notify(SNES::SPCRAM_READ, addr, r);
#endif
return r; return r;
} }
@@ -78,12 +81,12 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
//one-time clearing of APU port read registers, //one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00 //emulated by simulating CPU writes of 0x00
if(value & 0x20) { if(value & 0x20) {
cpu->port_write(2, 0x00); r_cpu->port_write(2, 0x00);
cpu->port_write(3, 0x00); r_cpu->port_write(3, 0x00);
} }
if(value & 0x10) { if(value & 0x10) {
cpu->port_write(0, 0x00); r_cpu->port_write(0, 0x00);
cpu->port_write(1, 0x00); r_cpu->port_write(1, 0x00);
} }
//0->1 transistion resets timers //0->1 transistion resets timers
@@ -111,7 +114,7 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
case 0xf3: //DSPDATA case 0xf3: //DSPDATA
//0x80-0xff is a read-only mirror of 0x00-0x7f //0x80-0xff is a read-only mirror of 0x00-0x7f
if(status.dsp_addr < 0x80) { if(status.dsp_addr < 0x80) {
dsp->write(status.dsp_addr & 0x7f, value); r_dsp->write(status.dsp_addr & 0x7f, value);
} }
break; break;
case 0xf4: //CPUIO0 case 0xf4: //CPUIO0
@@ -143,7 +146,10 @@ void bAPU::spcram_write(uint16 addr, uint8 value) {
//even if the iplrom is enabled. //even if the iplrom is enabled.
spcram[addr] = value; spcram[addr] = value;
} }
#ifdef DEBUGGER
snes->notify(SNES::SPCRAM_WRITE, addr, value); snes->notify(SNES::SPCRAM_WRITE, addr, value);
#endif
} }
uint8 bAPU::port_read(uint8 port) { uint8 bAPU::port_read(uint8 port) {

View File

@@ -1,18 +1,22 @@
void bAPU::exec_cycle() { void bAPU::exec_cycle() {
uint8 op; if(status.cycle_pos) {
if(status.cycle_pos == 0) {
op = spcram_read(regs.pc);
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
status.opcode = op_read();
status.cycle_pos = 1;
add_cycles(1);
} else {
(this->*optbl[status.opcode])(); (this->*optbl[status.opcode])();
add_cycles(1); add_cycles(1);
if(status.cycle_pos == 0) { if(status.cycle_pos == 0) {
#ifdef DEBUGGER
snes->notify(SNES::APU_EXEC_OPCODE_END); snes->notify(SNES::APU_EXEC_OPCODE_END);
#endif
} }
return;
} }
//on first cycle?
#ifdef DEBUGGER
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
#endif
status.opcode = op_read();
status.cycle_pos = 1;
add_cycles(1);
} }
//only return true when we are on an opcode edge //only return true when we are on an opcode edge

View File

@@ -1,171 +0,0 @@
#include "../../base.h"
uint8 bAPUSkip::spcram_read (uint16 addr) { return 0xff; }
void bAPUSkip::spcram_write(uint16 addr, uint8 value) {}
/*
This routine is very serious. It will eat holes through
the ROM to skip APU test conditions. Or in other words,
it will disable and/or force branches when neccesary.
It can very easily break or corrupt a game and prevent it
from being playable until the ROM is reloaded (ROM writes
are only performed in memory, of course).
However, this kind of brute force approach is required to
get many games playable without proper SPC700 emulation.
*/
uint8 bAPUSkip::port_read(uint8 port) {
port &= 3;
_apu_port *p = &apu_port[port];
int i, x, y, z, t;
uint32 addr;
addr = cpu->regs.pc.d;
p->read_addr[p->read_pos & 31] = addr;
//- lda $214x
// cmp $214x
// bne -
// cmp ???
// beq/bne -
__test1:
//look for an lda/cmp read pattern
if(addr == p->read_addr[(p->read_pos - 1) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test2;
if(addr == p->read_addr[(p->read_pos - 3) & 31])goto __test2;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test2;
if(p->read_addr[(p->read_pos - 1) & 31] != p->read_addr[(p->read_pos - 3) & 31])goto __test2;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test2;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else { //(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test2;
goto __pass;
//- lda $214x
// cmp ???
// beq/bne -
__test2:
//look for a repeated read pattern
if(addr != p->read_addr[(p->read_pos - 1) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 2) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 3) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 4) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 5) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 6) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 7) & 31])goto __test3;
if(addr != p->read_addr[(p->read_pos - 8) & 31])goto __test3;
//try and find compare opcode
for(i=0;i<24;i++) {
x = mem_bus->read(addr + i);
if(x == OP_CMP_CONST || x == OP_CPX_CONST || x == OP_CPY_CONST)break;
if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) break;
if(x == OP_CMP_LONG)break;
}
if(i == 24)goto __test3;
//seek to next opcode
if(x == OP_CMP_CONST) {
i += (cpu->regs.p.m)?2:3;
} else if(x == OP_CPX_CONST || x == OP_CPY_CONST) {
i += (cpu->regs.p.x)?2:3;
} else if(x == OP_CMP_ADDR || x == OP_CPX_ADDR || x == OP_CPY_ADDR) {
i += 3;
} else if(x == OP_CMP_LONG) {
i += 4;
}
x = mem_bus->read(addr + i);
if(x == OP_BNE) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_NOP);
mem_bus->write(addr + i + 1, OP_NOP);
mem_bus->cart->write_protect(true);
} else if(x == OP_BEQ) {
mem_bus->cart->write_protect(false);
mem_bus->write(addr + i, OP_BRA);
mem_bus->cart->write_protect(true);
} else goto __test3;
goto __pass;
//fallback
__test3:
if(p->pos < 4) {
if(!(port & 1)) {
p->value = cpu->regs.a.l;
} else {
p->value = cpu->regs.a.h;
}
} else if(p->pos < 8) {
if(!(port & 1)) {
p->value = cpu->regs.x.l;
} else {
p->value = cpu->regs.x.h;
}
} else if(p->pos < 12) {
if(!(port & 1)) {
p->value = cpu->regs.y.l;
} else {
p->value = cpu->regs.y.h;
}
} else if(p->pos < 16) {
p->value = rand();
}
if(++p->pos == 16)p->pos = 0;
__pass:
p->read_pos++;
p->read_pos &= 31;
return p->value;
}
void bAPUSkip::port_write(uint8 port, uint8 value) {
port &= 3;
apu_port[port].value = value;
}
void bAPUSkip::run() {
snes->notify(SNES::APU_EXEC_OPCODE_BEGIN);
snes->notify(SNES::APU_EXEC_OPCODE_END);
}
void bAPUSkip::power() {
reset();
}
void bAPUSkip::reset() {
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.sp = 0x00;
regs.p = 0x02;
regs.pc = 0xffc0;
memset(&apu_port[0], 0, sizeof(_apu_port));
memset(&apu_port[1], 0, sizeof(_apu_port));
memset(&apu_port[2], 0, sizeof(_apu_port));
memset(&apu_port[3], 0, sizeof(_apu_port));
}

View File

@@ -1,37 +0,0 @@
class bAPUSkip : public APU {
private:
uint8 spcram[65536];
public:
struct _apu_port {
uint8 value;
uint8 step, pos;
uint32 read_addr[32], read_pos;
}apu_port[4];
enum {
OP_CMP_CONST = 0xc9,
OP_CPX_CONST = 0xe0,
OP_CPY_CONST = 0xc0,
OP_CMP_ADDR = 0xcd,
OP_CPX_ADDR = 0xec,
OP_CPY_ADDR = 0xcc,
OP_CMP_LONG = 0xcf,
OP_BNE = 0xd0,
OP_BEQ = 0xf0,
OP_BRA = 0x80,
OP_NOP = 0xea
};
uint8 spcram_read (uint16 addr);
void spcram_write(uint16 addr, uint8 value);
uint8 port_read (uint8 port);
void port_write (uint8 port, uint8 value);
uint8 *get_spcram_handle() { return spcram; }
void run();
uint32 cycles_executed() { return 12 * 24; }
void power();
void reset();
};

View File

@@ -1,3 +1,6 @@
//#define DEBUGGER
//#define POLYMORPHISM
//this should be declared in the port-specific makefiles //this should be declared in the port-specific makefiles
//#define ARCH_LSB //#define ARCH_LSB
//#define ARCH_MSB //#define ARCH_MSB

View File

@@ -6,7 +6,7 @@ void SDD1::init() {
void SDD1::enable() { void SDD1::enable() {
for(int i=0x4800;i<=0x4807;i++) { for(int i=0x4800;i<=0x4807;i++) {
mem_bus->set_mmio_mapper(i, mmio); r_mem->set_mmio_mapper(i, mmio);
} }
} }
@@ -47,7 +47,7 @@ uint8 SDD1::mmio_read(uint16 addr) {
case 0x4807:return (sdd1.index[3] >> 20) & 7; case 0x4807:return (sdd1.index[3] >> 20) & 7;
} }
return cpu->regs.mdr; return r_cpu->regs.mdr;
} }
void SDD1::mmio_write(uint16 addr, uint8 data) { void SDD1::mmio_write(uint16 addr, uint8 data) {

View File

@@ -28,7 +28,7 @@ understood.
************************************************************************/ ************************************************************************/
#define SDD1_read(__addr) (mem_bus->read(__addr)) #define SDD1_read(__addr) (r_mem->read(__addr))
//////////////////////////////////////////////////// ////////////////////////////////////////////////////

View File

@@ -78,8 +78,8 @@ void SRTC::init() {
} }
void SRTC::enable() { void SRTC::enable() {
mem_bus->set_mmio_mapper(0x2800, mmio); r_mem->set_mmio_mapper(0x2800, mmio);
mem_bus->set_mmio_mapper(0x2801, mmio); r_mem->set_mmio_mapper(0x2801, mmio);
} }
void SRTC::power() { void SRTC::power() {
@@ -176,7 +176,7 @@ uint8 SRTCMMIO::read(uint32 addr) {
case 0x2800:return srtc->read(); case 0x2800:return srtc->read();
} }
return cpu->regs.mdr; return r_cpu->regs.mdr;
} }
void SRTCMMIO::write(uint32 addr, uint8 value) { void SRTCMMIO::write(uint32 addr, uint8 value) {

View File

@@ -85,7 +85,7 @@ void bCPU::power() {
void bCPU::reset() { void bCPU::reset() {
//reset vector location //reset vector location
regs.pc = mem_bus->read(0xfffc) | (mem_bus->read(0xfffd) << 8); regs.pc = r_mem->read(0xfffc) | (r_mem->read(0xfffd) << 8);
//registers are not fully reset by SNES //registers are not fully reset by SNES
regs.x.h = 0x00; regs.x.h = 0x00;
@@ -161,22 +161,25 @@ void bCPU::cpu_io() {
status.cycle_count = 6; status.cycle_count = 6;
pre_exec_cycle(); pre_exec_cycle();
add_cycles(6); add_cycles(6);
cycle_edge();
} }
uint8 bCPU::mem_read(uint32 addr) { uint8 bCPU::mem_read(uint32 addr) {
status.cycle_count = mem_bus->speed(addr); status.cycle_count = r_mem->speed(addr);
pre_exec_cycle(); pre_exec_cycle();
add_cycles(status.cycle_count - 4); add_cycles(status.cycle_count - 4);
regs.mdr = mem_bus->read(addr); regs.mdr = r_mem->read(addr);
add_cycles(4); add_cycles(4);
cycle_edge();
return regs.mdr; return regs.mdr;
} }
void bCPU::mem_write(uint32 addr, uint8 value) { void bCPU::mem_write(uint32 addr, uint8 value) {
status.cycle_count = mem_bus->speed(addr); status.cycle_count = r_mem->speed(addr);
pre_exec_cycle(); pre_exec_cycle();
add_cycles(status.cycle_count); add_cycles(status.cycle_count);
mem_bus->write(addr, value); r_mem->write(addr, value);
cycle_edge();
} }
uint32 bCPU::op_addr(uint8 mode, uint32 addr) { uint32 bCPU::op_addr(uint8 mode, uint32 addr) {

View File

@@ -25,10 +25,10 @@ uint8 x;
if(sdd1->dma_active() == true) { if(sdd1->dma_active() == true) {
x = sdd1->dma_read(); x = sdd1->dma_read();
} else { } else {
x = mem_bus->read(dma_addr(i)); x = r_mem->read(dma_addr(i));
} }
mem_bus->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x); r_mem->write(0x2100 | ((channel[i].destaddr + index) & 0xff), x);
add_cycles(8); add_cycles(8);
channel[i].xfersize--; channel[i].xfersize--;
@@ -36,8 +36,8 @@ uint8 x;
void bCPU::dma_mmiotocpu(uint8 i, uint8 index) { void bCPU::dma_mmiotocpu(uint8 i, uint8 index) {
uint8 x; uint8 x;
x = mem_bus->read(0x2100 | ((channel[i].destaddr + index) & 0xff)); x = r_mem->read(0x2100 | ((channel[i].destaddr + index) & 0xff));
mem_bus->write(dma_addr(i), x); r_mem->write(dma_addr(i), x);
add_cycles(8); add_cycles(8);
channel[i].xfersize--; channel[i].xfersize--;
@@ -113,21 +113,21 @@ uint16 index;
uint8 bCPU::hdma_read(uint8 i) { uint8 bCPU::hdma_read(uint8 i) {
if(channel[i].direction == DMA_MMIOTOCPU) { if(channel[i].direction == DMA_MMIOTOCPU) {
return mem_bus->read(hdma_mmio(i)); return r_mem->read(hdma_mmio(i));
} else if(!channel[i].hdma_indirect) { } else if(!channel[i].hdma_indirect) {
return mem_bus->read(hdma_addr(i)); return r_mem->read(hdma_addr(i));
} else { } else {
return mem_bus->read(hdma_iaddr(i)); return r_mem->read(hdma_iaddr(i));
} }
} }
void bCPU::hdma_write(uint8 i, uint8 x) { void bCPU::hdma_write(uint8 i, uint8 x) {
if(channel[i].direction == DMA_CPUTOMMIO) { if(channel[i].direction == DMA_CPUTOMMIO) {
mem_bus->write(hdma_mmio(i), x); r_mem->write(hdma_mmio(i), x);
} else if(!channel[i].hdma_indirect) { } else if(!channel[i].hdma_indirect) {
mem_bus->write(hdma_addr(i), x); r_mem->write(hdma_addr(i), x);
} else { } else {
mem_bus->write(hdma_iaddr(i), x); r_mem->write(hdma_iaddr(i), x);
} }
add_cycles(8); add_cycles(8);
@@ -135,12 +135,12 @@ void bCPU::hdma_write(uint8 i, uint8 x) {
} }
void bCPU::hdma_update(uint8 i) { void bCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = mem_bus->read(hdma_addr(i)); channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_cycles(8); add_cycles(8);
hdma_add_cycles(8); hdma_add_cycles(8);
if(channel[i].hdma_indirect) { if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = mem_bus->read(hdma_addr(i)) << 8; channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
add_cycles(8); add_cycles(8);
hdma_add_cycles(8); hdma_add_cycles(8);
} }
@@ -155,7 +155,7 @@ void bCPU::hdma_update(uint8 i) {
if(channel[i].hdma_indirect) { if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr >>= 8; channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= mem_bus->read(hdma_addr(i)) << 8; channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
add_cycles(8); add_cycles(8);
hdma_add_cycles(8); hdma_add_cycles(8);
} }

View File

@@ -133,6 +133,7 @@ static int z;
break; break;
case DMASTATE_RUN: case DMASTATE_RUN:
dma_run(); //updates status.dma_cycle_count dma_run(); //updates status.dma_cycle_count
cycle_edge();
break; break;
case DMASTATE_CPUSYNC: case DMASTATE_CPUSYNC:
exec_cycle(); exec_cycle();
@@ -147,18 +148,22 @@ void bCPU::exec_cycle() {
return; return;
} }
//on first cycle? if(status.cycle_pos) {
if(status.cycle_pos == 0) { (this->*optbl[status.opcode])();
snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN); #ifdef DEBUGGER
status.opcode = op_read(); if(status.cycle_pos == 0) {
status.cycle_pos = 1; snes->notify(SNES::CPU_EXEC_OPCODE_END);
}
#endif
return; return;
} }
(this->*optbl[status.opcode])(); //on first cycle?
if(status.cycle_pos == 0) { #ifdef DEBUGGER
snes->notify(SNES::CPU_EXEC_OPCODE_END); snes->notify(SNES::CPU_EXEC_OPCODE_BEGIN);
} #endif
status.opcode = op_read();
status.cycle_pos = 1;
} }
//only return true when we are on an opcode edge //only return true when we are on an opcode edge

View File

@@ -13,7 +13,7 @@ void bCPU::irq_run() {
//WDC documentation is incorrect, first cycle //WDC documentation is incorrect, first cycle
//is a memory read fetch from PBR:PC //is a memory read fetch from PBR:PC
switch(status.cycle_pos++) { switch(status.cycle_pos++) {
case 0: add_cycles(mem_bus->speed(regs.pc.d)); break; case 0: add_cycles(r_mem->speed(regs.pc.d)); break;
case 1: add_cycles(6); break; case 1: add_cycles(6); break;
case 2: stack_write(regs.pc.b); break; case 2: stack_write(regs.pc.b); break;
case 3: stack_write(regs.pc.h); break; case 3: stack_write(regs.pc.h); break;
@@ -25,8 +25,10 @@ void bCPU::irq_run() {
regs.pc.w = rd.w; regs.pc.w = rd.w;
regs.p.i = 1; regs.p.i = 1;
regs.p.d = 0; regs.p.d = 0;
#ifdef DEBUGGER
//let debugger know the new IRQ opcode address //let debugger know the new IRQ opcode address
snes->notify(SNES::CPU_EXEC_OPCODE_END); snes->notify(SNES::CPU_EXEC_OPCODE_END);
#endif
status.cycle_pos = 0; status.cycle_pos = 0;
run_state.irq = false; run_state.irq = false;
break; break;

View File

@@ -37,7 +37,7 @@ void bCPU::mmio_reset() {
//WMDATA //WMDATA
uint8 bCPU::mmio_r2180() { uint8 bCPU::mmio_r2180() {
uint8 r; uint8 r;
r = mem_bus->read(0x7e0000 | status.wram_addr); r = r_mem->read(0x7e0000 | status.wram_addr);
status.wram_addr++; status.wram_addr++;
status.wram_addr &= 0x01ffff; status.wram_addr &= 0x01ffff;
return r; return r;
@@ -324,7 +324,7 @@ uint8 bCPUMMIO::read(uint32 addr) {
uint i; uint i;
//APU //APU
if(addr >= 0x2140 && addr <= 0x217f) { if(addr >= 0x2140 && addr <= 0x217f) {
return apu->port_read(addr & 3); return r_apu->port_read(addr & 3);
} }
//HDMA //HDMA
@@ -374,7 +374,7 @@ uint i;
//WMDATA //WMDATA
void bCPU::mmio_w2180(uint8 value) { void bCPU::mmio_w2180(uint8 value) {
mem_bus->write(0x7e0000 | status.wram_addr, value); r_mem->write(0x7e0000 | status.wram_addr, value);
status.wram_addr++; status.wram_addr++;
status.wram_addr &= 0x01ffff; status.wram_addr &= 0x01ffff;
} }
@@ -441,7 +441,7 @@ void bCPU::mmio_w4200(uint8 value) {
//WRIO //WRIO
void bCPU::mmio_w4201(uint8 value) { void bCPU::mmio_w4201(uint8 value) {
if((status.pio & 0x80) && !(value & 0x80)) { if((status.pio & 0x80) && !(value & 0x80)) {
ppu->latch_counters(); r_ppu->latch_counters();
} }
status.pio = value; status.pio = value;
} }
@@ -525,7 +525,7 @@ void bCPU::mmio_w420c(uint8 value) {
//MEMSEL //MEMSEL
void bCPU::mmio_w420d(uint8 value) { void bCPU::mmio_w420d(uint8 value) {
mem_bus->set_speed(value & 1); r_mem->set_speed(value & 1);
} }
//DMAPx //DMAPx

View File

@@ -239,6 +239,24 @@ uint32 r = status.cycles_executed;
return r; return r;
} }
void bCPU::cycle_edge() {
if(time.hdmainit_triggered == false) {
if(time.hc >= time.hdmainit_trigger_pos || time.v) {
time.hdmainit_triggered = true;
hdmainit_activate();
}
}
if(time.hdma_triggered == false) {
if(time.v <= (overscan() ? 239 : 224)) {
if(time.hc >= 1106) {
time.hdma_triggered = true;
hdma_activate();
}
}
}
}
void bCPU::add_cycles(int cycles) { void bCPU::add_cycles(int cycles) {
status.cycles_executed += cycles; status.cycles_executed += cycles;
@@ -253,23 +271,16 @@ void bCPU::add_cycles(int cycles) {
if(time.v == 0) { if(time.v == 0) {
frame(); frame();
ppu->frame(); r_ppu->frame();
snes->frame(); snes->frame();
} }
scanline(); scanline();
ppu->scanline(); r_ppu->scanline();
snes->scanline(); snes->scanline();
time.line_rendered = false; time.line_rendered = false;
} }
if(time.hdmainit_triggered == false) {
if(time.hc + cycles >= time.hdmainit_trigger_pos || time.v) {
time.hdmainit_triggered = true;
hdmainit_activate();
}
}
if(time.dram_refreshed == false) { if(time.dram_refreshed == false) {
if(time.hc + cycles >= time.dram_refresh_pos) { if(time.hc + cycles >= time.dram_refresh_pos) {
time.dram_refreshed = true; time.dram_refreshed = true;
@@ -296,16 +307,7 @@ void bCPU::add_cycles(int cycles) {
//therefore, wait a few dots before rendering the scanline //therefore, wait a few dots before rendering the scanline
if(time.hc + cycles >= (48 * 4)) { if(time.hc + cycles >= (48 * 4)) {
time.line_rendered = true; time.line_rendered = true;
ppu->render_scanline(); r_ppu->render_scanline();
}
}
if(time.hdma_triggered == false) {
if(time.v <= (overscan() ? 239 : 224)) {
if(time.hc + cycles >= 1106) {
time.hdma_triggered = true;
hdma_activate();
}
} }
} }

View File

@@ -69,5 +69,6 @@ inline uint8 dma_counter();
inline void inc_vcounter(); inline void inc_vcounter();
inline uint16 get_hcounter(); inline uint16 get_hcounter();
inline void cycle_edge();
inline void add_cycles(int cycles); inline void add_cycles(int cycles);
inline void time_reset(); inline void time_reset();

View File

@@ -41,7 +41,7 @@ union {
struct { uint8 l, h; }; struct { uint8 l, h; };
#else #else
struct { uint8 h, l; }; struct { uint8 h, l; };
#endif; #endif
}; };
CPUReg16() { w = 0; } CPUReg16() { w = 0; }

View File

@@ -38,23 +38,23 @@ uint32 r = 0;
break; break;
case OPTYPE_IDP: case OPTYPE_IDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff; addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr); r = (regs.db << 16) + r_mem->read_word(addr);
break; break;
case OPTYPE_IDPX: case OPTYPE_IDPX:
addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff; addr = (regs.d + regs.x + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr); r = (regs.db << 16) + r_mem->read_word(addr);
break; break;
case OPTYPE_IDPY: case OPTYPE_IDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff; addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y; r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
break; break;
case OPTYPE_ILDP: case OPTYPE_ILDP:
addr = (regs.d + (addr & 0xffff)) & 0xffff; addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = mem_bus->read_long(addr); r = r_mem->read_long(addr);
break; break;
case OPTYPE_ILDPY: case OPTYPE_ILDPY:
addr = (regs.d + (addr & 0xffff)) & 0xffff; addr = (regs.d + (addr & 0xffff)) & 0xffff;
r = mem_bus->read_long(addr) + regs.y; r = r_mem->read_long(addr) + regs.y;
break; break;
case OPTYPE_ADDR: case OPTYPE_ADDR:
r = (regs.db << 16) + (addr & 0xffff); r = (regs.db << 16) + (addr & 0xffff);
@@ -88,7 +88,7 @@ uint32 r = 0;
break; break;
case OPTYPE_ISRY: case OPTYPE_ISRY:
addr = (regs.s + (addr & 0xff)) & 0xffff; addr = (regs.s + (addr & 0xff)) & 0xffff;
r = (regs.db << 16) + mem_bus->read_word(addr) + regs.y; r = (regs.db << 16) + r_mem->read_word(addr) + regs.y;
break; break;
} }
return r; return r;
@@ -109,10 +109,10 @@ static CPUReg24 pc;
pc.d = regs.pc.d; pc.d = regs.pc.d;
sprintf(s, "%0.6x ", pc.d); sprintf(s, "%0.6x ", pc.d);
op = mem_bus->read(pc.d); pc.w++; op = r_mem->read(pc.d); pc.w++;
op0 = mem_bus->read(pc.d); pc.w++; op0 = r_mem->read(pc.d); pc.w++;
op1 = mem_bus->read(pc.d); pc.w++; op1 = r_mem->read(pc.d); pc.w++;
op2 = mem_bus->read(pc.d); op2 = r_mem->read(pc.d);
switch(op) { switch(op) {
case 0x00:sprintf(t, "brk #$%0.2x ", op0);break; case 0x00:sprintf(t, "brk #$%0.2x ", op0);break;
@@ -457,7 +457,7 @@ static uint8 op_len_tbl[256] = {
return 0; return 0;
} }
op = mem_bus->read(regs.pc.d); op = r_mem->read(regs.pc.d);
len = op_len_tbl[op]; len = op_len_tbl[op];
if(len == 5)return (regs.p.m)?2:3; if(len == 5)return (regs.p.m)?2:3;
if(len == 6)return (regs.p.x)?2:3; if(len == 6)return (regs.p.x)?2:3;

View File

@@ -183,7 +183,7 @@ int i, v, n;
void bDSP::power() { void bDSP::power() {
int v; int v;
spcram = apu->get_spcram_handle(); spcram = r_apu->get_spcram_handle();
memset(dspram, 0x00, 128); memset(dspram, 0x00, 128);
for(v=0;v<8;v++) { for(v=0;v<8;v++) {

View File

@@ -1,49 +1,81 @@
#define BSNES_VERSION "0.013 wip2" #define BSNES_VERSION "0.014"
#define BSNES_TITLE "bsnes v" BSNES_VERSION #define BSNES_TITLE "bsnes v" BSNES_VERSION
#ifdef POLYMORPHISM
#define ref(x) x
#else
#define ref(x) (&x)
#endif
#define deref(x) __##x
#define r_mem ref(deref(mem))
#define r_cpu ref(deref(cpu))
#define r_apu ref(deref(apu))
#define r_dsp ref(deref(dsp))
#define r_ppu ref(deref(ppu))
#include "reader/reader.h" #include "reader/reader.h"
#include "memory/memory.h" #include "memory/memory.h"
#include "memory/bmemory/bmemory.h" #include "memory/bmemory/bmemory.h"
extern MMIO mmio_unmapped;
extern MemBus *mem_bus;
#include "cpu/cpu.h" #include "cpu/cpu.h"
#include "cpu/bcpu/bcpu.h" #include "cpu/bcpu/bcpu.h"
extern CPU *cpu;
#include "apu/apu.h" #include "apu/apu.h"
#include "apu/bapu/bapu.h" #include "apu/bapu/bapu.h"
#include "apu/bapuskip/bapuskip.h"
extern APU *apu;
#include "dsp/dsp.h" #include "dsp/dsp.h"
#include "dsp/bdsp/bdsp.h" #include "dsp/bdsp/bdsp.h"
extern DSP *dsp;
#include "ppu/ppu.h" #include "ppu/ppu.h"
#include "ppu/bppu/bppu.h" #include "ppu/bppu/bppu.h"
extern PPU *ppu;
#include "snes/snes.h" #include "snes/snes.h"
extern SNES *snes;
#include "chip/srtc/srtc.h" #include "chip/srtc/srtc.h"
#include "chip/sdd1/sdd1.h" #include "chip/sdd1/sdd1.h"
extern MMIO mmio_unmapped;
#ifdef POLYMORPHISM
extern MemBus *deref(mem);
extern CPU *deref(cpu);
extern APU *deref(apu);
extern DSP *deref(dsp);
extern PPU *deref(ppu);
#else
extern bMemBus deref(mem);
extern bCPU deref(cpu);
extern bAPU deref(apu);
extern bDSP deref(dsp);
extern bPPU deref(ppu);
#endif
extern SNES *snes;
extern SRTC *srtc; extern SRTC *srtc;
extern SDD1 *sdd1; extern SDD1 *sdd1;
#include "config/config.h" #include "config/config.h"
#ifdef INTERFACE_MAIN #ifdef INTERFACE_MAIN
#include "config/config.cpp"
MemBus *mem_bus;
CPU *cpu;
APU *apu;
DSP *dsp;
PPU *ppu;
SNES *snes;
SRTC *srtc; #include "config/config.cpp"
SDD1 *sdd1; #ifdef POLYMORPHISM
MemBus *deref(mem);
CPU *deref(cpu);
APU *deref(apu);
DSP *deref(dsp);
PPU *deref(ppu);
#else
bMemBus deref(mem);
bCPU deref(cpu);
bAPU deref(apu);
bDSP deref(dsp);
bPPU deref(ppu);
#endif
SNES *snes;
SRTC *srtc;
SDD1 *sdd1;
#endif #endif

View File

@@ -11,7 +11,6 @@ uint Setting::get() {
} }
void Setting::set(uint _data) { void Setting::set(uint _data) {
printf("%s %d\n", name, _data);
data = _data; data = _data;
if(type != DEC && type != HEX) { if(type != DEC && type != HEX) {

View File

@@ -15,7 +15,7 @@ uint8 mapper, region;
rom_size = rf->size(); rom_size = rf->size();
if(rom_size < 32768) { if(rom_size < 32768) {
free(rom_image); zerofree(rom_image);
return false; return false;
} }
@@ -77,7 +77,7 @@ end:
region = rom[index + 0x19]; region = rom[index + 0x19];
dprintf("* Image Name : \"%s\"", cart_title); dprintf("* Image Name : \"%s\"", cart_title);
dprintf("* Region : %s", (region <= 1)?"NTSC":"PAL"); dprintf("* Region : %s", (region <= 1) ? "NTSC" : "PAL");
dprintf("* MAD : %0.2x", mapper); dprintf("* MAD : %0.2x", mapper);
dprintf("* SRAM Size : %dkb", sram_size / 1024); dprintf("* SRAM Size : %dkb", sram_size / 1024);
dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x", dprintf("* Reset:%0.4x NMI:%0.4x IRQ:%0.4x BRK[n]:%0.4x COP[n]:%0.4x BRK[e]:%0.4x COP[e]:%0.4x",
@@ -206,7 +206,9 @@ static uint32 r;
break; break;
} }
#ifdef DEBUGGER
snes->notify(SNES::MEM_READ, addr, r); snes->notify(SNES::MEM_READ, addr, r);
#endif
return r; return r;
} }
@@ -245,7 +247,9 @@ void bMemBus::write(uint32 addr, uint8 value) {
break; break;
} }
#ifdef DEBUGGER
snes->notify(SNES::MEM_WRITE, addr, value); snes->notify(SNES::MEM_WRITE, addr, value);
#endif
} }
void bMemBus::power() { void bMemBus::power() {

View File

@@ -79,7 +79,7 @@ void Memory::write_long(uint32 addr, uint32 data, uint wrap) {
} }
MMIO mmio_unmapped; MMIO mmio_unmapped;
uint8 MMIO::read (uint32 addr) { return cpu->regs.mdr; } uint8 MMIO::read (uint32 addr) { return r_cpu->regs.mdr; }
void MMIO::write(uint32 addr, uint8 value) {} void MMIO::write(uint32 addr, uint8 value) {}
uint8 MemBus::calc_speed(uint32 addr, bool fast) { uint8 MemBus::calc_speed(uint32 addr, bool fast) {
@@ -92,10 +92,6 @@ uint8 MemBus::calc_speed(uint32 addr, bool fast) {
return 8; return 8;
} }
uint8 MemBus::speed(uint32 addr) {
return speed_table[addr >> 9];
}
void MemBus::set_speed(bool fast) { void MemBus::set_speed(bool fast) {
fastROM = fast; fastROM = fast;

View File

@@ -43,8 +43,10 @@ uint8 *speed_table,
speed_table_fastrom[32768]; speed_table_fastrom[32768];
inline uint8 calc_speed(uint32 addr, bool fast); inline uint8 calc_speed(uint32 addr, bool fast);
public: public:
uint8 speed(uint32 addr); inline uint8 speed(uint32 addr) {
void set_speed(bool fast); return speed_table[addr >> 9];
}
void set_speed(bool fast);
virtual bool load_cart(Reader *rf) = 0; virtual bool load_cart(Reader *rf) = 0;
virtual bool load_sram(Reader *rf) = 0; virtual bool load_sram(Reader *rf) = 0;

View File

@@ -0,0 +1,64 @@
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
if(!regs.color_mode) {
//add
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(regs.color_halve) {
cdest >>= 1;
} else {
if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
}
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
//subtract
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (!regs.color_halve) ? cdest : ((cdest & 0x7bde) >> 1);
}
}
inline uint16 bPPU::addsub_pixel(uint32 cdest) {
uint32 csrc = regs.color_rgb;
if(!regs.color_mode) {
//add
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(regs.color_halve && !regs.addsub_mode) {
cdest >>= 1;
} else {
if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
}
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
//subtract
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
if(regs.color_halve && !regs.addsub_mode) {
return (cdest & 0x7bde) >> 1;
}
return cdest;
}
}

View File

@@ -0,0 +1,82 @@
inline uint16 bPPU::get_palette(uint8 index) {
return read16(cgram, index << 1);
}
inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
//p = 00000bgr <palette data>
//t = BBGGGRRR <tilemap data>
//r = 0BBb00GGGg0RRRr0 <return data>
return ((t & 7) << 2) | ((p & 1) << 1) |
(((t >> 3) & 7) << 7) | (((p >> 1) & 1) << 6) |
((t >> 6) << 13) | ((p >> 2) << 12);
}
inline uint16 bPPU::get_pixel(int x) {
_pixel *p = &pixel_cache[x];
uint16 r, src_back = get_palette(0);
if(p->bg_main && p->bg_sub) {
if(!p->color_exempt && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
if(regs.addsub_mode) {
r = addsub_pixels(p->src_main, p->src_sub);
} else {
r = addsub_pixel(p->src_main);
}
} else {
r = p->src_main;
}
} else if(p->bg_main) {
if(!p->color_exempt && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
r = addsub_pixel(p->src_main);
} else {
r = p->src_main;
}
} else if(p->bg_sub) {
if(regs.color_enabled[BACK]) {
if(window_cache[COL].sub[x]) {
if(regs.addsub_mode) {
r = addsub_pixels(src_back, p->src_sub);
} else {
r = addsub_pixel(src_back);
}
} else {
r = src_back;
}
} else {
r = src_back; //was 0x0000 -- possibly another condition here?
}
} else {
if(window_cache[COL].main[x]) {
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
r = addsub_pixel(src_back);
} else {
r = src_back;
}
} else {
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
r = (!regs.color_mode) ? regs.color_rgb : 0x0000;
} else {
r = 0x0000;
}
}
}
return r;
}
inline void bPPU::render_line_output() {
uint16 r, x;
uint16 *ptr = (uint16*)output + (line.y * 1024) +
((line.interlace && line.interlace_field) ? 512 : 0);
uint16 *ltable = (uint16*)light_table + (regs.display_brightness << 15);
if(line.width == 256) {
for(x=0;x<256;x++) {
r = get_pixel(x);
*ptr++ = *(ltable + r);
}
} else {
for(x=0;x<512;x++) {
r = get_pixel(x);
*ptr++ = *(ltable + r);
}
}
}

View File

@@ -5,11 +5,11 @@
void bPPU::run() {} void bPPU::run() {}
void bPPU::scanline() { void bPPU::scanline() {
line.y = cpu->vcounter(); line.y = r_cpu->vcounter();
line.width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256; line.width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256;
line.hires = (regs.bg_mode == 5 || regs.bg_mode == 6); line.hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
line.interlace = cpu->interlace(); line.interlace = r_cpu->interlace();
line.interlace_field = cpu->interlace_field(); line.interlace_field = r_cpu->interlace_field();
if(line.y == 0) { if(line.y == 0) {
//RTO flag reset //RTO flag reset
@@ -26,7 +26,7 @@ void bPPU::scanline() {
} }
} }
if(line.y == (cpu->overscan() ? 239 : 224) && regs.display_disabled == false) { if(line.y == (r_cpu->overscan() ? 239 : 224) && regs.display_disabled == false) {
//OAM address reset //OAM address reset
regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1; regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1;
} }
@@ -35,17 +35,18 @@ void bPPU::scanline() {
void bPPU::render_scanline() { void bPPU::render_scanline() {
if(status.render_output == false)return; if(status.render_output == false)return;
if(line.y > 0 && line.y < (cpu->overscan() ? 239 : 224)) { if(line.y > 0 && line.y < (r_cpu->overscan() ? 239 : 224)) {
render_line(); render_line();
} }
} }
void bPPU::frame() { void bPPU::frame() {
PPU::frame(); PPU::frame();
snes->notify(SNES::RENDER_FRAME);
} }
void bPPU::power() { void bPPU::power() {
PPU::power();
memset(vram, 0, 65536); memset(vram, 0, 65536);
memset(oam, 0, 544); memset(oam, 0, 544);
memset(cgram, 0, 512); memset(cgram, 0, 512);
@@ -56,6 +57,7 @@ void bPPU::power() {
} }
void bPPU::reset() { void bPPU::reset() {
PPU::reset();
frame(); frame();
memset(sprite_list, 0, sizeof(sprite_list)); memset(sprite_list, 0, sizeof(sprite_list));
@@ -228,9 +230,10 @@ void bPPU::reset() {
regs.color_enabled[BG1] = false; regs.color_enabled[BG1] = false;
//$2132 //$2132
regs.color_r = 0x00; regs.color_r = 0x00;
regs.color_g = 0x00; regs.color_g = 0x00;
regs.color_b = 0x00; regs.color_b = 0x00;
regs.color_rgb = 0x0000;
//$2133 //$2133
regs.mode7_extbg = false; regs.mode7_extbg = false;
@@ -262,20 +265,26 @@ void bPPU::reset() {
uint8 bPPU::vram_read(uint16 addr) { uint8 bPPU::vram_read(uint16 addr) {
uint8 r; uint8 r;
r = vram[addr]; r = vram[addr];
#ifdef DEBUGGER
snes->notify(SNES::VRAM_READ, addr, r); snes->notify(SNES::VRAM_READ, addr, r);
#endif
return r; return r;
} }
void bPPU::vram_write(uint16 addr, uint8 value) { void bPPU::vram_write(uint16 addr, uint8 value) {
vram[addr] = value; vram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::VRAM_WRITE, addr, value); snes->notify(SNES::VRAM_WRITE, addr, value);
#endif
} }
uint8 bPPU::oam_read(uint16 addr) { uint8 bPPU::oam_read(uint16 addr) {
uint8 r; uint8 r;
if(addr >= 0x0200)addr = 0x0200 | (addr & 31); if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
r = oam[addr]; r = oam[addr];
#ifdef DEBUGGER
snes->notify(SNES::OAM_READ, addr, r); snes->notify(SNES::OAM_READ, addr, r);
#endif
return r; return r;
} }
@@ -283,7 +292,9 @@ void bPPU::oam_write(uint16 addr, uint8 value) {
if(addr >= 0x0200)addr = 0x0200 | (addr & 31); if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
oam[addr] = value; oam[addr] = value;
update_sprite_list(addr); update_sprite_list(addr);
#ifdef DEBUGGER
snes->notify(SNES::OAM_WRITE, addr, value); snes->notify(SNES::OAM_WRITE, addr, value);
#endif
} }
uint8 bPPU::cgram_read(uint16 addr) { uint8 bPPU::cgram_read(uint16 addr) {
@@ -293,7 +304,9 @@ uint8 r;
if(addr & 1) { if(addr & 1) {
r &= 0x7f; r &= 0x7f;
} }
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_READ, addr, r); snes->notify(SNES::CGRAM_READ, addr, r);
#endif
return r; return r;
} }
@@ -303,7 +316,9 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
value &= 0x7f; value &= 0x7f;
} }
cgram[addr] = value; cgram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_WRITE, addr, value); snes->notify(SNES::CGRAM_WRITE, addr, value);
#endif
} }
bPPU::bPPU() { bPPU::bPPU() {

View File

@@ -127,6 +127,7 @@ struct {
//$2132 //$2132
uint8 color_r, color_g, color_b; uint8 color_r, color_g, color_b;
uint16 color_rgb;
//$2133 //$2133
bool mode7_extbg; bool mode7_extbg;

View File

@@ -1,6 +1,6 @@
void bPPU::latch_counters() { void bPPU::latch_counters() {
regs.hcounter = cpu->hcounter(); regs.hcounter = r_cpu->hcounter();
regs.vcounter = cpu->vcounter(); regs.vcounter = r_cpu->vcounter();
regs.counters_latched = true; regs.counters_latched = true;
} }
@@ -21,20 +21,20 @@ bool bPPU::vram_can_read() {
return true; return true;
} }
uint16 v = cpu->vcounter(); uint16 v = r_cpu->vcounter();
uint16 hc = cpu->hcycles(); uint16 hc = r_cpu->hcycles();
uint16 ls; uint16 ls;
if(cpu->interlace() && !cpu->interlace_field()) { if(r_cpu->interlace() && !r_cpu->interlace_field()) {
ls = cpu->region_scanlines(); ls = r_cpu->region_scanlines();
} else { } else {
ls = cpu->region_scanlines() - 1; ls = r_cpu->region_scanlines() - 1;
} }
if(v == ls && hc == 1362)return false; if(v == ls && hc == 1362)return false;
if(v < (cpu->overscan() ? 239 : 224))return false; if(v < (r_cpu->overscan() ? 239 : 224))return false;
if(v == (cpu->overscan() ? 239 : 224)) { if(v == (r_cpu->overscan() ? 239 : 224)) {
if(hc == 1362)return true; if(hc == 1362)return true;
return false; return false;
} }
@@ -47,17 +47,17 @@ bool bPPU::vram_can_write(uint8 &value) {
return true; return true;
} }
uint16 v = cpu->vcounter(); uint16 v = r_cpu->vcounter();
uint16 hc = cpu->hcycles(); uint16 hc = r_cpu->hcycles();
if(v == 0) { if(v == 0) {
if(hc <= 4)return true; if(hc <= 4)return true;
if(hc == 6) { value = cpu->regs.mdr; return true; } if(hc == 6) { value = r_cpu->regs.mdr; return true; }
return false; return false;
} }
if(v < (cpu->overscan() ? 240 : 225))return false; if(v < (r_cpu->overscan() ? 240 : 225))return false;
if(v == (cpu->overscan() ? 240 : 225)) { if(v == (r_cpu->overscan() ? 240 : 225)) {
if(hc <= 4)return false; if(hc <= 4)return false;
return true; return true;
} }
@@ -542,6 +542,8 @@ void bPPU::mmio_w2132(uint8 value) {
if(value & 0x80)regs.color_b = value & 0x1f; if(value & 0x80)regs.color_b = value & 0x1f;
if(value & 0x40)regs.color_g = value & 0x1f; if(value & 0x40)regs.color_g = value & 0x1f;
if(value & 0x20)regs.color_r = value & 0x1f; if(value & 0x20)regs.color_r = value & 0x1f;
regs.color_rgb = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
} }
//SETINI //SETINI
@@ -552,8 +554,8 @@ void bPPU::mmio_w2133(uint8 value) {
regs.oam_halve = !!(value & 0x02); regs.oam_halve = !!(value & 0x02);
regs.interlace = !!(value & 0x01); regs.interlace = !!(value & 0x01);
cpu->set_overscan(regs.overscan); r_cpu->set_overscan(regs.overscan);
cpu->set_interlace(regs.interlace); r_cpu->set_interlace(regs.interlace);
} }
//MPYL //MPYL
@@ -582,10 +584,10 @@ uint32 r;
//SLHV //SLHV
uint8 bPPU::mmio_r2137() { uint8 bPPU::mmio_r2137() {
if(cpu->pio_status() & 0x80) { if(r_cpu->pio_status() & 0x80) {
latch_counters(); latch_counters();
} }
return cpu->regs.mdr; return r_cpu->regs.mdr;
} }
//OAMDATAREAD //OAMDATAREAD
@@ -689,8 +691,8 @@ uint8 r = 0x00;
regs.latch_hcounter = 0; regs.latch_hcounter = 0;
regs.latch_vcounter = 0; regs.latch_vcounter = 0;
r |= cpu->interlace_field() << 7; r |= r_cpu->interlace_field() << 7;
if(!(cpu->pio_status() & 0x80)) { if(!(r_cpu->pio_status() & 0x80)) {
r |= 0x40; r |= 0x40;
} else if(regs.counters_latched == true) { } else if(regs.counters_latched == true) {
r |= 0x40; r |= 0x40;
@@ -738,7 +740,7 @@ uint8 bPPUMMIO::read(uint32 addr) {
case 0x213f:return ppu->mmio_r213f(); //STAT78 case 0x213f:return ppu->mmio_r213f(); //STAT78
} }
return cpu->regs.mdr; return r_cpu->regs.mdr;
} }
void bPPUMMIO::write(uint32 addr, uint8 value) { void bPPUMMIO::write(uint32 addr, uint8 value) {

View File

@@ -20,28 +20,25 @@ inline void bPPU::render_line_mode0() {
} }
/* /*
Mode 1 (pri=0): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
Mode 1 (pri=1): -> Mode 1 (pri=1): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A BG3B, OAM0, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3, BG3A
Mode 1 (pri=0): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
BG3B, OAM0, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3
*/ */
inline void bPPU::render_line_mode1() { inline void bPPU::render_line_mode1() {
switch(regs.bg3_priority) { if(regs.bg3_priority) {
case 0:
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
render_line_oam(2, 4, 7, 10);
break;
case 1:
render_line_bg(BG1, COLORDEPTH_16, 5, 8); render_line_bg(BG1, COLORDEPTH_16, 5, 8);
render_line_bg(BG2, COLORDEPTH_16, 4, 7); render_line_bg(BG2, COLORDEPTH_16, 4, 7);
render_line_bg(BG3, COLORDEPTH_4, 1, 10); render_line_bg(BG3, COLORDEPTH_4, 1, 10);
render_line_oam(2, 3, 6, 9); render_line_oam(2, 3, 6, 9);
break; } else {
render_line_bg(BG1, COLORDEPTH_16, 6, 9);
render_line_bg(BG2, COLORDEPTH_16, 5, 8);
render_line_bg(BG3, COLORDEPTH_4, 1, 3);
render_line_oam(2, 4, 7, 10);
} }
} }
@@ -121,7 +118,7 @@ inline void bPPU::render_line_mode7() {
void bPPU::render_line() { void bPPU::render_line() {
if(regs.display_disabled == true) { if(regs.display_disabled == true) {
memset(snes->get_ppu_output_handle(), 0, 1024); memset(output + (line.y * 1024), 0, 1024);
return; return;
} }

View File

@@ -64,24 +64,25 @@ struct oam_tileitem {
} oam_tilelist[34]; } oam_tilelist[34];
enum { OAM_PRI_NONE = 4 }; enum { OAM_PRI_NONE = 4 };
uint8 oam_line_pal[512], oam_line_pri[512]; uint8 oam_line_pal[256], oam_line_pri[256];
bool is_sprite_on_scanline(); bool is_sprite_on_scanline();
void load_oam_tiles(); void load_oam_tiles();
void render_oam_tile(int tile_num); void render_oam_tile(int tile_num);
void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos); void render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
void render_line_oam_lores(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
void render_line_oam_hires(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos);
//bppu_render_mode7.cpp //bppu_render_mode7.cpp
void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos); void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos);
//bppu_render_addsub.cpp //bppu_render_addsub.cpp
inline uint16 addsub_pixels(uint32 cdest, uint32 csrc); inline uint16 addsub_pixels(uint32 x);
inline uint16 addsub_pixel (uint32 cdest);
//bppu_render_line.cpp //bppu_render_line.cpp
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 }; enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
inline uint16 get_palette(uint8 index); inline uint16 get_palette(uint8 index);
inline uint16 get_direct_color(uint8 p, uint8 t); inline uint16 get_direct_color(uint8 p, uint8 t);
inline uint16 get_pixel(int x); inline uint16 get_pixel(uint32 x);
inline void render_line_output(); inline void render_line_output();

View File

@@ -1,92 +1,39 @@
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) { inline uint16 bPPU::addsub_pixels(uint32 x) {
int r, g, b; uint32 cdest = pixel_cache[x].src_main,
uint16 res; csrc = pixel_cache[x].src_sub;
switch(regs.color_mode) { bool halve = false;
case 0: //COLORMODE_ADD: if(regs.color_halve && window_cache[COL].main[x]) {
if(regs.color_halve == true) { if(regs.addsub_mode && pixel_cache[x].bg_sub == BACK);
cdest = ((cdest << 16) | cdest) & 0x03e07c1f; else {
csrc = ((csrc << 16) | csrc) & 0x03e07c1f; halve = true;
cdest += csrc;
cdest >>= 1;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} }
break;
case 1: //COLORMODE_SUB:
if(regs.color_halve == true) {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (cdest & 0x7bde) >> 1;
} else {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return cdest;
}
break;
} }
return 0x0000; //prevent annoying warning message
}
inline uint16 bPPU::addsub_pixel(uint32 cdest) { if(!regs.color_mode) {
int r, g, b; //add
uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10); cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
uint16 res; csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
switch(regs.color_mode) { cdest += csrc;
case 0: //COLORMODE_ADD:
if(regs.color_halve == true && regs.addsub_mode == 0) { if(!halve) {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
cdest >>= 1;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(cdest & 0x04000000)cdest |= 0x03e00000; if(cdest & 0x04000000)cdest |= 0x03e00000;
if(cdest & 0x00008000)cdest |= 0x00007c00; if(cdest & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f; if(cdest & 0x00000020)cdest |= 0x0000001f;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
}
break;
case 1: //COLORMODE_SUB:
if(regs.color_halve == true && regs.addsub_mode == 0) {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (cdest & 0x7bde) >> 1;
} else { } else {
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00; cdest >>= 1;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return cdest;
} }
break;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
} else {
//subtract
if((cdest & 0x7c00) < (csrc & 0x7c00))cdest &= ~0x7c00;
else cdest -= (csrc & 0x7c00);
if((cdest & 0x03e0) < (csrc & 0x03e0))cdest &= ~0x03e0;
else cdest -= (csrc & 0x03e0);
if((cdest & 0x001f) < (csrc & 0x001f))cdest &= ~0x001f;
else cdest -= (csrc & 0x001f);
return (!halve) ? cdest : ((cdest & 0x7bde) >> 1);
} }
return 0x0000; //prevent annoying warning message
} }

View File

@@ -43,6 +43,7 @@ uint16 opt_valid_bit = (bg == BG1) ? 0x2000 : ((bg == BG2) ? 0x4000 : 0x0000);
uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0; uint8 bgpal_index = (regs.bg_mode == 0) ? (bg << 5) : 0;
uint8 pal_size = (color_depth == 2) ? 256 : ((color_depth == 1) ? 16 : 4); uint8 pal_size = (color_depth == 2) ? 256 : ((color_depth == 1) ? 16 : 4);
uint16 tile_mask = (color_depth == 2) ? 0x03ff : ((color_depth == 1) ? 0x07ff : 0x0fff);
//4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile //4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile
//index is a tile number count to add to base tile number //index is a tile number count to add to base tile number
uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth); uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth);
@@ -145,6 +146,7 @@ int32 prev_x = -1, prev_y = -1;
tile_num &= 0x03ff; tile_num &= 0x03ff;
tile_num += tiledata_index; tile_num += tiledata_index;
tile_num &= tile_mask;
if(bg_td_state[tile_num] == 1) { if(bg_td_state[tile_num] == 1) {
render_bg_tile(color_depth, tile_num); render_bg_tile(color_depth, tile_num);
@@ -162,7 +164,7 @@ int32 prev_x = -1, prev_y = -1;
xpos = mosaic_x & 7; xpos = mosaic_x & 7;
if(mirror_x)xpos ^= 7; //invert x tile pos if(mirror_x)xpos ^= 7; //invert x tile pos
col = *(tile_ptr + xpos); col = *(tile_ptr + xpos);
if(col && window_cache[COL].main[x]) { if(col) {
if(regs.direct_color == true && bg == BG1 && (regs.bg_mode == 3 || regs.bg_mode == 4)) { if(regs.direct_color == true && bg == BG1 && (regs.bg_mode == 3 || regs.bg_mode == 4)) {
col = get_direct_color(pal_num, col); col = get_direct_color(pal_num, col);
} else { } else {

View File

@@ -118,7 +118,7 @@ void bPPU::init_tiledata_cache() {
void bPPU::clear_tiledata_cache() { void bPPU::clear_tiledata_cache() {
memset(bg_tiledata[TILE_2BIT], 0, 262144); memset(bg_tiledata[TILE_2BIT], 0, 262144);
memset(bg_tiledata[TILE_4BIT], 0, 131072); memset(bg_tiledata[TILE_4BIT], 0, 131072);
memset(bg_tiledata[TILE_4BIT], 0, 65536); memset(bg_tiledata[TILE_8BIT], 0, 65536);
memset(bg_tiledata_state[TILE_2BIT], 0, 4096); memset(bg_tiledata_state[TILE_2BIT], 0, 4096);
memset(bg_tiledata_state[TILE_4BIT], 0, 2048); memset(bg_tiledata_state[TILE_4BIT], 0, 2048);
memset(bg_tiledata_state[TILE_8BIT], 0, 1024); memset(bg_tiledata_state[TILE_8BIT], 0, 1024);

View File

@@ -11,71 +11,59 @@ inline uint16 bPPU::get_direct_color(uint8 p, uint8 t) {
((t >> 6) << 13) | ((p >> 2) << 12); ((t >> 6) << 13) | ((p >> 2) << 12);
} }
inline uint16 bPPU::get_pixel(int x) { inline uint16 bPPU::get_pixel(uint32 x) {
_pixel *p = &pixel_cache[x]; _pixel *p = &pixel_cache[x];
uint16 _r, src_back = get_palette(0); if(!p->bg_main) {
if(p->bg_main && p->bg_sub) { p->bg_main = BACK;
if(p->color_exempt == false && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) { p->src_main = get_palette(0);
if(regs.addsub_mode) { p->color_exempt = false;
_r = addsub_pixels(p->src_main, p->src_sub);
} else {
_r = addsub_pixel(p->src_main);
}
} else {
_r = p->src_main;
}
} else if(p->bg_main) {
if(p->color_exempt == false && regs.color_enabled[p->bg_main & 0x7f] && window_cache[COL].sub[x]) {
_r = addsub_pixel(p->src_main);
} else {
_r = p->src_main;
}
} else if(p->bg_sub) {
if(regs.color_enabled[BACK]) {
if(window_cache[COL].sub[x]) {
if(regs.addsub_mode) {
_r = addsub_pixels(src_back, p->src_sub);
} else {
_r = addsub_pixel(src_back);
}
} else {
_r = src_back;
}
} else {
_r = src_back; //was 0x0000 -- possibly another condition here?
}
} else { } else {
if(window_cache[COL].main[x]) { p->bg_main &= 0x7f;
if(regs.color_enabled[BACK] && window_cache[COL].sub[x]) {
_r = addsub_pixel(src_back);
} else {
_r = src_back;
}
} else {
_r = 0x0000;
}
} }
return _r;
if(!p->bg_sub) {
p->bg_sub = BACK;
p->src_sub = regs.color_rgb;
} else {
p->bg_sub &= 0x7f;
}
if(!regs.addsub_mode) {
p->bg_sub = BACK;
p->src_sub = regs.color_rgb;
}
if(!window_cache[COL].main[x]) {
if(!window_cache[COL].sub[x]) {
return 0x0000;
}
//p->bg_main remains the same, even when the main color window
//masks out the color. this is needed for regs.color_enabled[p->bg_main]
//test below. illusion of gaia relies on this behavior for its load menu.
p->src_main = 0x0000;
}
if(!p->color_exempt && regs.color_enabled[p->bg_main] && window_cache[COL].sub[x]) {
return addsub_pixels(x);
}
return p->src_main;
} }
inline void bPPU::render_line_output() { inline void bPPU::render_line_output() {
int x; uint16 r, x;
uint16 _r; uint16 *ptr = (uint16*)output + (line.y * 1024) +
uint16 *ptr; ((line.interlace && line.interlace_field) ? 512 : 0);
ptr = (uint16*)snes->get_ppu_output_handle(); uint16 *ltable = (uint16*)light_table + (regs.display_brightness << 15);
uint16 *ltable;
ltable = (uint16*)light_table + (regs.display_brightness << 15);
if(line.width == 256) { if(line.width == 256) {
for(x=0;x<256;x++) { for(x=0;x<256;x++) {
_r = get_pixel(x); r = get_pixel(x);
*ptr++ = *(ltable + _r); *ptr++ = *(ltable + r);
} }
} else { } else {
for(x=0;x<512;x++) { for(x=0;x<512;x++) {
_r = get_pixel(x); r = get_pixel(x);
*ptr++ = *(ltable + _r); *ptr++ = *(ltable + r);
} }
} }
} }

View File

@@ -120,29 +120,27 @@ int32 psy = ((c * CLIP(hofs - cx)) & ~63) + ((d * CLIP(vofs - cy)) & ~63) + ((d
_x = x; _x = x;
} }
if(window_cache[COL].main[_x]) { uint32 col;
uint32 col; if(regs.direct_color == true && bg == BG1) {
if(regs.direct_color == true && bg == BG1) { //direct color mode does not apply to bg2, as it is only 128 colors...
//direct color mode does not apply to bg2, as it is only 128 colors... col = get_direct_color(0, palette);
col = get_direct_color(0, palette); } else {
} else { col = get_palette(palette);
col = get_palette(palette); }
}
if(regs.bg_enabled[bg] == true && !wt_main[_x]) { if(regs.bg_enabled[bg] == true && !wt_main[_x]) {
if(pixel_cache[_x].pri_main < _pri) { if(pixel_cache[_x].pri_main < _pri) {
pixel_cache[_x].pri_main = _pri; pixel_cache[_x].pri_main = _pri;
pixel_cache[_x].bg_main = 0x80 | bg; pixel_cache[_x].bg_main = 0x80 | bg;
pixel_cache[_x].src_main = col; pixel_cache[_x].src_main = col;
pixel_cache[_x].color_exempt = false; pixel_cache[_x].color_exempt = false;
}
} }
if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) { }
if(pixel_cache[_x].pri_sub < _pri) { if(regs.bgsub_enabled[bg] == true && !wt_sub[_x]) {
pixel_cache[_x].pri_sub = _pri; if(pixel_cache[_x].pri_sub < _pri) {
pixel_cache[_x].bg_sub = 0x80 | bg; pixel_cache[_x].pri_sub = _pri;
pixel_cache[_x].src_sub = col; pixel_cache[_x].bg_sub = 0x80 | bg;
} pixel_cache[_x].src_sub = col;
} }
} }
} }

View File

@@ -63,10 +63,10 @@ uint16 width, height;
addr &= 0x001f; addr &= 0x001f;
z = oam[0x0200 + addr]; z = oam[0x0200 + addr];
i = addr << 2; i = addr << 2;
sprite_list[i ].x = ((z & 0x01)?0x0100:0x0000) + (sprite_list[i ].x & 0xff); sprite_list[i ].x = ((z & 0x01) ? 256 : 0) + (sprite_list[i ].x & 255);
sprite_list[i + 1].x = ((z & 0x04)?0x0100:0x0000) + (sprite_list[i + 1].x & 0xff); sprite_list[i + 1].x = ((z & 0x04) ? 256 : 0) + (sprite_list[i + 1].x & 255);
sprite_list[i + 2].x = ((z & 0x10)?0x0100:0x0000) + (sprite_list[i + 2].x & 0xff); sprite_list[i + 2].x = ((z & 0x10) ? 256 : 0) + (sprite_list[i + 2].x & 255);
sprite_list[i + 3].x = ((z & 0x40)?0x0100:0x0000) + (sprite_list[i + 3].x & 0xff); sprite_list[i + 3].x = ((z & 0x40) ? 256 : 0) + (sprite_list[i + 3].x & 255);
get_sprite_size(i, !!(z & 0x02)); get_sprite_size(i, !!(z & 0x02));
get_sprite_size(i + 1, !!(z & 0x08)); get_sprite_size(i + 1, !!(z & 0x08));
get_sprite_size(i + 2, !!(z & 0x20)); get_sprite_size(i + 2, !!(z & 0x20));
@@ -90,7 +90,7 @@ uint16 addr = 0x0200;
bool bPPU::is_sprite_on_scanline() { bool bPPU::is_sprite_on_scanline() {
//if sprite is entirely offscreen and doesn't wrap around to the left side of the screen, //if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
//then it is not counted. 256 is correct, and not 255 -- as one might first expect //then it is not counted. 256 is correct, and not 255 -- as one might first expect
if(spr->x > 256 && (spr->x + spr->width) < 512 && line.width != 512)return false; if(spr->x > 256 && (spr->x + spr->width) < 512)return false;
if(regs.oam_halve == false) { if(regs.oam_halve == false) {
if(line.y >= spr->y && line.y < (spr->y + spr->height)) { if(line.y >= spr->y && line.y < (spr->y + spr->height)) {
@@ -110,19 +110,10 @@ bool bPPU::is_sprite_on_scanline() {
} }
void bPPU::load_oam_tiles() { void bPPU::load_oam_tiles() {
uint16 tile_width; uint16 tile_width = spr->width >> 3;
tile_width = spr->width >> 3; int x = spr->x;
int y = (spr->vflip) ? ((spr->height - 1) - (line.y - spr->y)) : (line.y - spr->y);
int x, y, chr, nameselect_index;
x = spr->x;
if(line.width == 512)x <<= 1;
x &= 511;
if(spr->vflip) {
y = ((spr->height - 1) - (line.y - spr->y));
} else {
y = (line.y - spr->y);
}
//todo: double-check code below. seems that interlace_field //todo: double-check code below. seems that interlace_field
//should be added to hires 512x448 sprites as well, and not //should be added to hires 512x448 sprites as well, and not
//just when oam_halve is enabled... //just when oam_halve is enabled...
@@ -132,40 +123,40 @@ int x, y, chr, nameselect_index;
y += line.interlace_field; y += line.interlace_field;
} }
} }
x &= 511;
y &= 255; y &= 255;
chr = spr->character; uint16 tdaddr = regs.oam_tdaddr;
uint16 chrx = (spr->character ) & 15;
uint16 chry = (spr->character >> 4) & 15;
if(spr->use_nameselect == true) { if(spr->use_nameselect == true) {
chr += 256; tdaddr += (256 * 32) + (regs.oam_nameselect << 13);
nameselect_index = regs.oam_nameselect << 13;
} else {
nameselect_index = 0x0000;
} }
chr += (y >> 3) << 4; chry += (y >> 3);
chry &= 15;
chry <<= 4;
int i, n, mx, pos, z; int i, n, sx, mx, pos;
for(i=0;i<tile_width;i++) { for(i=0;i<tile_width;i++) {
z = x; sx = x;
z += (i << ((line.width == 512) ? 4 : 3)); sx += i << 3;
z &= 511; sx &= 511;
//ignore sprites that are offscreen //ignore sprites that are offscreen
//sprites at 256 are still counted, even though they aren't visible onscreen //sprites at 256 are still counted, even though they aren't visible onscreen
if(z >= 257 && (z + 7) < 512 && line.width != 512)continue; if(sx >= 257 && (sx + 7) < 512)continue;
if(regs.oam_tilecount++ > 34)break; if(regs.oam_tilecount++ > 34)break;
n = regs.oam_tilecount - 1; n = regs.oam_tilecount - 1;
oam_tilelist[n].x = z; oam_tilelist[n].x = sx;
oam_tilelist[n].y = y; oam_tilelist[n].y = y;
oam_tilelist[n].pri = spr->priority; oam_tilelist[n].pri = spr->priority;
oam_tilelist[n].pal = (spr->palette << 4) + 128; oam_tilelist[n].pal = (spr->palette << 4) + 128;
oam_tilelist[n].hflip = spr->hflip; oam_tilelist[n].hflip = spr->hflip;
if(oam_tilelist[n].hflip) { mx = (oam_tilelist[n].hflip) ? ((tile_width - 1) - i) : i;
mx = (tile_width - 1) - i; pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
} else {
mx = i;
}
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + nameselect_index;
oam_tilelist[n].tile = (pos >> 5) & 0x07ff; oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
} }
} }
@@ -182,38 +173,26 @@ oam_tileitem *t = &oam_tilelist[tile_num];
int x, sx, col; int x, sx, col;
sx = t->x; sx = t->x;
//tile_ptr = tiledata + (tile * (8_width * 8_height)) + ((y & 7_height_mask) * 8_width);
tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3); tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3);
for(x=0;x<8;x++) { for(x=0;x<8;x++) {
sx &= 511; sx &= 511;
if(sx < line.width) { if(sx < 256) {
col = *(tile_ptr + ((t->hflip)?7-x:x)); col = *(tile_ptr + ((t->hflip) ? (7 - x) : x));
if(col) { if(col) {
col += t->pal; col += t->pal;
oam_line_pal[sx] = col; oam_line_pal[sx] = col;
oam_line_pri[sx] = t->pri; oam_line_pri[sx] = t->pri;
if(line.width == 512) {
oam_line_pal[sx + 1] = col;
oam_line_pri[sx + 1] = t->pri;
}
} }
} }
sx += (line.width == 512) ? 2 : 1; sx++;
} }
} }
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) { void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
int s, x; int s;
bool _bg_enabled = regs.bg_enabled[OAM];
bool _bgsub_enabled = regs.bgsub_enabled[OAM];
build_window_tables(OAM);
uint8 *wt_main = window_cache[OAM].main;
uint8 *wt_sub = window_cache[OAM].sub;
regs.oam_itemcount = 0; regs.oam_itemcount = 0;
regs.oam_tilecount = 0; regs.oam_tilecount = 0;
memset(oam_line_pri, OAM_PRI_NONE, 512); memset(oam_line_pri, OAM_PRI_NONE, 256);
memset(oam_itemlist, 0xff, 32); memset(oam_itemlist, 0xff, 32);
for(s=0;s<128;s++) { for(s=0;s<128;s++) {
@@ -239,34 +218,105 @@ uint8 *wt_sub = window_cache[OAM].sub;
regs.time_over |= (regs.oam_tilecount > 34); regs.time_over |= (regs.oam_tilecount > 34);
regs.range_over |= (regs.oam_itemcount > 32); regs.range_over |= (regs.oam_itemcount > 32);
if(_bg_enabled == false && _bgsub_enabled == false)return; if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false)return;
int _pri; if(line.width == 256) {
for(x=0;x<line.width;x++) { render_line_oam_lores(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
} else {
render_line_oam_hires(pri0_pos, pri1_pos, pri2_pos, pri3_pos);
}
}
void bPPU::render_line_oam_lores(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
bool bg_enabled = regs.bg_enabled[OAM];
bool bgsub_enabled = regs.bgsub_enabled[OAM];
build_window_tables(OAM);
uint8 *wt_main = window_cache[OAM].main;
uint8 *wt_sub = window_cache[OAM].sub;
int pri;
for(int x=0;x<256;x++) {
if(oam_line_pri[x] == OAM_PRI_NONE)continue; if(oam_line_pri[x] == OAM_PRI_NONE)continue;
switch(oam_line_pri[x]) { switch(oam_line_pri[x]) {
case 0:_pri = pri0_pos;break; case 0:pri = pri0_pos;break;
case 1:_pri = pri1_pos;break; case 1:pri = pri1_pos;break;
case 2:_pri = pri2_pos;break; case 2:pri = pri2_pos;break;
case 3:_pri = pri3_pos;break; case 3:pri = pri3_pos;break;
} }
if(window_cache[COL].main[x]) { if(bg_enabled == true && !wt_main[x]) {
if(_bg_enabled == true && !wt_main[x]) { if(pixel_cache[x].pri_main < pri) {
if(pixel_cache[x].pri_main < _pri) { pixel_cache[x].pri_main = pri;
pixel_cache[x].pri_main = _pri; pixel_cache[x].bg_main = PC_OAM;
pixel_cache[x].bg_main = PC_OAM; pixel_cache[x].src_main = get_palette(oam_line_pal[x]);
pixel_cache[x].src_main = get_palette(oam_line_pal[x]); pixel_cache[x].color_exempt = (oam_line_pal[x] < 192);
pixel_cache[x].color_exempt = (oam_line_pal[x] < 192);
}
} }
if(_bgsub_enabled == true && !wt_sub[x]) { }
if(pixel_cache[x].pri_sub < _pri) {
pixel_cache[x].pri_sub = _pri; if(bgsub_enabled == true && !wt_sub[x]) {
pixel_cache[x].bg_sub = PC_OAM; if(pixel_cache[x].pri_sub < pri) {
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]); pixel_cache[x].pri_sub = pri;
} pixel_cache[x].bg_sub = PC_OAM;
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]);
}
}
}
}
void bPPU::render_line_oam_hires(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
bool bg_enabled = regs.bg_enabled[OAM];
bool bgsub_enabled = regs.bgsub_enabled[OAM];
build_window_tables(OAM);
uint8 *wt_main = window_cache[OAM].main;
uint8 *wt_sub = window_cache[OAM].sub;
int pri, sx;
for(int x=0;x<256;x++) {
if(oam_line_pri[x] == OAM_PRI_NONE)continue;
switch(oam_line_pri[x]) {
case 0:pri = pri0_pos;break;
case 1:pri = pri1_pos;break;
case 2:pri = pri2_pos;break;
case 3:pri = pri3_pos;break;
}
sx = x << 1;
if(bg_enabled == true && !wt_main[sx]) {
if(pixel_cache[sx].pri_main < pri) {
pixel_cache[sx].pri_main = pri;
pixel_cache[sx].bg_main = PC_OAM;
pixel_cache[sx].src_main = get_palette(oam_line_pal[x]);
pixel_cache[sx].color_exempt = (oam_line_pal[x] < 192);
}
}
if(bgsub_enabled == true && !wt_sub[sx]) {
if(pixel_cache[sx].pri_sub < pri) {
pixel_cache[sx].pri_sub = pri;
pixel_cache[sx].bg_sub = PC_OAM;
pixel_cache[sx].src_sub = get_palette(oam_line_pal[x]);
}
}
sx++;
if(bg_enabled == true && !wt_main[sx]) {
if(pixel_cache[sx].pri_main < pri) {
pixel_cache[sx].pri_main = pri;
pixel_cache[sx].bg_main = PC_OAM;
pixel_cache[sx].src_main = get_palette(oam_line_pal[x]);
pixel_cache[sx].color_exempt = (oam_line_pal[x] < 192);
}
}
if(bgsub_enabled == true && !wt_sub[sx]) {
if(pixel_cache[sx].pri_sub < pri) {
pixel_cache[sx].pri_sub = pri;
pixel_cache[sx].bg_sub = PC_OAM;
pixel_cache[sx].src_sub = get_palette(oam_line_pal[x]);
} }
} }
} }

View File

@@ -2,14 +2,16 @@
void PPU::get_scanline_info(scanline_info *info) { void PPU::get_scanline_info(scanline_info *info) {
info->hires = scanline_is_hires(); info->hires = scanline_is_hires();
info->interlace = cpu->interlace(); info->interlace = r_cpu->interlace();
} }
void PPU::enable_renderer(bool r) { status.render_output = r; } void PPU::enable_renderer(bool r) { status.render_output = r; }
bool PPU::renderer_enabled() { return status.render_output; } bool PPU::renderer_enabled() { return status.render_output; }
void PPU::frame() { void PPU::frame() {
static fr = 0, fe = 0; status.frame_executed = true;
static int32 fr = 0, fe = 0;
static time_t prev, curr; static time_t prev, curr;
fe++; fe++;
if(status.render_output)fr++; if(status.render_output)fr++;
@@ -24,7 +26,16 @@ static time_t prev, curr;
prev = curr; prev = curr;
} }
void PPU::power() {}
void PPU::reset() {
memset(output, 0, 512 * 480 * sizeof(uint16));
}
PPU::PPU() { PPU::PPU() {
output = (uint16*)malloc(512 * 480 * sizeof(uint16));
memset(output, 0, 512 * 480 * sizeof(uint16));
status.render_output = true; status.render_output = true;
status.frames_updated = false; status.frames_updated = false;
status.frames_rendered = 0; status.frames_rendered = 0;
@@ -35,4 +46,6 @@ PPU::PPU() {
mmio = &mmio_unmapped; mmio = &mmio_unmapped;
} }
PPU::~PPU() {} PPU::~PPU() {
zerofree(output);
}

View File

@@ -1,11 +1,13 @@
class PPU { class PPU {
public: public:
uint16 *output;
//this struct should be read-only to //this struct should be read-only to
//functions outside of this class //functions outside of this class
struct { struct {
bool render_output; bool render_output;
bool frame_executed;
bool frames_updated; bool frames_updated;
uint32 frames_rendered; uint32 frames_rendered;
uint32 frames_executed; uint32 frames_executed;
@@ -43,8 +45,8 @@ struct scanline_info {
virtual void scanline() = 0; virtual void scanline() = 0;
virtual void render_scanline() = 0; virtual void render_scanline() = 0;
virtual void frame(); virtual void frame();
virtual void power() = 0; virtual void power();
virtual void reset() = 0; virtual void reset();
virtual void enable_renderer(bool r); virtual void enable_renderer(bool r);
virtual bool renderer_enabled(); virtual bool renderer_enabled();

View File

@@ -5,7 +5,7 @@ OBJS = sdlmain.o \
reader.o \ reader.o \
memory.o bmemory.o \ memory.o bmemory.o \
cpu.o bcpu.o \ cpu.o bcpu.o \
apu.o bapu.o bapuskip.o \ apu.o bapu.o \
bdsp.o \ bdsp.o \
ppu.o bppu.o \ ppu.o bppu.o \
snes.o \ snes.o \
@@ -58,9 +58,6 @@ apu.o: ../apu/*
bapu.o: ../apu/bapu/* bapu.o: ../apu/bapu/*
$(CC) $(CFLAGS) -c ../apu/bapu/bapu.cpp $(CC) $(CFLAGS) -c ../apu/bapu/bapu.cpp
bapuskip.o: ../apu/bapuskip/*
$(CC) $(CFLAGS) -c ../apu/bapuskip/bapuskip.cpp
########### ###########
### dsp ### ### dsp ###
########### ###########

View File

@@ -1,11 +1,11 @@
CC = cl CC = cl
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs /DARCH_LSB CFLAGS = /nologo /O2 /wd4996
OBJS = sdlmain.obj \ OBJS = sdlmain.obj \
libstring.obj libconfig.obj \ libstring.obj libconfig.obj \
reader.obj \ reader.obj \
memory.obj bmemory.obj \ memory.obj bmemory.obj \
cpu.obj bcpu.obj \ cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \ apu.obj bapu.obj \
bdsp.obj \ bdsp.obj \
ppu.obj bppu.obj \ ppu.obj bppu.obj \
snes.obj \ snes.obj \
@@ -59,9 +59,6 @@ apu.obj: ../apu/*
bapu.obj: ../apu/bapu/* bapu.obj: ../apu/bapu/*
$(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp $(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp
bapuskip.obj: ../apu/bapuskip/*
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
########### ###########
### dsp ### ### dsp ###
########### ###########

View File

@@ -6,11 +6,7 @@ void bSNES::run() {
switch(run_status) { switch(run_status) {
case RUN: case RUN:
while(update_frame == false) { SNES::runtoframe();
SNES::run();
}
update_frame = false;
render();
return; return;
case STOP: case STOP:
break; break;
@@ -18,13 +14,13 @@ void bSNES::run() {
} }
void bSNES::video_run() { void bSNES::video_run() {
if(ppu->status.frames_updated) { if(r_ppu->status.frames_updated) {
char s[512], t[512]; char s[512], t[512];
ppu->status.frames_updated = false; r_ppu->status.frames_updated = false;
// if((bool)config::gui.show_fps == true) { // if((bool)config::gui.show_fps == true) {
sprintf(s, "%s : %d fps", BSNES_TITLE, ppu->status.frames_executed); sprintf(s, "%s : %d fps", BSNES_TITLE, r_ppu->status.frames_executed);
// if(w_main->frameskip != 0) { // if(w_main->frameskip != 0) {
// sprintf(t, " (%d frames)", ppu->status.frames_rendered); // sprintf(t, " (%d frames)", r_ppu->status.frames_rendered);
// strcat(s, t); // strcat(s, t);
// } // }
SDL_WM_SetCaption(s, 0); SDL_WM_SetCaption(s, 0);
@@ -34,7 +30,28 @@ void bSNES::video_run() {
render(); render();
} }
void bSNES::sound_run() {} void bSNES::sound_run(uint32 data) {}
uint16 *bSNES::video_lock(uint32 &pitch) {
if(SDL_MUSTLOCK(screen)) {
SDL_LockSurface(screen);
}
if(SDL_MUSTLOCK(backbuffer)) {
SDL_LockSurface(backbuffer);
}
pitch = backbuffer->pitch;
return (uint16*)backbuffer->pixels;
}
void bSNES::video_unlock() {
if(SDL_MUSTLOCK(backbuffer)) {
SDL_UnlockSurface(backbuffer);
}
if(SDL_MUSTLOCK(screen)) {
SDL_UnlockSurface(screen);
}
}
/*********************** /***********************
*** Input functions *** *** Input functions ***
@@ -93,15 +110,8 @@ bJoypad::bJoypad() {
l = r = select = start = false; l = r = select = start = false;
} }
void bSNES::notify(uint32 message, uint32 param1, uint32 param2) { void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {}
switch(message) {
case RENDER_FRAME:
update_frame = true;
break;
}
}
bSNES::bSNES() { bSNES::bSNES() {
run_status = STOP; run_status = STOP;
update_frame = false;
} }

View File

@@ -9,17 +9,19 @@ bool l, r, select, start;
class bSNES : public SNES { class bSNES : public SNES {
private: private:
uint32 run_status; uint32 run_status;
bool update_frame;
bJoypad joypad1, joypad2; bJoypad joypad1, joypad2;
public: public:
enum { STOP = 0, RUN }; enum { STOP = 0, RUN };
void run(); void run();
void video_run(); void video_run();
void sound_run(); void sound_run(uint32 data);
void set_status(uint32 new_status); uint16 *video_lock(uint32 &data);
uint32 get_status(); void video_unlock();
void set_status(uint32 new_status);
uint32 get_status();
//input functions //input functions
void poll_input(uint8 type); void poll_input(uint8 type);

View File

@@ -1 +1,3 @@
@nmake /NOLOGO /f Makefile.win32 clean @nmake /NOLOGO /f Makefile.win32 clean
@del output.wav
@del bsnes_sdl.exe

View File

@@ -1,59 +1,11 @@
void render16() { void render() {
uint16 *dest, *src;
uint32 pitch;
int x, y;
SNES::video_info vi; SNES::video_info vi;
snes->get_video_info(&vi); snes->get_video_info(&vi);
pitch = (backbuffer->pitch >> 1);
dest = (uint16*)backbuffer->pixels;
src = (uint16*)vi.data;
if(vi.width == 256 && vi.height == 224) {
for(y=0;y<224;y++) {
memcpy(dest, src, 512);
dest += pitch;
src += 256;
}
} else if(vi.width == 512 && vi.height == 224) {
for(y=0;y<224;y++) {
memcpy(dest, src, 1024);
dest += pitch;
src += 512;
}
} else if(vi.width == 256 && vi.height == 448) {
for(y=0;y<448;y++) {
memcpy(dest, src, 512);
dest += pitch;
src += 256;
}
} else if(vi.width == 512 && vi.height == 448) {
for(y=0;y<448;y++) {
memcpy(dest, src, 1024);
dest += pitch;
src += 512;
}
}
screen_info.rs.x = 0; screen_info.rs.x = 0;
screen_info.rs.y = (vi.height == 224) ? 1 : 2; screen_info.rs.y = (vi.height == 224) ? 1 : 2;
screen_info.rs.w = vi.width; screen_info.rs.w = vi.width;
screen_info.rs.h = (vi.height == 224) ? 223 : 446; screen_info.rs.h = (vi.height == 224) ? 223 : 446;
}
void render32() {}
void render() {
if(SDL_MUSTLOCK(screen)) {
SDL_LockSurface(screen);
}
if(SDL_MUSTLOCK(backbuffer)) {
SDL_LockSurface(backbuffer);
}
render16();
//documentation says not to use this, but it's rather ridiculous that a graphics //documentation says not to use this, but it's rather ridiculous that a graphics
//library wouldn't support simple image scaling... so let's use it anyway and see //library wouldn't support simple image scaling... so let's use it anyway and see
@@ -61,12 +13,5 @@ void render() {
SDL_SoftStretch(backbuffer, &screen_info.rs, screen, &screen_info.rd); SDL_SoftStretch(backbuffer, &screen_info.rs, screen, &screen_info.rd);
//SDL_BlitSurface(backbuffer, &screen_info.rs, screen, &screen_info.rd); //SDL_BlitSurface(backbuffer, &screen_info.rs, screen, &screen_info.rd);
if(SDL_MUSTLOCK(backbuffer)) {
SDL_UnlockSurface(backbuffer);
}
if(SDL_MUSTLOCK(screen)) {
SDL_UnlockSurface(screen);
}
SDL_UpdateRect(screen, screen_info.rd.x, screen_info.rd.y, screen_info.rd.w, screen_info.rd.h); SDL_UpdateRect(screen, screen_info.rd.x, screen_info.rd.y, screen_info.rd.w, screen_info.rd.h);
} }

View File

@@ -27,14 +27,14 @@ FileReader *rf = new FileReader();
alert("Error loading image file [%s]!", rom_fn); alert("Error loading image file [%s]!", rom_fn);
return false; return false;
} }
mem_bus->load_cart(static_cast<Reader*>(rf)); r_mem->load_cart(static_cast<Reader*>(rf));
rf->close(); rf->close();
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); r_mem->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
rf->open(sram_fn); rf->open(sram_fn);
mem_bus->load_sram(static_cast<Reader*>(rf)); r_mem->load_sram(static_cast<Reader*>(rf));
rf->close(); rf->close();
} }
@@ -49,25 +49,25 @@ void ROMImage::unload() {
FileWriter *wf; FileWriter *wf;
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); r_mem->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
wf = new FileWriter(); wf = new FileWriter();
wf->open(sram_fn); wf->open(sram_fn);
mem_bus->save_sram(static_cast<Writer*>(wf)); r_mem->save_sram(static_cast<Writer*>(wf));
wf->close(); wf->close();
delete(wf); delete(wf);
} }
file_loaded = false; file_loaded = false;
mem_bus->unload_cart(); r_mem->unload_cart();
} }
void ROMImage::select(char *fn) { void ROMImage::select(char *fn) {
int i; int i;
if(file_loaded == true)return; if(file_loaded == true)return;
/* Remove quotes */ //remove quotes
if(fn[0] == '\"') { if(fn[0] == '\"') {
strcpy(rom_fn, fn + 1); strcpy(rom_fn, fn + 1);
rom_fn[strlen(rom_fn) - 1] = 0; rom_fn[strlen(rom_fn) - 1] = 0;

View File

@@ -44,13 +44,15 @@ va_list args;
} }
void init_snes() { void init_snes() {
mem_bus = new bMemBus(); #ifdef POLYMORPHISM
cpu = new bCPU(); deref(mem) = new bMemBus();
apu = new bAPU(); deref(cpu) = new bCPU();
dsp = new bDSP(); deref(apu) = new bAPU();
ppu = new bPPU(); deref(dsp) = new bDSP();
snes = new bSNES(); deref(ppu) = new bPPU();
bsnes = static_cast<bSNES*>(snes); #endif
snes = new bSNES();
bsnes = static_cast<bSNES*>(snes);
snes->init(); snes->init();
@@ -59,18 +61,18 @@ void init_snes() {
//play audio in real-time while sound output //play audio in real-time while sound output
//isn't available. //isn't available.
snes->log_audio_enable("output.wav"); snes->log_audio_enable("output.wav");
snes->set_playback_buffer_size(2000);
} }
void term_snes() { void term_snes() {
snes->term(); snes->term();
#ifdef POLYMORPHISM
if(mem_bus) { delete(static_cast<bMemBus*>(mem_bus)); mem_bus = 0; } if(deref(mem)) { delete static_cast<bMemBus*>(deref(mem)); deref(mem) = 0; }
if(cpu) { delete(static_cast<bCPU*> (cpu)); cpu = 0; } if(deref(cpu)) { delete static_cast<bCPU*> (deref(cpu)); deref(cpu) = 0; }
if(apu) { delete(static_cast<bAPU*> (apu)); apu = 0; } if(deref(apu)) { delete static_cast<bAPU*> (deref(apu)); deref(apu) = 0; }
if(ppu) { delete(static_cast<bPPU*> (ppu)); ppu = 0; } if(deref(dsp)) { delete static_cast<bDSP*> (deref(dsp)); deref(dsp) = 0; }
if(snes) { delete(static_cast<bSNES*> (snes)); snes = 0; } if(deref(ppu)) { delete static_cast<bPPU*> (deref(ppu)); deref(ppu) = 0; }
#endif
if(snes) { delete(static_cast<bSNES*>(snes)); snes = 0; }
} }
void center_window() { void center_window() {
@@ -133,7 +135,7 @@ SDL_Event event;
atexit(SDL_Quit); atexit(SDL_Quit);
set_window_info(); set_window_info();
screen = SDL_SetVideoMode(config::video.display_width, config::video.display_height, 16, screen = SDL_SetVideoMode(config::video.display_width, config::video.display_height, 16,
SDL_SWSURFACE | ((config::video.fullscreen)?SDL_FULLSCREEN:0)); SDL_SWSURFACE | ((config::video.fullscreen) ? SDL_FULLSCREEN : 0));
if(!screen) { alert("Failed to initialize SDL"); goto _end; } if(!screen) { alert("Failed to initialize SDL"); goto _end; }
backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000); backbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 512, 448, 16, 0xf800, 0x07e0, 0x001f, 0x0000);
if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; } if(!backbuffer) { alert("Failed to initialize SDL"); goto _end; }
@@ -160,7 +162,7 @@ int cursor_status;
snes->capture_screenshot(); snes->capture_screenshot();
break; break;
case SDLK_F10: //toggle cursor display case SDLK_F10: //toggle cursor display
cursor_status = (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE)?SDL_DISABLE:SDL_ENABLE; cursor_status = (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) ? SDL_DISABLE : SDL_ENABLE;
SDL_ShowCursor(cursor_status); SDL_ShowCursor(cursor_status);
break; break;
case SDLK_F11: //only supported on X11 case SDLK_F11: //only supported on X11

View File

@@ -5,13 +5,12 @@
#include "snes_input.cpp" #include "snes_input.cpp"
void SNES::run() { void SNES::run() {
uint32 cycles, r;
if(apusync.cycles < 0) { if(apusync.cycles < 0) {
cpu->run(); r_cpu->run();
apusync.cycles += apusync.apu_multbl[cpu->cycles_executed()]; apusync.cycles += apusync.apu_multbl[r_cpu->cycles_executed()];
} else { } else {
apu->run(); r_apu->run();
cycles = apu->cycles_executed(); uint32 cycles = r_apu->cycles_executed();
apusync.dsp += cycles; apusync.dsp += cycles;
apusync.cycles -= apusync.cpu_multbl[cycles]; apusync.cycles -= apusync.cpu_multbl[cycles];
@@ -19,11 +18,18 @@ uint32 cycles, r;
//24576000(Sound clock crystal) / 32000(DSP) = 768crystal/dsp ticks //24576000(Sound clock crystal) / 32000(DSP) = 768crystal/dsp ticks
while(apusync.dsp >= 768) { while(apusync.dsp >= 768) {
apusync.dsp -= 768; apusync.dsp -= 768;
audio_update(dsp->run()); audio_update(r_dsp->run());
} }
} }
} }
void SNES::runtoframe() {
while(r_ppu->status.frame_executed == false) {
SNES::run();
}
r_ppu->status.frame_executed = false;
}
void SNES::init() { void SNES::init() {
srtc = new SRTC(); srtc = new SRTC();
sdd1 = new SDD1(); sdd1 = new SDD1();
@@ -40,48 +46,44 @@ void SNES::term() {
} }
void SNES::power() { void SNES::power() {
cpu->power(); r_cpu->power();
apu->power(); r_apu->power();
dsp->power(); r_dsp->power();
ppu->power(); r_ppu->power();
mem_bus->power(); r_mem->power();
srtc->power(); srtc->power();
sdd1->power(); sdd1->power();
int i; int i;
mem_bus->flush_mmio_mappers(); r_mem->flush_mmio_mappers();
for(i=0x2100;i<=0x213f;i++)mem_bus->set_mmio_mapper(i, ppu->mmio); for(i=0x2100;i<=0x213f;i++)r_mem->set_mmio_mapper(i, r_ppu->mmio);
for(i=0x2140;i<=0x217f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x2140;i<=0x217f;i++)r_mem->set_mmio_mapper(i, r_cpu->mmio);
for(i=0x2180;i<=0x2183;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x2180;i<=0x2183;i++)r_mem->set_mmio_mapper(i, r_cpu->mmio);
//input //input
mem_bus->set_mmio_mapper(0x4016, cpu->mmio); r_mem->set_mmio_mapper(0x4016, r_cpu->mmio);
mem_bus->set_mmio_mapper(0x4017, cpu->mmio); r_mem->set_mmio_mapper(0x4017, r_cpu->mmio);
for(i=0x4200;i<=0x421f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x4200;i<=0x421f;i++)r_mem->set_mmio_mapper(i, r_cpu->mmio);
for(i=0x4300;i<=0x437f;i++)mem_bus->set_mmio_mapper(i, cpu->mmio); for(i=0x4300;i<=0x437f;i++)r_mem->set_mmio_mapper(i, r_cpu->mmio);
srtc->enable(); srtc->enable();
sdd1->enable(); sdd1->enable();
memset(video.data, 0, 512 * 448 * sizeof(uint32));
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
video_update(); video_update();
} }
void SNES::reset() { void SNES::reset() {
apusync.cycles = -apusync.cpu_multbl[32]; apusync.cycles = -apusync.cpu_multbl[32];
cpu->reset(); r_cpu->reset();
apu->reset(); r_apu->reset();
dsp->reset(); r_dsp->reset();
ppu->reset(); r_ppu->reset();
mem_bus->reset(); r_mem->reset();
srtc->reset(); srtc->reset();
sdd1->reset(); sdd1->reset();
memset(video.data, 0, 512 * 448 * sizeof(uint32));
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
video_update(); video_update();
} }
@@ -154,6 +156,4 @@ SNES::SNES() {
snes_region = NTSC; snes_region = NTSC;
update_timing(); update_timing();
dsp_buffer.data = 0;
} }

View File

@@ -19,7 +19,8 @@ public:
enum { NTSC = 0, PAL = 1 }; enum { NTSC = 0, PAL = 1 };
//system functions //system functions
virtual void run(); virtual inline void run();
virtual inline void runtoframe();
virtual void init(); virtual void init();
virtual void term(); virtual void term();
virtual void power(); virtual void power();
@@ -39,7 +40,6 @@ enum { NTSC = 0, PAL = 1 };
//debugging functions //debugging functions
enum { enum {
NO_ACTION = 0, NO_ACTION = 0,
RENDER_FRAME,
CPU_EXEC_OPCODE_BEGIN, CPU_EXEC_OPCODE_END, CPU_EXEC_OPCODE_BEGIN, CPU_EXEC_OPCODE_END,
APU_EXEC_OPCODE_BEGIN, APU_EXEC_OPCODE_END, APU_EXEC_OPCODE_BEGIN, APU_EXEC_OPCODE_END,
MEM_READ, MEM_WRITE, MEM_READ, MEM_WRITE,

View File

@@ -1,25 +1,3 @@
void SNES::set_playback_buffer_size(uint32 buffer_size) {
if(dsp_buffer.data) {
free(dsp_buffer.data);
dsp_buffer.data = 0;
}
//* 2 is for left/right channel data
dsp_buffer.data = (uint16*)malloc(buffer_size * sizeof(uint16) * 2);
memset(dsp_buffer.data, 0, buffer_size * sizeof(uint16) * 2);
dsp_buffer.size = buffer_size;
dsp_buffer.pos = 0;
}
uint32 SNES::get_playback_buffer_pos() {
return dsp_buffer.pos;
}
uint16 *SNES::get_playback_buffer() {
return dsp_buffer.data;
}
void SNES::audio_update(uint32 data) { void SNES::audio_update(uint32 data) {
if(pcmfp) { if(pcmfp) {
fputc(data, pcmfp); fputc(data, pcmfp);
@@ -30,11 +8,7 @@ void SNES::audio_update(uint32 data) {
if((bool)config::snes.mute == true)data = 0x0000; if((bool)config::snes.mute == true)data = 0x0000;
dsp_buffer.data[dsp_buffer.pos++] = (data) & 0xffff; sound_run(data);
dsp_buffer.data[dsp_buffer.pos++] = (data >> 16) & 0xffff;
dsp_buffer.pos %= dsp_buffer.size;
sound_run();
} }
void SNES::log_audio_enable(const char *fn) { void SNES::log_audio_enable(const char *fn) {

View File

@@ -1,15 +1,5 @@
struct {
uint16 *data;
uint32 size, pos;
} dsp_buffer;
FILE *pcmfp; FILE *pcmfp;
//buffer_size is in samples
void set_playback_buffer_size(uint32 buffer_size);
uint32 get_playback_buffer_pos();
uint16 *get_playback_buffer();
//if a filename is not specified, one will be generated //if a filename is not specified, one will be generated
//automatically ("audio%0.3d.wav") //automatically ("audio%0.3d.wav")
void log_audio_enable(const char *fn = 0); void log_audio_enable(const char *fn = 0);
@@ -19,4 +9,4 @@ FILE *pcmfp;
void audio_init(); void audio_init();
void audio_term(); void audio_term();
virtual void sound_run() = 0; virtual void sound_run(uint32 data) = 0;

View File

@@ -8,7 +8,7 @@ const uint8 SNES::color_curve_table[32] = {
}; };
void SNES::update_color_lookup_table() { void SNES::update_color_lookup_table() {
int i, l, r, g, b; int32 i, l, r, g, b;
double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance
uint32 col; uint32 col;
@@ -29,7 +29,7 @@ uint32 col;
} }
if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) { if((int)config::snes.video_color_adjust_mode == VCA_GRAYSCALE) {
l = int((double)r * lr) + ((double)g * lg) + ((double)b * lb); l = int32(((double)r * lr) + ((double)g * lg) + ((double)b * lb));
if(l < 0)l = 0; if(l < 0)l = 0;
if(l > 255)l = 255; if(l > 255)l = 255;
r = g = b = l; r = g = b = l;
@@ -92,7 +92,6 @@ void SNES::update_video_format() {
} }
void SNES::get_video_info(video_info *info) { void SNES::get_video_info(video_info *info) {
info->data = video.data;
info->mode = video.mode; info->mode = video.mode;
switch(video.mode) { switch(video.mode) {
@@ -129,10 +128,10 @@ void SNES::get_video_info(video_info *info) {
} }
} }
void SNES::video_update_256x224(uint16 *src) { void SNES::video_update_256x224() {
int x, y; int x, y;
uint16 *dest; uint16 *src = video.ppu_data;
dest = video.data; uint16 *dest = video.data;
for(y=0;y<224;y++) { for(y=0;y<224;y++) {
if(video_frame[y].hires == false) { if(video_frame[y].hires == false) {
@@ -147,13 +146,14 @@ uint16 *dest;
} }
src += 512; src += 512;
} }
dest += video.pitch - 256;
} }
} }
void SNES::video_update_512x224(uint16 *src) { void SNES::video_update_512x224() {
int x, y; int x, y;
uint16 *dest; uint16 *src = video.ppu_data;
dest = video.data; uint16 *dest = video.data;
for(y=0;y<224;y++) { for(y=0;y<224;y++) {
if(video_frame[y].hires == false) { if(video_frame[y].hires == false) {
@@ -168,31 +168,41 @@ uint16 *dest;
} }
src += 512; src += 512;
} }
dest += video.pitch - 512;
} }
} }
void SNES::video_update_256x448(uint16 *src) { void SNES::video_update_256x448() {
int x, y; int x, y;
uint16 *dest; uint16 *src = video.ppu_data;
bool field = !cpu->interlace_field(); uint16 *dest = video.data;
dest = video.data; bool field = !r_cpu->interlace_field();
for(y=0;y<224;y++) { for(y=0;y<224;y++) {
if(video_frame[y].interlace == false) { if(video_frame[y].interlace == false) {
if(video_frame[y].hires == false) { if(video_frame[y].hires == false) {
for(x=0;x<512;x++) { for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + (uint8)x)]; *dest++ = color_lookup_table[*(src + x)];
} }
src += 1024; dest += video.pitch - 256;
for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + x)];
}
dest += video.pitch - 256;
} else { } else {
for(x=0;x<512;x++) { for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + ((x & 255) << 1))]; *dest++ = color_lookup_table[*(src + (x << 1))];
} }
src += 1024; dest += video.pitch - 256;
for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + (x << 1))];
}
dest += video.pitch - 256;
} }
src += 1024;
} else { } else {
if(field) { if(field) {
dest += 256; dest += video.pitch;
src += 512; src += 512;
} }
@@ -207,38 +217,49 @@ bool field = !cpu->interlace_field();
src += 2; src += 2;
} }
} }
dest += video.pitch - 256;
if(!field) { if(!field) {
dest += 256; dest += video.pitch;
src += 512; src += 512;
} }
} }
} }
} }
void SNES::video_update_512x448(uint16 *src) { void SNES::video_update_512x448() {
int x, y; int x, y;
uint16 *dest; uint16 *src = video.ppu_data;
bool field = !cpu->interlace_field(); uint16 *dest = video.data;
dest = video.data; bool field = !r_cpu->interlace_field();
for(y=0;y<224;y++) { for(y=0;y<224;y++) {
if(video_frame[y].interlace == false) { if(video_frame[y].interlace == false) {
if(video_frame[y].hires == false) { if(video_frame[y].hires == false) {
for(x=0;x<512;x++) { for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + (uint8)x)]; *dest++ = color_lookup_table[*(src + x)];
*dest++ = color_lookup_table[*(src + (uint8)x)]; *dest++ = color_lookup_table[*(src + x)];
} }
src += 1024; dest += video.pitch - 512;
for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + x)];
*dest++ = color_lookup_table[*(src + x)];
}
dest += video.pitch - 512;
} else { } else {
for(x=0;x<1024;x++) { for(x=0;x<512;x++) {
*dest++ = color_lookup_table[*(src + (x & 511))]; *dest++ = color_lookup_table[*(src + x)];
} }
src += 1024; dest += video.pitch - 512;
for(x=0;x<512;x++) {
*dest++ = color_lookup_table[*(src + x)];
}
dest += video.pitch - 512;
} }
src += 1024;
} else { } else {
if(field) { if(field) {
dest += 512; dest += video.pitch;
src += 512; src += 512;
} }
@@ -253,9 +274,10 @@ bool field = !cpu->interlace_field();
*dest++ = color_lookup_table[*src++]; *dest++ = color_lookup_table[*src++];
} }
} }
dest += video.pitch - 512;
if(!field) { if(!field) {
dest += 512; dest += video.pitch;
src += 512; src += 512;
} }
} }
@@ -263,25 +285,30 @@ bool field = !cpu->interlace_field();
} }
void SNES::video_update() { void SNES::video_update() {
if(ppu->renderer_enabled()) { if(r_ppu->renderer_enabled()) {
if(video.format_changed == true) { if(video.format_changed == true) {
update_video_format(); update_video_format();
} }
uint16 *src = (uint16*)video.ppu_data + ((int(cpu->overscan()) << 3) * 1024); video.data = (uint16*)video_lock(video.pitch);
switch(video.mode) { video.ppu_data = (uint16*)r_ppu->output + (int(r_cpu->overscan()) << 13);
case VM_256x224:video_update_256x224(src);break; video.pitch >>= 1;
case VM_512x224:video_update_512x224(src);break; if(video.data) {
case VM_256x448:video_update_256x448(src);break; switch(video.mode) {
case VM_512x448:video_update_512x448(src);break; case VM_256x224:video_update_256x224();break;
case VM_VARIABLE: case VM_512x224:video_update_512x224();break;
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) { case VM_256x448:video_update_256x448();break;
case 0:video_update_256x224(src);break; case VM_512x448:video_update_512x448();break;
case 1:video_update_512x224(src);break; case VM_VARIABLE:
case 2:video_update_256x448(src);break; switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
case 3:video_update_512x448(src);break; case 0:video_update_256x224();break;
case 1:video_update_512x224();break;
case 2:video_update_256x448();break;
case 3:video_update_512x448();break;
}
break;
} }
break; video_unlock();
} }
//SNES::capture_screenshot() was called by emulation interface //SNES::capture_screenshot() was called by emulation interface
@@ -298,13 +325,13 @@ void SNES::video_update() {
} }
void SNES::video_scanline() { void SNES::video_scanline() {
int y = cpu->vcounter(); int y = r_cpu->vcounter();
int o = int(cpu->overscan()) << 3; int o = int(r_cpu->overscan()) << 3;
if(y <= (0 + o) || y >= (224 + o))return; if(y <= (0 + o) || y >= (224 + o))return;
y -= o; y -= o;
PPU::scanline_info si; PPU::scanline_info si;
ppu->get_scanline_info(&si); r_ppu->get_scanline_info(&si);
video_frame[y].hires = si.hires; video_frame[y].hires = si.hires;
video_frame[y].interlace = si.interlace; video_frame[y].interlace = si.interlace;
@@ -313,21 +340,10 @@ PPU::scanline_info si;
video.frame_interlace |= si.interlace; video.frame_interlace |= si.interlace;
} }
uint16 *SNES::get_ppu_output_handle() {
return (uint16*)(video.ppu_data +
(cpu->vcounter() * 1024) +
((cpu->interlace() && cpu->interlace_field())?512:0));
}
void SNES::video_init() { void SNES::video_init() {
int i, c; int i, c;
video.format_changed = false; video.format_changed = false;
video.data = (uint16*)malloc(512 * 448 * sizeof(uint32));
video.ppu_data = (uint16*)malloc(512 * 480 * sizeof(uint16));
memset(video.data, 0, 512 * 448 * sizeof(uint32));
memset(video.ppu_data, 0, 512 * 480 * sizeof(uint16));
for(i=0;i<224;i++) { for(i=0;i<224;i++) {
video_frame[i].hires = false; video_frame[i].hires = false;
video_frame[i].interlace = false; video_frame[i].interlace = false;

View File

@@ -29,6 +29,7 @@ struct {
uint16 *data, *ppu_data; uint16 *data, *ppu_data;
uint8 mode; uint8 mode;
uint8 depth; uint8 depth;
uint32 pitch;
bool frame_hires, frame_interlace; bool frame_hires, frame_interlace;
@@ -40,21 +41,20 @@ struct {
} video_frame[224]; } video_frame[224];
struct video_info { struct video_info {
uint16 *data; uint32 mode, width, height;
uint8 mode;
uint32 width, height;
}; };
//public functions //public functions
void capture_screenshot(); void capture_screenshot();
void update_color_lookup_table(); void update_color_lookup_table();
virtual void set_video_format(uint8 mode, uint8 depth); virtual void set_video_format(uint8 mode, uint8 depth);
virtual void get_video_info(video_info *info); virtual void get_video_info(video_info *info);
virtual void video_run() = 0; virtual void video_run() = 0;
virtual uint16 *video_lock(uint32 &pitch) = 0;
virtual void video_unlock() = 0;
//private functions //private functions
uint16 *get_ppu_output_handle(); //used by PPU only
private: private:
//when a screenshot is requested, wait until the frame //when a screenshot is requested, wait until the frame
//has finished rendering, so we can tell the image size //has finished rendering, so we can tell the image size
@@ -62,10 +62,10 @@ bool flag_output_screenshot;
uint16 to_rgb555(uint32 color); uint16 to_rgb555(uint32 color);
void output_screenshot(); void output_screenshot();
void update_video_format(); void update_video_format();
void video_update_256x224(uint16 *src); void video_update_256x224();
void video_update_512x224(uint16 *src); void video_update_512x224();
void video_update_256x448(uint16 *src); void video_update_256x448();
void video_update_512x448(uint16 *src); void video_update_512x448();
void video_update(); void video_update();
void video_scanline(); void video_scanline();
void video_init(); void video_init();

View File

@@ -5,25 +5,13 @@ void SNES::capture_screenshot() {
//used to convert pixel data to write to rgb555 format //used to convert pixel data to write to rgb555 format
//bitmap image via SNES::output_screenshot() function //bitmap image via SNES::output_screenshot() function
uint16 SNES::to_rgb555(uint32 color) { uint16 SNES::to_rgb555(uint32 color) {
if(video.depth == 15) { //bgr555->rgb555
//rgb555 return ((color & 0x7c00) >> 10) | (color & 0x03e0) | ((color & 0x001f) << 10);
return color & 0x7fff;
}
if(video.depth == 16) {
//rgb565->rgb555
return ((color >> 1) & 0x7fe0) | (color & 0x001f);
}
if(video.depth == 24 || video.depth == 32) {
//rgb888->rgb555
return ((color >> 9) & 0x7c00) | ((color >> 6) & 0x03e0) | ((color >> 3) & 0x001f);
}
//unsupported color depth
return color;
} }
//this routine isn't perfect... it will fail if the video frame
//mixes resolutions (e.g. the top half is 256x224, and the bottom
//half is 512x224, etc.)
void SNES::output_screenshot() { void SNES::output_screenshot() {
FILE *fp; FILE *fp;
char fn[256]; char fn[256];
@@ -95,7 +83,7 @@ int x, y;
uint16 c; uint16 c;
for(y=height;y>=1;y--) { for(y=height;y>=1;y--) {
for(x=0;x<width;x++) { for(x=0;x<width;x++) {
c = to_rgb555(video.data[y * width + x]); c = to_rgb555(video.ppu_data[y * 1024 + x]);
fputc(c, fp); fputc(c, fp);
fputc(c >> 8, fp); fputc(c >> 8, fp);
} }

View File

@@ -1,11 +1,11 @@
CC = cl CC = cl
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs /DARCH_LSB CFLAGS = /nologo /O2 /wd4996
OBJS = winmain.obj \ OBJS = winmain.obj \
libstring.obj libconfig.obj \ libstring.obj libconfig.obj \
reader.obj \ reader.obj \
memory.obj bmemory.obj \ memory.obj bmemory.obj \
cpu.obj bcpu.obj \ cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \ apu.obj bapu.obj \
bdsp.obj \ bdsp.obj \
ppu.obj bppu.obj \ ppu.obj bppu.obj \
snes.obj \ snes.obj \
@@ -15,9 +15,12 @@ LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dsound.lib dxgui
all: $(OBJS) all: $(OBJS)
rc /r /fobsnes.res bsnes.rc rc /r /fobsnes.res bsnes.rc
$(CC) /Febsnes.exe $(CFLAGS) $(OBJS) bsnes.res $(LIBS) $(CC) /Febsnes.exe $(CFLAGS) $(OBJS) bsnes.res $(LIBS)
#/link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
clean: clean:
del *.obj del *.obj
del *.pgd
del *.pgc
###################### ######################
### win32-specific ### ### win32-specific ###
@@ -60,9 +63,6 @@ apu.obj: ../apu/*
bapu.obj: ../apu/bapu/* bapu.obj: ../apu/bapu/*
$(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp $(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp
bapuskip.obj: ../apu/bapuskip/*
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
########### ###########
### dsp ### ### dsp ###
########### ###########

View File

@@ -1,3 +1,12 @@
void bSNES::power() {
ds_sound->init();
SNES::power();
}
void bSNES::reset() {
SNES::reset();
}
void bSNES::set_status(uint32 new_status) { void bSNES::set_status(uint32 new_status) {
uint8 cpu_op; uint8 cpu_op;
run_status = new_status; run_status = new_status;
@@ -12,7 +21,7 @@ uint8 cpu_op;
status.cpu_ran = false; status.cpu_ran = false;
break; break;
case RUNTOCPUPROCEED: case RUNTOCPUPROCEED:
cpu_op = mem_bus->read(cpu->regs.pc.d); cpu_op = r_mem->read(r_cpu->regs.pc.d);
if(cpu_op == 0x10 || //bpl rel if(cpu_op == 0x10 || //bpl rel
cpu_op == 0x30 || //bmi rel cpu_op == 0x30 || //bmi rel
@@ -27,7 +36,7 @@ uint8 cpu_op;
cpu_op == 0xfc //jsr (addr,x) cpu_op == 0xfc //jsr (addr,x)
) { ) {
w_console->is_running(true); w_console->is_running(true);
status.cpu_stop_pos = (cpu->regs.pc.b << 16) | ((cpu->regs.pc.d + cpu->opcode_length()) & 0xffff); status.cpu_stop_pos = (r_cpu->regs.pc.b << 16) | ((r_cpu->regs.pc.d + r_cpu->opcode_length()) & 0xffff);
} else { } else {
status.cpu_ran = false; status.cpu_ran = false;
run_status = RUNTOCPUSTEP; run_status = RUNTOCPUSTEP;
@@ -48,10 +57,7 @@ void bSNES::run() {
switch(run_status) { switch(run_status) {
case RUN: case RUN:
while(update_frame == false) { SNES::runtoframe();
SNES::run();
}
update_frame = false;
return; return;
case STOP: case STOP:
break; break;
@@ -68,8 +74,8 @@ void bSNES::run() {
break; break;
case RUNTOFRAME: case RUNTOFRAME:
SNES::run(); SNES::run();
if(update_frame == true) { if(r_ppu->status.frame_executed == true) {
update_frame = false; r_ppu->status.frame_executed = false;
set_status(STOP); set_status(STOP);
disassemble_apu_op(); disassemble_apu_op();
disassemble_cpu_op(); disassemble_cpu_op();
@@ -89,7 +95,7 @@ void bSNES::run() {
break; break;
case RUNTOCPUPROCEED: case RUNTOCPUPROCEED:
SNES::run(); SNES::run();
if(cpu->in_opcode() == false && status.cpu_stop_pos == cpu->regs.pc.d) { if(r_cpu->in_opcode() == false && status.cpu_stop_pos == r_cpu->regs.pc.d) {
set_status(STOP); set_status(STOP);
disassemble_cpu_op(); disassemble_cpu_op();
} else if(w_bp->hit() == true) { } else if(w_bp->hit() == true) {
@@ -114,13 +120,13 @@ void bSNES::run() {
} }
void bSNES::video_run() { void bSNES::video_run() {
if(ppu->status.frames_updated) { if(r_ppu->status.frames_updated) {
char s[512], t[512]; char s[512], t[512];
ppu->status.frames_updated = false; r_ppu->status.frames_updated = false;
if((bool)config::gui.show_fps == true) { if((bool)config::gui.show_fps == true) {
sprintf(s, "%s : %d fps", BSNES_TITLE, ppu->status.frames_executed); sprintf(s, "%s : %d fps", BSNES_TITLE, r_ppu->status.frames_executed);
if(w_main->frameskip != 0) { if(w_main->frameskip != 0) {
sprintf(t, " (%d frames)", ppu->status.frames_rendered); sprintf(t, " (%d frames)", r_ppu->status.frames_rendered);
strcat(s, t); strcat(s, t);
} }
SetWindowText(w_main->hwnd, s); SetWindowText(w_main->hwnd, s);
@@ -129,17 +135,43 @@ void bSNES::video_run() {
w_main->frameskip_pos++; w_main->frameskip_pos++;
w_main->frameskip_pos %= (w_main->frameskip + 1); w_main->frameskip_pos %= (w_main->frameskip + 1);
if(ppu->renderer_enabled())dd_renderer->update(); if(r_ppu->renderer_enabled())dd_renderer->update();
ppu->enable_renderer(w_main->frameskip_pos == 0); r_ppu->enable_renderer(w_main->frameskip_pos == 0);
} }
void bSNES::sound_run() { void bSNES::sound_run(uint32 data) {
ds_sound->run(); ds_sound->run(data);
}
/***********************
*** Video functions ***
***********************/
uint16 *bSNES::video_lock(uint32 &pitch) {
return dd_renderer->lock(pitch);
}
void bSNES::video_unlock() {
dd_renderer->unlock();
} }
/*********************** /***********************
*** Input functions *** *** Input functions ***
***********************/ ***********************/
void bSNES::clear_input() {
joypad1.up = joypad2.up =
joypad1.down = joypad2.down =
joypad1.left = joypad2.left =
joypad1.right = joypad2.right =
joypad1.a = joypad2.a =
joypad1.b = joypad2.b =
joypad1.x = joypad2.x =
joypad1.y = joypad2.y =
joypad1.l = joypad2.l =
joypad1.r = joypad2.r =
joypad1.select = joypad2.select =
joypad1.start = joypad2.start = 0;
}
void bSNES::poll_input(uint8 type) { void bSNES::poll_input(uint8 type) {
//only capture input when main window has focus //only capture input when main window has focus
if(GetForegroundWindow() == w_main->hwnd) { if(GetForegroundWindow() == w_main->hwnd) {
@@ -279,27 +311,27 @@ uint8 r = 0x00;
if(a >= 0x2000 && a <= 0x5fff) { if(a >= 0x2000 && a <= 0x5fff) {
r = 0x00; r = 0x00;
} else { } else {
r = mem_bus->read(addr); r = r_mem->read(addr);
} }
} else { } else {
r = mem_bus->read(addr); r = r_mem->read(addr);
} }
break; break;
case SPCRAM: case SPCRAM:
addr &= 0xffff; addr &= 0xffff;
r = apu->spcram_read(addr); r = r_apu->spcram_read(addr);
break; break;
case VRAM: case VRAM:
addr &= 0xffff; addr &= 0xffff;
r = ppu->vram_read(addr); r = r_ppu->vram_read(addr);
break; break;
case OAM: case OAM:
addr &= 0x03ff; addr &= 0x03ff;
r = ppu->oam_read(addr); r = r_ppu->oam_read(addr);
break; break;
case CGRAM: case CGRAM:
addr &= 0x01ff; addr &= 0x01ff;
r = ppu->cgram_read(addr); r = r_ppu->cgram_read(addr);
break; break;
} }
debug_command = false; debug_command = false;
@@ -311,38 +343,31 @@ void bSNES::write(uint8 type, uint32 addr, uint8 value) {
switch(type) { switch(type) {
case DRAM: case DRAM:
addr &= 0xffffff; addr &= 0xffffff;
mem_bus->cart->write_protect(false); r_mem->cart->write_protect(false);
mem_bus->write(addr, value); r_mem->write(addr, value);
mem_bus->cart->write_protect(true); r_mem->cart->write_protect(true);
break; break;
case SPCRAM: case SPCRAM:
addr &= 0xffff; addr &= 0xffff;
apu->spcram_write(addr, value); r_apu->spcram_write(addr, value);
break; break;
case VRAM: case VRAM:
addr &= 0xffff; addr &= 0xffff;
ppu->vram_write(addr, value); r_ppu->vram_write(addr, value);
break; break;
case OAM: case OAM:
addr &= 0x03ff; addr &= 0x03ff;
ppu->oam_write(addr, value); r_ppu->oam_write(addr, value);
break; break;
case CGRAM: case CGRAM:
addr &= 0x01ff; addr &= 0x01ff;
ppu->cgram_write(addr, value); r_ppu->cgram_write(addr, value);
break; break;
} }
debug_command = false; debug_command = false;
} }
void bSNES::notify(uint32 message, uint32 param1, uint32 param2) { void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
//system messages
switch(message) {
case RENDER_FRAME:
update_frame = true;
break;
}
//debugging messages //debugging messages
if(is_debugger_enabled == false)return; if(is_debugger_enabled == false)return;
@@ -353,14 +378,14 @@ void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
status.cpu_ran = true; status.cpu_ran = true;
status.cpu_trace_pos++; status.cpu_trace_pos++;
//test next opcode for breakpoint //test next opcode for breakpoint
w_bp->test(message, cpu->regs.pc.d, 0); w_bp->test(message, r_cpu->regs.pc.d, 0);
disassemble_cpu_op(); disassemble_cpu_op();
break; break;
case APU_EXEC_OPCODE_BEGIN: case APU_EXEC_OPCODE_BEGIN:
break; break;
case APU_EXEC_OPCODE_END: case APU_EXEC_OPCODE_END:
status.apu_ran = true; status.apu_ran = true;
w_bp->test(message, apu->regs.pc, 0); w_bp->test(message, r_apu->regs.pc, 0);
disassemble_apu_op(); disassemble_apu_op();
break; break;
case MEM_READ: case MEM_READ:
@@ -395,7 +420,7 @@ char t[512];
//don't disassemble opcodes that won't be printed to console/traced to log anyway //don't disassemble opcodes that won't be printed to console/traced to log anyway
if(!w_console->can_write(Console::CPU_MESSAGE) && !w_console->tracing_enabled)return; if(!w_console->can_write(Console::CPU_MESSAGE) && !w_console->tracing_enabled)return;
cpu->disassemble_opcode(t); r_cpu->disassemble_opcode(t);
w_console->write(t, Console::CPU_MESSAGE); w_console->write(t, Console::CPU_MESSAGE);
} }
@@ -405,7 +430,7 @@ char t[512];
if(!w_console->can_write(Console::APU_MESSAGE) && !w_console->tracing_enabled)return; if(!w_console->can_write(Console::APU_MESSAGE) && !w_console->tracing_enabled)return;
apu->disassemble_opcode(t); r_apu->disassemble_opcode(t);
w_console->write(t, Console::APU_MESSAGE); w_console->write(t, Console::APU_MESSAGE);
} }
@@ -540,7 +565,6 @@ uint32 i, style;
bSNES::bSNES() { bSNES::bSNES() {
run_status = STOP; run_status = STOP;
debug_command = false; debug_command = false;
update_frame = false;
debugger_disable(); debugger_disable();
} }

View File

@@ -18,8 +18,6 @@ bool is_debugger_activated;
bool debug_command; bool debug_command;
uint32 run_status; uint32 run_status;
bool update_frame;
bJoypad joypad1, joypad2; bJoypad joypad1, joypad2;
public: public:
@@ -35,14 +33,22 @@ enum {
RUNTOAPUSTEP RUNTOAPUSTEP
}; };
enum { DRAM = 0, SPCRAM = 1, VRAM = 2, OAM = 3, CGRAM = 4 }; enum { DRAM = 0, SPCRAM = 1, VRAM = 2, OAM = 3, CGRAM = 4 };
void power();
void reset();
void run(); void run();
void video_run(); void video_run();
void sound_run(); void sound_run(uint32 data);
void set_status(uint32 new_status); void set_status(uint32 new_status);
uint32 get_status(); uint32 get_status();
//video functions
uint16 *video_lock(uint32 &pitch);
void video_unlock();
//input functions //input functions
void clear_input();
void poll_input(uint8 type); void poll_input(uint8 type);
bool get_input_status(uint8 device, uint8 button); bool get_input_status(uint8 device, uint8 button);

Binary file not shown.

View File

@@ -1,5 +1,10 @@
namespace config { namespace config {
struct System {
static Setting regulate_speed;
} system;
Setting System::regulate_speed(&config_file, "system.regulate_speed", "Regulate speed to 60hz (NTSC) / 50hz (PAL)", true, Setting::TRUE_FALSE);
struct Video { struct Video {
static Setting mode, use_vram, vblank; static Setting mode, use_vram, vblank;
} video; } video;

View File

@@ -176,66 +176,19 @@ int rx, ry;
} }
} }
#include "dd_renderer16.cpp" uint16 *DDRenderer::lock(uint32 &pitch) {
void DDRenderer::update16() { if(lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK)return 0;
HRESULT hr; pitch = ddsd.lPitch;
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0); return (uint16*)ddsd.lpSurface;
if(hr != DD_OK)return;
set_source_window();
if (vi.width == 256 && vi.height == 224) {
update16_256x224();
} else if(vi.width == 512 && vi.height == 224) {
update16_512x224();
} else if(vi.width == 256 && vi.height == 448) {
update16_256x448();
} else if(vi.width == 512 && vi.height == 448) {
update16_512x448();
}
lpddsb->Unlock(0);
} }
//#include "dd_renderer32.cpp" void DDRenderer::unlock() {
/*
void DDRenderer::update32() {
HRESULT hr;
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0);
if(hr != DD_OK)return;
set_source_window();
if(ppu->output->hires == false) {
if(ppu->output->interlace == false) {
update32_256x224();
} else {
update32_256x448();
}
} else {
if(ppu->output->interlace == false) {
update32_512x224();
} else {
update32_512x448();
}
}
lpddsb->Unlock(0); lpddsb->Unlock(0);
} }
*/
void DDRenderer::update() { void DDRenderer::update() {
snes->get_video_info(&vi); snes->get_video_info(&vi);
set_source_window();
switch(color_depth) {
case 15:
case 16:
update16();
break;
case 32:
//update32();
break;
}
redraw(); redraw();
} }

View File

@@ -14,22 +14,15 @@ bool fullscreen;
int width, height; //used for fullscreen mode clipping only int width, height; //used for fullscreen mode clipping only
uint8 color_depth; uint8 color_depth;
SNES::video_info vi; //initialized each frame at start of update() SNES::video_info vi; //initialized each frame at start of update()
uint16 *lock(uint32 &pitch);
void unlock();
void set_window(HWND hwnd_handle); void set_window(HWND hwnd_handle);
void create_backbuffer(); void create_backbuffer();
void to_windowed(); void to_windowed();
void to_fullscreen(int _width, int _height); void to_fullscreen(int _width, int _height);
void set_source_window(); void set_source_window();
void redraw(); void redraw();
inline void update16_256x224();
inline void update16_512x224();
inline void update16_256x448();
inline void update16_512x448();
void update16();
//inline void update32_256x224();
//inline void update32_512x224();
//inline void update32_256x448();
//inline void update32_512x448();
//void update32();
void update(); void update();
void destroy(); void destroy();

View File

@@ -1,79 +0,0 @@
inline void DDRenderer::update16_256x224() {
uint16 *src, *dest;
uint32 pitch;
int x, y;
dest = (uint16*)ddsd.lpSurface;
src = (uint16*)vi.data;
#ifdef USE_X86_ASM
pitch = (ddsd.lPitch) - 512;
__asm {
mov edi,dest
mov esi,src
mov edx,224
ly:
mov ecx,32
lx:
movsd
movsd
movsd
movsd
loopnz lx
add edi,pitch
dec edx
jnz ly
}
#else
pitch = (ddsd.lPitch >> 1);
for(y=0;y<224;y++) {
memcpy(dest, src, 512);
dest += pitch;
src += 256;
}
#endif
}
inline void DDRenderer::update16_512x224() {
uint16 *src, *dest;
uint32 pitch;
int x, y;
pitch = (ddsd.lPitch >> 1);
dest = (uint16*)ddsd.lpSurface;
src = (uint16*)vi.data;
for(y=0;y<224;y++) {
memcpy(dest, src, 1024);
dest += pitch;
src += 512;
}
}
inline void DDRenderer::update16_256x448() {
uint16 *src, *dest;
uint32 pitch;
int x, y;
pitch = (ddsd.lPitch >> 1);
dest = (uint16*)ddsd.lpSurface;
src = (uint16*)vi.data;
for(y=0;y<448;y++) {
memcpy(dest, src, 512);
dest += pitch;
src += 256;
}
}
inline void DDRenderer::update16_512x448() {
uint16 *src, *dest;
uint32 pitch;
int x, y;
pitch = (ddsd.lPitch >> 1);
dest = (uint16*)ddsd.lpSurface;
src = (uint16*)vi.data;
for(y=0;y<448;y++) {
memcpy(dest, src, 1024);
dest += pitch;
src += 512;
}
}

View File

@@ -1,123 +0,0 @@
inline void DDRenderer::update32_256x224() {
uint16 *src;
uint32 *dest;
uint32 pitch;
int x, y;
src = (uint16*)ppu->output->buffer + (1 << 10);
dest = (uint32*)ddsd.lpSurface;
pitch = (ddsd.lPitch >> 2) - 256;
int overscan_adjust = 0;
if(cpu->overscan() == true) {
src += 7 << 10;
overscan_adjust = 7;
}
for(y=1+overscan_adjust;y<224+overscan_adjust;y++) {
x = 256;
while(x--) {
*dest++ = color_lookup_table[*src];
src += 2;
}
dest += pitch;
src += 512;
}
}
inline void DDRenderer::update32_256x448() {
uint16 *src;
uint32 *dest;
uint32 pitch;
int x, y;
src = (uint16*)ppu->output->buffer + (1 << 10);
dest = (uint32*)ddsd.lpSurface;
pitch = (ddsd.lPitch >> 2) - 256;
int overscan_adjust = 0;
if(cpu->overscan() == true) {
src += 7 << 10;
overscan_adjust = 14;
}
for(y=2+overscan_adjust;y<448+overscan_adjust;y++) {
x = 256;
while(x--) {
*dest++ = color_lookup_table[*src];
src += 2;
}
dest += pitch;
if(ppu->output->line[y >> 1].interlace == false) {
src += (y & 1)?512:-512;
}
}
}
inline void DDRenderer::update32_512x224() {
uint16 *src;
uint32 *dest;
uint32 pitch;
int x, y;
src = (uint16*)ppu->output->buffer + (1 << 10);
dest = (uint32*)ddsd.lpSurface;
pitch = (ddsd.lPitch >> 2) - 512;
int overscan_adjust = 0;
if(cpu->overscan() == true) {
src += 7 << 10;
overscan_adjust = 7;
}
for(y=1+overscan_adjust;y<224+overscan_adjust;y++) {
if(ppu->output->line[y].hires == true) {
x = 512;
while(x--) {
*dest++ = color_lookup_table[*src++];
}
} else {
x = 256;
while(x--) {
*dest++ = color_lookup_table[*src];
*dest++ = color_lookup_table[*src];
src += 2;
}
}
dest += pitch;
src += 512;
}
}
inline void DDRenderer::update32_512x448() {
uint16 *src;
uint32 *dest;
uint32 pitch;
int x, y;
src = (uint16*)ppu->output->buffer + (1 << 10);
dest = (uint32*)ddsd.lpSurface;
pitch = (ddsd.lPitch >> 2) - 512;
int overscan_adjust = 0;
if(cpu->overscan() == true) {
src += 7 << 10;
overscan_adjust = 14;
}
for(y=2+overscan_adjust;y<448+overscan_adjust;y++) {
if(ppu->output->line[y >> 1].hires == true) {
x = 512;
while(x--) {
*dest++ = color_lookup_table[*src++];
}
} else {
x = 256;
while(x--) {
*dest++ = color_lookup_table[*src];
*dest++ = color_lookup_table[*src];
src += 2;
}
}
dest += pitch;
if(ppu->output->line[y >> 1].interlace == false) {
src += (y & 1)?512:-512;
}
}
}

View File

@@ -1,77 +1,116 @@
DSSound::DSSound() { void DSSound::run(uint32 sample) {
data.buffer = 0; data.buffer[data.buffer_pos++] = sample;
data.lpos = data.lsample = data.lbuffer = 0;
}
void DSSound::run() { if(data.buffer_pos >= data.samples_per_frame) {
if(snes->get_playback_buffer_pos() != 0)return; uint32 pos, size;
void *buffer;
if((bool)config::system.regulate_speed == true) {
do {
dsb_b->GetCurrentPosition(&pos, 0);
data.read_buffer = pos / data.buffer_size;
} while(data.read_buffer == data.prev_buffer);
}
uint32 pos, status; data.prev_buffer = data.read_buffer;
data.read_buffer++;
data.read_buffer &= 7;
//dsb_b[0]->SetFrequency(22050); pos = (data.read_buffer + 1) & 7;
//do { if(dsb_b->Lock(pos * data.buffer_size,
// dsb_b[0]->GetStatus(&status); data.buffer_size, &buffer, &size, 0, 0, 0) == DS_OK) {
//} while(status & DSBSTATUS_PLAYING); memcpy(buffer, data.buffer, data.buffer_size);
dsb_b->Unlock(buffer, size, 0, 0);
}
dsb_b[0]->Lock(0, DSP_BUFFER_SIZE * 4, &dslb, &dslbs, 0, 0, 0); data.buffer_pos = 0;
memcpy(dslb, snes->get_playback_buffer(), DSP_BUFFER_SIZE * 4);
dsb_b[0]->Unlock(dslb, dslbs, 0, 0);
dsb_b[0]->SetCurrentPosition(0);
//has the buffer stopped (possibly due to running too fast)?
dsb_b[0]->GetStatus(&status);
if(!(status & DSBSTATUS_PLAYING)) {
dsb_b[0]->Play(0, 0, 0);
} }
} }
void DSSound::clear() {
data.read_buffer = 0;
data.prev_buffer = 0;
data.buffer_pos = 0;
memset(data.buffer, 0, 2048 * 4);
if(!dsb_b)return;
dsb_b->Stop();
dsb_b->SetCurrentPosition(0);
uint32 size;
void *buffer;
dsb_b->Lock(0, data.buffer_size * 8, &buffer, &size, 0, 0, 0);
memset(buffer, 0, data.buffer_size * 8);
dsb_b->Unlock(buffer, size, 0, 0);
dsb_b->Play(0, 0, DSBPLAY_LOOPING);
}
void DSSound::init() { void DSSound::init() {
clear();
term();
data.read_buffer = 0;
data.prev_buffer = 0;
data.buffer_pos = 0;
data.samples_per_frame = DSP_FREQ / ((snes->region() == SNES::NTSC) ? 60 : 50);
data.buffer_size = data.samples_per_frame * 4;
DirectSoundCreate(0, &ds, 0); DirectSoundCreate(0, &ds, 0);
ds->SetCooperativeLevel(w_main->hwnd, DSSCL_PRIORITY); ds->SetCooperativeLevel(w_main->hwnd, DSSCL_PRIORITY);
memset(&dsbd, 0, sizeof(dsbd)); memset(&dsbd, 0, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd); dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0; dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = 0; dsbd.lpwfxFormat = 0;
ds->CreateSoundBuffer(&dsbd, &dsb_p, 0); ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);
memset(&wfx, 0, sizeof(wfx)); memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2; wfx.nChannels = 2;
wfx.nSamplesPerSec = 32000; wfx.nSamplesPerSec = DSP_FREQ;
wfx.wBitsPerSample = 16; wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels; wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
dsb_p->SetFormat(&wfx); dsb_p->SetFormat(&wfx);
sample_size = (16 / 8) * 2;
buffer_size = DSP_BUFFER_SIZE * sample_size;
buffer_pos = 0;
dsb_b = new LPDIRECTSOUNDBUFFER[1];
memset(&dsbd, 0, sizeof(dsbd)); memset(&dsbd, 0, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd); dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS; dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY |
dsbd.dwBufferBytes = buffer_size; DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = data.buffer_size * 8;
dsbd.guid3DAlgorithm = GUID_NULL; dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfx; dsbd.lpwfxFormat = &wfx;
ds->CreateSoundBuffer(&dsbd, &dsb_b[0], 0); ds->CreateSoundBuffer(&dsbd, &dsb_b, 0);
ds->CreateSoundBuffer(&dsbd, &dsb_b[1], 0); dsb_b->SetFrequency(DSP_FREQ);
dsb_b[0]->SetFrequency(32000); dsb_b->SetCurrentPosition(0);
dsb_b[1]->SetFrequency(32000);
dsb_b[0]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0); uint32 size;
memset(dslb, 0, buffer_size); void *buffer;
dsb_b[0]->Unlock(dslb, dslbs, 0, 0); dsb_b->Lock(0, data.buffer_size * 8, &buffer, &size, 0, 0, 0);
memset(buffer, 0, data.buffer_size * 8);
dsb_b->Unlock(buffer, size, 0, 0);
dsb_b[1]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0); data.read_buffer = 0;
memset(dslb, 0, buffer_size); dsb_b->Play(0, 0, DSBPLAY_LOOPING);
dsb_b[1]->Unlock(dslb, dslbs, 0, 0); }
dsb_b[0]->Play(0, 0, 0); void DSSound::term() {
if(dsb_b) {
buffer_pos = 0; dsb_b->Stop();
dsb_b->Release();
dsb_b = 0;
}
if(dsb_p) {
dsb_p->Release();
dsb_p = 0;
}
if(ds) {
ds->Release();
ds = 0;
}
} }

View File

@@ -1,30 +1,28 @@
#include <dsound.h> #include <dsound.h>
#define DSP_FREQ 32000
class DSSound { class DSSound {
public: public:
LPDIRECTSOUND ds; LPDIRECTSOUND ds;
LPDIRECTSOUNDBUFFER dsb_p, *dsb_b; LPDIRECTSOUNDBUFFER dsb_p, dsb_b;
DSBUFFERDESC dsbd; DSBUFFERDESC dsbd;
WAVEFORMATEX wfx; WAVEFORMATEX wfx;
uint32 sample_size;
uint32 buffer_size; uint32 buffer_size;
uint32 buffer_pos;
void *dslb;
uint32 dslbs;
public: public:
void run(); void run(uint32 sample);
void clear();
void init(); void init();
void term();
DSSound();
}; };
struct { struct {
uint32 *buffer; uint32 buffer[2048];
uint32 lpos; uint8 read_buffer, prev_buffer;
uint32 lsample; uint32 buffer_pos, buffer_size;
bool lbuffer;
uint32 samples_per_frame;
} data; } data;
DSSound *ds_sound; DSSound *ds_sound;

View File

@@ -27,14 +27,14 @@ FileReader *rf = new FileReader();
alert("Error loading image file [%s]!", rom_fn); alert("Error loading image file [%s]!", rom_fn);
return false; return false;
} }
mem_bus->load_cart(static_cast<Reader*>(rf)); r_mem->load_cart(static_cast<Reader*>(rf));
rf->close(); rf->close();
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); r_mem->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
rf->open(sram_fn); rf->open(sram_fn);
mem_bus->load_sram(static_cast<Reader*>(rf)); r_mem->load_sram(static_cast<Reader*>(rf));
rf->close(); rf->close();
} }
@@ -50,11 +50,11 @@ void ROMImage::unload() {
FileWriter *wf; FileWriter *wf;
CartInfo ci; CartInfo ci;
mem_bus->get_cartinfo(&ci); r_mem->get_cartinfo(&ci);
if(ci.sram_size != 0) { if(ci.sram_size != 0) {
wf = new FileWriter(); wf = new FileWriter();
wf->open(sram_fn); wf->open(sram_fn);
mem_bus->save_sram(static_cast<Writer*>(wf)); r_mem->save_sram(static_cast<Writer*>(wf));
wf->close(); wf->close();
delete(wf); delete(wf);
} }
@@ -62,7 +62,7 @@ CartInfo ci;
file_loaded = false; file_loaded = false;
bsnes->debugger_deactivate(); bsnes->debugger_deactivate();
mem_bus->unload_cart(); r_mem->unload_cart();
} }
void ROMImage::select(char *fn) { void ROMImage::select(char *fn) {

View File

@@ -54,7 +54,6 @@ void init_ui1() {
SetFocus(w_main->hwnd); SetFocus(w_main->hwnd);
dd_renderer->set_window(w_main->hwnd); dd_renderer->set_window(w_main->hwnd);
dd_renderer->to_windowed(); dd_renderer->to_windowed();
ds_sound->init();
w_main->show_menu(); w_main->show_menu();
w_main->set_video_mode(config::video.mode); w_main->set_video_mode(config::video.mode);

View File

@@ -14,6 +14,7 @@ enum {
MENU_FILE_RESET, MENU_FILE_RESET,
MENU_FILE_POWER, MENU_FILE_POWER,
MENU_FILE_EXIT, MENU_FILE_EXIT,
MENU_SETTINGS_REGULATE_SPEED,
MENU_SETTINGS_FRAMESKIP_OFF, MENU_SETTINGS_FRAMESKIP_OFF,
MENU_SETTINGS_FRAMESKIP_1, MENU_SETTINGS_FRAMESKIP_1,
MENU_SETTINGS_FRAMESKIP_2, MENU_SETTINGS_FRAMESKIP_2,
@@ -251,7 +252,7 @@ bool auto_update; //update memory window whenever visible value is written to
uint8 read_byte(uint32 addr); uint8 read_byte(uint32 addr);
void write_byte(uint32 addr, uint8 value); void write_byte(uint32 addr, uint8 value);
void refresh(uint32 type = null, uint32 addr = 0); void refresh(uint32 type = null, uint32 addr = 0);
void export(uint32 type); void export_data(uint32 type);
}*w_memory = 0; }*w_memory = 0;
class InputConfig : public Window { class InputConfig : public Window {

View File

@@ -29,7 +29,7 @@ HDC hdc;
break; break;
case CONSOLE_CPUPROCEED: case CONSOLE_CPUPROCEED:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
if(cpu->in_opcode() == true) { if(r_cpu->in_opcode() == true) {
dprintf("* CPU within opcode, proceed aborted"); dprintf("* CPU within opcode, proceed aborted");
} else { } else {
bsnes->set_status(bSNES::RUNTOCPUPROCEED); bsnes->set_status(bSNES::RUNTOCPUPROCEED);
@@ -38,10 +38,10 @@ HDC hdc;
break; break;
case CONSOLE_CPUSKIP: case CONSOLE_CPUSKIP:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
if(cpu->in_opcode() == true) { if(r_cpu->in_opcode() == true) {
dprintf("* CPU within opcode, skip aborted"); dprintf("* CPU within opcode, skip aborted");
} else { } else {
cpu->regs.pc.w += cpu->opcode_length(); r_cpu->regs.pc.w += r_cpu->opcode_length();
bsnes->disassemble_cpu_op(); bsnes->disassemble_cpu_op();
} }
} }
@@ -57,15 +57,15 @@ HDC hdc;
break; break;
case CONSOLE_CPUDISABLE: case CONSOLE_CPUDISABLE:
if(bsnes->get_status() == bSNES::STOP) { if(bsnes->get_status() == bSNES::STOP) {
if(cpu->in_opcode() == true) { if(r_cpu->in_opcode() == true) {
dprintf("* CPU within opcode, disable aborted"); dprintf("* CPU within opcode, disable aborted");
} else { } else {
addr = cpu->regs.pc.d; addr = r_cpu->regs.pc.d;
len = cpu->opcode_length(); len = r_cpu->opcode_length();
for(i=0;i<len;i++) { for(i=0;i<len;i++) {
bsnes->write(bSNES::DRAM, (addr & 0xff0000) | ((addr + i) & 0xffff), 0xea); bsnes->write(bSNES::DRAM, (addr & 0xff0000) | ((addr + i) & 0xffff), 0xea);
} }
//cpu->regs.pc.w += len; //r_cpu->regs.pc.w += len;
bsnes->disassemble_cpu_op(); bsnes->disassemble_cpu_op();
} }
} }
@@ -123,23 +123,23 @@ HDC hdc;
value = strhex(t); value = strhex(t);
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGTYPE, CB_GETCURSEL, 0, 0); pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGTYPE, CB_GETCURSEL, 0, 0);
if(pos == 0) { //Set CPU register if(pos == 0) { //Set CPU register
if(cpu->in_opcode() == true) { if(r_cpu->in_opcode() == true) {
dprintf("* CPU within opcode, register set aborted"); dprintf("* CPU within opcode, register set aborted");
} else { } else {
pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0); pos = SendDlgItemMessage(hwnd, CONSOLE_CFGREGNUM, CB_GETCURSEL, 0, 0);
switch(pos) { switch(pos) {
case 0:cpu->regs.a.w = value;break; case 0:r_cpu->regs.a.w = value;break;
case 1:cpu->regs.x.w = value;break; case 1:r_cpu->regs.x.w = value;break;
case 2:cpu->regs.y.w = value;break; case 2:r_cpu->regs.y.w = value;break;
case 3:cpu->regs.s.w = value;break; case 3:r_cpu->regs.s.w = value;break;
case 4:cpu->regs.d.w = value;break; case 4:r_cpu->regs.d.w = value;break;
case 5:cpu->regs.db = value;break; case 5:r_cpu->regs.db = value;break;
case 6:cpu->regs.p = value;break; case 6:r_cpu->regs.p = value;break;
case 7:cpu->regs.e = value;break; case 7:r_cpu->regs.e = value;break;
case 8:cpu->regs.pc.d = value;break; case 8:r_cpu->regs.pc.d = value;break;
} }
//these bits can never be clear in emulation mode //these bits can never be clear in emulation mode
if(cpu->regs.e)cpu->regs.p |= 0x30; if(r_cpu->regs.e)r_cpu->regs.p |= 0x30;
bsnes->disassemble_cpu_op(); bsnes->disassemble_cpu_op();
} }
} else { //Set APU register } else { //Set APU register
@@ -229,10 +229,12 @@ int sl = strlen(s);
memset(t + sl, 0x20, 80 - sl); memset(t + sl, 0x20, 80 - sl);
} }
t[80] = 0; t[80] = 0;
//only allow ascii characters. other characters will force the //only allow ascii characters. other characters will force the
//font to change to one that supports non-ascii characters, //font to change to one that supports non-ascii characters,
//which will break the line highlighting and alignment of text //which will break the line highlighting and alignment of text
for(int i=0;i<80;i++) { int i;
for(i=0;i<80;i++) {
if(t[i] & 0x80)t[i] = '?'; if(t[i] & 0x80)t[i] = '?';
} }
@@ -281,13 +283,13 @@ static uint8 linecol[4] = { 1, 2, 3 };
strcpy(s, ""); strcpy(s, "");
sprintf(t, "V:%3d H:%3d HC:%4d I:%d IF:%d O:%d", sprintf(t, "V:%3d H:%3d HC:%4d I:%d IF:%d O:%d",
cpu->vcounter(), cpu->hcounter(), cpu->hcycles(), r_cpu->vcounter(), r_cpu->hcounter(), r_cpu->hcycles(),
cpu->interlace(), cpu->interlace_field(), cpu->overscan()); r_cpu->interlace(), r_cpu->interlace_field(), r_cpu->overscan());
strcat(s, t); strcat(s, t);
if(1) { //config::apu.enabled if(1) { //config::apu.enabled
sprintf(t, " -- CPU[$%0.2x,$%0.2x,$%0.2x,$%0.2x]<>APU[$%0.2x,$%0.2x,$%0.2x,$%0.2x]", sprintf(t, " -- CPU[$%0.2x,$%0.2x,$%0.2x,$%0.2x]<>APU[$%0.2x,$%0.2x,$%0.2x,$%0.2x]",
cpu->port_read(0), cpu->port_read(1), cpu->port_read(2), cpu->port_read(3), r_cpu->port_read(0), r_cpu->port_read(1), r_cpu->port_read(2), r_cpu->port_read(3),
apu->port_read(0), apu->port_read(1), apu->port_read(2), apu->port_read(3) r_apu->port_read(0), r_apu->port_read(1), r_apu->port_read(2), r_apu->port_read(3)
); );
strcat(s, t); strcat(s, t);
} }

View File

@@ -135,6 +135,16 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
time_t timeout; time_t timeout;
int i; int i;
switch(msg) { switch(msg) {
case WM_ENTERMENULOOP:
ds_sound->clear();
break;
case WM_EXITMENULOOP:
timeout = time(0);
while(difftime(time(0), timeout) < 3) {
if(!KeyDown(VK_RETURN))break;
}
bsnes->clear_input();
break;
case WM_KEYDOWN: case WM_KEYDOWN:
if(wparam == VK_ESCAPE) { if(wparam == VK_ESCAPE) {
if(GetMenu(w_main->hwnd) == NULL) { if(GetMenu(w_main->hwnd) == NULL) {
@@ -146,13 +156,6 @@ int i;
} }
break; break;
case WM_COMMAND: case WM_COMMAND:
//below code fails because it is triggered after snes->poll_input()...
//unsure how to fix this...
// timeout = time(NULL);
// while(difftime(time(NULL), timeout) < 5) {
// if(!KeyDown(VK_RETURN))break;
// }
switch(LOWORD(wparam)) { switch(LOWORD(wparam)) {
case MENU_FILE_LOAD: case MENU_FILE_LOAD:
w_main->menu_load(); w_main->menu_load();
@@ -175,6 +178,11 @@ int i;
case MENU_FILE_EXIT: case MENU_FILE_EXIT:
PostQuitMessage(0); PostQuitMessage(0);
break; break;
case MENU_SETTINGS_REGULATE_SPEED:
config::system.regulate_speed.toggle();
CheckMenuItem(w_main->hmenu, MENU_SETTINGS_REGULATE_SPEED,
(config::system.regulate_speed)?MF_CHECKED:MF_UNCHECKED);
break;
case MENU_SETTINGS_FRAMESKIP_OFF: case MENU_SETTINGS_FRAMESKIP_OFF:
case MENU_SETTINGS_FRAMESKIP_1: case MENU_SETTINGS_FRAMESKIP_1:
case MENU_SETTINGS_FRAMESKIP_2: case MENU_SETTINGS_FRAMESKIP_2:
@@ -314,6 +322,7 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&File"); AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&File");
hsubmenu = CreatePopupMenu(); hsubmenu = CreatePopupMenu();
AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_REGULATE_SPEED, "&Regulate Speed");
hbranchmenu = CreatePopupMenu(); hbranchmenu = CreatePopupMenu();
AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_OFF, "Off"); AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_FRAMESKIP_OFF, "Off");
@@ -356,8 +365,11 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_INPUTCFG_JOYPAD2, "Joypad 2"); AppendMenu(hbranchmenu, MF_STRING, MENU_SETTINGS_INPUTCFG_JOYPAD2, "Joypad 2");
AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Configure Input Devices"); AppendMenu(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Configure Input Devices");
#ifdef DEBUGGER
AppendMenu(hsubmenu, MF_SEPARATOR, 0, ""); AppendMenu(hsubmenu, MF_SEPARATOR, 0, "");
AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_DEBUGGER, "&Debugger"); AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_DEBUGGER, "&Debugger");
#endif
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings"); AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings");
hsubmenu = CreatePopupMenu(); hsubmenu = CreatePopupMenu();
@@ -367,6 +379,7 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hsubmenu, MF_STRING, MENU_MISC_ABOUT, "&About..."); AppendMenu(hsubmenu, MF_STRING, MENU_MISC_ABOUT, "&About...");
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Misc"); AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Misc");
CheckMenuItem(hmenu, MENU_SETTINGS_REGULATE_SPEED, (config::system.regulate_speed)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hmenu, MENU_SETTINGS_USEVRAM, (config::video.use_vram)?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(hmenu, MENU_SETTINGS_USEVRAM, (config::video.use_vram)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hmenu, MENU_SETTINGS_VBLANK, (config::video.vblank)?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(hmenu, MENU_SETTINGS_VBLANK, (config::video.vblank)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hmenu, MENU_SETTINGS_COLORADJUST_COLORCURVE, (config::snes.video_color_curve)?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(hmenu, MENU_SETTINGS_COLORADJUST_COLORCURVE, (config::snes.video_color_curve)?MF_CHECKED:MF_UNCHECKED);

View File

@@ -154,7 +154,7 @@ HDC hdc;
break; break;
case MEMORYEDITOR_FEXPORT: case MEMORYEDITOR_FEXPORT:
pos = SendDlgItemMessage(hwnd, MEMORYEDITOR_FSOURCE, CB_GETCURSEL, 0, 0); pos = SendDlgItemMessage(hwnd, MEMORYEDITOR_FSOURCE, CB_GETCURSEL, 0, 0);
w_memory->export(pos); w_memory->export_data(pos);
break; break;
case MEMORYEDITOR_AUTOUPDATE: case MEMORYEDITOR_AUTOUPDATE:
if(w_memory->auto_update == false) { if(w_memory->auto_update == false) {
@@ -186,7 +186,7 @@ HDC hdc;
return DefWindowProc(hwnd, msg, wparam, lparam); return DefWindowProc(hwnd, msg, wparam, lparam);
} }
void MemoryEditor::export(uint32 type) { void MemoryEditor::export_data(uint32 type) {
FILE *fp; FILE *fp;
int i, x; int i, x;
if(type == 0) { //DRAM if(type == 0) { //DRAM
@@ -233,12 +233,12 @@ int i, x;
} }
fclose(fp); fclose(fp);
} else if(type == 6) { //All } else if(type == 6) { //All
export(0); export_data(0);
export(1); export_data(1);
export(2); export_data(2);
export(3); export_data(3);
export(4); export_data(4);
export(5); export_data(5);
} }
} }

View File

@@ -1,15 +1,10 @@
#define INTERFACE_MAIN #define INTERFACE_MAIN
//requires visual c++
#define USE_X86_ASM
#include "winmain.h" #include "winmain.h"
#include "../base.h" #include "../base.h"
#include "config.cpp" #include "config.cpp"
#define DSP_BUFFER_SIZE 8000
#include "bsnes.h" #include "bsnes.h"
#include "ui.h" #include "ui.h"
#include "dd_renderer.h" #include "dd_renderer.h"
@@ -22,44 +17,47 @@
#include "ui.cpp" #include "ui.cpp"
void init_snes() { void init_snes() {
mem_bus = new bMemBus(); #ifdef POLYMORPHISM
cpu = new bCPU(); deref(mem) = new bMemBus();
apu = new bAPU(); deref(cpu) = new bCPU();
dsp = new bDSP(); deref(apu) = new bAPU();
ppu = new bPPU(); deref(dsp) = new bDSP();
snes = new bSNES(); deref(ppu) = new bPPU();
bsnes = static_cast<bSNES*>(snes); #endif
snes = new bSNES();
bsnes = static_cast<bSNES*>(snes);
snes->init(); snes->init();
snes->set_playback_buffer_size(DSP_BUFFER_SIZE);
} }
void term_snes() { void term_snes() {
snes->term(); snes->term();
#ifdef POLYMORPHISM
//static casting is neccesary to call derived class deconstructor... //static casting is neccesary to call derived class deconstructor...
if(mem_bus) { if(deref(mem)) {
delete(static_cast<bMemBus*>(mem_bus)); delete static_cast<bMemBus*>(deref(mem));
mem_bus = 0; deref(mem) = 0;
} }
if(cpu) { if(deref(cpu)) {
delete(static_cast<bCPU*>(cpu)); delete static_cast<bCPU*>(deref(cpu));
cpu = 0; deref(cpu) = 0;
} }
if(apu) { if(deref(apu)) {
delete(static_cast<bAPU*>(apu)); delete static_cast<bAPU*>(deref(apu));
apu = 0; deref(apu) = 0;
} }
if(dsp) { if(deref(dsp)) {
delete(static_cast<bDSP*>(dsp)); delete static_cast<bDSP*>(deref(dsp));
dsp = 0; deref(dsp) = 0;
} }
if(ppu) { if(deref(ppu)) {
delete(static_cast<bPPU*>(ppu)); delete static_cast<bPPU*>(deref(ppu));
ppu = 0; deref(ppu) = 0;
} }
#endif
if(snes) { if(snes) {
delete(static_cast<bSNES*>(snes)); delete static_cast<bSNES*>(snes);
snes = 0; snes = 0;
} }
} }