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
# (default = true)
snes.mute = true
snes.mute = false
# Regulate speed to 60hz (NTSC) / 50hz (PAL)
# (default = true)
system.regulate_speed = true
# Video mode
# 0 = 256x224w

BIN
bsnes.exe

Binary file not shown.

View File

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

View File

@ -1,18 +1,22 @@
void bAPU::exec_cycle() {
uint8 op;
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 {
if(status.cycle_pos) {
(this->*optbl[status.opcode])();
add_cycles(1);
if(status.cycle_pos == 0) {
#ifdef DEBUGGER
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

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
//#define ARCH_LSB
//#define ARCH_MSB

View File

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

View File

@ -85,7 +85,7 @@ void bCPU::power() {
void bCPU::reset() {
//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
regs.x.h = 0x00;
@ -161,22 +161,25 @@ void bCPU::cpu_io() {
status.cycle_count = 6;
pre_exec_cycle();
add_cycles(6);
cycle_edge();
}
uint8 bCPU::mem_read(uint32 addr) {
status.cycle_count = mem_bus->speed(addr);
status.cycle_count = r_mem->speed(addr);
pre_exec_cycle();
add_cycles(status.cycle_count - 4);
regs.mdr = mem_bus->read(addr);
regs.mdr = r_mem->read(addr);
add_cycles(4);
cycle_edge();
return regs.mdr;
}
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();
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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -183,7 +183,7 @@ int i, v, n;
void bDSP::power() {
int v;
spcram = apu->get_spcram_handle();
spcram = r_apu->get_spcram_handle();
memset(dspram, 0x00, 128);
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
#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 "memory/memory.h"
#include "memory/bmemory/bmemory.h"
extern MMIO mmio_unmapped;
extern MemBus *mem_bus;
#include "cpu/cpu.h"
#include "cpu/bcpu/bcpu.h"
extern CPU *cpu;
#include "apu/apu.h"
#include "apu/bapu/bapu.h"
#include "apu/bapuskip/bapuskip.h"
extern APU *apu;
#include "dsp/dsp.h"
#include "dsp/bdsp/bdsp.h"
extern DSP *dsp;
#include "ppu/ppu.h"
#include "ppu/bppu/bppu.h"
extern PPU *ppu;
#include "snes/snes.h"
extern SNES *snes;
#include "chip/srtc/srtc.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 SDD1 *sdd1;
#include "config/config.h"
#ifdef INTERFACE_MAIN
#include "config/config.cpp"
MemBus *mem_bus;
CPU *cpu;
APU *apu;
DSP *dsp;
PPU *ppu;
SNES *snes;
SRTC *srtc;
SDD1 *sdd1;
#include "config/config.cpp"
#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

View File

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

View File

@ -15,7 +15,7 @@ uint8 mapper, region;
rom_size = rf->size();
if(rom_size < 32768) {
free(rom_image);
zerofree(rom_image);
return false;
}
@ -77,7 +77,7 @@ end:
region = rom[index + 0x19];
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("* 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",
@ -206,7 +206,9 @@ static uint32 r;
break;
}
#ifdef DEBUGGER
snes->notify(SNES::MEM_READ, addr, r);
#endif
return r;
}
@ -245,7 +247,9 @@ void bMemBus::write(uint32 addr, uint8 value) {
break;
}
#ifdef DEBUGGER
snes->notify(SNES::MEM_WRITE, addr, value);
#endif
}
void bMemBus::power() {

View File

@ -79,7 +79,7 @@ void Memory::write_long(uint32 addr, uint32 data, uint wrap) {
}
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) {}
uint8 MemBus::calc_speed(uint32 addr, bool fast) {
@ -92,10 +92,6 @@ uint8 MemBus::calc_speed(uint32 addr, bool fast) {
return 8;
}
uint8 MemBus::speed(uint32 addr) {
return speed_table[addr >> 9];
}
void MemBus::set_speed(bool fast) {
fastROM = fast;

View File

@ -43,8 +43,10 @@ uint8 *speed_table,
speed_table_fastrom[32768];
inline uint8 calc_speed(uint32 addr, bool fast);
public:
uint8 speed(uint32 addr);
void set_speed(bool fast);
inline uint8 speed(uint32 addr) {
return speed_table[addr >> 9];
}
void set_speed(bool fast);
virtual bool load_cart(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::scanline() {
line.y = cpu->vcounter();
line.y = r_cpu->vcounter();
line.width = (regs.bg_mode == 5 || regs.bg_mode == 6) ? 512 : 256;
line.hires = (regs.bg_mode == 5 || regs.bg_mode == 6);
line.interlace = cpu->interlace();
line.interlace_field = cpu->interlace_field();
line.interlace = r_cpu->interlace();
line.interlace_field = r_cpu->interlace_field();
if(line.y == 0) {
//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
regs.oam_addr = ((regs.oam_addrh << 8) | regs.oam_addrl) << 1;
}
@ -35,17 +35,18 @@ void bPPU::scanline() {
void bPPU::render_scanline() {
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();
}
}
void bPPU::frame() {
PPU::frame();
snes->notify(SNES::RENDER_FRAME);
}
void bPPU::power() {
PPU::power();
memset(vram, 0, 65536);
memset(oam, 0, 544);
memset(cgram, 0, 512);
@ -56,6 +57,7 @@ void bPPU::power() {
}
void bPPU::reset() {
PPU::reset();
frame();
memset(sprite_list, 0, sizeof(sprite_list));
@ -228,9 +230,10 @@ void bPPU::reset() {
regs.color_enabled[BG1] = false;
//$2132
regs.color_r = 0x00;
regs.color_g = 0x00;
regs.color_b = 0x00;
regs.color_r = 0x00;
regs.color_g = 0x00;
regs.color_b = 0x00;
regs.color_rgb = 0x0000;
//$2133
regs.mode7_extbg = false;
@ -262,20 +265,26 @@ void bPPU::reset() {
uint8 bPPU::vram_read(uint16 addr) {
uint8 r;
r = vram[addr];
#ifdef DEBUGGER
snes->notify(SNES::VRAM_READ, addr, r);
#endif
return r;
}
void bPPU::vram_write(uint16 addr, uint8 value) {
vram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::VRAM_WRITE, addr, value);
#endif
}
uint8 bPPU::oam_read(uint16 addr) {
uint8 r;
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
r = oam[addr];
#ifdef DEBUGGER
snes->notify(SNES::OAM_READ, addr, r);
#endif
return r;
}
@ -283,7 +292,9 @@ void bPPU::oam_write(uint16 addr, uint8 value) {
if(addr >= 0x0200)addr = 0x0200 | (addr & 31);
oam[addr] = value;
update_sprite_list(addr);
#ifdef DEBUGGER
snes->notify(SNES::OAM_WRITE, addr, value);
#endif
}
uint8 bPPU::cgram_read(uint16 addr) {
@ -293,7 +304,9 @@ uint8 r;
if(addr & 1) {
r &= 0x7f;
}
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_READ, addr, r);
#endif
return r;
}
@ -303,7 +316,9 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
value &= 0x7f;
}
cgram[addr] = value;
#ifdef DEBUGGER
snes->notify(SNES::CGRAM_WRITE, addr, value);
#endif
}
bPPU::bPPU() {

View File

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

View File

@ -1,6 +1,6 @@
void bPPU::latch_counters() {
regs.hcounter = cpu->hcounter();
regs.vcounter = cpu->vcounter();
regs.hcounter = r_cpu->hcounter();
regs.vcounter = r_cpu->vcounter();
regs.counters_latched = true;
}
@ -21,20 +21,20 @@ bool bPPU::vram_can_read() {
return true;
}
uint16 v = cpu->vcounter();
uint16 hc = cpu->hcycles();
uint16 v = r_cpu->vcounter();
uint16 hc = r_cpu->hcycles();
uint16 ls;
if(cpu->interlace() && !cpu->interlace_field()) {
ls = cpu->region_scanlines();
if(r_cpu->interlace() && !r_cpu->interlace_field()) {
ls = r_cpu->region_scanlines();
} else {
ls = cpu->region_scanlines() - 1;
ls = r_cpu->region_scanlines() - 1;
}
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;
return false;
}
@ -47,17 +47,17 @@ bool bPPU::vram_can_write(uint8 &value) {
return true;
}
uint16 v = cpu->vcounter();
uint16 hc = cpu->hcycles();
uint16 v = r_cpu->vcounter();
uint16 hc = r_cpu->hcycles();
if(v == 0) {
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;
}
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;
return true;
}
@ -542,6 +542,8 @@ void bPPU::mmio_w2132(uint8 value) {
if(value & 0x80)regs.color_b = value & 0x1f;
if(value & 0x40)regs.color_g = 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
@ -552,8 +554,8 @@ void bPPU::mmio_w2133(uint8 value) {
regs.oam_halve = !!(value & 0x02);
regs.interlace = !!(value & 0x01);
cpu->set_overscan(regs.overscan);
cpu->set_interlace(regs.interlace);
r_cpu->set_overscan(regs.overscan);
r_cpu->set_interlace(regs.interlace);
}
//MPYL
@ -582,10 +584,10 @@ uint32 r;
//SLHV
uint8 bPPU::mmio_r2137() {
if(cpu->pio_status() & 0x80) {
if(r_cpu->pio_status() & 0x80) {
latch_counters();
}
return cpu->regs.mdr;
return r_cpu->regs.mdr;
}
//OAMDATAREAD
@ -689,8 +691,8 @@ uint8 r = 0x00;
regs.latch_hcounter = 0;
regs.latch_vcounter = 0;
r |= cpu->interlace_field() << 7;
if(!(cpu->pio_status() & 0x80)) {
r |= r_cpu->interlace_field() << 7;
if(!(r_cpu->pio_status() & 0x80)) {
r |= 0x40;
} else if(regs.counters_latched == true) {
r |= 0x40;
@ -738,7 +740,7 @@ uint8 bPPUMMIO::read(uint32 addr) {
case 0x213f:return ppu->mmio_r213f(); //STAT78
}
return cpu->regs.mdr;
return r_cpu->regs.mdr;
}
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): ->
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
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() {
switch(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:
if(regs.bg3_priority) {
render_line_bg(BG1, COLORDEPTH_16, 5, 8);
render_line_bg(BG2, COLORDEPTH_16, 4, 7);
render_line_bg(BG3, COLORDEPTH_4, 1, 10);
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() {
if(regs.display_disabled == true) {
memset(snes->get_ppu_output_handle(), 0, 1024);
memset(output + (line.y * 1024), 0, 1024);
return;
}

View File

@ -64,24 +64,25 @@ struct oam_tileitem {
} oam_tilelist[34];
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();
void load_oam_tiles();
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_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
void render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos);
//bppu_render_addsub.cpp
inline uint16 addsub_pixels(uint32 cdest, uint32 csrc);
inline uint16 addsub_pixel (uint32 cdest);
inline uint16 addsub_pixels(uint32 x);
//bppu_render_line.cpp
enum { BLENDTYPE_BACK = 0, BLENDTYPE_MAIN = 1, BLENDTYPE_SUB = 2, BLENDTYPE_COMBINE = 3 };
inline uint16 get_palette(uint8 index);
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();

View File

@ -1,92 +1,39 @@
inline uint16 bPPU::addsub_pixels(uint32 cdest, uint32 csrc) {
int r, g, b;
uint16 res;
switch(regs.color_mode) {
case 0: //COLORMODE_ADD:
if(regs.color_halve == true) {
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 & 0x00008000)cdest |= 0x00007c00;
if(cdest & 0x00000020)cdest |= 0x0000001f;
cdest &= 0x03e07c1f;
return (cdest >> 16) | cdest;
inline uint16 bPPU::addsub_pixels(uint32 x) {
uint32 cdest = pixel_cache[x].src_main,
csrc = pixel_cache[x].src_sub;
bool halve = false;
if(regs.color_halve && window_cache[COL].main[x]) {
if(regs.addsub_mode && pixel_cache[x].bg_sub == BACK);
else {
halve = true;
}
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) {
int r, g, b;
uint32 csrc = (regs.color_r) | (regs.color_g << 5) | (regs.color_b << 10);
uint16 res;
switch(regs.color_mode) {
case 0: //COLORMODE_ADD:
if(regs.color_halve == true && regs.addsub_mode == 0) {
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(!regs.color_mode) {
//add
cdest = ((cdest << 16) | cdest) & 0x03e07c1f;
csrc = ((csrc << 16) | csrc) & 0x03e07c1f;
cdest += csrc;
if(!halve) {
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 && 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 {
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;
cdest >>= 1;
}
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 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
//index is a tile number count to add to base tile number
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 += tiledata_index;
tile_num &= tile_mask;
if(bg_td_state[tile_num] == 1) {
render_bg_tile(color_depth, tile_num);
@ -162,7 +164,7 @@ int32 prev_x = -1, prev_y = -1;
xpos = mosaic_x & 7;
if(mirror_x)xpos ^= 7; //invert x tile pos
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)) {
col = get_direct_color(pal_num, col);
} else {

View File

@ -118,7 +118,7 @@ void bPPU::init_tiledata_cache() {
void bPPU::clear_tiledata_cache() {
memset(bg_tiledata[TILE_2BIT], 0, 262144);
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_4BIT], 0, 2048);
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);
}
inline uint16 bPPU::get_pixel(int x) {
inline uint16 bPPU::get_pixel(uint32 x) {
_pixel *p = &pixel_cache[x];
uint16 _r, src_back = get_palette(0);
if(p->bg_main && p->bg_sub) {
if(p->color_exempt == false && 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 == 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?
}
if(!p->bg_main) {
p->bg_main = BACK;
p->src_main = get_palette(0);
p->color_exempt = false;
} 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 {
_r = 0x0000;
}
p->bg_main &= 0x7f;
}
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() {
int x;
uint16 _r;
uint16 *ptr;
ptr = (uint16*)snes->get_ppu_output_handle();
uint16 *ltable;
ltable = (uint16*)light_table + (regs.display_brightness << 15);
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);
r = get_pixel(x);
*ptr++ = *(ltable + r);
}
} else {
for(x=0;x<512;x++) {
_r = get_pixel(x);
*ptr++ = *(ltable + _r);
r = get_pixel(x);
*ptr++ = *(ltable + r);
}
}
}

View File

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

View File

@ -63,10 +63,10 @@ uint16 width, height;
addr &= 0x001f;
z = oam[0x0200 + addr];
i = addr << 2;
sprite_list[i ].x = ((z & 0x01)?0x0100:0x0000) + (sprite_list[i ].x & 0xff);
sprite_list[i + 1].x = ((z & 0x04)?0x0100:0x0000) + (sprite_list[i + 1].x & 0xff);
sprite_list[i + 2].x = ((z & 0x10)?0x0100:0x0000) + (sprite_list[i + 2].x & 0xff);
sprite_list[i + 3].x = ((z & 0x40)?0x0100:0x0000) + (sprite_list[i + 3].x & 0xff);
sprite_list[i ].x = ((z & 0x01) ? 256 : 0) + (sprite_list[i ].x & 255);
sprite_list[i + 1].x = ((z & 0x04) ? 256 : 0) + (sprite_list[i + 1].x & 255);
sprite_list[i + 2].x = ((z & 0x10) ? 256 : 0) + (sprite_list[i + 2].x & 255);
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 + 1, !!(z & 0x08));
get_sprite_size(i + 2, !!(z & 0x20));
@ -90,7 +90,7 @@ uint16 addr = 0x0200;
bool bPPU::is_sprite_on_scanline() {
//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
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(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() {
uint16 tile_width;
tile_width = spr->width >> 3;
uint16 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
//should be added to hires 512x448 sprites as well, and not
//just when oam_halve is enabled...
@ -132,40 +123,40 @@ int x, y, chr, nameselect_index;
y += line.interlace_field;
}
}
x &= 511;
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) {
chr += 256;
nameselect_index = regs.oam_nameselect << 13;
} else {
nameselect_index = 0x0000;
tdaddr += (256 * 32) + (regs.oam_nameselect << 13);
}
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++) {
z = x;
z += (i << ((line.width == 512) ? 4 : 3));
z &= 511;
sx = x;
sx += i << 3;
sx &= 511;
//ignore sprites that are offscreen
//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;
n = regs.oam_tilecount - 1;
oam_tilelist[n].x = z;
oam_tilelist[n].x = sx;
oam_tilelist[n].y = y;
oam_tilelist[n].pri = spr->priority;
oam_tilelist[n].pal = (spr->palette << 4) + 128;
oam_tilelist[n].hflip = spr->hflip;
if(oam_tilelist[n].hflip) {
mx = (tile_width - 1) - i;
} else {
mx = i;
}
pos = regs.oam_tdaddr + ((chr + mx) << 5) + ((y & 7) << 1) + nameselect_index;
mx = (oam_tilelist[n].hflip) ? ((tile_width - 1) - i) : i;
pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);
oam_tilelist[n].tile = (pos >> 5) & 0x07ff;
}
}
@ -182,38 +173,26 @@ oam_tileitem *t = &oam_tilelist[tile_num];
int x, sx, col;
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);
for(x=0;x<8;x++) {
sx &= 511;
if(sx < line.width) {
col = *(tile_ptr + ((t->hflip)?7-x:x));
if(sx < 256) {
col = *(tile_ptr + ((t->hflip) ? (7 - x) : x));
if(col) {
col += t->pal;
oam_line_pal[sx] = col;
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) {
int s, x;
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 s;
regs.oam_itemcount = 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);
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.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;
for(x=0;x<line.width;x++) {
if(line.width == 256) {
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;
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;
case 0:pri = pri0_pos;break;
case 1:pri = pri1_pos;break;
case 2:pri = pri2_pos;break;
case 3:pri = pri3_pos;break;
}
if(window_cache[COL].main[x]) {
if(_bg_enabled == true && !wt_main[x]) {
if(pixel_cache[x].pri_main < _pri) {
pixel_cache[x].pri_main = _pri;
pixel_cache[x].bg_main = PC_OAM;
pixel_cache[x].src_main = get_palette(oam_line_pal[x]);
pixel_cache[x].color_exempt = (oam_line_pal[x] < 192);
}
if(bg_enabled == true && !wt_main[x]) {
if(pixel_cache[x].pri_main < pri) {
pixel_cache[x].pri_main = pri;
pixel_cache[x].bg_main = PC_OAM;
pixel_cache[x].src_main = get_palette(oam_line_pal[x]);
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;
pixel_cache[x].bg_sub = PC_OAM;
pixel_cache[x].src_sub = get_palette(oam_line_pal[x]);
}
}
if(bgsub_enabled == true && !wt_sub[x]) {
if(pixel_cache[x].pri_sub < pri) {
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) {
info->hires = scanline_is_hires();
info->interlace = cpu->interlace();
info->interlace = r_cpu->interlace();
}
void PPU::enable_renderer(bool r) { status.render_output = r; }
bool PPU::renderer_enabled() { return status.render_output; }
void PPU::frame() {
static fr = 0, fe = 0;
status.frame_executed = true;
static int32 fr = 0, fe = 0;
static time_t prev, curr;
fe++;
if(status.render_output)fr++;
@ -24,7 +26,16 @@ static time_t prev, curr;
prev = curr;
}
void PPU::power() {}
void PPU::reset() {
memset(output, 0, 512 * 480 * sizeof(uint16));
}
PPU::PPU() {
output = (uint16*)malloc(512 * 480 * sizeof(uint16));
memset(output, 0, 512 * 480 * sizeof(uint16));
status.render_output = true;
status.frames_updated = false;
status.frames_rendered = 0;
@ -35,4 +46,6 @@ PPU::PPU() {
mmio = &mmio_unmapped;
}
PPU::~PPU() {}
PPU::~PPU() {
zerofree(output);
}

View File

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

View File

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

View File

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

View File

@ -6,11 +6,7 @@ void bSNES::run() {
switch(run_status) {
case RUN:
while(update_frame == false) {
SNES::run();
}
update_frame = false;
render();
SNES::runtoframe();
return;
case STOP:
break;
@ -18,13 +14,13 @@ void bSNES::run() {
}
void bSNES::video_run() {
if(ppu->status.frames_updated) {
if(r_ppu->status.frames_updated) {
char s[512], t[512];
ppu->status.frames_updated = false;
r_ppu->status.frames_updated = false;
// 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) {
// sprintf(t, " (%d frames)", ppu->status.frames_rendered);
// sprintf(t, " (%d frames)", r_ppu->status.frames_rendered);
// strcat(s, t);
// }
SDL_WM_SetCaption(s, 0);
@ -34,7 +30,28 @@ void bSNES::video_run() {
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 ***
@ -93,15 +110,8 @@ bJoypad::bJoypad() {
l = r = select = start = false;
}
void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
switch(message) {
case RENDER_FRAME:
update_frame = true;
break;
}
}
void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {}
bSNES::bSNES() {
run_status = STOP;
update_frame = false;
run_status = STOP;
}

View File

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

View File

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

View File

@ -1,59 +1,11 @@
void render16() {
uint16 *dest, *src;
uint32 pitch;
int x, y;
void render() {
SNES::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.y = (vi.height == 224) ? 1 : 2;
screen_info.rs.w = vi.width;
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
//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_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);
}

View File

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

View File

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

View File

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

View File

@ -19,7 +19,8 @@ public:
enum { NTSC = 0, PAL = 1 };
//system functions
virtual void run();
virtual inline void run();
virtual inline void runtoframe();
virtual void init();
virtual void term();
virtual void power();
@ -39,7 +40,6 @@ enum { NTSC = 0, PAL = 1 };
//debugging functions
enum {
NO_ACTION = 0,
RENDER_FRAME,
CPU_EXEC_OPCODE_BEGIN, CPU_EXEC_OPCODE_END,
APU_EXEC_OPCODE_BEGIN, APU_EXEC_OPCODE_END,
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) {
if(pcmfp) {
fputc(data, pcmfp);
@ -30,11 +8,7 @@ void SNES::audio_update(uint32 data) {
if((bool)config::snes.mute == true)data = 0x0000;
dsp_buffer.data[dsp_buffer.pos++] = (data) & 0xffff;
dsp_buffer.data[dsp_buffer.pos++] = (data >> 16) & 0xffff;
dsp_buffer.pos %= dsp_buffer.size;
sound_run();
sound_run(data);
}
void SNES::log_audio_enable(const char *fn) {

View File

@ -1,15 +1,5 @@
struct {
uint16 *data;
uint32 size, pos;
} dsp_buffer;
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
//automatically ("audio%0.3d.wav")
void log_audio_enable(const char *fn = 0);
@ -19,4 +9,4 @@ FILE *pcmfp;
void audio_init();
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() {
int i, l, r, g, b;
int32 i, l, r, g, b;
double lr = 0.2126, lg = 0.7152, lb = 0.0722; //luminance
uint32 col;
@ -29,7 +29,7 @@ uint32 col;
}
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 > 255)l = 255;
r = g = b = l;
@ -92,7 +92,6 @@ void SNES::update_video_format() {
}
void SNES::get_video_info(video_info *info) {
info->data = video.data;
info->mode = 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;
uint16 *dest;
dest = video.data;
uint16 *src = video.ppu_data;
uint16 *dest = video.data;
for(y=0;y<224;y++) {
if(video_frame[y].hires == false) {
@ -147,13 +146,14 @@ uint16 *dest;
}
src += 512;
}
dest += video.pitch - 256;
}
}
void SNES::video_update_512x224(uint16 *src) {
void SNES::video_update_512x224() {
int x, y;
uint16 *dest;
dest = video.data;
uint16 *src = video.ppu_data;
uint16 *dest = video.data;
for(y=0;y<224;y++) {
if(video_frame[y].hires == false) {
@ -168,31 +168,41 @@ uint16 *dest;
}
src += 512;
}
dest += video.pitch - 512;
}
}
void SNES::video_update_256x448(uint16 *src) {
void SNES::video_update_256x448() {
int x, y;
uint16 *dest;
bool field = !cpu->interlace_field();
dest = video.data;
uint16 *src = video.ppu_data;
uint16 *dest = video.data;
bool field = !r_cpu->interlace_field();
for(y=0;y<224;y++) {
if(video_frame[y].interlace == false) {
if(video_frame[y].hires == false) {
for(x=0;x<512;x++) {
*dest++ = color_lookup_table[*(src + (uint8)x)];
for(x=0;x<256;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 {
for(x=0;x<512;x++) {
*dest++ = color_lookup_table[*(src + ((x & 255) << 1))];
for(x=0;x<256;x++) {
*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 {
if(field) {
dest += 256;
dest += video.pitch;
src += 512;
}
@ -207,38 +217,49 @@ bool field = !cpu->interlace_field();
src += 2;
}
}
dest += video.pitch - 256;
if(!field) {
dest += 256;
dest += video.pitch;
src += 512;
}
}
}
}
void SNES::video_update_512x448(uint16 *src) {
void SNES::video_update_512x448() {
int x, y;
uint16 *dest;
bool field = !cpu->interlace_field();
dest = video.data;
uint16 *src = video.ppu_data;
uint16 *dest = video.data;
bool field = !r_cpu->interlace_field();
for(y=0;y<224;y++) {
if(video_frame[y].interlace == false) {
if(video_frame[y].hires == false) {
for(x=0;x<512;x++) {
*dest++ = color_lookup_table[*(src + (uint8)x)];
*dest++ = color_lookup_table[*(src + (uint8)x)];
for(x=0;x<256;x++) {
*dest++ = color_lookup_table[*(src + 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 {
for(x=0;x<1024;x++) {
*dest++ = color_lookup_table[*(src + (x & 511))];
for(x=0;x<512;x++) {
*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 {
if(field) {
dest += 512;
dest += video.pitch;
src += 512;
}
@ -253,9 +274,10 @@ bool field = !cpu->interlace_field();
*dest++ = color_lookup_table[*src++];
}
}
dest += video.pitch - 512;
if(!field) {
dest += 512;
dest += video.pitch;
src += 512;
}
}
@ -263,25 +285,30 @@ bool field = !cpu->interlace_field();
}
void SNES::video_update() {
if(ppu->renderer_enabled()) {
if(r_ppu->renderer_enabled()) {
if(video.format_changed == true) {
update_video_format();
}
uint16 *src = (uint16*)video.ppu_data + ((int(cpu->overscan()) << 3) * 1024);
switch(video.mode) {
case VM_256x224:video_update_256x224(src);break;
case VM_512x224:video_update_512x224(src);break;
case VM_256x448:video_update_256x448(src);break;
case VM_512x448:video_update_512x448(src);break;
case VM_VARIABLE:
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
case 0:video_update_256x224(src);break;
case 1:video_update_512x224(src);break;
case 2:video_update_256x448(src);break;
case 3:video_update_512x448(src);break;
video.data = (uint16*)video_lock(video.pitch);
video.ppu_data = (uint16*)r_ppu->output + (int(r_cpu->overscan()) << 13);
video.pitch >>= 1;
if(video.data) {
switch(video.mode) {
case VM_256x224:video_update_256x224();break;
case VM_512x224:video_update_512x224();break;
case VM_256x448:video_update_256x448();break;
case VM_512x448:video_update_512x448();break;
case VM_VARIABLE:
switch(int(video.frame_hires) | (int(video.frame_interlace) << 1)) {
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
@ -298,13 +325,13 @@ void SNES::video_update() {
}
void SNES::video_scanline() {
int y = cpu->vcounter();
int o = int(cpu->overscan()) << 3;
int y = r_cpu->vcounter();
int o = int(r_cpu->overscan()) << 3;
if(y <= (0 + o) || y >= (224 + o))return;
y -= o;
PPU::scanline_info si;
ppu->get_scanline_info(&si);
r_ppu->get_scanline_info(&si);
video_frame[y].hires = si.hires;
video_frame[y].interlace = si.interlace;
@ -313,21 +340,10 @@ PPU::scanline_info si;
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() {
int i, c;
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++) {
video_frame[i].hires = false;
video_frame[i].interlace = false;

View File

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

View File

@ -5,25 +5,13 @@ void SNES::capture_screenshot() {
//used to convert pixel data to write to rgb555 format
//bitmap image via SNES::output_screenshot() function
uint16 SNES::to_rgb555(uint32 color) {
if(video.depth == 15) {
//rgb555
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;
//bgr555->rgb555
return ((color & 0x7c00) >> 10) | (color & 0x03e0) | ((color & 0x001f) << 10);
}
//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() {
FILE *fp;
char fn[256];
@ -95,7 +83,7 @@ int x, y;
uint16 c;
for(y=height;y>=1;y--) {
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 >> 8, fp);
}

View File

@ -1,11 +1,11 @@
CC = cl
CFLAGS = /nologo /O2 /Ogityb2 /Gr /Gs /DARCH_LSB
CFLAGS = /nologo /O2 /wd4996
OBJS = winmain.obj \
libstring.obj libconfig.obj \
reader.obj \
memory.obj bmemory.obj \
cpu.obj bcpu.obj \
apu.obj bapu.obj bapuskip.obj \
apu.obj bapu.obj \
bdsp.obj \
ppu.obj bppu.obj \
snes.obj \
@ -15,9 +15,12 @@ LIBS = kernel32.lib user32.lib gdi32.lib comdlg32.lib ddraw.lib dsound.lib dxgui
all: $(OBJS)
rc /r /fobsnes.res bsnes.rc
$(CC) /Febsnes.exe $(CFLAGS) $(OBJS) bsnes.res $(LIBS)
#/link /PGD:bsnes.pgd /LTCG:PGOPTIMIZE
clean:
del *.obj
del *.pgd
del *.pgc
######################
### win32-specific ###
@ -60,9 +63,6 @@ apu.obj: ../apu/*
bapu.obj: ../apu/bapu/*
$(CC) $(CFLAGS) /c ../apu/bapu/bapu.cpp
bapuskip.obj: ../apu/bapuskip/*
$(CC) $(CFLAGS) /c ../apu/bapuskip/bapuskip.cpp
###########
### 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) {
uint8 cpu_op;
run_status = new_status;
@ -12,7 +21,7 @@ uint8 cpu_op;
status.cpu_ran = false;
break;
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
cpu_op == 0x30 || //bmi rel
@ -27,7 +36,7 @@ uint8 cpu_op;
cpu_op == 0xfc //jsr (addr,x)
) {
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 {
status.cpu_ran = false;
run_status = RUNTOCPUSTEP;
@ -48,10 +57,7 @@ void bSNES::run() {
switch(run_status) {
case RUN:
while(update_frame == false) {
SNES::run();
}
update_frame = false;
SNES::runtoframe();
return;
case STOP:
break;
@ -68,8 +74,8 @@ void bSNES::run() {
break;
case RUNTOFRAME:
SNES::run();
if(update_frame == true) {
update_frame = false;
if(r_ppu->status.frame_executed == true) {
r_ppu->status.frame_executed = false;
set_status(STOP);
disassemble_apu_op();
disassemble_cpu_op();
@ -89,7 +95,7 @@ void bSNES::run() {
break;
case RUNTOCPUPROCEED:
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);
disassemble_cpu_op();
} else if(w_bp->hit() == true) {
@ -114,13 +120,13 @@ void bSNES::run() {
}
void bSNES::video_run() {
if(ppu->status.frames_updated) {
if(r_ppu->status.frames_updated) {
char s[512], t[512];
ppu->status.frames_updated = false;
r_ppu->status.frames_updated = false;
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) {
sprintf(t, " (%d frames)", ppu->status.frames_rendered);
sprintf(t, " (%d frames)", r_ppu->status.frames_rendered);
strcat(s, t);
}
SetWindowText(w_main->hwnd, s);
@ -129,17 +135,43 @@ void bSNES::video_run() {
w_main->frameskip_pos++;
w_main->frameskip_pos %= (w_main->frameskip + 1);
if(ppu->renderer_enabled())dd_renderer->update();
ppu->enable_renderer(w_main->frameskip_pos == 0);
if(r_ppu->renderer_enabled())dd_renderer->update();
r_ppu->enable_renderer(w_main->frameskip_pos == 0);
}
void bSNES::sound_run() {
ds_sound->run();
void bSNES::sound_run(uint32 data) {
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 ***
***********************/
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) {
//only capture input when main window has focus
if(GetForegroundWindow() == w_main->hwnd) {
@ -279,27 +311,27 @@ uint8 r = 0x00;
if(a >= 0x2000 && a <= 0x5fff) {
r = 0x00;
} else {
r = mem_bus->read(addr);
r = r_mem->read(addr);
}
} else {
r = mem_bus->read(addr);
r = r_mem->read(addr);
}
break;
case SPCRAM:
addr &= 0xffff;
r = apu->spcram_read(addr);
r = r_apu->spcram_read(addr);
break;
case VRAM:
addr &= 0xffff;
r = ppu->vram_read(addr);
r = r_ppu->vram_read(addr);
break;
case OAM:
addr &= 0x03ff;
r = ppu->oam_read(addr);
r = r_ppu->oam_read(addr);
break;
case CGRAM:
addr &= 0x01ff;
r = ppu->cgram_read(addr);
r = r_ppu->cgram_read(addr);
break;
}
debug_command = false;
@ -311,38 +343,31 @@ void bSNES::write(uint8 type, uint32 addr, uint8 value) {
switch(type) {
case DRAM:
addr &= 0xffffff;
mem_bus->cart->write_protect(false);
mem_bus->write(addr, value);
mem_bus->cart->write_protect(true);
r_mem->cart->write_protect(false);
r_mem->write(addr, value);
r_mem->cart->write_protect(true);
break;
case SPCRAM:
addr &= 0xffff;
apu->spcram_write(addr, value);
r_apu->spcram_write(addr, value);
break;
case VRAM:
addr &= 0xffff;
ppu->vram_write(addr, value);
r_ppu->vram_write(addr, value);
break;
case OAM:
addr &= 0x03ff;
ppu->oam_write(addr, value);
r_ppu->oam_write(addr, value);
break;
case CGRAM:
addr &= 0x01ff;
ppu->cgram_write(addr, value);
r_ppu->cgram_write(addr, value);
break;
}
debug_command = false;
}
void bSNES::notify(uint32 message, uint32 param1, uint32 param2) {
//system messages
switch(message) {
case RENDER_FRAME:
update_frame = true;
break;
}
//debugging messages
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_trace_pos++;
//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();
break;
case APU_EXEC_OPCODE_BEGIN:
break;
case APU_EXEC_OPCODE_END:
status.apu_ran = true;
w_bp->test(message, apu->regs.pc, 0);
w_bp->test(message, r_apu->regs.pc, 0);
disassemble_apu_op();
break;
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
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);
}
@ -405,7 +430,7 @@ char t[512];
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);
}
@ -540,7 +565,6 @@ uint32 i, style;
bSNES::bSNES() {
run_status = STOP;
debug_command = false;
update_frame = false;
debugger_disable();
}

View File

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

Binary file not shown.

View File

@ -1,5 +1,10 @@
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 {
static Setting mode, use_vram, vblank;
} video;

View File

@ -176,66 +176,19 @@ int rx, ry;
}
}
#include "dd_renderer16.cpp"
void DDRenderer::update16() {
HRESULT hr;
hr = lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0);
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);
uint16 *DDRenderer::lock(uint32 &pitch) {
if(lpddsb->Lock(0, &ddsd, DDLOCK_WAIT, 0) != DD_OK)return 0;
pitch = ddsd.lPitch;
return (uint16*)ddsd.lpSurface;
}
//#include "dd_renderer32.cpp"
/*
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();
}
}
void DDRenderer::unlock() {
lpddsb->Unlock(0);
}
*/
void DDRenderer::update() {
snes->get_video_info(&vi);
switch(color_depth) {
case 15:
case 16:
update16();
break;
case 32:
//update32();
break;
}
set_source_window();
redraw();
}

View File

@ -14,22 +14,15 @@ bool fullscreen;
int width, height; //used for fullscreen mode clipping only
uint8 color_depth;
SNES::video_info vi; //initialized each frame at start of update()
uint16 *lock(uint32 &pitch);
void unlock();
void set_window(HWND hwnd_handle);
void create_backbuffer();
void to_windowed();
void to_fullscreen(int _width, int _height);
void set_source_window();
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 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() {
data.buffer = 0;
data.lpos = data.lsample = data.lbuffer = 0;
}
void DSSound::run(uint32 sample) {
data.buffer[data.buffer_pos++] = sample;
void DSSound::run() {
if(snes->get_playback_buffer_pos() != 0)return;
if(data.buffer_pos >= data.samples_per_frame) {
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 {
// dsb_b[0]->GetStatus(&status);
//} while(status & DSBSTATUS_PLAYING);
if(dsb_b->Lock(pos * data.buffer_size,
data.buffer_size, &buffer, &size, 0, 0, 0) == DS_OK) {
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);
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);
data.buffer_pos = 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() {
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);
ds->SetCooperativeLevel(w_main->hwnd, DSSCL_PRIORITY);
memset(&dsbd, 0, sizeof(dsbd));
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = 0;
dsbd.lpwfxFormat = 0;
ds->CreateSoundBuffer(&dsbd, &dsb_p, 0);
memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 32000;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = DSP_FREQ;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
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));
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS;
dsbd.dwBufferBytes = buffer_size;
dsbd.dwSize = sizeof(dsbd);
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY |
DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE;
dsbd.dwBufferBytes = data.buffer_size * 8;
dsbd.guid3DAlgorithm = GUID_NULL;
dsbd.lpwfxFormat = &wfx;
ds->CreateSoundBuffer(&dsbd, &dsb_b[0], 0);
ds->CreateSoundBuffer(&dsbd, &dsb_b[1], 0);
dsb_b[0]->SetFrequency(32000);
dsb_b[1]->SetFrequency(32000);
dsbd.lpwfxFormat = &wfx;
ds->CreateSoundBuffer(&dsbd, &dsb_b, 0);
dsb_b->SetFrequency(DSP_FREQ);
dsb_b->SetCurrentPosition(0);
dsb_b[0]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0);
memset(dslb, 0, buffer_size);
dsb_b[0]->Unlock(dslb, dslbs, 0, 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[1]->Lock(0, buffer_size, &dslb, &dslbs, 0, 0, 0);
memset(dslb, 0, buffer_size);
dsb_b[1]->Unlock(dslb, dslbs, 0, 0);
dsb_b[0]->Play(0, 0, 0);
buffer_pos = 0;
data.read_buffer = 0;
dsb_b->Play(0, 0, DSBPLAY_LOOPING);
}
void DSSound::term() {
if(dsb_b) {
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>
#define DSP_FREQ 32000
class DSSound {
public:
LPDIRECTSOUND ds;
LPDIRECTSOUNDBUFFER dsb_p, *dsb_b;
LPDIRECTSOUNDBUFFER dsb_p, dsb_b;
DSBUFFERDESC dsbd;
WAVEFORMATEX wfx;
uint32 sample_size;
uint32 buffer_size;
uint32 buffer_pos;
void *dslb;
uint32 dslbs;
public:
void run();
void run(uint32 sample);
void clear();
void init();
DSSound();
void term();
};
struct {
uint32 *buffer;
uint32 lpos;
uint32 lsample;
bool lbuffer;
uint32 buffer[2048];
uint8 read_buffer, prev_buffer;
uint32 buffer_pos, buffer_size;
uint32 samples_per_frame;
} data;
DSSound *ds_sound;

View File

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

View File

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

View File

@ -14,6 +14,7 @@ enum {
MENU_FILE_RESET,
MENU_FILE_POWER,
MENU_FILE_EXIT,
MENU_SETTINGS_REGULATE_SPEED,
MENU_SETTINGS_FRAMESKIP_OFF,
MENU_SETTINGS_FRAMESKIP_1,
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);
void write_byte(uint32 addr, uint8 value);
void refresh(uint32 type = null, uint32 addr = 0);
void export(uint32 type);
void export_data(uint32 type);
}*w_memory = 0;
class InputConfig : public Window {

View File

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

View File

@ -135,6 +135,16 @@ long __stdcall wndproc_main(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
time_t timeout;
int i;
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:
if(wparam == VK_ESCAPE) {
if(GetMenu(w_main->hwnd) == NULL) {
@ -146,13 +156,6 @@ int i;
}
break;
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)) {
case MENU_FILE_LOAD:
w_main->menu_load();
@ -175,6 +178,11 @@ int i;
case MENU_FILE_EXIT:
PostQuitMessage(0);
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_1:
case MENU_SETTINGS_FRAMESKIP_2:
@ -314,6 +322,7 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&File");
hsubmenu = CreatePopupMenu();
AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_REGULATE_SPEED, "&Regulate Speed");
hbranchmenu = CreatePopupMenu();
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(hsubmenu, MF_STRING | MF_POPUP, (unsigned int)hbranchmenu, "&Configure Input Devices");
#ifdef DEBUGGER
AppendMenu(hsubmenu, MF_SEPARATOR, 0, "");
AppendMenu(hsubmenu, MF_STRING, MENU_SETTINGS_DEBUGGER, "&Debugger");
#endif
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned int)hsubmenu, "&Settings");
hsubmenu = CreatePopupMenu();
@ -367,6 +379,7 @@ HMENU hsubmenu, hbranchmenu;
AppendMenu(hsubmenu, MF_STRING, MENU_MISC_ABOUT, "&About...");
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_VBLANK, (config::video.vblank)?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;
case MEMORYEDITOR_FEXPORT:
pos = SendDlgItemMessage(hwnd, MEMORYEDITOR_FSOURCE, CB_GETCURSEL, 0, 0);
w_memory->export(pos);
w_memory->export_data(pos);
break;
case MEMORYEDITOR_AUTOUPDATE:
if(w_memory->auto_update == false) {
@ -186,7 +186,7 @@ HDC hdc;
return DefWindowProc(hwnd, msg, wparam, lparam);
}
void MemoryEditor::export(uint32 type) {
void MemoryEditor::export_data(uint32 type) {
FILE *fp;
int i, x;
if(type == 0) { //DRAM
@ -233,12 +233,12 @@ int i, x;
}
fclose(fp);
} else if(type == 6) { //All
export(0);
export(1);
export(2);
export(3);
export(4);
export(5);
export_data(0);
export_data(1);
export_data(2);
export_data(3);
export_data(4);
export_data(5);
}
}

View File

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