diff --git a/bsnes.cfg b/bsnes.cfg index 48be699b..78af5efa 100644 --- a/bsnes.cfg +++ b/bsnes.cfg @@ -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 diff --git a/bsnes.exe b/bsnes.exe index 1fe6a58a..8514825d 100644 Binary files a/bsnes.exe and b/bsnes.exe differ diff --git a/src/apu/bapu/bapu.cpp b/src/apu/bapu/bapu.cpp index 7395bce2..44501483 100644 --- a/src/apu/bapu/bapu.cpp +++ b/src/apu/bapu/bapu.cpp @@ -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) { diff --git a/src/apu/bapu/bapu_exec.cpp b/src/apu/bapu/bapu_exec.cpp index 37235466..25c92029 100644 --- a/src/apu/bapu/bapu_exec.cpp +++ b/src/apu/bapu/bapu_exec.cpp @@ -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 diff --git a/src/apu/bapuskip/bapuskip.cpp b/src/apu/bapuskip/bapuskip.cpp deleted file mode 100644 index 597a93bd..00000000 --- a/src/apu/bapuskip/bapuskip.cpp +++ /dev/null @@ -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)); -} diff --git a/src/apu/bapuskip/bapuskip.h b/src/apu/bapuskip/bapuskip.h deleted file mode 100644 index 63b1da50..00000000 --- a/src/apu/bapuskip/bapuskip.h +++ /dev/null @@ -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(); -}; diff --git a/src/base.h b/src/base.h index 3141c3a0..7e00bb59 100644 --- a/src/base.h +++ b/src/base.h @@ -1,3 +1,6 @@ +//#define DEBUGGER +//#define POLYMORPHISM + //this should be declared in the port-specific makefiles //#define ARCH_LSB //#define ARCH_MSB diff --git a/src/chip/sdd1/sdd1.cpp b/src/chip/sdd1/sdd1.cpp index c26694bb..e7e16098 100644 --- a/src/chip/sdd1/sdd1.cpp +++ b/src/chip/sdd1/sdd1.cpp @@ -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) { diff --git a/src/chip/sdd1/sdd1emu.cpp b/src/chip/sdd1/sdd1emu.cpp index c98506ee..fdb6aaca 100644 --- a/src/chip/sdd1/sdd1emu.cpp +++ b/src/chip/sdd1/sdd1emu.cpp @@ -28,7 +28,7 @@ understood. ************************************************************************/ -#define SDD1_read(__addr) (mem_bus->read(__addr)) +#define SDD1_read(__addr) (r_mem->read(__addr)) //////////////////////////////////////////////////// diff --git a/src/chip/srtc/srtc.cpp b/src/chip/srtc/srtc.cpp index 590037ab..aa59e006 100644 --- a/src/chip/srtc/srtc.cpp +++ b/src/chip/srtc/srtc.cpp @@ -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) { diff --git a/src/cpu/bcpu/bcpu.cpp b/src/cpu/bcpu/bcpu.cpp index 3d92c2aa..f6706b49 100644 --- a/src/cpu/bcpu/bcpu.cpp +++ b/src/cpu/bcpu/bcpu.cpp @@ -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) { diff --git a/src/cpu/bcpu/bcpu_dma.cpp b/src/cpu/bcpu/bcpu_dma.cpp index dc9ccbc0..2fad96eb 100644 --- a/src/cpu/bcpu/bcpu_dma.cpp +++ b/src/cpu/bcpu/bcpu_dma.cpp @@ -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); } diff --git a/src/cpu/bcpu/bcpu_exec.cpp b/src/cpu/bcpu/bcpu_exec.cpp index e0eb9b40..6a961442 100644 --- a/src/cpu/bcpu/bcpu_exec.cpp +++ b/src/cpu/bcpu/bcpu_exec.cpp @@ -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 diff --git a/src/cpu/bcpu/bcpu_int.cpp b/src/cpu/bcpu/bcpu_int.cpp index 9f47c88d..88336745 100644 --- a/src/cpu/bcpu/bcpu_int.cpp +++ b/src/cpu/bcpu/bcpu_int.cpp @@ -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; diff --git a/src/cpu/bcpu/bcpu_mmio.cpp b/src/cpu/bcpu/bcpu_mmio.cpp index fbcb0349..8d833cbe 100644 --- a/src/cpu/bcpu/bcpu_mmio.cpp +++ b/src/cpu/bcpu/bcpu_mmio.cpp @@ -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 diff --git a/src/cpu/bcpu/bcpu_timing.cpp b/src/cpu/bcpu/bcpu_timing.cpp index 93eed40e..2ca28391 100644 --- a/src/cpu/bcpu/bcpu_timing.cpp +++ b/src/cpu/bcpu/bcpu_timing.cpp @@ -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(); } } diff --git a/src/cpu/bcpu/bcpu_timing.h b/src/cpu/bcpu/bcpu_timing.h index bb70a3de..71a5e677 100644 --- a/src/cpu/bcpu/bcpu_timing.h +++ b/src/cpu/bcpu/bcpu_timing.h @@ -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(); diff --git a/src/cpu/cpuregs.h b/src/cpu/cpuregs.h index 8d6447bd..bf5207cb 100644 --- a/src/cpu/cpuregs.h +++ b/src/cpu/cpuregs.h @@ -41,7 +41,7 @@ union { struct { uint8 l, h; }; #else struct { uint8 h, l; }; -#endif; +#endif }; CPUReg16() { w = 0; } diff --git a/src/cpu/dcpu.cpp b/src/cpu/dcpu.cpp index be6896d0..8a3952ae 100644 --- a/src/cpu/dcpu.cpp +++ b/src/cpu/dcpu.cpp @@ -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; diff --git a/src/dsp/bdsp/bdsp.cpp b/src/dsp/bdsp/bdsp.cpp index d973ce81..18a91872 100644 --- a/src/dsp/bdsp/bdsp.cpp +++ b/src/dsp/bdsp/bdsp.cpp @@ -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++) { diff --git a/src/interface.h b/src/interface.h index b8729189..28fc434a 100644 --- a/src/interface.h +++ b/src/interface.h @@ -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 diff --git a/src/lib/libconfig.cpp b/src/lib/libconfig.cpp index 949e7c47..f772619e 100644 --- a/src/lib/libconfig.cpp +++ b/src/lib/libconfig.cpp @@ -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) { diff --git a/src/memory/bmemory/bmemory.cpp b/src/memory/bmemory/bmemory.cpp index 010459a3..de003674 100644 --- a/src/memory/bmemory/bmemory.cpp +++ b/src/memory/bmemory/bmemory.cpp @@ -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() { diff --git a/src/memory/memory.cpp b/src/memory/memory.cpp index ed894abd..c305ac2d 100644 --- a/src/memory/memory.cpp +++ b/src/memory/memory.cpp @@ -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; diff --git a/src/memory/memory.h b/src/memory/memory.h index 01424c13..7c195169 100644 --- a/src/memory/memory.h +++ b/src/memory/memory.h @@ -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; diff --git a/src/ppu/bppu/Copy of bppu_render_addsub.cpp b/src/ppu/bppu/Copy of bppu_render_addsub.cpp new file mode 100644 index 00000000..2a216632 --- /dev/null +++ b/src/ppu/bppu/Copy of bppu_render_addsub.cpp @@ -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; + } +} diff --git a/src/ppu/bppu/Copy of bppu_render_line.cpp b/src/ppu/bppu/Copy of bppu_render_line.cpp new file mode 100644 index 00000000..58ac93f8 --- /dev/null +++ b/src/ppu/bppu/Copy of bppu_render_line.cpp @@ -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 +//t = BBGGGRRR +//r = 0BBb00GGGg0RRRr0 + 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); + } + } +} diff --git a/src/ppu/bppu/bppu.cpp b/src/ppu/bppu/bppu.cpp index e67a663f..b0d1af9b 100644 --- a/src/ppu/bppu/bppu.cpp +++ b/src/ppu/bppu/bppu.cpp @@ -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() { diff --git a/src/ppu/bppu/bppu.h b/src/ppu/bppu/bppu.h index ce4956c3..6223b8db 100644 --- a/src/ppu/bppu/bppu.h +++ b/src/ppu/bppu/bppu.h @@ -127,6 +127,7 @@ struct { //$2132 uint8 color_r, color_g, color_b; + uint16 color_rgb; //$2133 bool mode7_extbg; diff --git a/src/ppu/bppu/bppu_mmio.cpp b/src/ppu/bppu/bppu_mmio.cpp index 0bb916bd..fcd3ddbb 100644 --- a/src/ppu/bppu/bppu_mmio.cpp +++ b/src/ppu/bppu/bppu_mmio.cpp @@ -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) { diff --git a/src/ppu/bppu/bppu_render.cpp b/src/ppu/bppu/bppu_render.cpp index 05618f3f..8edac47c 100644 --- a/src/ppu/bppu/bppu_render.cpp +++ b/src/ppu/bppu/bppu_render.cpp @@ -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; } diff --git a/src/ppu/bppu/bppu_render.h b/src/ppu/bppu/bppu_render.h index 5143f21d..0e9b3c24 100644 --- a/src/ppu/bppu/bppu_render.h +++ b/src/ppu/bppu/bppu_render.h @@ -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(); diff --git a/src/ppu/bppu/bppu_render_addsub.cpp b/src/ppu/bppu/bppu_render_addsub.cpp index 43bea198..835d4d8a 100644 --- a/src/ppu/bppu/bppu_render_addsub.cpp +++ b/src/ppu/bppu/bppu_render_addsub.cpp @@ -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 } diff --git a/src/ppu/bppu/bppu_render_bg.cpp b/src/ppu/bppu/bppu_render_bg.cpp index 87c54b5c..9b0bd8d6 100644 --- a/src/ppu/bppu/bppu_render_bg.cpp +++ b/src/ppu/bppu/bppu_render_bg.cpp @@ -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 { diff --git a/src/ppu/bppu/bppu_render_cache.cpp b/src/ppu/bppu/bppu_render_cache.cpp index aa57f3cf..0557f711 100644 --- a/src/ppu/bppu/bppu_render_cache.cpp +++ b/src/ppu/bppu/bppu_render_cache.cpp @@ -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); diff --git a/src/ppu/bppu/bppu_render_line.cpp b/src/ppu/bppu/bppu_render_line.cpp index 6293c76c..3e254660 100644 --- a/src/ppu/bppu/bppu_render_line.cpp +++ b/src/ppu/bppu/bppu_render_line.cpp @@ -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); } } } diff --git a/src/ppu/bppu/bppu_render_mode7.cpp b/src/ppu/bppu/bppu_render_mode7.cpp index 4c9f7d2a..6e0797eb 100644 --- a/src/ppu/bppu/bppu_render_mode7.cpp +++ b/src/ppu/bppu/bppu_render_mode7.cpp @@ -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; } } } diff --git a/src/ppu/bppu/bppu_render_oam.cpp b/src/ppu/bppu/bppu_render_oam.cpp index e6a3b0db..a1177b40 100644 --- a/src/ppu/bppu/bppu_render_oam.cpp +++ b/src/ppu/bppu/bppu_render_oam.cpp @@ -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= 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;xhires = 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); +} diff --git a/src/ppu/ppu.h b/src/ppu/ppu.h index 7065473d..6def0e52 100644 --- a/src/ppu/ppu.h +++ b/src/ppu/ppu.h @@ -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(); diff --git a/src/sdl/Makefile b/src/sdl/Makefile index 16b9d601..c80c0168 100644 --- a/src/sdl/Makefile +++ b/src/sdl/Makefile @@ -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 ### ########### diff --git a/src/sdl/Makefile.win32 b/src/sdl/Makefile.win32 index 1bc07ca4..3f83052b 100644 --- a/src/sdl/Makefile.win32 +++ b/src/sdl/Makefile.win32 @@ -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 ### ########### diff --git a/src/sdl/bsnes.cpp b/src/sdl/bsnes.cpp index 1c2482b0..11188844 100644 --- a/src/sdl/bsnes.cpp +++ b/src/sdl/bsnes.cpp @@ -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; } diff --git a/src/sdl/bsnes.h b/src/sdl/bsnes.h index de5af083..74a08e18 100644 --- a/src/sdl/bsnes.h +++ b/src/sdl/bsnes.h @@ -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); diff --git a/src/sdl/clean.bat b/src/sdl/clean.bat index 81715981..74d64470 100644 --- a/src/sdl/clean.bat +++ b/src/sdl/clean.bat @@ -1 +1,3 @@ @nmake /NOLOGO /f Makefile.win32 clean +@del output.wav +@del bsnes_sdl.exe diff --git a/src/sdl/render.cpp b/src/sdl/render.cpp index 38d4da84..9848f18a 100644 --- a/src/sdl/render.cpp +++ b/src/sdl/render.cpp @@ -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); } diff --git a/src/sdl/rom.cpp b/src/sdl/rom.cpp index f5beae7a..46897fcb 100644 --- a/src/sdl/rom.cpp +++ b/src/sdl/rom.cpp @@ -27,14 +27,14 @@ FileReader *rf = new FileReader(); alert("Error loading image file [%s]!", rom_fn); return false; } - mem_bus->load_cart(static_cast(rf)); + r_mem->load_cart(static_cast(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(rf)); + r_mem->load_sram(static_cast(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(wf)); + r_mem->save_sram(static_cast(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; diff --git a/src/sdl/sdlmain.cpp b/src/sdl/sdlmain.cpp index 76d69354..d371da97 100644 --- a/src/sdl/sdlmain.cpp +++ b/src/sdl/sdlmain.cpp @@ -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(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(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(mem_bus)); mem_bus = 0; } - if(cpu) { delete(static_cast (cpu)); cpu = 0; } - if(apu) { delete(static_cast (apu)); apu = 0; } - if(ppu) { delete(static_cast (ppu)); ppu = 0; } - if(snes) { delete(static_cast (snes)); snes = 0; } +#ifdef POLYMORPHISM + if(deref(mem)) { delete static_cast(deref(mem)); deref(mem) = 0; } + if(deref(cpu)) { delete static_cast (deref(cpu)); deref(cpu) = 0; } + if(deref(apu)) { delete static_cast (deref(apu)); deref(apu) = 0; } + if(deref(dsp)) { delete static_cast (deref(dsp)); deref(dsp) = 0; } + if(deref(ppu)) { delete static_cast (deref(ppu)); deref(ppu) = 0; } +#endif + if(snes) { delete(static_cast(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 diff --git a/src/snes/snes.cpp b/src/snes/snes.cpp index 9370b905..04ca776e 100644 --- a/src/snes/snes.cpp +++ b/src/snes/snes.cpp @@ -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; } diff --git a/src/snes/snes.h b/src/snes/snes.h index 4524c304..db2a31f5 100644 --- a/src/snes/snes.h +++ b/src/snes/snes.h @@ -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, diff --git a/src/snes/snes_audio.cpp b/src/snes/snes_audio.cpp index 5f10e603..eb2787e2 100644 --- a/src/snes/snes_audio.cpp +++ b/src/snes/snes_audio.cpp @@ -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) { diff --git a/src/snes/snes_audio.h b/src/snes/snes_audio.h index 4ba04c88..1442e57c 100644 --- a/src/snes/snes_audio.h +++ b/src/snes/snes_audio.h @@ -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; diff --git a/src/snes/snes_video.cpp b/src/snes/snes_video.cpp index eb79e5f6..dbdd1bc7 100644 --- a/src/snes/snes_video.cpp +++ b/src/snes/snes_video.cpp @@ -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; diff --git a/src/snes/snes_video.h b/src/snes/snes_video.h index df89b25d..02c1eb73 100644 --- a/src/snes/snes_video.h +++ b/src/snes/snes_video.h @@ -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(); diff --git a/src/snes/snes_video_ex.cpp b/src/snes/snes_video_ex.cpp index 7a899f72..4de1eada 100644 --- a/src/snes/snes_video_ex.cpp +++ b/src/snes/snes_video_ex.cpp @@ -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> 8, fp); } diff --git a/src/win/Makefile b/src/win/Makefile index e4e01a22..ec12082c 100644 --- a/src/win/Makefile +++ b/src/win/Makefile @@ -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 ### ########### diff --git a/src/win/bsnes.cpp b/src/win/bsnes.cpp index 18c54999..826e1128 100644 --- a/src/win/bsnes.cpp +++ b/src/win/bsnes.cpp @@ -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(); } diff --git a/src/win/bsnes.h b/src/win/bsnes.h index d0f3340a..054246ca 100644 --- a/src/win/bsnes.h +++ b/src/win/bsnes.h @@ -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); diff --git a/src/win/bsnes.lnk b/src/win/bsnes.lnk index ce73821e..b3f084ab 100644 Binary files a/src/win/bsnes.lnk and b/src/win/bsnes.lnk differ diff --git a/src/win/config.cpp b/src/win/config.cpp index c0a92860..8d238f06 100644 --- a/src/win/config.cpp +++ b/src/win/config.cpp @@ -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; diff --git a/src/win/dd_renderer.cpp b/src/win/dd_renderer.cpp index 47fae633..7dc31009 100644 --- a/src/win/dd_renderer.cpp +++ b/src/win/dd_renderer.cpp @@ -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(); } diff --git a/src/win/dd_renderer.h b/src/win/dd_renderer.h index b98127ec..626dc373 100644 --- a/src/win/dd_renderer.h +++ b/src/win/dd_renderer.h @@ -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(); diff --git a/src/win/dd_renderer16.cpp b/src/win/dd_renderer16.cpp deleted file mode 100644 index 6a4fef80..00000000 --- a/src/win/dd_renderer16.cpp +++ /dev/null @@ -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; - } -} diff --git a/src/win/dd_renderer32.cpp b/src/win/dd_renderer32.cpp deleted file mode 100644 index 6b4893ea..00000000 --- a/src/win/dd_renderer32.cpp +++ /dev/null @@ -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; - } - } -} diff --git a/src/win/ds_sound.cpp b/src/win/ds_sound.cpp index ab6862e8..25af846e 100644 --- a/src/win/ds_sound.cpp +++ b/src/win/ds_sound.cpp @@ -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; + } } diff --git a/src/win/ds_sound.h b/src/win/ds_sound.h index d580facb..4e2f9f5d 100644 --- a/src/win/ds_sound.h +++ b/src/win/ds_sound.h @@ -1,30 +1,28 @@ #include +#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; diff --git a/src/win/rom.cpp b/src/win/rom.cpp index e2a33fb5..7057affd 100644 --- a/src/win/rom.cpp +++ b/src/win/rom.cpp @@ -27,14 +27,14 @@ FileReader *rf = new FileReader(); alert("Error loading image file [%s]!", rom_fn); return false; } - mem_bus->load_cart(static_cast(rf)); + r_mem->load_cart(static_cast(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(rf)); + r_mem->load_sram(static_cast(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(wf)); + r_mem->save_sram(static_cast(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) { diff --git a/src/win/ui.cpp b/src/win/ui.cpp index 46ae9c34..d48ca202 100644 --- a/src/win/ui.cpp +++ b/src/win/ui.cpp @@ -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); diff --git a/src/win/ui.h b/src/win/ui.h index 9619a420..8ca69fc5 100644 --- a/src/win/ui.h +++ b/src/win/ui.h @@ -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 { diff --git a/src/win/ui_console.cpp b/src/win/ui_console.cpp index 52cf61fc..09b01dd0 100644 --- a/src/win/ui_console.cpp +++ b/src/win/ui_console.cpp @@ -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;iwrite(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); } diff --git a/src/win/ui_main.cpp b/src/win/ui_main.cpp index 0ad3aca6..142aa3cd 100644 --- a/src/win/ui_main.cpp +++ b/src/win/ui_main.cpp @@ -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); diff --git a/src/win/ui_memory.cpp b/src/win/ui_memory.cpp index 380d9fef..a877778b 100644 --- a/src/win/ui_memory.cpp +++ b/src/win/ui_memory.cpp @@ -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); } } diff --git a/src/win/winmain.cpp b/src/win/winmain.cpp index 7778e009..45d8f349 100644 --- a/src/win/winmain.cpp +++ b/src/win/winmain.cpp @@ -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(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(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(mem_bus)); - mem_bus = 0; + if(deref(mem)) { + delete static_cast(deref(mem)); + deref(mem) = 0; } - if(cpu) { - delete(static_cast(cpu)); - cpu = 0; + if(deref(cpu)) { + delete static_cast(deref(cpu)); + deref(cpu) = 0; } - if(apu) { - delete(static_cast(apu)); - apu = 0; + if(deref(apu)) { + delete static_cast(deref(apu)); + deref(apu) = 0; } - if(dsp) { - delete(static_cast(dsp)); - dsp = 0; + if(deref(dsp)) { + delete static_cast(deref(dsp)); + deref(dsp) = 0; } - if(ppu) { - delete(static_cast(ppu)); - ppu = 0; + if(deref(ppu)) { + delete static_cast(deref(ppu)); + deref(ppu) = 0; } +#endif if(snes) { - delete(static_cast(snes)); + delete static_cast(snes); snes = 0; } }