mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
f288280ceb
commit
7dec0b2a3c
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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();
|
||||
};
|
|
@ -1,3 +1,6 @@
|
|||
//#define DEBUGGER
|
||||
//#define POLYMORPHISM
|
||||
|
||||
//this should be declared in the port-specific makefiles
|
||||
//#define ARCH_LSB
|
||||
//#define ARCH_MSB
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -28,7 +28,7 @@ understood.
|
|||
|
||||
************************************************************************/
|
||||
|
||||
#define SDD1_read(__addr) (mem_bus->read(__addr))
|
||||
#define SDD1_read(__addr) (r_mem->read(__addr))
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -41,7 +41,7 @@ union {
|
|||
struct { uint8 l, h; };
|
||||
#else
|
||||
struct { uint8 h, l; };
|
||||
#endif;
|
||||
#endif
|
||||
};
|
||||
|
||||
CPUReg16() { w = 0; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -127,6 +127,7 @@ struct {
|
|||
|
||||
//$2132
|
||||
uint8 color_r, color_g, color_b;
|
||||
uint16 color_rgb;
|
||||
|
||||
//$2133
|
||||
bool mode7_extbg;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 ###
|
||||
###########
|
||||
|
|
|
@ -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 ###
|
||||
###########
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
@nmake /NOLOGO /f Makefile.win32 clean
|
||||
@del output.wav
|
||||
@del bsnes_sdl.exe
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ###
|
||||
###########
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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.
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue