diff --git a/apu/SNES_SPC.cpp b/apu/SNES_SPC.cpp deleted file mode 100644 index 567b7ddc..00000000 --- a/apu/SNES_SPC.cpp +++ /dev/null @@ -1,564 +0,0 @@ -// Core SPC emulation: CPU, timers, SMP registers, memory - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - -// Note: SPC_MORE_ACCURACY exists mainly so I can run my validation tests, which -// do crazy echo buffer accesses. -#ifndef SPC_MORE_ACCURACY - #define SPC_MORE_ACCURACY 0 -#endif - -#ifdef BLARGG_ENABLE_OPTIMIZER - #include BLARGG_ENABLE_OPTIMIZER -#endif - - -//// Timers - -#if SPC_DISABLE_TEMPO - #define TIMER_DIV( t, n ) ((n) >> t->prescaler) - #define TIMER_MUL( t, n ) ((n) << t->prescaler) -#else - #define TIMER_DIV( t, n ) ((n) / t->prescaler) - #define TIMER_MUL( t, n ) ((n) * t->prescaler) -#endif - -SNES_SPC::Timer* SNES_SPC::run_timer_( Timer* t, rel_time_t time ) -{ - int elapsed = TIMER_DIV( t, time - t->next_time ) + 1; - t->next_time += TIMER_MUL( t, elapsed ); - - if ( t->enabled ) - { - int remain = IF_0_THEN_256( t->period - t->divider ); - int divider = t->divider + elapsed; - int over = elapsed - remain; - if ( over >= 0 ) - { - int n = over / t->period; - t->counter = (t->counter + 1 + n) & 0x0F; - divider = over - n * t->period; - } - t->divider = (uint8_t) divider; - } - return t; -} - -inline SNES_SPC::Timer* SNES_SPC::run_timer( Timer* t, rel_time_t time ) -{ - if ( time >= t->next_time ) - t = run_timer_( t, time ); - return t; -} - - -//// ROM - -void SNES_SPC::enable_rom( int enable ) -{ - if ( m.rom_enabled != enable ) - { - m.rom_enabled = dsp.rom_enabled = enable; - if ( enable ) - memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram ); - memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size ); - // TODO: ROM can still get overwritten when DSP writes to echo buffer - } -} - - -//// DSP - -#if SPC_LESS_ACCURATE - int const max_reg_time = 29; - - signed char const SNES_SPC::reg_times_ [256] = - { - -1, 0,-11,-10,-15,-11, -2, -2, 4, 3, 14, 14, 26, 26, 14, 22, - 2, 3, 0, 1,-12, 0, 1, 1, 7, 6, 14, 14, 27, 14, 14, 23, - 5, 6, 3, 4, -1, 3, 4, 4, 10, 9, 14, 14, 26, -5, 14, 23, - 8, 9, 6, 7, 2, 6, 7, 7, 13, 12, 14, 14, 27, -4, 14, 24, - 11, 12, 9, 10, 5, 9, 10, 10, 16, 15, 14, 14, -2, -4, 14, 24, - 14, 15, 12, 13, 8, 12, 13, 13, 19, 18, 14, 14, -2,-36, 14, 24, - 17, 18, 15, 16, 11, 15, 16, 16, 22, 21, 14, 14, 28, -3, 14, 25, - 20, 21, 18, 19, 14, 18, 19, 19, 25, 24, 14, 14, 14, 29, 14, 25, - - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - }; - - #define RUN_DSP( time, offset ) \ - int count = (time) - (offset) - m.dsp_time;\ - if ( count >= 0 )\ - {\ - int clock_count = (count & ~(clocks_per_sample - 1)) + clocks_per_sample;\ - m.dsp_time += clock_count;\ - dsp.run( clock_count );\ - } -#else - #define RUN_DSP( time, offset ) \ - {\ - int count = (time) - m.dsp_time;\ - if ( !SPC_MORE_ACCURACY || count )\ - {\ - assert( count > 0 );\ - m.dsp_time = (time);\ - dsp.run( count );\ - }\ - } -#endif - -int SNES_SPC::dsp_read( rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr] & 0x7F] ); - - int result = dsp.read( REGS [r_dspaddr] & 0x7F ); - - #ifdef SPC_DSP_READ_HOOK - SPC_DSP_READ_HOOK( spc_time + time, (REGS [r_dspaddr] & 0x7F), result ); - #endif - - return result; -} - -inline void SNES_SPC::dsp_write( int data, rel_time_t time ) -{ - RUN_DSP( time, reg_times [REGS [r_dspaddr]] ) - #if SPC_LESS_ACCURATE - else if ( m.dsp_time == skipping_time ) - { - int r = REGS [r_dspaddr]; - if ( r == SPC_DSP::r_kon ) - m.skipped_kon |= data & ~dsp.read( SPC_DSP::r_koff ); - - if ( r == SPC_DSP::r_koff ) - { - m.skipped_koff |= data; - m.skipped_kon &= ~data; - } - } - #endif - - #ifdef SPC_DSP_WRITE_HOOK - SPC_DSP_WRITE_HOOK( m.spc_time + time, REGS [r_dspaddr], (uint8_t) data ); - #endif - - if ( REGS [r_dspaddr] <= 0x7F ) - dsp.write( REGS [r_dspaddr], data ); - else if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to DSP register > $7F\n" ); -} - - -//// Memory access extras - -#if SPC_MORE_ACCURACY - #define MEM_ACCESS( time, addr ) \ - {\ - if ( time >= m.dsp_time )\ - {\ - RUN_DSP( time, max_reg_time );\ - }\ - } -#elif !defined (NDEBUG) - // Debug-only check for read/write within echo buffer, since this might result in - // inaccurate emulation due to the DSP not being caught up to the present. - - bool SNES_SPC::check_echo_access( int addr ) - { - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int start = 0x100 * dsp.read( SPC_DSP::r_esa ); - int size = 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - int end = start + (size ? size : 4); - if ( start <= addr && addr < end ) - { - if ( !m.echo_accessed ) - { - m.echo_accessed = 1; - return true; - } - } - } - return false; - } - - #define MEM_ACCESS( time, addr ) check( !check_echo_access( (uint16_t) addr ) ); -#else - #define MEM_ACCESS( time, addr ) -#endif - - -//// CPU write - -#if SPC_MORE_ACCURACY -static unsigned char const glitch_probs [3] [256] = -{ - 0xC3,0x92,0x5B,0x1C,0xD1,0x92,0x5B,0x1C,0xDB,0x9C,0x72,0x18,0xCD,0x5C,0x38,0x0B, - 0xE1,0x9C,0x74,0x17,0xCF,0x75,0x45,0x0C,0xCF,0x6E,0x4A,0x0D,0xA3,0x3A,0x1D,0x08, - 0xDB,0xA0,0x82,0x19,0xD9,0x73,0x3C,0x0E,0xCB,0x76,0x52,0x0B,0xA5,0x46,0x1D,0x09, - 0xDA,0x74,0x55,0x0F,0xA2,0x3F,0x21,0x05,0x9A,0x40,0x20,0x07,0x63,0x1E,0x10,0x01, - 0xDF,0xA9,0x85,0x1D,0xD3,0x84,0x4B,0x0E,0xCF,0x6F,0x49,0x0F,0xB3,0x48,0x1E,0x05, - 0xD8,0x77,0x52,0x12,0xB7,0x49,0x23,0x06,0xAA,0x45,0x28,0x07,0x7D,0x28,0x0F,0x07, - 0xCC,0x7B,0x4A,0x0E,0xB2,0x4F,0x24,0x07,0xAD,0x43,0x2C,0x06,0x86,0x29,0x11,0x07, - 0xAE,0x48,0x1F,0x0A,0x76,0x21,0x19,0x05,0x76,0x21,0x14,0x05,0x44,0x11,0x0B,0x01, - 0xE7,0xAD,0x96,0x23,0xDC,0x86,0x59,0x0E,0xDC,0x7C,0x5F,0x15,0xBB,0x53,0x2E,0x09, - 0xD6,0x7C,0x4A,0x16,0xBB,0x4A,0x25,0x08,0xB3,0x4F,0x28,0x0B,0x8E,0x23,0x15,0x08, - 0xCF,0x7F,0x57,0x11,0xB5,0x4A,0x23,0x0A,0xAA,0x42,0x28,0x05,0x7D,0x22,0x12,0x03, - 0xA6,0x49,0x28,0x09,0x82,0x2B,0x0D,0x04,0x7A,0x20,0x0F,0x04,0x3D,0x0F,0x09,0x03, - 0xD1,0x7C,0x4C,0x0F,0xAF,0x4E,0x21,0x09,0xA8,0x46,0x2A,0x07,0x85,0x1F,0x0E,0x07, - 0xA6,0x3F,0x26,0x07,0x7C,0x24,0x14,0x07,0x78,0x22,0x16,0x04,0x46,0x12,0x0A,0x02, - 0xA6,0x41,0x2C,0x0A,0x7E,0x28,0x11,0x05,0x73,0x1B,0x14,0x05,0x3D,0x11,0x0A,0x02, - 0x70,0x22,0x17,0x05,0x48,0x13,0x08,0x03,0x3C,0x07,0x0D,0x07,0x26,0x07,0x06,0x01, - - 0xE0,0x9F,0xDA,0x7C,0x4F,0x18,0x28,0x0D,0xE9,0x9F,0xDA,0x7C,0x4F,0x18,0x1F,0x07, - 0xE6,0x97,0xD8,0x72,0x64,0x13,0x26,0x09,0xDC,0x67,0xA9,0x38,0x21,0x07,0x15,0x06, - 0xE9,0x91,0xD2,0x6B,0x63,0x14,0x2B,0x0E,0xD6,0x61,0xB7,0x41,0x2B,0x0E,0x10,0x09, - 0xCF,0x59,0xB0,0x2F,0x35,0x08,0x0F,0x07,0xB6,0x30,0x7A,0x21,0x17,0x07,0x09,0x03, - 0xE7,0xA3,0xE5,0x6B,0x65,0x1F,0x34,0x09,0xD8,0x6B,0xBE,0x45,0x27,0x07,0x10,0x07, - 0xDA,0x54,0xB1,0x39,0x2E,0x0E,0x17,0x08,0xA9,0x3C,0x86,0x22,0x16,0x06,0x07,0x03, - 0xD4,0x51,0xBC,0x3D,0x38,0x0A,0x13,0x06,0xB2,0x37,0x79,0x1C,0x17,0x05,0x0E,0x06, - 0xA7,0x31,0x74,0x1C,0x11,0x06,0x0C,0x02,0x6D,0x1A,0x38,0x10,0x0B,0x05,0x06,0x03, - 0xEB,0x9A,0xE1,0x7A,0x6F,0x13,0x34,0x0E,0xE6,0x75,0xC5,0x45,0x3E,0x0B,0x1A,0x05, - 0xD8,0x63,0xC1,0x40,0x3C,0x1B,0x19,0x06,0xB3,0x42,0x83,0x29,0x18,0x0A,0x08,0x04, - 0xD4,0x58,0xBA,0x43,0x3F,0x0A,0x1F,0x09,0xB1,0x33,0x8A,0x1F,0x1F,0x06,0x0D,0x05, - 0xAF,0x3C,0x7A,0x1F,0x16,0x08,0x0A,0x01,0x72,0x1B,0x52,0x0D,0x0B,0x09,0x06,0x01, - 0xCF,0x63,0xB7,0x47,0x40,0x10,0x14,0x06,0xC0,0x41,0x96,0x20,0x1C,0x09,0x10,0x05, - 0xA6,0x35,0x82,0x1A,0x20,0x0C,0x0E,0x04,0x80,0x1F,0x53,0x0F,0x0B,0x02,0x06,0x01, - 0xA6,0x31,0x81,0x1B,0x1D,0x01,0x08,0x08,0x7B,0x20,0x4D,0x19,0x0E,0x05,0x07,0x03, - 0x6B,0x17,0x49,0x07,0x0E,0x03,0x0A,0x05,0x37,0x0B,0x1F,0x06,0x04,0x02,0x07,0x01, - - 0xF0,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x47,0x1E,0x6E,0x1B,0x32,0x0A, - 0xF0,0xD6,0xEA,0xA4,0xED,0xC4,0xDE,0x82,0x98,0x1F,0x50,0x13,0x52,0x15,0x2A,0x0A, - 0xF1,0xD1,0xEB,0xA2,0xEB,0xB7,0xD8,0x69,0xA2,0x1F,0x5B,0x18,0x55,0x18,0x2C,0x0A, - 0xED,0xB5,0xDE,0x7E,0xE6,0x85,0xD3,0x59,0x59,0x0F,0x2C,0x09,0x24,0x07,0x15,0x09, - 0xF1,0xD6,0xEA,0xA0,0xEC,0xBB,0xDA,0x77,0xA9,0x23,0x58,0x14,0x5D,0x12,0x2F,0x09, - 0xF1,0xC1,0xE3,0x86,0xE4,0x87,0xD2,0x4E,0x68,0x15,0x26,0x0B,0x27,0x09,0x15,0x02, - 0xEE,0xA6,0xE0,0x5C,0xE0,0x77,0xC3,0x41,0x67,0x1B,0x3C,0x07,0x2A,0x06,0x19,0x07, - 0xE4,0x75,0xC6,0x43,0xCC,0x50,0x95,0x23,0x35,0x09,0x14,0x04,0x15,0x05,0x0B,0x04, - 0xEE,0xD6,0xED,0xAD,0xEC,0xB1,0xEB,0x79,0xAC,0x22,0x56,0x14,0x5A,0x12,0x26,0x0A, - 0xEE,0xBB,0xE7,0x7E,0xE9,0x8D,0xCB,0x49,0x67,0x11,0x34,0x07,0x2B,0x0B,0x14,0x07, - 0xED,0xA7,0xE5,0x76,0xE3,0x7E,0xC4,0x4B,0x77,0x14,0x34,0x08,0x27,0x07,0x14,0x04, - 0xE7,0x8B,0xD2,0x4C,0xCA,0x56,0x9E,0x31,0x36,0x0C,0x11,0x07,0x14,0x04,0x0A,0x02, - 0xF0,0x9B,0xEA,0x6F,0xE5,0x81,0xC4,0x43,0x74,0x10,0x30,0x0B,0x2D,0x08,0x1B,0x06, - 0xE6,0x83,0xCA,0x48,0xD9,0x56,0xA7,0x23,0x3B,0x09,0x12,0x09,0x15,0x07,0x0A,0x03, - 0xE5,0x5F,0xCB,0x3C,0xCF,0x48,0x91,0x22,0x31,0x0A,0x17,0x08,0x15,0x04,0x0D,0x02, - 0xD1,0x43,0x91,0x20,0xA9,0x2D,0x54,0x12,0x17,0x07,0x09,0x02,0x0C,0x04,0x05,0x03, -}; -#endif - -// divided into multiple functions to keep rarely-used functionality separate -// so often-used functionality can be optimized better by compiler - -// If write isn't preceded by read, data has this added to it -int const no_read_before_write = 0x2000; - -void SNES_SPC::cpu_write_smp_reg_( int data, rel_time_t time, int addr ) -{ - switch ( addr ) - { - case r_t0target: - case r_t1target: - case r_t2target: { - Timer* t = &m.timers [addr - r_t0target]; - int period = IF_0_THEN_256( data ); - if ( t->period != period ) - { - t = run_timer( t, time ); - #if SPC_MORE_ACCURACY - // Insane behavior when target is written just after counter is - // clocked and counter matches new period and new period isn't 1, 2, 4, or 8 - if ( t->divider == (period & 0xFF) && - t->next_time == time + TIMER_MUL( t, 1 ) && - ((period - 1) | ~0x0F) & period ) - { - //dprintf( "SPC pathological timer target write\n" ); - - // If the period is 3, 5, or 9, there's a probability this behavior won't occur, - // based on the previous period - int prob = 0xFF; - int old_period = t->period & 0xFF; - if ( period == 3 ) prob = glitch_probs [0] [old_period]; - if ( period == 5 ) prob = glitch_probs [1] [old_period]; - if ( period == 9 ) prob = glitch_probs [2] [old_period]; - - // The glitch suppresses incrementing of one of the counter bits, based on - // the lowest set bit in the new period - int b = 1; - while ( !(period & b) ) - b <<= 1; - - if ( (rand() >> 4 & 0xFF) <= prob ) - t->divider = (t->divider - b) & 0xFF; - } - #endif - t->period = period; - } - break; - } - - case r_t0out: - case r_t1out: - case r_t2out: - if ( !SPC_MORE_ACCURACY ) - dprintf( "SPC wrote to counter %d\n", (int) addr - r_t0out ); - - if ( data < no_read_before_write / 2 ) - run_timer( &m.timers [addr - r_t0out], time - 1 )->counter = 0; - break; - - // Registers that act like RAM - case 0x8: - case 0x9: - REGS_IN [addr] = (uint8_t) data; - break; - - case r_test: - if ( (uint8_t) data != 0x0A ) - dprintf( "SPC wrote to test register\n" ); - break; - - case r_control: - // port clears - if ( data & 0x10 ) - { - REGS_IN [r_cpuio0] = 0; - REGS_IN [r_cpuio1] = 0; - } - if ( data & 0x20 ) - { - REGS_IN [r_cpuio2] = 0; - REGS_IN [r_cpuio3] = 0; - } - - // timers - { - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - int enabled = data >> i & 1; - if ( t->enabled != enabled ) - { - t = run_timer( t, time ); - t->enabled = enabled; - if ( enabled ) - { - t->divider = 0; - t->counter = 0; - } - } - } - } - enable_rom( data & 0x80 ); - break; - } -} - -void SNES_SPC::cpu_write_smp_reg( int data, rel_time_t time, int addr ) -{ - if ( addr == r_dspdata ) // 99% - dsp_write( data, time ); - else - cpu_write_smp_reg_( data, time, addr ); -} - -void SNES_SPC::cpu_write_high( int data, int i, rel_time_t time ) -{ - if ( i < rom_size ) - { - m.hi_ram [i] = (uint8_t) data; - if ( m.rom_enabled ) - RAM [i + rom_addr] = m.rom [i]; // restore overwritten ROM - } - else - { - assert( *(&(RAM [0]) + i + rom_addr) == (uint8_t) data ); - *(&(RAM [0]) + i + rom_addr) = cpu_pad_fill; // restore overwritten padding - cpu_write( data, i + rom_addr - 0x10000, time ); - } -} - -int const bits_in_int = CHAR_BIT * sizeof (int); - -void SNES_SPC::cpu_write( int data, int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - RAM [addr] = (uint8_t) data; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 64% - { - // $F0-$FF - if ( reg < reg_count ) // 87% - { - REGS [reg] = (uint8_t) data; - - // Ports - #ifdef SPC_PORT_WRITE_HOOK - if ( (unsigned) (reg - r_cpuio0) < port_count ) - SPC_PORT_WRITE_HOOK( m.spc_time + time, (reg - r_cpuio0), - (uint8_t) data, ®S [r_cpuio0] ); - #endif - - // Registers other than $F2 and $F4-$F7 - //if ( reg != 2 && reg != 4 && reg != 5 && reg != 6 && reg != 7 ) - // TODO: this is a bit on the fragile side - if ( ((~0x2F00 << (bits_in_int - 16)) << reg) < 0 ) // 36% - cpu_write_smp_reg( data, time, reg ); - } - // High mem/address wrap-around - else - { - reg -= rom_addr - 0xF0; - if ( reg >= 0 ) // 1% in IPL ROM area or address wrapped around - cpu_write_high( data, reg, time ); - } - } -} - - -//// CPU read - -inline int SNES_SPC::cpu_read_smp_reg( int reg, rel_time_t time ) -{ - int result = REGS_IN [reg]; - reg -= r_dspaddr; - // DSP addr and data - if ( (unsigned) reg <= 1 ) // 4% 0xF2 and 0xF3 - { - result = REGS [r_dspaddr]; - if ( (unsigned) reg == 1 ) - result = dsp_read( time ); // 0xF3 - } - return result; -} - -int SNES_SPC::cpu_read( int addr, rel_time_t time ) -{ - MEM_ACCESS( time, addr ) - - // RAM - int result = RAM [addr]; - int reg = addr - 0xF0; - if ( reg >= 0 ) // 40% - { - reg -= 0x10; - if ( (unsigned) reg >= 0xFF00 ) // 21% - { - reg += 0x10 - r_t0out; - - // Timers - if ( (unsigned) reg < timer_count ) // 90% - { - Timer* t = &m.timers [reg]; - if ( time >= t->next_time ) - t = run_timer_( t, time ); - result = t->counter; - t->counter = 0; - } - // Other registers - else if ( reg < 0 ) // 10% - { - result = cpu_read_smp_reg( reg + r_t0out, time ); - } - else // 1% - { - assert( reg + (r_t0out + 0xF0 - 0x10000) < 0x100 ); - result = cpu_read( reg + (r_t0out + 0xF0 - 0x10000), time ); - } - } - } - - return result; -} - - -//// Run - -// Prefix and suffix for CPU emulator function -#define SPC_CPU_RUN_FUNC \ -BOOST::uint8_t* SNES_SPC::run_until_( time_t end_time )\ -{\ - rel_time_t rel_time = m.spc_time - end_time;\ - /*assert( rel_time <= 0 );*/\ - m.spc_time = end_time;\ - m.dsp_time += rel_time;\ - m.timers [0].next_time += rel_time;\ - m.timers [1].next_time += rel_time;\ - m.timers [2].next_time += rel_time; - -#define SPC_CPU_RUN_FUNC_END \ - m.spc_time += rel_time;\ - m.dsp_time -= rel_time;\ - m.timers [0].next_time -= rel_time;\ - m.timers [1].next_time -= rel_time;\ - m.timers [2].next_time -= rel_time;\ - /*assert( m.spc_time >= end_time );*/\ - return ®S [r_cpuio0];\ -} - -int const cpu_lag_max = 12 - 1; // DIV YA,X takes 12 clocks - -void SNES_SPC::end_frame( time_t end_time ) -{ - // Catch CPU up to as close to end as possible. If final instruction - // would exceed end, does NOT execute it and leaves m.spc_time < end. - if ( end_time > m.spc_time ) - run_until_( end_time ); - - m.spc_time -= end_time; - m.extra_clocks += end_time; - - // Greatest number of clocks early that emulation can stop early due to - // not being able to execute current instruction without going over - // allowed time. - assert( -cpu_lag_max <= m.spc_time && m.spc_time <= cpu_lag_max ); - - // Catch timers up to CPU - for ( int i = 0; i < timer_count; i++ ) - run_timer( &m.timers [i], 0 ); - - // Catch DSP up to CPU - if ( m.dsp_time < 0 ) - { - RUN_DSP( 0, max_reg_time ); - } - - // Save any extra samples beyond what should be generated - if ( m.buf_begin ) - save_extra(); -} - -// Inclusion here allows static memory access functions and better optimization -#include "SPC_CPU.h" diff --git a/apu/SNES_SPC.h b/apu/SNES_SPC.h deleted file mode 100644 index baf90063..00000000 --- a/apu/SNES_SPC.h +++ /dev/null @@ -1,316 +0,0 @@ -// SNES SPC-700 APU emulator - -// snes_spc 0.9.0 -#ifndef SNES_SPC_H -#define SNES_SPC_H - -#include "SPC_DSP.h" -#include "blargg_endian.h" - -#ifdef DEBUGGER -#include "snes9x.h" -#include "display.h" -#include "debug.h" -#endif - -struct SNES_SPC { -public: - typedef BOOST::uint8_t uint8_t; - - // Must be called once before using - blargg_err_t init(); - - // Sample pairs generated per second - enum { sample_rate = 32000 }; - -// Emulator use - - // Sets IPL ROM data. Library does not include ROM data. Most SPC music files - // don't need ROM, but a full emulator must provide this. - enum { rom_size = 0x40 }; - void init_rom( uint8_t const rom [rom_size] ); - - // Sets destination for output samples - typedef short sample_t; - void set_output( sample_t* out, int out_size ); - - // Number of samples written to output since last set - int sample_count() const; - - // Resets SPC to power-on state. This resets your output buffer, so you must - // call set_output() after this. - void reset(); - - // Emulates pressing reset switch on SNES. This resets your output buffer, so - // you must call set_output() after this. - void soft_reset(); - - // 1024000 SPC clocks per second, sample pair every 32 clocks - typedef int time_t; - enum { clock_rate = 1024000 }; - enum { clocks_per_sample = 32 }; - - // Emulated port read/write at specified time - enum { port_count = 4 }; - int read_port ( time_t, int port ); - void write_port( time_t, int port, int data ); - - // Runs SPC to end_time and starts a new time frame at 0 - void end_frame( time_t end_time ); - -// Sound control - - // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). - // Reduces emulation accuracy. - enum { voice_count = 8 }; - void mute_voices( int mask ); - - // If true, prevents channels and global volumes from being phase-negated. - // Only supported by fast DSP. - void disable_surround( bool disable = true ); - - // Sets tempo, where tempo_unit = normal, tempo_unit / 2 = half speed, etc. - enum { tempo_unit = 0x100 }; - void set_tempo( int ); - -// SPC music files - - // Loads SPC data into emulator - enum { spc_min_file_size = 0x10180 }; - enum { spc_file_size = 0x10200 }; - blargg_err_t load_spc( void const* in, long size ); - - // Clears echo region. Useful after loading an SPC as many have garbage in echo. - void clear_echo(); - - // Plays for count samples and write samples to out. Discards samples if out - // is NULL. Count must be a multiple of 2 since output is stereo. - blargg_err_t play( int count, sample_t* out ); - - // Skips count samples. Several times faster than play() when using fast DSP. - blargg_err_t skip( int count ); - -// State save/load (only available with accurate DSP) - -#if !SPC_NO_COPY_STATE_FUNCS - // Saves/loads state - enum { state_size = 68 * 1024L }; // maximum space needed when saving - typedef SPC_DSP::copy_func_t copy_func_t; - void copy_state( unsigned char** io, copy_func_t ); - - // Writes minimal header to spc_out - static void init_header( void* spc_out ); - - // Saves emulator state as SPC file data. Writes spc_file_size bytes to spc_out. - // Does not set up SPC header; use init_header() for that. - void save_spc( void* spc_out ); - - // Returns true if new key-on events occurred since last check. Useful for - // trimming silence while saving an SPC. - bool check_kon(); -#endif - -//// Snes9x Accessor - - void spc_allow_time_overflow( bool ); - - void dsp_set_spc_snapshot_callback( void (*callback) (void) ); - void dsp_dump_spc_snapshot( void ); - void dsp_set_stereo_switch( int ); - uint8_t dsp_reg_value( int, int ); - int dsp_envx_value( int ); - -//// Snes9x Debugger - -#ifdef DEBUGGER - void debug_toggle_trace( void ); - bool debug_is_enabled( void ); - void debug_do_trace( int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); - void debug_op_print( char *, int, int, int, uint8_t const *, uint8_t *, int, int, int, int ); - void debug_io_print( char * ); -#endif - -public: - BLARGG_DISABLE_NOTHROW - - typedef BOOST::uint16_t uint16_t; - - // Time relative to m_spc_time. Speeds up code a bit by eliminating need to - // constantly add m_spc_time to time from CPU. CPU uses time that ends at - // 0 to eliminate reloading end time every instruction. It pays off. - typedef int rel_time_t; - - struct Timer - { - rel_time_t next_time; // time of next event - int prescaler; - int period; - int divider; - int enabled; - int counter; - }; - enum { reg_count = 0x10 }; - enum { timer_count = 3 }; - enum { extra_size = SPC_DSP::extra_size }; - - enum { signature_size = 35 }; - -private: - SPC_DSP dsp; - - #if SPC_LESS_ACCURATE - static signed char const reg_times_ [256]; - signed char reg_times [256]; - #endif - - struct state_t - { - Timer timers [timer_count]; - - uint8_t smp_regs [2] [reg_count]; - - struct - { - int pc; - int a; - int x; - int y; - int psw; - int sp; - } cpu_regs; - - rel_time_t dsp_time; - time_t spc_time; - bool echo_accessed; - - int tempo; - int skipped_kon; - int skipped_koff; - const char* cpu_error; - - int extra_clocks; - sample_t* buf_begin; - sample_t const* buf_end; - sample_t* extra_pos; - sample_t extra_buf [extra_size]; - - int rom_enabled; - uint8_t rom [rom_size]; - uint8_t hi_ram [rom_size]; - - unsigned char cycle_table [256]; - - struct - { - // padding to neutralize address overflow - union { - uint8_t padding1 [0x100]; - uint16_t align; // makes compiler align data for 16-bit access - } padding1 [1]; - uint8_t ram [0x10000]; - uint8_t padding2 [0x100]; - } ram; - }; - state_t m; - - enum { rom_addr = 0xFFC0 }; - - enum { skipping_time = 127 }; - - // Value that padding should be filled with - enum { cpu_pad_fill = 0xFF }; - - enum { - r_test = 0x0, r_control = 0x1, - r_dspaddr = 0x2, r_dspdata = 0x3, - r_cpuio0 = 0x4, r_cpuio1 = 0x5, - r_cpuio2 = 0x6, r_cpuio3 = 0x7, - r_f8 = 0x8, r_f9 = 0x9, - r_t0target = 0xA, r_t1target = 0xB, r_t2target = 0xC, - r_t0out = 0xD, r_t1out = 0xE, r_t2out = 0xF - }; - - void timers_loaded(); - void enable_rom( int enable ); - void reset_buf(); - void save_extra(); - void load_regs( uint8_t const in [reg_count] ); - void ram_loaded(); - void regs_loaded(); - void reset_time_regs(); - void reset_common( int timer_counter_init ); - - Timer* run_timer_ ( Timer* t, rel_time_t ); - Timer* run_timer ( Timer* t, rel_time_t ); - int dsp_read ( rel_time_t ); - void dsp_write ( int data, rel_time_t ); - void cpu_write_smp_reg_( int data, rel_time_t, int addr ); - void cpu_write_smp_reg ( int data, rel_time_t, int addr ); - void cpu_write_high ( int data, int i, rel_time_t ); - void cpu_write ( int data, int addr, rel_time_t ); - int cpu_read_smp_reg ( int i, rel_time_t ); - int cpu_read ( int addr, rel_time_t ); - unsigned CPU_mem_bit ( uint8_t const* pc, rel_time_t ); - - bool check_echo_access ( int addr ); - uint8_t* run_until_( time_t end_time ); - - struct spc_file_t - { - char signature [signature_size]; - uint8_t has_id666; - uint8_t version; - uint8_t pcl, pch; - uint8_t a; - uint8_t x; - uint8_t y; - uint8_t psw; - uint8_t sp; - char text [212]; - uint8_t ram [0x10000]; - uint8_t dsp [128]; - uint8_t unused [0x40]; - uint8_t ipl_rom [0x40]; - }; - - static char const signature [signature_size + 1]; - - void save_regs( uint8_t out [reg_count] ); - -// Snes9x timing hack - bool allow_time_overflow; -// Snes9x debugger -#ifdef DEBUGGER - FILE *apu_trace; - bool debug_trace; -#endif -}; - -#include - -inline int SNES_SPC::sample_count() const { return (m.extra_clocks >> 5) * 2; } - -inline int SNES_SPC::read_port( time_t t, int port ) -{ - assert( (unsigned) port < port_count ); - return run_until_( t ) [port]; -} - -inline void SNES_SPC::write_port( time_t t, int port, int data ) -{ - assert( (unsigned) port < port_count ); - run_until_( t ) [0x10 + port] = data; - m.ram.ram [0xF4 + port] = data; -} - -inline void SNES_SPC::mute_voices( int mask ) { dsp.mute_voices( mask ); } - -inline void SNES_SPC::disable_surround( bool disable ) { dsp.disable_surround( disable ); } - -#if !SPC_NO_COPY_STATE_FUNCS -inline bool SNES_SPC::check_kon() { return dsp.check_kon(); } -#endif - -inline void SNES_SPC::spc_allow_time_overflow( bool allow ) { allow_time_overflow = allow; } - -#endif diff --git a/apu/SNES_SPC_misc.cpp b/apu/SNES_SPC_misc.cpp deleted file mode 100644 index 078120d2..00000000 --- a/apu/SNES_SPC_misc.cpp +++ /dev/null @@ -1,855 +0,0 @@ -// SPC emulation support: init, sample buffering, reset, SPC loading - -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SNES_SPC.h" - -#include - -/* Copyright (C) 2004-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -// (n ? n : 256) -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) - - -//// Init - -blargg_err_t SNES_SPC::init() -{ - memset( &m, 0, sizeof m ); - dsp.init( RAM ); - - m.tempo = tempo_unit; - - // Most SPC music doesn't need ROM, and almost all the rest only rely - // on these two bytes - m.rom [0x3E] = 0xFF; - m.rom [0x3F] = 0xC0; - - static unsigned char const cycle_table [128] = - {// 01 23 45 67 89 AB CD EF - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x68, // 0 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x46, // 1 - 0x28,0x47,0x34,0x36,0x26,0x54,0x54,0x74, // 2 - 0x48,0x47,0x45,0x56,0x55,0x65,0x22,0x38, // 3 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x66, // 4 - 0x48,0x47,0x45,0x56,0x55,0x45,0x22,0x43, // 5 - 0x28,0x47,0x34,0x36,0x26,0x44,0x54,0x75, // 6 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x36, // 7 - 0x28,0x47,0x34,0x36,0x26,0x54,0x52,0x45, // 8 - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0xC5, // 9 - 0x38,0x47,0x34,0x36,0x26,0x44,0x52,0x44, // A - 0x48,0x47,0x45,0x56,0x55,0x55,0x22,0x34, // B - 0x38,0x47,0x45,0x47,0x25,0x64,0x52,0x49, // C - 0x48,0x47,0x56,0x67,0x45,0x55,0x22,0x83, // D - 0x28,0x47,0x34,0x36,0x24,0x53,0x43,0x40, // E - 0x48,0x47,0x45,0x56,0x34,0x54,0x22,0x60, // F - }; - - // unpack cycle table - for ( int i = 0; i < 128; i++ ) - { - int n = cycle_table [i]; - m.cycle_table [i * 2 + 0] = n >> 4; - m.cycle_table [i * 2 + 1] = n & 0x0F; - } - - allow_time_overflow = false; - - dsp.rom = m.rom; - dsp.hi_ram = m.hi_ram; - -#ifdef DEBUGGER - apu_trace = NULL; - debug_trace = false; -#endif - - #if SPC_LESS_ACCURATE - memcpy( reg_times, reg_times_, sizeof reg_times ); - #endif - - reset(); - return 0; -} - -void SNES_SPC::init_rom( uint8_t const in [rom_size] ) -{ - memcpy( m.rom, in, sizeof m.rom ); -} - -void SNES_SPC::set_tempo( int t ) -{ - m.tempo = t; - int const timer2_shift = 4; // 64 kHz - int const other_shift = 3; // 8 kHz - - #if SPC_DISABLE_TEMPO - m.timers [2].prescaler = timer2_shift; - m.timers [1].prescaler = timer2_shift + other_shift; - m.timers [0].prescaler = timer2_shift + other_shift; - #else - if ( !t ) - t = 1; - int const timer2_rate = 1 << timer2_shift; - int rate = (timer2_rate * tempo_unit + (t >> 1)) / t; - if ( rate < timer2_rate / 4 ) - rate = timer2_rate / 4; // max 4x tempo - m.timers [2].prescaler = rate; - m.timers [1].prescaler = rate << other_shift; - m.timers [0].prescaler = rate << other_shift; - #endif -} - -// Timer registers have been loaded. Applies these to the timers. Does not -// reset timer prescalers or dividers. -void SNES_SPC::timers_loaded() -{ - int i; - for ( i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->period = IF_0_THEN_256( REGS [r_t0target + i] ); - t->enabled = REGS [r_control] >> i & 1; - t->counter = REGS_IN [r_t0out + i] & 0x0F; - } - - set_tempo( m.tempo ); -} - -// Loads registers from unified 16-byte format -void SNES_SPC::load_regs( uint8_t const in [reg_count] ) -{ - memcpy( REGS, in, reg_count ); - memcpy( REGS_IN, REGS, reg_count ); - - // These always read back as 0 - REGS_IN [r_test ] = 0; - REGS_IN [r_control ] = 0; - REGS_IN [r_t0target] = 0; - REGS_IN [r_t1target] = 0; - REGS_IN [r_t2target] = 0; -} - -// RAM was just loaded from SPC, with $F0-$FF containing SMP registers -// and timer counts. Copies these to proper registers. -void SNES_SPC::ram_loaded() -{ - m.rom_enabled = dsp.rom_enabled = 0; - load_regs( &RAM [0xF0] ); - - // Put STOP instruction around memory to catch PC underflow/overflow - memset( m.ram.padding1, cpu_pad_fill, sizeof m.ram.padding1 ); - memset( m.ram.padding2, cpu_pad_fill, sizeof m.ram.padding2 ); -} - -// Registers were just loaded. Applies these new values. -void SNES_SPC::regs_loaded() -{ - enable_rom( REGS [r_control] & 0x80 ); - timers_loaded(); -} - -void SNES_SPC::reset_time_regs() -{ - m.cpu_error = 0; - m.echo_accessed = 0; - m.spc_time = 0; - m.dsp_time = 0; - #if SPC_LESS_ACCURATE - m.dsp_time = clocks_per_sample + 1; - #endif - - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->next_time = 1; - t->divider = 0; - } - - regs_loaded(); - - m.extra_clocks = 0; - reset_buf(); -} - -void SNES_SPC::reset_common( int timer_counter_init ) -{ - int i; - for ( i = 0; i < timer_count; i++ ) - REGS_IN [r_t0out + i] = timer_counter_init; - - // Run IPL ROM - memset( &m.cpu_regs, 0, sizeof m.cpu_regs ); - m.cpu_regs.pc = rom_addr; - - REGS [r_test ] = 0x0A; - REGS [r_control] = 0xB0; // ROM enabled, clear ports - for ( i = 0; i < port_count; i++ ) - REGS_IN [r_cpuio0 + i] = 0; - - reset_time_regs(); -} - -void SNES_SPC::soft_reset() -{ - reset_common( 0 ); - dsp.soft_reset(); -} - -void SNES_SPC::reset() -{ - m.cpu_regs.pc = 0xFFC0; - m.cpu_regs.a = 0x00; - m.cpu_regs.x = 0x00; - m.cpu_regs.y = 0x00; - m.cpu_regs.psw = 0x02; - m.cpu_regs.sp = 0xEF; - memset( RAM, 0x00, 0x10000 ); - ram_loaded(); - reset_common( 0x0F ); - dsp.reset(); -} - -char const SNES_SPC::signature [signature_size + 1] = - "SNES-SPC700 Sound File Data v0.30\x1A\x1A"; - -blargg_err_t SNES_SPC::load_spc( void const* data, long size ) -{ - spc_file_t const* const spc = (spc_file_t const*) data; - - // be sure compiler didn't insert any padding into fle_t - assert( sizeof (spc_file_t) == spc_min_file_size + 0x80 ); - - // Check signature and file size - if ( size < signature_size || memcmp( spc, signature, 27 ) ) - return "Not an SPC file"; - - if ( size < spc_min_file_size ) - return "Corrupt SPC file"; - - // CPU registers - m.cpu_regs.pc = spc->pch * 0x100 + spc->pcl; - m.cpu_regs.a = spc->a; - m.cpu_regs.x = spc->x; - m.cpu_regs.y = spc->y; - m.cpu_regs.psw = spc->psw; - m.cpu_regs.sp = spc->sp; - - // RAM and registers - memcpy( RAM, spc->ram, 0x10000 ); - ram_loaded(); - - // DSP registers - dsp.load( spc->dsp ); - - reset_time_regs(); - - return 0; -} - -void SNES_SPC::clear_echo() -{ - if ( !(dsp.read( SPC_DSP::r_flg ) & 0x20) ) - { - int addr = 0x100 * dsp.read( SPC_DSP::r_esa ); - int end = addr + 0x800 * (dsp.read( SPC_DSP::r_edl ) & 0x0F); - if ( end > 0x10000 ) - end = 0x10000; - memset( &RAM [addr], 0xFF, end - addr ); - } -} - - -//// Sample output - -void SNES_SPC::reset_buf() -{ - // Start with half extra buffer of silence - sample_t* out = m.extra_buf; - while ( out < &m.extra_buf [extra_size / 2] ) - *out++ = 0; - - m.extra_pos = out; - m.buf_begin = 0; - - dsp.set_output( 0, 0 ); -} - -void SNES_SPC::set_output( sample_t* out, int size ) -{ - require( (size & 1) == 0 ); // size must be even - - m.extra_clocks &= clocks_per_sample - 1; - if ( out ) - { - sample_t const* out_end = out + size; - m.buf_begin = out; - m.buf_end = out_end; - - // Copy extra to output - sample_t const* in = m.extra_buf; - while ( in < m.extra_pos && out < out_end ) - *out++ = *in++; - - // Handle output being full already - if ( out >= out_end ) - { - // Have DSP write to remaining extra space - out = dsp.extra(); - out_end = &dsp.extra() [extra_size]; - - // Copy any remaining extra samples as if DSP wrote them - while ( in < m.extra_pos ) - *out++ = *in++; - assert( out <= out_end ); - } - - dsp.set_output( out, out_end - out ); - } - else - { - reset_buf(); - } -} - -void SNES_SPC::save_extra() -{ - // Get end pointers - sample_t const* main_end = m.buf_end; // end of data written to buf - sample_t const* dsp_end = dsp.out_pos(); // end of data written to dsp.extra() - if ( m.buf_begin <= dsp_end && dsp_end <= main_end ) - { - main_end = dsp_end; - dsp_end = dsp.extra(); // nothing in DSP's extra - } - - // Copy any extra samples at these ends into extra_buf - sample_t* out = m.extra_buf; - sample_t const* in; - for ( in = m.buf_begin + sample_count(); in < main_end; in++ ) - *out++ = *in; - for ( in = dsp.extra(); in < dsp_end ; in++ ) - *out++ = *in; - - m.extra_pos = out; - assert( out <= &m.extra_buf [extra_size] ); -} - -blargg_err_t SNES_SPC::play( int count, sample_t* out ) -{ - require( (count & 1) == 0 ); // must be even - if ( count ) - { - set_output( out, count ); - end_frame( count * (clocks_per_sample / 2) ); - } - - const char* err = m.cpu_error; - m.cpu_error = 0; - return err; -} - -blargg_err_t SNES_SPC::skip( int count ) -{ - #if SPC_LESS_ACCURATE - if ( count > 2 * sample_rate * 2 ) - { - set_output( 0, 0 ); - - // Skip a multiple of 4 samples - time_t end = count; - count = (count & 3) + 1 * sample_rate * 2; - end = (end - count) * (clocks_per_sample / 2); - - m.skipped_kon = 0; - m.skipped_koff = 0; - - // Preserve DSP and timer synchronization - // TODO: verify that this really preserves it - int old_dsp_time = m.dsp_time + m.spc_time; - m.dsp_time = end - m.spc_time + skipping_time; - end_frame( end ); - m.dsp_time = m.dsp_time - skipping_time + old_dsp_time; - - dsp.write( SPC_DSP::r_koff, m.skipped_koff & ~m.skipped_kon ); - dsp.write( SPC_DSP::r_kon , m.skipped_kon ); - clear_echo(); - } - #endif - - return play( count, 0 ); -} - -//// Snes9x Accessor - -void SNES_SPC::dsp_set_spc_snapshot_callback( void (*callback) (void) ) -{ - dsp.set_spc_snapshot_callback( callback ); -} - -void SNES_SPC::dsp_dump_spc_snapshot( void ) -{ - dsp.dump_spc_snapshot(); -} - -void SNES_SPC::dsp_set_stereo_switch( int value ) -{ - dsp.set_stereo_switch( value ); -} - -SNES_SPC::uint8_t SNES_SPC::dsp_reg_value( int ch, int addr ) -{ - return dsp.reg_value( ch, addr ); -} - -int SNES_SPC::dsp_envx_value( int ch ) -{ - return dsp.envx_value( ch ); -} - -//// Snes9x debugger - -#ifdef DEBUGGER - -void SNES_SPC::debug_toggle_trace( void ) -{ - debug_trace = !debug_trace; - - if (debug_trace) - { - printf("APU tracing enabled.\n"); - ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "wb") - } - else - { - printf("APU tracing disabled.\n"); - fclose(apu_trace); - apu_trace = NULL; - } -} - -bool SNES_SPC::debug_is_enabled( void ) { return debug_trace; } - -void SNES_SPC::debug_do_trace( int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp ) -{ - char msg[512]; - - ENSURE_TRACE_OPEN(apu_trace, "apu_trace.log", "a") - - debug_op_print(msg, a, x, y, pc, sp, psw, c, nz, dp); - fprintf(apu_trace, "%s ", msg); - debug_io_print(msg); - fprintf(apu_trace, "%s ", msg); - S9xPrintHVPosition(msg); - fprintf(apu_trace, "%s\n", msg); -} - -void SNES_SPC::debug_op_print( char *buffer, int a, int x, int y, uint8_t const *pc, uint8_t *sp, int psw, int c, int nz, int dp ) -{ - static char mnemonics[256][20] = - { - "NOP", - "TCALL 0", - "SET1 $%02X.0", - "BBS $%02X.0,$%04X", - "OR A,$%02X", - "OR A,!$%04X", - "OR A,(X)", - "OR A,[$%02X+X]", - "OR A,#$%02X", - "OR $%02X,$%02X", - "OR1 C,$%04X.%d", - "ASL $%02X", - "MOV !$%04X,Y", - "PUSH PSW", - "TSET1 !$%04X", - "BRK", - "BPL $%04X", - "TCALL 1", - "CLR1 $%02X.0", - "BBC $%02X.0,$%04X", - "OR A,$%02X+X", - "OR A,!$%04X+X", - "OR A,!$%04X+Y", - "OR A,[$%02X]+Y", - "OR $%02X,#$%02X", - "OR (X),(Y)", - "DECW $%02X", - "ASL $%02X+X", - "ASL A", - "DEC X", - "CMP X,!$%04X", - "JMP [!$%04X+X]", - "CLRP", - "TCALL 2", - "SET1 $%02X.1", - "BBS $%02X.1,$%04X", - "AND A,$%02X", - "AND A,!$%04X", - "AND A,(X)", - "AND A,[$%02X+X]", - "AND A,#$%02X", - "AND $%02X,$%02X", - "OR1 C,/$%04X.%d", - "ROL $%02X", - "ROL !$%04X", - "PUSH A", - "CBNE $%02X,$%04X", - "BRA $%04X", - "BMI $%04X", - "TCALL 3", - "CLR1 $%02X.1", - "BBC $%02X.1,$%04X", - "AND A,$%02X+X", - "AND A,!$%04X+X", - "AND A,!$%04X+Y", - "AND A,[$%02X]+Y", - "AND $%02X,#$%02X", - "AND (X),(Y)", - "INCW $%02X", - "ROL $%02X+X", - "ROL A", - "INC X", - "CMP X,$%02X", - "CALL !$%04X", - "SETP", - "TCALL 4", - "SET1 $%02X.2", - "BBS $%02X.2,$%04X", - "EOR A,$%02X", - "EOR A,!$%04X", - "EOR A,(X)", - "EOR A,[$%02X+X]", - "EOR A,#$%02X", - "EOR $%02X,$%02X", - "AND1 C,$%04X.%d", - "LSR $%02X", - "LSR !$%04X", - "PUSH X", - "TCLR1 !$%04X", - "PCALL $%02X", - "BVC $%04X", - "TCALL 5", - "CLR1 $%02X.2", - "BBC $%02X.2,$%04X", - "EOR A,$%02X+X", - "EOR A,!$%04X+X", - "EOR A,!$%04X+Y", - "EOR A,[$%02X]+Y", - "EOR $%02X,#$%02X", - "EOR (X),(Y)", - "CMPW YA,$%02X", - "LSR $%02X+X", - "LSR A", - "MOV X,A", - "CMP Y,!$%04X", - "JMP !$%04X", - "CLRC", - "TCALL 6", - "SET1 $%02X.3", - "BBS $%02X.3,$%04X", - "CMP A,$%02X", - "CMP A,!$%04X", - "CMP A,(X)", - "CMP A,[$%02X+X]", - "CMP A,#$%02X", - "CMP $%02X,$%02X", - "AND1 C,/$%04X.%d", - "ROR $%02X", - "ROR !$%04X", - "PUSH Y", - "DBNZ $%02X,$%04X", - "RET", - "BVS $%04X", - "TCALL 7", - "CLR1 $%02X.3", - "BBC $%02X.3,$%04X", - "CMP A,$%02X+X", - "CMP A,!$%04X+X", - "CMP A,!$%04X+Y", - "CMP A,[$%02X]+Y", - "CMP $%02X,#$%02X", - "CMP (X),(Y)", - "ADDW YA,$%02X", - "ROR $%02X+X", - "ROR A", - "MOV A,X", - "CMP Y,$%02X", - "RET1", - "SETC", - "TCALL 8", - "SET1 $%02X.4", - "BBS $%02X.4,$%04X", - "ADC A,$%02X", - "ADC A,!$%04X", - "ADC A,(X)", - "ADC A,[$%02X+X]", - "ADC A,#$%02X", - "ADC $%02X,$%02X", - "EOR1 C,$%04X.%d", - "DEC $%02X", - "DEC !$%04X", - "MOV Y,#$%02X", - "POP PSW", - "MOV $%02X,#$%02X", - "BCC $%04X", - "TCALL 9", - "CLR1 $%02X.4", - "BBC $%02X.4,$%04X", - "ADC A,$%02X+X", - "ADC A,!$%04X+X", - "ADC A,!$%04X+Y", - "ADC A,[$%02X]+Y", - "ADC $%02X,#$%02X", - "ADC (X),(Y)", - "SUBW YA,$%02X", - "DEC $%02X+X", - "DEC A", - "MOV X,SP", - "DIV YA,X", - "XCN A", - "EI", - "TCALL 10", - "SET1 $%02X.5", - "BBS $%02X.5,$%04X", - "SBC A,$%02X", - "SBC A,!$%04X", - "SBC A,(X)", - "SBC A,[$%02X+X]", - "SBC A,#$%02X", - "SBC $%02X,$%02X", - "MOV1 C,$%04X.%d", - "INC $%02X", - "INC !$%04X", - "CMP Y,#$%02X", - "POP A", - "MOV (X)+,A", - "BCS $%04X", - "TCALL 11", - "CLR1 $%02X.5", - "BBC $%02X.5,$%04X", - "SBC A,$%02X+X", - "SBC A,!$%04X+X", - "SBC A,!$%04X+Y", - "SBC A,[$%02X]+Y", - "SBC $%02X,#$%02X", - "SBC (X),(Y)", - "MOVW YA,$%02X", - "INC $%02X+X", - "INC A", - "MOV SP,X", - "DAS A", - "MOV A,(X)+", - "DI", - "TCALL 12", - "SET1 $%02X.6", - "BBS $%02X.6,$%04X", - "MOV $%02X,A", - "MOV !$%04X,A", - "MOV (X),A", - "MOV [$%02X+X],A", - "CMP X,#$%02X", - "MOV !$%04X,X", - "MOV1 $%04X.%d,C", - "MOV $%02X,Y", - "ASL !$%04X", - "MOV X,#$%02X", - "POP X", - "MUL YA", - "BNE $%04X", - "TCALL 13", - "CLR1 $%02X.6", - "BBC $%02X.6,$%04X", - "MOV $%02X+X,A", - "MOV !$%04X+X,A", - "MOV !$%04X+Y,A", - "MOV [$%02X]+Y,A", - "MOV $%02X,X", - "MOV $%02X+Y,X", - "MOVW $%02X,YA", - "MOV $%02X+X,Y", - "DEC Y", - "MOV A,Y", - "CBNE $%02X+X,$%04X", - "DAA A", - "CLRV", - "TCALL 14", - "SET1 $%02X.7", - "BBS $%02X.7,$%04X", - "MOV A,$%02X", - "MOV A,!$%04X", - "MOV A,(X)", - "MOV A,[$%02X+X]", - "MOV A,#$%02X", - "MOV X,!$%04X", - "NOT1 $%04X.%d", - "MOV Y,$%02X", - "MOV Y,!$%04X", - "NOTC", - "POP Y", - "SLEEP", - "BEQ $%04X", - "TCALL 15", - "CLR1 $%02X.7", - "BBC $%02X.7,$%04X", - "MOV A,$%02X+X", - "MOV A,!$%04X+X", - "MOV A,!$%04X+Y", - "MOV A,[$%02X]+Y", - "MOV X,$%02X", - "MOV X,$%02X+Y", - "MOV $%02X,$%02X", - "MOV Y,$%02X+X", - "INC Y", - "MOV Y,A", - "DBNZ Y,$%04X", - "STOP" - }; - - static int modes[256] = - { - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 2, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 7, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 1, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 1, 0, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 1, 1, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 2, 5, 2, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 0, 2, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 4, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 3, 6, 0, 1, 0, 2, 2, - 7, 2, 0, 5, 0, 1, 1, 0, 4, 2, 0, 0, 2, 2, 2, 2, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 0, 2, 2, - 7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 5, 2, - 2, 2, 0, 5, 0, 1, 2, 0, 0, 1, 6, 0, 1, 2, 2, 2, - 7, 2, 0, 5, 0, 1, 1, 0, 0, 0, 3, 0, 2, 2, 7, 2 - }; - - static int modesToBytes[] = - { - 2, 3, 1, 3, 3, 3, 3, 2 - }; - - int const n80 = 0x80; // nz - int const p20 = 0x20; // dp - int const z02 = 0x02; // nz - int const c01 = 0x01; // c - - #define GET_PC() (pc - ram) - #define GET_SP() (sp - 0x101 - ram) - #define GET_PSW( out )\ - {\ - out = psw & ~(n80 | p20 | z02 | c01);\ - out |= c >> 8 & c01;\ - out |= dp >> 3 & p20;\ - out |= ((nz >> 4) | nz) & n80;\ - if ( !(uint8_t) nz ) out |= z02;\ - } - - uint8_t const *ram = RAM; - - int addr; - int tsp, tpsw; - uint8_t d0, d1, d2; - - addr = GET_PC(); - tsp = GET_SP(); - GET_PSW(tpsw); - - d0 = *pc; - d1 = (addr < 0xffff) ? *(pc + 1) : 0; - d2 = (addr < 0xfffe) ? *(pc + 2) : 0; - - int mode = modes[d0]; - int bytes = modesToBytes[mode]; - char mnem[100]; - - switch (bytes) - { - case 1: - sprintf(buffer, "%04X %02X ", addr, d0); - break; - - case 2: - sprintf(buffer, "%04X %02X %02X ", addr, d0, d1); - break; - - case 3: - sprintf(buffer, "%04X %02X %02X %02X ", addr, d0, d1, d2); - break; - } - - switch (mode) - { - case 0: - sprintf(mnem, mnemonics[d0], d1); - break; - - case 1: - sprintf(mnem, mnemonics[d0], d1 + (d2 << 8)); - break; - - case 2: - strcpy (mnem, mnemonics[d0]); - break; - - case 3: - sprintf(mnem, mnemonics[d0], d2, d1); - break; - - case 4: - sprintf(mnem, mnemonics[d0], d2, d1); - break; - - case 5: - sprintf(mnem, mnemonics[d0], d1, addr + 3 + (int8_t) d2); - break; - - case 6: - sprintf(mnem, mnemonics[d0], (d1 + (d2 << 8)) & 0x1fff, d2 >> 5); - break; - - case 7: - sprintf(mnem, mnemonics[d0], addr + 2 + (int8_t) d1); - break; - } - - sprintf(buffer, "%s %-20s A:%02X X:%02X Y:%02X S:%02X P:%c%c%c%c%c%c%c%c ROM:%d", - buffer, mnem, a, x, y, tsp, - (tpsw & 0x80) ? 'N' : 'n', - (tpsw & 0x40) ? 'V' : 'v', - (tpsw & 0x20) ? 'P' : 'p', - (tpsw & 0x10) ? 'B' : 'b', - (tpsw & 0x08) ? 'H' : 'h', - (tpsw & 0x04) ? 'I' : 'i', - (tpsw & 0x02) ? 'Z' : 'z', - (tpsw & 0x01) ? 'C' : 'c', - m.rom_enabled ? 1 : 0); -} - -void SNES_SPC::debug_io_print( char *buffer ) -{ - sprintf(buffer, "i/o %02X/%02X %02X/%02X %02X/%02X %02X/%02X", - m.smp_regs[1][r_cpuio0], m.smp_regs[0][r_cpuio0], - m.smp_regs[1][r_cpuio1], m.smp_regs[0][r_cpuio1], - m.smp_regs[1][r_cpuio2], m.smp_regs[0][r_cpuio2], - m.smp_regs[1][r_cpuio3], m.smp_regs[0][r_cpuio3]); -} - -#endif diff --git a/apu/SNES_SPC_state.cpp b/apu/SNES_SPC_state.cpp deleted file mode 100644 index 3d9d3f3a..00000000 --- a/apu/SNES_SPC_state.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// SPC emulation state save/load: copy_state(), save_spc() -// Separate file to avoid linking in unless needed - -// snes_spc 0.9.0. http://www.slack.net/‾ant/ - -#include "SNES_SPC.h" - -#if !SPC_NO_COPY_STATE_FUNCS - -#include - -/* Copyright (C) 2004-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include "blargg_source.h" - -#define RAM (m.ram.ram) -#define REGS (m.smp_regs [0]) -#define REGS_IN (m.smp_regs [1]) - -void SNES_SPC::save_regs( uint8_t out [reg_count] ) -{ - // Use current timer counter values - for ( int i = 0; i < timer_count; i++ ) - out [r_t0out + i] = m.timers [i].counter; - - // Last written values - memcpy( out, REGS, r_t0out ); -} - -void SNES_SPC::init_header( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - spc->has_id666 = 26; // has none - spc->version = 30; - memcpy( spc, signature, sizeof spc->signature ); - memset( spc->text, 0, sizeof spc->text ); -} - -void SNES_SPC::save_spc( void* spc_out ) -{ - spc_file_t* const spc = (spc_file_t*) spc_out; - - // CPU - spc->pcl = (uint8_t) (m.cpu_regs.pc >> 0); - spc->pch = (uint8_t) (m.cpu_regs.pc >> 8); - spc->a = m.cpu_regs.a; - spc->x = m.cpu_regs.x; - spc->y = m.cpu_regs.y; - spc->psw = m.cpu_regs.psw; - spc->sp = m.cpu_regs.sp; - - // RAM, ROM - memcpy( spc->ram, RAM, sizeof spc->ram ); - if ( m.rom_enabled ) - memcpy( spc->ram + rom_addr, m.hi_ram, sizeof m.hi_ram ); - memset( spc->unused, 0, sizeof spc->unused ); - memcpy( spc->ipl_rom, m.rom, sizeof spc->ipl_rom ); - - // SMP registers - save_regs( &spc->ram [0xF0] ); - int i; - for ( i = 0; i < port_count; i++ ) - spc->ram [0xF0 + r_cpuio0 + i] = REGS_IN [r_cpuio0 + i]; - - // DSP registers - for ( i = 0; i < SPC_DSP::register_count; i++ ) - spc->dsp [i] = dsp.read( i ); -} - -#undef IF_0_THEN_256 -#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) -void SNES_SPC::copy_state( unsigned char** io, copy_func_t copy ) -{ - SPC_State_Copier copier( io, copy ); - - // Make state data more readable by putting 64K RAM, 16 SMP registers, - // then DSP (with its 128 registers) first - - // RAM - enable_rom( 0 ); // will get re-enabled if necessary in regs_loaded() below - copier.copy( RAM, 0x10000 ); - - { - // SMP registers - uint8_t regs [reg_count]; - uint8_t regs_in [reg_count]; - - memcpy( regs, REGS, reg_count ); - memcpy( regs_in, REGS_IN, reg_count ); - - copier.copy( regs, sizeof regs ); - copier.copy( regs_in, sizeof regs_in ); - - memcpy( REGS, regs, reg_count); - memcpy( REGS_IN, regs_in, reg_count ); - - enable_rom( REGS [r_control] & 0x80 ); - } - - // CPU registers - SPC_COPY( uint16_t, m.cpu_regs.pc ); - SPC_COPY( uint8_t, m.cpu_regs.a ); - SPC_COPY( uint8_t, m.cpu_regs.x ); - SPC_COPY( uint8_t, m.cpu_regs.y ); - SPC_COPY( uint8_t, m.cpu_regs.psw ); - SPC_COPY( uint8_t, m.cpu_regs.sp ); - copier.extra(); - - SPC_COPY( int16_t, m.spc_time ); - SPC_COPY( int16_t, m.dsp_time ); - - // DSP - dsp.copy_state( io, copy ); - - // Timers - for ( int i = 0; i < timer_count; i++ ) - { - Timer* t = &m.timers [i]; - t->period = IF_0_THEN_256( REGS [r_t0target + i] ); - t->enabled = REGS [r_control] >> i & 1; - SPC_COPY( int16_t, t->next_time ); - SPC_COPY( uint8_t, t->divider ); - SPC_COPY( uint8_t, t->counter ); - copier.extra(); - } - - set_tempo( m.tempo ); - - copier.extra(); -} -#endif diff --git a/apu/SPC_CPU.h b/apu/SPC_CPU.h deleted file mode 100644 index 67fee8da..00000000 --- a/apu/SPC_CPU.h +++ /dev/null @@ -1,1228 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -/* Copyright (C) 2004-2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -//// Memory access - -#if SPC_MORE_ACCURACY - #define SUSPICIOUS_OPCODE( name ) ((void) 0) -#else - #define SUSPICIOUS_OPCODE( name ) dprintf( "SPC: suspicious opcode: " name "\n" ) -#endif - -#define CPU_READ( time, offset, addr )\ - cpu_read( addr, time + offset ) - -#define CPU_WRITE( time, offset, addr, data )\ - cpu_write( data, addr, time + offset ) - -#if SPC_MORE_ACCURACY - #define CPU_READ_TIMER( time, offset, addr, out )\ - { out = CPU_READ( time, offset, addr ); } - -#else - // timers are by far the most common thing read from dp - #define CPU_READ_TIMER( time, offset, addr_, out )\ - {\ - rel_time_t adj_time = time + offset;\ - int dp_addr = addr_;\ - int ti = dp_addr - (r_t0out + 0xF0);\ - if ( (unsigned) ti < timer_count )\ - {\ - Timer* t = &m.timers [ti];\ - if ( adj_time >= t->next_time )\ - t = run_timer_( t, adj_time );\ - out = t->counter;\ - t->counter = 0;\ - }\ - else\ - {\ - out = ram [dp_addr];\ - int i = dp_addr - 0xF0;\ - if ( (unsigned) i < 0x10 )\ - out = cpu_read_smp_reg( i, adj_time );\ - }\ - } -#endif - -#define TIME_ADJ( n ) (n) - -#define READ_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), (addr), out ) -#define READ( time, addr ) CPU_READ ( rel_time, TIME_ADJ(time), (addr) ) -#define WRITE( time, addr, data ) CPU_WRITE( rel_time, TIME_ADJ(time), (addr), (data) ) - -#define DP_ADDR( addr ) (dp + (addr)) - -#define READ_DP_TIMER( time, addr, out ) CPU_READ_TIMER( rel_time, TIME_ADJ(time), DP_ADDR( addr ), out ) -#define READ_DP( time, addr ) READ ( time, DP_ADDR( addr ) ) -#define WRITE_DP( time, addr, data ) WRITE( time, DP_ADDR( addr ), data ) - -#define READ_PROG16( addr ) GET_LE16( ram + (addr) ) - -#define SET_PC( n ) (pc = ram + (n)) -#define GET_PC() (pc - ram) -#define READ_PC( pc ) (*(pc)) -#define READ_PC16( pc ) GET_LE16( pc ) - -// TODO: remove non-wrapping versions? -#define SPC_NO_SP_WRAPAROUND 0 - -#define SET_SP( v ) (sp = ram + 0x101 + (v)) -#define GET_SP() (sp - 0x101 - ram) - -#if SPC_NO_SP_WRAPAROUND -#define PUSH16( v ) (sp -= 2, SET_LE16( sp, v )) -#define PUSH( v ) (void) (*--sp = (uint8_t) (v)) -#define POP( out ) (void) ((out) = *sp++) - -#else -#define PUSH16( data )\ -{\ - int addr = (sp -= 2) - ram;\ - if ( addr > 0x100 )\ - {\ - SET_LE16( sp, data );\ - }\ - else\ - {\ - ram [(uint8_t) addr + 0x100] = (uint8_t) data;\ - sp [1] = (uint8_t) (data >> 8);\ - sp += 0x100;\ - }\ -} - -#define PUSH( data )\ -{\ - *--sp = (uint8_t) (data);\ - if ( sp - ram == 0x100 )\ - sp += 0x100;\ -} - -#define POP( out )\ -{\ - out = *sp++;\ - if ( sp - ram == 0x201 )\ - {\ - out = sp [-0x101];\ - sp -= 0x100;\ - }\ -} - -#endif - -#define MEM_BIT( rel ) CPU_mem_bit( pc, rel_time + rel ) - -unsigned SNES_SPC::CPU_mem_bit( uint8_t const* pc, rel_time_t rel_time ) -{ - unsigned addr = READ_PC16( pc ); - unsigned t = READ( 0, addr & 0x1FFF ) >> (addr >> 13); - return t << 8 & 0x100; -} - -//// Status flag handling - -// Hex value in name to clarify code and bit shifting. -// Flag stored in indicated variable during emulation -int const n80 = 0x80; // nz -int const v40 = 0x40; // psw -int const p20 = 0x20; // dp -int const b10 = 0x10; // psw -int const h08 = 0x08; // psw -int const i04 = 0x04; // psw -int const z02 = 0x02; // nz -int const c01 = 0x01; // c - -int const nz_neg_mask = 0x880; // either bit set indicates N flag set - -#define GET_PSW( out )\ -{\ - out = psw & ~(n80 | p20 | z02 | c01);\ - out |= c >> 8 & c01;\ - out |= dp >> 3 & p20;\ - out |= ((nz >> 4) | nz) & n80;\ - if ( !(uint8_t) nz ) out |= z02;\ -} - -#define SET_PSW( in )\ -{\ - psw = in;\ - c = in << 8;\ - dp = in << 3 & 0x100;\ - nz = (in << 4 & 0x800) | (~in & z02);\ -} - -SPC_CPU_RUN_FUNC -{ - uint8_t* const ram = RAM; - int a = m.cpu_regs.a; - int x = m.cpu_regs.x; - int y = m.cpu_regs.y; - uint8_t const* pc; - uint8_t* sp; - int psw; - int c; - int nz; - int dp; - - SET_PC( m.cpu_regs.pc ); - SET_SP( m.cpu_regs.sp ); - SET_PSW( m.cpu_regs.psw ); - - goto loop; - - - // Main loop - -cbranch_taken_loop: - pc += *(BOOST::int8_t const*) pc; -inc_pc_loop: - pc++; -loop: -{ - unsigned opcode; - unsigned data; - - check( (unsigned) a < 0x100 ); - check( (unsigned) x < 0x100 ); - check( (unsigned) y < 0x100 ); - - opcode = *pc; - if (allow_time_overflow && rel_time >= 0 ) - goto stop; - if ( (rel_time += m.cycle_table [opcode]) > 0 && !allow_time_overflow) - goto out_of_time; - - #ifdef SPC_CPU_OPCODE_HOOK - SPC_CPU_OPCODE_HOOK( GET_PC(), opcode ); - #endif - /* - //SUB_CASE_COUNTER( 1 ); - #define PROFILE_TIMER_LOOP( op, addr, len )\ - if ( opcode == op )\ - {\ - int cond = (unsigned) ((addr) - 0xFD) < 3 &&\ - pc [len] == 0xF0 && pc [len+1] == 0xFE - len;\ - SUB_CASE_COUNTER( op && cond );\ - } - - PROFILE_TIMER_LOOP( 0xEC, GET_LE16( pc + 1 ), 3 ); - PROFILE_TIMER_LOOP( 0xEB, pc [1], 2 ); - PROFILE_TIMER_LOOP( 0xE4, pc [1], 2 ); - */ - -#ifdef DEBUGGER - if (debug_trace) - debug_do_trace(a, x, y, pc, sp, psw, c, nz, dp); -#endif - - - // TODO: if PC is at end of memory, this will get wrong operand (very obscure) - data = *++pc; - switch ( opcode ) - { - -// Common instructions - -#define BRANCH( cond )\ -{\ - pc++;\ - pc += (BOOST::int8_t) data;\ - if ( cond )\ - goto loop;\ - pc -= (BOOST::int8_t) data;\ - rel_time -= 2;\ - goto loop;\ -} - - case 0xF0: // BEQ - BRANCH( !(uint8_t) nz ) // 89% taken - - case 0xD0: // BNE - BRANCH( (uint8_t) nz ) - - case 0x3F:{// CALL - int old_addr = GET_PC() + 2; - SET_PC( READ_PC16( pc ) ); - PUSH16( old_addr ); - goto loop; - } - - case 0x6F:// RET - #if SPC_NO_SP_WRAPAROUND - { - SET_PC( GET_LE16( sp ) ); - sp += 2; - } - #else - { - int addr = sp - ram; - SET_PC( GET_LE16( sp ) ); - sp += 2; - if ( addr < 0x1FF ) - goto loop; - - SET_PC( sp [-0x101] * 0x100 + ram [(uint8_t) addr + 0x100] ); - sp -= 0x100; - } - #endif - goto loop; - - case 0xE4: // MOV a,dp - ++pc; - // 80% from timer - READ_DP_TIMER( 0, data, a = nz ); - goto loop; - - case 0xFA:{// MOV dp,dp - int temp; - READ_DP_TIMER( -2, data, temp ); - data = temp + no_read_before_write ; - } - // fall through - case 0x8F:{// MOV dp,#imm - int temp = READ_PC( pc + 1 ); - pc += 2; - - #if !SPC_MORE_ACCURACY - { - int i = dp + temp; - ram [i] = (uint8_t) data; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 76% - { - REGS [i] = (uint8_t) data; - - // Registers other than $F2 and $F4-$F7 - //if ( i != 2 && i != 4 && i != 5 && i != 6 && i != 7 ) - if ( ((~0x2F00 << (bits_in_int - 16)) << i) < 0 ) // 12% - cpu_write_smp_reg( data, rel_time, i ); - } - } - #else - WRITE_DP( 0, temp, data ); - #endif - goto loop; - } - - case 0xC4: // MOV dp,a - ++pc; - #if !SPC_MORE_ACCURACY - { - int i = dp + data; - ram [i] = (uint8_t) a; - i -= 0xF0; - if ( (unsigned) i < 0x10 ) // 39% - { - unsigned sel = i - 2; - REGS [i] = (uint8_t) a; - - if ( sel == 1 ) // 51% $F3 - dsp_write( a, rel_time ); - else if ( sel > 1 ) // 1% not $F2 or $F3 - cpu_write_smp_reg_( a, rel_time, i ); - } - } - #else - WRITE_DP( 0, data, a ); - #endif - goto loop; - -#define CASE( n ) case n: - -// Define common address modes based on opcode for immediate mode. Execution -// ends with data set to the address of the operand. -#define ADDR_MODES_( op )\ - CASE( op - 0x02 ) /* (X) */\ - data = x + dp;\ - pc--;\ - goto end_##op;\ - CASE( op + 0x0F ) /* (dp)+Y */\ - data = READ_PROG16( data + dp ) + y;\ - goto end_##op;\ - CASE( op - 0x01 ) /* (dp+X) */\ - data = READ_PROG16( ((uint8_t) (data + x)) + dp );\ - goto end_##op;\ - CASE( op + 0x0E ) /* abs+Y */\ - data += y;\ - goto abs_##op;\ - CASE( op + 0x0D ) /* abs+X */\ - data += x;\ - CASE( op - 0x03 ) /* abs */\ - abs_##op:\ - data += 0x100 * READ_PC( ++pc );\ - goto end_##op;\ - CASE( op + 0x0C ) /* dp+X */\ - data = (uint8_t) (data + x); - -#define ADDR_MODES_NO_DP( op )\ - ADDR_MODES_( op )\ - data += dp;\ - end_##op: - -#define ADDR_MODES( op )\ - ADDR_MODES_( op )\ - CASE( op - 0x04 ) /* dp */\ - data += dp;\ - end_##op: - -// 1. 8-bit Data Transmission Commands. Group I - - ADDR_MODES_NO_DP( 0xE8 ) // MOV A,addr - a = nz = READ( 0, data ); - goto inc_pc_loop; - - case 0xBF:{// MOV A,(X)+ - int temp = x + dp; - x = (uint8_t) (x + 1); - a = nz = READ( -1, temp ); - goto loop; - } - - case 0xE8: // MOV A,imm - a = data; - nz = data; - goto inc_pc_loop; - - case 0xF9: // MOV X,dp+Y - data = (uint8_t) (data + y); - case 0xF8: // MOV X,dp - READ_DP_TIMER( 0, data, x = nz ); - goto inc_pc_loop; - - case 0xE9: // MOV X,abs - data = READ_PC16( pc ); - ++pc; - data = READ( 0, data ); - case 0xCD: // MOV X,imm - x = data; - nz = data; - goto inc_pc_loop; - - case 0xFB: // MOV Y,dp+X - data = (uint8_t) (data + x); - case 0xEB: // MOV Y,dp - // 70% from timer - pc++; - READ_DP_TIMER( 0, data, y = nz ); - goto loop; - - case 0xEC:{// MOV Y,abs - int temp = READ_PC16( pc ); - pc += 2; - READ_TIMER( 0, temp, y = nz ); - //y = nz = READ( 0, temp ); - goto loop; - } - - case 0x8D: // MOV Y,imm - y = data; - nz = data; - goto inc_pc_loop; - -// 2. 8-BIT DATA TRANSMISSION COMMANDS, GROUP 2 - - ADDR_MODES_NO_DP( 0xC8 ) // MOV addr,A - WRITE( 0, data, a ); - goto inc_pc_loop; - - { - int temp; - case 0xCC: // MOV abs,Y - temp = y; - goto mov_abs_temp; - case 0xC9: // MOV abs,X - temp = x; - mov_abs_temp: - WRITE( 0, READ_PC16( pc ), temp ); - pc += 2; - goto loop; - } - - case 0xD9: // MOV dp+Y,X - data = (uint8_t) (data + y); - case 0xD8: // MOV dp,X - WRITE( 0, data + dp, x ); - goto inc_pc_loop; - - case 0xDB: // MOV dp+X,Y - data = (uint8_t) (data + x); - case 0xCB: // MOV dp,Y - WRITE( 0, data + dp, y ); - goto inc_pc_loop; - -// 3. 8-BIT DATA TRANSMISSIN COMMANDS, GROUP 3. - - case 0x7D: // MOV A,X - a = x; - nz = x; - goto loop; - - case 0xDD: // MOV A,Y - a = y; - nz = y; - goto loop; - - case 0x5D: // MOV X,A - x = a; - nz = a; - goto loop; - - case 0xFD: // MOV Y,A - y = a; - nz = a; - goto loop; - - case 0x9D: // MOV X,SP - x = nz = GET_SP(); - goto loop; - - case 0xBD: // MOV SP,X - SET_SP( x ); - goto loop; - - //case 0xC6: // MOV (X),A (handled by MOV addr,A in group 2) - - case 0xAF: // MOV (X)+,A - WRITE_DP( 0, x, a + no_read_before_write ); - x++; - goto loop; - -// 5. 8-BIT LOGIC OPERATION COMMANDS - -#define LOGICAL_OP( op, func )\ - ADDR_MODES( op ) /* addr */\ - data = READ( 0, data );\ - case op: /* imm */\ - nz = a func##= data;\ - goto inc_pc_loop;\ - { unsigned addr;\ - case op + 0x11: /* X,Y */\ - data = READ_DP( -2, y );\ - addr = x + dp;\ - goto addr_##op;\ - case op + 0x01: /* dp,dp */\ - data = READ_DP( -3, data );\ - case op + 0x10:{/*dp,imm*/\ - uint8_t const* addr2 = pc + 1;\ - pc += 2;\ - addr = READ_PC( addr2 ) + dp;\ - }\ - addr_##op:\ - nz = data func READ( -1, addr );\ - WRITE( 0, addr, nz );\ - goto loop;\ - } - - LOGICAL_OP( 0x28, & ); // AND - - LOGICAL_OP( 0x08, | ); // OR - - LOGICAL_OP( 0x48, ^ ); // EOR - -// 4. 8-BIT ARITHMETIC OPERATION COMMANDS - - ADDR_MODES( 0x68 ) // CMP addr - data = READ( 0, data ); - case 0x68: // CMP imm - nz = a - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x79: // CMP (X),(Y) - data = READ_DP( -2, y ); - nz = READ_DP( -1, x ) - data; - c = ~nz; - nz &= 0xFF; - goto loop; - - case 0x69: // CMP dp,dp - data = READ_DP( -3, data ); - case 0x78: // CMP dp,imm - nz = READ_DP( -1, READ_PC( ++pc ) ) - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x3E: // CMP X,dp - data += dp; - goto cmp_x_addr; - case 0x1E: // CMP X,abs - data = READ_PC16( pc ); - pc++; - cmp_x_addr: - data = READ( 0, data ); - case 0xC8: // CMP X,imm - nz = x - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - case 0x7E: // CMP Y,dp - data += dp; - goto cmp_y_addr; - case 0x5E: // CMP Y,abs - data = READ_PC16( pc ); - pc++; - cmp_y_addr: - data = READ( 0, data ); - case 0xAD: // CMP Y,imm - nz = y - data; - c = ~nz; - nz &= 0xFF; - goto inc_pc_loop; - - { - int addr; - case 0xB9: // SBC (x),(y) - case 0x99: // ADC (x),(y) - pc--; // compensate for inc later - data = READ_DP( -2, y ); - addr = x + dp; - goto adc_addr; - case 0xA9: // SBC dp,dp - case 0x89: // ADC dp,dp - data = READ_DP( -3, data ); - case 0xB8: // SBC dp,imm - case 0x98: // ADC dp,imm - addr = READ_PC( ++pc ) + dp; - adc_addr: - nz = READ( -1, addr ); - goto adc_data; - -// catch ADC and SBC together, then decode later based on operand -#undef CASE -#define CASE( n ) case n: case (n) + 0x20: - ADDR_MODES( 0x88 ) // ADC/SBC addr - data = READ( 0, data ); - case 0xA8: // SBC imm - case 0x88: // ADC imm - addr = -1; // A - nz = a; - adc_data: { - int flags; - if ( opcode >= 0xA0 ) // SBC - data ^= 0xFF; - - flags = data ^ nz; - nz += data + (c >> 8 & 1); - flags ^= nz; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = nz; - if ( addr < 0 ) - { - a = (uint8_t) nz; - goto inc_pc_loop; - } - WRITE( 0, addr, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - } - - } - -// 6. ADDITION & SUBTRACTION COMMANDS - -#define INC_DEC_REG( reg, op )\ - nz = reg op;\ - reg = (uint8_t) nz;\ - goto loop; - - case 0xBC: INC_DEC_REG( a, + 1 ) // INC A - case 0x3D: INC_DEC_REG( x, + 1 ) // INC X - case 0xFC: INC_DEC_REG( y, + 1 ) // INC Y - - case 0x9C: INC_DEC_REG( a, - 1 ) // DEC A - case 0x1D: INC_DEC_REG( x, - 1 ) // DEC X - case 0xDC: INC_DEC_REG( y, - 1 ) // DEC Y - - case 0x9B: // DEC dp+X - case 0xBB: // INC dp+X - data = (uint8_t) (data + x); - case 0x8B: // DEC dp - case 0xAB: // INC dp - data += dp; - goto inc_abs; - case 0x8C: // DEC abs - case 0xAC: // INC abs - data = READ_PC16( pc ); - pc++; - inc_abs: - nz = (opcode >> 4 & 2) - 1; - nz += READ( -1, data ); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - -// 7. SHIFT, ROTATION COMMANDS - - case 0x5C: // LSR A - c = 0; - case 0x7C:{// ROR A - nz = (c >> 1 & 0x80) | (a >> 1); - c = a << 8; - a = nz; - goto loop; - } - - case 0x1C: // ASL A - c = 0; - case 0x3C:{// ROL A - int temp = c >> 8 & 1; - c = a << 1; - nz = c | temp; - a = (uint8_t) nz; - goto loop; - } - - case 0x0B: // ASL dp - c = 0; - data += dp; - goto rol_mem; - case 0x1B: // ASL dp+X - c = 0; - case 0x3B: // ROL dp+X - data = (uint8_t) (data + x); - case 0x2B: // ROL dp - data += dp; - goto rol_mem; - case 0x0C: // ASL abs - c = 0; - case 0x2C: // ROL abs - data = READ_PC16( pc ); - pc++; - rol_mem: - nz = c >> 8 & 1; - nz |= (c = READ( -1, data ) << 1); - WRITE( 0, data, /*(uint8_t)*/ nz ); - goto inc_pc_loop; - - case 0x4B: // LSR dp - c = 0; - data += dp; - goto ror_mem; - case 0x5B: // LSR dp+X - c = 0; - case 0x7B: // ROR dp+X - data = (uint8_t) (data + x); - case 0x6B: // ROR dp - data += dp; - goto ror_mem; - case 0x4C: // LSR abs - c = 0; - case 0x6C: // ROR abs - data = READ_PC16( pc ); - pc++; - ror_mem: { - int temp = READ( -1, data ); - nz = (c >> 1 & 0x80) | (temp >> 1); - c = temp << 8; - WRITE( 0, data, nz ); - goto inc_pc_loop; - } - - case 0x9F: // XCN - nz = a = (a >> 4) | (uint8_t) (a << 4); - goto loop; - -// 8. 16-BIT TRANSMISION COMMANDS - - case 0xBA: // MOVW YA,dp - a = READ_DP( -2, data ); - nz = (a & 0x7F) | (a >> 1); - y = READ_DP( 0, (uint8_t) (data + 1) ); - nz |= y; - goto inc_pc_loop; - - case 0xDA: // MOVW dp,YA - WRITE_DP( -1, data, a ); - WRITE_DP( 0, (uint8_t) (data + 1), y + no_read_before_write ); - goto inc_pc_loop; - -// 9. 16-BIT OPERATION COMMANDS - - case 0x3A: // INCW dp - case 0x1A:{// DECW dp - int temp; - // low byte - data += dp; - temp = READ( -3, data ); - temp += (opcode >> 4 & 2) - 1; // +1 for INCW, -1 for DECW - nz = ((temp >> 1) | temp) & 0x7F; - WRITE( -2, data, /*(uint8_t)*/ temp ); - - // high byte - data = (uint8_t) (data + 1) + dp; - temp = (uint8_t) ((temp >> 8) + READ( -1, data )); - nz |= temp; - WRITE( 0, data, temp ); - - goto inc_pc_loop; - } - - case 0x7A: // ADDW YA,dp - case 0x9A:{// SUBW YA,dp - int lo = READ_DP( -2, data ); - int hi = READ_DP( 0, (uint8_t) (data + 1) ); - int result; - int flags; - - if ( opcode == 0x9A ) // SUBW - { - lo = (lo ^ 0xFF) + 1; - hi ^= 0xFF; - } - - lo += a; - result = y + hi + (lo >> 8); - flags = hi ^ y ^ result; - - psw = (psw & ~(v40 | h08)) | - (flags >> 1 & h08) | - ((flags + 0x80) >> 2 & v40); - c = result; - a = (uint8_t) lo; - result = (uint8_t) result; - y = result; - nz = (((lo >> 1) | lo) & 0x7F) | result; - - goto inc_pc_loop; - } - - case 0x5A: { // CMPW YA,dp - int temp = a - READ_DP( -1, data ); - nz = ((temp >> 1) | temp) & 0x7F; - temp = y + (temp >> 8); - temp -= READ_DP( 0, (uint8_t) (data + 1) ); - nz |= temp; - c = ~temp; - nz &= 0xFF; - goto inc_pc_loop; - } - -// 10. MULTIPLICATION & DIVISON COMMANDS - - case 0xCF: { // MUL YA - unsigned temp = y * a; - a = (uint8_t) temp; - nz = ((temp >> 1) | temp) & 0x7F; - y = temp >> 8; - nz |= y; - goto loop; - } - - case 0x9E: // DIV YA,X - { - unsigned ya = y * 0x100 + a; - - psw &= ~(h08 | v40); - - if ( y >= x ) - psw |= v40; - - if ( (y & 15) >= (x & 15) ) - psw |= h08; - - if ( y < x * 2 ) - { - a = ya / x; - y = ya - a * x; - } - else - { - a = 255 - (ya - x * 0x200) / (256 - x); - y = x + (ya - x * 0x200) % (256 - x); - } - - nz = (uint8_t) a; - a = (uint8_t) a; - - goto loop; - } - -// 11. DECIMAL COMPENSATION COMMANDS - - case 0xDF: // DAA - SUSPICIOUS_OPCODE( "DAA" ); - if ( a > 0x99 || c & 0x100 ) - { - a += 0x60; - c = 0x100; - } - - if ( (a & 0x0F) > 9 || psw & h08 ) - a += 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - - case 0xBE: // DAS - SUSPICIOUS_OPCODE( "DAS" ); - if ( a > 0x99 || !(c & 0x100) ) - { - a -= 0x60; - c = 0; - } - - if ( (a & 0x0F) > 9 || !(psw & h08) ) - a -= 0x06; - - nz = a; - a = (uint8_t) a; - goto loop; - -// 12. BRANCHING COMMANDS - - case 0x2F: // BRA rel - pc += (BOOST::int8_t) data; - goto inc_pc_loop; - - case 0x30: // BMI - BRANCH( (nz & nz_neg_mask) ) - - case 0x10: // BPL - BRANCH( !(nz & nz_neg_mask) ) - - case 0xB0: // BCS - BRANCH( c & 0x100 ) - - case 0x90: // BCC - BRANCH( !(c & 0x100) ) - - case 0x70: // BVS - BRANCH( psw & v40 ) - - case 0x50: // BVC - BRANCH( !(psw & v40) ) - - #define CBRANCH( cond )\ - {\ - pc++;\ - if ( cond )\ - goto cbranch_taken_loop;\ - rel_time -= 2;\ - goto inc_pc_loop;\ - } - - case 0x03: // BBS dp.bit,rel - case 0x23: - case 0x43: - case 0x63: - case 0x83: - case 0xA3: - case 0xC3: - case 0xE3: - CBRANCH( READ_DP( -4, data ) >> (opcode >> 5) & 1 ) - - case 0x13: // BBC dp.bit,rel - case 0x33: - case 0x53: - case 0x73: - case 0x93: - case 0xB3: - case 0xD3: - case 0xF3: - CBRANCH( !(READ_DP( -4, data ) >> (opcode >> 5) & 1) ) - - case 0xDE: // CBNE dp+X,rel - data = (uint8_t) (data + x); - // fall through - case 0x2E:{// CBNE dp,rel - int temp; - // 61% from timer - READ_DP_TIMER( -4, data, temp ); - CBRANCH( temp != a ) - } - - case 0x6E: { // DBNZ dp,rel - unsigned temp = READ_DP( -4, data ) - 1; - WRITE_DP( -3, (uint8_t) data, /*(uint8_t)*/ temp + no_read_before_write ); - CBRANCH( temp ) - } - - case 0xFE: // DBNZ Y,rel - y = (uint8_t) (y - 1); - BRANCH( y ) - - case 0x1F: // JMP [abs+X] - SET_PC( READ_PC16( pc ) + x ); - // fall through - case 0x5F: // JMP abs - SET_PC( READ_PC16( pc ) ); - goto loop; - -// 13. SUB-ROUTINE CALL RETURN COMMANDS - - case 0x0F:{// BRK - int temp; - int ret_addr = GET_PC(); - SUSPICIOUS_OPCODE( "BRK" ); - SET_PC( READ_PROG16( 0xFFDE ) ); // vector address verified - PUSH16( ret_addr ); - GET_PSW( temp ); - psw = (psw | b10) & ~i04; - PUSH( temp ); - goto loop; - } - - case 0x4F:{// PCALL offset - int ret_addr = GET_PC() + 1; - SET_PC( 0xFF00 | data ); - PUSH16( ret_addr ); - goto loop; - } - - case 0x01: // TCALL n - case 0x11: - case 0x21: - case 0x31: - case 0x41: - case 0x51: - case 0x61: - case 0x71: - case 0x81: - case 0x91: - case 0xA1: - case 0xB1: - case 0xC1: - case 0xD1: - case 0xE1: - case 0xF1: { - int ret_addr = GET_PC(); - SET_PC( READ_PROG16( 0xFFDE - (opcode >> 3) ) ); - PUSH16( ret_addr ); - goto loop; - } - -// 14. STACK OPERATION COMMANDS - - { - int temp; - case 0x7F: // RET1 - temp = *sp; - SET_PC( GET_LE16( sp + 1 ) ); - sp += 3; - goto set_psw; - case 0x8E: // POP PSW - POP( temp ); - set_psw: - SET_PSW( temp ); - goto loop; - } - - case 0x0D: { // PUSH PSW - int temp; - GET_PSW( temp ); - PUSH( temp ); - goto loop; - } - - case 0x2D: // PUSH A - PUSH( a ); - goto loop; - - case 0x4D: // PUSH X - PUSH( x ); - goto loop; - - case 0x6D: // PUSH Y - PUSH( y ); - goto loop; - - case 0xAE: // POP A - POP( a ); - goto loop; - - case 0xCE: // POP X - POP( x ); - goto loop; - - case 0xEE: // POP Y - POP( y ); - goto loop; - -// 15. BIT OPERATION COMMANDS - - case 0x02: // SET1 - case 0x22: - case 0x42: - case 0x62: - case 0x82: - case 0xA2: - case 0xC2: - case 0xE2: - case 0x12: // CLR1 - case 0x32: - case 0x52: - case 0x72: - case 0x92: - case 0xB2: - case 0xD2: - case 0xF2: { - int bit = 1 << (opcode >> 5); - int mask = ~bit; - if ( opcode & 0x10 ) - bit = 0; - data += dp; - WRITE( 0, data, (READ( -1, data ) & mask) | bit ); - goto inc_pc_loop; - } - - case 0x0E: // TSET1 abs - case 0x4E: // TCLR1 abs - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data ); - nz = (uint8_t) (a - temp); - temp &= ~a; - if ( opcode == 0x0E ) - temp |= a; - WRITE( 0, data, temp ); - } - goto loop; - - case 0x4A: // AND1 C,mem.bit - c &= MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x6A: // AND1 C,/mem.bit - c &= ~MEM_BIT( 0 ); - pc += 2; - goto loop; - - case 0x0A: // OR1 C,mem.bit - c |= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x2A: // OR1 C,/mem.bit - c |= ~MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0x8A: // EOR1 C,mem.bit - c ^= MEM_BIT( -1 ); - pc += 2; - goto loop; - - case 0xEA: // NOT1 mem.bit - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -1, data & 0x1FFF ); - temp ^= 1 << (data >> 13); - WRITE( 0, data & 0x1FFF, temp ); - } - goto loop; - - case 0xCA: // MOV1 mem.bit,C - data = READ_PC16( pc ); - pc += 2; - { - unsigned temp = READ( -2, data & 0x1FFF ); - unsigned bit = data >> 13; - temp = (temp & ~(1 << bit)) | ((c >> 8 & 1) << bit); - WRITE( 0, data & 0x1FFF, temp + no_read_before_write ); - } - goto loop; - - case 0xAA: // MOV1 C,mem.bit - c = MEM_BIT( 0 ); - pc += 2; - goto loop; - -// 16. PROGRAM PSW FLAG OPERATION COMMANDS - - case 0x60: // CLRC - c = 0; - goto loop; - - case 0x80: // SETC - c = ~0; - goto loop; - - case 0xED: // NOTC - c ^= 0x100; - goto loop; - - case 0xE0: // CLRV - psw &= ~(v40 | h08); - goto loop; - - case 0x20: // CLRP - dp = 0; - goto loop; - - case 0x40: // SETP - dp = 0x100; - goto loop; - - case 0xA0: // EI - SUSPICIOUS_OPCODE( "EI" ); - psw |= i04; - goto loop; - - case 0xC0: // DI - SUSPICIOUS_OPCODE( "DI" ); - psw &= ~i04; - goto loop; - -// 17. OTHER COMMANDS - - case 0x00: // NOP - goto loop; - - case 0xFF:{// STOP - // handle PC wrap-around - unsigned addr = GET_PC() - 1; - if ( addr >= 0x10000 ) - { - addr &= 0xFFFF; - SET_PC( addr ); - dprintf( "SPC: PC wrapped around\n" ); - goto loop; - } - } - // fall through - case 0xEF: // SLEEP - SUSPICIOUS_OPCODE( "STOP/SLEEP" ); - --pc; - rel_time = 0; - m.cpu_error = "SPC emulation error"; - goto stop; - } // switch - - assert( 0 ); // catch any unhandled instructions -} -out_of_time: - rel_time -= m.cycle_table [*pc]; // undo partial execution of opcode -stop: - - // Uncache registers - if ( GET_PC() >= 0x10000 ) - dprintf( "SPC: PC wrapped around\n" ); - m.cpu_regs.pc = (uint16_t) GET_PC(); - m.cpu_regs.sp = ( uint8_t) GET_SP(); - m.cpu_regs.a = ( uint8_t) a; - m.cpu_regs.x = ( uint8_t) x; - m.cpu_regs.y = ( uint8_t) y; - { - int temp; - GET_PSW( temp ); - m.cpu_regs.psw = (uint8_t) temp; - } -} -SPC_CPU_RUN_FUNC_END diff --git a/apu/SPC_Filter.cpp b/apu/SPC_Filter.cpp deleted file mode 100644 index b3d57708..00000000 --- a/apu/SPC_Filter.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// snes_spc 0.9.0. http://www.slack.net/~ant/ - -#include "SPC_Filter.h" - -#include - -/* Copyright (C) 2007 Shay Green. This module is free software; you -can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -module is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include "blargg_source.h" - -void SPC_Filter::clear() { memset( ch, 0, sizeof ch ); } - -SPC_Filter::SPC_Filter() -{ - gain = gain_unit; - bass = bass_norm; - clear(); -} - -void SPC_Filter::run( short* io, int count ) -{ - require( (count & 1) == 0 ); // must be even - - int const gain = this->gain; - int const bass = this->bass; - chan_t* c = &ch [2]; - do - { - // cache in registers - int sum = (--c)->sum; - int pp1 = c->pp1; - int p1 = c->p1; - - for ( int i = 0; i < count; i += 2 ) - { - // Low-pass filter (two point FIR with coeffs 0.25, 0.75) - int f = io [i] + p1; - p1 = io [i] * 3; - - // High-pass filter ("leaky integrator") - int delta = f - pp1; - pp1 = f; - int s = sum >> (gain_bits + 2); - sum += (delta * gain) - (sum >> bass); - - // Clamp to 16 bits - if ( (short) s != s ) - s = (s >> 31) ^ 0x7FFF; - - io [i] = (short) s; - } - - c->p1 = p1; - c->pp1 = pp1; - c->sum = sum; - ++io; - } - while ( c != ch ); -} diff --git a/apu/SPC_Filter.h b/apu/SPC_Filter.h deleted file mode 100644 index d5c83cb8..00000000 --- a/apu/SPC_Filter.h +++ /dev/null @@ -1,47 +0,0 @@ -// Simple low-pass and high-pass filter to better match sound output of a SNES - -// snes_spc 0.9.0 -#ifndef SPC_FILTER_H -#define SPC_FILTER_H - -#include "blargg_common.h" - -struct SPC_Filter { -public: - - // Filters count samples of stereo sound in place. Count must be a multiple of 2. - typedef short sample_t; - void run( sample_t* io, int count ); - -// Optional features - - // Clears filter to silence - void clear(); - - // Sets gain (volume), where gain_unit is normal. Gains greater than gain_unit - // are fine, since output is clamped to 16-bit sample range. - enum { gain_unit = 0x100 }; - void set_gain( int gain ); - - // Sets amount of bass (logarithmic scale) - enum { bass_none = 0 }; - enum { bass_norm = 8 }; // normal amount - enum { bass_max = 31 }; - void set_bass( int bass ); - -public: - SPC_Filter(); - BLARGG_DISABLE_NOTHROW -private: - enum { gain_bits = 8 }; - int gain; - int bass; - struct chan_t { int p1, pp1, sum; }; - chan_t ch [2]; -}; - -inline void SPC_Filter::set_gain( int g ) { gain = g; } - -inline void SPC_Filter::set_bass( int b ) { bass = b; } - -#endif diff --git a/apu/apu.cpp b/apu/apu.cpp index f6e24456..5c04cbe5 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -175,15 +175,15 @@ Nintendo Co., Limited and its subsidiary companies. ***********************************************************************************/ - #include #include "snes9x.h" #include "apu.h" #include "snapshot.h" #include "display.h" -#include "linear_resampler.h" #include "hermite_resampler.h" +#include "snes/snes.hpp" + #define APU_DEFAULT_INPUT_RATE 32000 #define APU_MINIMUM_SAMPLE_COUNT 512 #define APU_MINIMUM_SAMPLE_BLOCK 128 @@ -191,21 +191,13 @@ #define APU_DENOMINATOR_NTSC 328125 #define APU_NUMERATOR_PAL 34176 #define APU_DENOMINATOR_PAL 709379 -#define APU_DEFAULT_RESAMPLER HermiteResampler -SNES_SPC *spc_core = NULL; - -static uint8 APUROM[64] = +namespace SNES { - 0xCD, 0xEF, 0xBD, 0xE8, 0x00, 0xC6, 0x1D, 0xD0, - 0xFC, 0x8F, 0xAA, 0xF4, 0x8F, 0xBB, 0xF5, 0x78, - 0xCC, 0xF4, 0xD0, 0xFB, 0x2F, 0x19, 0xEB, 0xF4, - 0xD0, 0xFC, 0x7E, 0xF4, 0xD0, 0x0B, 0xE4, 0xF5, - 0xCB, 0xF4, 0xD7, 0x00, 0xFC, 0xD0, 0xF3, 0xAB, - 0x01, 0x10, 0xEF, 0x7E, 0xF4, 0x10, 0xEB, 0xBA, - 0xF6, 0xDA, 0x00, 0xBA, 0xF4, 0xC4, 0xF4, 0xDD, - 0x5D, 0xD0, 0xDB, 0x1F, 0x00, 0x00, 0xC0, 0xFF -}; +#include "bapu/dsp/blargg_endian.h" + + CPU cpu; +} namespace spc { @@ -227,8 +219,8 @@ namespace spc static int32 reference_time; static uint32 remainder; - static const int timing_hack_numerator = SNES_SPC::tempo_unit; - static int timing_hack_denominator = SNES_SPC::tempo_unit; + static const int timing_hack_numerator = 256; + static int timing_hack_denominator = 256; /* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup if necessary on game load. */ static uint32 ratio_numerator = APU_NUMERATOR_NTSC; @@ -239,8 +231,6 @@ static void EightBitize (uint8 *, int); static void DeStereo (uint8 *, int); static void ReverseStereo (uint8 *, int); static void UpdatePlaybackRate (void); -static void from_apu_to_state (uint8 **, void *, size_t); -static void to_apu_from_state (uint8 **, void *, size_t); static void SPCSnapshotCallback (void); static inline int S9xAPUGetClock (int32); static inline int S9xAPUGetClockRemainder (int32); @@ -354,11 +344,12 @@ int S9xGetSampleCount (void) return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1)); } +/* TODO: Attach */ void S9xFinalizeSamples (void) { if (!Settings.Mute) { - if (!spc::resampler->push((short *) spc::landing_buffer, spc_core->sample_count())) + if (!spc::resampler->push((short *) spc::landing_buffer, SNES::dsp.spc_dsp.sample_count ())) { /* We weren't able to process the entire buffer. Potential overrun. */ spc::sound_in_sync = FALSE; @@ -376,7 +367,7 @@ void S9xFinalizeSamples (void) else spc::sound_in_sync = FALSE; - spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); } void S9xLandSamples (void) @@ -452,7 +443,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) arguments. Use 2x in the resampler for buffer leveling with SoundSync */ if (!spc::resampler) { - spc::resampler = new APU_DEFAULT_RESAMPLER(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); + spc::resampler = new HermiteResampler(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); if (!spc::resampler) { delete[] spc::landing_buffer; @@ -462,7 +453,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) else spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); - spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); UpdatePlaybackRate(); @@ -473,7 +464,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms) void S9xSetSoundControl (uint8 voice_switch) { - spc_core->dsp_set_stereo_switch(voice_switch << 8 | voice_switch); + SNES::dsp.spc_dsp.set_stereo_switch (voice_switch << 8 | voice_switch); } void S9xSetSoundMute (bool8 mute) @@ -485,7 +476,8 @@ void S9xSetSoundMute (bool8 mute) void S9xDumpSPCSnapshot (void) { - spc_core->dsp_dump_spc_snapshot(); + SNES::dsp.spc_dsp.dump_spc_snapshot(); + } static void SPCSnapshotCallback (void) @@ -496,15 +488,6 @@ static void SPCSnapshotCallback (void) bool8 S9xInitAPU (void) { - spc_core = new SNES_SPC; - if (!spc_core) - return (FALSE); - - spc_core->init(); - spc_core->init_rom(APUROM); - - spc_core->dsp_set_spc_snapshot_callback(SPCSnapshotCallback); - spc::landing_buffer = NULL; spc::shrink_buffer = NULL; spc::resampler = NULL; @@ -514,12 +497,6 @@ bool8 S9xInitAPU (void) void S9xDeinitAPU (void) { - if (spc_core) - { - delete spc_core; - spc_core = NULL; - } - if (spc::resampler) { delete spc::resampler; @@ -553,12 +530,14 @@ static inline int S9xAPUGetClockRemainder (int32 cpucycles) uint8 S9xAPUReadPort (int port) { - return ((uint8) spc_core->read_port(S9xAPUGetClock(CPU.Cycles), port)); + S9xAPUExecute (); + return ((uint8) SNES::smp.port_read (port & 3)); } void S9xAPUWritePort (int port, uint8 byte) { - spc_core->write_port(S9xAPUGetClock(CPU.Cycles), port, byte); + S9xAPUExecute (); + SNES::cpu.port_write (port & 3, byte); } void S9xAPUSetReferenceTime (int32 cpucycles) @@ -568,8 +547,8 @@ void S9xAPUSetReferenceTime (int32 cpucycles) void S9xAPUExecute (void) { - /* Accumulate partial APU cycles */ - spc_core->end_frame(S9xAPUGetClock(CPU.Cycles)); + SNES::smp.clock -= S9xAPUGetClock (CPU.Cycles); + SNES::smp.enter (); spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles); @@ -579,8 +558,9 @@ void S9xAPUExecute (void) void S9xAPUEndScanline (void) { S9xAPUExecute(); + SNES::dsp.synchronize(); - if (spc_core->sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync) + if (SNES::dsp.spc_dsp.sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync) S9xLandSamples(); } @@ -589,8 +569,7 @@ void S9xAPUTimingSetSpeedup (int ticks) if (ticks != 0) printf("APU speedup hack: %d\n", ticks); - spc::timing_hack_denominator = SNES_SPC::tempo_unit - ticks; - spc_core->set_tempo(spc::timing_hack_denominator); + spc::timing_hack_denominator = 256 - ticks; spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC; spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC; @@ -599,20 +578,17 @@ void S9xAPUTimingSetSpeedup (int ticks) UpdatePlaybackRate(); } -void S9xAPUAllowTimeOverflow (bool allow) -{ - if (allow) - printf("APU time overflow allowed\n"); - - spc_core->spc_allow_time_overflow(allow); -} - void S9xResetAPU (void) { spc::reference_time = 0; spc::remainder = 0; - spc_core->reset(); - spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + + SNES::cpu.reset (); + SNES::cpu.frequency = Settings.PAL ? PAL_MASTER_CLOCK : NTSC_MASTER_CLOCK; + SNES::smp.power (); + SNES::dsp.power (); + SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback); spc::resampler->clear(); } @@ -621,44 +597,178 @@ void S9xSoftResetAPU (void) { spc::reference_time = 0; spc::remainder = 0; - spc_core->soft_reset(); - spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + SNES::cpu.reset (); + SNES::smp.reset (); + SNES::dsp.reset (); + SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); spc::resampler->clear(); } -static void from_apu_to_state (uint8 **buf, void *var, size_t size) -{ - memcpy(*buf, var, size); - *buf += size; -} - -static void to_apu_from_state (uint8 **buf, void *var, size_t size) -{ - memcpy(var, *buf, size); - *buf += size; -} - void S9xAPUSaveState (uint8 *block) { uint8 *ptr = block; - spc_core->copy_state(&ptr, from_apu_to_state); + SNES::smp.save_state (&ptr); + SNES::dsp.save_state (&ptr); - SET_LE32(ptr, spc::reference_time); + SNES::set_le32(ptr, spc::reference_time); ptr += sizeof(int32); - SET_LE32(ptr, spc::remainder); + SNES::set_le32(ptr, spc::remainder); + ptr += sizeof(int32); + SNES::set_le32(ptr, SNES::dsp.clock); + ptr += sizeof(int32); + memcpy (ptr, SNES::cpu.registers, 4); } void S9xAPULoadState (uint8 *block) { uint8 *ptr = block; - S9xResetAPU(); + SNES::smp.load_state (&ptr); + SNES::dsp.load_state (&ptr); - spc_core->copy_state(&ptr, to_apu_from_state); - - spc::reference_time = GET_LE32(ptr); + spc::reference_time = SNES::get_le32(ptr); ptr += sizeof(int32); - spc::remainder = GET_LE32(ptr); + spc::remainder = SNES::get_le32(ptr); + ptr += sizeof(int32); + SNES::dsp.clock = SNES::get_le32(ptr); + ptr += sizeof(int32); + memcpy (SNES::cpu.registers, ptr, 4); +} + +static void to_var_from_buf (uint8 **buf, void *var, size_t size) +{ + memcpy(var, *buf, size); + *buf += size; +} + +#undef IF_0_THEN_256 +#define IF_0_THEN_256( n ) ((uint8_t) ((n) - 1) + 1) +void S9xAPULoadBlarggState(uint8 *oldblock) +{ + uint8 *ptr = oldblock; + + SNES::SPC_State_Copier copier(&ptr,to_var_from_buf); + + copier.copy(SNES::smp.apuram,0x10000); // RAM + + uint8_t regs_in [0x10]; + uint8_t regs [0x10]; + uint16_t pc, spc_time, dsp_time; + uint8_t a,x,y,psw,sp; + + copier.copy(regs,0x10); // REGS + copier.copy(regs_in,0x10); // REGS_IN + + // CPU Regs + pc = copier.copy_int( 0, sizeof(uint16_t) ); + a = copier.copy_int( 0, sizeof(uint8_t) ); + x = copier.copy_int( 0, sizeof(uint8_t) ); + y = copier.copy_int( 0, sizeof(uint8_t) ); + psw = copier.copy_int( 0, sizeof(uint8_t) ); + sp = copier.copy_int( 0, sizeof(uint8_t) ); + copier.extra(); + + // times + spc_time = copier.copy_int( 0, sizeof(uint16_t) ); + dsp_time = copier.copy_int( 0, sizeof(uint16_t) ); + + int cur_time = S9xAPUGetClock(CPU.Cycles); + + // spc_time is absolute, dsp_time is relative + // smp.clock is relative, dsp.clock relative but counting upwards + SNES::smp.clock = spc_time - cur_time; + SNES::dsp.clock = -1 * dsp_time; + + // DSP + SNES::dsp.load_state(&ptr); + + // Timers + uint16_t next_time[3]; + uint8_t divider[3], counter[3]; + for ( int i = 0; i < 3; i++ ) + { + next_time[i] = copier.copy_int( 0, sizeof(uint16_t) ); + divider[i] = copier.copy_int( 0, sizeof(uint8_t) ); + counter[i] = copier.copy_int( 0, sizeof(uint8_t) ); + copier.extra(); + } + // construct timers out of available parts from blargg smp + SNES::smp.timer0.enable = regs[1] >> 0 & 1; // regs[1] = CONTROL + SNES::smp.timer0.target = IF_0_THEN_256(regs[10]); // regs[10+i] = TiTARGET + // blargg counts time, get ticks through timer frequency + // (assume tempo = 256) + SNES::smp.timer0.stage1_ticks = 128 - (next_time[0] - cur_time) / 128; + SNES::smp.timer0.stage2_ticks = divider[0]; + SNES::smp.timer0.stage3_ticks = counter[0]; + + SNES::smp.timer1.enable = regs[1] >> 1 & 1; + SNES::smp.timer1.target = IF_0_THEN_256(regs[11]); + SNES::smp.timer1.stage1_ticks = 128 - (next_time[1] - cur_time) / 128; + SNES::smp.timer1.stage2_ticks = divider[0]; + SNES::smp.timer1.stage3_ticks = counter[0]; + + SNES::smp.timer2.enable = regs[1] >> 2 & 1; + SNES::smp.timer2.target = IF_0_THEN_256(regs[12]); + SNES::smp.timer2.stage1_ticks = 16 - (next_time[2] - cur_time) / 16; + SNES::smp.timer2.stage2_ticks = divider[0]; + SNES::smp.timer2.stage3_ticks = counter[0]; + + copier.extra(); + + SNES::smp.opcode_number = 0; + SNES::smp.opcode_cycle = 0; + + SNES::smp.regs.pc = pc; + SNES::smp.regs.sp = sp; + SNES::smp.regs.a = a; + SNES::smp.regs.x = x; + SNES::smp.regs.y = y; + + // blargg's psw has same layout as byuu's flags + SNES::smp.regs.p = psw; + + // blargg doesn't explicitly store iplrom_enable + SNES::smp.status.iplrom_enable = regs[1] & 0x80; + + SNES::smp.status.dsp_addr = regs[2]; + + SNES::smp.status.ram00f8 = regs_in[8]; + SNES::smp.status.ram00f9 = regs_in[9]; + + // default to 0 - we are on an opcode boundary, shouldn't matter + SNES::smp.rd=SNES::smp.wr=SNES::smp.dp=SNES::smp.sp=SNES::smp.ya=SNES::smp.bit=0; + + spc::reference_time = SNES::get_le32(ptr); + ptr += sizeof(int32); + spc::remainder = SNES::get_le32(ptr); + ptr += sizeof(int32); + + // blargg stores CPUIx in regs_in + memcpy (SNES::cpu.registers, regs_in + 4, 4); +} + +bool8 S9xSPCDump (const char *filename) +{ + FILE *fs; + uint8 buf[SPC_FILE_SIZE]; + size_t ignore; + + fs = fopen(filename, "wb"); + if (!fs) + return (FALSE); + + S9xSetSoundMute(TRUE); + + SNES::smp.save_spc (buf); + + if ((ignore = fwrite(buf, SPC_FILE_SIZE, 1, fs)) <= 0) + fprintf (stderr, "Couldn't write file %s.\n", filename); + + fclose(fs); + + S9xSetSoundMute(FALSE); + + return (TRUE); } diff --git a/apu/apu.h b/apu/apu.h index 358469da..61575dae 100644 --- a/apu/apu.h +++ b/apu/apu.h @@ -180,11 +180,11 @@ #define _APU_H_ #include "snes9x.h" -#include "SNES_SPC.h" typedef void (*apu_callback) (void *); -#define SPC_SAVE_STATE_BLOCK_SIZE (SNES_SPC::state_size + 8) +#define SPC_SAVE_STATE_BLOCK_SIZE (1024 * 65) +#define SPC_FILE_SIZE (66048) bool8 S9xInitAPU (void); void S9xDeinitAPU (void); @@ -198,8 +198,10 @@ void S9xAPUSetReferenceTime (int32); void S9xAPUTimingSetSpeedup (int); void S9xAPUAllowTimeOverflow (bool); void S9xAPULoadState (uint8 *); +void S9xAPULoadBlarggState(uint8 *oldblock); void S9xAPUSaveState (uint8 *); void S9xDumpSPCSnapshot (void); +bool8 S9xSPCDump (const char *); bool8 S9xInitSound (int, int); bool8 S9xOpenSoundDevice (void); @@ -214,6 +216,4 @@ void S9xClearSamples (void); bool8 S9xMixSamples (uint8 *, int); void S9xSetSamplesAvailableCallback (apu_callback, void *); -extern SNES_SPC *spc_core; - #endif diff --git a/apu/SPC_DSP.cpp b/apu/bapu/dsp/SPC_DSP.cpp similarity index 97% rename from apu/SPC_DSP.cpp rename to apu/bapu/dsp/SPC_DSP.cpp index e6ba49ed..aa036c09 100644 --- a/apu/SPC_DSP.cpp +++ b/apu/bapu/dsp/SPC_DSP.cpp @@ -132,7 +132,7 @@ inline int SPC_DSP::interpolate( voice_t const* v ) int offset = v->interp_pos >> 4 & 0xFF; short const* fwd = gauss + 255 - offset; short const* rev = gauss + offset; // mirror left half of gaussian - + int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos]; int out; out = (fwd [ 0] * in [0]) >> 11; @@ -140,7 +140,7 @@ inline int SPC_DSP::interpolate( voice_t const* v ) out += (rev [256] * in [2]) >> 11; out = (int16_t) out; out += (rev [ 0] * in [3]) >> 11; - + CLAMP16( out ); out &= ~1; return out; @@ -262,13 +262,13 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) } } } - + // Sustain level if ( (env >> 8) == (env_data >> 5) && v->env_mode == env_decay ) v->env_mode = env_sustain; - + v->hidden_env = env; - + // unsigned cast because linear decrease going negative also triggers this if ( (unsigned) env > 0x7FF ) { @@ -276,7 +276,7 @@ inline void SPC_DSP::run_envelope( voice_t* const v ) if ( v->env_mode == env_attack ) v->env_mode = env_decay; } - + if ( !read_counter( rate ) ) v->env = env; // nothing else is controlled by the counter } @@ -289,27 +289,27 @@ inline void SPC_DSP::decode_brr( voice_t* v ) { // Arrange the four input nybbles in 0xABCD order for easy decoding int nybbles = m.t_brr_byte * 0x100 + m.ram [(v->brr_addr + v->brr_offset + 1) & 0xFFFF]; - + int const header = m.t_brr_header; - + // Write to next four samples in circular buffer int* pos = &v->buf [v->buf_pos]; int* end; if ( (v->buf_pos += 4) >= brr_buf_size ) v->buf_pos = 0; - + // Decode four samples for ( end = pos + 4; pos < end; pos++, nybbles <<= 4 ) { // Extract nybble and sign-extend int s = (int16_t) nybbles >> 12; - + // Shift sample based on header int const shift = header >> 4; s = (s << shift) >> 1; if ( shift >= 0xD ) // handle invalid range s = (s >> 25) << 11; // same as: s = (s < 0 ? -0x800 : 0) - + // Apply IIR filter (8 is the most commonly used) int const filter = header & 0x0C; int const p1 = pos [brr_buf_size - 1]; @@ -334,7 +334,7 @@ inline void SPC_DSP::decode_brr( voice_t* v ) s += p1 >> 1; s += (-p1) >> 5; } - + // Adjust and write sample CLAMP16( s ); s = (int16_t) (s * 2); @@ -367,11 +367,11 @@ MISC_CLOCK( 30 ) if ( m.every_other_sample ) { m.kon = m.new_kon; - m.t_koff = REG(koff) | m.mute_mask; + m.t_koff = REG(koff) | m.mute_mask; } - + run_counters(); - + // Noise if ( !read_counter( REG(flg) & 0x1F ) ) { @@ -397,9 +397,9 @@ inline VOICE_CLOCK( V2 ) if ( !v->kon_delay ) entry += 2; m.t_brr_next_addr = GET_LE16A( entry ); - + m.t_adsr0 = VREG(v->regs,adsr0); - + // Read pitch, spread over two clocks m.t_pitch = VREG(v->regs,pitchl); } @@ -418,7 +418,7 @@ VOICE_CLOCK( V3c ) // Pitch modulation using previous voice's output if ( m.t_pmon & v->vbit ) m.t_pitch += ((m.t_output >> 5) * m.t_pitch) >> 10; - + if ( v->kon_delay ) { // Get ready to start BRR decoding on next sample @@ -437,46 +437,46 @@ VOICE_CLOCK( V3c ) spc_snapshot_callback(); } } - + // Envelope is never run during KON v->env = 0; v->hidden_env = 0; - + // Disable BRR decoding until last three samples v->interp_pos = 0; if ( --v->kon_delay & 3 ) v->interp_pos = 0x4000; - + // Pitch is never added during KON m.t_pitch = 0; } - + // Gaussian interpolation { int output = interpolate( v ); - + // Noise if ( m.t_non & v->vbit ) output = (int16_t) (m.noise * 2); - + // Apply envelope m.t_output = (output * v->env) >> 11 & ~1; v->t_envx_out = (uint8_t) (v->env >> 4); } - + // Immediate silence due to end of sample or soft reset if ( REG(flg) & 0x80 || (m.t_brr_header & 3) == 1 ) { v->env_mode = env_release; v->env = 0; } - + if ( m.every_other_sample ) { // KOFF if ( m.t_koff & v->vbit ) v->env_mode = env_release; - + // KON if ( m.kon & v->vbit ) { @@ -484,7 +484,7 @@ VOICE_CLOCK( V3c ) v->env_mode = env_attack; } } - + // Run envelope for next sample if ( !v->kon_delay ) run_envelope( v ); @@ -499,7 +499,7 @@ inline void SPC_DSP::voice_output( voice_t const* v, int ch ) // Add to output total m.t_main_out [ch] += amp; CLAMP16( m.t_main_out [ch] ); - + // Optionally add to echo total if ( m.t_eon & v->vbit ) { @@ -514,7 +514,7 @@ VOICE_CLOCK( V4 ) if ( v->interp_pos >= 0x4000 ) { decode_brr( v ); - + if ( (v->brr_offset += 2) >= brr_block_size ) { // Start decoding next BRR block @@ -528,14 +528,14 @@ VOICE_CLOCK( V4 ) v->brr_offset = 1; } } - + // Apply pitch v->interp_pos = (v->interp_pos & 0x3FFF) + m.t_pitch; - + // Keep from getting too far ahead (when using pitch modulation) if ( v->interp_pos > 0x7FFF ) v->interp_pos = 0x7FFF; - + // Output left voice_output( v, 0 ); } @@ -543,10 +543,10 @@ inline VOICE_CLOCK( V5 ) { // Output right voice_output( v, 1 ); - + // ENDX, OUTX, and ENVX won't update if you wrote to them 1-2 clocks earlier int endx_buf = REG(endx) | m.t_looped; - + // Clear bit in ENDX if KON just began if ( v->kon_delay == 5 ) endx_buf &= ~v->vbit; @@ -561,7 +561,7 @@ inline VOICE_CLOCK( V7 ) { // Update ENDX REG(endx) = m.endx_buf; - + m.envx_buf = v->t_envx_out; } inline VOICE_CLOCK( V8 ) @@ -605,11 +605,7 @@ VOICE_CLOCK(V9_V6_V3) { voice_V9(v); voice_V6(v+1); voice_V3(v+2); } inline void SPC_DSP::echo_read( int ch ) { - int s; - if ( m.t_echo_ptr >= 0xffc0 && rom_enabled ) - s = GET_LE16SA( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0] ); - else - s = GET_LE16SA( ECHO_PTR( ch ) ); + int s = GET_LE16SA( ECHO_PTR( ch ) ); // second copy simplifies wrap-around handling ECHO_FIR( 0 ) [ch] = ECHO_FIR( 8 ) [ch] = s >> 1; } @@ -619,14 +615,14 @@ ECHO_CLOCK( 22 ) // History if ( ++m.echo_hist_pos >= &m.echo_hist [echo_hist_size] ) m.echo_hist_pos = m.echo_hist; - + m.t_echo_ptr = (m.t_esa * 0x100 + m.echo_offset) & 0xFFFF; echo_read( 0 ); - + // FIR (using l and r temporaries below helps compiler optimize) int l = CALC_FIR( 0, 0 ); int r = CALC_FIR( 0, 1 ); - + m.t_echo_in [0] = l; m.t_echo_in [1] = r; } @@ -634,17 +630,17 @@ ECHO_CLOCK( 23 ) { int l = CALC_FIR( 1, 0 ) + CALC_FIR( 2, 0 ); int r = CALC_FIR( 1, 1 ) + CALC_FIR( 2, 1 ); - + m.t_echo_in [0] += l; m.t_echo_in [1] += r; - + echo_read( 1 ); } ECHO_CLOCK( 24 ) { int l = CALC_FIR( 3, 0 ) + CALC_FIR( 4, 0 ) + CALC_FIR( 5, 0 ); int r = CALC_FIR( 3, 1 ) + CALC_FIR( 4, 1 ) + CALC_FIR( 5, 1 ); - + m.t_echo_in [0] += l; m.t_echo_in [1] += r; } @@ -652,16 +648,16 @@ ECHO_CLOCK( 25 ) { int l = m.t_echo_in [0] + CALC_FIR( 6, 0 ); int r = m.t_echo_in [1] + CALC_FIR( 6, 1 ); - + l = (int16_t) l; r = (int16_t) r; - + l += (int16_t) CALC_FIR( 7, 0 ); r += (int16_t) CALC_FIR( 7, 1 ); - + CLAMP16( l ); CLAMP16( r ); - + m.t_echo_in [0] = l & ~1; m.t_echo_in [1] = r & ~1; } @@ -677,14 +673,14 @@ ECHO_CLOCK( 26 ) // Left output volumes // (save sample for next clock so we can output both together) m.t_main_out [0] = echo_output( 0 ); - + // Echo feedback int l = m.t_echo_out [0] + (int16_t) ((m.t_echo_in [0] * (int8_t) REG(efb)) >> 7); int r = m.t_echo_out [1] + (int16_t) ((m.t_echo_in [1] * (int8_t) REG(efb)) >> 7); - + CLAMP16( l ); CLAMP16( r ); - + m.t_echo_out [0] = l & ~1; m.t_echo_out [1] = r & ~1; } @@ -695,7 +691,7 @@ ECHO_CLOCK( 27 ) int r = echo_output( 1 ); m.t_main_out [0] = 0; m.t_main_out [1] = 0; - + // TODO: global muting isn't this simple (turns DAC on and off // or something, causing small ~37-sample pulse when first muted) if ( REG(flg) & 0x40 ) @@ -703,7 +699,7 @@ ECHO_CLOCK( 27 ) l = 0; r = 0; } - + // Output sample to DAC #ifdef SPC_DSP_OUT_HOOK SPC_DSP_OUT_HOOK( l, r ); @@ -720,29 +716,24 @@ ECHO_CLOCK( 28 ) inline void SPC_DSP::echo_write( int ch ) { if ( !(m.t_echo_enabled & 0x20) ) - { - if ( m.t_echo_ptr >= 0xffc0 && rom_enabled ) - SET_LE16A( &hi_ram [m.t_echo_ptr + ch * 2 - 0xffc0], m.t_echo_out [ch] ); - else - SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); - } + SET_LE16A( ECHO_PTR( ch ), m.t_echo_out [ch] ); m.t_echo_out [ch] = 0; } ECHO_CLOCK( 29 ) { m.t_esa = REG(esa); - + if ( !m.echo_offset ) m.echo_length = (REG(edl) & 0x0F) * 0x800; - + m.echo_offset += 4; if ( m.echo_offset >= m.echo_length ) m.echo_offset = 0; - + // Write left echo echo_write( 0 ); - + m.t_echo_enabled = REG(flg); } ECHO_CLOCK( 30 ) @@ -805,17 +796,17 @@ PHASE(31) V(V4,0) V(V1,2)\ void SPC_DSP::run( int clocks_remain ) { require( clocks_remain > 0 ); - + int const phase = m.phase; m.phase = (phase + clocks_remain) & 31; switch ( phase ) { loop: - + #define PHASE( n ) if ( n && !--clocks_remain ) break; case n: GEN_DSP_TIMING #undef PHASE - + if ( --clocks_remain ) goto loop; } @@ -841,15 +832,15 @@ void SPC_DSP::init( void* ram_64k ) #ifndef NDEBUG // be sure this sign-extends assert( (int16_t) 0x8000 == -0x8000 ); - + // be sure right shift preserves sign assert( (-1 >> 1) == -1 ); - + // check clamp macro int i; i = +0x8000; CLAMP16( i ); assert( i == +0x7FFF ); i = -0x8001; CLAMP16( i ); assert( i == -0x8000 ); - + blargg_verify_byte_order(); #endif } @@ -857,13 +848,13 @@ void SPC_DSP::init( void* ram_64k ) void SPC_DSP::soft_reset_common() { require( m.ram ); // init() must have been called already - + m.noise = 0x4000; m.echo_hist_pos = m.echo_hist; m.every_other_sample = 1; m.echo_offset = 0; m.phase = 0; - + init_counter(); for (int i = 0; i < voice_count; i++) @@ -880,7 +871,7 @@ void SPC_DSP::load( uint8_t const regs [register_count] ) { memcpy( m.regs, regs, sizeof m.regs ); memset( &m.regs [register_count], 0, offsetof (state_t,ram) - register_count ); - + // Internal state for ( int i = voice_count; --i >= 0; ) { @@ -892,7 +883,7 @@ void SPC_DSP::load( uint8_t const regs [register_count] ) m.new_kon = REG(kon); m.t_dir = REG(dir); m.t_esa = REG(esa); - + soft_reset_common(); } @@ -945,18 +936,18 @@ void SPC_State_Copier::extra() void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) { SPC_State_Copier copier( io, copy ); - + // DSP registers copier.copy( m.regs, register_count ); - + // Internal state - + // Voices int i; for ( i = 0; i < voice_count; i++ ) { voice_t* v = &m.voices [i]; - + // BRR buffer int i; for ( i = 0; i < brr_buf_size; i++ ) @@ -965,7 +956,7 @@ void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) SPC_COPY( int16_t, s ); v->buf [i] = v->buf [i + brr_buf_size] = s; } - + SPC_COPY( uint16_t, v->interp_pos ); SPC_COPY( uint16_t, v->brr_addr ); SPC_COPY( uint16_t, v->env ); @@ -979,10 +970,10 @@ void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) v->env_mode = (enum env_mode_t) m; } SPC_COPY( uint8_t, v->t_envx_out ); - + copier.extra(); } - + // Echo history for ( i = 0; i < echo_hist_size; i++ ) { @@ -996,28 +987,28 @@ void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) } m.echo_hist_pos = m.echo_hist; memcpy( &m.echo_hist [echo_hist_size], m.echo_hist, echo_hist_size * sizeof m.echo_hist [0] ); - + // Misc SPC_COPY( uint8_t, m.every_other_sample ); SPC_COPY( uint8_t, m.kon ); - + SPC_COPY( uint16_t, m.noise ); SPC_COPY( uint16_t, m.counter ); SPC_COPY( uint16_t, m.echo_offset ); SPC_COPY( uint16_t, m.echo_length ); SPC_COPY( uint8_t, m.phase ); - + SPC_COPY( uint8_t, m.new_kon ); SPC_COPY( uint8_t, m.endx_buf ); SPC_COPY( uint8_t, m.envx_buf ); SPC_COPY( uint8_t, m.outx_buf ); - + SPC_COPY( uint8_t, m.t_pmon ); SPC_COPY( uint8_t, m.t_non ); SPC_COPY( uint8_t, m.t_eon ); SPC_COPY( uint8_t, m.t_dir ); SPC_COPY( uint8_t, m.t_koff ); - + SPC_COPY( uint16_t, m.t_brr_next_addr ); SPC_COPY( uint8_t, m.t_adsr0 ); SPC_COPY( uint8_t, m.t_brr_header ); @@ -1025,20 +1016,20 @@ void SPC_DSP::copy_state( unsigned char** io, copy_func_t copy ) SPC_COPY( uint8_t, m.t_srcn ); SPC_COPY( uint8_t, m.t_esa ); SPC_COPY( uint8_t, m.t_echo_enabled ); - + SPC_COPY( int16_t, m.t_main_out [0] ); SPC_COPY( int16_t, m.t_main_out [1] ); SPC_COPY( int16_t, m.t_echo_out [0] ); SPC_COPY( int16_t, m.t_echo_out [1] ); SPC_COPY( int16_t, m.t_echo_in [0] ); SPC_COPY( int16_t, m.t_echo_in [1] ); - + SPC_COPY( uint16_t, m.t_dir_addr ); SPC_COPY( uint16_t, m.t_pitch ); SPC_COPY( int16_t, m.t_output ); SPC_COPY( uint16_t, m.t_echo_ptr ); SPC_COPY( uint8_t, m.t_looped ); - + copier.extra(); } #endif diff --git a/apu/SPC_DSP.h b/apu/bapu/dsp/SPC_DSP.h similarity index 98% rename from apu/SPC_DSP.h rename to apu/bapu/dsp/SPC_DSP.h index 61d05ab5..ca61cc95 100644 --- a/apu/SPC_DSP.h +++ b/apu/bapu/dsp/SPC_DSP.h @@ -11,7 +11,7 @@ extern "C" { typedef void (*dsp_copy_func_t)( unsigned char** io, void* state, s class SPC_DSP { public: typedef BOOST::uint8_t uint8_t; - + // Setup // Initializes DSP and has it use the 64K RAM provided @@ -34,7 +34,7 @@ public: // Emulates pressing reset switch on SNES void soft_reset(); - + // Reads/writes DSP registers. For accuracy, you must first call run() // to catch the DSP up to present. int read ( int addr ) const; @@ -43,7 +43,7 @@ public: // Runs DSP for specified number of clocks (~1024000 per second). Every 32 clocks // a pair of samples is be generated. void run( int clock_count ); - + // Sound control // Mutes voices corresponding to non-zero bits in mask (issues repeated KOFF events). @@ -52,7 +52,7 @@ public: void mute_voices( int mask ); // State - + // Resets DSP and uses supplied values to initialize registers enum { register_count = 128 }; void load( uint8_t const regs [register_count] ); @@ -69,8 +69,6 @@ public: int stereo_switch; int take_spc_snapshot; - int rom_enabled; // mirror - uint8_t *rom, *hi_ram; // mirror void (*spc_snapshot_callback) (void); void set_spc_snapshot_callback( void (*callback) (void) ); @@ -110,12 +108,12 @@ public: void disable_surround( bool ) { } // not supported public: BLARGG_DISABLE_NOTHROW - + typedef BOOST::int8_t int8_t; typedef BOOST::int16_t int16_t; - + enum { echo_hist_size = 8 }; - + enum env_mode_t { env_release, env_attack, env_decay, env_sustain }; enum { brr_buf_size = 12 }; struct voice_t @@ -136,15 +134,15 @@ public: }; private: enum { brr_block_size = 9 }; - + struct state_t { uint8_t regs [register_count]; - + // Echo history keeps most recent 8 samples (twice the size to simplify wrap handling) int echo_hist [echo_hist_size * 2] [2]; int (*echo_hist_pos) [2]; // &echo_hist [0 to 7] - + int every_other_sample; // toggles every sample int kon; // KON value when last checked int noise; @@ -153,22 +151,22 @@ private: int echo_length; // number of bytes that echo_offset will stop at int phase; // next clock cycle to run (0-31) bool kon_check; // set when a new KON occurs - + // Hidden registers also written to when main register is written to int new_kon; uint8_t endx_buf; uint8_t envx_buf; uint8_t outx_buf; - + // Temporary state between clocks - + // read once per sample int t_pmon; int t_non; int t_eon; int t_dir; int t_koff; - + // read a few clocks ahead then used int t_brr_next_addr; int t_adsr0; @@ -177,21 +175,21 @@ private: int t_srcn; int t_esa; int t_echo_enabled; - + // internal state that is recalculated every sample int t_dir_addr; int t_pitch; int t_output; int t_looped; int t_echo_ptr; - + // left/right sums int t_main_out [2]; int t_echo_out [2]; int t_echo_in [2]; - + voice_t voices [voice_count]; - + // non-emulation state uint8_t* ram; // 64K shared RAM between DSP and SMP int mute_mask; @@ -201,11 +199,11 @@ private: sample_t extra [extra_size]; }; state_t m; - + void init_counter(); void run_counters(); unsigned read_counter( int rate ); - + int interpolate( voice_t const* v ); void run_envelope( voice_t* const v ); void decode_brr( voice_t* v ); @@ -244,7 +242,7 @@ private: void echo_28(); void echo_29(); void echo_30(); - + void soft_reset_common(); }; @@ -261,22 +259,22 @@ inline int SPC_DSP::read( int addr ) const inline void SPC_DSP::write( int addr, int data ) { assert( (unsigned) addr < register_count ); - + m.regs [addr] = (uint8_t) data; switch ( addr & 0x0F ) { case v_envx: m.envx_buf = (uint8_t) data; break; - + case v_outx: m.outx_buf = (uint8_t) data; break; - + case 0x0C: if ( addr == r_kon ) m.new_kon = (uint8_t) data; - + if ( addr == r_endx ) // always cleared, regardless of data written { m.endx_buf = 0; diff --git a/apu/blargg_common.h b/apu/bapu/dsp/blargg_common.h similarity index 100% rename from apu/blargg_common.h rename to apu/bapu/dsp/blargg_common.h diff --git a/apu/blargg_config.h b/apu/bapu/dsp/blargg_config.h similarity index 96% rename from apu/blargg_config.h rename to apu/bapu/dsp/blargg_config.h index 9dc69db8..d85d2663 100644 --- a/apu/blargg_config.h +++ b/apu/bapu/dsp/blargg_config.h @@ -5,7 +5,7 @@ #define BLARGG_CONFIG_H // Uncomment to disable debugging checks -//#define NDEBUG 1 +#define NDEBUG 1 // Uncomment to enable platform-specific (and possibly non-portable) optimizations //#define BLARGG_NONPORTABLE 1 diff --git a/apu/blargg_endian.h b/apu/bapu/dsp/blargg_endian.h similarity index 100% rename from apu/blargg_endian.h rename to apu/bapu/dsp/blargg_endian.h diff --git a/apu/blargg_source.h b/apu/bapu/dsp/blargg_source.h similarity index 100% rename from apu/blargg_source.h rename to apu/bapu/dsp/blargg_source.h diff --git a/apu/bapu/dsp/sdsp.cpp b/apu/bapu/dsp/sdsp.cpp new file mode 100644 index 00000000..0fe01476 --- /dev/null +++ b/apu/bapu/dsp/sdsp.cpp @@ -0,0 +1,50 @@ +#include + +#define DSP_CPP +namespace SNES { + +DSP dsp; + +#include "SPC_DSP.cpp" + +void DSP::power() +{ + spc_dsp.init(smp.apuram); + spc_dsp.reset(); + clock = 0; +} + +void DSP::reset() +{ + spc_dsp.soft_reset(); + clock = 0; +} + +static void from_dsp_to_state (uint8 **buf, void *var, size_t size) +{ + memcpy(*buf, var, size); + *buf += size; +} + +static void to_dsp_from_state (uint8 **buf, void *var, size_t size) +{ + memcpy(var, *buf, size); + *buf += size; +} + +void DSP::save_state (uint8 **ptr) +{ + spc_dsp.copy_state(ptr, from_dsp_to_state); +} + +void DSP::load_state (uint8 **ptr) +{ + spc_dsp.copy_state(ptr, to_dsp_from_state); +} + +DSP::DSP() +{ + clock = 0; +} + +} diff --git a/apu/bapu/dsp/sdsp.hpp b/apu/bapu/dsp/sdsp.hpp new file mode 100644 index 00000000..baf1e88b --- /dev/null +++ b/apu/bapu/dsp/sdsp.hpp @@ -0,0 +1,34 @@ +#include "SPC_DSP.h" +#include + +class DSP : public Processor { +public: + inline uint8 read(uint8 addr) { + synchronize (); + return spc_dsp.read(addr); + } + + inline void synchronize (void) { + if (clock) { + spc_dsp.run (clock); + clock = 0; + } + } + + inline void write(uint8 addr, uint8 data) { + synchronize (); + spc_dsp.write(addr, data); + } + + void save_state(uint8 **); + void load_state(uint8 **); + + void power(); + void reset(); + + DSP(); + + SPC_DSP spc_dsp; +}; + +extern DSP dsp; diff --git a/apu/bapu/smp/algorithms.cpp b/apu/bapu/smp/algorithms.cpp new file mode 100644 index 00000000..a55369fb --- /dev/null +++ b/apu/bapu/smp/algorithms.cpp @@ -0,0 +1,122 @@ +uint8 SMP::op_adc(uint8 x, uint8 y) { + int r = x + y + regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = ~(x ^ y) & (x ^ r) & 0x80; + regs.p.h = (x ^ y ^ r) & 0x10; + regs.p.z = (uint8)r == 0; + regs.p.c = r > 0xff; + return r; +} + +uint16 SMP::op_addw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 0; + r = op_adc(x, y); + r |= op_adc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_and(uint8 x, uint8 y) { + x &= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_cmp(uint8 x, uint8 y) { + int r = x - y; + regs.p.n = r & 0x80; + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint16 SMP::op_cmpw(uint16 x, uint16 y) { + int r = x - y; + regs.p.n = r & 0x8000; + regs.p.z = (uint16)r == 0; + regs.p.c = r >= 0; + return x; +} + +uint8 SMP::op_eor(uint8 x, uint8 y) { + x ^= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_or(uint8 x, uint8 y) { + x |= y; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_sbc(uint8 x, uint8 y) { + int r = x - y - !regs.p.c; + regs.p.n = r & 0x80; + regs.p.v = (x ^ y) & (x ^ r) & 0x80; + regs.p.h = !((x ^ y ^ r) & 0x10); + regs.p.z = (uint8)r == 0; + regs.p.c = r >= 0; + return r; +} + +uint16 SMP::op_subw(uint16 x, uint16 y) { + uint16 r; + regs.p.c = 1; + r = op_sbc(x, y); + r |= op_sbc(x >> 8, y >> 8) << 8; + regs.p.z = r == 0; + return r; +} + +uint8 SMP::op_inc(uint8 x) { + x++; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_dec(uint8 x) { + x--; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_asl(uint8 x) { + regs.p.c = x & 0x80; + x <<= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_lsr(uint8 x) { + regs.p.c = x & 0x01; + x >>= 1; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_rol(uint8 x) { + unsigned carry = (unsigned)regs.p.c; + regs.p.c = x & 0x80; + x = (x << 1) | carry; + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} + +uint8 SMP::op_ror(uint8 x) { + unsigned carry = (unsigned)regs.p.c << 7; + regs.p.c = x & 0x01; + x = carry | (x >> 1); + regs.p.n = x & 0x80; + regs.p.z = x == 0; + return x; +} diff --git a/apu/bapu/smp/core.cpp b/apu/bapu/smp/core.cpp new file mode 100644 index 00000000..43234f6a --- /dev/null +++ b/apu/bapu/smp/core.cpp @@ -0,0 +1,142 @@ +void SMP::tick() { + timer0.tick(); + timer1.tick(); + timer2.tick(); + +#ifndef SNES9X + clock += cycle_step_cpu; + dsp.clock -= 24; + synchronize_dsp(); +#else + clock++; + dsp.clock++; +#endif +} + +void SMP::tick(unsigned clocks) { + timer0.tick(clocks); + timer1.tick(clocks); + timer2.tick(clocks); + + clock += clocks; + dsp.clock += clocks; +} + +void SMP::op_io() { + #if defined(CYCLE_ACCURATE) + tick(); + #endif +} + +void SMP::op_io(unsigned clocks) { + tick(clocks); +} + +uint8 SMP::op_read(uint16 addr) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) return mmio_read(addr); + if(addr >= 0xffc0 && status.iplrom_enable) return iplrom[addr & 0x3f]; + return apuram[addr]; +} + +void SMP::op_write(uint16 addr, uint8 data) { + #if defined(CYCLE_ACCURATE) + tick(); + #endif + if((addr & 0xfff0) == 0x00f0) mmio_write(addr, data); + apuram[addr] = data; //all writes go to RAM, even MMIO writes +} + +void SMP::op_step() { + #define op_readpc() op_read(regs.pc++) + #define op_readdp(addr) op_read((regs.p.p << 8) + addr) + #define op_writedp(addr, data) op_write((regs.p.p << 8) + addr, data) + #define op_readaddr(addr) op_read(addr) + #define op_writeaddr(addr, data) op_write(addr, data) + #define op_readstack() op_read(0x0100 | ++regs.sp) + #define op_writestack(data) op_write(0x0100 | regs.sp--, data) + + #if defined(CYCLE_ACCURATE) + #if defined(PSEUDO_CYCLE) + + if(opcode_cycle == 0) + opcode_number = op_readpc(); + + switch(opcode_number) { + #include "core/oppseudo_misc.cpp" + #include "core/oppseudo_mov.cpp" + #include "core/oppseudo_pc.cpp" + #include "core/oppseudo_read.cpp" + #include "core/oppseudo_rmw.cpp" + } + + #else + + if(opcode_cycle == 0) { + opcode_number = op_readpc(); + opcode_cycle++; + } else switch(opcode_number) { + #include "core/opcycle_misc.cpp" + #include "core/opcycle_mov.cpp" + #include "core/opcycle_pc.cpp" + #include "core/opcycle_read.cpp" + #include "core/opcycle_rmw.cpp" + } + + #endif // defined(PSEUDO_CYCLE) + #else + + unsigned opcode = op_readpc(); + switch(opcode) { + #include "core/op_misc.cpp" + #include "core/op_mov.cpp" + #include "core/op_pc.cpp" + #include "core/op_read.cpp" + #include "core/op_rmw.cpp" + } + + //TODO: untaken branches should consume less cycles + + timer0.tick(cycle_count_table[opcode]); + timer1.tick(cycle_count_table[opcode]); + timer2.tick(cycle_count_table[opcode]); + +#ifndef SNES9X + clock += cycle_table_cpu[opcode]; + dsp.clock -= cycle_table_dsp[opcode]; + synchronize_dsp(); +#else + clock += cycle_count_table[opcode]; + dsp.clock += cycle_count_table[opcode]; +#endif + + #endif // defined(CYCLE_ACCURATE) +} + +const unsigned SMP::cycle_count_table[256] = { + #define c 12 +//0 1 2 3 4 5 6 7 8 9 A B C D E F + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,6,8, //0 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,4,6, //1 + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,4,7,4, //2 + 4,8,4,7, 4,5,5,6, 5,5,6,5, 2,2,3,8, //3 + + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,6,6, //4 + 4,8,4,7, 4,5,5,6, 5,5,4,5, 2,2,4,3, //5 + 2,8,4,7, 3,4,3,6, 2,6,4,4, 5,4,7,5, //6 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,6, //7 + + 2,8,4,7, 3,4,3,6, 2,6,5,4, 5,2,4,5, //8 + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,c,5, //9 + 3,8,4,7, 3,4,3,6, 2,6,4,4, 5,2,4,4, //A + 4,8,4,7, 4,5,5,6, 5,5,5,5, 2,2,3,4, //B + + 3,8,4,7, 4,5,4,7, 2,5,6,4, 5,2,4,9, //C + 4,8,4,7, 5,6,6,7, 4,5,5,5, 2,2,8,3, //D + 2,8,4,7, 3,4,3,6, 2,4,5,3, 4,3,4,1, //E + 4,8,4,7, 4,5,5,6, 3,4,5,4, 2,2,6,1, //F + + #undef c +}; diff --git a/apu/bapu/smp/core/cc.sh b/apu/bapu/smp/core/cc.sh new file mode 100755 index 00000000..937b7139 --- /dev/null +++ b/apu/bapu/smp/core/cc.sh @@ -0,0 +1 @@ +g++-4.5 -std=gnu++0x -I../../../.. -o generate generate.cpp diff --git a/apu/bapu/smp/core/generate.cpp b/apu/bapu/smp/core/generate.cpp new file mode 100644 index 00000000..77ab3ed2 --- /dev/null +++ b/apu/bapu/smp/core/generate.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +using namespace nall; + +static bool cycle_accurate; + +struct opcode_t { + string name; + lstring args; + unsigned opcode; +}; + +void generate(const char *sourceFilename, const char *targetFilename) { + file fp; + fp.open(targetFilename, file::mode::write); + + string filedata; + filedata.readfile(sourceFilename); + filedata.replace("\r", ""); + + lstring block; + block.split("\n\n", filedata); + + foreach(data, block) { + lstring lines; + lines.split("\n", data); + + linear_vector array; + + unsigned sourceStart = 0; + foreach(line, lines, currentLine) { + line.transform("()", "``"); + lstring part; + part.split("`", line); + lstring arguments; + arguments.split(", ", part[1]); + + opcode_t opcode; + opcode.name = part[0]; + opcode.args = arguments; + opcode.opcode = hex(arguments[0]); + array.append(opcode); + + line.rtrim<1>(","); + if(line.endswith(" {")) { + line.rtrim<1>("{ "); + sourceStart = currentLine + 1; + break; + } + } + + if(cycle_accurate == false) { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + string output; + + if(lines[n].beginswith(" ")) { + output = lines[n]; + } else { + lstring part; + part.split<1>(":", lines[n]); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "break;"); + + fp.print(output, "\n"); + } + + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } else { + foreach(opcode, array) { + fp.print("case 0x", hex<2>(opcode.opcode), ": {\n"); + fp.print(" switch(opcode_cycle++) {\n"); + + for(unsigned n = sourceStart; n < lines.size(); n++) { + if(lines[n] == "}") break; + + bool nextLineEndsCycle = false; + if(lines[n + 1] == "}") nextLineEndsCycle = true; + if(lines[n + 1].beginswith(" ") == false) nextLineEndsCycle = true; + + string output; + + if(lines[n].beginswith(" ")) { + output = { " ", lines[n] }; + } else { + lstring part; + part.split<1>(":", lines[n]); + fp.print(" case ", (unsigned)decimal(part[0]), ":\n"); + output = { " ", part[1] }; + } + + output.replace("$1", opcode.args[1]); + output.replace("$2", opcode.args[2]); + output.replace("$3", opcode.args[3]); + output.replace("$4", opcode.args[4]); + output.replace("$5", opcode.args[5]); + output.replace("$6", opcode.args[6]); + output.replace("$7", opcode.args[7]); + output.replace("$8", opcode.args[8]); + output.replace("end;", "{ opcode_cycle = 0; break; }"); + + fp.print(output, "\n"); + if(nextLineEndsCycle) { + if(lines[n + 1].beginswith("}")) { + fp.print(" opcode_cycle = 0;\n"); + } + fp.print(" break;\n"); + } + } + + fp.print(" }\n"); + fp.print(" break;\n"); + fp.print("}\n\n"); + } + } + } + + fp.close(); +} + +int main() { + cycle_accurate = false; + generate("op_misc.b", "op_misc.cpp"); + generate("op_mov.b", "op_mov.cpp" ); + generate("op_pc.b", "op_pc.cpp" ); + generate("op_read.b", "op_read.cpp"); + generate("op_rmw.b", "op_rmw.cpp" ); + + cycle_accurate = true; + generate("op_misc.b", "opcycle_misc.cpp"); + generate("op_mov.b", "opcycle_mov.cpp" ); + generate("op_pc.b", "opcycle_pc.cpp" ); + generate("op_read.b", "opcycle_read.cpp"); + generate("op_rmw.b", "opcycle_rmw.cpp" ); + + return 0; +} diff --git a/apu/bapu/smp/core/op_misc.b b/apu/bapu/smp/core/op_misc.b new file mode 100644 index 00000000..fb258650 --- /dev/null +++ b/apu/bapu/smp/core/op_misc.b @@ -0,0 +1,163 @@ +nop(0x00) { +1:op_io(); +} + +sleep(0xef), +stop(0xff) { +1:op_io(); +2:op_io(); + regs.pc--; +} + +xcn(0x9f) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +daa(0xdf) { +1:op_io(); +2:op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +das(0xbe) { +1:op_io(); +2:op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +clrc(0x60, regs.p.c = 0), +clrp(0x20, regs.p.p = 0), +setc(0x80, regs.p.c = 1), +setp(0x40, regs.p.p = 1) { +1:op_io(); + $1; +} + +clrv(0xe0) { +1:op_io(); + regs.p.v = 0; + regs.p.h = 0; +} + +notc(0xed) { +1:op_io(); +2:op_io(); + regs.p.c = !regs.p.c; +} + +ei(0xa0, 1), +di(0xc0, 0) { +1:op_io(); +2:op_io(); + regs.p.i = $1; +} + +set0_dp(0x02, rd |= 0x01), +clr0_dp(0x12, rd &= ~0x01), +set1_dp(0x22, rd |= 0x02), +clr1_dp(0x32, rd &= ~0x02), +set2_dp(0x42, rd |= 0x04), +clr2_dp(0x52, rd &= ~0x04), +set3_dp(0x62, rd |= 0x08), +clr3_dp(0x72, rd &= ~0x08), +set4_dp(0x82, rd |= 0x10), +clr4_dp(0x92, rd &= ~0x10), +set5_dp(0xa2, rd |= 0x20), +clr5_dp(0xb2, rd &= ~0x20), +set6_dp(0xc2, rd |= 0x40), +clr6_dp(0xd2, rd &= ~0x40), +set7_dp(0xe2, rd |= 0x80), +clr7_dp(0xf2, rd &= ~0x80) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:$1; + op_writedp(dp, rd); +} + +push_a(0x2d, a), +push_x(0x4d, x), +push_y(0x6d, y), +push_p(0x0d, p) { +1:op_io(); +2:op_io(); +3:op_writestack(regs.$1); +} + +pop_a(0xae, a), +pop_x(0xce, x), +pop_y(0xee, y), +pop_p(0x8e, p) { +1:op_io(); +2:op_io(); +3:regs.$1 = op_readstack(); +} + +mul_ya(0xcf) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); +} + +div_ya_x(0x9e) { +1:op_io(); +2:op_io(); +3:op_io(); +4:op_io(); +5:op_io(); +6:op_io(); +7:op_io(); +8:op_io(); +9:op_io(); +10:op_io(); +11:op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} diff --git a/apu/bapu/smp/core/op_misc.cpp b/apu/bapu/smp/core/op_misc.cpp new file mode 100644 index 00000000..9a6a062d --- /dev/null +++ b/apu/bapu/smp/core/op_misc.cpp @@ -0,0 +1,346 @@ +case 0x00: { + op_io(); + break; +} + +case 0xef: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0xff: { + op_io(); + op_io(); + regs.pc--; + break; +} + +case 0x9f: { + op_io(); + op_io(); + op_io(); + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdf: { + op_io(); + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbe: { + op_io(); + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x60: { + op_io(); + regs.p.c = 0; + break; +} + +case 0x20: { + op_io(); + regs.p.p = 0; + break; +} + +case 0x80: { + op_io(); + regs.p.c = 1; + break; +} + +case 0x40: { + op_io(); + regs.p.p = 1; + break; +} + +case 0xe0: { + op_io(); + regs.p.v = 0; + regs.p.h = 0; + break; +} + +case 0xed: { + op_io(); + op_io(); + regs.p.c = !regs.p.c; + break; +} + +case 0xa0: { + op_io(); + op_io(); + regs.p.i = 1; + break; +} + +case 0xc0: { + op_io(); + op_io(); + regs.p.i = 0; + break; +} + +case 0x02: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x01; + op_writedp(dp, rd); + break; +} + +case 0x12: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x01; + op_writedp(dp, rd); + break; +} + +case 0x22: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x02; + op_writedp(dp, rd); + break; +} + +case 0x32: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x02; + op_writedp(dp, rd); + break; +} + +case 0x42: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x04; + op_writedp(dp, rd); + break; +} + +case 0x52: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x04; + op_writedp(dp, rd); + break; +} + +case 0x62: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x08; + op_writedp(dp, rd); + break; +} + +case 0x72: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x08; + op_writedp(dp, rd); + break; +} + +case 0x82: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x10; + op_writedp(dp, rd); + break; +} + +case 0x92: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x10; + op_writedp(dp, rd); + break; +} + +case 0xa2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x20; + op_writedp(dp, rd); + break; +} + +case 0xb2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x20; + op_writedp(dp, rd); + break; +} + +case 0xc2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x40; + op_writedp(dp, rd); + break; +} + +case 0xd2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x40; + op_writedp(dp, rd); + break; +} + +case 0xe2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x80; + op_writedp(dp, rd); + break; +} + +case 0xf2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x80; + op_writedp(dp, rd); + break; +} + +case 0x2d: { + op_io(); + op_io(); + op_writestack(regs.a); + break; +} + +case 0x4d: { + op_io(); + op_io(); + op_writestack(regs.x); + break; +} + +case 0x6d: { + op_io(); + op_io(); + op_writestack(regs.y); + break; +} + +case 0x0d: { + op_io(); + op_io(); + op_writestack(regs.p); + break; +} + +case 0xae: { + op_io(); + op_io(); + regs.a = op_readstack(); + break; +} + +case 0xce: { + op_io(); + op_io(); + regs.x = op_readstack(); + break; +} + +case 0xee: { + op_io(); + op_io(); + regs.y = op_readstack(); + break; +} + +case 0x8e: { + op_io(); + op_io(); + regs.p = op_readstack(); + break; +} + +case 0xcf: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9e: { + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + diff --git a/apu/bapu/smp/core/op_mov.b b/apu/bapu/smp/core/op_mov.b new file mode 100644 index 00000000..dee821af --- /dev/null +++ b/apu/bapu/smp/core/op_mov.b @@ -0,0 +1,217 @@ +mov_a_x(0x7d, a, x), +mov_a_y(0xdd, a, y), +mov_x_a(0x5d, x, a), +mov_y_a(0xfd, y, a), +mov_x_sp(0x9d, x, sp) { +1:op_io(); + regs.$1 = regs.$2; + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_sp_x(0xbd, sp, x) { +1:op_io(); + regs.$1 = regs.$2; +} + +mov_a_const(0xe8, a), +mov_x_const(0xcd, x), +mov_y_const(0x8d, y) { +1:regs.$1 = op_readpc(); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_ix(0xe6) { +1:op_io(); +2:regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_ixinc(0xbf) { +1:op_io(); +2:regs.a = op_readdp(regs.x++); +3:op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_dp(0xe4, a), +mov_x_dp(0xf8, x), +mov_y_dp(0xeb, y) { +1:sp = op_readpc(); +2:regs.$1 = op_readdp(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_dpx(0xf4, a, x), +mov_x_dpy(0xf9, x, y), +mov_y_dpx(0xfb, y, x) { +1:sp = op_readpc(); +2:op_io(); +3:regs.$1 = op_readdp(sp + regs.$2); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addr(0xe5, a), +mov_x_addr(0xe9, x), +mov_y_addr(0xec, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:regs.$1 = op_readaddr(sp); + regs.p.n = !!(regs.$1 & 0x80); + regs.p.z = (regs.$1 == 0); +} + +mov_a_addrx(0xf5, x), +mov_a_addry(0xf6, y) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:op_io(); +4:regs.a = op_readaddr(sp + regs.$1); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpx(0xe7) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_a_idpy(0xf7) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); +} + +mov_dp_dp(0xfa) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:op_writedp(dp, rd); +} + +mov_dp_const(0x8f) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:op_readdp(dp); +4:op_writedp(dp, rd); +} + +mov_ix_a(0xc6) { +1:op_io(); +2:op_readdp(regs.x); +3:op_writedp(regs.x, regs.a); +} + +mov_ixinc_a(0xaf) { +1:op_io(); +2:op_io(); +3:op_writedp(regs.x++, regs.a); +} + +mov_dp_a(0xc4, a), +mov_dp_x(0xd8, x), +mov_dp_y(0xcb, y) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.$1); +} + +mov_dpx_a(0xd4, x, a), +mov_dpy_x(0xd9, y, x), +mov_dpx_y(0xdb, x, y) { +1:dp = op_readpc(); +2:op_io(); + dp += regs.$1; +3:op_readdp(dp); +4:op_writedp(dp, regs.$2); +} + +mov_addr_a(0xc5, a), +mov_addr_x(0xc9, x), +mov_addr_y(0xcc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_readaddr(dp); +4:op_writeaddr(dp, regs.$1); +} + +mov_addrx_a(0xd5, x), +mov_addry_a(0xd6, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.$1; +4:op_readaddr(dp); +5:op_writeaddr(dp, regs.a); +} + +mov_idpx_a(0xc7) { +1:sp = op_readpc(); +2:op_io(); + sp += regs.x; +3:dp = op_readdp(sp); +4:dp |= op_readdp(sp + 1) << 8; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +mov_idpy_a(0xd7) { +1:sp = op_readpc(); +2:dp = op_readdp(sp); +3:dp |= op_readdp(sp + 1) << 8; +4:op_io(); + dp += regs.y; +5:op_readaddr(dp); +6:op_writeaddr(dp, regs.a); +} + +movw_ya_dp(0xba) { +1:sp = op_readpc(); +2:regs.a = op_readdp(sp); +3:op_io(); +4:regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); +} + +movw_dp_ya(0xda) { +1:dp = op_readpc(); +2:op_readdp(dp); +3:op_writedp(dp, regs.a); +4:op_writedp(dp + 1, regs.y); +} + +mov1_c_bit(0xaa) { +1:sp = op_readpc(); +2:sp |= op_readpc() << 8; +3:bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); +} + +mov1_bit_c(0xca) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); +4:op_io(); +5:op_writeaddr(dp, rd); +} diff --git a/apu/bapu/smp/core/op_mov.cpp b/apu/bapu/smp/core/op_mov.cpp new file mode 100644 index 00000000..f3079423 --- /dev/null +++ b/apu/bapu/smp/core/op_mov.cpp @@ -0,0 +1,389 @@ +case 0x7d: { + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdd: { + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x5d: { + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfd: { + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9d: { + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xbd: { + op_io(); + regs.sp = regs.x; + break; +} + +case 0xe8: { + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xcd: { + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0x8d: { + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe6: { + op_io(); + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbf: { + op_io(); + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe4: { + sp = op_readpc(); + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf8: { + sp = op_readpc(); + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xeb: { + sp = op_readpc(); + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf4: { + sp = op_readpc(); + op_io(); + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf9: { + sp = op_readpc(); + op_io(); + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfb: { + sp = op_readpc(); + op_io(); + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe9: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xec: { + sp = op_readpc(); + sp |= op_readpc() << 8; + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xf5: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf6: { + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xe7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xf7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xfa: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + op_writedp(dp, rd); + break; +} + +case 0x8f: { + rd = op_readpc(); + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, rd); + break; +} + +case 0xc6: { + op_io(); + op_readdp(regs.x); + op_writedp(regs.x, regs.a); + break; +} + +case 0xaf: { + op_io(); + op_io(); + op_writedp(regs.x++, regs.a); + break; +} + +case 0xc4: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd8: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xcb: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xd4: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.a); + break; +} + +case 0xd9: { + dp = op_readpc(); + op_io(); + dp += regs.y; + op_readdp(dp); + op_writedp(dp, regs.x); + break; +} + +case 0xdb: { + dp = op_readpc(); + op_io(); + dp += regs.x; + op_readdp(dp); + op_writedp(dp, regs.y); + break; +} + +case 0xc5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc9: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.x); + break; +} + +case 0xcc: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.y); + break; +} + +case 0xd5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xc7: { + sp = op_readpc(); + op_io(); + sp += regs.x; + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xd7: { + sp = op_readpc(); + dp = op_readdp(sp); + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + op_readaddr(dp); + op_writeaddr(dp, regs.a); + break; +} + +case 0xba: { + sp = op_readpc(); + regs.a = op_readdp(sp); + op_io(); + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + break; +} + +case 0xda: { + dp = op_readpc(); + op_readdp(dp); + op_writedp(dp, regs.a); + op_writedp(dp + 1, regs.y); + break; +} + +case 0xaa: { + sp = op_readpc(); + sp |= op_readpc() << 8; + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + break; +} + +case 0xca: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + op_io(); + op_writeaddr(dp, rd); + break; +} + diff --git a/apu/bapu/smp/core/op_pc.b b/apu/bapu/smp/core/op_pc.b new file mode 100644 index 00000000..affaf844 --- /dev/null +++ b/apu/bapu/smp/core/op_pc.b @@ -0,0 +1,179 @@ +bra(0x2f, 0), +beq(0xf0, !regs.p.z), +bne(0xd0, regs.p.z), +bcs(0xb0, !regs.p.c), +bcc(0x90, regs.p.c), +bvs(0x70, !regs.p.v), +bvc(0x50, regs.p.v), +bmi(0x30, !regs.p.n), +bpl(0x10, regs.p.n) { +1:rd = op_readpc(); + if($1)end; +2:op_io(); +3:op_io(); + regs.pc += (int8)rd; +} + +bbs0(0x03, 0x01, !=), +bbc0(0x13, 0x01, ==), +bbs1(0x23, 0x02, !=), +bbc1(0x33, 0x02, ==), +bbs2(0x43, 0x04, !=), +bbc2(0x53, 0x04, ==), +bbs3(0x63, 0x08, !=), +bbc3(0x73, 0x08, ==), +bbs4(0x83, 0x10, !=), +bbc4(0x93, 0x10, ==), +bbs5(0xa3, 0x20, !=), +bbc5(0xb3, 0x20, ==), +bbs6(0xc3, 0x40, !=), +bbc6(0xd3, 0x40, ==), +bbs7(0xe3, 0x80, !=), +bbc7(0xf3, 0x80, ==) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if((sp & $1) $2 $1)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dp(0x2e) { +1:dp = op_readpc(); +2:sp = op_readdp(dp); +3:rd = op_readpc(); +4:op_io(); + if(regs.a == sp)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +cbne_dpx(0xde) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp + regs.x); +4:rd = op_readpc(); +5:op_io(); + if(regs.a == sp)end; +6:op_io(); +7:op_io(); + regs.pc += (int8)rd; +} + +dbnz_dp(0x6e) { +1:dp = op_readpc(); +2:wr = op_readdp(dp); +3:op_writedp(dp, --wr); +4:rd = op_readpc(); + if(wr == 0x00)end; +5:op_io(); +6:op_io(); + regs.pc += (int8)rd; +} + +dbnz_y(0xfe) { +1:rd = op_readpc(); +2:op_io(); + regs.y--; +3:op_io(); + if(regs.y == 0x00)end; +4:op_io(); +5:op_io(); + regs.pc += (int8)rd; +} + +jmp_addr(0x5f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; + regs.pc = rd; +} + +jmp_iaddrx(0x1f) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); + dp += regs.x; +4:rd = op_readaddr(dp); +5:rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; +} + +call(0x3f) { +1:rd = op_readpc(); +2:rd |= op_readpc() << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +pcall(0x4f) { +1:rd = op_readpc(); +2:op_io(); +3:op_io(); +4:op_writestack(regs.pc >> 8); +5:op_writestack(regs.pc); + regs.pc = 0xff00 | rd; +} + +tcall_0(0x01, 0), +tcall_1(0x11, 1), +tcall_2(0x21, 2), +tcall_3(0x31, 3), +tcall_4(0x41, 4), +tcall_5(0x51, 5), +tcall_6(0x61, 6), +tcall_7(0x71, 7), +tcall_8(0x81, 8), +tcall_9(0x91, 9), +tcall_10(0xa1, 10), +tcall_11(0xb1, 11), +tcall_12(0xc1, 12), +tcall_13(0xd1, 13), +tcall_14(0xe1, 14), +tcall_15(0xf1, 15) { +1:dp = 0xffde - ($1 << 1); + rd = op_readaddr(dp); +2:rd |= op_readaddr(dp + 1) << 8; +3:op_io(); +4:op_io(); +5:op_io(); +6:op_writestack(regs.pc >> 8); +7:op_writestack(regs.pc); + regs.pc = rd; +} + +brk(0x0f) { +1:rd = op_readaddr(0xffde); +2:rd |= op_readaddr(0xffdf) << 8; +3:op_io(); +4:op_io(); +5:op_writestack(regs.pc >> 8); +6:op_writestack(regs.pc); +7:op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; +} + +ret(0x6f) { +1:rd = op_readstack(); +2:rd |= op_readstack() << 8; +3:op_io(); +4:op_io(); + regs.pc = rd; +} + +reti(0x7f) { +1:regs.p = op_readstack(); +2:rd = op_readstack(); +3:rd |= op_readstack() << 8; +4:op_io(); +5:op_io(); + regs.pc = rd; +} diff --git a/apu/bapu/smp/core/op_pc.cpp b/apu/bapu/smp/core/op_pc.cpp new file mode 100644 index 00000000..763a033e --- /dev/null +++ b/apu/bapu/smp/core/op_pc.cpp @@ -0,0 +1,603 @@ +case 0x2f: { + rd = op_readpc(); + if(0)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf0: { + rd = op_readpc(); + if(!regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd0: { + rd = op_readpc(); + if(regs.p.z)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb0: { + rd = op_readpc(); + if(!regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x90: { + rd = op_readpc(); + if(regs.p.c)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x70: { + rd = op_readpc(); + if(!regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x50: { + rd = op_readpc(); + if(regs.p.v)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x30: { + rd = op_readpc(); + if(!regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x10: { + rd = op_readpc(); + if(regs.p.n)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x03: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) != 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x13: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) == 0x01)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x23: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) != 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x33: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) == 0x02)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x43: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) != 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x53: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) == 0x04)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x63: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) != 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x73: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) == 0x08)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x83: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) != 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x93: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) == 0x10)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xa3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) != 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xb3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) == 0x20)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xc3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) != 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xd3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) == 0x40)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xe3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) != 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xf3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) == 0x80)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x2e: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xde: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x6e: { + dp = op_readpc(); + wr = op_readdp(dp); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0xfe: { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0x00)break; + op_io(); + op_io(); + regs.pc += (int8)rd; + break; +} + +case 0x5f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + regs.pc = rd; + break; +} + +case 0x1f: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + break; +} + +case 0x3f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x4f: { + rd = op_readpc(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + break; +} + +case 0x01: { + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x11: { + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x21: { + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x31: { + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x41: { + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x51: { + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x61: { + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x71: { + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x81: { + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x91: { + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xa1: { + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xb1: { + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xc1: { + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xd1: { + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xe1: { + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xf1: { + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(); + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x0f: { + rd = op_readaddr(0xffde); + rd |= op_readaddr(0xffdf) << 8; + op_io(); + op_io(); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + break; +} + +case 0x6f: { + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + +case 0x7f: { + regs.p = op_readstack(); + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(); + op_io(); + regs.pc = rd; + break; +} + diff --git a/apu/bapu/smp/core/op_read.b b/apu/bapu/smp/core/op_read.b new file mode 100644 index 00000000..fd2f9d82 --- /dev/null +++ b/apu/bapu/smp/core/op_read.b @@ -0,0 +1,205 @@ +adc_a_const(0x88, adc, a), +and_a_const(0x28, and, a), +cmp_a_const(0x68, cmp, a), +cmp_x_const(0xc8, cmp, x), +cmp_y_const(0xad, cmp, y), +eor_a_const(0x48, eor, a), +or_a_const(0x08, or, a), +sbc_a_const(0xa8, sbc, a) { +1:rd = op_readpc(); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_ix(0x86, adc), +and_a_ix(0x26, and), +cmp_a_ix(0x66, cmp), +eor_a_ix(0x46, eor), +or_a_ix(0x06, or), +sbc_a_ix(0xa6, sbc) { +1:op_io(); +2:rd = op_readdp(regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_dp(0x84, adc, a), +and_a_dp(0x24, and, a), +cmp_a_dp(0x64, cmp, a), +cmp_x_dp(0x3e, cmp, x), +cmp_y_dp(0x7e, cmp, y), +eor_a_dp(0x44, eor, a), +or_a_dp(0x04, or, a), +sbc_a_dp(0xa4, sbc, a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_dpx(0x94, adc), +and_a_dpx(0x34, and), +cmp_a_dpx(0x74, cmp), +eor_a_dpx(0x54, eor), +or_a_dpx(0x14, or), +sbc_a_dpx(0xb4, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); + regs.a = op_$1(regs.a, rd); +} + +adc_a_addr(0x85, adc, a), +and_a_addr(0x25, and, a), +cmp_a_addr(0x65, cmp, a), +cmp_x_addr(0x1e, cmp, x), +cmp_y_addr(0x5e, cmp, y), +eor_a_addr(0x45, eor, a), +or_a_addr(0x05, or, a), +sbc_a_addr(0xa5, sbc, a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.$2 = op_$1(regs.$2, rd); +} + +adc_a_addrx(0x95, adc, x), +adc_a_addry(0x96, adc, y), +and_a_addrx(0x35, and, x), +and_a_addry(0x36, and, y), +cmp_a_addrx(0x75, cmp, x), +cmp_a_addry(0x76, cmp, y), +eor_a_addrx(0x55, eor, x), +eor_a_addry(0x56, eor, y), +or_a_addrx(0x15, or, x), +or_a_addry(0x16, or, y), +sbc_a_addrx(0xb5, sbc, x), +sbc_a_addry(0xb6, sbc, y) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:op_io(); +4:rd = op_readaddr(dp + regs.$2); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpx(0x87, adc), +and_a_idpx(0x27, and), +cmp_a_idpx(0x67, cmp), +eor_a_idpx(0x47, eor), +or_a_idpx(0x07, or), +sbc_a_idpx(0xa7, sbc) { +1:dp = op_readpc() + regs.x; +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp); + regs.a = op_$1(regs.a, rd); +} + +adc_a_idpy(0x97, adc), +and_a_idpy(0x37, and), +cmp_a_idpy(0x77, cmp), +eor_a_idpy(0x57, eor), +or_a_idpy(0x17, or), +sbc_a_idpy(0xb7, sbc) { +1:dp = op_readpc(); +2:op_io(); +3:sp = op_readdp(dp); +4:sp |= op_readdp(dp + 1) << 8; +5:rd = op_readaddr(sp + regs.y); + regs.a = op_$1(regs.a, rd); +} + +adc_ix_iy(0x99, adc, 1), +and_ix_iy(0x39, and, 1), +cmp_ix_iy(0x79, cmp, 0), +eor_ix_iy(0x59, eor, 1), +or_ix_iy(0x19, or, 1), +sbc_ix_iy(0xb9, sbc, 1) { +1:op_io(); +2:rd = op_readdp(regs.y); +3:wr = op_readdp(regs.x); + wr = op_$1(wr, rd); +4:($2) ? op_writedp(regs.x, wr) : op_io(); +} + +adc_dp_dp(0x89, adc, 1), +and_dp_dp(0x29, and, 1), +cmp_dp_dp(0x69, cmp, 0), +eor_dp_dp(0x49, eor, 1), +or_dp_dp(0x09, or, 1), +sbc_dp_dp(0xa9, sbc, 1) { +1:sp = op_readpc(); +2:rd = op_readdp(sp); +3:dp = op_readpc(); +4:wr = op_readdp(dp); +5:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +adc_dp_const(0x98, adc, 1), +and_dp_const(0x38, and, 1), +cmp_dp_const(0x78, cmp, 0), +eor_dp_const(0x58, eor, 1), +or_dp_const(0x18, or, 1), +sbc_dp_const(0xb8, sbc, 1) { +1:rd = op_readpc(); +2:dp = op_readpc(); +3:wr = op_readdp(dp); +4:wr = op_$1(wr, rd); + ($2) ? op_writedp(dp, wr) : op_io(); +} + +addw_ya_dp(0x7a, addw), +subw_ya_dp(0x9a, subw) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:op_io(); +4:rd |= op_readdp(dp + 1) << 8; + regs.ya = op_$1(regs.ya, rd); +} + +cmpw_ya_dp(0x5a) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); +} + +and1_bit(0x4a, !!), +and1_notbit(0x6a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & $1(rd & (1 << bit)); +} + +eor1_bit(0x8a) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); +} + +not1_bit(0xea) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); +4:op_writeaddr(dp, rd); +} + +or1_bit(0x0a, !!), +or1_notbit(0x2a, !) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); +4:op_io(); + regs.p.c = regs.p.c | $1(rd & (1 << bit)); +} diff --git a/apu/bapu/smp/core/op_read.cpp b/apu/bapu/smp/core/op_read.cpp new file mode 100644 index 00000000..2a16a3c8 --- /dev/null +++ b/apu/bapu/smp/core/op_read.cpp @@ -0,0 +1,744 @@ +case 0x88: { + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x28: { + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x68: { + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0xc8: { + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0xad: { + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x48: { + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x08: { + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa8: { + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x86: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x26: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x66: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x46: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x06: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa6: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x84: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x24: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x64: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x3e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x7e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x44: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x04: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa4: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x94: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x34: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x74: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x54: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x14: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb4: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x85: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x25: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x65: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x1e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x5e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x45: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x05: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x95: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x96: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x35: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x36: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x75: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x76: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x55: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x56: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x15: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0x16: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0xb6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x87: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x27: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x67: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x47: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x07: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x97: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x37: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x77: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x57: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x17: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x99: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x39: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x79: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + (0) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x59: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x19: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0xb9: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x89: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x29: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x69: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x49: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x09: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xa9: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x98: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x38: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x78: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x58: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x18: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xb8: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x7a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + break; +} + +case 0x9a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + break; +} + +case 0x5a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + break; +} + +case 0x4a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + break; +} + +case 0x6a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + break; +} + +case 0x8a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + break; +} + +case 0xea: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + op_writeaddr(dp, rd); + break; +} + +case 0x0a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + break; +} + +case 0x2a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + break; +} + diff --git a/apu/bapu/smp/core/op_rmw.b b/apu/bapu/smp/core/op_rmw.b new file mode 100644 index 00000000..425574e8 --- /dev/null +++ b/apu/bapu/smp/core/op_rmw.b @@ -0,0 +1,74 @@ +inc_a(0xbc, inc, a), +inc_x(0x3d, inc, x), +inc_y(0xfc, inc, y), +dec_a(0x9c, dec, a), +dec_x(0x1d, dec, x), +dec_y(0xdc, dec, y), +asl_a(0x1c, asl, a), +lsr_a(0x5c, lsr, a), +rol_a(0x3c, rol, a), +ror_a(0x7c, ror, a) { +1:op_io(); + regs.$2 = op_$1(regs.$2); +} + +inc_dp(0xab, inc), +dec_dp(0x8b, dec), +asl_dp(0x0b, asl), +lsr_dp(0x4b, lsr), +rol_dp(0x2b, rol), +ror_dp(0x6b, ror) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); +3:rd = op_$1(rd); + op_writedp(dp, rd); +} + +inc_dpx(0xbb, inc), +dec_dpx(0x9b, dec), +asl_dpx(0x1b, asl), +lsr_dpx(0x5b, lsr), +rol_dpx(0x3b, rol), +ror_dpx(0x7b, ror) { +1:dp = op_readpc(); +2:op_io(); +3:rd = op_readdp(dp + regs.x); +4:rd = op_$1(rd); + op_writedp(dp + regs.x, rd); +} + +inc_addr(0xac, inc), +dec_addr(0x8c, dec), +asl_addr(0x0c, asl), +lsr_addr(0x4c, lsr), +rol_addr(0x2c, rol), +ror_addr(0x6c, ror) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); +4:rd = op_$1(rd); + op_writeaddr(dp, rd); +} + +tset_addr_a(0x0e, |), +tclr_addr_a(0x4e, &~) { +1:dp = op_readpc(); +2:dp |= op_readpc() << 8; +3:rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); +4:op_readaddr(dp); +5:op_writeaddr(dp, rd $1 regs.a); +} + +incw_dp(0x3a, ++), +decw_dp(0x1a, --) { +1:dp = op_readpc(); +2:rd = op_readdp(dp); + rd$1; +3:op_writedp(dp++, rd); +4:rd += op_readdp(dp) << 8; +5:op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); +} diff --git a/apu/bapu/smp/core/op_rmw.cpp b/apu/bapu/smp/core/op_rmw.cpp new file mode 100644 index 00000000..f89ecacf --- /dev/null +++ b/apu/bapu/smp/core/op_rmw.cpp @@ -0,0 +1,262 @@ +case 0xbc: { + op_io(); + regs.a = op_inc(regs.a); + break; +} + +case 0x3d: { + op_io(); + regs.x = op_inc(regs.x); + break; +} + +case 0xfc: { + op_io(); + regs.y = op_inc(regs.y); + break; +} + +case 0x9c: { + op_io(); + regs.a = op_dec(regs.a); + break; +} + +case 0x1d: { + op_io(); + regs.x = op_dec(regs.x); + break; +} + +case 0xdc: { + op_io(); + regs.y = op_dec(regs.y); + break; +} + +case 0x1c: { + op_io(); + regs.a = op_asl(regs.a); + break; +} + +case 0x5c: { + op_io(); + regs.a = op_lsr(regs.a); + break; +} + +case 0x3c: { + op_io(); + regs.a = op_rol(regs.a); + break; +} + +case 0x7c: { + op_io(); + regs.a = op_ror(regs.a); + break; +} + +case 0xab: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_inc(rd); + op_writedp(dp, rd); + break; +} + +case 0x8b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_dec(rd); + op_writedp(dp, rd); + break; +} + +case 0x0b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_asl(rd); + op_writedp(dp, rd); + break; +} + +case 0x4b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_lsr(rd); + op_writedp(dp, rd); + break; +} + +case 0x2b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_rol(rd); + op_writedp(dp, rd); + break; +} + +case 0x6b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_ror(rd); + op_writedp(dp, rd); + break; +} + +case 0xbb: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x9b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x1b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x5b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x3b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x7b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0xac: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_inc(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x8c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_dec(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_asl(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x4c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_lsr(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x2c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_rol(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x6c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_ror(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd | regs.a); + break; +} + +case 0x4e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd &~ regs.a); + break; +} + +case 0x3a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd++; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + +case 0x1a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd--; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + diff --git a/apu/bapu/smp/core/opcycle_misc.cpp b/apu/bapu/smp/core/opcycle_misc.cpp new file mode 100644 index 00000000..963f9fc2 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_misc.cpp @@ -0,0 +1,696 @@ +case 0x00: { + switch(opcode_cycle++) { + case 1: + op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xef: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0xff: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.pc--; + opcode_cycle = 0; + break; + } + break; +} + +case 0x9f: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbe: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x60: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x20: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x80: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.c = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0x40: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.p = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe0: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.p.v = 0; + regs.p.h = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0xed: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.c = !regs.p.c; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 1; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc0: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x02: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x12: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x01; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x22: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x32: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x02; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x42: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x52: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x04; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x62: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x72: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x08; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x82: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x92: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x10; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x20; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x40; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= 0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf2: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd &= ~0x80; + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0d: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writestack(regs.p); + opcode_cycle = 0; + break; + } + break; +} + +case 0xae: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xce: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xee: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + regs.p = op_readstack(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9e: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_io(); + break; + case 7: + op_io(); + break; + case 8: + op_io(); + break; + case 9: + op_io(); + break; + case 10: + op_io(); + break; + case 11: + op_io(); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_mov.cpp b/apu/bapu/smp/core/opcycle_mov.cpp new file mode 100644 index 00000000..635c7ca5 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_mov.cpp @@ -0,0 +1,806 @@ +case 0x7d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbd: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.sp = regs.x; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe8: { + switch(opcode_cycle++) { + case 1: + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcd: { + switch(opcode_cycle++) { + case 1: + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8d: { + switch(opcode_cycle++) { + case 1: + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x++); + break; + case 3: + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf8: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xeb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf4: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfb: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xec: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf5: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf6: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_readdp(regs.x); + break; + case 3: + op_writedp(regs.x, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaf: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + op_io(); + break; + case 3: + op_writedp(regs.x++, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd8: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.y; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + dp += regs.x; + break; + case 3: + op_readdp(dp); + break; + case 4: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc9: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcc: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.y; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + op_io(); + sp += regs.x; + break; + case 3: + dp = op_readdp(sp); + break; + case 4: + dp |= op_readdp(sp + 1) << 8; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd7: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + dp = op_readdp(sp); + break; + case 3: + dp |= op_readdp(sp + 1) << 8; + break; + case 4: + op_io(); + dp += regs.y; + break; + case 5: + op_readaddr(dp); + break; + case 6: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xba: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + break; + case 3: + op_io(); + break; + case 4: + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xda: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + break; + case 4: + op_writedp(dp + 1, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaa: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xca: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + break; + case 4: + op_io(); + break; + case 5: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_pc.cpp b/apu/bapu/smp/core/opcycle_pc.cpp new file mode 100644 index 00000000..1cdda647 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_pc.cpp @@ -0,0 +1,1347 @@ +case 0x2f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(0){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.z){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb0: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x90: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.c){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x70: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x50: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.v){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x30: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(!regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x10: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + if(regs.p.n){ opcode_cycle = 0; break; } + break; + case 2: + op_io(); + break; + case 3: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x03: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) != 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x13: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x01) == 0x01){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x23: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) != 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x33: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x02) == 0x02){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x43: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) != 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x53: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x04) == 0x04){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x63: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) != 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x73: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x08) == 0x08){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x83: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) != 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x93: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x10) == 0x10){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) != 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x20) == 0x20){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) != 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x40) == 0x40){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) != 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf3: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if((sp & 0x80) == 0x80){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x2e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + rd = op_readpc(); + break; + case 4: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xde: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp + regs.x); + break; + case 4: + rd = op_readpc(); + break; + case 5: + op_io(); + if(regs.a == sp){ opcode_cycle = 0; break; } + break; + case 6: + op_io(); + break; + case 7: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + wr = op_readdp(dp); + break; + case 3: + op_writedp(dp, --wr); + break; + case 4: + rd = op_readpc(); + if(wr == 0x00){ opcode_cycle = 0; break; } + break; + case 5: + op_io(); + break; + case 6: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xfe: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + regs.y--; + break; + case 3: + op_io(); + if(regs.y == 0x00){ opcode_cycle = 0; break; } + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc += (int8)rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x5f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x1f: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + dp += regs.x; + break; + case 4: + rd = op_readaddr(dp); + break; + case 5: + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x3f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + rd |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x4f: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + op_io(); + break; + case 4: + op_writestack(regs.pc >> 8); + break; + case 5: + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x01: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x11: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x21: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x31: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x41: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x51: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x61: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x71: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x81: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x91: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xa1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xb1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xc1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xd1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xe1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0xf1: { + switch(opcode_cycle++) { + case 1: + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + break; + case 2: + rd |= op_readaddr(dp + 1) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_io(); + break; + case 6: + op_writestack(regs.pc >> 8); + break; + case 7: + op_writestack(regs.pc); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x0f: { + switch(opcode_cycle++) { + case 1: + rd = op_readaddr(0xffde); + break; + case 2: + rd |= op_readaddr(0xffdf) << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + break; + case 5: + op_writestack(regs.pc >> 8); + break; + case 6: + op_writestack(regs.pc); + break; + case 7: + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + opcode_cycle = 0; + break; + } + break; +} + +case 0x6f: { + switch(opcode_cycle++) { + case 1: + rd = op_readstack(); + break; + case 2: + rd |= op_readstack() << 8; + break; + case 3: + op_io(); + break; + case 4: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + +case 0x7f: { + switch(opcode_cycle++) { + case 1: + regs.p = op_readstack(); + break; + case 2: + rd = op_readstack(); + break; + case 3: + rd |= op_readstack() << 8; + break; + case 4: + op_io(); + break; + case 5: + op_io(); + regs.pc = rd; + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_read.cpp b/apu/bapu/smp/core/opcycle_read.cpp new file mode 100644 index 00000000..6c19f3a9 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_read.cpp @@ -0,0 +1,1599 @@ +case 0x88: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x28: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x68: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xad: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x48: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x08: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x86: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x26: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x66: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x46: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x06: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa6: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x84: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x24: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x64: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x44: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x04: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x94: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x34: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x74: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x54: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x14: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb4: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x85: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x25: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x65: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x45: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x05: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x95: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x96: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x35: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x36: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x75: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x76: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x55: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x56: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x15: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x16: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb5: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb6: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_io(); + break; + case 4: + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x87: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x27: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x67: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x47: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x07: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc() + regs.x; + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x97: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x37: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x77: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x57: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x17: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb7: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + sp = op_readdp(dp); + break; + case 4: + sp |= op_readdp(dp + 1) << 8; + break; + case 5: + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x99: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x39: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x79: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + break; + case 4: + (0) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x59: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x19: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb9: { + switch(opcode_cycle++) { + case 1: + op_io(); + break; + case 2: + rd = op_readdp(regs.y); + break; + case 3: + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + break; + case 4: + (1) ? op_writedp(regs.x, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x89: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x29: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x69: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x49: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x09: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xa9: { + switch(opcode_cycle++) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + wr = op_readdp(dp); + break; + case 5: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x98: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x38: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x78: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x58: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x18: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0xb8: { + switch(opcode_cycle++) { + case 1: + rd = op_readpc(); + break; + case 2: + dp = op_readpc(); + break; + case 3: + wr = op_readdp(dp); + break; + case 4: + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + op_io(); + break; + case 4: + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xea: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + break; + case 4: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + break; + case 4: + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/opcycle_rmw.cpp b/apu/bapu/smp/core/opcycle_rmw.cpp new file mode 100644 index 00000000..eca62f02 --- /dev/null +++ b/apu/bapu/smp/core/opcycle_rmw.cpp @@ -0,0 +1,550 @@ +case 0xbc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_inc(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_inc(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_inc(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_dec(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1d: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.x = op_dec(regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdc: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.y = op_dec(regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_asl(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_lsr(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_rol(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7c: { + switch(opcode_cycle++) { + case 1: + op_io(); + regs.a = op_ror(regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xab: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_inc(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_dec(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_asl(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_lsr(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_rol(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + break; + case 3: + rd = op_ror(rd); + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbb: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x9b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x5b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x7b: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + op_io(); + break; + case 3: + rd = op_readdp(dp + regs.x); + break; + case 4: + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xac: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_inc(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_dec(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_asl(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_lsr(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x2c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_rol(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x6c: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + break; + case 4: + rd = op_ror(rd); + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x0e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd | regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x4e: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, rd &~ regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0x3a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd++; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0x1a: { + switch(opcode_cycle++) { + case 1: + dp = op_readpc(); + break; + case 2: + rd = op_readdp(dp); + rd--; + break; + case 3: + op_writedp(dp++, rd); + break; + case 4: + rd += op_readdp(dp) << 8; + break; + case 5: + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/oppseudo_misc.cpp b/apu/bapu/smp/core/oppseudo_misc.cpp new file mode 100644 index 00000000..d266ef92 --- /dev/null +++ b/apu/bapu/smp/core/oppseudo_misc.cpp @@ -0,0 +1,311 @@ +case 0x00: { + op_io(); + break; +} + +case 0xef: { + op_io(2); + regs.pc--; + break; +} + +case 0xff: { + op_io(2); + regs.pc--; + break; +} + +case 0x9f: { + op_io(4); + regs.a = (regs.a >> 4) | (regs.a << 4); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdf: { + op_io(2); + if(regs.p.c || (regs.a) > 0x99) { + regs.a += 0x60; + regs.p.c = 1; + } + if(regs.p.h || (regs.a & 15) > 0x09) { + regs.a += 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xbe: { + op_io(2); + if(!regs.p.c || (regs.a) > 0x99) { + regs.a -= 0x60; + regs.p.c = 0; + } + if(!regs.p.h || (regs.a & 15) > 0x09) { + regs.a -= 0x06; + } + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x60: { + op_io(); + regs.p.c = 0; + break; +} + +case 0x20: { + op_io(); + regs.p.p = 0; + break; +} + +case 0x80: { + op_io(); + regs.p.c = 1; + break; +} + +case 0x40: { + op_io(); + regs.p.p = 1; + break; +} + +case 0xe0: { + op_io(); + regs.p.v = 0; + regs.p.h = 0; + break; +} + +case 0xed: { + op_io(2); + regs.p.c = !regs.p.c; + break; +} + +case 0xa0: { + op_io(2); + regs.p.i = 1; + break; +} + +case 0xc0: { + op_io(2); + regs.p.i = 0; + break; +} + +case 0x02: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x01; + op_writedp(dp, rd); + break; +} + +case 0x12: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x01; + op_writedp(dp, rd); + break; +} + +case 0x22: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x02; + op_writedp(dp, rd); + break; +} + +case 0x32: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x02; + op_writedp(dp, rd); + break; +} + +case 0x42: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x04; + op_writedp(dp, rd); + break; +} + +case 0x52: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x04; + op_writedp(dp, rd); + break; +} + +case 0x62: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x08; + op_writedp(dp, rd); + break; +} + +case 0x72: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x08; + op_writedp(dp, rd); + break; +} + +case 0x82: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x10; + op_writedp(dp, rd); + break; +} + +case 0x92: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x10; + op_writedp(dp, rd); + break; +} + +case 0xa2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x20; + op_writedp(dp, rd); + break; +} + +case 0xb2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x20; + op_writedp(dp, rd); + break; +} + +case 0xc2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x40; + op_writedp(dp, rd); + break; +} + +case 0xd2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x40; + op_writedp(dp, rd); + break; +} + +case 0xe2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= 0x80; + op_writedp(dp, rd); + break; +} + +case 0xf2: { + dp = op_readpc(); + rd = op_readdp(dp); + rd &= ~0x80; + op_writedp(dp, rd); + break; +} + +case 0x2d: { + op_io(2); + op_writestack(regs.a); + break; +} + +case 0x4d: { + op_io(2); + op_writestack(regs.x); + break; +} + +case 0x6d: { + op_io(2); + op_writestack(regs.y); + break; +} + +case 0x0d: { + op_io(2); + op_writestack(regs.p); + break; +} + +case 0xae: { + op_io(2); + regs.a = op_readstack(); + break; +} + +case 0xce: { + op_io(2); + regs.x = op_readstack(); + break; +} + +case 0xee: { + op_io(2); + regs.y = op_readstack(); + break; +} + +case 0x8e: { + op_io(2); + regs.p = op_readstack(); + break; +} + +case 0xcf: { + op_io(8); + ya = regs.y * regs.a; + regs.a = ya; + regs.y = ya >> 8; + //result is set based on y (high-byte) only + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9e: { + op_io(11); + ya = regs.ya; + //overflow set if quotient >= 256 + regs.p.v = !!(regs.y >= regs.x); + regs.p.h = !!((regs.y & 15) >= (regs.x & 15)); + if(regs.y < (regs.x << 1)) { + //if quotient is <= 511 (will fit into 9-bit result) + regs.a = ya / regs.x; + regs.y = ya % regs.x; + } else { + //otherwise, the quotient won't fit into regs.p.v + regs.a + //this emulates the odd behavior of the S-SMP in this case + regs.a = 255 - (ya - (regs.x << 9)) / (256 - regs.x); + regs.y = regs.x + (ya - (regs.x << 9)) % (256 - regs.x); + } + //result is set based on a (quotient) only + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + diff --git a/apu/bapu/smp/core/oppseudo_mov.cpp b/apu/bapu/smp/core/oppseudo_mov.cpp new file mode 100644 index 00000000..fd44ad29 --- /dev/null +++ b/apu/bapu/smp/core/oppseudo_mov.cpp @@ -0,0 +1,705 @@ +case 0x7d: { + op_io(); + regs.a = regs.x; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xdd: { + op_io(); + regs.a = regs.y; + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0x5d: { + op_io(); + regs.x = regs.a; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xfd: { + op_io(); + regs.y = regs.a; + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0x9d: { + op_io(); + regs.x = regs.sp; + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0xbd: { + op_io(); + regs.sp = regs.x; + break; +} + +case 0xe8: { + regs.a = op_readpc(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + break; +} + +case 0xcd: { + regs.x = op_readpc(); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + break; +} + +case 0x8d: { + regs.y = op_readpc(); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + break; +} + +case 0xe6: { + switch(++opcode_cycle) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xbf: { + switch(++opcode_cycle) { + case 1: + op_io(); + break; + case 2: + regs.a = op_readdp(regs.x++); + op_io(); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe4: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf8: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.x = op_readdp(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xeb: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.y = op_readdp(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf4: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + op_io(); + break; + case 2: + regs.a = op_readdp(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf9: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + op_io(); + break; + case 2: + regs.x = op_readdp(sp + regs.y); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfb: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + op_io(); + break; + case 2: + regs.y = op_readdp(sp + regs.x); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe5: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + sp |= op_readpc() << 8; + break; + case 3: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe9: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + sp |= op_readpc() << 8; + break; + case 2: + regs.x = op_readaddr(sp); + regs.p.n = !!(regs.x & 0x80); + regs.p.z = (regs.x == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xec: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + sp |= op_readpc() << 8; + break; + case 2: + regs.y = op_readaddr(sp); + regs.p.n = !!(regs.y & 0x80); + regs.p.z = (regs.y == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf5: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + break; + case 2: + regs.a = op_readaddr(sp + regs.x); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf6: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + sp |= op_readpc() << 8; + op_io(); + break; + case 2: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xe7: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc() + regs.x; + op_io(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + sp |= op_readdp(dp + 1) << 8; + break; + case 4: + regs.a = op_readaddr(sp); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xf7: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + op_io(); + break; + case 2: + sp = op_readdp(dp); + break; + case 3: + sp |= op_readdp(dp + 1) << 8; + break; + case 4: + regs.a = op_readaddr(sp + regs.y); + regs.p.n = !!(regs.a & 0x80); + regs.p.z = (regs.a == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xfa: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + rd = op_readdp(sp); + break; + case 3: + dp = op_readpc(); + break; + case 4: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0x8f: { + switch(++opcode_cycle) { + case 1: + rd = op_readpc(); + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc6: { + switch(++opcode_cycle) { + case 1: + op_io(); + break; + case 2: + op_readdp(regs.x); + break; + case 3: + op_writedp(regs.x, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaf: { + switch(++opcode_cycle) { + case 1: + op_io(2); + case 2: + op_writedp(regs.x++, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc4: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd8: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcb: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd4: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + op_io(); + dp += regs.x; + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd9: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + op_io(); + dp += regs.y; + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xdb: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + op_io(); + dp += regs.x; + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc5: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc9: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.x); + opcode_cycle = 0; + break; + } + break; +} + +case 0xcc: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + dp |= op_readpc() << 8; + break; + case 3: + op_readaddr(dp); + break; + case 4: + op_writeaddr(dp, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd5: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + break; + case 2: + op_readaddr(dp); + break; + case 3: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd6: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.y; + break; + case 2: + op_readaddr(dp); + break; + case 3: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xc7: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + op_io(); + sp += regs.x; + break; + case 2: + dp = op_readdp(sp); + break; + case 3: + dp |= op_readdp(sp + 1) << 8; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xd7: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + dp = op_readdp(sp); + break; + case 3: + dp |= op_readdp(sp + 1) << 8; + op_io(); + dp += regs.y; + break; + case 4: + op_readaddr(dp); + break; + case 5: + op_writeaddr(dp, regs.a); + opcode_cycle = 0; + break; + } + break; +} + +case 0xba: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + break; + case 2: + regs.a = op_readdp(sp); + op_io(); + break; + case 3: + regs.y = op_readdp(sp + 1); + regs.p.n = !!(regs.ya & 0x8000); + regs.p.z = (regs.ya == 0); + opcode_cycle = 0; + break; + } + break; +} + +case 0xda: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + break; + case 2: + op_readdp(dp); + break; + case 3: + op_writedp(dp, regs.a); + break; + case 4: + op_writedp(dp + 1, regs.y); + opcode_cycle = 0; + break; + } + break; +} + +case 0xaa: { + switch(++opcode_cycle) { + case 1: + sp = op_readpc(); + sp |= op_readpc() << 8; + break; + case 2: + bit = sp >> 13; + sp &= 0x1fff; + rd = op_readaddr(sp); + regs.p.c = !!(rd & (1 << bit)); + opcode_cycle = 0; + break; + } + break; +} + +case 0xca: { + switch(++opcode_cycle) { + case 1: + dp = op_readpc(); + dp |= op_readpc() << 8; + break; + case 2: + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + if(regs.p.c)rd |= (1 << bit); + else rd &= ~(1 << bit); + op_io(); + break; + case 3: + op_writeaddr(dp, rd); + opcode_cycle = 0; + break; + } + break; +} + diff --git a/apu/bapu/smp/core/oppseudo_pc.cpp b/apu/bapu/smp/core/oppseudo_pc.cpp new file mode 100644 index 00000000..022179d1 --- /dev/null +++ b/apu/bapu/smp/core/oppseudo_pc.cpp @@ -0,0 +1,536 @@ +case 0x2f: { + rd = op_readpc(); + if(0){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xf0: { + rd = op_readpc(); + if(!regs.p.z){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xd0: { + rd = op_readpc(); + if(regs.p.z){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xb0: { + rd = op_readpc(); + if(!regs.p.c){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x90: { + rd = op_readpc(); + if(regs.p.c){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x70: { + rd = op_readpc(); + if(!regs.p.v){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x50: { + rd = op_readpc(); + if(regs.p.v){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x30: { + rd = op_readpc(); + if(!regs.p.n){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x10: { + rd = op_readpc(); + if(regs.p.n){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x03: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) != 0x01){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x13: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x01) == 0x01){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x23: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) != 0x02){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x33: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x02) == 0x02){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x43: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) != 0x04){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x53: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x04) == 0x04){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x63: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) != 0x08){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x73: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x08) == 0x08){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x83: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) != 0x10){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x93: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x10) == 0x10){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xa3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) != 0x20){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xb3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x20) == 0x20){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xc3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) != 0x40){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xd3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x40) == 0x40){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xe3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) != 0x80){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xf3: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if((sp & 0x80) == 0x80){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x2e: { + dp = op_readpc(); + sp = op_readdp(dp); + rd = op_readpc(); + op_io(); + if(regs.a == sp){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xde: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp + regs.x); + rd = op_readpc(); + op_io(); + if(regs.a == sp){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x6e: { + dp = op_readpc(); + wr = op_readdp(dp); + op_writedp(dp, --wr); + rd = op_readpc(); + if(wr == 0x00){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0xfe: { + rd = op_readpc(); + op_io(); + regs.y--; + op_io(); + if(regs.y == 0x00){ break; } + op_io(2); + regs.pc += (int8)rd; + break; +} + +case 0x5f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + regs.pc = rd; + break; +} + +case 0x1f: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + dp += regs.x; + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + regs.pc = rd; + break; +} + +case 0x3f: { + rd = op_readpc(); + rd |= op_readpc() << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x4f: { + rd = op_readpc(); + op_io(2); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = 0xff00 | rd; + break; +} + +case 0x01: { + dp = 0xffde - (0 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x11: { + dp = 0xffde - (1 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x21: { + dp = 0xffde - (2 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x31: { + dp = 0xffde - (3 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x41: { + dp = 0xffde - (4 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x51: { + dp = 0xffde - (5 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x61: { + dp = 0xffde - (6 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x71: { + dp = 0xffde - (7 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x81: { + dp = 0xffde - (8 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x91: { + dp = 0xffde - (9 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xa1: { + dp = 0xffde - (10 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xb1: { + dp = 0xffde - (11 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xc1: { + dp = 0xffde - (12 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xd1: { + dp = 0xffde - (13 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xe1: { + dp = 0xffde - (14 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0xf1: { + dp = 0xffde - (15 << 1); + rd = op_readaddr(dp); + rd |= op_readaddr(dp + 1) << 8; + op_io(3); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + regs.pc = rd; + break; +} + +case 0x0f: { + rd = op_readaddr(0xffde); + rd |= op_readaddr(0xffdf) << 8; + op_io(2); + op_writestack(regs.pc >> 8); + op_writestack(regs.pc); + op_writestack(regs.p); + regs.pc = rd; + regs.p.b = 1; + regs.p.i = 0; + break; +} + +case 0x6f: { + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(2); + regs.pc = rd; + break; +} + +case 0x7f: { + regs.p = op_readstack(); + rd = op_readstack(); + rd |= op_readstack() << 8; + op_io(2); + regs.pc = rd; + break; +} + diff --git a/apu/bapu/smp/core/oppseudo_read.cpp b/apu/bapu/smp/core/oppseudo_read.cpp new file mode 100644 index 00000000..2a16a3c8 --- /dev/null +++ b/apu/bapu/smp/core/oppseudo_read.cpp @@ -0,0 +1,744 @@ +case 0x88: { + rd = op_readpc(); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x28: { + rd = op_readpc(); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x68: { + rd = op_readpc(); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0xc8: { + rd = op_readpc(); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0xad: { + rd = op_readpc(); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x48: { + rd = op_readpc(); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x08: { + rd = op_readpc(); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa8: { + rd = op_readpc(); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x86: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x26: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x66: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x46: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x06: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa6: { + op_io(); + rd = op_readdp(regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x84: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x24: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x64: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x3e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x7e: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x44: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x04: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa4: { + dp = op_readpc(); + rd = op_readdp(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x94: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x34: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x74: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x54: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x14: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb4: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x85: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x25: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x65: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x1e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.x = op_cmp(regs.x, rd); + break; +} + +case 0x5e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.y = op_cmp(regs.y, rd); + break; +} + +case 0x45: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x05: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x95: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x96: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x35: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x36: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x75: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x76: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x55: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x56: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x15: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_or(regs.a, rd); + break; +} + +case 0x16: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb5: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.x); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0xb6: { + dp = op_readpc(); + dp |= op_readpc() << 8; + op_io(); + rd = op_readaddr(dp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x87: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x27: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x67: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x47: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x07: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xa7: { + dp = op_readpc() + regs.x; + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x97: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_adc(regs.a, rd); + break; +} + +case 0x37: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_and(regs.a, rd); + break; +} + +case 0x77: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_cmp(regs.a, rd); + break; +} + +case 0x57: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_eor(regs.a, rd); + break; +} + +case 0x17: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_or(regs.a, rd); + break; +} + +case 0xb7: { + dp = op_readpc(); + op_io(); + sp = op_readdp(dp); + sp |= op_readdp(dp + 1) << 8; + rd = op_readaddr(sp + regs.y); + regs.a = op_sbc(regs.a, rd); + break; +} + +case 0x99: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_adc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x39: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_and(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x79: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_cmp(wr, rd); + (0) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x59: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_eor(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x19: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_or(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0xb9: { + op_io(); + rd = op_readdp(regs.y); + wr = op_readdp(regs.x); + wr = op_sbc(wr, rd); + (1) ? op_writedp(regs.x, wr) : op_io(); + break; +} + +case 0x89: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x29: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x69: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x49: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x09: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xa9: { + sp = op_readpc(); + rd = op_readdp(sp); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x98: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_adc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x38: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_and(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x78: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_cmp(wr, rd); + (0) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x58: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_eor(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x18: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_or(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0xb8: { + rd = op_readpc(); + dp = op_readpc(); + wr = op_readdp(dp); + wr = op_sbc(wr, rd); + (1) ? op_writedp(dp, wr) : op_io(); + break; +} + +case 0x7a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_addw(regs.ya, rd); + break; +} + +case 0x9a: { + dp = op_readpc(); + rd = op_readdp(dp); + op_io(); + rd |= op_readdp(dp + 1) << 8; + regs.ya = op_subw(regs.ya, rd); + break; +} + +case 0x5a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd |= op_readdp(dp + 1) << 8; + op_cmpw(regs.ya, rd); + break; +} + +case 0x4a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !!(rd & (1 << bit)); + break; +} + +case 0x6a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + regs.p.c = regs.p.c & !(rd & (1 << bit)); + break; +} + +case 0x8a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c ^ !!(rd & (1 << bit)); + break; +} + +case 0xea: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + rd ^= (1 << bit); + op_writeaddr(dp, rd); + break; +} + +case 0x0a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !!(rd & (1 << bit)); + break; +} + +case 0x2a: { + dp = op_readpc(); + dp |= op_readpc() << 8; + bit = dp >> 13; + dp &= 0x1fff; + rd = op_readaddr(dp); + op_io(); + regs.p.c = regs.p.c | !(rd & (1 << bit)); + break; +} + diff --git a/apu/bapu/smp/core/oppseudo_rmw.cpp b/apu/bapu/smp/core/oppseudo_rmw.cpp new file mode 100644 index 00000000..9b0dd2fb --- /dev/null +++ b/apu/bapu/smp/core/oppseudo_rmw.cpp @@ -0,0 +1,262 @@ +case 0xbc: { + op_io(); + regs.a = op_inc(regs.a); + break; +} + +case 0x3d: { + op_io(); + regs.x = op_inc(regs.x); + break; +} + +case 0xfc: { + op_io(); + regs.y = op_inc(regs.y); + break; +} + +case 0x9c: { + op_io(); + regs.a = op_dec(regs.a); + break; +} + +case 0x1d: { + op_io(); + regs.x = op_dec(regs.x); + break; +} + +case 0xdc: { + op_io(); + regs.y = op_dec(regs.y); + break; +} + +case 0x1c: { + op_io(); + regs.a = op_asl(regs.a); + break; +} + +case 0x5c: { + op_io(); + regs.a = op_lsr(regs.a); + break; +} + +case 0x3c: { + op_io(); + regs.a = op_rol(regs.a); + break; +} + +case 0x7c: { + op_io(); + regs.a = op_ror(regs.a); + break; +} + +case 0xab: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_inc(rd); + op_writedp(dp, rd); + break; +} + +case 0x8b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_dec(rd); + op_writedp(dp, rd); + break; +} + +case 0x0b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_asl(rd); + op_writedp(dp, rd); + break; +} + +case 0x4b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_lsr(rd); + op_writedp(dp, rd); + break; +} + +case 0x2b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_rol(rd); + op_writedp(dp, rd); + break; +} + +case 0x6b: { + dp = op_readpc(); + rd = op_readdp(dp); + rd = op_ror(rd); + op_writedp(dp, rd); + break; +} + +case 0xbb: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_inc(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x9b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_dec(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x1b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_asl(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x5b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_lsr(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x3b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_rol(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0x7b: { + dp = op_readpc(); + op_io(); + rd = op_readdp(dp + regs.x); + rd = op_ror(rd); + op_writedp(dp + regs.x, rd); + break; +} + +case 0xac: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_inc(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x8c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_dec(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_asl(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x4c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_lsr(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x2c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_rol(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x6c: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + rd = op_ror(rd); + op_writeaddr(dp, rd); + break; +} + +case 0x0e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd | regs.a); + break; +} + +case 0x4e: { + dp = op_readpc(); + dp |= op_readpc() << 8; + rd = op_readaddr(dp); + regs.p.n = !!((regs.a - rd) & 0x80); + regs.p.z = ((regs.a - rd) == 0); + op_readaddr(dp); + op_writeaddr(dp, rd &~ regs.a); + break; +} + +case 0x3a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd++; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + +case 0x1a: { + dp = op_readpc(); + rd = op_readdp(dp); + rd--; + op_writedp(dp++, rd); + rd += op_readdp(dp) << 8; + op_writedp(dp, rd >> 8); + regs.p.n = !!(rd & 0x8000); + regs.p.z = (rd == 0); + break; +} + diff --git a/apu/bapu/smp/debugger/debugger.cpp b/apu/bapu/smp/debugger/debugger.cpp new file mode 100644 index 00000000..9546c118 --- /dev/null +++ b/apu/bapu/smp/debugger/debugger.cpp @@ -0,0 +1,75 @@ +#ifdef SMP_CPP + +void SMPDebugger::op_step() { + bool break_event = false; + + usage[regs.pc] |= UsageExec; + opcode_pc = regs.pc; + + opcode_edge = true; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Exec, regs.pc, 0x00); + if(step_event && step_event() == true) { + debugger.break_event = Debugger::BreakEvent::SMPStep; + scheduler.exit(Scheduler::ExitReason::DebuggerEvent); + } + opcode_edge = false; + + SMP::op_step(); + synchronize_cpu(); +} + +uint8 SMPDebugger::op_read(uint16 addr) { + uint8 data = SMP::op_read(addr); + usage[addr] |= UsageRead; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data); + return data; +} + +void SMPDebugger::op_write(uint16 addr, uint8 data) { + SMP::op_write(addr, data); + usage[addr] |= UsageWrite; + usage[addr] &= ~UsageExec; + debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Write, addr, data); +} + +SMPDebugger::SMPDebugger() { + usage = new uint8[1 << 16](); + opcode_pc = 0xffc0; + opcode_edge = false; +} + +SMPDebugger::~SMPDebugger() { + delete[] usage; +} + +bool SMPDebugger::property(unsigned id, string &name, string &value) { + unsigned n = 0; + + #define item(name_, value_) \ + if(id == n++) { \ + name = name_; \ + value = value_; \ + return true; \ + } + + //$00f0 + item("$00f0", ""); + item("Clock Speed", (unsigned)status.clock_speed); + item("Timers Enable", status.timers_enable); + item("RAM Disable", status.ram_disable); + item("RAM Writable", status.ram_writable); + item("Timers Disable", status.timers_disable); + + //$00f1 + item("$00f1", ""); + item("IPLROM Enable", status.iplrom_enable); + + //$00f2 + item("$00f2", ""); + item("DSP Address", string("0x", hex<2>(status.dsp_addr))); + + #undef item + return false; +} + +#endif diff --git a/apu/bapu/smp/debugger/debugger.hpp b/apu/bapu/smp/debugger/debugger.hpp new file mode 100644 index 00000000..811aa4c6 --- /dev/null +++ b/apu/bapu/smp/debugger/debugger.hpp @@ -0,0 +1,27 @@ +class SMPDebugger : public SMP, public ChipDebugger { +public: + bool property(unsigned id, string &name, string &value); + + function step_event; + + enum Usage { + UsageRead = 0x80, + UsageWrite = 0x40, + UsageExec = 0x20, + }; + uint8 *usage; + uint16 opcode_pc; + bool opcode_edge; + + void op_step(); + uint8 op_read(uint16 addr); + void op_write(uint16 addr, uint8 data); + + SMPDebugger(); + ~SMPDebugger(); + + //disassembler + void disassemble_opcode(char *output, uint16 addr); + inline uint8 disassemble_read(uint16 addr); + inline uint16 relb(int8 offset, int op_len); +}; diff --git a/apu/bapu/smp/debugger/disassembler.cpp b/apu/bapu/smp/debugger/disassembler.cpp new file mode 100644 index 00000000..fb76ae92 --- /dev/null +++ b/apu/bapu/smp/debugger/disassembler.cpp @@ -0,0 +1,304 @@ +uint8 SMP::disassemble_read(uint16 addr) { + if(addr >= 0xffc0) return smp.iplrom[addr & 0x3f]; + return smp.apuram[addr]; +} + +uint16 SMP::relb(int8 offset, int op_len) { + uint16 pc = regs.pc + op_len; + return pc + offset; +} + +void SMP::disassemble_opcode(char *output, uint16 addr) { + char *s, t[512]; + uint8 op, op0, op1; + uint16 opw, opdp0, opdp1; + s = output; + + sprintf(s, "..%.4x ", addr); + + op = disassemble_read(addr + 0); + op0 = disassemble_read(addr + 1); + op1 = disassemble_read(addr + 2); + opw = (op0) | (op1 << 8); + opdp0 = ((unsigned)regs.p.p << 8) + op0; + opdp1 = ((unsigned)regs.p.p << 8) + op1; + + strcpy(t, " "); + + switch(op) { + case 0x00: sprintf(t, "nop"); break; + case 0x01: sprintf(t, "tcall 0"); break; + case 0x02: sprintf(t, "set0 $%.3x", opdp0); break; + case 0x03: sprintf(t, "bbs0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x04: sprintf(t, "or a,$%.3x", opdp0); break; + case 0x05: sprintf(t, "or a,$%.4x", opw); break; + case 0x06: sprintf(t, "or a,(x)"); break; + case 0x07: sprintf(t, "or a,($%.3x+x)", opdp0); break; + case 0x08: sprintf(t, "or a,#$%.2x", op0); break; + case 0x09: sprintf(t, "or $%.3x,$%.3x", opdp1, opdp0); break; + case 0x0a: sprintf(t, "or1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x0b: sprintf(t, "asl $%.3x", opdp0); break; + case 0x0c: sprintf(t, "asl $%.4x", opw); break; + case 0x0d: sprintf(t, "push p"); break; + case 0x0e: sprintf(t, "tset $%.4x,a", opw); break; + case 0x0f: sprintf(t, "brk"); break; + case 0x10: sprintf(t, "bpl $%.4x", relb(op0, 2)); break; + case 0x11: sprintf(t, "tcall 1"); break; + case 0x12: sprintf(t, "clr0 $%.3x", opdp0); break; + case 0x13: sprintf(t, "bbc0 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x14: sprintf(t, "or a,$%.3x+x", opdp0); break; + case 0x15: sprintf(t, "or a,$%.4x+x", opw); break; + case 0x16: sprintf(t, "or a,$%.4x+y", opw); break; + case 0x17: sprintf(t, "or a,($%.3x)+y", opdp0); break; + case 0x18: sprintf(t, "or $%.3x,#$%.2x", opdp1, op0); break; + case 0x19: sprintf(t, "or (x),(y)"); break; + case 0x1a: sprintf(t, "decw $%.3x", opdp0); break; + case 0x1b: sprintf(t, "asl $%.3x+x", opdp0); break; + case 0x1c: sprintf(t, "asl a"); break; + case 0x1d: sprintf(t, "dec x"); break; + case 0x1e: sprintf(t, "cmp x,$%.4x", opw); break; + case 0x1f: sprintf(t, "jmp ($%.4x+x)", opw); break; + case 0x20: sprintf(t, "clrp"); break; + case 0x21: sprintf(t, "tcall 2"); break; + case 0x22: sprintf(t, "set1 $%.3x", opdp0); break; + case 0x23: sprintf(t, "bbs1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x24: sprintf(t, "and a,$%.3x", opdp0); break; + case 0x25: sprintf(t, "and a,$%.4x", opw); break; + case 0x26: sprintf(t, "and a,(x)"); break; + case 0x27: sprintf(t, "and a,($%.3x+x)", opdp0); break; + case 0x28: sprintf(t, "and a,#$%.2x", op0); break; + case 0x29: sprintf(t, "and $%.3x,$%.3x", opdp1, opdp0); break; + case 0x2a: sprintf(t, "or1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x2b: sprintf(t, "rol $%.3x", opdp0); break; + case 0x2c: sprintf(t, "rol $%.4x", opw); break; + case 0x2d: sprintf(t, "push a"); break; + case 0x2e: sprintf(t, "cbne $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x2f: sprintf(t, "bra $%.4x", relb(op0, 2)); break; + case 0x30: sprintf(t, "bmi $%.4x", relb(op0, 2)); break; + case 0x31: sprintf(t, "tcall 3"); break; + case 0x32: sprintf(t, "clr1 $%.3x", opdp0); break; + case 0x33: sprintf(t, "bbc1 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x34: sprintf(t, "and a,$%.3x+x", opdp0); break; + case 0x35: sprintf(t, "and a,$%.4x+x", opw); break; + case 0x36: sprintf(t, "and a,$%.4x+y", opw); break; + case 0x37: sprintf(t, "and a,($%.3x)+y", opdp0); break; + case 0x38: sprintf(t, "and $%.3x,#$%.2x", opdp1, op0); break; + case 0x39: sprintf(t, "and (x),(y)"); break; + case 0x3a: sprintf(t, "incw $%.3x", opdp0); break; + case 0x3b: sprintf(t, "rol $%.3x+x", opdp0); break; + case 0x3c: sprintf(t, "rol a"); break; + case 0x3d: sprintf(t, "inc x"); break; + case 0x3e: sprintf(t, "cmp x,$%.3x", opdp0); break; + case 0x3f: sprintf(t, "call $%.4x", opw); break; + case 0x40: sprintf(t, "setp"); break; + case 0x41: sprintf(t, "tcall 4"); break; + case 0x42: sprintf(t, "set2 $%.3x", opdp0); break; + case 0x43: sprintf(t, "bbs2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x44: sprintf(t, "eor a,$%.3x", opdp0); break; + case 0x45: sprintf(t, "eor a,$%.4x", opw); break; + case 0x46: sprintf(t, "eor a,(x)"); break; + case 0x47: sprintf(t, "eor a,($%.3x+x)", opdp0); break; + case 0x48: sprintf(t, "eor a,#$%.2x", op0); break; + case 0x49: sprintf(t, "eor $%.3x,$%.3x", opdp1, opdp0); break; + case 0x4a: sprintf(t, "and1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x4b: sprintf(t, "lsr $%.3x", opdp0); break; + case 0x4c: sprintf(t, "lsr $%.4x", opw); break; + case 0x4d: sprintf(t, "push x"); break; + case 0x4e: sprintf(t, "tclr $%.4x,a", opw); break; + case 0x4f: sprintf(t, "pcall $ff%.2x", op0); break; + case 0x50: sprintf(t, "bvc $%.4x", relb(op0, 2)); break; + case 0x51: sprintf(t, "tcall 5"); break; + case 0x52: sprintf(t, "clr2 $%.3x", opdp0); break; + case 0x53: sprintf(t, "bbc2 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x54: sprintf(t, "eor a,$%.3x+x", opdp0); break; + case 0x55: sprintf(t, "eor a,$%.4x+x", opw); break; + case 0x56: sprintf(t, "eor a,$%.4x+y", opw); break; + case 0x57: sprintf(t, "eor a,($%.3x)+y", opdp0); break; + case 0x58: sprintf(t, "eor $%.3x,#$%.2x", opdp1, op0); break; + case 0x59: sprintf(t, "eor (x),(y)"); break; + case 0x5a: sprintf(t, "cmpw ya,$%.3x", opdp0); break; + case 0x5b: sprintf(t, "lsr $%.3x+x", opdp0); break; + case 0x5c: sprintf(t, "lsr a"); break; + case 0x5d: sprintf(t, "mov x,a"); break; + case 0x5e: sprintf(t, "cmp y,$%.4x", opw); break; + case 0x5f: sprintf(t, "jmp $%.4x", opw); break; + case 0x60: sprintf(t, "clrc"); break; + case 0x61: sprintf(t, "tcall 6"); break; + case 0x62: sprintf(t, "set3 $%.3x", opdp0); break; + case 0x63: sprintf(t, "bbs3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x64: sprintf(t, "cmp a,$%.3x", opdp0); break; + case 0x65: sprintf(t, "cmp a,$%.4x", opw); break; + case 0x66: sprintf(t, "cmp a,(x)"); break; + case 0x67: sprintf(t, "cmp a,($%.3x+x)", opdp0); break; + case 0x68: sprintf(t, "cmp a,#$%.2x", op0); break; + case 0x69: sprintf(t, "cmp $%.3x,$%.3x", opdp1, opdp0); break; + case 0x6a: sprintf(t, "and1 c,!$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x6b: sprintf(t, "ror $%.3x", opdp0); break; + case 0x6c: sprintf(t, "ror $%.4x", opw); break; + case 0x6d: sprintf(t, "push y"); break; + case 0x6e: sprintf(t, "dbnz $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x6f: sprintf(t, "ret"); break; + case 0x70: sprintf(t, "bvs $%.4x", relb(op0, 2)); break; + case 0x71: sprintf(t, "tcall 7"); break; + case 0x72: sprintf(t, "clr3 $%.3x", opdp0); break; + case 0x73: sprintf(t, "bbc3 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x74: sprintf(t, "cmp a,$%.3x+x", opdp0); break; + case 0x75: sprintf(t, "cmp a,$%.4x+x", opw); break; + case 0x76: sprintf(t, "cmp a,$%.4x+y", opw); break; + case 0x77: sprintf(t, "cmp a,($%.3x)+y", opdp0); break; + case 0x78: sprintf(t, "cmp $%.3x,#$%.2x", opdp1, op0); break; + case 0x79: sprintf(t, "cmp (x),(y)"); break; + case 0x7a: sprintf(t, "addw ya,$%.3x", opdp0); break; + case 0x7b: sprintf(t, "ror $%.3x+x", opdp0); break; + case 0x7c: sprintf(t, "ror a"); break; + case 0x7d: sprintf(t, "mov a,x"); break; + case 0x7e: sprintf(t, "cmp y,$%.3x", opdp0); break; + case 0x7f: sprintf(t, "reti"); break; + case 0x80: sprintf(t, "setc"); break; + case 0x81: sprintf(t, "tcall 8"); break; + case 0x82: sprintf(t, "set4 $%.3x", opdp0); break; + case 0x83: sprintf(t, "bbs4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x84: sprintf(t, "adc a,$%.3x", opdp0); break; + case 0x85: sprintf(t, "adc a,$%.4x", opw); break; + case 0x86: sprintf(t, "adc a,(x)"); break; + case 0x87: sprintf(t, "adc a,($%.3x+x)", opdp0); break; + case 0x88: sprintf(t, "adc a,#$%.2x", op0); break; + case 0x89: sprintf(t, "adc $%.3x,$%.3x", opdp1, opdp0); break; + case 0x8a: sprintf(t, "eor1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0x8b: sprintf(t, "dec $%.3x", opdp0); break; + case 0x8c: sprintf(t, "dec $%.4x", opw); break; + case 0x8d: sprintf(t, "mov y,#$%.2x", op0); break; + case 0x8e: sprintf(t, "pop p"); break; + case 0x8f: sprintf(t, "mov $%.3x,#$%.2x", opdp1, op0); break; + case 0x90: sprintf(t, "bcc $%.4x", relb(op0, 2)); break; + case 0x91: sprintf(t, "tcall 9"); break; + case 0x92: sprintf(t, "clr4 $%.3x", opdp0); break; + case 0x93: sprintf(t, "bbc4 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0x94: sprintf(t, "adc a,$%.3x+x", opdp0); break; + case 0x95: sprintf(t, "adc a,$%.4x+x", opw); break; + case 0x96: sprintf(t, "adc a,$%.4x+y", opw); break; + case 0x97: sprintf(t, "adc a,($%.3x)+y", opdp0); break; + case 0x98: sprintf(t, "adc $%.3x,#$%.2x", opdp1, op0); break; + case 0x99: sprintf(t, "adc (x),(y)"); break; + case 0x9a: sprintf(t, "subw ya,$%.3x", opdp0); break; + case 0x9b: sprintf(t, "dec $%.3x+x", opdp0); break; + case 0x9c: sprintf(t, "dec a"); break; + case 0x9d: sprintf(t, "mov x,sp"); break; + case 0x9e: sprintf(t, "div ya,x"); break; + case 0x9f: sprintf(t, "xcn a"); break; + case 0xa0: sprintf(t, "ei"); break; + case 0xa1: sprintf(t, "tcall 10"); break; + case 0xa2: sprintf(t, "set5 $%.3x", opdp0); break; + case 0xa3: sprintf(t, "bbs5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xa4: sprintf(t, "sbc a,$%.3x", opdp0); break; + case 0xa5: sprintf(t, "sbc a,$%.4x", opw); break; + case 0xa6: sprintf(t, "sbc a,(x)"); break; + case 0xa7: sprintf(t, "sbc a,($%.3x+x)", opdp0); break; + case 0xa8: sprintf(t, "sbc a,#$%.2x", op0); break; + case 0xa9: sprintf(t, "sbc $%.3x,$%.3x", opdp1, opdp0); break; + case 0xaa: sprintf(t, "mov1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xab: sprintf(t, "inc $%.3x", opdp0); break; + case 0xac: sprintf(t, "inc $%.4x", opw); break; + case 0xad: sprintf(t, "cmp y,#$%.2x", op0); break; + case 0xae: sprintf(t, "pop a"); break; + case 0xaf: sprintf(t, "mov (x)+,a"); break; + case 0xb0: sprintf(t, "bcs $%.4x", relb(op0, 2)); break; + case 0xb1: sprintf(t, "tcall 11"); break; + case 0xb2: sprintf(t, "clr5 $%.3x", opdp0); break; + case 0xb3: sprintf(t, "bbc5 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xb4: sprintf(t, "sbc a,$%.3x+x", opdp0); break; + case 0xb5: sprintf(t, "sbc a,$%.4x+x", opw); break; + case 0xb6: sprintf(t, "sbc a,$%.4x+y", opw); break; + case 0xb7: sprintf(t, "sbc a,($%.3x)+y", opdp0); break; + case 0xb8: sprintf(t, "sbc $%.3x,#$%.2x", opdp1, op0); break; + case 0xb9: sprintf(t, "sbc (x),(y)"); break; + case 0xba: sprintf(t, "movw ya,$%.3x", opdp0); break; + case 0xbb: sprintf(t, "inc $%.3x+x", opdp0); break; + case 0xbc: sprintf(t, "inc a"); break; + case 0xbd: sprintf(t, "mov sp,x"); break; + case 0xbe: sprintf(t, "das a"); break; + case 0xbf: sprintf(t, "mov a,(x)+"); break; + case 0xc0: sprintf(t, "di"); break; + case 0xc1: sprintf(t, "tcall 12"); break; + case 0xc2: sprintf(t, "set6 $%.3x", opdp0); break; + case 0xc3: sprintf(t, "bbs6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xc4: sprintf(t, "mov $%.3x,a", opdp0); break; + case 0xc5: sprintf(t, "mov $%.4x,a", opw); break; + case 0xc6: sprintf(t, "mov (x),a"); break; + case 0xc7: sprintf(t, "mov ($%.3x+x),a", opdp0); break; + case 0xc8: sprintf(t, "cmp x,#$%.2x", op0); break; + case 0xc9: sprintf(t, "mov $%.4x,x", opw); break; + case 0xca: sprintf(t, "mov1 $%.4x:%d,c", opw & 0x1fff, opw >> 13); break; + case 0xcb: sprintf(t, "mov $%.3x,y", opdp0); break; + case 0xcc: sprintf(t, "mov $%.4x,y", opw); break; + case 0xcd: sprintf(t, "mov x,#$%.2x", op0); break; + case 0xce: sprintf(t, "pop x"); break; + case 0xcf: sprintf(t, "mul ya"); break; + case 0xd0: sprintf(t, "bne $%.4x", relb(op0, 2)); break; + case 0xd1: sprintf(t, "tcall 13"); break; + case 0xd2: sprintf(t, "clr6 $%.3x", opdp0); break; + case 0xd3: sprintf(t, "bbc6 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xd4: sprintf(t, "mov $%.3x+x,a", opdp0); break; + case 0xd5: sprintf(t, "mov $%.4x+x,a", opw); break; + case 0xd6: sprintf(t, "mov $%.4x+y,a", opw); break; + case 0xd7: sprintf(t, "mov ($%.3x)+y,a", opdp0); break; + case 0xd8: sprintf(t, "mov $%.3x,x", opdp0); break; + case 0xd9: sprintf(t, "mov $%.3x+y,x", opdp0); break; + case 0xda: sprintf(t, "movw $%.3x,ya", opdp0); break; + case 0xdb: sprintf(t, "mov $%.3x+x,y", opdp0); break; + case 0xdc: sprintf(t, "dec y"); break; + case 0xdd: sprintf(t, "mov a,y"); break; + case 0xde: sprintf(t, "cbne $%.3x+x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xdf: sprintf(t, "daa a"); break; + case 0xe0: sprintf(t, "clrv"); break; + case 0xe1: sprintf(t, "tcall 14"); break; + case 0xe2: sprintf(t, "set7 $%.3x", opdp0); break; + case 0xe3: sprintf(t, "bbs7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xe4: sprintf(t, "mov a,$%.3x", opdp0); break; + case 0xe5: sprintf(t, "mov a,$%.4x", opw); break; + case 0xe6: sprintf(t, "mov a,(x)"); break; + case 0xe7: sprintf(t, "mov a,($%.3x+x)", opdp0); break; + case 0xe8: sprintf(t, "mov a,#$%.2x", op0); break; + case 0xe9: sprintf(t, "mov x,$%.4x", opw); break; + case 0xea: sprintf(t, "not1 c,$%.4x:%d", opw & 0x1fff, opw >> 13); break; + case 0xeb: sprintf(t, "mov y,$%.3x", opdp0); break; + case 0xec: sprintf(t, "mov y,$%.4x", opw); break; + case 0xed: sprintf(t, "notc"); break; + case 0xee: sprintf(t, "pop y"); break; + case 0xef: sprintf(t, "sleep"); break; + case 0xf0: sprintf(t, "beq $%.4x", relb(op0, 2)); break; + case 0xf1: sprintf(t, "tcall 15"); break; + case 0xf2: sprintf(t, "clr7 $%.3x", opdp0); break; + case 0xf3: sprintf(t, "bbc7 $%.3x,$%.4x", opdp0, relb(op1, 3)); break; + case 0xf4: sprintf(t, "mov a,$%.3x+x", opdp0); break; + case 0xf5: sprintf(t, "mov a,$%.4x+x", opw); break; + case 0xf6: sprintf(t, "mov a,$%.4x+y", opw); break; + case 0xf7: sprintf(t, "mov a,($%.3x)+y", opdp0); break; + case 0xf8: sprintf(t, "mov x,$%.3x", opdp0); break; + case 0xf9: sprintf(t, "mov x,$%.3x+y", opdp0); break; + case 0xfa: sprintf(t, "mov $%.3x,$%.3x", opdp1, opdp0); break; + case 0xfb: sprintf(t, "mov y,$%.3x+x", opdp0); break; + case 0xfc: sprintf(t, "inc y"); break; + case 0xfd: sprintf(t, "mov y,a"); break; + case 0xfe: sprintf(t, "dbnz y,$%.4x", relb(op0, 2)); break; + case 0xff: sprintf(t, "stop"); break; + } + + t[strlen(t)] = ' '; + strcat(s, t); + + sprintf(t, "A:%.2x X:%.2x Y:%.2x SP:01%.2x YA:%.4x ", + regs.a, regs.x, regs.y, regs.sp, (uint16)regs.ya); + strcat(s, t); + + sprintf(t, "%c%c%c%c%c%c%c%c", + regs.p.n ? 'N' : 'n', + regs.p.v ? 'V' : 'v', + regs.p.p ? 'P' : 'p', + regs.p.b ? 'B' : 'b', + regs.p.h ? 'H' : 'h', + regs.p.i ? 'I' : 'i', + regs.p.z ? 'Z' : 'z', + regs.p.c ? 'C' : 'c'); + strcat(s, t); +} diff --git a/apu/bapu/smp/iplrom.cpp b/apu/bapu/smp/iplrom.cpp new file mode 100644 index 00000000..a2ade89d --- /dev/null +++ b/apu/bapu/smp/iplrom.cpp @@ -0,0 +1,44 @@ +#ifdef SMP_CPP + +//this is the IPLROM for the S-SMP coprocessor. +//the S-SMP does not allow writing to the IPLROM. +//all writes are instead mapped to the extended +//RAM region, accessible when $f1.d7 is clear. + +const uint8 SMP::iplrom[64] = { +/*ffc0*/ 0xcd, 0xef, //mov x,#$ef +/*ffc2*/ 0xbd, //mov sp,x +/*ffc3*/ 0xe8, 0x00, //mov a,#$00 +/*ffc5*/ 0xc6, //mov (x),a +/*ffc6*/ 0x1d, //dec x +/*ffc7*/ 0xd0, 0xfc, //bne $ffc5 +/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa +/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb +/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc +/*ffd2*/ 0xd0, 0xfb, //bne $ffcf +/*ffd4*/ 0x2f, 0x19, //bra $ffef +/*ffd6*/ 0xeb, 0xf4, //mov y,$f4 +/*ffd8*/ 0xd0, 0xfc, //bne $ffd6 +/*ffda*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffdc*/ 0xd0, 0x0b, //bne $ffe9 +/*ffde*/ 0xe4, 0xf5, //mov a,$f5 +/*ffe0*/ 0xcb, 0xf4, //mov $f4,y +/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a +/*ffe4*/ 0xfc, //inc y +/*ffe5*/ 0xd0, 0xf3, //bne $ffda +/*ffe7*/ 0xab, 0x01, //inc $01 +/*ffe9*/ 0x10, 0xef, //bpl $ffda +/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4 +/*ffed*/ 0x10, 0xeb, //bpl $ffda +/*ffef*/ 0xba, 0xf6, //movw ya,$f6 +/*fff1*/ 0xda, 0x00, //movw $00,ya +/*fff3*/ 0xba, 0xf4, //movw ya,$f4 +/*fff5*/ 0xc4, 0xf4, //mov $f4,a +/*fff7*/ 0xdd, //mov a,y +/*fff8*/ 0x5d, //mov x,a +/*fff9*/ 0xd0, 0xdb, //bne $ffd6 +/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x) +/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0) +}; + +#endif diff --git a/apu/bapu/smp/memory.cpp b/apu/bapu/smp/memory.cpp new file mode 100644 index 00000000..aecba720 --- /dev/null +++ b/apu/bapu/smp/memory.cpp @@ -0,0 +1,130 @@ +unsigned SMP::port_read(unsigned addr) { + return apuram[0xf4 + (addr & 3)]; +} + +void SMP::port_write(unsigned addr, unsigned data) { + apuram[0xf4 + (addr & 3)] = data; +} + +unsigned SMP::mmio_read(unsigned addr) { + switch(addr) { + + case 0xf2: + return status.dsp_addr; + + case 0xf3: + return dsp.read(status.dsp_addr & 0x7f); + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + return cpu.port_read(addr); + + case 0xf8: + return status.ram00f8; + + case 0xf9: + return status.ram00f9; + + case 0xfd: { + unsigned result = timer0.stage3_ticks & 15; + timer0.stage3_ticks = 0; + return result; + } + + case 0xfe: { + unsigned result = timer1.stage3_ticks & 15; + timer1.stage3_ticks = 0; + return result; + } + + case 0xff: { + unsigned result = timer2.stage3_ticks & 15; + timer2.stage3_ticks = 0; + return result; + } + + } + + return 0x00; +} + +void SMP::mmio_write(unsigned addr, unsigned data) { + switch(addr) { + + case 0xf1: + status.iplrom_enable = data & 0x80; + + if(data & 0x30) { + synchronize_cpu(); + if(data & 0x20) { + cpu.port_write(3, 0x00); + cpu.port_write(2, 0x00); + } + if(data & 0x10) { + cpu.port_write(1, 0x00); + cpu.port_write(0, 0x00); + } + } + + if(timer2.enable == false && (data & 0x04)) { + timer2.stage2_ticks = 0; + timer2.stage3_ticks = 0; + } + timer2.enable = data & 0x04; + + if(timer1.enable == false && (data & 0x02)) { + timer1.stage2_ticks = 0; + timer1.stage3_ticks = 0; + } + timer1.enable = data & 0x02; + + if(timer0.enable == false && (data & 0x01)) { + timer0.stage2_ticks = 0; + timer0.stage3_ticks = 0; + } + timer0.enable = data & 0x01; + + break; + + case 0xf2: + status.dsp_addr = data; + break; + + case 0xf3: + if(status.dsp_addr & 0x80) break; + dsp.write(status.dsp_addr, data); + break; + + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + synchronize_cpu(); + port_write(addr, data); + break; + + case 0xf8: + status.ram00f8 = data; + break; + + case 0xf9: + status.ram00f9 = data; + break; + + case 0xfa: + timer0.target = data; + break; + + case 0xfb: + timer1.target = data; + break; + + case 0xfc: + timer2.target = data; + break; + + } +} diff --git a/apu/bapu/smp/smp.cpp b/apu/bapu/smp/smp.cpp new file mode 100644 index 00000000..1a20b7ae --- /dev/null +++ b/apu/bapu/smp/smp.cpp @@ -0,0 +1,157 @@ +#define CYCLE_ACCURATE +#define PSEUDO_CYCLE + +#include + +#define SMP_CPP +namespace SNES { + +#if defined(DEBUGGER) + #include "debugger/debugger.cpp" + #include "debugger/disassembler.cpp" + SMPDebugger smp; +#else + SMP smp; +#endif + +#include "algorithms.cpp" +#include "core.cpp" +#include "iplrom.cpp" +#include "memory.cpp" +#include "timing.cpp" + +void SMP::synchronize_cpu() { +#ifndef SNES9X + if(CPU::Threaded == true) { + //if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +#endif +} + +void SMP::synchronize_dsp() { +#ifndef SNES9X + if(DSP::Threaded == true) { + //if(dsp.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(dsp.thread); + } else { + while(dsp.clock < 0) dsp.enter(); + } +#endif +} + +void SMP::enter() { + while(clock < 0) op_step(); +} + +void SMP::power() { +#ifndef SNES9X + Processor::frequency = system.apu_frequency(); +#endif + + Processor::clock = 0; + + timer0.target = 0; + timer1.target = 0; + timer2.target = 0; + + for(unsigned n = 0; n < 256; n++) { + cycle_table_dsp[n] = (cycle_count_table[n] * 24); + cycle_table_cpu[n] = (cycle_count_table[n] * 24) * cpu.frequency; + } + + cycle_step_cpu = 24 * cpu.frequency; + + reset(); +} + +void SMP::reset() { + for(unsigned n = 0x0000; n <= 0xffff; n++) apuram[n] = 0x00; + + opcode_number = 0; + opcode_cycle = 0; + + regs.pc = 0xffc0; + regs.sp = 0xef; + regs.a = 0x00; + regs.x = 0x00; + regs.y = 0x00; + regs.p = 0x02; + + //$00f1 + status.iplrom_enable = true; + + //$00f2 + status.dsp_addr = 0x00; + + //$00f8,$00f9 + status.ram00f8 = 0x00; + status.ram00f9 = 0x00; + + //timers + timer0.enable = timer1.enable = timer2.enable = false; + timer0.stage1_ticks = timer1.stage1_ticks = timer2.stage1_ticks = 0; + timer0.stage2_ticks = timer1.stage2_ticks = timer2.stage2_ticks = 0; + timer0.stage3_ticks = timer1.stage3_ticks = timer2.stage3_ticks = 0; +} + +#ifndef SNES9X +void SMP::serialize(serializer &s) { + Processor::serialize(s); + + s.array(apuram, 64 * 1024); + + s.integer(opcode_number); + s.integer(opcode_cycle); + + s.integer(regs.pc); + s.integer(regs.sp); + s.integer(regs.a); + s.integer(regs.x); + s.integer(regs.y); + + s.integer(regs.p.n); + s.integer(regs.p.v); + s.integer(regs.p.p); + s.integer(regs.p.b); + s.integer(regs.p.h); + s.integer(regs.p.i); + s.integer(regs.p.z); + s.integer(regs.p.c); + + s.integer(status.iplrom_enable); + + s.integer(status.dsp_addr); + + s.integer(status.ram00f8); + s.integer(status.ram00f9); + + s.integer(timer0.enable); + s.integer(timer0.target); + s.integer(timer0.stage1_ticks); + s.integer(timer0.stage2_ticks); + s.integer(timer0.stage3_ticks); + + s.integer(timer1.enable); + s.integer(timer1.target); + s.integer(timer1.stage1_ticks); + s.integer(timer1.stage2_ticks); + s.integer(timer1.stage3_ticks); + + s.integer(timer2.enable); + s.integer(timer2.target); + + s.integer(timer2.stage1_ticks); + s.integer(timer2.stage2_ticks); + s.integer(timer2.stage3_ticks); +} +#endif + +SMP::SMP() { + apuram = new uint8[64 * 1024]; +} + +SMP::~SMP() { +} + +} diff --git a/apu/bapu/smp/smp.hpp b/apu/bapu/smp/smp.hpp new file mode 100644 index 00000000..c96ebea9 --- /dev/null +++ b/apu/bapu/smp/smp.hpp @@ -0,0 +1,132 @@ +class SMP : public Processor { +public: + static const uint8 iplrom[64]; + uint8 *apuram; + + enum { Threaded = false }; + alwaysinline void synchronize_cpu(); + alwaysinline void synchronize_dsp(); + + unsigned port_read(unsigned port); + void port_write(unsigned port, unsigned data); + + unsigned mmio_read(unsigned addr); + void mmio_write(unsigned addr, unsigned data); + + void enter(); + void power(); + void reset(); + +#ifndef SNES9X + void serialize(serializer&); +#else + void load_state(uint8 **); + void save_state(uint8 **); + void save_spc (uint8 *); +#endif + SMP(); + ~SMP(); + +//private: + struct Flags { + bool n, v, p, b, h, i, z, c; + + alwaysinline operator unsigned() const { + return (n << 7) | (v << 6) | (p << 5) | (b << 4) + | (h << 3) | (i << 2) | (z << 1) | (c << 0); + }; + + alwaysinline unsigned operator=(unsigned data) { + n = data & 0x80; v = data & 0x40; p = data & 0x20; b = data & 0x10; + h = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01; + return data; + } + + alwaysinline unsigned operator|=(unsigned data) { return operator=(operator unsigned() | data); } + alwaysinline unsigned operator^=(unsigned data) { return operator=(operator unsigned() ^ data); } + alwaysinline unsigned operator&=(unsigned data) { return operator=(operator unsigned() & data); } + }; + + unsigned opcode_number; + unsigned opcode_cycle; + + uint16 rd, wr, dp, sp, ya, bit; + + struct Regs { + uint16 pc; + uint8 sp; + union { + uint16 ya; +#ifndef __BIG_ENDIAN__ + struct { uint8 a, y; }; +#else + struct { uint8 y, a; }; +#endif + }; + uint8 x; + Flags p; + } regs; + + struct Status { + //$00f1 + bool iplrom_enable; + + //$00f2 + unsigned dsp_addr; + + //$00f8,$00f9 + unsigned ram00f8; + unsigned ram00f9; + } status; + + template + struct Timer { + bool enable; + uint8 target; + uint8 stage1_ticks; + uint8 stage2_ticks; + uint8 stage3_ticks; + + inline void tick(); + inline void tick(unsigned clocks); + }; + + Timer<128> timer0; + Timer<128> timer1; + Timer< 16> timer2; + + inline void tick(); + inline void tick(unsigned clocks); + alwaysinline void op_io(); + alwaysinline void op_io(unsigned clocks); + debugvirtual alwaysinline uint8 op_read(uint16 addr); + debugvirtual alwaysinline void op_write(uint16 addr, uint8 data); + debugvirtual alwaysinline void op_step(); + static const unsigned cycle_count_table[256]; + uint64 cycle_table_cpu[256]; + unsigned cycle_table_dsp[256]; + uint64 cycle_step_cpu; + + inline uint8 op_adc (uint8 x, uint8 y); + inline uint16 op_addw(uint16 x, uint16 y); + inline uint8 op_and (uint8 x, uint8 y); + inline uint8 op_cmp (uint8 x, uint8 y); + inline uint16 op_cmpw(uint16 x, uint16 y); + inline uint8 op_eor (uint8 x, uint8 y); + inline uint8 op_inc (uint8 x); + inline uint8 op_dec (uint8 x); + inline uint8 op_or (uint8 x, uint8 y); + inline uint8 op_sbc (uint8 x, uint8 y); + inline uint16 op_subw(uint16 x, uint16 y); + inline uint8 op_asl (uint8 x); + inline uint8 op_lsr (uint8 x); + inline uint8 op_rol (uint8 x); + inline uint8 op_ror (uint8 x); +}; + +#if defined(DEBUGGER) + #include "debugger/debugger.hpp" + extern SMPDebugger smp; +#else + extern SMP smp; +#endif diff --git a/apu/bapu/smp/smp_state.cpp b/apu/bapu/smp/smp_state.cpp new file mode 100644 index 00000000..adefdacb --- /dev/null +++ b/apu/bapu/smp/smp_state.cpp @@ -0,0 +1,197 @@ +#include "snes/snes.hpp" +#include + +typedef struct spc_file { + uint8 header[33]; + uint8 idtag[3]; + uint8 version_minor; + + uint8 pc_low; + uint8 pc_high; + uint8 a; + uint8 x; + uint8 y; + uint8 psw; + uint8 sp; + uint8 unused_a[2]; + + uint8 id666[210]; + + uint8 apuram[65536]; + uint8 dsp_registers[128]; + uint8 unused_b[64]; + uint8 iplrom[64]; +} spc_file; + +namespace SNES { + +#include "dsp/blargg_endian.h" + +void SMP::save_spc (uint8 *block) { + spc_file out; + + const char *header = "SNES-SPC700 Sound File Data v0.30"; + memcpy (out.header, header, 33); + out.idtag[0] = out.idtag[1] = 26; + out.idtag[2] = 27; + out.version_minor = 30; + + out.pc_low = regs.pc & 0xff; + out.pc_high = (regs.pc >> 8) & 0xff; + out.a = regs.a; + out.x = regs.x; + out.y = regs.y; + out.psw = (uint8) ((unsigned) regs.p); + out.sp = regs.sp; + out.unused_a[0] = out.unused_a[1] = 0; + + memset (out.id666, 0, 210); + memcpy (out.apuram, apuram, 65536); + + for (int i = 0xf2; i <= 0xf9; i++) + { + out.apuram[i] = mmio_read (i); + } + + for (int i = 0xfd; i <= 0xff; i++) + { + out.apuram[i] = mmio_read (i); + } + + for (int i = 0; i < 128; i++) + { + out.dsp_registers[i] = dsp.read (i); + } + + memset (out.unused_b, 0, 64); + memcpy (out.iplrom, iplrom, 64); + + memcpy (block, &out, 66048); +} + + +void SMP::save_state(uint8 **block) { + uint8 *ptr = *block; + memcpy(ptr, apuram, 64 * 1024); + ptr += 64 * 1024; + +#undef INT32 +#define INT32(i) set_le32(ptr, (i)); ptr += sizeof(int32) + INT32(clock); + + INT32(opcode_number); + INT32(opcode_cycle); + + INT32(regs.pc); + INT32(regs.sp); + INT32(regs.a); + INT32(regs.x); + INT32(regs.y); + + INT32(regs.p.n); + INT32(regs.p.v); + INT32(regs.p.p); + INT32(regs.p.b); + INT32(regs.p.h); + INT32(regs.p.i); + INT32(regs.p.z); + INT32(regs.p.c); + + INT32(status.iplrom_enable); + + INT32(status.dsp_addr); + + INT32(status.ram00f8); + INT32(status.ram00f9); + + INT32(timer0.enable); + INT32(timer0.target); + INT32(timer0.stage1_ticks); + INT32(timer0.stage2_ticks); + INT32(timer0.stage3_ticks); + + INT32(timer1.enable); + INT32(timer1.target); + INT32(timer1.stage1_ticks); + INT32(timer1.stage2_ticks); + INT32(timer1.stage3_ticks); + + INT32(timer2.enable); + INT32(timer2.target); + INT32(timer2.stage1_ticks); + INT32(timer2.stage2_ticks); + INT32(timer2.stage3_ticks); + + INT32(rd); + INT32(wr); + INT32(dp); + INT32(sp); + INT32(ya); + INT32(bit); + + *block = ptr; +} + +void SMP::load_state(uint8 **block) { + uint8 *ptr = *block; + memcpy(apuram, ptr, 64 * 1024); + ptr += 64 * 1024; + +#undef INT32 +#define INT32(i) i = get_le32(ptr); ptr += sizeof(int32) + INT32(clock); + + INT32(opcode_number); + INT32(opcode_cycle); + + INT32(regs.pc); + INT32(regs.sp); + INT32(regs.a); + INT32(regs.x); + INT32(regs.y); + + INT32(regs.p.n); + INT32(regs.p.v); + INT32(regs.p.p); + INT32(regs.p.b); + INT32(regs.p.h); + INT32(regs.p.i); + INT32(regs.p.z); + INT32(regs.p.c); + + INT32(status.iplrom_enable); + + INT32(status.dsp_addr); + + INT32(status.ram00f8); + INT32(status.ram00f9); + + INT32(timer0.enable); + INT32(timer0.target); + INT32(timer0.stage1_ticks); + INT32(timer0.stage2_ticks); + INT32(timer0.stage3_ticks); + + INT32(timer1.enable); + INT32(timer1.target); + INT32(timer1.stage1_ticks); + INT32(timer1.stage2_ticks); + INT32(timer1.stage3_ticks); + + INT32(timer2.enable); + INT32(timer2.target); + INT32(timer2.stage1_ticks); + INT32(timer2.stage2_ticks); + INT32(timer2.stage3_ticks); + + INT32(rd); + INT32(wr); + INT32(dp); + INT32(sp); + INT32(ya); + INT32(bit); + + *block = ptr; +} + +} /* namespace SNES */ diff --git a/apu/bapu/smp/timing.cpp b/apu/bapu/smp/timing.cpp new file mode 100644 index 00000000..d278f6f4 --- /dev/null +++ b/apu/bapu/smp/timing.cpp @@ -0,0 +1,26 @@ +template +void SMP::Timer::tick() { + if(++stage1_ticks < cycle_frequency) return; + + stage1_ticks = 0; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} + +template +void SMP::Timer::tick(unsigned clocks) { + stage1_ticks += clocks; + if(stage1_ticks < cycle_frequency) return; + + stage1_ticks -= cycle_frequency; + if(enable == false) return; + + if(++stage2_ticks != target) return; + + stage2_ticks = 0; + stage3_ticks = (stage3_ticks + 1) & 15; +} diff --git a/apu/bapu/snes/snes.hpp b/apu/bapu/snes/snes.hpp new file mode 100644 index 00000000..017856b8 --- /dev/null +++ b/apu/bapu/snes/snes.hpp @@ -0,0 +1,60 @@ +#ifndef __SNES_HPP +#define __SNES_HPP + +#include "snes9x.h" + +#define SNES9X + +#if defined(__GNUC__) + #define inline inline + #define alwaysinline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) + #define inline inline + #define alwaysinline inline __forceinline +#else + #define inline inline + #define alwaysinline inline +#endif + +#define debugvirtual + +namespace SNES +{ + +struct Processor +{ + unsigned frequency; + int32 clock; +}; + +#include "../smp/smp.hpp" +#include "../dsp/sdsp.hpp" + +class CPU +{ +public: + enum { Threaded = false }; + int frequency; + uint8 registers[4]; + + inline void reset () + { + registers[0] = registers[1] = registers[2] = registers[3] = 0; + } + + alwaysinline void port_write (uint8 port, uint8 data) + { + registers[port & 3] = data; + } + + alwaysinline uint8 port_read (uint8 port) + { + return registers[port & 3]; + } +}; + +extern CPU cpu; + +} /* namespace SNES */ + +#endif diff --git a/apu/hermite_resampler.h b/apu/hermite_resampler.h index 30ee1032..8c7dd96b 100644 --- a/apu/hermite_resampler.h +++ b/apu/hermite_resampler.h @@ -14,25 +14,20 @@ class HermiteResampler : public Resampler { protected: - double r_step; - double r_frac; - int r_left[4], r_right[4]; + float r_step; + float r_frac; + int r_left[4], r_right[4]; - double - hermite (double mu1, double a, double b, double c, double d) + static inline float + hermite (float mu1, float a, float b, float c, float d) { - const double tension = 0.0; //-1 = low, 0 = normal, 1 = high - const double bias = 0.0; //-1 = left, 0 = even, 1 = right - - double mu2, mu3, m0, m1, a0, a1, a2, a3; + float mu2, mu3, m0, m1, a0, a1, a2, a3; mu2 = mu1 * mu1; mu3 = mu2 * mu1; - m0 = (b - a) * (1 + bias) * (1 - tension) / 2; - m0 += (c - b) * (1 - bias) * (1 - tension) / 2; - m1 = (c - b) * (1 + bias) * (1 - tension) / 2; - m1 += (d - c) * (1 - bias) * (1 - tension) / 2; + m0 = (c - a) * 0.5; + m1 = (d - b) * 0.5; a0 = +2 * mu3 - 3 * mu2 + 1; a1 = mu3 - 2 * mu2 + mu1; @@ -72,6 +67,7 @@ class HermiteResampler : public Resampler read (short *data, int num_samples) { int i_position = start >> 1; + int max_samples = buffer_size >> 1; short *internal_buffer = (short *) buffer; int o_position = 0; int consumed = 0; @@ -80,27 +76,14 @@ class HermiteResampler : public Resampler { int s_left = internal_buffer[i_position]; int s_right = internal_buffer[i_position + 1]; - int max_samples = buffer_size >> 1; - const double margin_of_error = 1.0e-10; - - if (fabs(r_step - 1.0) < margin_of_error) - { - data[o_position] = (short) s_left; - data[o_position + 1] = (short) s_right; - - o_position += 2; - i_position += 2; - if (i_position >= max_samples) - i_position -= max_samples; - consumed += 2; - - continue; - } + float hermite_val[2]; while (r_frac <= 1.0 && o_position < num_samples) { - data[o_position] = SHORT_CLAMP (hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3])); - data[o_position + 1] = SHORT_CLAMP (hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3])); + hermite_val[0] = hermite (r_frac, r_left [0], r_left [1], r_left [2], r_left [3]); + hermite_val[1] = hermite (r_frac, r_right[0], r_right[1], r_right[2], r_right[3]); + data[o_position] = SHORT_CLAMP (hermite_val[0]); + data[o_position + 1] = SHORT_CLAMP (hermite_val[1]); o_position += 2; @@ -113,14 +96,14 @@ class HermiteResampler : public Resampler r_left [1] = r_left [2]; r_left [2] = r_left [3]; r_left [3] = s_left; - + r_right[0] = r_right[1]; r_right[1] = r_right[2]; r_right[2] = r_right[3]; - r_right[3] = s_right; - + r_right[3] = s_right; + r_frac -= 1.0; - + i_position += 2; if (i_position >= max_samples) i_position -= max_samples; diff --git a/apu/license.txt b/apu/license.txt deleted file mode 100644 index 5ab7695a..00000000 --- a/apu/license.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/apu/linear_resampler.h b/apu/linear_resampler.h deleted file mode 100644 index 35789db1..00000000 --- a/apu/linear_resampler.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Simple fixed-point linear resampler by BearOso*/ - -#ifndef __LINEAR_RESAMPLER_H -#define __LINEAR_RESAMPLER_H - -#include "resampler.h" -#include "snes9x.h" - -static const int f_prec = 15; -static const uint32 f__one = (1 << f_prec); - -#define lerp(t, a, b) (((((b) - (a)) * (t)) >> f_prec) + (a)) - -class LinearResampler : public Resampler -{ - protected: - uint32 f__r_step; - uint32 f__inv_r_step; - uint32 f__r_frac; - int r_left, r_right; - - public: - LinearResampler (int num_samples) : Resampler (num_samples) - { - f__r_frac = 0; - } - - ~LinearResampler () - { - } - - void - time_ratio (double ratio) - { - if (ratio == 0.0) - ratio = 1.0; - f__r_step = (uint32) (ratio * f__one); - f__inv_r_step = (uint32) (f__one / ratio); - clear (); - } - - void - clear (void) - { - ring_buffer::clear (); - f__r_frac = 0; - r_left = 0; - r_right = 0; - } - - void - read (short *data, int num_samples) - { - int i_position = start >> 1; - short *internal_buffer = (short *) buffer; - int o_position = 0; - int consumed = 0; - int max_samples = (buffer_size >> 1); - - while (o_position < num_samples && consumed < buffer_size) - { - if (f__r_step == f__one) - { - data[o_position] = internal_buffer[i_position]; - data[o_position + 1] = internal_buffer[i_position + 1]; - - o_position += 2; - i_position += 2; - if (i_position >= max_samples) - i_position -= max_samples; - consumed += 2; - - continue; - } - - while (f__r_frac <= f__one && o_position < num_samples) - { - data[o_position] = lerp (f__r_frac, - r_left, - internal_buffer[i_position]); - data[o_position + 1] = lerp (f__r_frac, - r_right, - internal_buffer[i_position + 1]); - - o_position += 2; - - f__r_frac += f__r_step; - } - - if (f__r_frac > f__one) - { - f__r_frac -= f__one; - r_left = internal_buffer[i_position]; - r_right = internal_buffer[i_position + 1]; - i_position += 2; - if (i_position >= max_samples) - i_position -= max_samples; - consumed += 2; - } - } - - size -= consumed << 1; - start += consumed << 1; - if (start >= buffer_size) - start -= buffer_size; - } - - inline int - avail (void) - { - return (((size >> 2) * f__inv_r_step) - ((f__r_frac * f__inv_r_step) >> f_prec)) >> (f_prec - 1); - } -}; - -#endif /* __LINEAR_RESAMPLER_H */ diff --git a/bsx.cpp b/bsx.cpp index d55b346c..88f27dc3 100644 --- a/bsx.cpp +++ b/bsx.cpp @@ -1023,11 +1023,19 @@ static bool8 BSX_LoadBIOS (void) return (r); } +static bool8 is_BSX_BIOS (const uint8 *data, uint32 size) +{ + if (size == BIOS_SIZE && strncmp((char *) (data + 0x7FC0), "Satellaview BS-X ", 21) == 0) + return (TRUE); + else + return (FALSE); +} + void S9xInitBSX (void) { Settings.BS = FALSE; - if (!memcmp(&Memory.ROM[0x7FC0], "Satellaview BS-X ", 21)) + if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize)) { // BS-X itself @@ -1074,7 +1082,7 @@ void S9xInitBSX (void) BSX.bootup = Settings.BSXBootup; - if (!BSX_LoadBIOS()) + if (!BSX_LoadBIOS() && !is_BSX_BIOS(BIOSROM,BIOS_SIZE)) { BSX.bootup = FALSE; memset(BIOSROM, 0, BIOS_SIZE); diff --git a/cheats2.cpp b/cheats2.cpp index ce1d153a..c3558efe 100644 --- a/cheats2.cpp +++ b/cheats2.cpp @@ -186,10 +186,13 @@ static void S9xSetByteFree (uint8, uint32); static uint8 S9xGetByteFree (uint32 address) { - uint32 Cycles = CPU.Cycles; + int32 Cycles = CPU.Cycles; + int32 NextEvent = CPU.NextEvent; uint8 byte; + CPU.NextEvent = 0x7FFFFFFF; byte = S9xGetByte(address); + CPU.NextEvent = NextEvent; CPU.Cycles = Cycles; return (byte); @@ -197,9 +200,12 @@ static uint8 S9xGetByteFree (uint32 address) static void S9xSetByteFree (uint8 byte, uint32 address) { - uint32 Cycles = CPU.Cycles; + int32 Cycles = CPU.Cycles; + int32 NextEvent = CPU.NextEvent; + CPU.NextEvent = 0x7FFFFFFF; S9xSetByte(byte, address); + CPU.NextEvent = NextEvent; CPU.Cycles = Cycles; } @@ -368,7 +374,7 @@ bool8 S9xSaveCheatFile (const char *filename) for (uint32 i = 0; i < Cheat.num_cheats; i++) { - ZeroMemory(data, 28); + memset(data, 0, 28); if (i == 0) { diff --git a/conffile.cpp b/conffile.cpp index 2923ecc8..b6afe379 100644 --- a/conffile.cpp +++ b/conffile.cpp @@ -209,16 +209,16 @@ void ConfigFile::Clear(void){ } bool ConfigFile::LoadFile(const char *filename){ - STREAM s; + FSTREAM s; bool ret=false; const char *n, *n2; - if((s=OPEN_STREAM(filename, "r"))){ + if((s=OPEN_FSTREAM(filename, "r"))){ n=filename; n2=strrchr(n, '/'); if(n2!=NULL) n=n2+1; n2=strrchr(n, '\\'); if(n2!=NULL) n=n2+1; - LoadFile(new fReader(s), n); - CLOSE_STREAM(s); + LoadFile(new fStream(s), n); + CLOSE_FSTREAM(s); ret = true; } else { fprintf(stderr, "Couldn't open conffile "); @@ -228,7 +228,7 @@ bool ConfigFile::LoadFile(const char *filename){ } -void ConfigFile::LoadFile(Reader *r, const char *name){ +void ConfigFile::LoadFile(Stream *r, const char *name){ curConfigFile = this; string l, key, val; string section; @@ -280,7 +280,7 @@ void ConfigFile::LoadFile(Reader *r, const char *name){ } key=l.substr(0,i); ConfigEntry::trim(key); val=l.substr(i+1); comment = ConfigEntry::trimCommented(val); - if(val[0]=='"' && *val.rbegin()=='"') val=val.substr(1, val.size()-2); + if(val.size() > 0 && val[0]=='"' && *val.rbegin()=='"') val=val.substr(1, val.size()-2); ConfigEntry e(line, section, key, val); e.comment = comment; @@ -427,7 +427,7 @@ string ConfigFile::GetString(const char *key, string def){ char *ConfigFile::GetString(const char *key, char *out, uint32 outlen){ if(!Exists(key)) return NULL; - ZeroMemory(out, outlen); + memset(out, 0, outlen); string o=Get(key); if(outlen>0){ outlen--; diff --git a/conffile.h b/conffile.h index 24c8c20e..54339fd0 100644 --- a/conffile.h +++ b/conffile.h @@ -188,7 +188,6 @@ #include "unzip/unzip.h" #endif #include "snes9x.h" -#include "reader.h" #ifndef MAX # define MAX(a,b) ((a) > (b)? (a) : (b)) @@ -203,7 +202,7 @@ class ConfigFile { // return false on failure bool LoadFile(const char *filename); - void LoadFile(Reader *r, const char *name=NULL); + void LoadFile(Stream *r, const char *name=NULL); // return false if key does not exist or is empty bool Exists(const char *key); diff --git a/controls.cpp b/controls.cpp index 08aa3e8e..714bb206 100644 --- a/controls.cpp +++ b/controls.cpp @@ -182,6 +182,7 @@ #include #include #include +#include #include "snes9x.h" #include "memmap.h" @@ -623,7 +624,7 @@ void S9xUnmapAllControls (void) if (!(superscope.crosshair.set & 4)) superscope.crosshair.bg = 1; - ZeroMemory(pseudobuttons, sizeof(pseudobuttons)); + memset(pseudobuttons, 0, sizeof(pseudobuttons)); turbo_time = 1; } @@ -1240,7 +1241,7 @@ s9xcommand_t S9xGetCommandT (const char *name) int i, j; const char *s; - ZeroMemory(&cmd, sizeof(cmd)); + memset(&cmd, 0, sizeof(cmd)); cmd.type = S9xBadMapping; cmd.multi_press = 0; cmd.button_norpt = 0; @@ -3449,7 +3450,7 @@ void S9xGetControllerCrosshair (enum crosscontrols ctl, int8 *idx, const char ** void S9xControlPreSaveState (struct SControlSnapshot *s) { - ZeroMemory(s, sizeof(*s)); + memset(s, 0, sizeof(*s)); s->ver = 3; for (int j = 0; j < 2; j++) diff --git a/cpu.cpp b/cpu.cpp index 575bc59b..4bdb92b2 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -274,7 +274,7 @@ void S9xReset (void) memset(Memory.RAM, 0x55, 0x20000); memset(Memory.VRAM, 0x00, 0x10000); - ZeroMemory(Memory.FillRAM, 0x8000); + memset(Memory.FillRAM, 0, 0x8000); if (Settings.BS) S9xResetBSX(); @@ -308,7 +308,7 @@ void S9xSoftReset (void) { S9xResetSaveTimer(FALSE); - ZeroMemory(Memory.FillRAM, 0x8000); + memset(Memory.FillRAM, 0, 0x8000); if (Settings.BS) S9xResetBSX(); diff --git a/cpuexec.h b/cpuexec.h index 7e65b313..8d201d01 100644 --- a/cpuexec.h +++ b/cpuexec.h @@ -281,7 +281,7 @@ static inline void S9xCheckInterrupts (void) if (PPU.HTimerEnabled) { int32 htimepos = PPU.HTimerPosition; - if (CPU.Cycles >= Timings.H_Max) + if (CPU.Cycles >= Timings.H_Max && htimepos < CPU.PrevCycles) htimepos += Timings.H_Max; if (CPU.PrevCycles >= htimepos || CPU.Cycles < htimepos) @@ -291,7 +291,7 @@ static inline void S9xCheckInterrupts (void) if (PPU.VTimerEnabled) { int32 vcounter = CPU.V_Counter; - if (CPU.Cycles >= Timings.H_Max) + if (CPU.Cycles >= Timings.H_Max && (!PPU.HTimerEnabled || PPU.HTimerPosition < CPU.PrevCycles)) vcounter++; if (vcounter != PPU.VTimerPosition) diff --git a/docs/portsofsnes9x.txt b/docs/portsofsnes9x.txt index d05365cb..ae324f88 100644 --- a/docs/portsofsnes9x.txt +++ b/docs/portsofsnes9x.txt @@ -1,5 +1,5 @@ These are all the known ports of Snes9X to other consoles/handhelds/etc as of -2011/04/24. They are all supported and welcomed on the official Snes9X site. +2011/08/28. They are all supported and welcomed on the official Snes9X site. **If you know of anyone who is currently working on a port of Snes9X, or if you have some interest in making a port, please have them go to the Snes9X forums @@ -13,42 +13,52 @@ Ports and how to get them running are as follows: *PSP Version of Snes9X* Name: Snes9X Euphoria Latest version: R5 Beta -Homepage/forum: http://www.retroemu.com/forum/ -Maintainer: Zack +Homepage/forum: http://code.google.com/p/snes9x-euphoria/ +Maintainer: Open due to Zack discontinuing the port; he has made the source +code available. If you are interested in taking over the project or starting a +new port from scratch, let Ryan and/or Jerremy know ASAP. HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * Downgrading/upgrading your firmware * Checking if your PSP-2000 series can use Pandora's Battery -* Checking if your PSP-3000 series can use the DaveeFTW Downgrader -* Creating Pandora's Battery +* Checking if your PSP-3000 series can use DaveeFTW's and/or some1's Downgrader +* Creating Pandora's Battery (as needed) * Finding the hacks, HENs, CFWs, etc and how to use/install them 1. Make sure your PSP is hackable in some way. This means: -* PSP-1000 series and certain PSP-2000 series can use Pandora Battery -* PSP-2000 series that can't use Pandora Battery, most PSP-3000 series, and PSP -Gos are hackable via other means (DaveeFTW Downgrader, etc) +* All PSP-1000 series and certain PSP-2000 series can use Pandora Battery; this +would be considered fully hackable. +* PSP-2000 series that can't use Pandora Battery, just about all PSP-3000 +series, and PSP Gos are hackable via other means (DaveeFTW's and/or some1's +Downgrader, etc); this would be considered partially hackable. 2. Make sure your PSP has custom firmware or a HEN that's useable (you'll have to upgrade/downgrade the firmware as necessary). (Hint: I personally prefer -5.50 GEN-D3 on the Pandora-able PSPs; 6.20 or 6.35 PRO-B4 or better on the -non-Pandora-able PSPs.) +5.50 GEN-D3 if your PSP can use Pandora Battery; latest version of 6.20 or +6.35 PRO CFW if your PSP can't use Pandora Battery (if you can't downgrade past +6.35, then you should be able to use 6.39 and/or 6.60 PRO).) 3. When that’s done, be sure to put the Snes9X Euphoria folder in /PSP/GAME on your PSP’s memory stick (PSP-1000/2000/3000 series) or internal memory (PSP Go). Be sure to copy the ROMs into the roms folder, saves (*.srm, etc) into the saves folder, and cheats into the cheats folder. +Note: as of right now, there is no one to maintain the PSP port; I am leaving +these instructions up just in case someone wants to take it over, and you can +use these tips to get other homebrews going. + *Wii/Gamecube version of Snes9X* Name: Snes9X GX -Latest Version: 4.2.7 +Latest Version: 4.2.8 Homepage/forum: http://code.google.com/p/snes9x-gx Maintainer: Tantric HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: -* Finding the latest Homebrew Channel, Snes9X GX Channel, and/or IOS58 -installers and installing them +* Finding and installing the latest versions of: Homebrew Channel, Snes9X GX +Channel (optional), and/or IOS58 installer (also optional; this is to make the +Snes9X GX channel work) * Finding a modchip for your GameCube and installing it Wii: You will need the latest Homebrew Channel installed on your Wii. After @@ -66,16 +76,19 @@ Gamecube: You might need a modchip. *Android and iOS (Apple iPhone/iPod Touch) version of Snes9X* Name: Snes9X EX -Latest Version: 1.3.23 +Latest Version: 1.4.2 (iOS); 1.4.7.1 (Android) Homepage/forum: http://www.explusalpha.com/home/snes9x-ex -Maintainer: Rakashazi (on the Snes9X forums) +Maintainer: Rakashazi HOW TO GET IT RUNNING: *DISCLAIMER* You will have to do some Googling, including but not limited to: * iOS (iPhone/iPod Touch) ONLY!!!: Jailbreaking your firmware -Android: It appears you can just download from the Android app-store thingy and -run it from there :) Be sure to copy over your ROMs, saves, etc though. +Android: Due to the Android Marketplace unfairly taking down Snes9X EX, you +will have to visit Rakashazi's website and download the apk either using your +PC (you'll have to connect the Android to your computer, mount the SD card, +then copy the apk to it) or your Android, then run package installer +(or easy installer is fine too) on your Android to install the app. iOS: You’ll have to jailbreak your firmware and install the Cydia app installer. Then you’ll have to install the BigBoss repository within Cydia and @@ -84,6 +97,10 @@ stuff for that, as it’s the only way you can put the ROMs, saves, etc onto you iPhone/iPod Touch. After that you should be able to download and run from there :) +Hint: a more detailed description of copying your ROMs/saves/etc over to the +iOS device can be found here: +http://snes9x.com/phpbb2/viewtopic.php?t=5107 + *PS3 version of Snes9X* Name: Snes9X PS3 Latest Version: 4.4.9 @@ -115,4 +132,4 @@ Really, it's not hard. Read the readme, and use a softmod or modchip and a replacement dashboard. After that's installed, it should be as simple as copying over the emulator, ROMs, saves, etc to the X-Box and it should work. -Updated most recently by: 2011/4/24 adventure_of_link \ No newline at end of file +Updated most recently by: 2011/11/2 adventure_of_link \ No newline at end of file diff --git a/gfx.cpp b/gfx.cpp index 0937852e..040a1e8d 100644 --- a/gfx.cpp +++ b/gfx.cpp @@ -216,7 +216,7 @@ static uint16 get_crosshair_color (uint8); bool8 S9xGraphicsInit (void) { S9xInitTileRenderer(); - ZeroMemory(BlackColourMap, 256 * sizeof(uint16)); + memset(BlackColourMap, 0, 256 * sizeof(uint16)); #ifdef GFX_MULTI_FORMAT if (GFX.BuildPixel == NULL) @@ -246,7 +246,7 @@ bool8 S9xGraphicsInit (void) } // Lookup table for color addition - ZeroMemory(GFX.X2, 0x10000 * sizeof(uint16)); + memset(GFX.X2, 0, 0x10000 * sizeof(uint16)); for (uint32 r = 0; r <= MAX_RED; r++) { uint32 r2 = r << 1; @@ -272,7 +272,7 @@ bool8 S9xGraphicsInit (void) } // Lookup table for 1/2 color subtraction - ZeroMemory(GFX.ZERO, 0x10000 * sizeof(uint16)); + memset(GFX.ZERO, 0, 0x10000 * sizeof(uint16)); for (uint32 r = 0; r <= MAX_RED; r++) { uint32 r2 = r; @@ -387,8 +387,8 @@ void S9xStartScreenRefresh (void) PPU.RecomputeClipWindows = TRUE; IPPU.PreviousLine = IPPU.CurrentLine = 0; - ZeroMemory(GFX.ZBuffer, GFX.ScreenSize); - ZeroMemory(GFX.SubZBuffer, GFX.ScreenSize); + memset(GFX.ZBuffer, 0, GFX.ScreenSize); + memset(GFX.SubZBuffer, 0, GFX.ScreenSize); } if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0) @@ -709,7 +709,7 @@ void S9xUpdateScreen (void) IPPU.RenderedScreenWidth = 512; } - if (!IPPU.DoubleHeightPixels && IPPU.Interlace) + if (!IPPU.DoubleHeightPixels && IPPU.Interlace && (PPU.BGMode == 5 || PPU.BGMode == 6)) { IPPU.DoubleHeightPixels = TRUE; IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1; @@ -719,16 +719,6 @@ void S9xUpdateScreen (void) for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--) memmove(GFX.Screen + y * GFX.PPL, GFX.Screen + y * GFX.RealPPL, IPPU.RenderedScreenWidth * sizeof(uint16)); } - else if (IPPU.DoubleHeightPixels && !IPPU.Interlace) - { - for (register int32 y = 0; y < (int32) GFX.StartY; y++) - memmove(GFX.Screen + y * GFX.RealPPL, GFX.Screen + y * GFX.PPL, IPPU.RenderedScreenWidth * sizeof(uint16)); - - IPPU.DoubleHeightPixels = FALSE; - IPPU.RenderedScreenHeight = PPU.ScreenHeight; - GFX.PPL = GFX.RealPPL; - GFX.DoInterlace = 0; - } } if ((Memory.FillRAM[0x2130] & 0x30) != 0x30 && (Memory.FillRAM[0x2131] & 0x3f)) @@ -820,7 +810,7 @@ static void SetupOBJ (void) if (!PPU.OAMPriorityRotation || !(PPU.OAMFlip & PPU.OAMAddr & 1)) // normal case { uint8 LineOBJ[SNES_HEIGHT_EXTENDED]; - ZeroMemory(LineOBJ, sizeof(LineOBJ)); + memset(LineOBJ, 0, sizeof(LineOBJ)); for (int i = 0; i < SNES_HEIGHT_EXTENDED; i++) { @@ -897,7 +887,7 @@ static void SetupOBJ (void) { // First, find out which sprites are on which lines uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128]; - ZeroMemory(OBJOnLine, sizeof(OBJOnLine)); + memset(OBJOnLine, 0, sizeof(OBJOnLine)); for (S = 0; S < 128; S++) { @@ -2252,43 +2242,37 @@ void S9xDrawCrosshair (const char *crosshair, uint8 fgcolor, uint8 bgcolor, int1 fg = get_crosshair_color(fgcolor); bg = get_crosshair_color(bgcolor); - // XXX: FIXME: why does it crash without this on Linux port? There are no out-of-bound writes without it... -#if (defined(__unix) || defined(__linux) || defined(__sun) || defined(__DJGPP)) - if (x >= 0 && y >= 0) -#endif + uint16 *s = GFX.Screen + y * (int32)GFX.RealPPL + x; + + for (r = 0; r < 15 * rx; r++, s += GFX.RealPPL - 15 * cx) { - uint16 *s = GFX.Screen + y * GFX.RealPPL + x; - - for (r = 0; r < 15 * rx; r++, s += GFX.RealPPL - 15 * cx) + if (y + r < 0) { - if (y + r < 0) - { - s += 15 * cx; + s += 15 * cx; + continue; + } + + if (y + r >= H) + break; + + for (c = 0; c < 15 * cx; c++, s++) + { + if (x + c < 0 || s < GFX.Screen) continue; - } - if (y + r >= H) - break; - - for (c = 0; c < 15 * cx; c++, s++) + if (x + c >= W) { - if (x + c < 0 || s < GFX.Screen) - continue; - - if (x + c >= W) - { - s += 15 * cx - c; - break; - } - - uint8 p = crosshair[(r / rx) * 15 + (c / cx)]; - - if (p == '#' && fgcolor) - *s = (fgcolor & 0x10) ? COLOR_ADD1_2(fg, *s) : fg; - else - if (p == '.' && bgcolor) - *s = (bgcolor & 0x10) ? COLOR_ADD1_2(*s, bg) : bg; + s += 15 * cx - c; + break; } + + uint8 p = crosshair[(r / rx) * 15 + (c / cx)]; + + if (p == '#' && fgcolor) + *s = (fgcolor & 0x10) ? COLOR_ADD1_2(fg, *s) : fg; + else + if (p == '.' && bgcolor) + *s = (bgcolor & 0x10) ? COLOR_ADD1_2(*s, bg) : bg; } } } diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 14d99899..277ad11e 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -8,7 +8,7 @@ snes9x_gtk_CXXFLAGS = -fno-exceptions -fno-rtti endif noinst_LIBRARIES = -INCLUDES = -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" +INCLUDES = -I../apu/bapu -I$(top_srcdir) -I.. -DSNES9XLOCALEDIR=\""$(snes9xlocaledir)"\" CLEANFILES = \ src/gtk_snes9x_ui.cpp \ @@ -119,12 +119,14 @@ endif # APU snes9x_gtk_SOURCES += \ - ../apu/apu.cpp \ - ../apu/SNES_SPC.cpp \ - ../apu/SNES_SPC_misc.cpp \ - ../apu/SNES_SPC_state.cpp \ - ../apu/SPC_DSP.cpp \ - ../apu/SPC_Filter.cpp + ../apu/apu.cpp + +# Byuu's APU +snes9x_gtk_SOURCES += \ + ../apu/bapu/dsp/sdsp.cpp \ + ../apu/bapu/dsp/SPC_DSP.cpp \ + ../apu/bapu/smp/smp.cpp \ + ../apu/bapu/smp/smp_state.cpp # DSP snes9x_gtk_SOURCES += \ @@ -157,7 +159,7 @@ snes9x_gtk_SOURCES += \ ../dma.cpp \ ../snes9x.cpp \ ../globals.cpp \ - ../reader.cpp \ + ../stream.cpp \ ../conffile.cpp \ ../bsx.cpp \ ../logger.cpp \ diff --git a/gtk/configure.ac b/gtk/configure.ac index f946b695..95024a23 100644 --- a/gtk/configure.ac +++ b/gtk/configure.ac @@ -342,15 +342,6 @@ if test yes = "$with_jma_decomp"; then JMA=yes fi -dnl FIXME: There is a third case (OLD) that is missed with this. -if test yes = "$with_newblend"; then - CFLAGS="$CFLAGS -DNEW_COLOUR_BLENDING" -else - #OLD_COLOUR_BLENDING hasn't been default for a while - # SYSDEFINES="$SYSDEFINES"' -DOLD_COLOUR_BLENDING' - : -fi - if test yes = "$with_zlib"; then AC_CHECK_HEADERS(zlib.h) AC_CHECK_LIB(z, gzread, [ @@ -432,7 +423,7 @@ if test $ac_cv_my_sar_int8 = yes && \ CFLAGS="$CFLAGS -DRIGHTSHIFT_IS_SAR" fi -CFLAGS="$CFLAGS -DCPU_SHUTDOWN -DSPC700_SHUTDOWN -DNO_INLINE_SET_GET -DUNZIP_SUPPORT -DSPC700_C -I. -I.. -I../unzip" +CFLAGS="$CFLAGS -DUNZIP_SUPPORT -DSPC700_C -I. -I.. -I../unzip" CXXFLAGS="$CFLAGS" diff --git a/gtk/po/POTFILES.in b/gtk/po/POTFILES.in index 32e6d8d8..dead100a 100644 --- a/gtk/po/POTFILES.in +++ b/gtk/po/POTFILES.in @@ -2,7 +2,8 @@ src/gtk_binding.cpp src/gtk_cheat.cpp src/gtk_config.cpp src/gtk_display_driver_opengl.cpp +src/gtk_netplay.cpp src/gtk_preferences.cpp src/gtk_s9x.cpp src/gtk_s9xwindow.cpp -src/snes9x.glade +src/snes9x.ui diff --git a/gtk/po/fr_FR.po b/gtk/po/fr_FR.po index dafe7ce6..66946fe8 100644 --- a/gtk/po/fr_FR.po +++ b/gtk/po/fr_FR.po @@ -104,7 +104,7 @@ msgstr "" #: ../src/gtk_preferences.cpp:388 msgid " Only barebones features enabled" -msgstr "" +msgstr " FonctionnalitĂ©s de base seulement" #: ../src/gtk_preferences.cpp:391 msgid " OpenGL" @@ -179,7 +179,7 @@ msgstr "Erreur Ă  l'ouverture de %s\n" #: ../src/gtk_s9xwindow.cpp:767 msgid "Couldn't load files." -msgstr "Impossible de charger les fichiers" +msgstr "Impossible de charger les fichiers." #: ../src/gtk_s9xwindow.cpp:799 msgid "Open SNES Movie" @@ -321,9 +321,9 @@ msgid "" "24-bit (GL_RGB)\n" "32-bit (GL_BGRA)" msgstr "" -"16-bit (GL_BVRA)\n" -"24-bit (GL_RVB)\n" -"32-bit (GL_BVRA)" +"16-bits (GL_BGRA)\n" +"24-bits (GL_RGB)\n" +"32-bits (GL_BGRA)" #: ../src/snes9x.glade.h:15 msgid "1x" @@ -506,7 +506,7 @@ msgstr "Autoriser les filtres Ă  utiliser plusieurs processeurs" #: ../src/snes9x.glade.h:61 msgid "Apply scaling filter:" -msgstr "Appliquer un filtre" +msgstr "Appliquer un filtre d'agrandissement:" #: ../src/snes9x.glade.h:62 msgid "Artifacts:" @@ -547,7 +547,7 @@ msgid "" "Automatically save the game's SRAM at this interval. Setting this to 0 will " "only save when quitting or changing ROMs" msgstr "" -"Sauver automatiquement la SRAM Ă  cet interval. RĂ©gler Ă  0 pour ne sauver " +"Sauver automatiquement la SRAM Ă  cet intervalle. RĂ©gler Ă  0 pour ne sauver " "qu'en quittant ou en changeant de ROM" #: ../src/snes9x.glade.h:76 @@ -703,7 +703,7 @@ msgstr "Bas" #: ../src/snes9x.glade.h:113 msgid "Emulation" -msgstr "Emulation" +msgstr "Émulation" #: ../src/snes9x.glade.h:114 msgid "Enable HDMA" @@ -735,7 +735,7 @@ msgstr "Forcer la sortie Hires" #: ../src/snes9x.glade.h:121 msgid "Force an inverted byte-ordering" -msgstr "" +msgstr "Inverser l'ordre des octets" #: ../src/snes9x.glade.h:122 msgid "" @@ -783,12 +783,12 @@ msgid "" "Host a game on this computer as Player 1, requiring extra throughput to " "support multitple users" msgstr "" -"HĂ©berger une partie sur cet ordinateur en temps que 'Joueur 1', requiert un " +"HĂ©berger une partie sur cet ordinateur en tant que 'Joueur 1'; requiert un " "dĂ©bit plus important pour supporter plusieurs utilisateurs" #: ../src/snes9x.glade.h:134 msgid "Hue:" -msgstr "Teinte" +msgstr "Teinte:" #: ../src/snes9x.glade.h:135 msgid "Increase frame rate" @@ -800,7 +800,7 @@ msgstr "Augmenter le temps entre chaque image" #: ../src/snes9x.glade.h:137 msgid "Input rate:" -msgstr "FrĂ©quence d'entrĂ©e" +msgstr "FrĂ©quence d'entrĂ©e:" #: ../src/snes9x.glade.h:138 msgid "Joypad" @@ -864,7 +864,7 @@ msgstr "Sourdine" #: ../src/snes9x.glade.h:153 msgid "Name or IP address:" -msgstr "Nom ou adresse IP" +msgstr "Nom ou adresse IP:" #: ../src/snes9x.glade.h:154 msgid "" @@ -946,7 +946,7 @@ msgstr "DĂ©sactiver l'Ă©cran de veille" #: ../src/snes9x.glade.h:178 msgid "Prevents edge artifacts, but can slow performance" -msgstr "EmpĂªche les artefacts des bords, mais peut ralentir le jeu" +msgstr "EmpĂªche les artefacts de bords, mais peut ralentir le jeu" #: ../src/snes9x.glade.h:179 msgid "Quit Snes9x" @@ -1084,7 +1084,7 @@ msgstr "Raccourcis" #: ../src/snes9x.glade.h:212 msgid "Show ROM _Info..." -msgstr "Afficher les _Information de l'image ROM..." +msgstr "Afficher les _Informations de l'image ROM..." #: ../src/snes9x.glade.h:213 msgid "Show frame rate" @@ -1172,7 +1172,7 @@ msgstr "" #: ../src/snes9x.glade.h:234 msgid "Smoothens (blurs) the image" -msgstr "Adoucie (floute) l'image" +msgstr "Adoucit (floute) l'image" #: ../src/snes9x.glade.h:235 msgid "Snes9x" @@ -1208,7 +1208,7 @@ msgstr "Son" #: ../src/snes9x.glade.h:243 msgid "Sound driver:" -msgstr "Pilote audio" +msgstr "Pilote audio:" #: ../src/snes9x.glade.h:244 msgid "Start" @@ -1370,7 +1370,7 @@ msgstr "" #: ../src/snes9x.glade.h:283 msgid "Up" -msgstr "Haut:" +msgstr "Haut" #: ../src/snes9x.glade.h:284 msgid "Use " @@ -1378,7 +1378,7 @@ msgstr "Utiliser " #: ../src/snes9x.glade.h:285 msgid "Use SNES extended height. Will probably cause letterboxing" -msgstr "" +msgstr "Utiliser la hauteur Ă©tendue SNES. Peut causer l'effet letterbox" #: ../src/snes9x.glade.h:286 msgid "Use fullscreen on ROM open" @@ -1547,7 +1547,7 @@ msgstr "threads pour le filtrage et le zoom" #~ msgid "Enable hacks that may improve performance, but can cause errors" #~ msgstr "" -#~ "Activer des hacks amĂ©liorant les performances, mais pouvant causer des " +#~ "Activer des hacks amĂ©liorant la performance, mais pouvant causer des " #~ "erreurs" #~ msgid "Enable speed hacks" @@ -1563,11 +1563,11 @@ msgstr "threads pour le filtrage et le zoom" #~ "Interpolates between samples. Smoothes the sound output to match the real " #~ "SNES" #~ msgstr "" -#~ "Interpole entre les samples. Fluidifie la sortie sonore pour correspondre " +#~ "Interpole entre les Ă©chantillons. Fluidifie la sortie sonore pour correspondre " #~ "au mieux Ă  la SNES" #~ msgid "Outputs at 16 bits per sample instead of 8 bits. More accurate sound" -#~ msgstr "Sortie en 16 bits par sample au lieu de 8. Son plus prĂ©cis" +#~ msgstr "Sortie en 16 bits par Ă©chantillon plutĂ´t que 8. Son plus prĂ©cis" #~ msgid "Reverse stereo" #~ msgstr "StĂ©rĂ©o inversĂ©e" diff --git a/gtk/src/gtk_display.cpp b/gtk/src/gtk_display.cpp index 2b4d6cf2..c2897e1b 100644 --- a/gtk/src/gtk_display.cpp +++ b/gtk/src/gtk_display.cpp @@ -718,6 +718,40 @@ S9xMergeHires (void *buffer, return; } +static void +S9xBlendHires (void *buffer, int pitch, int &width, int &height) +{ + uint16 tmp[512]; + + if (width < 512) + { + width <<= 1; + + for (int y = 0; y < height; y++) + { + uint16 *input = (uint16 *) ((uint8 *) buffer + y * pitch); + + tmp[0] = input[0]; + for (int x = 1; x < width; x++) + tmp[x] = AVERAGE_1555 (input[(x - 1) >> 1], input[(x >> 1)]); + + memcpy (input, tmp, width << 1); + } + } + else for (int y = 0; y < height; y++) + { + uint16 *input = (uint16 *) ((uint8 *) buffer + y * pitch); + + tmp[0] = input[0]; + for (int x = 1; x < width; x++) + tmp[x] = AVERAGE_1555 (input[x - 1], input[x]); + + memcpy (input, tmp, pitch); + } + + return; +} + void filter_2x (void *src, int src_pitch, @@ -843,23 +877,24 @@ filter_scanlines (void *src_buffer, int height) { register int x, y; + register uint16 *src, *dst_a, *dst_b; uint8 shift = scanline_shifts[gui_config->scanline_filter_intensity]; + src = (uint16 *) src_buffer; + dst_a = (uint16 *) dst_buffer; + dst_b = ((uint16 *) dst_buffer) + (dst_pitch >> 1); + for (y = 0; y < height; y++) { - register uint16 *src = (uint16 *) ((uint8 *) src_buffer + y * src_pitch); - register uint16 *dst_a = (uint16 *) ((uint8 *) dst_buffer + (y * 2) * dst_pitch); - register uint16 *dst_b = (uint16 *) ((uint8 *) dst_buffer + ((y * 2) + 1) * dst_pitch); - for (x = 0; x < width; x++) { register uint8 rs, gs, bs, /* Source components */ rh, gh, bh; /* High (bright) components */ - rs = ((*(src + x) >> 10) & 0x1f); - gs = ((*(src + x) >> 5) & 0x1f); - bs = ((*(src + x)) & 0x1f); + rs = ((src[x] >> 10) & 0x1f); + gs = ((src[x] >> 5) & 0x1f); + bs = ((src[x]) & 0x1f); rh = rs + (rs >> shift); gh = gs + (gs >> shift); @@ -869,11 +904,15 @@ filter_scanlines (void *src_buffer, gh = (gh > 31) ? 31 : gh; bh = (bh > 31) ? 31 : bh; - *(dst_a + x) = (rh << 10) | (gh << 5) | (bh); - *(dst_b + x) = ((rs + rs - rh) << 10) | - ((gs + gs - gh) << 5) | - (bs + bs - bh); + dst_a[x] = (rh << 10) + (gh << 5) + (bh); + dst_b[x] = ((rs + rs - rh) << 10) + + ((gs + gs - gh) << 5) + + (bs + bs - bh); } + + src += src_pitch >> 1; + dst_a += dst_pitch; + dst_b += dst_pitch; } return; diff --git a/gtk/src/gtk_display_driver_gtk.cpp b/gtk/src/gtk_display_driver_gtk.cpp index 234d5410..36ce8b35 100644 --- a/gtk/src/gtk_display_driver_gtk.cpp +++ b/gtk/src/gtk_display_driver_gtk.cpp @@ -83,7 +83,7 @@ S9xGTKDisplayDriver::output (void *src, gdk_buffer_width = width; gdk_buffer_height = height; - gdk_pixbuf_unref (pixbuf); + g_object_unref (pixbuf); padded_buffer[2] = realloc (padded_buffer[2], gdk_buffer_width * gdk_buffer_height * 3); @@ -195,7 +195,7 @@ S9xGTKDisplayDriver::deinit (void) free (buffer[0]); free (buffer[1]); - gdk_pixbuf_unref (pixbuf); + g_object_unref (pixbuf); free (padded_buffer[2]); return; diff --git a/gtk/src/gtk_display_driver_opengl.cpp b/gtk/src/gtk_display_driver_opengl.cpp index 5e692c43..153bfc17 100644 --- a/gtk/src/gtk_display_driver_opengl.cpp +++ b/gtk/src/gtk_display_driver_opengl.cpp @@ -905,16 +905,19 @@ S9xOpenGLDisplayDriver::swap_control (int enable) queried = TRUE; } - if (glSwapInterval) - { - glSwapInterval (enable); - } - if (glXSwapIntervalEXT) { + if (glSwapInterval) + glSwapInterval (0); + glXSwapIntervalEXT (display, xwindow, enable); } + else if (glSwapInterval) + { + glSwapInterval (enable); + } + return; } diff --git a/gtk/src/gtk_display_driver_xv.cpp b/gtk/src/gtk_display_driver_xv.cpp index d6046aab..1333a705 100644 --- a/gtk/src/gtk_display_driver_xv.cpp +++ b/gtk/src/gtk_display_driver_xv.cpp @@ -443,17 +443,11 @@ S9xXVDisplayDriver::init (void) } } - XSetWindowAttributes window_attr; xcolormap = XCreateColormap (display, GDK_COMPAT_WINDOW_XID (gtk_widget_get_window (drawing_area)), vi->visual, AllocNone); - window_attr.colormap = xcolormap; - window_attr.border_pixel = 0; - window_attr.event_mask = StructureNotifyMask | ExposureMask | PropertyChangeMask; - window_attr.background_pixmap = None; - create_window (1, 1); gdk_window_hide (gdk_window); diff --git a/gtk/src/gtk_file.cpp b/gtk/src/gtk_file.cpp index 0610d439..a0df75d8 100644 --- a/gtk/src/gtk_file.cpp +++ b/gtk/src/gtk_file.cpp @@ -157,6 +157,7 @@ S9xGetDirectory (enum s9x_getdirtype dirtype) case SCREENSHOT_DIR: case SPC_DIR: sprintf (path, "%s", gui_config->export_directory); + break; default: path[0] = '\0'; @@ -310,13 +311,7 @@ S9xOpenSnapshotFile (const char *fname, bool8 read_only, STREAM *file) { if ((*file = OPEN_STREAM (filename, "wb"))) { - if (chown (filename, getuid (), getgid ()) < 0) - { - fprintf (stderr, "Couldn't set ownership of file.\n"); - return (FALSE); - } - else - return (TRUE); + return (TRUE); } else { diff --git a/gtk/src/gtk_s9x.cpp b/gtk/src/gtk_s9x.cpp index a2f354c9..03e1c812 100644 --- a/gtk/src/gtk_s9x.cpp +++ b/gtk/src/gtk_s9x.cpp @@ -51,7 +51,7 @@ main (int argc, char *argv[]) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - ZeroMemory (&Settings, sizeof (Settings)); + memset (&Settings, 0, sizeof (Settings)); /* Allow original config file for backend settings */ S9xLoadConfigFiles (argv, argc); @@ -207,8 +207,6 @@ S9xOpenROM (const char *rom_filename) } else { - S9xReset (); - CPU.Flags = flags; Settings.Paused = 1; diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp index f7713978..21e5ea34 100644 --- a/gtk/src/gtk_s9xwindow.cpp +++ b/gtk/src/gtk_s9xwindow.cpp @@ -221,7 +221,6 @@ event_motion_notify (GtkWidget *widget, gpointer user_data) { Snes9xWindow *window = (Snes9xWindow *) user_data; - int c_width, c_height; if (!window->config->rom_loaded || window->last_width <= 0 || @@ -230,9 +229,6 @@ event_motion_notify (GtkWidget *widget, return FALSE; } - c_width = window->get_width (); - c_height = window->get_height (); - window->mouse_loc_x = (uint16) ((int) (event->x) - window->mouse_region_x) * 256 / (window->mouse_region_width <= 0 ? 1 : window->mouse_region_width); @@ -980,6 +976,8 @@ Snes9xWindow::try_open_rom (const char *filename) } else { + const char *groups[] = { "cartridge", NULL }; + GtkRecentData recent_data = { NULL, @@ -987,7 +985,7 @@ Snes9xWindow::try_open_rom (const char *filename) (gchar *) "application/x-snes-rom", (gchar *) "Snes9x", NULL, - NULL, + (gchar **) groups, FALSE }; gchar *u_filename; @@ -1837,7 +1835,7 @@ Snes9xWindow::show (void) GtkRecentFilter *filter = gtk_recent_filter_new (); GtkRecentChooser *chooser = GTK_RECENT_CHOOSER (recent_menu); - gtk_recent_filter_add_application (filter, "Snes9x"); + gtk_recent_filter_add_group (filter, "cartridge"); gtk_recent_chooser_set_local_only (chooser, TRUE); gtk_recent_chooser_set_show_icons (chooser, FALSE); gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU); diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui index 3f86e43d..bff0a613 100644 --- a/gtk/src/snes9x.ui +++ b/gtk/src/snes9x.ui @@ -1,5822 +1,108 @@ - + - - GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_SUBSTRUCTURE_MASK - Snes9x - - - - - - - - - True - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - True - _File - True - - - - - _Open ROM Image... - True - True - image2 - False - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Open Recent - True - - - - - True - - - - - Open with _NetPlay... - True - Open a ROM to use with NetPlay - True - image3 - False - - - - - - True - Open _MultiCart... - True - - - - - - True - - - - - True - _Load State - True - - - - - - True - Slot _0 - True - - - - - - True - Slot _1 - True - - - - - - True - Slot _2 - True - - - - - - True - Slot _3 - True - - - - - - True - Slot _4 - True - - - - - - True - Slot _5 - True - - - - - - True - Slot _6 - True - - - - - - True - Slot _7 - True - - - - - - True - Slot _8 - True - - - - - - True - - - - - True - From _File... - True - - - - - - - - - - True - _Save State - True - - - - - - True - Slot _0 - True - - - - - - True - Slot _1 - True - - - - - - True - Slot _2 - True - - - - - - True - Slot _3 - True - - - - - - True - Slot _4 - True - - - - - - True - Slot _5 - True - - - - - - True - Slot _6 - True - - - - - - True - Slot _7 - True - - - - - - True - Slot _8 - True - - - - - - True - - - - - True - To _File... - True - - - - - - - - - - True - - - - - Save SPC... - True - True - image4 - False - - - - - - True - - - - - Show ROM _Info... - True - True - image5 - False - - - - - - True - - - - - _Quit - True - True - image18 - False - - - - - - - - - - True - _Emulation - True - - - - - Run / _Continue - True - True - image6 - False - - - - - - _Pause - True - True - image7 - False - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - Load _Movie... - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - image8 - False - - - - - - R_ecord Movie... - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - image19 - False - - - - - - _Stop Recording - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - image9 - False - - - - - - _Jump to Frame... - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - image10 - False - - - - - - True - - - - - Sy_nc Clients - True - True - image11 - False - - - - - - True - - - - - Reset - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - image12 - False - - - - - - Soft _Reset - True - True - image13 - False - - - - - - - - - - True - _View - True - - - - - - _Hide Menu - True - True - image14 - False - - - - - - True - _Status Bar - True - - - - - - True - - - - - _Change Size - True - True - image17 - False - - - True - - - True - False - Exact Pixels - True - - - - - True - _1x - True - - - - - - True - _2x - True - - - - - - True - _3x - True - - - - - - True - _4x - True - - - - - - True - _5x - True - - - - - - True - - - - - True - False - Correct Aspect - True - - - - - True - 1x - True - - - - - - True - 2x - True - - - - - - True - 3x - True - - - - - - True - 4x - True - - - - - - True - 5x - True - - - - - - - - - - True - - - - - _Fullscreen - True - True - image15 - False - - - - - - - - - - True - _Options - True - - - - - True - Controller Ports - True - - - - - True - SNES Port 1 - True - - - - - - True - Joypad - True - - - - - - True - Mouse - True - joypad1 - - - - - - True - Superscope - True - True - joypad1 - - - - - - - - - - True - SNES Port 2 - True - - - - - - True - Joypad - True - - - - - - True - Mouse - True - joypad2 - - - - - - True - Multitap - True - joypad2 - - - - - - True - Superscope - True - True - joypad2 - - - - - - - - - - - - - - True - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - _Cheats... - True - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - _Preferences... - True - True - image16 - False - - - - - - - - - - False - 0 - - - - - 256 - 224 - True - True - GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK | GDK_SUBSTRUCTURE_MASK - - - - - - - - 1 - - - - - True - - - False - 2 - - - - - - - GDK_KEY_PRESS_MASK - Snes9x Preferences - center - 480 - dialog + + 560 + 448 + False + About Snes9x + normal True - - - + True + False + 2 - + True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + 5 - + True - True - left - 0 - 1 - 0 - + False + 5 - + True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - never - automatic - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - queue - none - - - True - 5 - - - True - 0 - none - - - True - 5 - 5 - 12 - - - True - 5 - - - Use fullscreen on ROM open - True - True - False - Go to fullscreen mode immediately after opening a ROM - True - True - - - False - False - 0 - - - - - Show frame rate - True - True - False - True - True - - - False - False - 1 - - - - - Use overscanned height - True - True - False - Use SNES extended height. Will probably cause letterboxing - True - True - - - False - False - 2 - - - - - True - 12 - - - Change fullscreen resolution: - True - True - False - Changes the screen resolution when running Snes9x in fullscreen mode - True - True - - - False - False - 0 - - - - - True - liststore14 - - - - 0 - - - - - 1 - - - - - False - False - 3 - - - - - - - - - True - <b>Basic Settings</b> - True - - - - - False - 0 - - - - - True - 0 - none - - - True - 5 - 5 - 12 - - - True - 5 - - - Scale image to fit window - True - True - False - Scales the image so no black bars are present - True - True - - - False - False - 0 - - - - - True - 12 - - - Maintain aspect-ratio: - True - True - False - Scales the image as large as possible without distortion - True - True - - - False - False - 0 - - - - - True - liststore13 - - - - 0 - - - - - False - 1 - - - - - 1 - - - - - True - 5 - - - Use - True - True - False - Allows scaling and filtering to use multiple processors - True - True - - - False - False - 0 - - - - - True - True - adjustment17 - True - True - - - False - 1 - - - - - True - threads for filtering and scaling - - - False - 2 - - - - - 2 - - - - - True - 12 - - - True - High-resolution effect: - - - False - 0 - - - - - True - liststore15 - - - - 0 - - - - - False - 1 - - - - - 3 - - - - - True - 12 - - - True - 0 - Apply scaling filter: - - - False - 0 - - - - - True - liststore12 - - - - - 0 - - - - - False - 1 - - - - - False - False - 4 - - - - - - - - - True - <b>Image Adjustments</b> - True - - - - - False - 1 - - - - - True - 0 - none - - - True - 5 - 5 - 12 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Video preset: - - - False - 0 - - - - - True - - - Composite - True - True - True - - - - False - 0 - - - - - S-Video - True - True - True - - - - False - 1 - - - - - RGB - True - True - True - - - - False - 2 - - - - - Monochrome - True - True - True - - - - False - 3 - - - - - False - 1 - - - - - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 11 - 2 - 12 - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Artifacts: - - - 6 - 7 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Sharpness: - - - 4 - 5 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Brightness: - - - 3 - 4 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Contrast: - - - 2 - 3 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Saturation: - - - 1 - 2 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Hue: - - - GTK_FILL - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment16 - False - -1 - 2 - left - - - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment15 - False - -1 - 2 - left - - - 1 - 2 - 1 - 2 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment14 - False - -1 - 2 - left - - - 1 - 2 - 2 - 3 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment13 - False - -1 - 2 - left - - - 1 - 2 - 3 - 4 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment12 - False - -1 - 2 - left - - - 1 - 2 - 4 - 5 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment11 - False - -1 - 2 - left - - - 1 - 2 - 6 - 7 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment10 - False - -1 - 2 - left - - - 1 - 2 - 7 - 8 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment9 - False - -1 - 2 - left - - - 1 - 2 - 8 - 9 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment8 - False - -1 - 2 - left - - - 1 - 2 - 9 - 10 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - adjustment7 - False - -1 - 2 - left - - - 1 - 2 - 10 - 11 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Gamma: - - - 7 - 8 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Fringing: - - - 8 - 9 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Bleed: - - - 9 - 10 - GTK_FILL - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Resolution: - - - 10 - 11 - GTK_FILL - - - - - True - - - 2 - 5 - 6 - - - - - 1 - - - - - Merge odd and even fields - True - True - False - True - - - 2 - - - - - True - 12 - - - True - 0 - Scanline intensity: - - - False - 0 - - - - - True - liststore11 - - - - 0 - - - - - False - 1 - - - - - 3 - - - - - - - - - True - <b>NTSC Filter</b> - True - - - - - False - 2 - - - - - True - 0 - none - - - True - 5 - 5 - 12 - - - True - 12 - - - True - 0 - Scanline intensity: - - - False - 0 - - - - - True - liststore10 - - - - 0 - - - - - False - 1 - - - - - - - - - True - <b>Scanline Filter</b> - True - - - - - False - 3 - - - - - True - 0 - none - - - True - 5 - 5 - 12 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - liststore9 - - - - - 0 - - - - - 0 - - - - - Bilinear-filter output - True - True - False - True - True - - - 1 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - Sync to vertical blank - True - True - False - Sync the image to the vertical retrace to stop tearing - True - True - - - False - False - 0 - - - - - Reduce input lag - True - True - False - Sync the program with the video output after every displayed frame to reduce input latency - True - - - 1 - - - - - Allow non-power-of-two textures - True - True - False - Prevents edge artifacts, but can slow performance - True - - - 2 - - - - - Use pixel-buffer objects - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Can be faster or slower depending on drivers - True - - - 3 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Different formats can yield highly different performance - 10 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Pixel-buffer format: - - - False - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - liststore8 - - - - 0 - - - - - False - 1 - - - - - - - 4 - - - - - True - 5 - - - Use GLSL shader: - True - True - False - 0 - True - - - False - 0 - - - - - True - True - - True - - - 1 - - - - - Browse... - True - True - True - - - - False - 2 - - - - - 5 - - - - - 2 - - - - - True - - - Force an inverted byte-ordering - True - True - False - Forces a swapped byte-ordering for cases where the system's endian is used instead of the video card - True - - - 0 - - - - - 3 - - - - - - - - - True - <b>Hardware Acceleration</b> - True - - - - - False - 4 - - - - - - + False + gtk-missing-image - - - True - - - True - video-display - - - 0 - - - - - True - Display - True - - - False - False - 1 - - - - - False - - + + + False + True + 0 + + + + + True + False + 0 + 10 + 10 + label106 + True + center + True + + + False + True + 1 + + + + + True + False + queue - - True - True - never - automatic - - - True - queue - none - - - True - 5 - 0 - none - - - True - 12 - - - True - 5 - 5 - - - True - 12 - - - True - Sound driver: - - - False - False - 0 - - - - - True - liststore7 - - - - 0 - - - - - False - False - 1 - - - - - False - False - 0 - - - - - Synchronize with sound - True - True - False - Base emulation speed on the rate sound is output - True - - - False - False - 1 - - - - - Mute sound output - True - True - False - Disables output of sound - True - True - - - False - False - 2 - - - - - Stereo - True - True - False - Output two channels, left and right - True - True - - - False - False - 3 - - - - - True - 4 - 2 - 10 - 5 - - - True - 0 - Playback rate: - - - GTK_FILL - - - - - - True - 5 - - - True - True - adjustment6 - True - True - - - False - 0 - - - - - True - milliseconds - - - False - 1 - - - - - 1 - 2 - 3 - 4 - GTK_FILL - GTK_FILL - - - - - True - 0 - Buffer size: - - - 3 - 4 - GTK_FILL - GTK_FILL - - - - - True - 0 - Input rate: - - - 1 - 2 - GTK_FILL - - - - - True - True - Adjust to produce more or less data. Decrease the rate if experiencing crackling. Increase the rate if experiencing frame-rate stuttering. Best used with the "Synchronize with sound" option - adjustment5 - False - 0 - left - - - 1 - 2 - 1 - 2 - - - - - True - - - True - liststore6 - - - - 0 - - - - - False - False - 0 - - - - - 1 - 2 - GTK_FILL - - - - - True - 0 - Video rate: - - - 2 - 3 - GTK_FILL - - - - - True - label - - - 1 - 2 - 2 - 3 - - - - - False - 4 - - - - - - - - - True - <b>Sound Settings</b> - True - - - - - - - - - 1 - - - - - True - - - True - audio-x-generic - - - 0 - - - - - True - Sound - True - - - False - False - 1 - - - - - 1 - False - - - - + True True automatic - automatic - - True - queue - none - - - True - - - True - 5 - 0 - none - - - True - 12 - - - True - 5 - 5 - - - True - 10 - - - True - Frameskip: - - - False - False - 0 - - - - - True - liststore5 - - - - 0 - - - - - False - False - 1 - - - - - False - 0 - - - - - Block invalid VRAM access - True - True - False - True - - - 1 - - - - - Allow opposing dpad directions - True - True - False - Let left and right or up and down be pressed at the same time - True - - - 2 - - - - - - - - - True - <b>Accuracy</b> - True - - - - - False - 0 - - - - - True - 5 - 0 - none - - - True - 12 - - - True - 5 - 5 - - - Pause emulation when switching away from Snes9x - True - True - False - True - - - 0 - - - - - True - 12 - - - True - The ESC key should: - - - False - 0 - - - - - True - liststore4 - - - - 0 - - - - - False - 1 - - - - - 1 - - - - - - - - - True - <b>Window Switching</b> - True - - - - - False - 1 - - - - - True - 5 - 0 - none - - - True - 12 - - - True - 5 - - - Prevent the screensaver from activating - True - True - False - True - - - 0 - - - - - - - - - True - <b>Screensaver</b> - True - - - - - False - 2 - - - - - - - - - 2 - - - - - True - - - True - utilities-terminal - - - 0 - - - - - True - Emulation - True - - - False - False - 1 - - - - - 2 - False - - - - - True - 5 - - - True - 5 - 0 - none - - - True - 12 - - - True - 5 - - - True - 5 - 3 - 5 - 5 - - - True - True - False - - gtk-clear - - - - - 1 - 2 - - - - - True - True - False - - gtk-clear - - - - - 1 - 2 - 1 - 2 - - - - - True - True - False - - gtk-clear - - - - - 1 - 2 - 2 - 3 - - - - - True - True - False - - gtk-clear - - - - - 1 - 2 - 3 - 4 - - - - - True - True - False - - gtk-clear - - - - - 1 - 2 - 4 - 5 - - - - - Browse... - True - True - True - - - - 2 - 3 - GTK_FILL - - - - - - Browse... - True - True - True - - - - 2 - 3 - 1 - 2 - GTK_FILL - - - - - - Browse... - True - True - True - - - - 2 - 3 - 2 - 3 - GTK_FILL - - - - - - Browse... - True - True - True - - - - 2 - 3 - 3 - 4 - GTK_FILL - - - - - - Browse... - True - True - True - - - - 2 - 3 - 4 - 5 - GTK_FILL - - - - - - True - 0 - SRAM: - - - GTK_FILL - - - - - True - 0 - Save states: - - - 1 - 2 - GTK_FILL - - - - - True - 0 - Cheats: - - - 2 - 3 - GTK_FILL - - - - - True - 0 - Patches: - - - 3 - 4 - GTK_FILL - - - - - True - 0 - Exports: - - - 4 - 5 - GTK_FILL - - - - - False - 0 - - - - - - - - - True - <b>Game Data Locations</b> - True - - - - - False - 0 - - - - - True - 0 - none - - - True - 5 - 12 - - - True - 5 - - - True - Save SRAM: - - - False - 0 - - - - - True - True - Automatically save the game's SRAM at this interval. Setting this to 0 will only save when quitting or changing ROMs - - 5 - 1 - - - False - 1 - - - - - True - seconds after change - - - False - 2 - - - - - - - - - True - <b>Automatic Saving</b> - True - - - - - False - 1 - - - - - 3 - - - - - True - - - True - folder - - - 0 - - - - - True - Files - True - - - False - False - 1 - - - - - 3 - False - - - - - True - 5 - 5 - - - True - 5 - - - True - 5 - <b>Joypad:</b> - True - - - False - False - 0 - - - - - True - liststore3 - - - - - 0 - - - - - False - 1 - - - - - True - - - False - 2 - - - - - _Reset - True - True - True - True - - - - False - False - 3 - - - - - True - - - False - 4 - - - - - True - Swap with: - - - False - 5 - - - - - True - liststore2 - - - - 0 - - - - - False - 6 - - - - - _Swap - True - True - True - True - - - - False - 7 - - - - - False - 0 - - - - - Use modifier keys (CTRL, SHIFT, ALT) directly + True True - False - Allow using modifier keys as independent keys instead of modifiers - True - True + False + False + textbuffer1 - - False - False - 1 - - - - - True - True - - - - True - 10 - 12 - - - True - 6 - 2 - 10 - 5 - - - True - 0 - Up - - - GTK_FILL - - - - - - True - 0 - Down - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - Left - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Right - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - Start - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - Select - - - 5 - 6 - GTK_FILL - - - - - - 50 - True - True - False - - - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 0 - - - - - True - 6 - 2 - 10 - 5 - - - True - 0 - A - - - GTK_FILL - - - - - - True - 0 - B - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - X - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Y - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - L - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - R - - - 5 - 6 - GTK_FILL - - - - - - 50 - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - GTK_FILL - - - - - 1 - - - - - - - True - Buttons - - - False - - - - - True - 5 - 2 - 2 - 5 - - - True - 5 - 6 - 2 - 10 - 5 - - - True - 0 - A - - - GTK_FILL - - - - - - True - 0 - B - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - X - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Y - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - L - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - R - - - 5 - 6 - GTK_FILL - - - - - - 50 - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - GTK_FILL - - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - 5 - 6 - 2 - 10 - 5 - - - True - 0 - A - - - GTK_FILL - - - - - - True - 0 - B - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - X - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Y - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - L - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - R - - - 5 - 6 - GTK_FILL - - - - - - 50 - True - True - False - - - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 1 - 2 - GTK_FILL - - - - - True - 0 - <b>Sticky</b> - True - center - - - 1 - 2 - - - - - - - True - 0 - <b>Turbo</b> - True - center - - - - - - - - - 1 - False - - - - - True - Turbo / Sticky Buttons - - - 1 - False - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 0 - none - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - 5 - 5 - - - True - Set new axis bindings at: - - - False - False - 0 - - - - - True - True - Changes the amount a joystick should be tilted to register a button press - adjustment4 - 1 - True - - - False - False - 1 - - - - - True - percent - - - False - False - 2 - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Joystick Axis Threshold</b> - True - - - - - False - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - none - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Center all axes on all joysticks and press Calibrate. - - - False - False - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - Cali_brate - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 0 - - - - - - - - False - False - 1 - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - <b>Calibration</b> - True - - - - - 1 - - - - - 2 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Joystick Options - - - 2 - False - - - - - 2 - - - - - True - <small>Click an entry and then press the desired keys or joystick button -<i>Escape</i>: Move to next<i> Shift-Escape</i>: Clear selected</small> - True - fill - True - - - False - 3 - - - 4 - - - - - True - - - True - input-gaming - - - 0 - - - - - True - Joypads - True - - - False - False - 1 - - - - - 4 - False - - - - - True - 5 - 5 - - - True - 0 - 5 - <b>Snes9x Emulator Shortcut Keys</b> - True - - - False - False - 0 - - - - - True - - - False - False - 1 - - - - - True - True - - - - True - True - never - automatic - - - True - queue - none - - - True - 10 - 11 - 2 - 10 - 5 - - - True - 0 - Soft reset - - - 9 - 10 - GTK_FILL - - - - - - True - 0 - Hardware reset - - - 8 - 9 - GTK_FILL - - - - - - True - 0 - Increase frame time - - - 7 - 8 - GTK_FILL - - - - - - True - 0 - Decrease frame time - - - 6 - 7 - GTK_FILL - - - - - - True - 0 - Increase frame rate - - - 5 - 6 - GTK_FILL - - - - - - True - 0 - Decrease frame rate - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - Pause - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - Toggle turbo - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Enable turbo - - - 1 - 2 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Open ROM - - - GTK_FILL - - - - - - True - 0 - Quit Snes9x - - - 10 - 11 - GTK_FILL - GTK_FILL - - - - - True - True - False - - - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 7 - 8 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 8 - 9 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 9 - 10 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 10 - 11 - GTK_FILL - - - - - - - - - - - True - Emulation - - - False - - - - - True - True - never - automatic - - - True - queue - none - - - True - 10 - 8 - 2 - 10 - 5 - - - True - 0 - Toggle BG layer 0 - - - GTK_FILL - - - - - - True - 0 - Toggle BG layer 1 - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - Toggle BG layer 2 - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Toggle BG layer 3 - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - Toggle sprites - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - BG layering hack - - - 5 - 6 - GTK_FILL - - - - - - True - 0 - Screenshot - - - 6 - 7 - GTK_FILL - - - - - - True - 0 - Toggle fullscreen - - - 7 - 8 - GTK_FILL - - - - - - True - True - False - - - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 7 - 8 - GTK_FILL - - - - - - - - - 1 - - - - - True - Graphics - - - 1 - False - - - - - True - True - never - automatic - - - True - queue - none - - - True - 10 - 10 - 4 - 10 - 5 - - - True - 0 - <b>Quick save state</b> - True - center - - - 2 - - - - - - - True - 0 - <b>Quick load state</b> - True - - - 2 - 4 - - - - - - - True - 0 - Slot 1 - - - 2 - 3 - - - - - - - True - 0 - Slot 0 - - - 1 - 2 - - - - - - - True - 0 - Slot 2 - - - 3 - 4 - - - - - - - True - 0 - Slot 3 - - - 4 - 5 - - - - - - - True - 0 - Slot 4 - - - 5 - 6 - - - - - - - True - 0 - Slot 5 - - - 6 - 7 - - - - - - - True - 0 - Slot 6 - - - 7 - 8 - - - - - - - True - 0 - Slot 7 - - - 8 - 9 - - - - - - - True - 0 - Slot 0 - - - 2 - 3 - 1 - 2 - - - - - - - True - 0 - Slot 1 - - - 2 - 3 - 2 - 3 - - - - - - - True - 0 - Slot 2 - - - 2 - 3 - 3 - 4 - - - - - - - True - 0 - Slot 3 - - - 2 - 3 - 4 - 5 - - - - - - - True - 0 - Slot 4 - - - 2 - 3 - 5 - 6 - - - - - - - True - 0 - Slot 5 - - - 2 - 3 - 6 - 7 - - - - - - - True - 0 - Slot 6 - - - 2 - 3 - 7 - 8 - - - - - - - True - 0 - Slot 7 - - - 2 - 3 - 8 - 9 - - - - - - - True - 0 - Slot 8 - - - 2 - 3 - 9 - 10 - - - - - - - True - 0 - Slot 8 - - - 9 - 10 - - - - - - - 50 - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 7 - 8 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 8 - 9 - GTK_FILL - - - - - 50 - True - True - False - - - 1 - 2 - 9 - 10 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 1 - 2 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 3 - 4 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 2 - 3 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 4 - 5 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 5 - 6 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 9 - 10 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 7 - 8 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 6 - 7 - GTK_FILL - - - - - 50 - True - True - False - - - 3 - 4 - 8 - 9 - GTK_FILL - - - - - - - - - 2 - - - - - True - Save States - - - 2 - False - - - - - True - True - never - automatic - - - True - queue - none - - - True - 10 - 9 - 2 - 10 - 5 - - - True - 0 - Toggle sound channel 0 - - - GTK_FILL - - - - - - True - 0 - Toggle sound channel 1 - - - 1 - 2 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 2 - - - 2 - 3 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 3 - - - 3 - 4 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 4 - - - 4 - 5 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 5 - - - 5 - 6 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 6 - - - 6 - 7 - GTK_FILL - - - - - - True - 0 - Toggle sound channel 7 - - - 7 - 8 - GTK_FILL - - - - - - True - 0 - Toggle all sound channels - - - 8 - 9 - GTK_FILL - - - - - - True - True - False - - - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 6 - 7 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 7 - 8 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 8 - 9 - GTK_FILL - - - - - - - - - 3 - - - - - True - Sound - - - 3 - False - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - 6 - 2 - 10 - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Seek to frame - - - 4 - 5 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Load Movie - - - 3 - 4 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Stop movie recording - - - 2 - 3 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Begin movie recording - - - 1 - 2 - GTK_FILL - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Save SPC - - - GTK_FILL - - - - - - True - True - False - - - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 3 - 4 - GTK_FILL - - - - - True - True - False - - - 1 - 2 - 4 - 5 - GTK_FILL - - - - - True - 0 - Swap controllers 1 & 2 - - - 5 - 6 - GTK_FILL - - - - - - True - True - - - 1 - 2 - 5 - 6 - GTK_FILL - - - - - 4 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Misc - - - 4 - False - - - - - 2 - - - - - True - <small>Click an entry and then press the desired keys or joystick button -<i>Escape</i>: Move to next<i> Shift-Escape</i>: Clear selected</small> - True - fill - True - - - False - False - 3 - - - - - 5 - - - - - True - - - True - input-keyboard - - - 0 - - - - - True - Shortcuts - True - - - False - False - 1 - - - - - 5 - False - + + True + True + 2 + - 2 + True + True + 0 - + True + False end - - gtk-cancel + + gtk-close True True - True - False + True + False True @@ -5825,15 +111,307 @@ 0 + + + False + True + end + 1 + + + + + + button15 + + + + 1 + 60 + 1 + 1 + 1 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 1.0408340855860843e-17 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + 2 + 8 + 2 + 1 + 1 + + + 1 + 9999 + 6096 + 1 + 1 + + + 1 + 9999 + 6096 + 1 + 1 + + + 1 + 100 + 50 + 1 + 10 + + + 31500 + 32500 + 31990 + 1 + 10 + + + 2 + 256 + 2 + 1 + 1 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + -1 + 1 + 0.01 + 0.10000000000000001 + + + 512 + 350 + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + Snes9x Cheats + center-on-parent + dialog + True + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + end - - gtk-apply + + gtk-close True True - True - False + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True - + + + False + False + 0 + + + + + False + True + end + 0 + + + + + True + False + 5 + + + True + False + 0 + in + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + + + + True + True + 0 + + + + + True + False + 5 + 5 + + + True + False + 0 + Code: + + + False + True + 0 + + + + + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + False + False + True + True + + + False + True + 1 + + + + + True + False + 0 + Description: + + + False + True + 2 + + + + + True + True + 21 + True + False + False + True + True + + + False + True + 3 + + + + + gtk-add + True + True + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + False + False + 4 + + + + + gtk-remove + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + False + False + 5 + + False @@ -5841,54 +419,21 @@ 1 - - - gtk-ok - True - True - True - False - True - - - False - False - 2 - - - - - gtk-about - True - True - True - True - - - - False - False - 3 - True - - - False - end - 0 + True + True + 1 - cancel_button - ok_button - button1 - button8 + button7 + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 Advance to Frame @@ -5898,67 +443,13 @@ True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 2 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - 10 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - The current frame in the movie is - True - - - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 10 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Fast-forward to frame - - - 0 - - - - - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - 1 - - - - - 1 - - - - - False - 1 - - True + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK end @@ -5968,6 +459,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -5985,6 +477,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -5996,10 +489,84 @@ False + True end 0 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 10 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + The current frame in the movie is + True + + + True + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Fast-forward to frame + + + True + True + 0 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + True + False + False + True + True + + + True + True + 1 + + + + + True + True + 1 + + + + + False + True + 1 + + @@ -6007,6 +574,114 @@ button2 + + True + False + gtk-media-next + 1 + + + True + False + gtk-revert-to-saved + 1 + + + True + False + gtk-redo + 1 + + + True + False + gtk-refresh + 1 + + + True + False + gtk-leave-fullscreen + 1 + + + True + False + gtk-fullscreen + 1 + + + True + False + gtk-preferences + 1 + + + True + False + gtk-zoom-in + 1 + + + True + False + gtk-quit + 1 + + + True + False + gtk-media-record + 1 + + + True + False + gtk-open + 1 + + + True + False + gtk-network + 1 + + + True + False + gtk-save + 1 + + + True + False + gtk-dialog-info + 1 + + + True + False + gtk-go-forward + 1 + + + True + False + gtk-media-pause + 1 + + + True + False + gtk-open + 1 + + + True + False + gtk-media-stop + 1 + @@ -6024,6 +699,127 @@ + + + + + + + + 12.5% + + + 25% + + + 50% + + + 100% + + + + + + + + + + + 0% + + + 12.5% + + + 25% + + + 50% + + + 100% + + + + + + + + + + + None + + + SuperEagle + + + 2xSaI + + + Super2xSaI + + + EPX + + + EPX Smooth + + + Blargg's NTSC + + + Scanlines + + + Simple2x + + + Simple3x + + + Simple4x + + + + + + + + + + + 8:7 Square pixels + + + 4:3 SNES correct aspect + + + + + + + + + + + + + + + + + Merge adjacent pairs + + + Output directly + + + Scale low-resolution screens + + + @@ -6219,274 +1015,977 @@ - - - - - - - - 12.5% - - - 25% - - - 50% - - - 100% - - - - - - - - - - - 0% - - - 12.5% - - - 25% - - - 50% - - - 100% - - - - - - - - - - - None - - - SuperEagle - - - 2xSaI - - - Super2xSaI - - - EPX - - - EPX Smooth - - - Blargg's NTSC - - - Scanlines - - - Simple2x - - - Simple3x - - - Simple4x - - - - - - - - - - - 8:7 Square pixels - - - 4:3 SNES correct aspect - - - - - - - - - - - - - - - - - Merge adjacent pairs - - - Output directly - - - Scale low-resolution screens - - - - - 512 - 350 - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 5 - Snes9x Cheats - center-on-parent - dialog - True - - + + False + GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_SUBSTRUCTURE_MASK + Snes9x + + + + + + + + True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 2 + False - + True - 5 + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + True - 0 - in - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + False + _File + True + + + False + + + _Open ROM Image... + True + False + False + True + image2 + False + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + Open Recent + True + + + + + True + False + + + + + Open with _NetPlay... + True + False + Open a ROM to use with NetPlay + False + True + image3 + False + + + + + + True + False + False + Open _MultiCart... + True + + + + + + True + False + + + + + True + False + False + _Load State + True + + + + False + + + True + False + False + Slot _0 + True + + + + + + True + False + False + Slot _1 + True + + + + + + True + False + False + Slot _2 + True + + + + + + True + False + False + Slot _3 + True + + + + + + True + False + False + Slot _4 + True + + + + + + True + False + False + Slot _5 + True + + + + + + True + False + False + Slot _6 + True + + + + + + True + False + False + Slot _7 + True + + + + + + True + False + False + Slot _8 + True + + + + + + True + False + + + + + True + False + False + From _File... + True + + + + + + + + + + True + False + False + _Save State + True + + + + False + + + True + False + False + Slot _0 + True + + + + + + True + False + False + Slot _1 + True + + + + + + True + False + False + Slot _2 + True + + + + + + True + False + False + Slot _3 + True + + + + + + True + False + False + Slot _4 + True + + + + + + True + False + False + Slot _5 + True + + + + + + True + False + False + Slot _6 + True + + + + + + True + False + False + Slot _7 + True + + + + + + True + False + False + Slot _8 + True + + + + + + True + False + + + + + True + False + False + To _File... + True + + + + + + + + + + True + False + + + + + Save SPC... + True + False + False + True + image4 + False + + + + + + True + False + + + + + Show ROM _Info... + True + False + False + True + image5 + False + + + + + + True + False + + + + + _Quit + True + False + False + True + image18 + False + + + - - - - - 0 - - + True - 5 - 5 - - - True - 0 - Code: + False + False + _Emulation + True + + + False + + + Run / _Continue + True + False + False + True + image6 + False + + + + + + _Pause + True + False + False + True + image7 + False + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + Load _Movie... + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + image8 + False + + + + + + R_ecord Movie... + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + image19 + False + + + + + + _Stop Recording + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + image9 + False + + + + + + _Jump to Frame... + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + image10 + False + + + + + + True + False + + + + + Sy_nc Clients + True + False + False + True + image11 + False + + + + + + True + False + + + + + Reset + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + image12 + False + + + + + + Soft _Reset + True + False + False + True + image13 + False + + + + + + + + + + True + False + False + _View + True + + + + False + + + _Hide Menu + True + False + False + True + image14 + False + + + + + + True + False + False + _Status Bar + True + + + + + + True + False + + + + + _Change Size + True + False + False + True + image17 + False + + + True + False + + + True + False + False + False + Exact Pixels + True + + + + + True + False + False + _1x + True + + + + + + True + False + False + _2x + True + + + + + + True + False + False + _3x + True + + + + + + True + False + False + _4x + True + + + + + + True + False + False + _5x + True + + + + + + True + False + + + + + True + False + False + False + Correct Aspect + True + + + + + True + False + False + 1x + True + + + + + + True + False + False + 2x + True + + + + + + True + False + False + 3x + True + + + + + + True + False + False + 4x + True + + + + + + True + False + False + 5x + True + + + + + + + + + + True + False + + + + + _Fullscreen + True + False + False + True + image15 + False + + + + + + + + + + True + False + False + _Options + True + + + False + + + True + False + False + Controller Ports + True + + + False + + + True + False + False + SNES Port 1 + True + + + + False + + + True + False + False + Joypad + True + + + + + + True + False + False + Mouse + True + joypad1 + + + + + + True + False + False + Superscope + True + True + joypad1 + + + + + + + + + + True + False + False + SNES Port 2 + True + + + + False + + + True + False + False + Joypad + True + + + + + + True + False + False + Mouse + True + joypad2 + + + + + + True + False + False + Multitap + True + joypad2 + + + + + + True + False + False + Superscope + True + True + joypad2 + + + + + + + + + + + + + + True + False + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + _Cheats... + True + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + _Preferences... + True + False + False + True + image16 + False + + + - - False - 0 - - - - - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - False - 1 - - - - - True - 0 - Description: - - - False - 2 - - - - - True - True - 21 - True - - - False - 3 - - - - - gtk-add - True - True - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 4 - - - - - gtk-remove - True - True - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - - - - False - False - 5 - - - False - False - 1 - + False + True + 0 + + + + + 256 + 224 + True + True + False + GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK | GDK_SUBSTRUCTURE_MASK + + + + + + + + True + True 1 - - + + True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + + + False + True + 2 + + + + + + + False + 5 + Open Multiple ROM Images (MultiCart) + center-on-parent + 320 + dialog + + + True + False + + + True + False end - - gtk-close + + gtk-cancel True True True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False True @@ -6495,20 +1994,122 @@ 0 + + + gtk-ok + True + True + True + False + True + + + False + False + 1 + + False + True end 0 + + + True + False + 5 + + + True + False + 12 + + + True + False + Slot A: + + + False + True + 0 + + + + + True + False + Select an Image for Slot A + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + 12 + + + True + False + Slot B: + + + False + True + 0 + + + + + True + False + Select an Image for Slot B + + + True + True + 1 + + + + + False + True + 1 + + + + + True + True + 1 + + - button7 + button14 + button13 + False 5 Snes9x NetPlay center-on-parent @@ -6516,344 +2117,12 @@ True + False 2 - - - True - 5 - 5 - - - True - 0 - none - - - True - 12 - - - True - 5 - 5 - - - True - True - The game chosen will be loaded before connecting. This field can be blank if the server will send the ROM image - False - - - 0 - - - - - Browse... - True - True - True - - - - False - 1 - - - - - True - True - True - - - - True - Clear entry - gtk-clear - 1 - - - - - False - 2 - - - - - - - - - True - <b>ROM Image</b> - True - - - - - False - 0 - - - - - True - 0 - none - - - True - 5 - 12 - - - True - - - Connect to another computer - True - True - False - Connect to another computer that is running Snes9x NetPlay as a server - True - True - - - 0 - - - - - True - 5 - 5 - - - True - Name or IP address: - - - False - 0 - - - - - True - True - Domain name or internet protocol address of a remote computer - - - 1 - - - - - True - Port: - - - False - 2 - - - - - True - True - Connect to specified TCP port on remote computer - adjustment3 - True - True - - - False - 3 - - - - - 1 - - - - - Act as a server - True - True - False - Host a game on this computer as Player 1, requiring extra throughput to support multitple users - True - True - connect_radio - - - - 2 - - - - - - - - - True - <b>Server</b> - True - - - - - False - 1 - - - - - True - 0 - none - - - True - 12 - - - True - 5 - 5 - - - Sync using reset - True - True - False - Reset the game when players join instead of transferring potentially unreliable freeze states - True - - - False - 0 - - - - - Send ROM image to clients - True - True - False - Send the running game image to players instead of requiring them to have their own copies - True - - - False - 1 - - - - - True - 5 - - - True - Default port: - - - False - 0 - - - - - True - True - TCP port used as a connection point for remote clients - adjustment2 - True - True - - - False - 1 - - - - - False - 2 - - - - - True - 5 - - - True - Ask server to pause when - - - False - 0 - - - - - True - True - adjustment1 - True - True - - - False - 1 - - - - - True - frames behind - - - False - 2 - - - - - False - 3 - - - - - - - - - True - <b>Settings</b> - True - - - - - 2 - - - - - 1 - - True + False end @@ -6861,6 +2130,7 @@ True True True + False True @@ -6876,6 +2146,7 @@ True True True + False True @@ -6887,10 +2158,423 @@ False + True end 0 + + + True + False + 5 + 5 + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 5 + + + True + True + The game chosen will be loaded before connecting. This field can be blank if the server will send the ROM image + False + False + False + True + True + + + True + True + 0 + + + + + Browse... + True + True + True + False + + + + False + True + 1 + + + + + True + True + True + False + + + + True + False + Clear entry + gtk-clear + 1 + + + + + False + True + 2 + + + + + + + + + True + False + <b>ROM Image</b> + True + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 5 + 12 + + + True + False + + + Connect to another computer + True + True + False + Connect to another computer that is running Snes9x NetPlay as a server + False + True + True + + + False + True + 0 + + + + + True + False + 5 + 5 + + + True + False + Name or IP address: + + + False + True + 0 + + + + + True + True + Domain name or internet protocol address of a remote computer + False + False + True + True + + + True + True + 1 + + + + + True + False + Port: + + + False + True + 2 + + + + + True + True + Connect to specified TCP port on remote computer + False + False + True + True + adjustment3 + True + True + + + False + True + 3 + + + + + False + True + 1 + + + + + Act as a server + True + True + False + Host a game on this computer as Player 1, requiring extra throughput to support multitple users + False + True + True + connect_radio + + + + False + True + 2 + + + + + + + + + True + False + <b>Server</b> + True + + + + + False + True + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + 5 + + + Sync using reset + True + True + False + Reset the game when players join instead of transferring potentially unreliable freeze states + False + True + + + False + True + 0 + + + + + Send ROM image to clients + True + True + False + Send the running game image to players instead of requiring them to have their own copies + False + True + + + False + True + 1 + + + + + True + False + 5 + + + True + False + Default port: + + + False + True + 0 + + + + + True + True + TCP port used as a connection point for remote clients + False + False + True + True + adjustment2 + True + True + + + False + True + 1 + + + + + False + True + 2 + + + + + True + False + 5 + + + True + False + Ask server to pause when + + + False + True + 0 + + + + + True + True + False + False + True + True + adjustment1 + True + True + + + False + True + 1 + + + + + True + False + frames behind + + + False + True + 2 + + + + + False + True + 3 + + + + + + + + + True + False + <b>Settings</b> + True + + + + + True + True + 2 + + + + + True + True + 1 + + @@ -6898,92 +2582,33 @@ button10 - - 5 - Open Multiple ROM Images (MultiCart) - center-on-parent - 320 + + False + GDK_KEY_PRESS_MASK + Snes9x Preferences + center + 480 dialog + True + + - + True - - - True - 5 - - - True - 12 - - - True - Slot A: - - - False - 0 - - - - - True - Select an Image for Slot A - - - 1 - - - - - False - 0 - - - - - True - 12 - - - True - Slot B: - - - False - 0 - - - - - True - Select an Image for Slot B - - - 1 - - - - - False - 1 - - - - - 1 - - + False - + True + False end - + gtk-cancel True True - True + True + False + False True @@ -6993,12 +2618,15 @@ - - gtk-ok + + gtk-apply True True - True + True + False + False True + False @@ -7006,220 +2634,5873 @@ 1 + + + gtk-ok + True + True + True + False + False + True + + + False + False + 2 + + + + + gtk-about + True + True + True + False + True + + + + False + False + 3 + True + + False + True end 0 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + True + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + never + automatic + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + queue + none + + + True + False + 5 + + + True + False + 0 + none + + + True + False + 5 + 5 + 12 + + + True + False + 5 + + + Use fullscreen on ROM open + True + True + False + Go to fullscreen mode immediately after opening a ROM + False + True + True + + + False + False + 0 + + + + + Show frame rate + True + True + False + False + True + True + + + False + False + 1 + + + + + Use overscanned height + True + True + False + Use SNES extended height. Will probably cause letterboxing + False + True + True + + + False + False + 2 + + + + + True + False + 12 + + + Change fullscreen resolution: + True + True + False + Changes the screen resolution when running Snes9x in fullscreen mode + False + True + True + + + False + False + 0 + + + + + True + False + liststore14 + + + + 0 + + + + + True + True + 1 + + + + + False + False + 3 + + + + + + + + + True + False + <b>Basic Settings</b> + True + + + + + False + False + 0 + + + + + True + False + 0 + none + + + True + False + 5 + 5 + 12 + + + True + False + 5 + + + Scale image to fit window + True + True + False + Scales the image so no black bars are present + False + True + True + + + False + False + 0 + + + + + True + False + 12 + + + Maintain aspect-ratio: + True + True + False + Scales the image as large as possible without distortion + False + True + True + + + False + False + 0 + + + + + True + False + liststore13 + + + + 0 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + 5 + + + Use + True + True + False + Allows scaling and filtering to use multiple processors + False + True + True + + + False + False + 0 + + + + + True + True + False + False + True + True + adjustment17 + True + True + + + False + True + 1 + + + + + True + False + threads for filtering and scaling + + + False + True + 2 + + + + + False + True + 2 + + + + + True + False + 12 + + + True + False + High-resolution effect: + + + False + True + 0 + + + + + True + False + liststore15 + + + + 0 + + + + + False + True + 1 + + + + + False + True + 3 + + + + + True + False + 12 + + + True + False + 0 + Apply scaling filter: + + + False + True + 0 + + + + + True + False + liststore12 + + + + + 0 + + + + + False + True + 1 + + + + + False + False + 4 + + + + + + + + + True + False + <b>Image Adjustments</b> + True + + + + + False + False + 1 + + + + + True + False + 0 + none + + + True + False + 5 + 5 + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Video preset: + + + False + True + 0 + + + + + True + False + + + Composite + True + True + True + False + + + + False + True + 0 + + + + + S-Video + True + True + True + False + + + + False + True + 1 + + + + + RGB + True + True + True + False + + + + False + True + 2 + + + + + Monochrome + True + True + True + False + + + + False + True + 3 + + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 11 + 2 + 12 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Artifacts: + + + 6 + 7 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Sharpness: + + + 4 + 5 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Brightness: + + + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Contrast: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Saturation: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Hue: + + + GTK_FILL + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment16 + False + -1 + 2 + left + + + 1 + 2 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment15 + False + -1 + 2 + left + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment14 + False + -1 + 2 + left + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment13 + False + -1 + 2 + left + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment12 + False + -1 + 2 + left + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment11 + False + -1 + 2 + left + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment10 + False + -1 + 2 + left + + + 1 + 2 + 7 + 8 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment9 + False + -1 + 2 + left + + + 1 + 2 + 8 + 9 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment8 + False + -1 + 2 + left + + + 1 + 2 + 9 + 10 + GTK_FILL + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + adjustment7 + False + -1 + 2 + left + + + 1 + 2 + 10 + 11 + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Gamma: + + + 7 + 8 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Fringing: + + + 8 + 9 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Bleed: + + + 9 + 10 + GTK_FILL + GTK_FILL + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Resolution: + + + 10 + 11 + GTK_FILL + GTK_FILL + + + + + True + False + + + 2 + 5 + 6 + GTK_FILL + + + + + False + True + 1 + + + + + Merge odd and even fields + True + True + False + False + True + + + False + True + 2 + + + + + True + False + 12 + + + True + False + 0 + Scanline intensity: + + + False + True + 0 + + + + + True + False + liststore11 + + + + 0 + + + + + False + True + 1 + + + + + False + True + 3 + + + + + + + + + True + False + <b>NTSC Filter</b> + True + + + + + False + False + 2 + + + + + True + False + 0 + none + + + True + False + 5 + 5 + 12 + + + True + False + 12 + + + True + False + 0 + Scanline intensity: + + + False + True + 0 + + + + + True + False + liststore10 + + + + 0 + + + + + False + True + 1 + + + + + + + + + True + False + <b>Scanline Filter</b> + True + + + + + False + False + 3 + + + + + True + False + 0 + none + + + True + False + 5 + 5 + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + liststore9 + + + + + 0 + + + + + False + True + 0 + + + + + Bilinear-filter output + True + True + False + False + True + True + + + False + True + 1 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + Sync to vertical blank + True + True + False + Sync the image to the vertical retrace to stop tearing + False + True + True + + + False + False + 0 + + + + + Reduce input lag + True + True + False + Sync the program with the video output after every displayed frame to reduce input latency + False + True + + + False + True + 1 + + + + + Allow non-power-of-two textures + True + True + False + Prevents edge artifacts, but can slow performance + False + True + + + False + True + 2 + + + + + Use pixel-buffer objects + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Can be faster or slower depending on drivers + False + True + + + False + True + 3 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Different formats can yield highly different performance + 10 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Pixel-buffer format: + + + False + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + liststore8 + + + + 0 + + + + + False + True + 1 + + + + + + + False + True + 4 + + + + + True + False + 5 + + + Use GLSL shader: + True + True + False + False + 0 + True + + + False + True + 0 + + + + + True + True + • + True + False + False + True + True + + + True + True + 1 + + + + + Browse... + True + True + True + False + + + + False + True + 2 + + + + + False + True + 5 + + + + + False + True + 2 + + + + + True + False + + + Force an inverted byte-ordering + True + True + False + Forces a swapped byte-ordering for cases where the system's endian is used instead of the video card + False + True + + + False + True + 0 + + + + + False + True + 3 + + + + + + + + + True + False + <b>Hardware Acceleration</b> + True + + + + + False + False + 4 + + + + + + + + + + + True + False + + + True + False + video-display + + + False + True + 0 + + + + + True + False + Display + True + + + False + False + 1 + + + + + False + + + + + True + True + never + automatic + + + True + False + queue + none + + + True + False + 5 + 0 + none + + + True + False + 12 + + + True + False + 5 + 5 + + + True + False + 12 + + + True + False + Sound driver: + + + False + False + 0 + + + + + True + False + liststore7 + + + + 0 + + + + + False + False + 1 + + + + + False + False + 0 + + + + + Synchronize with sound + True + True + False + Base emulation speed on the rate sound is output + False + True + + + False + False + 1 + + + + + Mute sound output + True + True + False + Disables output of sound + False + True + True + + + False + False + 2 + + + + + Stereo + True + True + False + Output two channels, left and right + False + True + True + + + False + False + 3 + + + + + True + False + 4 + 2 + 10 + 5 + + + True + False + 0 + Playback rate: + + + GTK_FILL + + + + + + True + False + 5 + + + True + True + False + False + True + True + adjustment6 + True + True + + + False + True + 0 + + + + + True + False + milliseconds + + + False + True + 1 + + + + + 1 + 2 + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Buffer size: + + + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Input rate: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + True + Adjust to produce more or less data. Decrease the rate if experiencing crackling. Increase the rate if experiencing frame-rate stuttering. Best used with the "Synchronize with sound" option + adjustment5 + False + 0 + left + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + False + + + True + False + liststore6 + + + + 0 + + + + + False + False + 0 + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Video rate: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + label + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + False + True + 4 + + + + + + + + + True + False + <b>Sound Settings</b> + True + + + + + + + + + 1 + + + + + True + False + + + True + False + audio-x-generic + + + False + True + 0 + + + + + True + False + Sound + True + + + False + False + 1 + + + + + 1 + False + + + + + True + True + automatic + automatic + + + True + False + queue + none + + + True + False + + + True + False + 5 + 0 + none + + + True + False + 12 + + + True + False + 5 + 5 + + + True + False + 10 + + + True + False + Frameskip: + + + False + False + 0 + + + + + True + False + liststore5 + + + + 0 + + + + + False + False + 1 + + + + + False + False + 0 + + + + + Block invalid VRAM access + True + False + False + True + + + False + True + 1 + + + + + Allow opposing dpad directions + True + True + False + Let left and right or up and down be pressed at the same time + False + True + + + False + True + 2 + + + + + + + + + True + False + <b>Accuracy</b> + True + + + + + False + False + 0 + + + + + True + False + 5 + 0 + none + + + True + False + 12 + + + True + False + 5 + 5 + + + Pause emulation when switching away from Snes9x + True + True + False + False + True + + + False + True + 0 + + + + + True + False + 12 + + + True + False + The ESC key should: + + + False + True + 0 + + + + + True + False + liststore4 + + + + 0 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + + + + + True + False + <b>Window Switching</b> + True + + + + + False + False + 1 + + + + + True + False + 5 + 0 + none + + + True + False + 12 + + + True + False + 5 + + + Prevent the screensaver from activating + True + True + False + False + True + + + False + True + 0 + + + + + + + + + True + False + <b>Screensaver</b> + True + + + + + False + False + 2 + + + + + + + + + 2 + False + + + + + True + False + + + True + False + utilities-terminal + + + False + True + 0 + + + + + True + False + Emulation + True + + + False + False + 1 + + + + + 2 + False + + + + + True + False + 5 + + + True + False + 5 + 0 + none + + + True + False + 12 + + + True + False + 5 + + + True + False + 5 + 3 + 5 + 5 + + + True + True + False + • + gtk-clear + False + False + True + True + + + + + 1 + 2 + GTK_FILL + + + + + True + True + False + • + gtk-clear + False + False + True + True + + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + False + • + gtk-clear + False + False + True + True + + + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + False + • + gtk-clear + False + False + True + True + + + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + False + • + gtk-clear + False + False + True + True + + + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + Browse... + True + True + True + False + + + + 2 + 3 + GTK_FILL + + + + + + Browse... + True + True + True + False + + + + 2 + 3 + 1 + 2 + GTK_FILL + + + + + + Browse... + True + True + True + False + + + + 2 + 3 + 2 + 3 + GTK_FILL + + + + + + Browse... + True + True + True + False + + + + 2 + 3 + 3 + 4 + GTK_FILL + + + + + + Browse... + True + True + True + False + + + + 2 + 3 + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + SRAM: + + + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Save states: + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Cheats: + + + 2 + 3 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Patches: + + + 3 + 4 + GTK_FILL + GTK_FILL + + + + + True + False + 0 + Exports: + + + 4 + 5 + GTK_FILL + GTK_FILL + + + + + False + True + 0 + + + + + + + + + True + False + <b>Game Data Locations</b> + True + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 5 + 12 + + + True + False + 5 + + + True + False + Save SRAM: + + + False + True + 0 + + + + + True + True + Automatically save the game's SRAM at this interval. Setting this to 0 will only save when quitting or changing ROMs + • + 5 + 1 + False + False + True + True + + + False + True + 1 + + + + + True + False + seconds after change + + + False + True + 2 + + + + + + + + + True + False + <b>Automatic Saving</b> + True + + + + + False + True + 1 + + + + + 3 + + + + + True + False + + + True + False + folder + + + False + True + 0 + + + + + True + False + Files + True + + + False + False + 1 + + + + + 3 + False + + + + + True + False + 5 + 5 + + + True + False + 5 + + + True + False + 5 + <b>Joypad:</b> + True + + + False + False + 0 + + + + + True + False + liststore3 + + + + + 0 + + + + + False + True + 1 + + + + + True + False + + + False + True + 2 + + + + + _Reset + True + True + True + False + True + + + + False + False + 3 + + + + + True + False + + + False + True + 4 + + + + + True + False + Swap with: + + + False + True + 5 + + + + + True + False + liststore2 + + + + 0 + + + + + False + True + 6 + + + + + _Swap + True + True + True + False + True + + + + False + True + 7 + + + + + False + True + 0 + + + + + Use modifier keys (CTRL, SHIFT, ALT) directly + True + True + False + Allow using modifier keys as independent keys instead of modifiers + False + True + True + + + False + False + 1 + + + + + True + True + + + + True + False + 10 + 12 + + + True + False + 6 + 2 + 10 + 5 + + + True + False + 0 + Up + + + GTK_FILL + + + + + + True + False + 0 + Down + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + Left + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Right + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + Start + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + Select + + + 5 + 6 + GTK_FILL + + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + True + True + 0 + + + + + True + False + 6 + 2 + 10 + 5 + + + True + False + 0 + A + + + GTK_FILL + + + + + + True + False + 0 + B + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + X + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Y + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + L + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + R + + + 5 + 6 + GTK_FILL + + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + True + True + 1 + + + + + + + True + False + Buttons + + + False + + + + + True + False + 5 + 2 + 2 + 5 + + + True + False + 5 + 6 + 2 + 10 + 5 + + + True + False + 0 + A + + + GTK_FILL + + + + + + True + False + 0 + B + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + X + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Y + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + L + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + R + + + 5 + 6 + GTK_FILL + + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + False + 5 + 6 + 2 + 10 + 5 + + + True + False + 0 + A + + + GTK_FILL + + + + + + True + False + 0 + B + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + X + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Y + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + L + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + R + + + 5 + 6 + GTK_FILL + + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + 1 + 2 + GTK_FILL + + + + + True + False + 0 + <b>Sticky</b> + True + center + + + 1 + 2 + + + + + + + True + False + 0 + <b>Turbo</b> + True + center + + + + + + + + + 1 + False + + + + + True + False + Turbo / Sticky Buttons + + + 1 + False + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + 5 + 5 + + + True + False + Set new axis bindings at: + + + False + False + 0 + + + + + True + True + Changes the amount a joystick should be tilted to register a button press + False + False + True + True + adjustment4 + 1 + True + + + False + False + 1 + + + + + True + False + percent + + + False + False + 2 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Joystick Axis Threshold</b> + True + + + + + False + True + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + none + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 12 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 5 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Center all axes on all joysticks and press Calibrate. + + + False + False + 0 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + Cali_brate + True + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + + False + False + 0 + + + + + + + + False + False + 1 + + + + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + <b>Calibration</b> + True + + + + + True + True + 1 + + + + + 2 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Joystick Options + + + 2 + False + + + + + True + True + 2 + + + + + True + False + <small>Click an entry and then press the desired keys or joystick button +<i>Escape</i>: Move to next<i> Shift-Escape</i>: Clear selected</small> + True + fill + True + + + False + True + 3 + + + + + 4 + + + + + True + False + + + True + False + input-gaming + + + False + True + 0 + + + + + True + False + Joypads + True + + + False + False + 1 + + + + + 4 + False + + + + + True + False + 5 + 5 + + + True + False + 0 + 5 + <b>Snes9x Emulator Shortcut Keys</b> + True + + + False + False + 0 + + + + + True + False + + + False + False + 1 + + + + + True + True + + + + True + True + never + automatic + + + True + False + queue + none + + + True + False + 10 + 11 + 2 + 10 + 5 + + + True + False + 0 + Soft reset + + + 9 + 10 + GTK_FILL + + + + + + True + False + 0 + Hardware reset + + + 8 + 9 + GTK_FILL + + + + + + True + False + 0 + Increase frame time + + + 7 + 8 + GTK_FILL + + + + + + True + False + 0 + Decrease frame time + + + 6 + 7 + GTK_FILL + + + + + + True + False + 0 + Increase frame rate + + + 5 + 6 + GTK_FILL + + + + + + True + False + 0 + Decrease frame rate + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + Pause + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + Toggle turbo + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Enable turbo + + + 1 + 2 + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Open ROM + + + GTK_FILL + + + + + + True + False + 0 + Quit Snes9x + + + 10 + 11 + GTK_FILL + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 7 + 8 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 8 + 9 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 9 + 10 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 10 + 11 + GTK_FILL + + + + + + + + + + + True + False + Emulation + + + False + + + + + True + True + never + automatic + + + True + False + queue + none + + + True + False + 10 + 8 + 2 + 10 + 5 + + + True + False + 0 + Toggle BG layer 0 + + + GTK_FILL + + + + + + True + False + 0 + Toggle BG layer 1 + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + Toggle BG layer 2 + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Toggle BG layer 3 + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + Toggle sprites + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + BG layering hack + + + 5 + 6 + GTK_FILL + + + + + + True + False + 0 + Screenshot + + + 6 + 7 + GTK_FILL + + + + + + True + False + 0 + Toggle fullscreen + + + 7 + 8 + GTK_FILL + + + + + + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 7 + 8 + GTK_FILL + + + + + + + + + 1 + + + + + True + False + Graphics + + + 1 + False + + + + + True + True + never + automatic + + + True + False + queue + none + + + True + False + 10 + 10 + 4 + 10 + 5 + + + True + False + 0 + <b>Quick save state</b> + True + center + + + 2 + + + + + + + True + False + 0 + <b>Quick load state</b> + True + + + 2 + 4 + + + + + + + True + False + 0 + Slot 1 + + + 2 + 3 + + + + + + + True + False + 0 + Slot 0 + + + 1 + 2 + + + + + + + True + False + 0 + Slot 2 + + + 3 + 4 + + + + + + + True + False + 0 + Slot 3 + + + 4 + 5 + + + + + + + True + False + 0 + Slot 4 + + + 5 + 6 + + + + + + + True + False + 0 + Slot 5 + + + 6 + 7 + + + + + + + True + False + 0 + Slot 6 + + + 7 + 8 + + + + + + + True + False + 0 + Slot 7 + + + 8 + 9 + + + + + + + True + False + 0 + Slot 0 + + + 2 + 3 + 1 + 2 + + + + + + + True + False + 0 + Slot 1 + + + 2 + 3 + 2 + 3 + + + + + + + True + False + 0 + Slot 2 + + + 2 + 3 + 3 + 4 + + + + + + + True + False + 0 + Slot 3 + + + 2 + 3 + 4 + 5 + + + + + + + True + False + 0 + Slot 4 + + + 2 + 3 + 5 + 6 + + + + + + + True + False + 0 + Slot 5 + + + 2 + 3 + 6 + 7 + + + + + + + True + False + 0 + Slot 6 + + + 2 + 3 + 7 + 8 + + + + + + + True + False + 0 + Slot 7 + + + 2 + 3 + 8 + 9 + + + + + + + True + False + 0 + Slot 8 + + + 2 + 3 + 9 + 10 + + + + + + + True + False + 0 + Slot 8 + + + 9 + 10 + + + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 7 + 8 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 8 + 9 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 1 + 2 + 9 + 10 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 1 + 2 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 3 + 4 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 2 + 3 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 4 + 5 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 5 + 6 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 9 + 10 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 7 + 8 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 6 + 7 + GTK_FILL + + + + + 50 + True + True + False + False + False + True + True + + + 3 + 4 + 8 + 9 + GTK_FILL + + + + + + + + + 2 + + + + + True + False + Save States + + + 2 + False + + + + + True + True + never + automatic + + + True + False + queue + none + + + True + False + 10 + 9 + 2 + 10 + 5 + + + True + False + 0 + Toggle sound channel 0 + + + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 1 + + + 1 + 2 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 2 + + + 2 + 3 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 3 + + + 3 + 4 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 4 + + + 4 + 5 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 5 + + + 5 + 6 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 6 + + + 6 + 7 + GTK_FILL + + + + + + True + False + 0 + Toggle sound channel 7 + + + 7 + 8 + GTK_FILL + + + + + + True + False + 0 + Toggle all sound channels + + + 8 + 9 + GTK_FILL + + + + + + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 6 + 7 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 7 + 8 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 8 + 9 + GTK_FILL + + + + + + + + + 3 + + + + + True + False + Sound + + + 3 + False + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 10 + 6 + 2 + 10 + 5 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Seek to frame + + + 4 + 5 + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Load Movie + + + 3 + 4 + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Stop movie recording + + + 2 + 3 + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Begin movie recording + + + 1 + 2 + GTK_FILL + + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 0 + Save SPC + + + GTK_FILL + + + + + + True + True + False + False + False + True + True + + + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 2 + 3 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 3 + 4 + GTK_FILL + + + + + True + True + False + False + False + True + True + + + 1 + 2 + 4 + 5 + GTK_FILL + + + + + True + False + 0 + Swap controllers 1 & 2 + + + 5 + 6 + GTK_FILL + + + + + + True + True + False + False + True + True + + + 1 + 2 + 5 + 6 + GTK_FILL + + + + + 4 + + + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Misc + + + 4 + False + + + + + True + True + 2 + + + + + True + False + <small>Click an entry and then press the desired keys or joystick button +<i>Escape</i>: Move to next<i> Shift-Escape</i>: Clear selected</small> + True + fill + True + + + False + False + 3 + + + + + 5 + + + + + True + False + + + True + False + input-keyboard + + + False + True + 0 + + + + + True + False + Shortcuts + True + + + False + False + 1 + + + + + 5 + False + + + + + + + True + True + 2 + + - button14 - button13 + cancel_button + ok_button + button1 + button8 - - True - gtk-open - 1 - - - True - gtk-network - 1 - - - True - gtk-save - 1 - - - True - gtk-dialog-info - 1 - - - True - gtk-quit - 1 - - - True - gtk-go-forward - 1 - - - True - gtk-media-pause - 1 - - - True - gtk-open - 1 - - - True - gtk-media-record - 1 - - - True - gtk-media-stop - 1 - - - True - gtk-media-next - 1 - - - True - gtk-revert-to-saved - 1 - - - True - gtk-redo - 1 - - - True - gtk-refresh - 1 - - - True - gtk-leave-fullscreen - 1 - - - True - gtk-zoom-in - 1 - - - True - gtk-fullscreen - 1 - - - True - gtk-preferences - 1 - - - 1 - 1 - 60 - 1 - 1 - - - 6096 - 1 - 9999 - 1 - 1 - - - 6096 - 1 - 9999 - 1 - 1 - - - 50 - 1 - 100 - 1 - 10 - - - 31990 - 31500 - 32500 - 1 - 10 - - - 2 - 2 - 256 - 1 - 1 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - 1.0408340855860843e-17 - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - -1 - 1 - 0.01 - 0.10000000000000001 - - - 2 - 2 - 8 - 1 - 1 - Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. @@ -7396,111 +8677,4 @@ Super NES and Super Nintendo Entertainment System are trademarks of Nintendo Co., Limited and its subsidiary companies. - - 560 - 448 - About Snes9x - normal - True - - - True - 2 - - - True - 5 - - - True - 5 - - - True - gtk-missing-image - - - - - False - 0 - - - - - True - 0 - 10 - 10 - label106 - True - center - True - - - False - 1 - - - - - True - queue - - - True - True - automatic - - - True - True - False - False - textbuffer1 - - - - - - - 2 - - - - - 0 - - - - - True - end - - - gtk-close - True - True - True - True - - - False - False - 0 - - - - - False - end - 1 - - - - - - button15 - - diff --git a/libretro/Makefile b/libretro/Makefile new file mode 100644 index 00000000..5958bd7e --- /dev/null +++ b/libretro/Makefile @@ -0,0 +1,53 @@ +ifeq ($(platform),) +platform = unix +ifeq ($(shell uname -a),) + platform = win +else ifneq ($(findstring Darwin,$(shell uname -a)),) + platform = osx +else ifneq ($(findstring MINGW,$(shell uname -a)),) + platform = win +else ifneq ($(findstring win,$(shell uname -a)),) + platform = win +endif +endif + +ifeq ($(platform), unix) + TARGET := libretro.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=link.T +else ifeq ($(platform), osx) + TARGET := libretro.dylib + fpic := -fPIC + SHARED := -dynamiclib +else + TARGET := libretro.dll + CC = gcc + CXX = g++ + SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=link.T + CXXFLAGS += -D__WIN32__ -D__WIN32_LIBSNES__ +endif + +OBJECTS = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o libretro.o + +CXX = g++ +CC = gcc +INCLUDES = -I. -I.. -I../apu/ -I../apu/bapu + +CXXFLAGS += -O3 -fomit-frame-pointer -fno-exceptions -fno-rtti -pedantic -Wall -W -Wno-unused-parameter $(fpic) +CXXFLAGS += -DHAVE_STRINGS_H -DHAVE_STDINT_H -DRIGHTSHIFT_IS_SAR +CFLAGS = $(CXXFLAGS) + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(fpic) $(SHARED) $(INCLUDES) -o $@ $(OBJECTS) -lm + +%.o: %.cpp + $(CXX) $(INCLUDES) $(CXXFLAGS) -c -o $@ $< + +%.o: %.c + $(CC) $(INCLUDES) $(CFLAGS) -c -o $@ $< + +clean: + rm -f $(OBJECTS) $(TARGET) + diff --git a/libretro/libretro-win32.vcproj b/libretro/libretro-win32.vcproj new file mode 100644 index 00000000..3063f48c --- /dev/null +++ b/libretro/libretro-win32.vcproj @@ -0,0 +1,786 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp new file mode 100644 index 00000000..90dc874d --- /dev/null +++ b/libretro/libretro.cpp @@ -0,0 +1,732 @@ +#include "libretro.h" + +#include "snes9x.h" +#include "memmap.h" +#include "srtc.h" +#include "apu/apu.h" +#include "apu/bapu/snes/snes.hpp" +#include "gfx.h" +#include "snapshot.h" +#include "controls.h" +#include "cheats.h" +#include "movie.h" +#include "logger.h" +#include "display.h" +#include "conffile.h" +#include +#ifndef __WIN32__ +#include +#endif +#include +#include +#include + +static retro_video_refresh_t s9x_video_cb = NULL; +static retro_audio_sample_t s9x_audio_cb = NULL; +static retro_audio_sample_batch_t s9x_audio_batch_cb = NULL; +static retro_input_poll_t s9x_poller_cb = NULL; +static retro_input_state_t s9x_input_state_cb = NULL; + +void retro_set_video_refresh(retro_video_refresh_t cb) +{ + s9x_video_cb = cb; +} + +void retro_set_audio_sample(retro_audio_sample_t cb) +{ + s9x_audio_cb = cb; +} + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) +{ + s9x_audio_batch_cb = cb; +} + +void retro_set_input_poll(retro_input_poll_t cb) +{ + s9x_poller_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) +{ + s9x_input_state_cb = cb; +} + +static retro_environment_t environ_cb; +static bool use_overscan = false; +static bool rom_loaded = false; +void retro_set_environment(retro_environment_t cb) +{ + environ_cb = cb; +} + +static void S9xAudioCallback(void*) +{ + // Just pick a big buffer. We won't use it all. + static int16_t audio_buf[0x10000]; + + S9xFinalizeSamples(); + size_t avail = S9xGetSampleCount(); + S9xMixSamples((uint8*)audio_buf, avail); + s9x_audio_batch_cb(audio_buf,avail >> 1); +} + +void retro_get_system_info(struct retro_system_info *info) +{ + memset(info,0,sizeof(retro_system_info)); + + info->library_name = "SNES9x"; + info->library_version = VERSION; + info->valid_extensions = "smc|sfc|zip|gz|swc|fig|jma"; + info->need_fullpath = false; + info->block_extract = false; +} + +void retro_get_system_av_info(struct retro_system_av_info *info) +{ + memset(info,0,sizeof(retro_system_av_info)); + + info->geometry.base_width = SNES_WIDTH; + info->geometry.base_height = use_overscan ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT; + info->geometry.max_width = MAX_SNES_WIDTH; + info->geometry.max_height = MAX_SNES_HEIGHT; + info->geometry.aspect_ratio = 4.0f / 3.0f; + info->timing.sample_rate = 32040.5; + info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0; +} + +const char *retro_library_id() +{ + return "SNES9x v" VERSION; +} + +unsigned retro_api_version() +{ + return RETRO_API_VERSION; +} + + +void retro_reset() +{ + S9xSoftReset(); +} + +static unsigned snes_devices[2]; +void retro_set_controller_port_device(unsigned port, unsigned device) +{ + switch (device) + { + case RETRO_DEVICE_JOYPAD: + S9xSetController(port, CTL_JOYPAD, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_JOYPAD; + break; + case RETRO_DEVICE_JOYPAD_MULTITAP: + S9xSetController(port, CTL_MP5, 1, 2, 3, 4); + snes_devices[port] = RETRO_DEVICE_JOYPAD_MULTITAP; + break; + case RETRO_DEVICE_MOUSE: + S9xSetController(port, CTL_MOUSE, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_MOUSE; + break; + case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: + S9xSetController(port, CTL_SUPERSCOPE, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE; + break; + case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: + S9xSetController(port, CTL_JUSTIFIER, 0, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIER; + break; + case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS: + S9xSetController(port, CTL_JUSTIFIER, 1, 0, 0, 0); + snes_devices[port] = RETRO_DEVICE_LIGHTGUN_JUSTIFIERS; + break; + default: + fprintf(stderr, "[libretro]: Invalid device!\n"); + } +} + +void retro_cheat_reset() +{} + +void retro_cheat_set(unsigned, bool, const char*) +{} + +bool retro_load_game(const struct retro_game_info *game) +{ + + if(game->data == NULL && game->size == NULL && game->path != NULL) + rom_loaded = Memory.LoadROM(game->path); + else + rom_loaded = Memory.LoadROMMem((const uint8_t*)game->data ,game->size); + + if (!rom_loaded) + { + fprintf(stderr, "[libretro]: Rom loading failed...\n"); + } + + return rom_loaded; +} + +void retro_unload_game(void) +{} + +bool retro_load_game_special(unsigned game_type, + const struct retro_game_info *info, size_t num_info) { + + switch (game_type) { + case RETRO_GAME_TYPE_BSX: + + if(num_info == 1) { + rom_loaded = Memory.LoadROMMem((const uint8_t*)info[0].data,info[0].size); + } else if(num_info == 2) { + memcpy(Memory.BIOSROM,(const uint8_t*)info[0].data,info[0].size); + rom_loaded = Memory.LoadROMMem((const uint8_t*)info[1].data,info[1].size); + } + + if (!rom_loaded) + { + fprintf(stderr, "[libretro]: BSX Rom loading failed...\n"); + } + + break; + + case RETRO_GAME_TYPE_BSX_SLOTTED: + + if(num_info == 2) + rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[0].data, info[0].size, + (const uint8_t*)info[1].data, info[1].size, NULL, NULL); + + if (!rom_loaded) + { + fprintf(stderr, "[libretro]: Multirom loading failed...\n"); + } + + break; + + case RETRO_GAME_TYPE_SUFAMI_TURBO: + + if(num_info == 3) + rom_loaded = Memory.LoadMultiCartMem((const uint8_t*)info[1].data, info[1].size, + (const uint8_t*)info[2].data, info[2].size, (const uint8_t*)info[0].data, info[0].size); + + if (!rom_loaded) + { + fprintf(stderr, "[libretro]: Sufami Turbo Rom loading failed...\n"); + } + + break; + + default: + rom_loaded = false; + break; + } + + return rom_loaded; +} + +static void map_buttons(); + + +void retro_init() +{ + if (environ_cb) + { + if (!environ_cb(RETRO_ENVIRONMENT_GET_OVERSCAN, &use_overscan)) + use_overscan = false; + } + + memset(&Settings, 0, sizeof(Settings)); + Settings.MouseMaster = TRUE; + Settings.SuperScopeMaster = TRUE; + Settings.JustifierMaster = TRUE; + Settings.MultiPlayer5Master = TRUE; + Settings.FrameTimePAL = 20000; + Settings.FrameTimeNTSC = 16667; + Settings.SixteenBitSound = TRUE; + Settings.Stereo = TRUE; + Settings.SoundPlaybackRate = 32000; + Settings.SoundInputRate = 32000; + Settings.SupportHiRes = TRUE; + Settings.Transparency = TRUE; + Settings.AutoDisplayMessages = TRUE; + Settings.InitialInfoStringTimeout = 120; + Settings.HDMATimingHack = 100; + Settings.BlockInvalidVRAMAccessMaster = TRUE; + Settings.WrongMovieStateProtection = TRUE; + Settings.DumpStreamsMaxFrames = -1; + Settings.StretchScreenshots = 0; + Settings.SnapshotScreenshots = FALSE; + Settings.CartAName[0] = 0; + Settings.CartBName[0] = 0; + Settings.AutoSaveDelay = 1; + Settings.DontSaveOopsSnapshot = TRUE; + + CPU.Flags = 0; + + if (!Memory.Init() || !S9xInitAPU()) + { + Memory.Deinit(); + S9xDeinitAPU(); + fprintf(stderr, "[libretro]: Failed to init Memory or APU.\n"); + exit(1); + } + + S9xInitSound(16, 0); + S9xSetSoundMute(FALSE); + S9xSetSamplesAvailableCallback(S9xAudioCallback, NULL); + + S9xSetRenderPixelFormat(RGB555); + GFX.Pitch = MAX_SNES_WIDTH * sizeof(uint16); + GFX.Screen = (uint16*) calloc(1, GFX.Pitch * MAX_SNES_HEIGHT); + S9xGraphicsInit(); + + S9xInitInputDevices(); + for (int i = 0; i < 2; i++) + { + S9xSetController(i, CTL_JOYPAD, i, 0, 0, 0); + snes_devices[i] = RETRO_DEVICE_JOYPAD; + } + + S9xUnmapAllControls(); + map_buttons(); + +} + +#define MAP_BUTTON(id, name) S9xMapButton((id), S9xGetCommandT((name)), false) +#define MAKE_BUTTON(pad, btn) (((pad)<<4)|(btn)) + +#define PAD_1 1 +#define PAD_2 2 +#define PAD_3 3 +#define PAD_4 4 +#define PAD_5 5 + +#define BTN_B RETRO_DEVICE_ID_JOYPAD_B +#define BTN_Y RETRO_DEVICE_ID_JOYPAD_Y +#define BTN_SELECT RETRO_DEVICE_ID_JOYPAD_SELECT +#define BTN_START RETRO_DEVICE_ID_JOYPAD_START +#define BTN_UP RETRO_DEVICE_ID_JOYPAD_UP +#define BTN_DOWN RETRO_DEVICE_ID_JOYPAD_DOWN +#define BTN_LEFT RETRO_DEVICE_ID_JOYPAD_LEFT +#define BTN_RIGHT RETRO_DEVICE_ID_JOYPAD_RIGHT +#define BTN_A RETRO_DEVICE_ID_JOYPAD_A +#define BTN_X RETRO_DEVICE_ID_JOYPAD_X +#define BTN_L RETRO_DEVICE_ID_JOYPAD_L +#define BTN_R RETRO_DEVICE_ID_JOYPAD_R +#define BTN_FIRST BTN_B +#define BTN_LAST BTN_R + +#define MOUSE_X RETRO_DEVICE_ID_MOUSE_X +#define MOUSE_Y RETRO_DEVICE_ID_MOUSE_Y +#define MOUSE_LEFT RETRO_DEVICE_ID_MOUSE_LEFT +#define MOUSE_RIGHT RETRO_DEVICE_ID_MOUSE_RIGHT +#define MOUSE_FIRST MOUSE_X +#define MOUSE_LAST MOUSE_RIGHT + +#define SCOPE_X RETRO_DEVICE_ID_SUPER_SCOPE_X +#define SCOPE_Y RETRO_DEVICE_ID_SUPER_SCOPE_Y +#define SCOPE_TRIGGER RETRO_DEVICE_ID_LIGHTGUN_TRIGGER +#define SCOPE_CURSOR RETRO_DEVICE_ID_LIGHTGUN_CURSOR +#define SCOPE_TURBO RETRO_DEVICE_ID_LIGHTGUN_TURBO +#define SCOPE_PAUSE RETRO_DEVICE_ID_LIGHTGUN_PAUSE +#define SCOPE_FIRST SCOPE_X +#define SCOPE_LAST SCOPE_PAUSE + +#define JUSTIFIER_X RETRO_DEVICE_ID_JUSTIFIER_X +#define JUSTIFIER_Y RETRO_DEVICE_ID_JUSTIFIER_Y +#define JUSTIFIER_TRIGGER RETRO_DEVICE_ID_LIGHTGUN_TRIGGER +#define JUSTIFIER_START RETRO_DEVICE_ID_LIGHTGUN_PAUSE +#define JUSTIFIER_FIRST JUSTIFIER_X +#define JUSTIFIER_LAST JUSTIFIER_START + +#define BTN_POINTER (BTN_LAST + 1) +#define BTN_POINTER2 (BTN_POINTER + 1) + +static void map_buttons() +{ + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_A), "Joypad1 A"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_B), "Joypad1 B"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_X), "Joypad1 X"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_Y), "Joypad1 Y"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_SELECT), "{Joypad1 Select,Mouse1 L}"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_START), "{Joypad1 Start,Mouse1 R}"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_L), "Joypad1 L"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_R), "Joypad1 R"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_LEFT), "Joypad1 Left"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_RIGHT), "Joypad1 Right"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_UP), "Joypad1 Up"); + MAP_BUTTON(MAKE_BUTTON(PAD_1, BTN_DOWN), "Joypad1 Down"); + S9xMapPointer((BTN_POINTER), S9xGetCommandT("Pointer Mouse1+Superscope+Justifier1"), false); + S9xMapPointer((BTN_POINTER2), S9xGetCommandT("Pointer Mouse2"), false); + + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_A), "Joypad2 A"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_B), "Joypad2 B"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_X), "Joypad2 X"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_Y), "Joypad2 Y"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_SELECT), "{Joypad2 Select,Mouse2 L,Superscope Fire,Justifier1 Trigger}"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_START), "{Joypad2 Start,Mouse2 R,Superscope Cursor,Justifier1 Start}"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_L), "Joypad2 L"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_R), "Joypad2 R"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_LEFT), "Joypad2 Left"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_RIGHT), "Joypad2 Right"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_UP), "{Joypad2 Up,Superscope ToggleTurbo}"); + MAP_BUTTON(MAKE_BUTTON(PAD_2, BTN_DOWN), "{Joypad2 Down,Superscope Pause}"); + + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_A), "Joypad3 A"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_B), "Joypad3 B"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_X), "Joypad3 X"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_Y), "Joypad3 Y"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_SELECT), "Joypad3 Select"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_START), "Joypad3 Start"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_L), "Joypad3 L"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_R), "Joypad3 R"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_LEFT), "Joypad3 Left"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_RIGHT), "Joypad3 Right"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_UP), "Joypad3 Up"); + MAP_BUTTON(MAKE_BUTTON(PAD_3, BTN_DOWN), "Joypad3 Down"); + + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_A), "Joypad4 A"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_B), "Joypad4 B"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_X), "Joypad4 X"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_Y), "Joypad4 Y"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_SELECT), "Joypad4 Select"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_START), "Joypad4 Start"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_L), "Joypad4 L"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_R), "Joypad4 R"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_LEFT), "Joypad4 Left"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_RIGHT), "Joypad4 Right"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_UP), "Joypad4 Up"); + MAP_BUTTON(MAKE_BUTTON(PAD_4, BTN_DOWN), "Joypad4 Down"); + + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_A), "Joypad5 A"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_B), "Joypad5 B"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_X), "Joypad5 X"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_Y), "Joypad5 Y"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_SELECT), "Joypad5 Select"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_START), "Joypad5 Start"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_L), "Joypad5 L"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_R), "Joypad5 R"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_LEFT), "Joypad5 Left"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_RIGHT), "Joypad5 Right"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_UP), "Joypad5 Up"); + MAP_BUTTON(MAKE_BUTTON(PAD_5, BTN_DOWN), "Joypad5 Down"); + +} + +// libretro uses relative values for analogue devices. +// S9x seems to use absolute values, but do convert these into relative values in the core. (Why?!) +// Hack around it. :) +static int16_t snes_mouse_state[2][2] = {{0}, {0}}; +static int16_t snes_scope_state[2] = {0}; +static int16_t snes_justifier_state[2][2] = {{0}, {0}}; +static void report_buttons() +{ + int _x, _y; + for (int port = 0; port <= 1; port++) + { + switch (snes_devices[port]) + { + case RETRO_DEVICE_JOYPAD: + for (int i = BTN_FIRST; i <= BTN_LAST; i++) + S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_JOYPAD, 0, i)); + break; + + case RETRO_DEVICE_JOYPAD_MULTITAP: + for (int j = 0; j < 4; j++) + for (int i = BTN_FIRST; i <= BTN_LAST; i++) + S9xReportButton(MAKE_BUTTON(j + 2, i), s9x_input_state_cb(port, RETRO_DEVICE_JOYPAD_MULTITAP, j, i)); + break; + + case RETRO_DEVICE_MOUSE: + _x = s9x_input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); + _y = s9x_input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); + snes_mouse_state[port][0] += _x; + snes_mouse_state[port][1] += _y; + S9xReportPointer(BTN_POINTER + port, snes_mouse_state[port][0], snes_mouse_state[port][1]); + for (int i = MOUSE_LEFT; i <= MOUSE_LAST; i++) + S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_MOUSE, 0, i)); + break; + + case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: + snes_scope_state[0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_X); + snes_scope_state[1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); + S9xReportPointer(BTN_POINTER, snes_scope_state[0], snes_scope_state[1]); + for (int i = SCOPE_TRIGGER; i <= SCOPE_LAST; i++) + S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE, 0, i)); + break; + + case RETRO_DEVICE_LIGHTGUN_JUSTIFIER: + case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS: + snes_justifier_state[0][0] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_X); + snes_justifier_state[0][1] += s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, RETRO_DEVICE_ID_LIGHTGUN_Y); + S9xReportPointer(BTN_POINTER, snes_justifier_state[0][0], snes_justifier_state[0][1]); + for (int i = JUSTIFIER_TRIGGER; i <= JUSTIFIER_LAST; i++) + S9xReportButton(MAKE_BUTTON(port + 1, i), s9x_input_state_cb(port, RETRO_DEVICE_LIGHTGUN_JUSTIFIER, 0, i)); + break; + + default: + fprintf(stderr, "[libretro]: Unknown device...\n"); + + } + } +} + +void retro_run() +{ + s9x_poller_cb(); + report_buttons(); + S9xMainLoop(); +} + +void retro_deinit() +{ + S9xDeinitAPU(); + Memory.Deinit(); + S9xGraphicsDeinit(); + S9xUnmapAllControls(); +} + + +unsigned retro_get_region() +{ + return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; +} + +void* retro_get_memory_data(unsigned type) +{ + void* data; + + switch(type) { + case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM: + case RETRO_MEMORY_SAVE_RAM: + data = Memory.SRAM; + break; + case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM: + data = Multi.sramB; + break; + case RETRO_MEMORY_RTC: + data = RTCData.reg; + break; + case RETRO_MEMORY_SYSTEM_RAM: + data = Memory.RAM; + break; + case RETRO_MEMORY_VIDEO_RAM: + data = Memory.VRAM; + break; + default: + data = NULL; + break; + } + + return data; +} + +void retro_unload_cartridge() +{ + +} + +size_t retro_get_memory_size(unsigned type) +{ + size_t size; + + switch(type) { + case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM: + case RETRO_MEMORY_SAVE_RAM: + size = (unsigned) (Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0); + if (size > 0x20000) + size = 0x20000; + break; + case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM: + size = (unsigned) (Multi.cartType && Multi.sramSizeB ? (1 << (Multi.sramSizeB + 3)) * 128 : 0); + break; + case RETRO_MEMORY_RTC: + size = (Settings.SRTC || Settings.SPC7110RTC)?20:0; + break; + case RETRO_MEMORY_SYSTEM_RAM: + size = 128 * 1024; + break; + case RETRO_MEMORY_VIDEO_RAM: + size = 64 * 1024; + break; + default: + size = 0; + break; + } + + return size; +} + +size_t retro_serialize_size() +{ + return rom_loaded ? S9xFreezeSize() : 0; +} + +bool retro_serialize(void *data, size_t size) +{ + if (S9xFreezeGameMem((uint8_t*)data,size) == FALSE) + return false; + + return true; +} + +bool retro_unserialize(const void* data, size_t size) +{ + if (S9xUnfreezeGameMem((const uint8_t*)data,size) != SUCCESS) + return false; + return true; +} + +bool8 S9xDeinitUpdate(int width, int height) +{ + if (!use_overscan) + { + if (height >= SNES_HEIGHT << 1) + { + height = SNES_HEIGHT << 1; + } + else + { + height = SNES_HEIGHT; + } + } + else + { + if (height > SNES_HEIGHT_EXTENDED) + { + if (height < SNES_HEIGHT_EXTENDED << 1) + memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * ((SNES_HEIGHT_EXTENDED << 1) - height)); + height = SNES_HEIGHT_EXTENDED << 1; + } + else + { + if (height < SNES_HEIGHT_EXTENDED) + memset(GFX.Screen + (GFX.Pitch >> 1) * height,0,GFX.Pitch * (SNES_HEIGHT_EXTENDED - height)); + height = SNES_HEIGHT_EXTENDED; + } + } + + s9x_video_cb(GFX.Screen, width, height, GFX.Pitch); + return TRUE; +} + +bool8 S9xContinueUpdate(int width, int height) +{ + return S9xDeinitUpdate(width, height); +} + +// Dummy functions that should probably be implemented correctly later. +void S9xParsePortConfig(ConfigFile&, int) {} +void S9xSyncSpeed() {} +const char* S9xStringInput(const char* in) { return in; } +const char* S9xGetFilename(const char* in, s9x_getdirtype) { return in; } +const char* S9xGetDirectory(s9x_getdirtype) { return ""; } +void S9xInitInputDevices() {} +const char* S9xChooseFilename(unsigned char) { return ""; } +void S9xHandlePortCommand(s9xcommand_t, short, short) {} +bool S9xPollButton(unsigned int, bool*) { return false; } +void S9xToggleSoundChannel(int) {} +const char* S9xGetFilenameInc(const char* in, s9x_getdirtype) { return ""; } +const char* S9xBasename(const char* in) { return in; } +bool8 S9xInitUpdate() { return TRUE; } +void S9xExtraUsage() {} +bool8 S9xOpenSoundDevice() { return TRUE; } +void S9xMessage(int, int, const char*) {} +bool S9xPollAxis(unsigned int, short*) { return FALSE; } +void S9xSetPalette() {} +void S9xParseArg(char**, int&, int) {} +void S9xExit() {} +bool S9xPollPointer(unsigned int, short*, short*) { return false; } +const char *S9xChooseMovieFilename(unsigned char) { return NULL; } + +bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file) +{ + if(read_only) + { + if((*file = OPEN_STREAM(filepath, "rb")) != 0) + { + return (TRUE); + } + } + else + { + if((*file = OPEN_STREAM(filepath, "wb")) != 0) + { + return (TRUE); + } + } + return (FALSE); +} + +void S9xCloseSnapshotFile(STREAM file) +{ + CLOSE_STREAM(file); +} + +void S9xAutoSaveSRAM() +{ + return; +} + +#ifndef __WIN32__ +// S9x weirdness. +void _splitpath (const char *path, char *drive, char *dir, char *fname, char *ext) +{ + *drive = 0; + + const char *slash = strrchr(path, SLASH_CHAR), + *dot = strrchr(path, '.'); + + if (dot && slash && dot < slash) + dot = NULL; + + if (!slash) + { + *dir = 0; + + strcpy(fname, path); + + if (dot) + { + fname[dot - path] = 0; + strcpy(ext, dot + 1); + } + else + *ext = 0; + } + else + { + strcpy(dir, path); + dir[slash - path] = 0; + + strcpy(fname, slash + 1); + + if (dot) + { + fname[dot - slash - 1] = 0; + strcpy(ext, dot + 1); + } + else + *ext = 0; + } +} + +void _makepath (char *path, const char *, const char *dir, const char *fname, const char *ext) +{ + if (dir && *dir) + { + strcpy(path, dir); + strcat(path, SLASH_STR); + } + else + *path = 0; + + strcat(path, fname); + + if (ext && *ext) + { + strcat(path, "."); + strcat(path, ext); + } +} +#endif // __WIN32__ diff --git a/libretro/libretro.def b/libretro/libretro.def new file mode 100644 index 00000000..aa6381b4 --- /dev/null +++ b/libretro/libretro.def @@ -0,0 +1,41 @@ +LIBRARY libretro + +EXPORTS + +retro_api_version + +retro_get_system_info +retro_get_system_av_info + +retro_set_video_refresh +retro_set_audio_sample +retro_set_audio_sample_batch +retro_set_input_poll +retro_set_input_state + +retro_set_environment + +retro_set_controller_port_device + +retro_init +retro_deinit + +retro_reset +retro_run + +retro_serialize_size +retro_serialize +retro_unserialize + +retro_cheat_reset +retro_cheat_set + +retro_load_game +retro_unload_game +retro_load_game_special + +retro_unload_cartridge + +retro_get_region +retro_get_memory_data +retro_get_memory_size \ No newline at end of file diff --git a/libretro/libretro.h b/libretro/libretro.h new file mode 100644 index 00000000..fcd3bbc6 --- /dev/null +++ b/libretro/libretro.h @@ -0,0 +1,277 @@ +#ifndef LIBRETRO_H__ +#define LIBRETRO_H__ + +#include "snes9x.h" +#include + +#ifdef __cplusplus +extern "C" { +#else +#if defined(_MSC_VER) && !defined(__cplusplus) +#define bool unsigned char +#define true 1 +#define false 0 +#else +#include +#endif +#endif + +#define RETRO_API_VERSION 1 + +#define RETRO_DEVICE_MASK 0xff +#define RETRO_DEVICE_NONE 0 +#define RETRO_DEVICE_JOYPAD 1 +#define RETRO_DEVICE_MOUSE 2 +#define RETRO_DEVICE_KEYBOARD 3 +#define RETRO_DEVICE_LIGHTGUN 4 + +#define RETRO_DEVICE_JOYPAD_MULTITAP ((1 << 8) | RETRO_DEVICE_JOYPAD) +#define RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE ((1 << 8) | RETRO_DEVICE_LIGHTGUN) +#define RETRO_DEVICE_LIGHTGUN_JUSTIFIER ((2 << 8) | RETRO_DEVICE_LIGHTGUN) +#define RETRO_DEVICE_LIGHTGUN_JUSTIFIERS ((3 << 8) | RETRO_DEVICE_LIGHTGUN) + +#define RETRO_DEVICE_ID_JOYPAD_B 0 +#define RETRO_DEVICE_ID_JOYPAD_Y 1 +#define RETRO_DEVICE_ID_JOYPAD_SELECT 2 +#define RETRO_DEVICE_ID_JOYPAD_START 3 +#define RETRO_DEVICE_ID_JOYPAD_UP 4 +#define RETRO_DEVICE_ID_JOYPAD_DOWN 5 +#define RETRO_DEVICE_ID_JOYPAD_LEFT 6 +#define RETRO_DEVICE_ID_JOYPAD_RIGHT 7 +#define RETRO_DEVICE_ID_JOYPAD_A 8 +#define RETRO_DEVICE_ID_JOYPAD_X 9 +#define RETRO_DEVICE_ID_JOYPAD_L 10 +#define RETRO_DEVICE_ID_JOYPAD_R 11 + +#define RETRO_DEVICE_ID_MOUSE_X 0 +#define RETRO_DEVICE_ID_MOUSE_Y 1 +#define RETRO_DEVICE_ID_MOUSE_LEFT 2 +#define RETRO_DEVICE_ID_MOUSE_RIGHT 3 + +#define RETRO_DEVICE_ID_LIGHTGUN_X 0 +#define RETRO_DEVICE_ID_LIGHTGUN_Y 1 +#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2 +#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3 +#define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4 +#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5 +#define RETRO_DEVICE_ID_LIGHTGUN_START 6 + +#define RETRO_REGION_NTSC 0 +#define RETRO_REGION_PAL 1 + +#define RETRO_MEMORY_MASK 0xff +#define RETRO_MEMORY_SAVE_RAM 0 +#define RETRO_MEMORY_RTC 1 +#define RETRO_MEMORY_SYSTEM_RAM 2 +#define RETRO_MEMORY_VIDEO_RAM 3 + +#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM) +#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC) + +#define RETRO_GAME_TYPE_BSX 0x101 +#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102 +#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103 +#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104 + + +// Environment commands. +#define RETRO_ENVIRONMENT_SET_ROTATION 1 // const unsigned * -- + // Sets screen rotation of graphics. + // Is only implemented if rotation can be accelerated by hardware. + // Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, 270 degrees + // counter-clockwise respectively. + // +#define RETRO_ENVIRONMENT_GET_OVERSCAN 2 // bool * -- + // Boolean value whether or not the implementation should use overscan, or crop away overscan. + // +#define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 // bool * -- + // Boolean value whether or not RetroArch supports frame duping, + // passing NULL to video frame callback. + // +#define RETRO_ENVIRONMENT_GET_VARIABLE 4 // struct retro_variable * -- + // Interface to aquire user-defined information from environment + // that cannot feasibly be supported in a multi-system way. + // Mostly used for obscure, + // specific features that the user can tap into when neseccary. + // +#define RETRO_ENVIRONMENT_SET_VARIABLES 5 // const struct retro_variable * -- + // Allows an implementation to signal the environment + // which variables it might want to check for later using GET_VARIABLE. + // 'data' points to an array of retro_variable structs terminated by a { NULL, NULL } element. + // retro_variable::value should contain a human readable description of the key. + // +#define RETRO_ENVIRONMENT_SET_MESSAGE 6 // const struct retro_message * -- + // Sets a message to be displayed in implementation-specific manner for a certain amount of 'frames'. + // Should not be used for trivial messages, which should simply be logged to stderr. + +struct retro_message +{ + const char *msg; // Message to be displayed. + unsigned frames; // Duration in frames of message. +}; + +struct retro_system_info +{ + const char *library_name; // Descriptive name of library. Should not contain any version numbers, etc. + const char *library_version; // Descriptive version of core. + + const char *valid_extensions; // A string listing probably rom extensions the core will be able to load, separated with pipe. + // I.e. "bin|rom|iso". + // Typically used for a GUI to filter out extensions. + + bool need_fullpath; // If true, retro_load_game() is guaranteed to provide a valid pathname in retro_game_info::path. + // ::data and ::size are both invalid. + // If false, ::data and ::size are guaranteed to be valid, but ::path might not be valid. + // This is typically set to true for libretro implementations that must load from file. + // Implementations should strive for setting this to false, as it allows the frontend to perform patching, etc. + + bool block_extract; // If true, the frontend is not allowed to extract any archives before loading the real ROM. + // Necessary for certain libretro implementations that load games from zipped archives. +}; + +struct retro_game_geometry +{ + unsigned base_width; // Nominal video width of game. + unsigned base_height; // Nominal video height of game. + unsigned max_width; // Maximum possible width of game. + unsigned max_height; // Maximum possible height of game. + + float aspect_ratio; // Nominal aspect ratio of game. If aspect_ratio is <= 0.0, + // an aspect ratio of base_width / base_height is assumed. + // A frontend could override this setting if desired. +}; + +struct retro_system_timing +{ + double fps; // FPS of video content. + double sample_rate; // Sampling rate of audio. +}; + +struct retro_system_av_info +{ + struct retro_game_geometry geometry; + struct retro_system_timing timing; +}; + +struct retro_variable +{ + const char *key; // Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. + // If NULL, obtains the complete environment string if more complex parsing is necessary. + // The environment string is formatted as key-value pairs delimited by semicolons as so: + // "key1=value1;key2=value2;..." + const char *value; // Value to be obtained. If key does not exist, it is set to NULL. +}; + +struct retro_game_info +{ + const char *path; // Path to game, UTF-8 encoded. Usually used as a reference. + // May be NULL if rom was loaded from stdin or similar. + // retro_system_info::need_fullpath guaranteed that this path is valid. + const void *data; // Memory buffer of loaded game. Will be NULL if need_fullpath was set. + size_t size; // Size of memory buffer. + const char *meta; // String of implementation specific meta-data. +}; + +// Callbacks +// +// Environment callback. Gives implementations a way of performing uncommon tasks. Extensible. +typedef bool (*retro_environment_t)(unsigned cmd, void *data); + +// Render a frame. Pixel format is 15-bit XRGB1555 native endian. +// Width and height specify dimensions of buffer. +// Pitch specifices length in bytes between two lines in buffer. +typedef void (*retro_video_refresh_t)(const void *data, unsigned width, unsigned height, size_t pitch); + +// Renders a single audio frame. Should only be used if implementation generates a single sample at a time. +// Format is signed 16-bit native endian. +typedef void (*retro_audio_sample_t)(int16_t left, int16_t right); +// Renders multiple audio frames in one go. One frame is defined as a sample of left and right channels, interleaved. +// I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames. +// Only one of the audio callbacks must ever be used. +typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data, size_t frames); + +// Polls input. +typedef void (*retro_input_poll_t)(void); +// Queries for input for player 'port'. device will be masked with RETRO_DEVICE_MASK. +// Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that have been set with retro_set_controller_port_device() +// will still use the higher level RETRO_DEVICE_JOYPAD to request input. +typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, unsigned index, unsigned id); + +// Sets callbacks. retro_set_environment() is guaranteed to be called before retro_init(). +// The rest of the set_* functions are guaranteed to have been called before the first call to retro_run() is made. +void retro_set_environment(retro_environment_t); +void retro_set_video_refresh(retro_video_refresh_t); +void retro_set_audio_sample(retro_audio_sample_t); +void retro_set_audio_sample_batch(retro_audio_sample_batch_t); +void retro_set_input_poll(retro_input_poll_t); +void retro_set_input_state(retro_input_state_t); + +// Library global initialization/deinitialization. +void retro_init(void); +void retro_deinit(void); + +// Must return RETRO_API_VERSION. Used to validate ABI compatibility when the API is revised. +unsigned retro_api_version(void); + +// Gets statically known system info. Pointers provided in *info must be statically allocated. +// Can be called at any time, even before retro_init(). +void retro_get_system_info(struct retro_system_info *info); + +// Gets information about system audio/video timings and geometry. +// Can be called only after retro_load_game() has successfully completed. +void retro_get_system_av_info(struct retro_system_av_info *info); + +// Sets device to be used for player 'port'. +void retro_set_controller_port_device(unsigned port, unsigned device); + +// Resets the current game. +void retro_reset(void); + +// Runs the game for one video frame. +// During retro_run(), input_poll callback must be called at least once. +// +// If a frame is not rendered for reasons where a game "dropped" a frame, +// this still counts as a frame, and retro_run() should explicitly dupe a frame if GET_CAN_DUPE returns true. +// In this case, the video callback can take a NULL argument for data. +void retro_run(void); + +// Returns the amount of data the implementation requires to serialize internal state (save states). +// Beetween calls to retro_load_game() and retro_unload_game(), the returned size is never allowed to be larger than a previous returned value, to +// ensure that the frontend can allocate a save state buffer once. +size_t retro_serialize_size(void); + +// Serializes internal state. If failed, or size is lower than retro_serialize_size(), it should return false, true otherwise. +bool retro_serialize(void *data, size_t size); +bool retro_unserialize(const void *data, size_t size); + +void retro_cheat_reset(void); +void retro_cheat_set(unsigned index, bool enabled, const char *code); + +// Loads a game. +bool retro_load_game(const struct retro_game_info *game); + +// Loads a "special" kind of game. Should not be used except in extreme cases. +bool retro_load_game_special( + unsigned game_type, + const struct retro_game_info *info, size_t num_info +); + +// Unloads a currently loaded game. +void retro_unload_game(void); + +// Gets region of game. +unsigned retro_get_region(void); + +// Gets region of memory. +void *retro_get_memory_data(unsigned id); +size_t retro_get_memory_size(unsigned id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libretro/link.T b/libretro/link.T new file mode 100644 index 00000000..9e82b5dd --- /dev/null +++ b/libretro/link.T @@ -0,0 +1,4 @@ +{ + global: retro_*; + local: *; +}; diff --git a/loadzip.cpp b/loadzip.cpp index 6ce8e7c8..1a92828a 100644 --- a/loadzip.cpp +++ b/loadzip.cpp @@ -185,10 +185,9 @@ #include "memmap.h" -bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 *buffer) +bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer) { *TotalFileSize = 0; - *headers = 0; unzFile file = unzOpen(zipname); if (file == NULL) @@ -196,7 +195,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 // find largest file in zip file (under MAX_ROM_SIZE) or a file with extension .1 char filename[132]; - int filesize = 0; + uint32 filesize = 0; int port = unzGoToFirstFile(file); unz_file_info info; @@ -212,7 +211,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 continue; } - if ((int) info.uncompressed_size > filesize) + if (info.uncompressed_size > filesize) { strcpy(filename, name); filesize = info.uncompressed_size; @@ -259,7 +258,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 { assert(info.uncompressed_size <= CMemory::MAX_ROM_SIZE + 512); - int FileSize = info.uncompressed_size; + uint32 FileSize = info.uncompressed_size; int l = unzReadCurrentFile(file, ptr, FileSize); if (unzCloseCurrentFile(file) == UNZ_CRCERROR) @@ -274,7 +273,7 @@ bool8 LoadZip (const char *zipname, int32 *TotalFileSize, int32 *headers, uint8 return (FALSE); } - FileSize = (int) Memory.HeaderRemove((uint32) FileSize, *headers, ptr); + FileSize = Memory.HeaderRemove(FileSize, ptr); ptr += FileSize; *TotalFileSize += FileSize; diff --git a/macosx/mac-controls.cpp b/macosx/mac-controls.cpp index 26e0d5b4..46a5d4ab 100644 --- a/macosx/mac-controls.cpp +++ b/macosx/mac-controls.cpp @@ -424,7 +424,7 @@ s9xcommand_t S9xGetPortCommandT (const char *name) { s9xcommand_t cmd; - ZeroMemory(&cmd, sizeof(cmd)); + memset(&cmd, 0, sizeof(cmd)); cmd.type = S9xBadMapping; return (cmd); diff --git a/macosx/snes9x.xcodeproj/project.pbxproj b/macosx/snes9x.xcodeproj/project.pbxproj index 176f07e6..37ab5032 100755 --- a/macosx/snes9x.xcodeproj/project.pbxproj +++ b/macosx/snes9x.xcodeproj/project.pbxproj @@ -36,7 +36,7 @@ CF047D54109D0E0600FD0754 /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; }; CF047D55109D0E0600FD0754 /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; }; CF047D56109D0E0600FD0754 /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; }; - CF047D57109D0E0600FD0754 /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; }; + CF047D57109D0E0600FD0754 /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; }; CF047D58109D0E0600FD0754 /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; }; CF047D59109D0E0600FD0754 /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; }; CF047D5A109D0E0600FD0754 /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; }; @@ -145,7 +145,7 @@ CF047DC9109D0E0600FD0754 /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; }; CF047DCA109D0E0600FD0754 /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; }; CF047DCB109D0E0600FD0754 /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; }; - CF047DCC109D0E0600FD0754 /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; }; + CF047DCC109D0E0600FD0754 /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; }; CF047DCD109D0E0600FD0754 /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; }; CF047DCE109D0E0600FD0754 /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; }; CF047DCF109D0E0600FD0754 /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; }; @@ -237,7 +237,7 @@ CF0566A90CF98E7E00C7877C /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; }; CF0566AA0CF98E7E00C7877C /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; }; CF0566AB0CF98E7E00C7877C /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; }; - CF0566AC0CF98E7E00C7877C /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; }; + CF0566AC0CF98E7E00C7877C /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; }; CF0566AD0CF98E7E00C7877C /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; }; CF0566AE0CF98E7E00C7877C /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; }; CF0566AF0CF98E7E00C7877C /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; }; @@ -333,7 +333,7 @@ CF0567180CF98E7E00C7877C /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; }; CF0567190CF98E7E00C7877C /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; }; CF05671A0CF98E7E00C7877C /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; }; - CF05671B0CF98E7E00C7877C /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; }; + CF05671B0CF98E7E00C7877C /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; }; CF05671C0CF98E7E00C7877C /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; }; CF05671D0CF98E7E00C7877C /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; }; CF05671E0CF98E7E00C7877C /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; }; @@ -424,7 +424,7 @@ CF2F462E1095EE72007D33FA /* pixform.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C60526CCB900A80003 /* pixform.h */; }; CF2F462F1095EE72007D33FA /* port.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C70526CCB900A80003 /* port.h */; }; CF2F46301095EE72007D33FA /* ppu.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061C90526CCB900A80003 /* ppu.h */; }; - CF2F46311095EE72007D33FA /* reader.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* reader.h */; }; + CF2F46311095EE72007D33FA /* stream.h in Headers */ = {isa = PBXBuildFile; fileRef = EA809E9708F8D70D0072CDFB /* stream.h */; }; CF2F46321095EE72007D33FA /* sa1.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CC0526CCB900A80003 /* sa1.h */; }; CF2F46331095EE72007D33FA /* sar.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061CE0526CCB900A80003 /* sar.h */; }; CF2F46341095EE72007D33FA /* screenshot.h in Headers */ = {isa = PBXBuildFile; fileRef = EAE061D00526CCB900A80003 /* screenshot.h */; }; @@ -533,7 +533,7 @@ CF2F46A31095EE72007D33FA /* movie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA813E9A066F50A5004F99B5 /* movie.cpp */; }; CF2F46A41095EE72007D33FA /* obc1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C30526CCB900A80003 /* obc1.cpp */; }; CF2F46A51095EE72007D33FA /* ppu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061C80526CCB900A80003 /* ppu.cpp */; }; - CF2F46A61095EE72007D33FA /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* reader.cpp */; }; + CF2F46A61095EE72007D33FA /* stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA809E9F08F8D7530072CDFB /* stream.cpp */; }; CF2F46A71095EE72007D33FA /* sa1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CB0526CCB900A80003 /* sa1.cpp */; }; CF2F46A81095EE72007D33FA /* sa1cpu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061CD0526CCB900A80003 /* sa1cpu.cpp */; }; CF2F46A91095EE72007D33FA /* sdd1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EAE061D10526CCB900A80003 /* sdd1.cpp */; }; @@ -817,11 +817,11 @@ EA6E6C0E08F9734500CB3555 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; EA809E9308F8D6C40072CDFB /* controls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controls.h; sourceTree = ""; }; EA809E9508F8D6E00072CDFB /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = language.h; sourceTree = ""; }; - EA809E9708F8D70D0072CDFB /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader.h; sourceTree = ""; }; + EA809E9708F8D70D0072CDFB /* stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream.h; sourceTree = ""; }; EA809E9908F8D7240072CDFB /* controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = controls.cpp; sourceTree = ""; }; EA809E9B08F8D72C0072CDFB /* crosshairs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crosshairs.cpp; sourceTree = ""; }; EA809E9D08F8D73A0072CDFB /* crosshairs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crosshairs.h; sourceTree = ""; }; - EA809E9F08F8D7530072CDFB /* reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reader.cpp; sourceTree = ""; }; + EA809E9F08F8D7530072CDFB /* stream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stream.cpp; sourceTree = ""; }; EA809F9D08F8F2190072CDFB /* mac-controls.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "mac-controls.h"; sourceTree = ""; }; EA809FA108F8F2420072CDFB /* mac-controls.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = "mac-controls.cpp"; sourceTree = ""; }; EA813E86066F5076004F99B5 /* movie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = movie.h; sourceTree = ""; }; @@ -1179,7 +1179,7 @@ EAE061C60526CCB900A80003 /* pixform.h */, EAE061C70526CCB900A80003 /* port.h */, EAE061C90526CCB900A80003 /* ppu.h */, - EA809E9708F8D70D0072CDFB /* reader.h */, + EA809E9708F8D70D0072CDFB /* stream.h */, EAE061CC0526CCB900A80003 /* sa1.h */, EAE061CE0526CCB900A80003 /* sar.h */, EAE061D00526CCB900A80003 /* screenshot.h */, @@ -1222,7 +1222,7 @@ EA813E9A066F50A5004F99B5 /* movie.cpp */, EAE061C30526CCB900A80003 /* obc1.cpp */, EAE061C80526CCB900A80003 /* ppu.cpp */, - EA809E9F08F8D7530072CDFB /* reader.cpp */, + EA809E9F08F8D7530072CDFB /* stream.cpp */, EAE061CB0526CCB900A80003 /* sa1.cpp */, EAE061CD0526CCB900A80003 /* sa1cpu.cpp */, EAE061D10526CCB900A80003 /* sdd1.cpp */, @@ -1384,7 +1384,7 @@ CF047D54109D0E0600FD0754 /* pixform.h in Headers */, CF047D55109D0E0600FD0754 /* port.h in Headers */, CF047D56109D0E0600FD0754 /* ppu.h in Headers */, - CF047D57109D0E0600FD0754 /* reader.h in Headers */, + CF047D57109D0E0600FD0754 /* stream.h in Headers */, CF047D58109D0E0600FD0754 /* sa1.h in Headers */, CF047D59109D0E0600FD0754 /* sar.h in Headers */, CF047D5A109D0E0600FD0754 /* screenshot.h in Headers */, @@ -1503,7 +1503,7 @@ CF0566A90CF98E7E00C7877C /* pixform.h in Headers */, CF0566AA0CF98E7E00C7877C /* port.h in Headers */, CF0566AB0CF98E7E00C7877C /* ppu.h in Headers */, - CF0566AC0CF98E7E00C7877C /* reader.h in Headers */, + CF0566AC0CF98E7E00C7877C /* stream.h in Headers */, CF0566AD0CF98E7E00C7877C /* sa1.h in Headers */, CF0566AE0CF98E7E00C7877C /* sar.h in Headers */, CF0566AF0CF98E7E00C7877C /* screenshot.h in Headers */, @@ -1622,7 +1622,7 @@ CF2F462E1095EE72007D33FA /* pixform.h in Headers */, CF2F462F1095EE72007D33FA /* port.h in Headers */, CF2F46301095EE72007D33FA /* ppu.h in Headers */, - CF2F46311095EE72007D33FA /* reader.h in Headers */, + CF2F46311095EE72007D33FA /* stream.h in Headers */, CF2F46321095EE72007D33FA /* sa1.h in Headers */, CF2F46331095EE72007D33FA /* sar.h in Headers */, CF2F46341095EE72007D33FA /* screenshot.h in Headers */, @@ -1938,7 +1938,7 @@ CF047DC9109D0E0600FD0754 /* movie.cpp in Sources */, CF047DCA109D0E0600FD0754 /* obc1.cpp in Sources */, CF047DCB109D0E0600FD0754 /* ppu.cpp in Sources */, - CF047DCC109D0E0600FD0754 /* reader.cpp in Sources */, + CF047DCC109D0E0600FD0754 /* stream.cpp in Sources */, CF047DCD109D0E0600FD0754 /* sa1.cpp in Sources */, CF047DCE109D0E0600FD0754 /* sa1cpu.cpp in Sources */, CF047DCF109D0E0600FD0754 /* sdd1.cpp in Sources */, @@ -2033,7 +2033,7 @@ CF0567180CF98E7E00C7877C /* movie.cpp in Sources */, CF0567190CF98E7E00C7877C /* obc1.cpp in Sources */, CF05671A0CF98E7E00C7877C /* ppu.cpp in Sources */, - CF05671B0CF98E7E00C7877C /* reader.cpp in Sources */, + CF05671B0CF98E7E00C7877C /* stream.cpp in Sources */, CF05671C0CF98E7E00C7877C /* sa1.cpp in Sources */, CF05671D0CF98E7E00C7877C /* sa1cpu.cpp in Sources */, CF05671E0CF98E7E00C7877C /* sdd1.cpp in Sources */, @@ -2128,7 +2128,7 @@ CF2F46A31095EE72007D33FA /* movie.cpp in Sources */, CF2F46A41095EE72007D33FA /* obc1.cpp in Sources */, CF2F46A51095EE72007D33FA /* ppu.cpp in Sources */, - CF2F46A61095EE72007D33FA /* reader.cpp in Sources */, + CF2F46A61095EE72007D33FA /* stream.cpp in Sources */, CF2F46A71095EE72007D33FA /* sa1.cpp in Sources */, CF2F46A81095EE72007D33FA /* sa1cpu.cpp in Sources */, CF2F46A91095EE72007D33FA /* sdd1.cpp in Sources */, diff --git a/memmap.cpp b/memmap.cpp index 81edf082..72196bb1 100644 --- a/memmap.cpp +++ b/memmap.cpp @@ -197,7 +197,6 @@ #include "controls.h" #include "cheats.h" #include "movie.h" -#include "reader.h" #include "display.h" #ifndef SET_UI_COLOR @@ -937,15 +936,17 @@ static void S9xDeinterleaveType1 (int, uint8 *); static void S9xDeinterleaveType2 (int, uint8 *); static void S9xDeinterleaveGD24 (int, uint8 *); static bool8 allASCII (uint8 *, int); -static bool8 is_SufamiTurbo_BIOS (uint8 *, uint32); -static bool8 is_SufamiTurbo_Cart (uint8 *, uint32); -static bool8 is_SameGame_BIOS (uint8 *, uint32); -static bool8 is_SameGame_Add_On (uint8 *, uint32); +static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32); +static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32); +static bool8 is_SameGame_BIOS (const uint8 *, uint32); +static bool8 is_SameGame_Add_On (const uint8 *, uint32); +static bool8 is_GNEXT_BIOS (const uint8 *, uint32); +static bool8 is_GNEXT_Add_On (const uint8 *, uint32); static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff); static uint32 ReadUPSPointer (const uint8 *, unsigned &, unsigned); -static bool8 ReadUPSPatch (Reader *, long, int32 &); -static long ReadInt (Reader *, unsigned); -static bool8 ReadIPSPatch (Reader *, long, int32 &); +static bool8 ReadUPSPatch (Stream *, long, int32 &); +static long ReadInt (Stream *, unsigned); +static bool8 ReadIPSPatch (Stream *, long, int32 &); #ifdef UNZIP_SUPPORT static int unzFindExtension (unzFile &, const char *, bool restart = TRUE, bool print = TRUE); #endif @@ -1099,26 +1100,26 @@ bool8 CMemory::Init (void) return (FALSE); } - ZeroMemory(RAM, 0x20000); - ZeroMemory(SRAM, 0x20000); - ZeroMemory(VRAM, 0x10000); - ZeroMemory(ROM, MAX_ROM_SIZE + 0x200 + 0x8000); + memset(RAM, 0, 0x20000); + memset(SRAM, 0, 0x20000); + memset(VRAM, 0, 0x10000); + memset(ROM, 0, MAX_ROM_SIZE + 0x200 + 0x8000); - ZeroMemory(IPPU.TileCache[TILE_2BIT], MAX_2BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_4BIT], MAX_4BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_8BIT], MAX_8BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_2BIT_EVEN], MAX_2BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_2BIT_ODD], MAX_2BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_4BIT_EVEN], MAX_4BIT_TILES * 64); - ZeroMemory(IPPU.TileCache[TILE_4BIT_ODD], MAX_4BIT_TILES * 64); + memset(IPPU.TileCache[TILE_2BIT], 0, MAX_2BIT_TILES * 64); + memset(IPPU.TileCache[TILE_4BIT], 0, MAX_4BIT_TILES * 64); + memset(IPPU.TileCache[TILE_8BIT], 0, MAX_8BIT_TILES * 64); + memset(IPPU.TileCache[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES * 64); + memset(IPPU.TileCache[TILE_2BIT_ODD], 0, MAX_2BIT_TILES * 64); + memset(IPPU.TileCache[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES * 64); + memset(IPPU.TileCache[TILE_4BIT_ODD], 0, MAX_4BIT_TILES * 64); - ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_2BIT_EVEN], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES); // FillRAM uses first 32K of ROM image area, otherwise space just // wasted. Might be read by the SuperFX code. @@ -1205,7 +1206,7 @@ static bool8 allASCII (uint8 *b, int size) return (TRUE); } -static bool8 is_SufamiTurbo_BIOS (uint8 *data, uint32 size) +static bool8 is_SufamiTurbo_BIOS (const uint8 *data, uint32 size) { if (size == 0x40000 && strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) == 0) @@ -1214,7 +1215,7 @@ static bool8 is_SufamiTurbo_BIOS (uint8 *data, uint32 size) return (FALSE); } -static bool8 is_SufamiTurbo_Cart (uint8 *data, uint32 size) +static bool8 is_SufamiTurbo_Cart (const uint8 *data, uint32 size) { if (size >= 0x80000 && size <= 0x100000 && strncmp((char *) data, "BANDAI SFC-ADX", 14) == 0 && strncmp((char * ) (data + 0x10), "SFC-ADX BACKUP", 14) != 0) @@ -1223,7 +1224,7 @@ static bool8 is_SufamiTurbo_Cart (uint8 *data, uint32 size) return (FALSE); } -static bool8 is_SameGame_BIOS (uint8 *data, uint32 size) +static bool8 is_SameGame_BIOS (const uint8 *data, uint32 size) { if (size == 0x100000 && strncmp((char *) (data + 0xffc0), "Same Game Tsume Game", 20) == 0) return (TRUE); @@ -1231,7 +1232,23 @@ static bool8 is_SameGame_BIOS (uint8 *data, uint32 size) return (FALSE); } -static bool8 is_SameGame_Add_On (uint8 *data, uint32 size) +static bool8 is_SameGame_Add_On (const uint8 *data, uint32 size) +{ + if (size == 0x80000) + return (TRUE); + else + return (FALSE); +} + +static bool8 is_GNEXT_BIOS (const uint8 *data, uint32 size) +{ + if (size == 0x180000 && strncmp((char *) (data + 0x7fc0), "SFC SDGUNDAMGNEXT", 17) == 0) + return (TRUE); + else + return (FALSE); +} + +static bool8 is_GNEXT_Add_On (const uint8 *data, uint32 size) { if (size == 0x80000) return (TRUE); @@ -1334,7 +1351,7 @@ int CMemory::ScoreLoROM (bool8 skip_header, int32 romoff) return (score); } -uint32 CMemory::HeaderRemove (uint32 size, int32 &headerCount, uint8 *buf) +uint32 CMemory::HeaderRemove (uint32 size, uint8 *buf) { uint32 calc_size = (size / 0x2000) * 0x2000; @@ -1355,20 +1372,20 @@ uint32 CMemory::HeaderRemove (uint32 size, int32 &headerCount, uint8 *buf) } memmove(buf, buf + 512, calc_size); - headerCount++; + HeaderCount++; size -= 512; } return (size); } -uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize) +uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, uint32 maxsize) { // <- ROM size without header // ** Memory.HeaderCount // ** Memory.ROMFilename - int32 totalSize = 0; + uint32 totalSize = 0; char fname[PATH_MAX + 1]; char drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], name[_MAX_FNAME + 1], exts[_MAX_EXT + 1]; char *ext; @@ -1397,7 +1414,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize) case FILE_ZIP: { #ifdef UNZIP_SUPPORT - if (!LoadZip(fname, &totalSize, &HeaderCount, buffer)) + if (!LoadZip(fname, &totalSize, buffer)) { S9xMessage(S9X_ERROR, S9X_ROM_INFO, "Invalid Zip archive."); return (0); @@ -1421,7 +1438,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize) return (0); } - totalSize = HeaderRemove(size, HeaderCount, buffer); + totalSize = HeaderRemove(size, buffer); strcpy(ROMFilename, fname); #else @@ -1450,7 +1467,7 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize) size = READ_STREAM(ptr, maxsize + 0x200 - (ptr - buffer), fp); CLOSE_STREAM(fp); - size = HeaderRemove(size, HeaderCount, ptr); + size = HeaderRemove(size, ptr); totalSize += size; ptr += size; @@ -1493,32 +1510,56 @@ uint32 CMemory::FileLoader (uint8 *buffer, const char *filename, int32 maxsize) return ((uint32) totalSize); } +bool8 CMemory::LoadROMMem (const uint8 *source, uint32 sourceSize) +{ + if(!source || sourceSize > MAX_ROM_SIZE) + return FALSE; + + strcpy(ROMFilename,"MemoryROM"); + + do + { + memset(ROM,0, MAX_ROM_SIZE); + memset(&Multi, 0,sizeof(Multi)); + memcpy(ROM,source,sourceSize); + } + while(!LoadROMInt(sourceSize)); + + return TRUE; +} + bool8 CMemory::LoadROM (const char *filename) { - int retry_count = 0; + if(!filename || !*filename) + return FALSE; - if (!filename || !*filename) - return (FALSE); + int32 totalFileSize; - ZeroMemory(ROM, MAX_ROM_SIZE); - ZeroMemory(&Multi, sizeof(Multi)); - -again: + do + { + memset(ROM,0, MAX_ROM_SIZE); + memset(&Multi, 0,sizeof(Multi)); + totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE); + + if (!totalFileSize) + return (FALSE); + + if (!Settings.NoPatch) + CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize); + } + while(!LoadROMInt(totalFileSize)); + + return TRUE; +} + +bool8 CMemory::LoadROMInt (int32 ROMfillSize) +{ Settings.DisplayColor = BUILD_PIXEL(31, 31, 31); SET_UI_COLOR(255, 255, 255); CalculatedSize = 0; ExtendedFormat = NOPE; - int32 totalFileSize; - - totalFileSize = FileLoader(ROM, filename, MAX_ROM_SIZE); - if (!totalFileSize) - return (FALSE); - - if (!Settings.NoPatch) - CheckForAnyPatch(filename, HeaderCount != 0, totalFileSize); - int hi_score, lo_score; hi_score = ScoreHiROM(FALSE); @@ -1528,17 +1569,19 @@ again: ((hi_score > lo_score && ScoreHiROM(TRUE) > hi_score) || (hi_score <= lo_score && ScoreLoROM(TRUE) > lo_score))) { - memmove(ROM, ROM + 512, totalFileSize - 512); - totalFileSize -= 512; + memmove(ROM, ROM + 512, ROMfillSize - 512); + ROMfillSize -= 512; S9xMessage(S9X_INFO, S9X_HEADER_WARNING, "Try 'force no-header' option if the game doesn't work"); // modifying ROM, so we need to rescore hi_score = ScoreHiROM(FALSE); lo_score = ScoreLoROM(FALSE); } - CalculatedSize = (totalFileSize / 0x2000) * 0x2000; + CalculatedSize = (ROMfillSize / 0x2000) * 0x2000; if (CalculatedSize > 0x400000 && + (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3423 && // exclude SA-1 + (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x3523 && (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4332 && // exclude S-DD1 (ROM[0x7fd5] + (ROM[0x7fd6] << 8)) != 0x4532 && (ROM[0xffd5] + (ROM[0xffd6] << 8)) != 0xF93a && // exclude SPC7110 @@ -1551,7 +1594,7 @@ again: ((ROM[0xfffc] + (ROM[0xfffd] << 8)) < 0x8000)) { if (!Settings.ForceInterleaved && !Settings.ForceNotInterleaved) - S9xDeinterleaveType1(totalFileSize, ROM); + S9xDeinterleaveType1(ROMfillSize, ROM); } // CalculatedSize is now set, so rescore @@ -1679,14 +1722,10 @@ again: if ((HiROM && (lo_score >= hi_score || hi_score < 0)) || (LoROM && (hi_score > lo_score || lo_score < 0))) { - if (retry_count == 0) - { - S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again."); - Settings.ForceNotInterleaved = TRUE; - Settings.ForceInterleaved = FALSE; - retry_count++; - goto again; - } + S9xMessage(S9X_INFO, S9X_ROM_CONFUSING_FORMAT_INFO, "ROM lied about its type! Trying again."); + Settings.ForceNotInterleaved = TRUE; + Settings.ForceInterleaved = FALSE; + return (FALSE); } } @@ -1706,13 +1745,13 @@ again: } } - if (strncmp(LastRomFilename, filename, PATH_MAX + 1)) + if (strncmp(LastRomFilename, ROMFilename, PATH_MAX + 1)) { - strncpy(LastRomFilename, filename, PATH_MAX + 1); + strncpy(LastRomFilename, ROMFilename, PATH_MAX + 1); LastRomFilename[PATH_MAX] = 0; } - ZeroMemory(&SNESGameFixes, sizeof(SNESGameFixes)); + memset(&SNESGameFixes, 0, sizeof(SNESGameFixes)); SNESGameFixes.SRAMInitialValue = 0x60; S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); @@ -1727,53 +1766,144 @@ again: return (TRUE); } +bool8 CMemory::LoadMultiCartMem (const uint8 *sourceA, uint32 sourceASize, + const uint8 *sourceB, uint32 sourceBSize, + const uint8 *bios, uint32 biosSize) +{ + uint32 offset = 0; + memset(ROM, 0, MAX_ROM_SIZE); + memset(&Multi, 0, sizeof(Multi)); + + if(bios) { + if(!is_SufamiTurbo_BIOS(bios,biosSize)) + return FALSE; + + memcpy(ROM,bios,biosSize); + offset+=biosSize; + } + + if(sourceA) { + memcpy(ROM + offset,sourceA,sourceASize); + Multi.cartOffsetA = offset; + Multi.cartSizeA = sourceASize; + offset += sourceASize; + strcpy(Multi.fileNameA,"MemCartA"); + } + + if(sourceB) { + memcpy(ROM + offset,sourceB,sourceBSize); + Multi.cartOffsetB = offset; + Multi.cartSizeB = sourceBSize; + offset += sourceBSize; + strcpy(Multi.fileNameB,"MemCartB"); + } + + return LoadMultiCartInt(); +} + bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB) { - bool8 r = TRUE; - - ZeroMemory(ROM, MAX_ROM_SIZE); - ZeroMemory(&Multi, sizeof(Multi)); + memset(ROM, 0, MAX_ROM_SIZE); + memset(&Multi, 0, sizeof(Multi)); Settings.DisplayColor = BUILD_PIXEL(31, 31, 31); SET_UI_COLOR(255, 255, 255); - CalculatedSize = 0; - ExtendedFormat = NOPE; + if (cartB && cartB[0]) + Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE); + + if (Multi.cartSizeB) { + strcpy(Multi.fileNameB, cartB); + + if(!Settings.NoPatch) + CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB); + + Multi.cartOffsetB = 0x400000; + memcpy(ROM + Multi.cartOffsetB,ROM,Multi.cartSizeB); + } if (cartA && cartA[0]) Multi.cartSizeA = FileLoader(ROM, cartA, MAX_ROM_SIZE); - if (Multi.cartSizeA == 0) - { - if (cartB && cartB[0]) - Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE); - } + if (Multi.cartSizeA) { + strcpy(Multi.fileNameA, cartA); + + if(!Settings.NoPatch) + CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA); + } + + return LoadMultiCartInt(); +} + +bool8 CMemory::LoadMultiCartInt () +{ + bool8 r = TRUE; + + CalculatedSize = 0; + ExtendedFormat = NOPE; if (Multi.cartSizeA) { - if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeA)) + if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetA, Multi.cartSizeA)) Multi.cartType = 4; else - if (is_SameGame_BIOS(ROM, Multi.cartSizeA)) + if (is_SameGame_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) Multi.cartType = 3; + else + if (is_GNEXT_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA)) + Multi.cartType = 5; } else if (Multi.cartSizeB) { - if (is_SufamiTurbo_Cart(ROM, Multi.cartSizeB)) + if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartType = 4; } else Multi.cartType = 4; // assuming BIOS only + + if(Multi.cartType == 4 && Multi.cartOffsetA == 0) { // try to load bios from file + Multi.cartOffsetA = 0x40000; + if(Multi.cartSizeA) + memmove(ROM + Multi.cartOffsetA,ROM,Multi.cartOffsetB - Multi.cartOffsetA); + else // clear cart A so the bios can detect that it's not present + memset(ROM,0,Multi.cartOffsetB); + + FILE *fp; + size_t size; + char path[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(BIOS_DIR)); + strcat(path, SLASH_STR); + strcat(path, "STBIOS.bin"); + + fp = fopen(path, "rb"); + if (fp) + { + size = fread((void *) ROM, 1, 0x40000, fp); + fclose(fp); + if (!is_SufamiTurbo_BIOS(ROM, size)) + return (FALSE); + } + else + return (FALSE); + + strcpy(ROMFilename, path); + } + switch (Multi.cartType) { case 4: - r = LoadSufamiTurbo(cartA, cartB); + r = LoadSufamiTurbo(); break; case 3: - r = LoadSameGame(cartA, cartB); + r = LoadSameGame(); + break; + + case 5: + r = LoadGNEXT(); break; default: @@ -1782,11 +1912,17 @@ bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB) if (!r) { - ZeroMemory(&Multi, sizeof(Multi)); + memset(&Multi, 0, sizeof(Multi)); return (FALSE); } - ZeroMemory(&SNESGameFixes, sizeof(SNESGameFixes)); + if (Multi.cartSizeA) + strcpy(ROMFilename, Multi.fileNameA); + else + if (Multi.cartSizeB) + strcpy(ROMFilename, Multi.fileNameB); + + memset(&SNESGameFixes, 0, sizeof(SNESGameFixes)); SNESGameFixes.SRAMInitialValue = 0x60; S9xLoadCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); @@ -1801,10 +1937,8 @@ bool8 CMemory::LoadMultiCart (const char *cartA, const char *cartB) return (TRUE); } -bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB) +bool8 CMemory::LoadSufamiTurbo () { - Multi.cartOffsetA = 0x100000; - Multi.cartOffsetB = 0x200000; Multi.sramA = SRAM; Multi.sramB = SRAM + 0x10000; @@ -1812,65 +1946,20 @@ bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB) { Multi.sramSizeA = 4; // ROM[0x37]? Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; - - if (!Settings.NoPatch) - CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA); - - strcpy(Multi.fileNameA, cartA); - memcpy(ROM + Multi.cartOffsetA, ROM, Multi.cartSizeA); } - if (Multi.cartSizeA && !Multi.cartSizeB) + if (Multi.cartSizeB) { - if (cartB && cartB[0]) - Multi.cartSizeB = FileLoader(ROM, cartB, MAX_ROM_SIZE); - - if (Multi.cartSizeB) - { - if (!is_SufamiTurbo_Cart(ROM, Multi.cartSizeB)) - Multi.cartSizeB = 0; - } + if (!is_SufamiTurbo_Cart(ROM + Multi.cartOffsetB, Multi.cartSizeB)) + Multi.cartSizeB = 0; } if (Multi.cartSizeB) { Multi.sramSizeB = 4; // ROM[0x37]? Multi.sramMaskB = Multi.sramSizeB ? ((1 << (Multi.sramSizeB + 3)) * 128 - 1) : 0; - - if (!Settings.NoPatch) - CheckForAnyPatch(cartB, HeaderCount != 0, Multi.cartSizeB); - - strcpy(Multi.fileNameB, cartB); - memcpy(ROM + Multi.cartOffsetB, ROM, Multi.cartSizeB); } - FILE *fp; - size_t size; - char path[PATH_MAX + 1]; - - strcpy(path, S9xGetDirectory(BIOS_DIR)); - strcat(path, SLASH_STR); - strcat(path, "STBIOS.bin"); - - fp = fopen(path, "rb"); - if (fp) - { - size = fread((void *) ROM, 1, 0x40000, fp); - fclose(fp); - if (!is_SufamiTurbo_BIOS(ROM, size)) - return (FALSE); - } - else - return (FALSE); - - if (Multi.cartSizeA) - strcpy(ROMFilename, Multi.fileNameA); - else - if (Multi.cartSizeB) - strcpy(ROMFilename, Multi.fileNameB); - else - strcpy(ROMFilename, path); - LoROM = TRUE; HiROM = FALSE; CalculatedSize = 0x40000; @@ -1878,10 +1967,8 @@ bool8 CMemory::LoadSufamiTurbo (const char *cartA, const char *cartB) return (TRUE); } -bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB) +bool8 CMemory::LoadSameGame () { - Multi.cartOffsetA = 0; - Multi.cartOffsetB = 0x200000; Multi.sramA = SRAM; Multi.sramB = NULL; @@ -1890,24 +1977,12 @@ bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB) Multi.sramSizeB = 0; Multi.sramMaskB = 0; - if (!Settings.NoPatch) - CheckForAnyPatch(cartA, HeaderCount != 0, Multi.cartSizeA); - - strcpy(Multi.fileNameA, cartA); - - if (cartB && cartB[0]) - Multi.cartSizeB = FileLoader(ROM + Multi.cartOffsetB, cartB, MAX_ROM_SIZE - Multi.cartOffsetB); - if (Multi.cartSizeB) { if (!is_SameGame_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB)) Multi.cartSizeB = 0; - else - strcpy(Multi.fileNameB, cartB); } - strcpy(ROMFilename, Multi.fileNameA); - LoROM = FALSE; HiROM = TRUE; CalculatedSize = Multi.cartSizeA; @@ -1915,6 +1990,29 @@ bool8 CMemory::LoadSameGame (const char *cartA, const char *cartB) return (TRUE); } +bool8 CMemory::LoadGNEXT () +{ + Multi.sramA = SRAM; + Multi.sramB = NULL; + + Multi.sramSizeA = ROM[0x7fd8]; + Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0; + Multi.sramSizeB = 0; + Multi.sramMaskB = 0; + + if (Multi.cartSizeB) + { + if (!is_GNEXT_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB)) + Multi.cartSizeB = 0; + } + + LoROM = TRUE; + HiROM = FALSE; + CalculatedSize = Multi.cartSizeA; + + return (TRUE); +} + bool8 CMemory::LoadSRTC (void) { FILE *fp; @@ -2069,9 +2167,6 @@ bool8 CMemory::SaveSRAM (const char *filename) size_t ignore; ignore = fwrite((char *) Multi.sramB, size, 1, file); fclose(file); - #ifdef __linux - ignore = chown(name, getuid(), getgid()); - #endif } strcpy(ROMFilename, temp); @@ -2089,9 +2184,6 @@ bool8 CMemory::SaveSRAM (const char *filename) size_t ignore; ignore = fwrite((char *) SRAM, size, 1, file); fclose(file); - #ifdef __linux - ignore = chown(sramName, getuid(), getgid()); - #endif if (Settings.SRTC || Settings.SPC7110RTC) SaveSRTC(); @@ -2254,7 +2346,7 @@ void CMemory::InitROM (void) Settings.SETA = 0; Settings.SRTC = FALSE; Settings.BS = FALSE; - + SuperFX.nRomBanks = CalculatedSize >> 15; //// Parse ROM header and read ROM informatoin @@ -2461,7 +2553,12 @@ void CMemory::InitROM (void) Map_SuperFXLoROMMap(); else if (Settings.SA1) - Map_SA1LoROMMap(); + { + if (Multi.cartType == 5) + Map_GNEXTSA1LoROMMap(); + else + Map_SA1LoROMMap(); + } else if (Settings.SDD1) Map_SDD1LoROMMap(); @@ -3143,6 +3240,51 @@ void CMemory::Map_SA1LoROMMap (void) BWRAM = SRAM; } +void CMemory::Map_GNEXTSA1LoROMMap (void) +{ + printf("Map_GNEXTSA1LoROMMap\n"); + map_System(); + + map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); + map_lorom_offset(0x80, 0xbf, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); + + map_hirom_offset(0xc0, 0xff, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA); + + map_space(0x00, 0x3f, 0x3000, 0x3fff, FillRAM); + map_space(0x80, 0xbf, 0x3000, 0x3fff, FillRAM); + map_index(0x00, 0x3f, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); + map_index(0x80, 0xbf, 0x6000, 0x7fff, MAP_BWRAM, MAP_TYPE_I_O); + + for (int c = 0x40; c < 0x80; c++) + map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000); + + // FIXME: untested! + map_hirom_offset(0x70, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB); + + map_WRAM(); + + map_WriteProtectROM(); + + // Now copy the map and correct it for the SA1 CPU. + memmove((void *) SA1.Map, (void *) Map, sizeof(Map)); + memmove((void *) SA1.WriteMap, (void *) WriteMap, sizeof(WriteMap)); + + // SA-1 Banks 00->3f and 80->bf + for (int c = 0x000; c < 0x400; c += 0x10) + { + SA1.Map[c + 0] = SA1.Map[c + 0x800] = FillRAM + 0x3000; + SA1.Map[c + 1] = SA1.Map[c + 0x801] = (uint8 *) MAP_NONE; + SA1.WriteMap[c + 0] = SA1.WriteMap[c + 0x800] = FillRAM + 0x3000; + SA1.WriteMap[c + 1] = SA1.WriteMap[c + 0x801] = (uint8 *) MAP_NONE; + } + + // SA-1 Banks 60->6f + for (int c = 0x600; c < 0x700; c++) + SA1.Map[c] = SA1.WriteMap[c] = (uint8 *) MAP_BWRAM_BITMAP; + + BWRAM = SRAM; +} + void CMemory::Map_HiROMMap (void) { printf("Map_HiROMMap\n"); @@ -3204,7 +3346,7 @@ void CMemory::Map_SPC7110HiROMMap (void) map_System(); map_index(0x00, 0x00, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); - map_hirom(0x00, 0x0f, 0x8000, 0xffff, CalculatedSize); + map_hirom(0x00, 0x0f, 0x8000, 0xffff, CalculatedSize); map_index(0x30, 0x30, 0x6000, 0x7fff, MAP_HIROM_SRAM, MAP_TYPE_RAM); map_index(0x50, 0x50, 0x0000, 0xffff, MAP_SPC7110_DRAM, MAP_TYPE_ROM); map_hirom(0x80, 0x8f, 0x8000, 0xffff, CalculatedSize); @@ -3499,14 +3641,13 @@ void CMemory::ApplyROMFixes (void) //// APU timing hacks :( Timings.APUSpeedup = 0; - Timings.APUAllowTimeOverflow = FALSE; if (!Settings.DisableGameSpecificHacks) { if (match_id("AVCJ")) // Rendering Ranger R2 - Timings.APUSpeedup = 4; + Timings.APUSpeedup = 2; - if (match_na("GAIA GENSOUKI 1 JPN") || // Gaia Gensouki +/* if (match_na("GAIA GENSOUKI 1 JPN") || // Gaia Gensouki match_id("JG ") || // Illusion of Gaia match_id("CQ ") || // Stunt Race FX match_na("SOULBLADER - 1") || // Soul Blader @@ -3540,22 +3681,10 @@ void CMemory::ApplyROMFixes (void) match_nn("Parlor") || // Parlor mini/2/3/4/5/6/7, Parlor Parlor!/2/3/4/5 match_na("HEIWA Parlor!Mini8") || // Parlor mini 8 match_nn("SANKYO Fever! \xCC\xA8\xB0\xCA\xDE\xB0!")) // SANKYO Fever! Fever! - Timings.APUSpeedup = 1; - - if (match_na ("EARTHWORM JIM 2") || // Earthworm Jim 2 - match_na ("NBA Hangtime") || // NBA Hang Time - match_na ("MSPACMAN") || // Ms Pacman - match_na ("THE MASK") || // The Mask - match_na ("PRIMAL RAGE") || // Primal Rage - match_na ("PORKY PIGS HAUNTED") || // Porky Pig's Haunted Holiday - match_na ("Big Sky Trooper") || // Big Sky Trooper - match_id ("A35") || // Mechwarrior 3050 / Battle Tech 3050 - match_na ("DOOM TROOPERS")) // Doom Troopers - Timings.APUAllowTimeOverflow = TRUE; + Timings.APUSpeedup = 1; */ } S9xAPUTimingSetSpeedup(Timings.APUSpeedup); - S9xAPUAllowTimeOverflow(Timings.APUAllowTimeOverflow); //// Other timing hacks :( @@ -3636,9 +3765,10 @@ void CMemory::ApplyROMFixes (void) } } -// UPS % IPS +// BPS % UPS % IPS -static uint32 ReadUPSPointer (const uint8 *data, unsigned &addr, unsigned size) +// number decoding used for both BPS and UPS +static uint32 XPSdecode (const uint8 *data, unsigned &addr, unsigned size) { uint32 offset = 0, shift = 1; while(addr < size) { @@ -3660,7 +3790,7 @@ static uint32 ReadUPSPointer (const uint8 *data, unsigned &addr, unsigned size) //no-header patching errors that result in IPS patches having a 50/50 chance of //being applied correctly. -static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size) +static bool8 ReadUPSPatch (Stream *r, long, int32 &rom_size) { //Reader lacks size() and rewind(), so we need to read in the file to get its size uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ... @@ -3693,8 +3823,8 @@ static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size) if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted if((rom_crc32 != px_crc32) && (rom_crc32 != py_crc32)) { delete[] data; return false; } //patch is for a different ROM - uint32 px_size = ReadUPSPointer(data, addr, size); - uint32 py_size = ReadUPSPointer(data, addr, size); + uint32 px_size = XPSdecode(data, addr, size); + uint32 py_size = XPSdecode(data, addr, size); uint32 out_size = ((uint32) rom_size == px_size) ? py_size : px_size; if(out_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer @@ -3706,7 +3836,7 @@ static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size) uint32 relative = 0; while(addr < size - 12) { - relative += ReadUPSPointer(data, addr, size); + relative += XPSdecode(data, addr, size); while(addr < size - 12) { uint8 x = data[addr++]; Memory.ROM[relative++] ^= x; @@ -3738,7 +3868,102 @@ static bool8 ReadUPSPatch (Reader *r, long, int32 &rom_size) } } -static long ReadInt (Reader *r, unsigned nbytes) +// header notes for UPS patches also apply to BPS +// +// logic taken from http://byuu.org/programming/bps and the accompanying source +// +static bool8 ReadBPSPatch (Stream *r, long, int32 &rom_size) +{ + uint8 *data = new uint8[8 * 1024 * 1024]; //allocate a lot of memory, better safe than sorry ... + uint32 size = 0; + while(true) { + int value = r->get_char(); + if(value == EOF) break; + data[size++] = value; + if(size >= 8 * 1024 * 1024) { + //prevent buffer overflow: SNES-made BPS patches should never be this big anyway ... + delete[] data; + return false; + } + } + + /* 4-byte header + 1-byte input size + 1-byte output size + 1-byte metadata size + + 4-byte unpatched CRC32 + 4-byte patched CRC32 + 4-byte patch CRC32 */ + if(size < 19) { delete[] data; return false; } //patch is too small + + uint32 addr = 0; + if(data[addr++] != 'B') { delete[] data; return false; } //patch has an invalid header + if(data[addr++] != 'P') { delete[] data; return false; } //... + if(data[addr++] != 'S') { delete[] data; return false; } //... + if(data[addr++] != '1') { delete[] data; return false; } //... + + uint32 patch_crc32 = caCRC32(data, size - 4); //don't include patch CRC32 itself in CRC32 calculation + uint32 rom_crc32 = caCRC32(Memory.ROM, rom_size); + uint32 source_crc32 = (data[size - 12] << 0) + (data[size - 11] << 8) + (data[size - 10] << 16) + (data[size - 9] << 24); + uint32 target_crc32 = (data[size - 8] << 0) + (data[size - 7] << 8) + (data[size - 6] << 16) + (data[size - 5] << 24); + uint32 pp_crc32 = (data[size - 4] << 0) + (data[size - 3] << 8) + (data[size - 2] << 16) + (data[size - 1] << 24); + if(patch_crc32 != pp_crc32) { delete[] data; return false; } //patch is corrupted + if(rom_crc32 != source_crc32) { delete[] data; return false; } //patch is for a different ROM + + uint32 source_size = XPSdecode(data, addr, size); + uint32 target_size = XPSdecode(data, addr, size); + uint32 metadata_size = XPSdecode(data, addr, size); + addr += metadata_size; + + if(target_size > CMemory::MAX_ROM_SIZE) { delete[] data; return false; } //applying this patch will overflow Memory.ROM buffer + + enum { SourceRead, TargetRead, SourceCopy, TargetCopy }; + uint32 outputOffset = 0, sourceRelativeOffset = 0, targetRelativeOffset = 0; + + uint8 *patched_rom = new uint8[target_size]; + memset(patched_rom,0,target_size); + + while(addr < size - 12) { + uint32 length = XPSdecode(data, addr, size); + uint32 mode = length & 3; + length = (length >> 2) + 1; + + switch((int)mode) { + case SourceRead: + while(length--) patched_rom[outputOffset++] = Memory.ROM[outputOffset]; + break; + case TargetRead: + while(length--) patched_rom[outputOffset++] = data[addr++]; + break; + case SourceCopy: + case TargetCopy: + int32 offset = XPSdecode(data, addr, size); + bool negative = offset & 1; + offset >>= 1; + if(negative) offset = -offset; + + if(mode == SourceCopy) { + sourceRelativeOffset += offset; + while(length--) patched_rom[outputOffset++] = Memory.ROM[sourceRelativeOffset++]; + } else { + targetRelativeOffset += offset; + while(length--) patched_rom[outputOffset++] = patched_rom[targetRelativeOffset++]; + } + break; + } + } + + delete[] data; + + uint32 out_crc32 = caCRC32(patched_rom, target_size); + if(out_crc32 == target_crc32) { + memcpy(Memory.ROM, patched_rom, target_size); + rom_size = target_size; + delete[] patched_rom; + return true; + } else { + delete[] patched_rom; + fprintf(stderr, "WARNING: BPS patching failed.\nROM has not been altered.\n"); + return false; + } +} + +static long ReadInt (Stream *r, unsigned nbytes) { long v = 0; @@ -3753,7 +3978,7 @@ static long ReadInt (Reader *r, unsigned nbytes) return (v); } -static bool8 ReadIPSPatch (Reader *r, long offset, int32 &rom_size) +static bool8 ReadIPSPatch (Stream *r, long offset, int32 &rom_size) { const int32 IPS_EOF = 0x00454F46l; int32 ofs; @@ -3855,7 +4080,7 @@ static int unzFindExtension (unzFile &file, const char *ext, bool restart, bool if (len >= l + 1 && name[len - l - 1] == '.' && strcasecmp(name + len - l, ext) == 0 && unzOpenCurrentFile(file) == UNZ_OK) { if (print) - printf("Using IPS or UPS patch %s", name); + printf("Using patch %s", name); return (port); } @@ -3872,7 +4097,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r if (Settings.NoPatch) return; - STREAM patch_file = NULL; + FSTREAM patch_file = NULL; uint32 i; long offset = header ? 512 : 0; int ret; @@ -3880,17 +4105,78 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r char dir[_MAX_DIR + 1], drive[_MAX_DRIVE + 1], name[_MAX_FNAME + 1], ext[_MAX_EXT + 1], ips[_MAX_EXT + 3], fname[PATH_MAX + 1]; const char *n; + _splitpath(rom_filename, drive, dir, name, ext); + + // BPS + _makepath(fname, drive, dir, name, "bps"); + + if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) + { + printf("Using BPS patch %s", fname); + + ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size); + CLOSE_FSTREAM(patch_file); + + if (ret) + { + printf("!\n"); + return; + } + else + printf(" failed!\n"); + } + +#ifdef UNZIP_SUPPORT + if (!strcasecmp(ext, "zip") || !strcasecmp(ext, ".zip")) + { + unzFile file = unzOpen(rom_filename); + if (file) + { + int port = unzFindExtension(file, "bps"); + if (port == UNZ_OK) + { + printf(" in %s", rom_filename); + + ret = ReadBPSPatch(new unzStream(file), offset, rom_size); + unzCloseCurrentFile(file); + + if (ret) + printf("!\n"); + else + printf(" failed!\n"); + } + } + } +#endif + + n = S9xGetFilename(".bps", IPS_DIR); + + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) + { + printf("Using BPS patch %s", n); + + ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size); + CLOSE_FSTREAM(patch_file); + + if (ret) + { + printf("!\n"); + return; + } + else + printf(" failed!\n"); + } + // UPS - _splitpath(rom_filename, drive, dir, name, ext); _makepath(fname, drive, dir, name, "ups"); - if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL) + if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) { printf("Using UPS patch %s", fname); - ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -3912,7 +4198,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r { printf(" in %s", rom_filename); - ret = ReadUPSPatch(new unzReader(file), offset, rom_size); + ret = ReadUPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) @@ -3926,12 +4212,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r n = S9xGetFilename(".ups", IPS_DIR); - if ((patch_file = OPEN_STREAM(n, "rb")) != NULL) + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) { printf("Using UPS patch %s", n); - ret = ReadUPSPatch(new fReader(patch_file), 0, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -3944,15 +4230,14 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r // IPS - _splitpath(rom_filename, drive, dir, name, ext); _makepath(fname, drive, dir, name, "ips"); - if ((patch_file = OPEN_STREAM(fname, "rb")) != NULL) + if ((patch_file = OPEN_FSTREAM(fname, "rb")) != NULL) { printf("Using IPS patch %s", fname); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -3973,13 +4258,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r snprintf(ips, 8, "%03d.ips", i); _makepath(fname, drive, dir, name, ips); - if (!(patch_file = OPEN_STREAM(fname, "rb"))) + if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4009,13 +4294,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r break; _makepath(fname, drive, dir, name, ips); - if (!(patch_file = OPEN_STREAM(fname, "rb"))) + if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4043,13 +4328,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r snprintf(ips, 4, "ip%d", i); _makepath(fname, drive, dir, name, ips); - if (!(patch_file = OPEN_STREAM(fname, "rb"))) + if (!(patch_file = OPEN_FSTREAM(fname, "rb"))) break; printf("Using IPS patch %s", fname); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4078,7 +4363,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r { printf(" in %s", rom_filename); - ret = ReadIPSPatch(new unzReader(file), offset, rom_size); + ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) @@ -4105,7 +4390,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r printf(" in %s", rom_filename); - ret = ReadIPSPatch(new unzReader(file), offset, rom_size); + ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) @@ -4139,7 +4424,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r printf(" in %s", rom_filename); - ret = ReadIPSPatch(new unzReader(file), offset, rom_size); + ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) @@ -4171,7 +4456,7 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r printf(" in %s", rom_filename); - ret = ReadIPSPatch(new unzReader(file), offset, rom_size); + ret = ReadIPSPatch(new unzStream(file), offset, rom_size); unzCloseCurrentFile(file); if (ret) @@ -4200,12 +4485,12 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r n = S9xGetFilename(".ips", IPS_DIR); - if ((patch_file = OPEN_STREAM(n, "rb")) != NULL) + if ((patch_file = OPEN_FSTREAM(n, "rb")) != NULL) { printf("Using IPS patch %s", n); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4226,13 +4511,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r snprintf(ips, 9, ".%03d.ips", i); n = S9xGetFilename(ips, IPS_DIR); - if (!(patch_file = OPEN_STREAM(n, "rb"))) + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4262,13 +4547,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r break; n = S9xGetFilename(ips, IPS_DIR); - if (!(patch_file = OPEN_STREAM(n, "rb"))) + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { @@ -4296,13 +4581,13 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r snprintf(ips, 5, ".ip%d", i); n = S9xGetFilename(ips, IPS_DIR); - if (!(patch_file = OPEN_STREAM(n, "rb"))) + if (!(patch_file = OPEN_FSTREAM(n, "rb"))) break; printf("Using IPS patch %s", n); - ret = ReadIPSPatch(new fReader(patch_file), offset, rom_size); - CLOSE_STREAM(patch_file); + ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size); + CLOSE_FSTREAM(patch_file); if (ret) { diff --git a/memmap.h b/memmap.h index 2b05de61..0f943542 100644 --- a/memmap.h +++ b/memmap.h @@ -271,12 +271,18 @@ struct CMemory int ScoreHiROM (bool8, int32 romoff = 0); int ScoreLoROM (bool8, int32 romoff = 0); - uint32 HeaderRemove (uint32, int32 &, uint8 *); - uint32 FileLoader (uint8 *, const char *, int32); + uint32 HeaderRemove (uint32, uint8 *); + uint32 FileLoader (uint8 *, const char *, uint32); + uint32 MemLoader (uint8 *, const char*, uint32); + bool8 LoadROMMem (const uint8 *, uint32); bool8 LoadROM (const char *); + bool8 LoadROMInt (int32); + bool8 LoadMultiCartMem (const uint8 *, uint32, const uint8 *, uint32, const uint8 *, uint32); bool8 LoadMultiCart (const char *, const char *); - bool8 LoadSufamiTurbo (const char *, const char *); - bool8 LoadSameGame (const char *, const char *); + bool8 LoadMultiCartInt (); + bool8 LoadSufamiTurbo (); + bool8 LoadSameGame (); + bool8 LoadGNEXT (); bool8 LoadSRAM (const char *); bool8 SaveSRAM (const char *); void ClearSRAM (bool8 onlyNonSavedSRAM = 0); @@ -317,6 +323,7 @@ struct CMemory void Map_SetaDSPLoROMMap (void); void Map_SDD1LoROMMap (void); void Map_SA1LoROMMap (void); + void Map_GNEXTSA1LoROMMap (void); void Map_HiROMMap (void); void Map_ExtendedHiROMMap (void); void Map_SameGameHiROMMap (void); @@ -359,7 +366,7 @@ extern CMemory Memory; extern SMulti Multi; void S9xAutoSaveSRAM (void); -bool8 LoadZip(const char *, int32 *, int32 *, uint8 *); +bool8 LoadZip(const char *, uint32 *, uint8 *); enum s9xwrap_t { diff --git a/movie.cpp b/movie.cpp index 982b9ebd..6b42745a 100644 --- a/movie.cpp +++ b/movie.cpp @@ -412,14 +412,14 @@ static void reset_controllers (void) MovieSetJoypad(i, 0); uint8 clearedMouse[MOUSE_DATA_SIZE]; - ZeroMemory(clearedMouse, MOUSE_DATA_SIZE); + memset(clearedMouse, 0, MOUSE_DATA_SIZE); clearedMouse[4] = 1; uint8 clearedScope[SCOPE_DATA_SIZE]; - ZeroMemory(clearedScope, SCOPE_DATA_SIZE); + memset(clearedScope, 0, SCOPE_DATA_SIZE); uint8 clearedJustifier[JUSTIFIER_DATA_SIZE]; - ZeroMemory(clearedJustifier, JUSTIFIER_DATA_SIZE); + memset(clearedJustifier, 0, JUSTIFIER_DATA_SIZE); for (int p = 0; p < 2; p++) { @@ -614,7 +614,7 @@ static void write_movie_header (FILE *fd, SMovie *movie) { uint8 buf[SMV_HEADER_SIZE], *ptr = buf; - ZeroMemory(buf, sizeof(buf)); + memset(buf, 0, sizeof(buf)); Write32(SMV_MAGIC, ptr); Write32(SMV_VERSION, ptr); @@ -963,7 +963,7 @@ int S9xMovieGetInfo (const char *filename, struct MovieInfo *info) flush_movie(); - ZeroMemory(info, sizeof(*info)); + memset(info, 0, sizeof(*info)); if (!(fd = fopen(filename, "rb"))) return (FILE_NOT_FOUND); @@ -1092,7 +1092,7 @@ void S9xMovieUpdateOnReset (void) void S9xMovieInit (void) { - ZeroMemory(&Movie, sizeof(Movie)); + memset(&Movie, 0, sizeof(Movie)); Movie.State = MOVIE_STATE_NONE; } diff --git a/movie.h b/movie.h index 508ad307..cf55b5a2 100644 --- a/movie.h +++ b/movie.h @@ -185,10 +185,8 @@ #define MOVIE_OPT_NOSAVEDATA (1 << 2) #define MOVIE_SYNC_DATA_EXISTS 0x01 #define MOVIE_SYNC_OBSOLETE 0x02 -#define MOVIE_SYNC_LEFTRIGHT 0x04 #define MOVIE_SYNC_VOLUMEENVX 0x08 #define MOVIE_SYNC_FAKEMUTE 0x10 -#define MOVIE_SYNC_SYNCSOUND 0x20 #define MOVIE_SYNC_HASROMINFO 0x40 #define MOVIE_SYNC_NOCPUSHUTDOWN 0x80 #define MOVIE_MAX_METADATA 512 diff --git a/netplay.cpp b/netplay.cpp index dff5d0a3..6e18291c 100644 --- a/netplay.cpp +++ b/netplay.cpp @@ -189,6 +189,8 @@ #include #include +#include "snes9x.h" + #ifdef __WIN32__ #include #include @@ -222,7 +224,6 @@ #include #endif -#include "snes9x.h" #include "memmap.h" #include "netplay.h" #include "snapshot.h" @@ -350,6 +351,7 @@ on the remote machine on this port?"); errno #endif ); + S9xNPSetError(buf); S9xNPDisconnect (); } return (FALSE); diff --git a/port.h b/port.h index 0e8192e5..1e62b35b 100644 --- a/port.h +++ b/port.h @@ -202,7 +202,9 @@ #define RIGHTSHIFT_int8_IS_SAR #define RIGHTSHIFT_int16_IS_SAR #define RIGHTSHIFT_int32_IS_SAR +#ifndef __WIN32_LIBSNES__ #define SNES_JOY_READ_CALLBACKS +#endif //__WIN32_LIBSNES__ #endif #ifdef __MACOSX__ @@ -227,31 +229,22 @@ typedef uint64_t uint64; #else // HAVE_STDINT_H #ifdef __WIN32__ typedef intptr_t pint; -#else // __WIN32__ -#ifdef PTR_NOT_INT -typedef long pint; -#else -typedef int pint; -#endif -#endif // __WIN32__ -#ifdef __WIN32__ -#ifdef __BORLANDC__ -#include -#else typedef signed char int8; typedef unsigned char uint8; typedef signed short int16; typedef unsigned short uint16; -#ifndef WSAAP -// winsock2.h typedefs int32 as well -typedef signed int int32; -#endif +typedef signed int int32; typedef unsigned int uint32; -#endif -typedef unsigned char uint8_t; -typedef signed char int8_t; typedef signed __int64 int64; typedef unsigned __int64 uint64; +typedef int8 int8_t; +typedef uint8 uint8_t; +typedef int16 int16_t; +typedef uint16 uint16_t; +typedef int32 int32_t; +typedef uint32 uint32_t; +typedef int64 int64_t; +typedef uint64 uint64_t; typedef int socklen_t; #else // __WIN32__ typedef signed char int8; @@ -266,6 +259,11 @@ __extension__ #endif typedef long long int64; typedef unsigned long long uint64; +#ifdef PTR_NOT_INT +typedef long pint; +#else // __PTR_NOT_INT +typedef int pint; +#endif // __PTR_NOT_INT #endif // __WIN32__ #endif // HAVE_STDINT_H #endif // snes9x_types_defined @@ -296,19 +294,22 @@ typedef unsigned long long uint64; #endif #ifndef __WIN32__ -#define ZeroMemory(a, b) memset((a), 0, (b)) void _splitpath (const char *, char *, char *, char *, char *); void _makepath (char *, const char *, const char *, const char *, const char *); #define S9xDisplayString DisplayStringFromBottom -#else +#else // __WIN32__ #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp +#ifndef __WIN32_LIBSNES__ void WinDisplayStringFromBottom(const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap); #define S9xDisplayString WinDisplayStringFromBottom void SetInfoDlgColor(unsigned char, unsigned char, unsigned char); #define SET_UI_COLOR(r,g,b) SetInfoDlgColor(r,g,b) -#endif +#else // __WIN32_LIBSNES__ +#define S9xDisplayString DisplayStringFromBottom +#endif // __WIN32_LIBSNES__ +#endif // __WIN32__ #ifdef __DJGPP #define SLASH_STR "\\" diff --git a/ppu.cpp b/ppu.cpp index 7733baaf..59d11f25 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -1498,6 +1498,11 @@ void S9xSetCPU (uint8 Byte, uint16 Address) Timings.NMITriggerPos = CPU.Cycles + 6 + 6; } + #ifdef DEBUGGER + S9xTraceFormattedMessage("--- IRQ Timer Enable HTimer:%d Pos:%04d VTimer:%d Pos:%03d", + PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); + #endif + break; case 0x4201: // WRIO @@ -1872,7 +1877,7 @@ void S9xSoftResetPPU (void) PPU.OAMReadFlip = 0; PPU.OAMTileAddress = 0; PPU.OAMWriteRegister = 0; - ZeroMemory(PPU.OAMData, 512 + 32); + memset(PPU.OAMData, 0, 512 + 32); PPU.FirstSprite = 0; PPU.LastSprite = 127; @@ -1947,13 +1952,13 @@ void S9xSoftResetPPU (void) IPPU.ColorsChanged = TRUE; IPPU.OBJChanged = TRUE; IPPU.DirectColourMapsNeedRebuild = TRUE; - ZeroMemory(IPPU.TileCached[TILE_2BIT], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT], MAX_4BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_8BIT], MAX_8BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_2BIT_EVEN], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_2BIT_ODD], MAX_2BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT_EVEN], MAX_4BIT_TILES); - ZeroMemory(IPPU.TileCached[TILE_4BIT_ODD], MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_8BIT], 0, MAX_8BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_EVEN], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_2BIT_ODD], 0, MAX_2BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_EVEN], 0, MAX_4BIT_TILES); + memset(IPPU.TileCached[TILE_4BIT_ODD], 0, MAX_4BIT_TILES); IPPU.VRAMReadBuffer = 0; // XXX: FIXME: anything better? IPPU.Interlace = FALSE; IPPU.InterlaceOBJ = FALSE; @@ -1978,11 +1983,11 @@ void S9xSoftResetPPU (void) for (int c = 0; c < 0x8000; c += 0x100) memset(&Memory.FillRAM[c], c >> 8, 0x100); - ZeroMemory(&Memory.FillRAM[0x2100], 0x100); - ZeroMemory(&Memory.FillRAM[0x4200], 0x100); - ZeroMemory(&Memory.FillRAM[0x4000], 0x100); + memset(&Memory.FillRAM[0x2100], 0, 0x100); + memset(&Memory.FillRAM[0x4200], 0, 0x100); + memset(&Memory.FillRAM[0x4000], 0, 0x100); // For BS Suttehakkun 2... - ZeroMemory(&Memory.FillRAM[0x1000], 0x1000); + memset(&Memory.FillRAM[0x1000], 0, 0x1000); Memory.FillRAM[0x4201] = Memory.FillRAM[0x4213] = 0xff; } diff --git a/server.cpp b/server.cpp index fc2f3fa4..6a376132 100644 --- a/server.cpp +++ b/server.cpp @@ -190,6 +190,8 @@ #include #endif +#include "snes9x.h" + #ifdef __WIN32__ #include @@ -219,7 +221,6 @@ #endif // !__WIN32__ -#include "snes9x.h" #include "memmap.h" #include "snapshot.h" #include "netplay.h" diff --git a/snapshot.cpp b/snapshot.cpp index 7b758b42..b816fd43 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -1169,6 +1169,21 @@ void S9xResetSaveTimer (bool8 dontsave) t = time(NULL); } +uint32 S9xFreezeSize() +{ + nulStream stream; + S9xFreezeToStream(&stream); + return stream.size(); +} + +bool8 S9xFreezeGameMem (uint8 *buf, uint32 bufSize) +{ + memStream mStream(buf, bufSize); + S9xFreezeToStream(&mStream); + + return (TRUE); +} + bool8 S9xFreezeGame (const char *filename) { STREAM stream = NULL; @@ -1194,6 +1209,14 @@ bool8 S9xFreezeGame (const char *filename) return (FALSE); } +int S9xUnfreezeGameMem (const uint8 *buf, uint32 bufSize) +{ + memStream stream(buf, bufSize); + int result = S9xUnfreezeFromStream(&stream); + + return result; +} + bool8 S9xUnfreezeGame (const char *filename) { STREAM stream = NULL; @@ -1626,7 +1649,11 @@ int S9xUnfreezeFromStream (STREAM stream) memcpy(Memory.FillRAM, local_fillram, 0x8000); - S9xAPULoadState(local_apu_sound); + if(version < SNAPSHOT_VERSION_BAPU) { + printf("Using Blargg APU snapshot loading (snapshot version %d, current is %d)\n...", version, SNAPSHOT_VERSION); + S9xAPULoadBlarggState(local_apu_sound); + } else + S9xAPULoadState(local_apu_sound); struct SControlSnapshot ctl_snap; UnfreezeStructFromCopy(&ctl_snap, SnapControls, COUNT(SnapControls), local_control_data, version); @@ -1678,7 +1705,7 @@ int S9xUnfreezeFromStream (STREAM stream) if (local_bsx_data) UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version); - if (version < SNAPSHOT_VERSION) + if (version < SNAPSHOT_VERSION_IRQ) { printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION); @@ -2037,7 +2064,9 @@ static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int siz if (l != 11 || strncmp(buffer, name, 3) != 0 || buffer[3] != ':') { err: +#ifdef DEBUGGER fprintf(stdout, "absent: %s(%d); next: '%.11s'\n", name, size, buffer); +#endif REVERT_STREAM(stream, FIND_STREAM(stream) - l, 0); return (WRONG_FORMAT); } @@ -2061,7 +2090,7 @@ static int UnfreezeBlock (STREAM stream, const char *name, uint8 *block, int siz len = size; } - ZeroMemory(block, size); + memset(block, 0, size); if (READ_STREAM(block, len, stream) != len) { @@ -2275,27 +2304,3 @@ static void UnfreezeStructFromCopy (void *sbase, FreezeData *fields, int num_fie } } } - -bool8 S9xSPCDump (const char *filename) -{ - FILE *fs; - uint8 buf[SNES_SPC::spc_file_size]; - size_t ignore; - - fs = fopen(filename, "wb"); - if (!fs) - return (FALSE); - - S9xSetSoundMute(TRUE); - - spc_core->init_header(buf); - spc_core->save_spc(buf); - - ignore = fwrite(buf, SNES_SPC::spc_file_size, 1, fs); - - fclose(fs); - - S9xSetSoundMute(FALSE); - - return (TRUE); -} diff --git a/snapshot.h b/snapshot.h index d55b8b7e..88798a23 100644 --- a/snapshot.h +++ b/snapshot.h @@ -180,7 +180,9 @@ #define _SNAPSHOT_H_ #define SNAPSHOT_MAGIC "#!s9xsnp" -#define SNAPSHOT_VERSION 7 +#define SNAPSHOT_VERSION_IRQ 7 +#define SNAPSHOT_VERSION_BAPU 8 +#define SNAPSHOT_VERSION 8 #define SUCCESS 1 #define WRONG_FORMAT (-1) @@ -192,9 +194,11 @@ void S9xResetSaveTimer (bool8); bool8 S9xFreezeGame (const char *); +uint32 S9xFreezeSize (void); +bool8 S9xFreezeGameMem (uint8 *,uint32); bool8 S9xUnfreezeGame (const char *); +int S9xUnfreezeGameMem (const uint8 *,uint32); void S9xFreezeToStream (STREAM); int S9xUnfreezeFromStream (STREAM); -bool8 S9xSPCDump (const char *); #endif diff --git a/snes9x.cpp b/snes9x.cpp index 148073e8..4a84e70b 100644 --- a/snes9x.cpp +++ b/snes9x.cpp @@ -315,14 +315,14 @@ static void parse_crosshair_spec (enum crosscontrols ctl, const char *spec) static bool try_load_config_file (const char *fname, ConfigFile &conf) { - STREAM fp; + FSTREAM fp; - fp = OPEN_STREAM(fname, "r"); + fp = OPEN_FSTREAM(fname, "r"); if (fp) { fprintf(stdout, "Reading config file %s.\n", fname); - conf.LoadFile(new fReader(fp)); - CLOSE_STREAM(fp); + conf.LoadFile(new fStream(fp)); + CLOSE_FSTREAM(fp); return (true); } diff --git a/snes9x.h b/snes9x.h index 4e09c0dd..97689baf 100644 --- a/snes9x.h +++ b/snes9x.h @@ -189,29 +189,42 @@ #ifdef ZLIB #include -#define STREAM gzFile -#define READ_STREAM(p, l, s) gzread(s, p, l) -#define WRITE_STREAM(p, l, s) gzwrite(s, p, l) -#define GETS_STREAM(p, l, s) gzgets(s, p, l) -#define GETC_STREAM(s) gzgetc(s) -#define OPEN_STREAM(f, m) gzopen(f, m) -#define REOPEN_STREAM(f, m) gzdopen(f, m) -#define FIND_STREAM(f) gztell(f) -#define REVERT_STREAM(f, o, s) gzseek(f, o, s) -#define CLOSE_STREAM(s) gzclose(s) +#define FSTREAM gzFile +#define READ_FSTREAM(p, l, s) gzread(s, p, l) +#define WRITE_FSTREAM(p, l, s) gzwrite(s, p, l) +#define GETS_FSTREAM(p, l, s) gzgets(s, p, l) +#define GETC_FSTREAM(s) gzgetc(s) +#define OPEN_FSTREAM(f, m) gzopen(f, m) +#define REOPEN_FSTREAM(f, m) gzdopen(f, m) +#define FIND_FSTREAM(f) gztell(f) +#define REVERT_FSTREAM(s, o, p) gzseek(s, o, p) +#define CLOSE_FSTREAM(s) gzclose(s) #else -#define STREAM FILE * -#define READ_STREAM(p, l, s) fread(p, 1, l, s) -#define WRITE_STREAM(p, l, s) fwrite(p, 1, l, s) -#define GETS_STREAM(p, l, s) fgets(p, l, s) -#define GETC_STREAM(s) fgetc(s) -#define OPEN_STREAM(f, m) fopen(f, m) -#define REOPEN_STREAM(f, m) fdopen(f, m) -#define FIND_STREAM(f) ftell(f) -#define REVERT_STREAM(f, o, s) fseek(f, o, s) -#define CLOSE_STREAM(s) fclose(s) +#define FSTREAM FILE * +#define READ_FSTREAM(p, l, s) fread(p, 1, l, s) +#define WRITE_FSTREAM(p, l, s) fwrite(p, 1, l, s) +#define GETS_FSTREAM(p, l, s) fgets(p, l, s) +#define GETC_FSTREAM(s) fgetc(s) +#define OPEN_FSTREAM(f, m) fopen(f, m) +#define REOPEN_FSTREAM(f, m) fdopen(f, m) +#define FIND_FSTREAM(s) ftell(s) +#define REVERT_FSTREAM(s, o, p) fseek(s, o, p) +#define CLOSE_FSTREAM(s) fclose(s) #endif +#include "stream.h" + +#define STREAM Stream * +#define READ_STREAM(p, l, s) s->read(p,l) +#define WRITE_STREAM(p, l, s) s->write(p,l) +#define GETS_STREAM(p, l, s) s->gets(p,l) +#define GETC_STREAM(s) s->get_char() +#define OPEN_STREAM(f, m) openStreamFromFSTREAM(f, m) +#define REOPEN_STREAM(f, m) reopenStreamFromFd(f, m) +#define FIND_STREAM(s) s->pos() +#define REVERT_STREAM(s, o, p) s->revert(p, o) +#define CLOSE_STREAM(s) s->closeStream() + #define SNES_WIDTH 256 #define SNES_HEIGHT 224 #define SNES_HEIGHT_EXTENDED 239 diff --git a/statemanager.cpp b/statemanager.cpp new file mode 100644 index 00000000..7280ec89 --- /dev/null +++ b/statemanager.cpp @@ -0,0 +1,191 @@ +#include "statemanager.h" +#include "snapshot.h" + +/* State Manager Class that records snapshot data for rewinding + mostly based on SSNES's rewind code by Themaister +*/ + +static inline size_t nearest_pow2_size(size_t v) +{ + size_t orig = v; + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; +#if SIZE_MAX >= 0xffff + v |= v >> 8; +#endif +#if SIZE_MAX >= 0xffffffff + v |= v >> 16; +#endif +#if SIZE_MAX >= 0xffffffffffffffff + v |= v >> 32; +#endif + v++; + + size_t next = v; + size_t prev = v >> 1; + + if ((next - orig) < (orig - prev)) + return next; + else + return prev; +} + +void StateManager::deallocate() { + if(buffer) { + delete [] buffer; + buffer = NULL; + } + if(tmp_state) { + delete [] tmp_state; + tmp_state = NULL; + } + if(in_state) { + delete [] in_state; + in_state = NULL; + } +} + +StateManager::StateManager() +{ + buffer = NULL; + tmp_state = NULL; + in_state = NULL; + init_done = false; +} + +StateManager::~StateManager() { + deallocate(); +} + +bool StateManager::init(size_t buffer_size) { + + init_done = false; + + deallocate(); + + real_state_size = S9xFreezeSize(); + state_size = real_state_size / sizeof(uint32_t); // Works in multiple of 4. + + // We need 4-byte aligned state_size to avoid having to enforce this with unneeded memcpy's! + if(real_state_size % sizeof(uint32_t)) state_size ++; + + if (buffer_size <= real_state_size) // Need a sufficient buffer size. + return false; + + top_ptr = 1; + + + buf_size = nearest_pow2_size(buffer_size) / sizeof(uint64_t); // Works in multiple of 8. + buf_size_mask = buf_size - 1; + + if (!(buffer = new uint64_t[buf_size])) + return false; + if (!(tmp_state = new uint32_t[state_size])) + return false; + if (!(in_state = new uint32_t[state_size])) + return false; + + memset(tmp_state,0,state_size * sizeof(uint32_t)); + memset(in_state,0,state_size * sizeof(uint32_t)); + + init_done = true; + + return true; +} + +int StateManager::pop() +{ + if(!init_done) + return 0; + + if (first_pop) + { + first_pop = false; + return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size); + } + + top_ptr = (top_ptr - 1) & buf_size_mask; + + if (top_ptr == bottom_ptr) // Our stack is completely empty... :v + { + top_ptr = (top_ptr + 1) & buf_size_mask; + return 0; + } + + while (buffer[top_ptr]) + { + // Apply the xor patch. + uint32_t addr = buffer[top_ptr] >> 32; + uint32_t xor_ = buffer[top_ptr] & 0xFFFFFFFFU; + tmp_state[addr] ^= xor_; + + top_ptr = (top_ptr - 1) & buf_size_mask; + } + + if (top_ptr == bottom_ptr) // Our stack is completely empty... :v + { + top_ptr = (top_ptr + 1) & buf_size_mask; + } + + return S9xUnfreezeGameMem((uint8 *)tmp_state,real_state_size); +} + +void StateManager::reassign_bottom() +{ + bottom_ptr = (top_ptr + 1) & buf_size_mask; + while (buffer[bottom_ptr]) // Skip ahead until we find the first 0 (boundary for state delta). + bottom_ptr = (bottom_ptr + 1) & buf_size_mask; +} + +void StateManager::generate_delta(const void *data) +{ + bool crossed = false; + const uint32_t *old_state = tmp_state; + const uint32_t *new_state = (const uint32_t*)data; + + buffer[top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between. + top_ptr &= buf_size_mask; + + // Check if top_ptr and bottom_ptr crossed each other, which means we need to delete old cruft. + if (top_ptr == bottom_ptr) + crossed = true; + + for (uint64_t i = 0; i < state_size; i++) + { + uint64_t xor_ = old_state[i] ^ new_state[i]; + + // If the data differs (xor != 0), we push that xor on the stack with index and xor. + // This can be reversed by reapplying the xor. + // This, if states don't really differ much, we'll save lots of space :) + // Hopefully this will work really well with save states. + if (xor_) + { + buffer[top_ptr] = (i << 32) | xor_; + top_ptr = (top_ptr + 1) & buf_size_mask; + + if (top_ptr == bottom_ptr) + crossed = true; + } + } + + if (crossed) + reassign_bottom(); +} + +bool StateManager::push() +{ + if(!init_done) + return false; + if(!S9xFreezeGameMem((uint8 *)in_state,real_state_size)) + return false; + generate_delta(in_state); + uint32 *tmp = tmp_state; + tmp_state = in_state; + in_state = tmp; + + first_pop = true; + + return true; +} diff --git a/statemanager.h b/statemanager.h new file mode 100644 index 00000000..38f3c0d7 --- /dev/null +++ b/statemanager.h @@ -0,0 +1,35 @@ +#ifndef STATEMANAGER_H +#define STATEMANAGER_H + +/* State Manager Class that records snapshot data for rewinding + mostly based on SSNES's rewind code by Themaister +*/ + +#include "snes9x.h" + +class StateManager { +private: + uint64_t *buffer; + size_t buf_size; + size_t buf_size_mask; + uint32_t *tmp_state; + uint32_t *in_state; + size_t top_ptr; + size_t bottom_ptr; + size_t state_size; + size_t real_state_size; + bool init_done; + bool first_pop; + + void reassign_bottom(); + void generate_delta(const void *data); + void deallocate(); +public: + StateManager(); + ~StateManager(); + bool init(size_t buffer_size); + int pop(); + bool push(); +}; + +#endif // STATEMANAGER_H diff --git a/stream.cpp b/stream.cpp new file mode 100644 index 00000000..0d4082c4 --- /dev/null +++ b/stream.cpp @@ -0,0 +1,592 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ + + +// Abstract the details of reading from zip files versus FILE *'s. + +#include +#ifdef UNZIP_SUPPORT +#include "unzip.h" +#endif +#include "snes9x.h" +#include "stream.h" + + +// Generic constructor/destructor + +Stream::Stream (void) +{ + return; +} + +Stream::~Stream (void) +{ + return; +} + +// Generic getline function, based on gets. Reimlpement if you can do better. + +char * Stream::getline (void) +{ + bool eof; + std::string ret; + + ret = getline(eof); + if (ret.size() == 0 && eof) + return (NULL); + + return (strdup(ret.c_str())); +} + +std::string Stream::getline (bool &eof) +{ + char buf[1024]; + std::string ret; + + eof = false; + ret.clear(); + + do + { + if (gets(buf, sizeof(buf)) == NULL) + { + eof = true; + break; + } + + ret.append(buf); + } + while (*ret.rbegin() != '\n'); + + return (ret); +} + +// snes9x.h FSTREAM Stream + +fStream::fStream (FSTREAM f) +{ + fp = f; +} + +fStream::~fStream (void) +{ + return; +} + +int fStream::get_char (void) +{ + return (GETC_FSTREAM(fp)); +} + +char * fStream::gets (char *buf, size_t len) +{ + return (GETS_FSTREAM(buf, len, fp)); +} + +size_t fStream::read (void *buf, size_t len) +{ + return (READ_FSTREAM(buf, len, fp)); +} + +size_t fStream::write (void *buf, size_t len) +{ + return (WRITE_FSTREAM(buf, len, fp)); +} + +size_t fStream::pos (void) +{ + return (FIND_FSTREAM(fp)); +} + +size_t fStream::size (void) +{ + size_t sz; + REVERT_FSTREAM(fp,0L,SEEK_END); + sz = FIND_FSTREAM(fp); + REVERT_FSTREAM(fp,0L,SEEK_SET); + return sz; +} + +int fStream::revert (size_t from, size_t offset) +{ + return (REVERT_FSTREAM(fp, from, offset)); +} + +void fStream::closeStream() +{ + CLOSE_FSTREAM(fp); + delete this; +} + +// unzip Stream + +#ifdef UNZIP_SUPPORT + +unzStream::unzStream (unzFile &v) +{ + file = v; + head = NULL; + numbytes = 0; +} + +unzStream::~unzStream (void) +{ + return; +} + +int unzStream::get_char (void) +{ + unsigned char c; + + if (numbytes <= 0) + { + numbytes = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); + if (numbytes <= 0) + return (EOF); + head = buffer; + } + + c = *head; + head++; + numbytes--; + + return ((int) c); +} + +char * unzStream::gets (char *buf, size_t len) +{ + size_t i; + int c; + + for (i = 0; i < len - 1; i++) + { + c = get_char(); + if (c == EOF) + { + if (i == 0) + return (NULL); + break; + } + + buf[i] = (char) c; + if (buf[i] == '\n') + break; + } + + buf[i] = '\0'; + + return (buf); +} + +size_t unzStream::read (void *buf, size_t len) +{ + if (len == 0) + return (len); + + if (len <= numbytes) + { + memcpy(buf, head, len); + numbytes -= len; + head += len; + return (len); + } + + size_t numread = 0; + if (numbytes > 0) + { + memcpy(buf, head, numbytes); + numread += numbytes; + head = NULL; + numbytes = 0; + } + + int l = unzReadCurrentFile(file, (uint8 *)buf + numread, len - numread); + if (l > 0) + numread += l; + + return (numread); +} + +// not supported +size_t unzStream::write (void *buf, size_t len) +{ + return (0); +} + +size_t unzStream::pos (void) +{ + return (unztell(file)); +} + +size_t unzStream::size (void) +{ + unz_file_info info; + unzGetCurrentFileInfo(file,&info,NULL,0,NULL,0,NULL,0); + return info.uncompressed_size; +} + +// not supported +int unzStream::revert (size_t from, size_t offset) +{ + return -1; +} + +void unzStream::closeStream() +{ + unzCloseCurrentFile(file); + delete this; +} + +#endif + +// memory Stream + +memStream::memStream (uint8 *source, size_t sourceSize) +{ + mem = head = source; + msize = remaining = sourceSize; + readonly = false; +} + +memStream::memStream (const uint8 *source, size_t sourceSize) +{ + mem = head = const_cast(source); + msize = remaining = sourceSize; + readonly = true; +} + +memStream::~memStream (void) +{ + return; +} + +int memStream::get_char (void) +{ + if(!remaining) + return EOF; + + remaining--; + return *head++; +} + +char * memStream::gets (char *buf, size_t len) +{ + size_t i; + int c; + + for (i = 0; i < len - 1; i++) + { + c = get_char(); + if (c == EOF) + { + if (i == 0) + return (NULL); + break; + } + + buf[i] = (char) c; + if (buf[i] == '\n') + break; + } + + buf[i] = '\0'; + + return (buf); +} + +size_t memStream::read (void *buf, size_t len) +{ + size_t bytes = len < remaining ? len : remaining; + memcpy(buf,head,bytes); + head += bytes; + remaining -= bytes; + + return bytes; +} + +size_t memStream::write (void *buf, size_t len) +{ + if(readonly) + return 0; + + size_t bytes = len < remaining ? len : remaining; + memcpy(head,buf,bytes); + head += bytes; + remaining -= bytes; + + return bytes; +} + +size_t memStream::pos (void) +{ + return msize - remaining; +} + +size_t memStream::size (void) +{ + return msize; +} + +int memStream::revert (size_t from, size_t offset) +{ + size_t pos = from + offset; + + if(pos > msize) + return -1; + + head = mem + pos; + remaining = msize - pos; + + return 0; +} + +void memStream::closeStream() +{ + delete [] mem; + delete this; +} + +// dummy Stream + +nulStream::nulStream (void) +{ + bytes_written = 0; +} + +nulStream::~nulStream (void) +{ + return; +} + +int nulStream::get_char (void) +{ + return 0; +} + +char * nulStream::gets (char *buf, size_t len) +{ + *buf = '\0'; + return NULL; +} + +size_t nulStream::read (void *buf, size_t len) +{ + return 0; +} + +size_t nulStream::write (void *buf, size_t len) +{ + bytes_written += len; + return len; +} + +size_t nulStream::pos (void) +{ + return 0; +} + +size_t nulStream::size (void) +{ + return bytes_written; +} + +int nulStream::revert (size_t from, size_t offset) +{ + bytes_written = from + offset; + return 0; +} + +void nulStream::closeStream() +{ + delete this; +} + +Stream *openStreamFromFSTREAM(const char* filename, const char* mode) +{ + FSTREAM f = OPEN_FSTREAM(filename,mode); + if(!f) + return NULL; + return new fStream(f); +} + +Stream *reopenStreamFromFd(int fd, const char* mode) +{ + FSTREAM f = REOPEN_FSTREAM(fd,mode); + if(!f) + return NULL; + return new fStream(f); +} diff --git a/stream.h b/stream.h new file mode 100644 index 00000000..7a0e509a --- /dev/null +++ b/stream.h @@ -0,0 +1,296 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ + + +#ifndef _STREAM_H_ +#define _STREAM_H_ + +#include + +class Stream +{ + public: + Stream (void); + virtual ~Stream (void); + virtual int get_char (void) = 0; + virtual char * gets (char *, size_t) = 0; + virtual char * getline (void); // free() when done + virtual std::string getline (bool &); + virtual size_t read (void *, size_t) = 0; + virtual size_t write (void *, size_t) = 0; + virtual size_t pos (void) = 0; + virtual size_t size (void) = 0; + virtual int revert (size_t from, size_t offset) = 0; + virtual void closeStream() = 0; +}; + +class fStream : public Stream +{ + public: + fStream (FSTREAM); + virtual ~fStream (void); + virtual int get_char (void); + virtual char * gets (char *, size_t); + virtual size_t read (void *, size_t); + virtual size_t write (void *, size_t); + virtual size_t pos (void); + virtual size_t size (void); + virtual int revert (size_t from, size_t offset); + virtual void closeStream(); + + private: + FSTREAM fp; +}; + +#ifdef UNZIP_SUPPORT + +#include "unzip.h" + +#define unz_BUFFSIZ 1024 + +class unzStream : public Stream +{ + public: + unzStream (unzFile &); + virtual ~unzStream (void); + virtual int get_char (void); + virtual char * gets (char *, size_t); + virtual size_t read (void *, size_t); + virtual size_t write (void *, size_t); + virtual size_t pos (void); + virtual size_t size (void); + virtual int revert (size_t from, size_t offset); + virtual void closeStream(); + + private: + unzFile file; + char buffer[unz_BUFFSIZ]; + char *head; + size_t numbytes; +}; + +#endif + +class memStream : public Stream +{ + public: + memStream (uint8 *,size_t); + memStream (const uint8 *,size_t); + virtual ~memStream (void); + virtual int get_char (void); + virtual char * gets (char *, size_t); + virtual size_t read (void *, size_t); + virtual size_t write (void *, size_t); + virtual size_t pos (void); + virtual size_t size (void); + virtual int revert (size_t from, size_t offset); + virtual void closeStream(); + + private: + uint8 *mem; + size_t msize; + size_t remaining; + uint8 *head; + bool readonly; +}; + +/* dummy stream that always reads 0 and writes nowhere + but counts bytes written +*/ +class nulStream : public Stream +{ + public: + nulStream (void); + virtual ~nulStream (void); + virtual int get_char (void); + virtual char * gets (char *, size_t); + virtual size_t read (void *, size_t); + virtual size_t write (void *, size_t); + virtual size_t pos (void); + virtual size_t size (void); + virtual int revert (size_t from, size_t offset); + virtual void closeStream(); + + private: + size_t bytes_written; +}; + +Stream *openStreamFromFSTREAM(const char* filename, const char* mode); +Stream *reopenStreamFromFd(int fd, const char* mode); + + +#endif diff --git a/unix/Makefile.in b/unix/Makefile.in index 36cf6050..58495689 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -7,7 +7,7 @@ OS = `uname -s -r -m|sed \"s/ /-/g\"|tr \"[A-Z]\" \"[a-z]\"|tr \"/()\" \"___\"` BUILDDIR = . -OBJECTS = ../apu/apu.o ../apu/SNES_SPC.o ../apu/SNES_SPC_misc.o ../apu/SNES_SPC_state.o ../apu/SPC_DSP.o ../apu/SPC_Filter.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../reader.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o unix.o x11.o +OBJECTS = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o ../statemanager.o unix.o x11.o DEFS = -DMITSHM ifdef S9XDEBUGGER @@ -29,7 +29,7 @@ endif CCC = @CXX@ CC = @CC@ GASM = @CXX@ -INCLUDES = -I. -I.. -I../apu/ -I../unzip/ -I../jma/ -I../filter/ +INCLUDES = -I. -I.. -I../apu/ -I../apu/bapu -I../unzip/ -I../jma/ -I../filter/ CCFLAGS = @S9XFLGS@ @S9XDEFS@ $(DEFS) CFLAGS = $(CCFLAGS) diff --git a/unix/unix.cpp b/unix/unix.cpp index c5f6da26..938e5698 100644 --- a/unix/unix.cpp +++ b/unix/unix.cpp @@ -222,6 +222,7 @@ #ifdef DEBUGGER #include "debug.h" #endif +#include "statemanager.h" #ifdef NETPLAY_SUPPORT #ifdef _DEBUG @@ -233,6 +234,8 @@ typedef std::pair strpair_t; ConfigFile::secvec_t keymaps; +StateManager stateMan; + #define FIXED_POINT 0x10000 #define FIXED_POINT_SHIFT 16 #define FIXED_POINT_REMAINDER 0xffff @@ -275,6 +278,8 @@ struct SUnixSettings bool8 ThreadSound; uint32 SoundBufferSize; uint32 SoundFragmentSize; + uint32 rewindBufferSize; + uint32 rewindGranularity; }; struct SoundStatus @@ -290,6 +295,8 @@ struct SoundStatus static SUnixSettings unixSettings; static SoundStatus so; +static bool8 rewinding; + #ifndef NOSOUND static uint8 Buf[SOUND_BUFFER_SIZE]; #endif @@ -436,6 +443,10 @@ void S9xExtraUsage (void) S9xMessage(S9X_INFO, S9X_USAGE, " frames (use with -dumpstreams)"); S9xMessage(S9X_INFO, S9X_USAGE, ""); + S9xMessage(S9X_INFO, S9X_USAGE, "-rwbuffersize Rewind buffer size in MB"); + S9xMessage(S9X_INFO, S9X_USAGE, "-rwgranularity Rewind granularity in frames"); + S9xMessage(S9X_INFO, S9X_USAGE, ""); + S9xExtraDisplayUsage(); } @@ -534,6 +545,22 @@ void S9xParseArg (char **argv, int &i, int argc) else if (!strcasecmp(argv[i], "-dumpmaxframes")) Settings.DumpStreamsMaxFrames = atoi(argv[++i]); + else + if (!strcasecmp(argv[i], "-rwbuffersize")) + { + if (i + 1 < argc) + unixSettings.rewindBufferSize = atoi(argv[++i]); + else + S9xUsage(); + } + else + if (!strcasecmp(argv[i], "-rwgranularity")) + { + if (i + 1 < argc) + unixSettings.rewindGranularity = atoi(argv[++i]); + else + S9xUsage(); + } else S9xParseDisplayArg(argv, i, argc); } @@ -1138,6 +1165,13 @@ s9xcommand_t S9xGetPortCommandT (const char *n) return (cmd); } + } else + if (!strcmp(n,"Rewind")) + { + cmd.type = S9xButtonPort; + cmd.port[1] = 2; + + return (cmd); } return (S9xGetDisplayCommandT(n)); @@ -1168,6 +1202,9 @@ char * S9xGetPortCommandName (s9xcommand_t cmd) x += " ToggleMeta"; x += (int) cmd.port[3]; return (strdup(x.c_str())); + + case 2: + return (strdup("Rewind")); } break; @@ -1204,6 +1241,10 @@ void S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2) if (data1) js_mod[cmd.port[2]] ^= cmd.port[3]; break; + + case 2: + rewinding = (bool8) data1; + break; } break; @@ -1555,7 +1596,7 @@ int main (int argc, char **argv) snprintf(default_dir, PATH_MAX + 1, "%s%s%s", getenv("HOME"), SLASH_STR, ".snes9x"); s9x_base_dir = default_dir; - ZeroMemory(&Settings, sizeof(Settings)); + memset(&Settings, 0, sizeof(Settings)); Settings.MouseMaster = TRUE; Settings.SuperScopeMaster = TRUE; Settings.JustifierMaster = TRUE; @@ -1594,7 +1635,12 @@ int main (int argc, char **argv) unixSettings.SoundBufferSize = 100; unixSettings.SoundFragmentSize = 2048; - ZeroMemory(&so, sizeof(so)); + unixSettings.rewindBufferSize = 0; + unixSettings.rewindGranularity = 1; + + memset(&so, 0, sizeof(so)); + + rewinding = false; CPU.Flags = 0; @@ -1733,6 +1779,8 @@ int main (int argc, char **argv) { NetPlay.MaxFrameSkip = 10; + unixSettings.rewindBufferSize = 0; + if (!S9xNPConnectToServer(Settings.ServerName, Settings.Port, Memory.ROMName)) { fprintf(stderr, "Failed to connect to server %s on port %d.\n", Settings.ServerName, Settings.Port); @@ -1759,12 +1807,18 @@ int main (int argc, char **argv) CPU.Flags |= flags; } else - if (snapshot_filename) { - uint32 flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG); - if (!S9xUnfreezeGame(snapshot_filename)) - exit(1); - CPU.Flags |= flags; + if (snapshot_filename) + { + uint32 flags = CPU.Flags & (DEBUG_MODE_FLAG | TRACE_FLAG); + if (!S9xUnfreezeGame(snapshot_filename)) + exit(1); + CPU.Flags |= flags; + } + if (unixSettings.rewindBufferSize) + { + stateMan.init(unixSettings.rewindBufferSize * 1024 * 1024); + } } S9xGraphicsMode(); @@ -1822,7 +1876,14 @@ int main (int argc, char **argv) #else if (!Settings.Paused) #endif + { + if(rewinding) + rewinding = stateMan.pop(); + else if(IPPU.TotalEmulatedFrames % unixSettings.rewindGranularity == 0) + stateMan.push(); + S9xMainLoop(); + } #ifdef NETPLAY_SUPPORT if (NP_Activated) diff --git a/unix/x11.cpp b/unix/x11.cpp index cb76f82d..d510464a 100644 --- a/unix/x11.cpp +++ b/unix/x11.cpp @@ -462,6 +462,8 @@ const char * S9xParseDisplayConfig (ConfigFile &conf, int pass) keymaps.push_back(strpair_t("M00:Pointer", "Pointer Mouse1+Superscope+Justifier1")); keymaps.push_back(strpair_t("K00:grave", "Superscope ToggleTurbo")); keymaps.push_back(strpair_t("K00:slash", "Superscope Pause")); + + keymaps.push_back(strpair_t("K00:r", "Rewind")); } GUI.no_repeat = !conf.GetBool("Unix/X11::SetKeyRepeat", TRUE); diff --git a/win32/CCGShader.cpp b/win32/CCGShader.cpp new file mode 100644 index 00000000..7789e321 --- /dev/null +++ b/win32/CCGShader.cpp @@ -0,0 +1,297 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ +#include "CCGShader.h" +#include "../conffile.h" + +CCGShader::CCGShader(void) +{ + +} + +CCGShader::~CCGShader(void) +{ +} + +cgScaleType CCGShader::scaleStringToEnum(const char *scale) +{ + if(!strcasecmp(scale,"source")) { + return CG_SCALE_SOURCE; + } else if(!strcasecmp(scale,"viewport")) { + return CG_SCALE_VIEWPORT; + } else if(!strcasecmp(scale,"absolute")) { + return CG_SCALE_ABSOLUTE; + } else { + return CG_SCALE_NONE; + } +} + +bool CCGShader::LoadShader(const char *path) +{ + ConfigFile conf; + int shaderCount; + char keyName[100]; + + shaderPasses.clear(); + lookupTextures.clear(); + + if(strlen(path)<4 || strcasecmp(&path[strlen(path)-4],".cgp")) { + shaderPass pass; + pass.scaleParams.scaleTypeX = CG_SCALE_NONE; + pass.scaleParams.scaleTypeY = CG_SCALE_NONE; + pass.linearFilter = false; + pass.filterSet = false; + strcpy(pass.cgShaderFile,path); + shaderPasses.push_back(pass); + return true; + } else { + conf.LoadFile(path); + } + + shaderCount = conf.GetInt("::shaders",0); + + if(shaderCount<1) + return false; + + for(int i=0;i -#ifndef _READER_H_ -#define _READER_H_ +enum cgScaleType { CG_SCALE_NONE, CG_SCALE_SOURCE, CG_SCALE_VIEWPORT, CG_SCALE_ABSOLUTE }; +typedef struct _cgScaleParams { + cgScaleType scaleTypeX; + cgScaleType scaleTypeY; + float scaleX; + float scaleY; + unsigned absX; + unsigned absY; +} cgScaleParams; -class Reader +class CCGShader { - public: - Reader (void); - virtual ~Reader (void); - virtual int get_char (void) = 0; - virtual char * gets (char *, size_t) = 0; - virtual char * getline (void); // free() when done - virtual std::string getline (bool &); - virtual size_t read (char *, size_t) = 0; -}; +private: + cgScaleType scaleStringToEnum(const char* scale); +public: + typedef struct _shaderPass { + cgScaleParams scaleParams; + bool linearFilter; + bool filterSet; + char cgShaderFile[PATH_MAX]; + } shaderPass; + typedef struct _lookupTexture { + char id[PATH_MAX]; + char texturePath[PATH_MAX]; + bool linearfilter; + } lookupTexture; -class fReader : public Reader -{ - public: - fReader (STREAM); - virtual ~fReader (void); - virtual int get_char (void); - virtual char * gets (char *, size_t); - virtual size_t read (char *, size_t); + CCGShader(void); + ~CCGShader(void); + bool LoadShader(const char *path); - private: - STREAM fp; -}; - -#ifdef UNZIP_SUPPORT - -#define unz_BUFFSIZ 1024 - -class unzReader : public Reader -{ - public: - unzReader (unzFile &); - virtual ~unzReader (void); - virtual int get_char (void); - virtual char * gets (char *, size_t); - virtual size_t read (char *, size_t); - - private: - unzFile file; - char buffer[unz_BUFFSIZ]; - char *head; - size_t numbytes; + typedef std::vector passVector; + typedef std::vector lutVector; + passVector shaderPasses; + lutVector lookupTextures; }; #endif - -#endif diff --git a/win32/CD3DCG.cpp b/win32/CD3DCG.cpp new file mode 100644 index 00000000..1d51dc24 --- /dev/null +++ b/win32/CD3DCG.cpp @@ -0,0 +1,840 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ +#include "CD3DCG.h" +#include "wsnes9x.h" +#include "win32_display.h" +#include +#include +#include "CDirect3D.h" + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static float npot(float desired) +{ + float out=512.0; + while(outcgContext = cgContext; + this->pDevice = pDevice; + ClearPasses(); + frameCnt=0; +} + +CD3DCG::~CD3DCG(void) +{ + LoadShader(NULL); +} + +void CD3DCG::ClearPasses() +{ + /* clean up cg programs, vertex buffers/declarations and textures + from all regular passes. pass 0 is the orignal texture, so ignore that + */ + if(shaderPasses.size()>1) { + for(std::vector::iterator it=(shaderPasses.begin()+1);it!=shaderPasses.end();it++) { + if(it->cgFragmentProgram) + cgDestroyProgram(it->cgFragmentProgram); + if(it->cgVertexProgram) + cgDestroyProgram(it->cgVertexProgram); + if(it->tex) + it->tex->Release(); + if(it->vertexBuffer) + it->vertexBuffer->Release(); + if(it->vertexDeclaration) + it->vertexDeclaration->Release(); + } + } + for(std::vector::iterator it=lookupTextures.begin();it!=lookupTextures.end();it++) { + if(it->tex) + it->tex->Release(); + } + for(std::deque::iterator it=prevPasses.begin();it!=prevPasses.end();it++) { + if(it->tex) + it->tex->Release(); + if(it->vertexBuffer) + it->vertexBuffer->Release(); + } + prevPasses.clear(); + shaderPasses.clear(); + lookupTextures.clear(); + // prevPasses deque is always filled with PREV + PREV1-6 elements + prevPasses.resize(7); + shaderLoaded = false; +} + +void CD3DCG::OnLostDevice() +{ + /* release all non-managed textures so the device can reset - + will be recreated when required + */ + if(shaderPasses.size()>1) { + for(std::vector::iterator it=(shaderPasses.begin()+1);it!=shaderPasses.end();it++) { + if(it->tex) { + it->tex->Release(); + it->tex = NULL; + } + } + } +} + +void CD3DCG::OnResetDevice() +{ + +} + +void CD3DCG::checkForCgError(const char *situation) +{ + char buffer[4096]; + CGerror error = cgGetError(); + const char *string = cgGetErrorString(error); + + if (error != CG_NO_ERROR) { + sprintf(buffer, + "Situation: %s\n" + "Error: %s\n\n" + "Cg compiler output...\n", situation, string); + MessageBoxA(0, buffer, + "Cg error", MB_OK|MB_ICONEXCLAMATION); + if (error == CG_COMPILER_ERROR) { + MessageBoxA(0, cgGetLastListing(cgContext), + "Cg compilation error", MB_OK|MB_ICONEXCLAMATION); + } + } +} + +#define IS_SLASH(x) ((x) == TEXT('\\') || (x) == TEXT('/')) + +bool CD3DCG::LoadShader(const TCHAR *shaderFile) +{ + CCGShader cgShader; + TCHAR shaderPath[MAX_PATH]; + TCHAR tempPath[MAX_PATH]; + HRESULT hr; + GLenum error; + + ClearPasses(); + + if (shaderFile == NULL || *shaderFile==TEXT('\0')) + return true; + + lstrcpy(shaderPath,shaderFile); + for(int i=lstrlen(shaderPath); i>=0; i--){ + if(IS_SLASH(shaderPath[i])){ + shaderPath[i]=TEXT('\0'); + break; + } + } + + SetCurrentDirectory(shaderPath); + if(!cgShader.LoadShader(_tToChar(shaderFile))) + return false; + + CGprofile vertexProfile = cgD3D9GetLatestVertexProfile(); + CGprofile pixelProfile = cgD3D9GetLatestPixelProfile(); + + const char** vertexOptions = cgD3D9GetOptimalOptions(vertexProfile); + const char** pixelOptions = cgD3D9GetOptimalOptions(pixelProfile); + + shaderPasses.push_back(shaderPass()); + + for(CCGShader::passVector::iterator it=cgShader.shaderPasses.begin(); + it!=cgShader.shaderPasses.end();it++) { + shaderPass pass; + + pass.scaleParams = it->scaleParams; + /* if this is the last pass (the only one that can have CG_SCALE_NONE) + and no filter has been set use the GUI setting + */ + if(pass.scaleParams.scaleTypeX==CG_SCALE_NONE && !it->filterSet) { + pass.linearFilter = GUI.BilinearFilter; + } else { + pass.linearFilter = it->linearFilter; + } + + // paths in the meta file can be relative + _tfullpath(tempPath,_tFromChar(it->cgShaderFile),MAX_PATH); + char *fileContents = ReadShaderFileContents(tempPath); + if(!fileContents) + return false; + + pass.cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + vertexProfile, "main_vertex", vertexOptions); + + checkForCgError("Compiling vertex program"); + + pass.cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + pixelProfile, "main_fragment", pixelOptions); + + checkForCgError("Compiling fragment program"); + + delete [] fileContents; + if(!pass.cgVertexProgram || !pass.cgFragmentProgram) { + return false; + } + if(pass.cgVertexProgram) { + hr = cgD3D9LoadProgram(pass.cgVertexProgram,false,0); + } + checkForCgError("Loading vertex program"); + if(pass.cgFragmentProgram) { + hr = cgD3D9LoadProgram(pass.cgFragmentProgram,false,0); + } + checkForCgError("Loading fragment program"); + + /* generate vertex buffer + */ + + hr = pDevice->CreateVertexBuffer(sizeof(VERTEX)*4,D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&pass.vertexBuffer,NULL); + if(FAILED(hr)) { + pass.vertexBuffer = NULL; + DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex buffer"), hr); + return false; + } + + /* set up vertex declarations for the pass, + this also creates the vertex declaration + */ + setupVertexDeclaration(pass); + + shaderPasses.push_back(pass); + } + + for(std::vector::iterator it=cgShader.lookupTextures.begin();it!=cgShader.lookupTextures.end();it++) { + lookupTexture tex; + strcpy(tex.id,it->id); + tex.linearFilter = it->linearfilter; + + _tfullpath(tempPath,_tFromChar(it->texturePath),MAX_PATH); + + hr = D3DXCreateTextureFromFileEx( + pDevice, + tempPath, + D3DX_DEFAULT_NONPOW2, + D3DX_DEFAULT_NONPOW2, + 0, + 0, + D3DFMT_FROM_FILE, + D3DPOOL_MANAGED, + it->linearfilter?D3DX_FILTER_LINEAR:D3DX_FILTER_POINT, + 0, + 0, + NULL, + NULL, + &tex.tex); + if FAILED(hr){ + tex.tex = NULL; + } + lookupTextures.push_back(tex); + } + + shaderLoaded = true; + + return true; +} + +void CD3DCG::ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, + D3DXVECTOR2 wantedSize,bool renderTarget) +{ + HRESULT hr; + + if(!tex || texSize != wantedSize) { + if(tex) + tex->Release(); + + hr = pDevice->CreateTexture( + wantedSize.x, wantedSize.y, + 1, // 1 level, no mipmaps + renderTarget?D3DUSAGE_RENDERTARGET:0, + renderTarget?D3DFMT_X8R8G8B8:D3DFMT_R5G6B5, + renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, // render targets cannot be managed + &tex, + NULL ); + + texSize = wantedSize; + + if(FAILED(hr)) { + DXTRACE_ERR_MSGBOX(TEXT("Error while creating texture"), hr); + return; + } + } +} + +void CD3DCG::setVertexStream(IDirect3DVertexBuffer9 *vertexBuffer, + D3DXVECTOR2 inputSize,D3DXVECTOR2 textureSize,D3DXVECTOR2 outputSize) +{ + float tX = inputSize.x / textureSize.x; + float tY = inputSize.y / textureSize.y; + VERTEX vertexStream[4]; + + /* vertex is POSITION, TEXCOORD, LUT TEXCOORD + */ + + vertexStream[0] = VERTEX(0.0f,0.0f,0.0f, + 0.0f,tY, + 0.0f,1.0f); + vertexStream[1] = VERTEX(0.0f,1.0f,0.0f, + 0.0f,0.0f, + 0.0f,0.0f); + vertexStream[2] = VERTEX(1.0f,0.0f,0.0f, + tX,tY, + 1.0f,1.0f); + vertexStream[3] = VERTEX(1.0f,1.0f,0.0f, + tX,0.0f, + 1.0f,0.0f); + // offset coordinates to correct pixel/texture alignment + for(int i=0;i<4;i++) { + vertexStream[i].x -= 0.5f / outputSize.x; + vertexStream[i].y += 0.5f / outputSize.y; + } + + void *pLockedVertexBuffer; + HRESULT hr = vertexBuffer->Lock(0,0,&pLockedVertexBuffer,NULL); + memcpy(pLockedVertexBuffer,vertexStream,sizeof(vertexStream)); + vertexBuffer->Unlock(); + + /* set vertex to stream 0-3, for POSITION,TEXCOORD0,TEXCOORD1,COLOR + if stream is used in parameter, this will be set in setShaderVars + */ + pDevice->SetStreamSource(0,vertexBuffer,0,sizeof(VERTEX)); + pDevice->SetStreamSource(1,vertexBuffer,0,sizeof(VERTEX)); + pDevice->SetStreamSource(2,vertexBuffer,0,sizeof(VERTEX)); + pDevice->SetStreamSource(3,vertexBuffer,0,sizeof(VERTEX)); +} + +void CD3DCG::Render(LPDIRECT3DTEXTURE9 &origTex, D3DXVECTOR2 textureSize, + D3DXVECTOR2 inputSize, D3DXVECTOR2 viewportSize, D3DXVECTOR2 windowSize) +{ + LPDIRECT3DSURFACE9 pRenderSurface = NULL,pBackBuffer = NULL; + frameCnt++; + + if(!shaderLoaded) + return; + + /* save back buffer render target + */ + pDevice->GetRenderTarget(0,&pBackBuffer); + + /* pass 0 represents the original texture + */ + shaderPasses[0].tex = origTex; + shaderPasses[0].outputSize = inputSize; + shaderPasses[0].textureSize = textureSize; + + calculateMatrix(); + + for(int i=1;iGetSurfaceLevel(0,&pRenderSurface); + pDevice->SetTexture(0, shaderPasses[i-1].tex); + pDevice->SetRenderTarget(0,pRenderSurface); + pRenderSurface->Release(); + + /* set vertex declaration of current pass, update vertex + buffer and set base streams + */ + pDevice->SetVertexDeclaration(shaderPasses[i].vertexDeclaration); + setVertexStream(shaderPasses[i].vertexBuffer, + shaderPasses[i-1].outputSize,shaderPasses[i-1].textureSize,shaderPasses[i].outputSize); + pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); + pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); + pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, shaderPasses[i].linearFilter?D3DTEXF_LINEAR:D3DTEXF_POINT); + pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, shaderPasses[i].linearFilter?D3DTEXF_LINEAR:D3DTEXF_POINT); + + /* shader vars need to be set after the base vertex streams + have been set so they can override them + */ + setShaderVars(i); + + cgD3D9BindProgram(shaderPasses[i].cgVertexProgram); + checkForCgError("Binding vertex program"); + cgD3D9BindProgram(shaderPasses[i].cgFragmentProgram); + checkForCgError("Binding fragment program"); + + /* viewport defines output size + */ + setViewport(0,0,shaderPasses[i].outputSize.x,shaderPasses[i].outputSize.y); + + pDevice->BeginScene(); + pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); + pDevice->EndScene(); + } + + /* take oldes PREV out of deque, make sure it has + the same size as the current texture and + then set it up as new original texture + */ + prevPass &oldestPrev = prevPasses.back(); + ensureTextureSize(oldestPrev.tex,oldestPrev.textureSize,textureSize,false); + if(oldestPrev.vertexBuffer) + oldestPrev.vertexBuffer->Release(); + origTex = oldestPrev.tex; + prevPasses.pop_back(); + + /* push current original with corresponding vertex + buffer to front of PREV deque + */ + shaderPasses[0].vertexBuffer = shaderPasses[1].vertexBuffer; + prevPasses.push_front(prevPass(shaderPasses[0])); + + /* create new vertex buffer so that next render call + will not overwrite the PREV + */ + pDevice->CreateVertexBuffer(sizeof(VERTEX)*4,D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&shaderPasses[1].vertexBuffer,NULL); + + /* set up last pass texture, backbuffer and viewport + for final display pass without shaders + */ + pDevice->SetTexture(0, shaderPasses.back().tex); + pDevice->SetRenderTarget(0,pBackBuffer); + pBackBuffer->Release(); + RECT displayRect=CalculateDisplayRect(shaderPasses.back().outputSize.x,shaderPasses.back().outputSize.y,windowSize.x,windowSize.y); + setViewport(displayRect.left,displayRect.top,displayRect.right - displayRect.left,displayRect.bottom - displayRect.top); + setVertexStream(shaderPasses.back().vertexBuffer, + shaderPasses.back().outputSize,shaderPasses.back().textureSize, + D3DXVECTOR2(displayRect.right - displayRect.left,displayRect.bottom - displayRect.top)); + pDevice->SetVertexShader(NULL); + pDevice->SetPixelShader(NULL); +} + +void CD3DCG::calculateMatrix() +{ + D3DXMATRIX matWorld; + D3DXMATRIX matView; + D3DXMATRIX matProj; + + pDevice->GetTransform(D3DTS_WORLD,&matWorld); + pDevice->GetTransform(D3DTS_VIEW,&matView); + pDevice->GetTransform(D3DTS_PROJECTION,&matProj); + + mvp = matWorld * matView * matProj; + D3DXMatrixTranspose(&mvp,&mvp); +} + +void CD3DCG::setViewport(DWORD x, DWORD y, DWORD width, DWORD height) +{ + D3DVIEWPORT9 viewport; + viewport.X = x; + viewport.Y = y; + viewport.Height = height; + viewport.Width = width; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; + HRESULT hr = pDevice->SetViewport(&viewport); +} + +void CD3DCG::setShaderVars(int pass) +{ + D3DXVECTOR2 inputSize = shaderPasses[pass-1].outputSize; + D3DXVECTOR2 textureSize = shaderPasses[pass-1].textureSize; + D3DXVECTOR2 outputSize = shaderPasses[pass].outputSize; + + /* mvp paramater + */ + CGparameter cgpModelViewProj = cgGetNamedParameter(shaderPasses[pass].cgVertexProgram, "modelViewProj"); + + if(cgpModelViewProj) + cgD3D9SetUniformMatrix(cgpModelViewProj,&mvp); + +#define setProgramUniform(pass,varname,floats)\ +{\ + CGparameter cgpf = cgGetNamedParameter(shaderPasses[pass].cgFragmentProgram, varname);\ + CGparameter cgpv = cgGetNamedParameter(shaderPasses[pass].cgVertexProgram, varname);\ + if(cgpf)\ + cgD3D9SetUniform(cgpf,floats);\ + if(cgpv)\ + cgD3D9SetUniform(cgpv,floats);\ +}\ + +#define setTextureParameter(pass,varname,val,linear)\ +{\ + CGparameter cgpf = cgGetNamedParameter(shaderPasses[pass].cgFragmentProgram, varname);\ + if(cgpf) {\ + cgD3D9SetTexture(cgpf,val);\ + cgD3D9SetSamplerState(cgpf, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);\ + cgD3D9SetSamplerState(cgpf, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);\ + cgD3D9SetSamplerState(cgpf, D3DSAMP_MINFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);\ + cgD3D9SetSamplerState(cgpf, D3DSAMP_MAGFILTER, linear?D3DTEXF_LINEAR:D3DTEXF_POINT);\ + }\ +}\ + +#define setTexCoordsParameter(pass,varname,val)\ +{\ + CGparameter cgpv = cgGetNamedParameter(shaderPasses[pass].cgVertexProgram, varname);\ + if(cgpv) {\ + unsigned long index = cgGetParameterResourceIndex(cgpv);\ + pDevice->SetStreamSource(shaderPasses[pass].parameterMap[index].streamNumber,val,0,sizeof(VERTEX));\ + }\ +}\ + + /* IN paramater + */ + setProgramUniform(pass,"IN.video_size",&inputSize); + setProgramUniform(pass,"IN.texture_size",&textureSize); + setProgramUniform(pass,"IN.output_size",&outputSize); + setProgramUniform(pass,"IN.frame_count",&frameCnt); + float frameDirection = GUI.rewinding?-1.0f:1.0f; + setProgramUniform(pass,"IN.frame_direction",&frameDirection); + + /* ORIG parameter + */ + setProgramUniform(pass,"ORIG.video_size",shaderPasses[0].outputSize); + setProgramUniform(pass,"ORIG.texture_size",shaderPasses[0].textureSize); + setTextureParameter(pass,"ORIG.texture",shaderPasses[0].tex,shaderPasses[1].linearFilter); + setTexCoordsParameter(pass,"ORIG.tex_coord",shaderPasses[1].vertexBuffer); + + /* PREV parameter + */ + if(prevPasses[0].tex) { + setProgramUniform(pass,"PREV.video_size",prevPasses[0].imageSize); + setProgramUniform(pass,"PREV.texture_size",prevPasses[0].textureSize); + setTextureParameter(pass,"PREV.texture",prevPasses[0].tex,shaderPasses[1].linearFilter); + setTexCoordsParameter(pass,"PREV.tex_coord",prevPasses[0].vertexBuffer); + } + + /* PREV1-6 parameters + */ + for(int i=1;i2) { + for(int i=1;i &map, CGparameter param) +{ + parameterEntry mapEntry; + while (param) { + if(cgGetParameterType(param)==CG_STRUCT) + fillParameterMap(map,cgGetFirstStructParameter(param)); + else + if (cgGetParameterDirection(param) == CG_IN && cgGetParameterVariability(param) == CG_VARYING) { + mapEntry.rIndex = cgGetParameterResourceIndex(param); + mapEntry.semantic = cgGetParameterSemantic(param); + mapEntry.isKnownParam = isKnownParameter(cgGetParameterName(param)); + if(map.size()CreateVertexDeclaration(vElems,&vertexDeclaration); + if(FAILED(hr)) { + DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex declaration"), hr); + } + if(pass.vertexDeclaration) + pass.vertexDeclaration->Release(); + pass.vertexDeclaration = vertexDeclaration; + delete [] vElems; +} diff --git a/win32/CD3DCG.h b/win32/CD3DCG.h new file mode 100644 index 00000000..f46d8aa6 --- /dev/null +++ b/win32/CD3DCG.h @@ -0,0 +1,264 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ +#ifndef CGD3DCG_H +#define CGD3DCG_H + +#include +#include +#include +#include +#include "CCGShader.h" +#include +#include + +class CD3DCG +{ +private: + typedef struct _parameterEntry { + unsigned long rIndex; + const char* semantic; + bool isKnownParam; + UINT streamNumber; + } parameterEntry; + typedef struct _shaderPass { + cgScaleParams scaleParams; + bool linearFilter; + CGprogram cgVertexProgram, cgFragmentProgram; + LPDIRECT3DTEXTURE9 tex; + LPDIRECT3DVERTEXBUFFER9 vertexBuffer; + LPDIRECT3DVERTEXDECLARATION9 vertexDeclaration; + std::vector parameterMap; + + D3DXVECTOR2 outputSize; + D3DXVECTOR2 textureSize; + + _shaderPass() {cgVertexProgram=NULL; + cgFragmentProgram=NULL; + tex=NULL; + vertexBuffer=NULL; + vertexDeclaration=NULL;} + } shaderPass; + typedef struct _prevPass { + LPDIRECT3DTEXTURE9 tex; + LPDIRECT3DVERTEXBUFFER9 vertexBuffer; + D3DXVECTOR2 imageSize; + D3DXVECTOR2 textureSize; + _prevPass() {tex=NULL; + vertexBuffer=NULL;} + _prevPass(const shaderPass &pass) {tex = pass.tex; + vertexBuffer = pass.vertexBuffer; + imageSize = pass.outputSize; + textureSize = pass.textureSize;} + } prevPass; + typedef struct _lookupTexture { + char id[PATH_MAX]; + LPDIRECT3DTEXTURE9 tex; + bool linearFilter; + _lookupTexture() {tex=NULL;} + } lookupTexture; + + std::vector shaderPasses; + std::vector lookupTextures; + std::deque prevPasses; + + bool shaderLoaded; + void checkForCgError(const char *situation); + void setVertexStream(IDirect3DVertexBuffer9 *vertexBuffer,D3DXVECTOR2 inputSize,D3DXVECTOR2 textureSize,D3DXVECTOR2 outputSize); + void setViewport(DWORD x, DWORD y, DWORD width, DWORD height); + void setShaderVars(int pass); + void ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize, D3DXVECTOR2 wantedSize,bool renderTarget); + void fillParameterMap(std::vector &map, CGparameter param); + void setupVertexDeclaration(shaderPass &pass); + void calculateMatrix(); + + LPDIRECT3DDEVICE9 pDevice; + CGcontext cgContext; + float frameCnt; + D3DXMATRIX mvp; + +public: + CD3DCG(CGcontext cgContext,LPDIRECT3DDEVICE9 pDevice); + ~CD3DCG(void); + + bool LoadShader(const TCHAR *shaderFile); + void Render(LPDIRECT3DTEXTURE9 &origTex, D3DXVECTOR2 textureSize, D3DXVECTOR2 inputSize, D3DXVECTOR2 viewportSize, D3DXVECTOR2 windowSize); + void ClearPasses(); + void OnLostDevice(); + void OnResetDevice(); +}; + +#endif diff --git a/win32/CDirect3D.cpp b/win32/CDirect3D.cpp index ed0d819a..2d611cd9 100644 --- a/win32/CDirect3D.cpp +++ b/win32/CDirect3D.cpp @@ -198,6 +198,13 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif +const D3DVERTEXELEMENT9 CDirect3D::vertexElems[4] = { + {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, + {0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, + {0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, + D3DDECL_END() + }; + /* CDirect3D::CDirect3D() sets default values for the variables */ @@ -221,9 +228,11 @@ CDirect3D::CDirect3D() shaderTimer = 1.0f; shaderTimeStart = 0; shaderTimeElapsed = 0; + frameCount = 0; cgContext = NULL; - cgVertexProgram = cgFragmentProgram = NULL; cgAvailable = false; + cgShader = NULL; + vertexDeclaration = NULL; } /* CDirect3D::~CDirect3D() @@ -253,7 +262,7 @@ bool CDirect3D::Initialize(HWND hWnd) return false; } - ZeroMemory(&dPresentParams, sizeof(dPresentParams)); + memset(&dPresentParams, 0, sizeof(dPresentParams)); dPresentParams.hDeviceWindow = hWnd; dPresentParams.Windowed = true; dPresentParams.BackBufferCount = GUI.DoubleBuffered?2:1; @@ -272,12 +281,18 @@ bool CDirect3D::Initialize(HWND hWnd) return false; } - hr = pDevice->CreateVertexBuffer(sizeof(triangleStripVertices),D3DUSAGE_WRITEONLY,FVF_COORDS_TEX,D3DPOOL_MANAGED,&vertexBuffer,NULL); + hr = pDevice->CreateVertexBuffer(sizeof(vertexStream),D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&vertexBuffer,NULL); if(FAILED(hr)) { DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex buffer"), hr); return false; } + hr = pDevice->CreateVertexDeclaration(vertexElems,&vertexDeclaration); + if(FAILED(hr)) { + DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex declaration"), hr); + return false; + } + cgAvailable = loadCgFunctions(); if(cgAvailable) { @@ -286,9 +301,13 @@ bool CDirect3D::Initialize(HWND hWnd) if(FAILED(hr)) { DXTRACE_ERR_MSGBOX(TEXT("Error setting cg device"), hr); } + cgShader = new CD3DCG(cgContext,pDevice); } pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + pDevice->SetRenderState( D3DRS_ZENABLE, FALSE); + pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); + pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); @@ -305,11 +324,14 @@ void CDirect3D::DeInitialize() DestroyDrawSurface(); SetShader(NULL); + if(cgShader) { + delete cgShader; + cgShader = NULL; + } if(cgContext) { cgDestroyContext(cgContext); cgContext = NULL; } - if(cgAvailable) cgD3D9SetDevice(NULL); @@ -318,6 +340,11 @@ void CDirect3D::DeInitialize() vertexBuffer = NULL; } + if(vertexDeclaration) { + vertexDeclaration->Release(); + vertexDeclaration = NULL; + } + if( pDevice ) { pDevice->Release(); pDevice = NULL; @@ -344,7 +371,9 @@ bool CDirect3D::SetShader(const TCHAR *file) SetShaderCG(NULL); SetShaderHLSL(NULL); shader_type = D3D_SHADER_NONE; - if(file!=NULL && lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) { + if(file!=NULL && + (lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) || + (lstrlen(file)>4 && _tcsncicmp(&file[lstrlen(file)-4],TEXT(".cgp"),4)==0)){ return SetShaderCG(file); } else { return SetShaderHLSL(file); @@ -373,79 +402,16 @@ void CDirect3D::checkForCgError(const char *situation) bool CDirect3D::SetShaderCG(const TCHAR *file) { - TCHAR errorMsg[MAX_PATH + 50]; - HRESULT hr; - - if(cgFragmentProgram) { - cgDestroyProgram(cgFragmentProgram); - cgFragmentProgram = NULL; - } - if(cgVertexProgram) { - cgDestroyProgram(cgVertexProgram); - cgVertexProgram = NULL; - } - - if (file == NULL || *file==TEXT('\0')) - return true; - if(!cgAvailable) { - MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"), - MB_OK|MB_ICONEXCLAMATION); + if(file) + MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"), + MB_OK|MB_ICONEXCLAMATION); return false; } - CGprofile vertexProfile = cgD3D9GetLatestVertexProfile(); - CGprofile pixelProfile = cgD3D9GetLatestPixelProfile(); - - const char** vertexOptions = cgD3D9GetOptimalOptions(vertexProfile); - const char** pixelOptions = cgD3D9GetOptimalOptions(pixelProfile); - - char *fileContents = ReadShaderFileContents(file); - if(!fileContents) + if(!cgShader->LoadShader(file)) return false; - cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - vertexProfile, "main_vertex", vertexOptions); - - checkForCgError("Compiling vertex program"); - - cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - pixelProfile, "main_fragment", pixelOptions); - - checkForCgError("Compiling fragment program"); - - delete [] fileContents; - - if(!cgVertexProgram || !cgFragmentProgram) { - return false; - } - - if(cgVertexProgram) { - hr = cgD3D9LoadProgram(cgVertexProgram,true,0); - hr = cgD3D9BindProgram(cgVertexProgram); - - D3DXMATRIX matWorld; - D3DXMATRIX matView; - D3DXMATRIX matProj; - D3DXMATRIX mvp; - - pDevice->GetTransform(D3DTS_WORLD,&matWorld); - pDevice->GetTransform(D3DTS_VIEW,&matView); - pDevice->GetTransform(D3DTS_PROJECTION,&matProj); - - mvp = matWorld * matView * matProj; - D3DXMatrixTranspose(&mvp,&mvp); - - CGparameter cgpModelViewProj = cgGetNamedParameter(cgVertexProgram, "modelViewProj"); - - if(cgpModelViewProj) - cgD3D9SetUniformMatrix(cgpModelViewProj,&mvp); - } - if(cgFragmentProgram) { - hr = cgD3D9LoadProgram(cgFragmentProgram,false,0); - hr = cgD3D9BindProgram(cgFragmentProgram); - } - shader_type = D3D_SHADER_CG; return true; @@ -605,7 +571,7 @@ bool CDirect3D::SetShaderHLSL(const TCHAR *file) return true; } -void CDirect3D::SetShaderVars() +void CDirect3D::SetShaderVars(bool setMatrix) { if(shader_type == D3D_SHADER_HLSL) { D3DXVECTOR4 rubyTextureSize; @@ -645,16 +611,19 @@ void CDirect3D::SetShaderVars() effect->SetTexture( rubyLUTName, rubyLUT[i] ); } } - } else if(shader_type == D3D_SHADER_CG) { + }/* else if(shader_type == D3D_SHADER_CG) { D3DXVECTOR2 videoSize; D3DXVECTOR2 textureSize; D3DXVECTOR2 outputSize; + float frameCnt; videoSize.x = (float)afterRenderWidth; videoSize.y = (float)afterRenderHeight; textureSize.x = textureSize.y = (float)quadTextureSize; outputSize.x = GUI.Stretch?(float)dPresentParams.BackBufferWidth:(float)afterRenderWidth; outputSize.y = GUI.Stretch?(float)dPresentParams.BackBufferHeight:(float)afterRenderHeight; + frameCnt = (float)++frameCount; + videoSize = textureSize; #define setProgramUniform(program,varname,floats)\ {\ @@ -666,11 +635,32 @@ void CDirect3D::SetShaderVars() setProgramUniform(cgFragmentProgram,"IN.video_size",&videoSize); setProgramUniform(cgFragmentProgram,"IN.texture_size",&textureSize); setProgramUniform(cgFragmentProgram,"IN.output_size",&outputSize); + setProgramUniform(cgFragmentProgram,"IN.frame_count",&frameCnt); setProgramUniform(cgVertexProgram,"IN.video_size",&videoSize); setProgramUniform(cgVertexProgram,"IN.texture_size",&textureSize); setProgramUniform(cgVertexProgram,"IN.output_size",&outputSize); - } + setProgramUniform(cgVertexProgram,"IN.frame_count",&frameCnt); + + if(setMatrix) { + D3DXMATRIX matWorld; + D3DXMATRIX matView; + D3DXMATRIX matProj; + D3DXMATRIX mvp; + + pDevice->GetTransform(D3DTS_WORLD,&matWorld); + pDevice->GetTransform(D3DTS_VIEW,&matView); + pDevice->GetTransform(D3DTS_PROJECTION,&matProj); + + mvp = matWorld * matView * matProj; + D3DXMatrixTranspose(&mvp,&mvp); + + CGparameter cgpModelViewProj = cgGetNamedParameter(cgVertexProgram, "modelViewProj"); + + if(cgpModelViewProj) + cgD3D9SetUniformMatrix(cgpModelViewProj,&mvp); + } + }*/ } /* CDirect3D::Render @@ -739,22 +729,16 @@ void CDirect3D::Render(SSurface Src) SetViewport(); } - pDevice->BeginScene(); - pDevice->SetTexture(0, drawSurface); - pDevice->SetFVF(FVF_COORDS_TEX); + pDevice->SetVertexDeclaration(vertexDeclaration); pDevice->SetStreamSource(0,vertexBuffer,0,sizeof(VERTEX)); - SetShaderVars(); - - if(shader_type == D3D_SHADER_CG) { - cgD3D9BindProgram(cgFragmentProgram); - cgD3D9BindProgram(cgVertexProgram); - } - if (shader_type == D3D_SHADER_HLSL) { - UINT passes; + SetShaderVars(); + SetFiltering(); + UINT passes; + pDevice->BeginScene(); hr = effect->Begin(&passes, 0); for(UINT pass = 0; pass < passes; pass++ ) { effect->BeginPass(pass); @@ -762,11 +746,30 @@ void CDirect3D::Render(SSurface Src) effect->EndPass(); } effect->End(); - } else { - pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); - } + pDevice->EndScene(); - pDevice->EndScene(); + } else { + if(shader_type == D3D_SHADER_CG) { + RECT displayRect; + //Get maximum rect respecting AR setting + displayRect=CalculateDisplayRect(dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight, + dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight); + cgShader->Render(drawSurface, + D3DXVECTOR2((float)quadTextureSize, (float)quadTextureSize), + D3DXVECTOR2((float)afterRenderWidth, (float)afterRenderHeight), + D3DXVECTOR2((float)(displayRect.right - displayRect.left), + (float)(displayRect.bottom - displayRect.top)), + D3DXVECTOR2((float)dPresentParams.BackBufferWidth, (float)dPresentParams.BackBufferHeight)); + } + + SetFiltering(); + + pDevice->SetVertexDeclaration(vertexDeclaration); + + pDevice->BeginScene(); + pDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,0,2); + pDevice->EndScene(); + } pDevice->Present(NULL, NULL, NULL, NULL); @@ -870,13 +873,18 @@ void CDirect3D::SetupVertices() float tX = (float)afterRenderWidth / (float)quadTextureSize; float tY = (float)afterRenderHeight / (float)quadTextureSize; - triangleStripVertices[0] = VERTEX(0.0f,0.0f,0.0f,0.0f,tY); - triangleStripVertices[1] = VERTEX(0.0f,1.0f,0.0f,0.0f,0.0f); - triangleStripVertices[2] = VERTEX(1.0f,0.0f,0.0f,tX,tY); - triangleStripVertices[3] = VERTEX(1.0f,1.0f,0.0f,tX,0.0f); + vertexStream[0] = VERTEX(0.0f,0.0f,0.0f,0.0f,tY,0.0f,0.0f); + vertexStream[1] = VERTEX(0.0f,1.0f,0.0f,0.0f,0.0f,0.0f,0.0f); + vertexStream[2] = VERTEX(1.0f,0.0f,0.0f,tX,tY,0.0f,0.0f); + vertexStream[3] = VERTEX(1.0f,1.0f,0.0f,tX,0.0f,0.0f,0.0f); + for(int i=0;i<4;i++) { + vertexStream[i].x -= 0.5f / (float)dPresentParams.BackBufferWidth; + vertexStream[i].y += 0.5f / (float)dPresentParams.BackBufferHeight; + } + HRESULT hr = vertexBuffer->Lock(0,0,&pLockedVertexBuffer,NULL); - memcpy(pLockedVertexBuffer,triangleStripVertices,sizeof(triangleStripVertices)); + memcpy(pLockedVertexBuffer,vertexStream,sizeof(vertexStream)); vertexBuffer->Unlock(); } @@ -891,6 +899,8 @@ void CDirect3D::SetViewport() pDevice->SetTransform(D3DTS_VIEW,&matIdentity); pDevice->SetTransform(D3DTS_PROJECTION,&matProjection); + SetShaderVars(true); + RECT drawRect = CalculateDisplayRect(afterRenderWidth,afterRenderHeight,dPresentParams.BackBufferWidth,dPresentParams.BackBufferHeight); D3DVIEWPORT9 viewport; viewport.X = drawRect.left; @@ -944,6 +954,7 @@ bool CDirect3D::ResetDevice() DestroyDrawSurface(); if(cgAvailable) { + cgShader->OnLostDevice(); cgD3D9SetDevice(NULL); } @@ -981,14 +992,7 @@ bool CDirect3D::ResetDevice() if(cgAvailable) { cgD3D9SetDevice(pDevice); - } - - if(GUI.BilinearFilter) { - pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - } else { - pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); - pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + cgShader->OnResetDevice(); } pDevice->SetRenderState(D3DRS_LIGHTING, FALSE); @@ -1103,3 +1107,14 @@ bool CDirect3D::ApplyDisplayChanges(void) return ChangeRenderSize(0,0); } + +void CDirect3D::SetFiltering() +{ + if(GUI.BilinearFilter) { + pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + } else { + pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + } +} diff --git a/win32/CDirect3D.h b/win32/CDirect3D.h index 92b1a9ae..459184e7 100644 --- a/win32/CDirect3D.h +++ b/win32/CDirect3D.h @@ -185,6 +185,7 @@ #include #include "cgFunctions.h" +#include "CD3DCG.h" #include "render.h" #include "wsnes9x.h" @@ -195,9 +196,10 @@ typedef struct _VERTEX { float x, y, z; float tx, ty; + float lutx, luty; _VERTEX() {} - _VERTEX(float x,float y,float z,float tx,float ty) { - this->x=x;this->y=y;this->z=z;this->tx=tx;this->ty=ty; + _VERTEX(float x,float y,float z,float tx,float ty,float lutx, float luty) { + this->x=x;this->y=y;this->z=z;this->tx=tx;this->ty=ty;this->lutx=lutx;this->luty=luty; } } VERTEX; //our custom vertex with a constuctor for easier assignment @@ -218,18 +220,23 @@ private: unsigned int quadTextureSize; //size of the texture (only multiples of 2) bool fullscreen; //are we currently displaying in fullscreen mode - VERTEX triangleStripVertices[4]; //the 4 vertices that make up our display rectangle + VERTEX vertexStream[4]; //the 4 vertices that make up our display rectangle + + static const D3DVERTEXELEMENT9 vertexElems[4]; + LPDIRECT3DVERTEXDECLARATION9 vertexDeclaration; LPD3DXEFFECT effect; LPDIRECT3DTEXTURE9 rubyLUT[MAX_SHADER_TEXTURES]; CGcontext cgContext; - CGprogram cgVertexProgram, cgFragmentProgram; current_d3d_shader_type shader_type; bool cgAvailable; + CD3DCG *cgShader; + float shaderTimer; int shaderTimeStart; int shaderTimeElapsed; + int frameCount; bool BlankTexture(LPDIRECT3DTEXTURE9 texture); void CreateDrawSurface(); @@ -238,7 +245,8 @@ private: void SetViewport(); void SetupVertices(); bool ResetDevice(); - void SetShaderVars(); + void SetFiltering(); + void SetShaderVars(bool setMatrix = false); bool SetShader(const TCHAR *file); bool SetShaderHLSL(const TCHAR *file); void checkForCgError(const char *situation); diff --git a/win32/CDirectDraw.cpp b/win32/CDirectDraw.cpp index 4943a226..99f5efbd 100644 --- a/win32/CDirectDraw.cpp +++ b/win32/CDirectDraw.cpp @@ -554,7 +554,7 @@ void CDirectDraw::Render(SSurface Src) if(!dDinitialized) return; - ZeroMemory(&caps,sizeof(DDSCAPS)); + memset(&caps, 0,sizeof(DDSCAPS)); caps.dwCaps = DDSCAPS_BACKBUFFER; if (lpDDSPrimary2->GetAttachedSurface (&caps, &pDDSurface) != DD_OK || @@ -676,7 +676,7 @@ void CDirectDraw::Render(SSurface Src) lpDDSurface2->Unlock (Dst.Surface); - ZeroMemory(&caps,sizeof(DDSCAPS)); + memset(&caps, 0,sizeof(DDSCAPS)); caps.dwCaps = DDSCAPS_BACKBUFFER; if (lpDDSPrimary2->GetAttachedSurface (&caps, &pDDSurface) != DD_OK || diff --git a/win32/CDirectSound.cpp b/win32/CDirectSound.cpp index 8dc6c948..bd640a92 100644 --- a/win32/CDirectSound.cpp +++ b/win32/CDirectSound.cpp @@ -489,7 +489,8 @@ void CDirectSound::MixSound() S9xMixSamples(B2,(Settings.SixteenBitSound?S2>>1:S2)); } LeaveCriticalSection(&GUI.SoundCritSect); - + + SetEvent(GUI.SoundSyncEvent); hResult = lpDSB -> Unlock (B1, S1, B2, S2); if (!SUCCEEDED(hResult)) diff --git a/win32/CFMOD.cpp b/win32/CFMOD.cpp index 2c2c9a14..ffd93daf 100644 --- a/win32/CFMOD.cpp +++ b/win32/CFMOD.cpp @@ -357,6 +357,8 @@ F_CALLBACKAPI CFMOD::FMODStreamCallback (FSOUND_STREAM *stream, void *buff, int LeaveCriticalSection(&GUI.SoundCritSect); + SetEvent(GUI.SoundSyncEvent); + #if defined (FSOUND_LOADRAW) @@ -364,4 +366,4 @@ F_CALLBACKAPI CFMOD::FMODStreamCallback (FSOUND_STREAM *stream, void *buff, int #endif } -#endif \ No newline at end of file +#endif diff --git a/win32/CFMODEx.cpp b/win32/CFMODEx.cpp index 09f9035e..b5a6b4d9 100644 --- a/win32/CFMODEx.cpp +++ b/win32/CFMODEx.cpp @@ -135,7 +135,9 @@ FMOD_RESULT F_CALLBACK CFMODEx::FMODExStreamCallback( LeaveCriticalSection(&GUI.SoundCritSect); + SetEvent(GUI.SoundSyncEvent); + return FMOD_OK; } #endif -#endif \ No newline at end of file +#endif diff --git a/win32/CGLCG.cpp b/win32/CGLCG.cpp new file mode 100644 index 00000000..182314d2 --- /dev/null +++ b/win32/CGLCG.cpp @@ -0,0 +1,931 @@ +/*********************************************************************************** + Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + + (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com), + Jerremy Koot (jkoot@snes9x.com) + + (c) Copyright 2002 - 2004 Matthew Kendora + + (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org) + + (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/) + + (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net) + + (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca), + Kris Bleakley (codeviolation@hotmail.com) + + (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), + Nach (n-a-c-h@users.sourceforge.net), + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2006 - 2007 nitsuja + + (c) Copyright 2009 - 2011 BearOso, + OV2 + + + BS-X C emulator code + (c) Copyright 2005 - 2006 Dreamer Nom, + zones + + C4 x86 assembler and some C emulation code + (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com), + Nach, + zsKnight (zsknight@zsnes.com) + + C4 C++ code + (c) Copyright 2003 - 2006 Brad Jorsch, + Nach + + DSP-1 emulator code + (c) Copyright 1998 - 2006 _Demo_, + Andreas Naive (andreasnaive@gmail.com), + Gary Henderson, + Ivar (ivar@snes9x.com), + John Weidman, + Kris Bleakley, + Matthew Kendora, + Nach, + neviksti (neviksti@hotmail.com) + + DSP-2 emulator code + (c) Copyright 2003 John Weidman, + Kris Bleakley, + Lord Nightmare (lord_nightmare@users.sourceforge.net), + Matthew Kendora, + neviksti + + DSP-3 emulator code + (c) Copyright 2003 - 2006 John Weidman, + Kris Bleakley, + Lancer, + z80 gaiden + + DSP-4 emulator code + (c) Copyright 2004 - 2006 Dreamer Nom, + John Weidman, + Kris Bleakley, + Nach, + z80 gaiden + + OBC1 emulator code + (c) Copyright 2001 - 2004 zsKnight, + pagefault (pagefault@zsnes.com), + Kris Bleakley + Ported from x86 assembler to C by sanmaiwashi + + SPC7110 and RTC C++ emulator code used in 1.39-1.51 + (c) Copyright 2002 Matthew Kendora with research by + zsKnight, + John Weidman, + Dark Force + + SPC7110 and RTC C++ emulator code used in 1.52+ + (c) Copyright 2009 byuu, + neviksti + + S-DD1 C emulator code + (c) Copyright 2003 Brad Jorsch with research by + Andreas Naive, + John Weidman + + S-RTC C emulator code + (c) Copyright 2001 - 2006 byuu, + John Weidman + + ST010 C++ emulator code + (c) Copyright 2003 Feather, + John Weidman, + Kris Bleakley, + Matthew Kendora + + Super FX x86 assembler emulator code + (c) Copyright 1998 - 2003 _Demo_, + pagefault, + zsKnight + + Super FX C emulator code + (c) Copyright 1997 - 1999 Ivar, + Gary Henderson, + John Weidman + + Sound emulator code used in 1.5-1.51 + (c) Copyright 1998 - 2003 Brad Martin + (c) Copyright 1998 - 2006 Charles Bilyue' + + Sound emulator code used in 1.52+ + (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + + SH assembler code partly based on x86 assembler code + (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) + + 2xSaI filter + (c) Copyright 1999 - 2001 Derek Liauw Kie Fa + + HQ2x, HQ3x, HQ4x filters + (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com) + + NTSC filter + (c) Copyright 2006 - 2007 Shay Green + + GTK+ GUI code + (c) Copyright 2004 - 2011 BearOso + + Win32 GUI code + (c) Copyright 2003 - 2006 blip, + funkyass, + Matthew Kendora, + Nach, + nitsuja + (c) Copyright 2009 - 2011 OV2 + + Mac OS GUI code + (c) Copyright 1998 - 2001 John Stiles + (c) Copyright 2001 - 2011 zones + + + Specific ports contains the works of other authors. See headers in + individual files. + + + Snes9x homepage: http://www.snes9x.com/ + + Permission to use, copy, modify and/or distribute Snes9x in both binary + and source form, for non-commercial purposes, is hereby granted without + fee, providing that this license information and copyright notice appear + with all copies and any derived work. + + This software is provided 'as-is', without any express or implied + warranty. In no event shall the authors be held liable for any damages + arising from the use of this software or it's derivatives. + + Snes9x is freeware for PERSONAL USE only. Commercial users should + seek permission of the copyright holders first. Commercial use includes, + but is not limited to, charging money for Snes9x or software derived from + Snes9x, including Snes9x or derivatives in commercial game bundles, and/or + using Snes9x as a promotion for your commercial product. + + The copyright holders request that bug fixes and improvements to the code + should be forwarded to them so everyone can benefit from the modifications + in future versions. + + Super NES and Super Nintendo Entertainment System are trademarks of + Nintendo Co., Limited and its subsidiary companies. + ***********************************************************************************/ +#include "CGLCG.h" +#include "wsnes9x.h" +#include "win32_display.h" +#include + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static float npot(float desired) +{ + float out=512.0; + while(outcgContext = cgContext; + fboFunctionsLoaded = FALSE; + ClearPasses(); + LoadFBOFunctions(); + frameCnt=0; +} + +CGLCG::~CGLCG(void) +{ + LoadShader(NULL); +} + +void CGLCG::ClearPasses() +{ + /* clean up cg programs, fbos and textures from all regular passes + pass 0 is the orignal texture, so ignore that + */ + if(shaderPasses.size()>1) { + for(glPassVector::iterator it=(shaderPasses.begin()+1);it!=shaderPasses.end();it++) { + if(it->cgFragmentProgram) + cgDestroyProgram(it->cgFragmentProgram); + if(it->cgVertexProgram) + cgDestroyProgram(it->cgVertexProgram); + if(it->fbo) + glDeleteFramebuffers(1,&it->fbo); + if(it->tex) + glDeleteTextures(1,&it->tex); + } + } + for(glLutVector::iterator it=lookupTextures.begin();it!=lookupTextures.end();it++) { + if(it->tex) + glDeleteTextures(1,&it->tex); + } + for(glPrevDeque::iterator it=prevPasses.begin();it!=prevPasses.end();it++) { + if(it->tex) + glDeleteTextures(1,&it->tex); + } + shaderPasses.clear(); + lookupTextures.clear(); + prevPasses.clear(); + // prevPasses deque is always filled with PREV + PREV1-6 elements + prevPasses.resize(7); + + shaderLoaded = false; +} + +bool CGLCG::LoadFBOFunctions() +{ + if(fboFunctionsLoaded) + return true; + + const char *extensions = (const char *) glGetString(GL_EXTENSIONS); + + if(extensions && strstr(extensions, "framebuffer_object")) { + glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress("glGenFramebuffers"); + glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress("glDeleteFramebuffers"); + glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebuffer"); + glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress("glFramebufferTexture2D"); + glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress("glCheckFramebufferStatus"); + glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glClientActiveTexture"); + + if(glGenFramebuffers && glDeleteFramebuffers && glBindFramebuffer && glFramebufferTexture2D && glClientActiveTexture) { + fboFunctionsLoaded = true; + } + + } + return fboFunctionsLoaded; +} + +void CGLCG::checkForCgError(const char *situation) +{ + char buffer[4096]; + CGerror error = cgGetError(); + const char *string = cgGetErrorString(error); + + if (error != CG_NO_ERROR) { + sprintf(buffer, + "Situation: %s\n" + "Error: %s\n\n" + "Cg compiler output...\n", situation, string); + MessageBoxA(0, buffer, + "Cg error", MB_OK|MB_ICONEXCLAMATION); + if (error == CG_COMPILER_ERROR) { + MessageBoxA(0, cgGetLastListing(cgContext), + "Cg compilation error", MB_OK|MB_ICONEXCLAMATION); + } + } +} + +#define IS_SLASH(x) ((x) == TEXT('\\') || (x) == TEXT('/')) + +bool CGLCG::LoadShader(const TCHAR *shaderFile) +{ + CCGShader cgShader; + TCHAR shaderPath[MAX_PATH]; + TCHAR tempPath[MAX_PATH]; + CGprofile vertexProfile, fragmentProfile; + GLenum error; + + if(!fboFunctionsLoaded) { + MessageBox(NULL, TEXT("Your OpenGL graphics driver does not support framebuffer objects.\nYou will not be able to use CG shaders in OpenGL mode."), TEXT("CG Error"), + MB_OK|MB_ICONEXCLAMATION); + return false; + } + + vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); + fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); + + cgGLDisableProfile(vertexProfile); + cgGLDisableProfile(fragmentProfile); + + ClearPasses(); + + if (shaderFile == NULL || *shaderFile==TEXT('\0')) + return true; + + lstrcpy(shaderPath,shaderFile); + for(int i=lstrlen(shaderPath); i>=0; i--){ + if(IS_SLASH(shaderPath[i])){ + shaderPath[i]=TEXT('\0'); + break; + } + } + + SetCurrentDirectory(shaderPath); + if(!cgShader.LoadShader(_tToChar(shaderFile))) + return false; + + cgGLSetOptimalOptions(vertexProfile); + cgGLSetOptimalOptions(fragmentProfile); + + /* insert dummy pass that will contain the original texture + */ + shaderPasses.push_back(shaderPass()); + + for(CCGShader::passVector::iterator it=cgShader.shaderPasses.begin(); + it!=cgShader.shaderPasses.end();it++) { + shaderPass pass; + + pass.scaleParams = it->scaleParams; + /* if this is the last pass (the only one that can have CG_SCALE_NONE) + and no filter has been set use the GUI setting + */ + if(pass.scaleParams.scaleTypeX==CG_SCALE_NONE && !it->filterSet) { + pass.linearFilter = GUI.BilinearFilter; + } else { + pass.linearFilter = it->linearFilter; + } + + // paths in the meta file can be relative + _tfullpath(tempPath,_tFromChar(it->cgShaderFile),MAX_PATH); + char *fileContents = ReadShaderFileContents(tempPath); + if(!fileContents) + return false; + + pass.cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + vertexProfile, "main_vertex", NULL); + + checkForCgError("Compiling vertex program"); + + pass.cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, + fragmentProfile, "main_fragment", NULL); + + checkForCgError("Compiling fragment program"); + + delete [] fileContents; + if(!pass.cgVertexProgram || !pass.cgFragmentProgram) { + return false; + } + cgGLLoadProgram(pass.cgVertexProgram); + cgGLLoadProgram(pass.cgFragmentProgram); + + /* generate framebuffer and texture for this pass and apply + default texture settings + */ + glGenFramebuffers(1,&pass.fbo); + glGenTextures(1,&pass.tex); + glBindTexture(GL_TEXTURE_2D,pass.tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + shaderPasses.push_back(pass); + } + + for(std::vector::iterator it=cgShader.lookupTextures.begin();it!=cgShader.lookupTextures.end();it++) { + lookupTexture tex; + strcpy(tex.id,it->id); + + /* generate texture for the lut and apply specified filter setting + */ + glGenTextures(1,&tex.tex); + glBindTexture(GL_TEXTURE_2D,tex.tex); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, it->linearfilter?GL_LINEAR:GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, it->linearfilter?GL_LINEAR:GL_NEAREST); + + _tfullpath(tempPath,_tFromChar(it->texturePath),MAX_PATH); + + // simple file extension png/tga decision + int strLen = strlen(it->texturePath); + if(strLen>4) { + if(!strcasecmp(&it->texturePath[strLen-4],".png")) { + int width, height; + bool hasAlpha; + GLubyte *texData; + if(loadPngImage(tempPath,width,height,hasAlpha,&texData)) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + glTexImage2D(GL_TEXTURE_2D, 0, hasAlpha ? 4 : 3, width, + height, 0, hasAlpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, texData); + free(texData); + } + } else if(!strcasecmp(&it->texturePath[strLen-4],".tga")) { + STGA stga; + if(loadTGA(tempPath,stga)) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stga.width); + glTexImage2D(GL_TEXTURE_2D, 0, 4, stga.width, + stga.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, stga.data); + } + } + } + lookupTextures.push_back(tex); + } + + /* enable texture unit 1 for the lookup textures + */ + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2,GL_FLOAT,0,lut_coords); + glClientActiveTexture(GL_TEXTURE0); + + /* generate textures and set default values for the pref-filled PREV deque. + */ + for(int i=0;i0) { + float prev_videoSize[2] = {prevPasses[0].videoSize.x,prevPasses[0].videoSize.y}; + float prev_textureSize[2] = {prevPasses[0].textureSize.x,prevPasses[0].textureSize.y}; + + setProgram2fv(pass,"PREV.video_size",prev_videoSize); + setProgram2fv(pass,"PREV.texture_size",prev_textureSize); + setTextureParameter(pass,"PREV.texture",prevPasses[0].tex); + setTexCoordsParameter(pass,"PREV.tex_coord",prevPasses[0].texCoords); + } + + /* PREV1-6 parameters + */ + for(int i=1;i2) { + for(int i=1;i +#include +#include "glext.h" +#include "cgFunctions.h" +#include "CCGShader.h" +#include +#include -// Abstract the details of reading from zip files versus FILE *'s. +typedef struct _xySize { + double x; + double y; + operator CONST FLOAT* () const; +} xySize; -#include -#ifdef UNZIP_SUPPORT -#include "unzip.h" -#endif -#include "snes9x.h" -#include "reader.h" - - -// Generic constructor/destructor - -Reader::Reader (void) +class CGLCG { - return; -} +private: + typedef struct _STGA { + _STGA() {data = (unsigned char*)0; + width = 0; + height = 0; + byteCount = 0;} -Reader::~Reader (void) -{ - return; -} + ~_STGA() { delete[] data; data = 0; } -// Generic getline function, based on gets. Reimlpement if you can do better. + void destroy() { delete[] data; data = 0; } -char * Reader::getline (void) -{ - bool eof; - std::string ret; + int width; + int height; + unsigned char byteCount; + unsigned char* data; + } STGA; + typedef struct _shaderPass { + cgScaleParams scaleParams; + bool linearFilter; + CGprogram cgVertexProgram, cgFragmentProgram; + GLuint tex; + GLuint fbo; + xySize outputSize; + xySize textureSize; + GLfloat texcoords[8]; + _shaderPass() {cgVertexProgram=NULL; + cgFragmentProgram=NULL; + fbo=NULL; + tex=NULL;} + } shaderPass; + typedef struct _prevPass { + GLuint tex; + xySize videoSize; + xySize textureSize; + GLfloat texCoords[8]; + _prevPass() {tex=0;} + } prevPass; + typedef struct _lookupTexture { + char id[PATH_MAX]; + GLuint tex; + _lookupTexture() {tex=NULL;} + } lookupTexture; - ret = getline(eof); - if (ret.size() == 0 && eof) - return (NULL); + typedef std::vector glPassVector; + typedef std::vector glLutVector; + typedef std::deque glPrevDeque; + typedef std::vector glAttribParams; + glPassVector shaderPasses; + glLutVector lookupTextures; + glPrevDeque prevPasses; + glAttribParams cgAttribParams; - return (strdup(ret.c_str())); -} + bool fboFunctionsLoaded; + bool shaderLoaded; + bool LoadFBOFunctions(); + void checkForCgError(const char *situation); + void setTexCoords(int pass,xySize inputSize,xySize textureSize,bool topdown=false); + void setShaderVars(int pass); + void resetAttribParams(); + bool loadPngImage(const TCHAR *name, int &outWidth, int &outHeight, bool &outHasAlpha, GLubyte **outData); + bool loadTGA(const TCHAR *filename, STGA& tgaFile); -std::string Reader::getline (bool &eof) -{ - char buf[1024]; - std::string ret; + CGcontext cgContext; + int frameCnt; + static const GLfloat lut_coords[8]; - eof = false; - ret.clear(); - do - { - if (gets(buf, sizeof(buf)) == NULL) - { - eof = true; - break; - } + PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; + PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; + PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; + PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; + PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; + PFNGLACTIVETEXTUREPROC glClientActiveTexture; - ret.append(buf); - } - while (*ret.rbegin() != '\n'); +public: + CGLCG(CGcontext cgContext); + ~CGLCG(void); - return (ret); -} - -// snes9x.h STREAM reader - -fReader::fReader (STREAM f) -{ - fp = f; -} - -fReader::~fReader (void) -{ - return; -} - -int fReader::get_char (void) -{ - return (GETC_STREAM(fp)); -} - -char * fReader::gets (char *buf, size_t len) -{ - return (GETS_STREAM(buf, len, fp)); -} - -size_t fReader::read (char *buf, size_t len) -{ - return (READ_STREAM(buf, len, fp)); -} - -// unzip reader - -#ifdef UNZIP_SUPPORT - -unzReader::unzReader (unzFile &v) -{ - file = v; - head = NULL; - numbytes = 0; -} - -unzReader::~unzReader (void) -{ - return; -} - -int unzReader::get_char (void) -{ - unsigned char c; - - if (numbytes <= 0) - { - numbytes = unzReadCurrentFile(file, buffer, unz_BUFFSIZ); - if (numbytes <= 0) - return (EOF); - head = buffer; - } - - c = *head; - head++; - numbytes--; - - return ((int) c); -} - -char * unzReader::gets (char *buf, size_t len) -{ - size_t i; - int c; - - for (i = 0; i < len - 1; i++) - { - c = get_char(); - if (c == EOF) - { - if (i == 0) - return (NULL); - break; - } - - buf[i] = (char) c; - if (buf[i] == '\n') - break; - } - - buf[i] = '\0'; - - return (buf); -} - -size_t unzReader::read (char *buf, size_t len) -{ - if (len == 0) - return (len); - - if (len <= numbytes) - { - memcpy(buf, head, len); - numbytes -= len; - head += len; - return (len); - } - - size_t numread = 0; - if (numbytes > 0) - { - memcpy(buf, head, numbytes); - numread += numbytes; - head = NULL; - numbytes = 0; - } - - int l = unzReadCurrentFile(file, buf + numread, len - numread); - if (l > 0) - numread += l; - - return (numread); -} + bool LoadShader(const TCHAR *shaderFile); + void Render(GLuint &origTex, xySize textureSize, xySize inputSize, xySize viewportSize, xySize windowSize); + void ClearPasses(); +}; #endif diff --git a/win32/COpenGL.cpp b/win32/COpenGL.cpp index 4775cbca..04557484 100644 --- a/win32/COpenGL.cpp +++ b/win32/COpenGL.cpp @@ -210,6 +210,8 @@ COpenGL::COpenGL(void) cgContext = NULL; cgVertexProgram = cgFragmentProgram = NULL; cgAvailable = false; + frameCount = 0; + cgShader = NULL; } COpenGL::~COpenGL(void) @@ -284,10 +286,10 @@ bool COpenGL::Initialize(HWND hWnd) cgAvailable = loadCgFunctions(); if(cgAvailable) { cgContext = cgCreateContext(); + cgShader = new CGLCG(cgContext); } - GetClientRect(hWnd,&windowRect); - ChangeRenderSize(windowRect.right,windowRect.bottom); + ApplyDisplayChanges(); glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClear(GL_COLOR_BUFFER_BIT); @@ -319,6 +321,10 @@ void COpenGL::DeInitialize() afterRenderHeight = 0; shaderFunctionsLoaded = false; shader_type = OGL_SHADER_NONE; + if(cgShader) { + delete cgShader; + cgShader = NULL; + } if(cgAvailable) unloadCgLibrary(); cgAvailable = false; @@ -343,6 +349,7 @@ void COpenGL::CreateDrawSurface() glGenBuffers(1,&drawBuffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER,drawBuffer); glBufferData(GL_PIXEL_UNPACK_BUFFER,quadTextureSize*quadTextureSize*2,NULL,GL_STREAM_DRAW); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER,0); } else { noPboBuffer = new BYTE[quadTextureSize*quadTextureSize*2]; } @@ -350,7 +357,6 @@ void COpenGL::CreateDrawSurface() glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); } - ApplyDisplayChanges(); } void COpenGL::DestroyDrawSurface() @@ -401,6 +407,7 @@ void COpenGL::SetupVertices() texcoords[5] = 0.0f; texcoords[6] = 0.0f; texcoords[7] = 0.0f; + glTexCoordPointer(2, GL_FLOAT, 0, texcoords); } void COpenGL::Render(SSurface Src) @@ -420,6 +427,7 @@ void COpenGL::Render(SSurface Src) } if(pboFunctionsLoaded) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, drawBuffer); Dst.Surface = (unsigned char *)glMapBuffer(GL_PIXEL_UNPACK_BUFFER,GL_WRITE_ONLY); } else { Dst.Surface = noPboBuffer; @@ -440,20 +448,29 @@ void COpenGL::Render(SSurface Src) if(afterRenderHeight != dstRect.bottom || afterRenderWidth != dstRect.right) { afterRenderHeight = dstRect.bottom; afterRenderWidth = dstRect.right; - ApplyDisplayChanges(); + + ChangeRenderSize(0,0); } - if (shader_type != OGL_SHADER_NONE) { - GLint location; + glBindTexture(GL_TEXTURE_2D,drawTexture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, quadTextureSize); + glTexSubImage2D (GL_TEXTURE_2D,0,0,0,dstRect.right-dstRect.left,dstRect.bottom-dstRect.top,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,pboFunctionsLoaded?0:noPboBuffer); - float inputSize[2] = { (float)afterRenderWidth, (float)afterRenderHeight }; - RECT windowSize; - GetClientRect(hWnd,&windowSize); - float outputSize[2] = {(float)(GUI.Stretch?windowSize.right:afterRenderWidth), - (float)(GUI.Stretch?windowSize.bottom:afterRenderHeight) }; - float textureSize[2] = { (float)quadTextureSize, (float)quadTextureSize }; + if(pboFunctionsLoaded) + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + if (shader_type != OGL_SHADER_NONE) { if(shader_type == OGL_SHADER_GLSL) { + GLint location; + + float inputSize[2] = { (float)afterRenderWidth, (float)afterRenderHeight }; + RECT windowSize; + GetClientRect(hWnd,&windowSize); + float outputSize[2] = {(float)(GUI.Stretch?windowSize.right:afterRenderWidth), + (float)(GUI.Stretch?windowSize.bottom:afterRenderHeight) }; + float textureSize[2] = { (float)quadTextureSize, (float)quadTextureSize }; + float frameCnt = (float)++frameCount; location = glGetUniformLocation (shaderProgram, "rubyInputSize"); glUniform2fv (location, 1, inputSize); @@ -463,28 +480,26 @@ void COpenGL::Render(SSurface Src) location = glGetUniformLocation (shaderProgram, "rubyTextureSize"); glUniform2fv (location, 1, textureSize); } else if(shader_type == OGL_SHADER_CG) { - CGparameter cgpModelViewProj = cgGetNamedParameter(cgVertexProgram, "modelViewProj"); - - cgGLSetStateMatrixParameter(cgpModelViewProj, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); - -#define setProgram2fv(program,varname,floats)\ -{\ - CGparameter cgp = cgGetNamedParameter(program, varname);\ - if(cgp)\ - cgGLSetParameter2fv(cgp,floats);\ -}\ - - setProgram2fv(cgFragmentProgram,"IN.video_size",inputSize); - setProgram2fv(cgFragmentProgram,"IN.texture_size",textureSize); - setProgram2fv(cgFragmentProgram,"IN.output_size",outputSize); - setProgram2fv(cgVertexProgram,"IN.video_size",inputSize); - setProgram2fv(cgVertexProgram,"IN.texture_size",textureSize); - setProgram2fv(cgVertexProgram,"IN.output_size",outputSize); + xySize inputSize = { (float)afterRenderWidth, (float)afterRenderHeight }; + RECT windowSize, displayRect; + GetClientRect(hWnd,&windowSize); + xySize xywindowSize = { (double)windowSize.right, (double)windowSize.bottom }; + //Get maximum rect respecting AR setting + displayRect=CalculateDisplayRect(windowSize.right,windowSize.bottom,windowSize.right,windowSize.bottom); + xySize viewportSize = { (double)(displayRect.right - displayRect.left), + (double)(displayRect.bottom - displayRect.top) }; + xySize textureSize = { (double)quadTextureSize, (double)quadTextureSize }; + cgShader->Render(drawTexture, textureSize, inputSize, viewportSize, xywindowSize); } } - glPixelStorei(GL_UNPACK_ROW_LENGTH, quadTextureSize); - glTexSubImage2D (GL_TEXTURE_2D,0,0,0,dstRect.right-dstRect.left,dstRect.bottom-dstRect.top,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,pboFunctionsLoaded?0:noPboBuffer); + if(GUI.BilinearFilter) { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } glClearColor(0.0f, 0.0f, 0.0f, 0.5f); glClear(GL_COLOR_BUFFER_BIT); @@ -496,7 +511,13 @@ void COpenGL::Render(SSurface Src) bool COpenGL::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) { - RECT displayRect=CalculateDisplayRect(afterRenderWidth,afterRenderHeight,newWidth,newHeight); + RECT displayRect, windowSize; + if(newWidth==0||newHeight==0) { + GetClientRect(hWnd,&windowSize); + newWidth = windowSize.right; + newHeight = windowSize.bottom; + } + displayRect=CalculateDisplayRect(afterRenderWidth,afterRenderHeight,newWidth,newHeight); glViewport(displayRect.left,newHeight-displayRect.bottom,displayRect.right-displayRect.left,displayRect.bottom-displayRect.top); SetupVertices(); return true; @@ -504,13 +525,6 @@ bool COpenGL::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) bool COpenGL::ApplyDisplayChanges(void) { - if(GUI.BilinearFilter) { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } if(wglSwapIntervalEXT) { wglSwapIntervalEXT(GUI.Vsync?1:0); } @@ -519,9 +533,7 @@ bool COpenGL::ApplyDisplayChanges(void) else SetShaders(NULL); - RECT windowSize; - GetClientRect(hWnd,&windowSize); - ChangeRenderSize(windowSize.right,windowSize.bottom); + ChangeRenderSize(0,0); return true; } @@ -584,7 +596,7 @@ void COpenGL::EnumModes(std::vector *modeVector) if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) && (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) { DEVMODE dm; - ZeroMemory(&dm, sizeof(dm)); + memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); iMode = 0; while(EnumDisplaySettings(dd.DeviceName,iMode,&dm)) { @@ -604,6 +616,9 @@ void COpenGL::EnumModes(std::vector *modeVector) bool COpenGL::LoadPBOFunctions() { + if(GUI.OGLdisablePBOs) + return false; + if(pboFunctionsLoaded) return true; @@ -669,7 +684,9 @@ bool COpenGL::SetShaders(const TCHAR *file) SetShadersCG(NULL); SetShadersGLSL(NULL); shader_type = OGL_SHADER_NONE; - if(file!=NULL && lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) { + if(file!=NULL && ( + (lstrlen(file)>3 && _tcsncicmp(&file[lstrlen(file)-3],TEXT(".cg"),3)==0) || + (lstrlen(file)>4 && _tcsncicmp(&file[lstrlen(file)-4],TEXT(".cgp"),4)==0))) { return SetShadersCG(file); } else { return SetShadersGLSL(file); @@ -698,70 +715,16 @@ void COpenGL::checkForCgError(const char *situation) bool COpenGL::SetShadersCG(const TCHAR *file) { - TCHAR errorMsg[MAX_PATH + 50]; - HRESULT hr; - CGprofile vertexProfile, fragmentProfile; - - if(cgFragmentProgram) { - cgDestroyProgram(cgFragmentProgram); - cgFragmentProgram = NULL; - } - if(cgVertexProgram) { - cgDestroyProgram(cgVertexProgram); - cgVertexProgram = NULL; - } - - if(cgAvailable) { - vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); - fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); - - cgGLDisableProfile(vertexProfile); - cgGLDisableProfile(fragmentProfile); - } - - if (file == NULL || *file==TEXT('\0')) - return true; - if(!cgAvailable) { - MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"), - MB_OK|MB_ICONEXCLAMATION); + if(file) + MessageBox(NULL, TEXT("The CG runtime is unavailable, CG shaders will not run.\nConsult the snes9x readme for information on how to obtain the runtime."), TEXT("CG Error"), + MB_OK|MB_ICONEXCLAMATION); return false; } - cgGLSetOptimalOptions(vertexProfile); - cgGLSetOptimalOptions(fragmentProfile); - - char *fileContents = ReadShaderFileContents(file); - if(!fileContents) + if(!cgShader->LoadShader(file)) return false; - cgVertexProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - vertexProfile, "main_vertex", NULL); - - checkForCgError("Compiling vertex program"); - - cgFragmentProgram = cgCreateProgram( cgContext, CG_SOURCE, fileContents, - fragmentProfile, "main_fragment", NULL); - - checkForCgError("Compiling fragment program"); - - delete [] fileContents; - - if(!cgVertexProgram || !cgFragmentProgram) { - return false; - } - - if(cgVertexProgram) { - cgGLEnableProfile(vertexProfile); - cgGLLoadProgram(cgVertexProgram); - cgGLBindProgram(cgVertexProgram); - } - if(cgFragmentProgram) { - cgGLEnableProfile(fragmentProfile); - cgGLLoadProgram(cgFragmentProgram); - cgGLBindProgram(cgFragmentProgram); - } - shader_type = OGL_SHADER_CG; return true; diff --git a/win32/COpenGL.h b/win32/COpenGL.h index 4837d9bf..12448c8a 100644 --- a/win32/COpenGL.h +++ b/win32/COpenGL.h @@ -183,6 +183,7 @@ #include #include #include "cgFunctions.h" +#include "CGLCG.h" #include "glext.h" #include "wglext.h" @@ -202,6 +203,8 @@ private: GLfloat texcoords[8]; unsigned char * noPboBuffer; + int frameCount; + bool initDone; bool fullscreen; unsigned int quadTextureSize; @@ -217,6 +220,8 @@ private: current_ogl_shader_type shader_type; bool cgAvailable; + CGLCG *cgShader; + GLuint shaderProgram; GLuint vertexShader; GLuint fragmentShader; diff --git a/win32/CXAudio2.cpp b/win32/CXAudio2.cpp index ba4297be..90286f1b 100644 --- a/win32/CXAudio2.cpp +++ b/win32/CXAudio2.cpp @@ -308,6 +308,7 @@ pBufferContext - unused void CXAudio2::OnBufferEnd(void *pBufferContext) { InterlockedDecrement(&bufferCount); + SetEvent(GUI.SoundSyncEvent); } /* CXAudio2::PushBuffer diff --git a/win32/InputCustom.cpp b/win32/InputCustom.cpp index d86813ad..39f2cc0c 100644 --- a/win32/InputCustom.cpp +++ b/win32/InputCustom.cpp @@ -688,6 +688,8 @@ int GetNumHotKeysAssignedTo (WORD Key, int modifiers) if(MATCHES_KEY(TurboDown)) count++; if(MATCHES_KEY(ResetGame)) count++; if(MATCHES_KEY(ToggleCheats)) count++; + if(MATCHES_KEY(QuitS9X)) count++; + if(MATCHES_KEY(Rewind)) count++; #undef MATCHES_KEY } diff --git a/win32/cgFunctions.cpp b/win32/cgFunctions.cpp index 2c88931d..0d19757d 100644 --- a/win32/cgFunctions.cpp +++ b/win32/cgFunctions.cpp @@ -192,6 +192,16 @@ CGGES cgGetErrorString = NULL; CGGLL cgGetLastListing = NULL; CGCP cgCreateProgram = NULL; CGDP cgDestroyProgram = NULL; +CGGPRI cgGetParameterResourceIndex = NULL; +CGGFP cgGetFirstParameter = NULL; +CGGNEP cgGetNextParameter = NULL; +CGGPD cgGetParameterDirection = NULL; +CGGPS cgGetParameterSemantic = NULL; +CGGRS cgGetResourceString = NULL; +CGGPV cgGetParameterVariability = NULL; +CGGPT cgGetParameterType = NULL; +CGGFSP cgGetFirstStructParameter = NULL; +CGGPN cgGetParameterName = NULL; //cgD3D9.dll CGD3DSD cgD3D9SetDevice = NULL; CGD3DBP cgD3D9BindProgram = NULL; @@ -201,15 +211,24 @@ CGD3DGOO cgD3D9GetOptimalOptions = NULL; CGD3DLP cgD3D9LoadProgram = NULL; CGD3DSUM cgD3D9SetUniformMatrix = NULL; CGD3DSU cgD3D9SetUniform = NULL; +CGD3DST cgD3D9SetTexture = NULL; +CGD3DGVD cgD3D9GetVertexDeclaration = NULL; +CGD3DSSS cgD3D9SetSamplerState = NULL; //cggl.dll CGGLSSMP cgGLSetStateMatrixParameter = NULL; CGGLSP2FV cgGLSetParameter2fv = NULL; +CGGLSP1F cgGLSetParameter1f = NULL; CGGLGLP cgGLGetLatestProfile = NULL; CGGLEP cgGLEnableProfile = NULL; CGGLDP cgGLDisableProfile = NULL; CGGLSOO cgGLSetOptimalOptions = NULL; CGGLLP cgGLLoadProgram = NULL; CGGLBP cgGLBindProgram = NULL; +CGGLSTP cgGLSetTextureParameter = NULL; +CGGLETP cgGLEnableTextureParameter = NULL; +CGGLSPP cgGLSetParameterPointer = NULL; +CGGLECS cgGLEnableClientState = NULL; +CGGLDCS cgGLDisableClientState = NULL; bool loadCgFunctions() { @@ -236,6 +255,16 @@ bool loadCgFunctions() cgGetLastListing = (CGGLL)GetProcAddress(hCgDll,"cgGetLastListing"); cgCreateProgram = (CGCP)GetProcAddress(hCgDll,"cgCreateProgram"); cgDestroyProgram = (CGDP)GetProcAddress(hCgDll,"cgDestroyProgram"); + cgGetParameterResourceIndex = (CGGPRI)GetProcAddress(hCgDll,"cgGetParameterResourceIndex"); + cgGetFirstParameter = (CGGFP)GetProcAddress(hCgDll,"cgGetFirstParameter"); + cgGetNextParameter = (CGGNEP)GetProcAddress(hCgDll,"cgGetNextParameter"); + cgGetParameterDirection = (CGGPD)GetProcAddress(hCgDll,"cgGetParameterDirection"); + cgGetParameterSemantic = (CGGPS)GetProcAddress(hCgDll,"cgGetParameterSemantic"); + cgGetResourceString = (CGGRS)GetProcAddress(hCgDll,"cgGetResourceString"); + cgGetParameterVariability = (CGGPV)GetProcAddress(hCgDll,"cgGetParameterVariability"); + cgGetParameterType = (CGGPT)GetProcAddress(hCgDll,"cgGetParameterType"); + cgGetFirstStructParameter = (CGGFSP)GetProcAddress(hCgDll,"cgGetFirstStructParameter"); + cgGetParameterName = (CGGPN)GetProcAddress(hCgDll,"cgGetParameterName"); //cgD3D9.dll cgD3D9SetDevice = (CGD3DSD)GetProcAddress(hCgD3D9Dll,"cgD3D9SetDevice"); cgD3D9BindProgram = (CGD3DBP)GetProcAddress(hCgD3D9Dll,"cgD3D9BindProgram"); @@ -245,15 +274,24 @@ bool loadCgFunctions() cgD3D9LoadProgram = (CGD3DLP)GetProcAddress(hCgD3D9Dll,"cgD3D9LoadProgram"); cgD3D9SetUniformMatrix = (CGD3DSUM)GetProcAddress(hCgD3D9Dll,"cgD3D9SetUniformMatrix"); cgD3D9SetUniform = (CGD3DSU)GetProcAddress(hCgD3D9Dll,"cgD3D9SetUniform"); + cgD3D9SetTexture = (CGD3DST)GetProcAddress(hCgD3D9Dll,"cgD3D9SetTexture"); + cgD3D9GetVertexDeclaration = (CGD3DGVD)GetProcAddress(hCgD3D9Dll,"cgD3D9GetVertexDeclaration"); + cgD3D9SetSamplerState = (CGD3DSSS)GetProcAddress(hCgD3D9Dll,"cgD3D9SetSamplerState"); //cggl.dll cgGLSetStateMatrixParameter = (CGGLSSMP)GetProcAddress(hCgGLDll,"cgGLSetStateMatrixParameter"); cgGLSetParameter2fv = (CGGLSP2FV)GetProcAddress(hCgGLDll,"cgGLSetParameter2fv"); + cgGLSetParameter1f = (CGGLSP1F)GetProcAddress(hCgGLDll,"cgGLSetParameter1f"); cgGLGetLatestProfile = (CGGLGLP)GetProcAddress(hCgGLDll,"cgGLGetLatestProfile"); cgGLEnableProfile = (CGGLEP)GetProcAddress(hCgGLDll,"cgGLEnableProfile"); cgGLDisableProfile = (CGGLDP)GetProcAddress(hCgGLDll,"cgGLDisableProfile"); cgGLSetOptimalOptions = (CGGLSOO)GetProcAddress(hCgGLDll,"cgGLSetOptimalOptions"); cgGLLoadProgram = (CGGLLP)GetProcAddress(hCgGLDll,"cgGLLoadProgram"); cgGLBindProgram = (CGGLBP)GetProcAddress(hCgGLDll,"cgGLBindProgram"); + cgGLSetTextureParameter = (CGGLSTP)GetProcAddress(hCgGLDll,"cgGLSetTextureParameter"); + cgGLEnableTextureParameter = (CGGLETP)GetProcAddress(hCgGLDll,"cgGLEnableTextureParameter"); + cgGLSetParameterPointer = (CGGLSPP)GetProcAddress(hCgGLDll,"cgGLSetParameterPointer"); + cgGLEnableClientState = (CGGLECS)GetProcAddress(hCgGLDll,"cgGLEnableClientState"); + cgGLDisableClientState = (CGGLDCS)GetProcAddress(hCgGLDll,"cgGLDisableClientState"); if( //cg.dll @@ -265,6 +303,16 @@ bool loadCgFunctions() !cgGetLastListing || !cgCreateProgram || !cgDestroyProgram || + !cgGetParameterResourceIndex || + !cgGetFirstParameter || + !cgGetNextParameter || + !cgGetParameterDirection || + !cgGetParameterSemantic || + !cgGetResourceString || + !cgGetParameterVariability || + !cgGetParameterType || + !cgGetFirstStructParameter || + !cgGetParameterName || //cgD3D9.dll !cgD3D9SetDevice || !cgD3D9BindProgram || @@ -274,15 +322,24 @@ bool loadCgFunctions() !cgD3D9LoadProgram || !cgD3D9SetUniformMatrix || !cgD3D9SetUniform || + !cgD3D9SetTexture || + !cgD3D9GetVertexDeclaration || + !cgD3D9SetSamplerState || //cggl.dll !cgGLSetStateMatrixParameter || !cgGLSetParameter2fv || + !cgGLSetParameter1f || !cgGLGetLatestProfile || !cgGLEnableProfile || !cgGLDisableProfile || !cgGLSetOptimalOptions || !cgGLLoadProgram || - !cgGLBindProgram) { + !cgGLBindProgram || + !cgGLSetTextureParameter || + !cgGLEnableTextureParameter || + !cgGLSetParameterPointer || + !cgGLEnableClientState || + !cgGLDisableClientState) { unloadCgLibrary(); return false; } @@ -310,6 +367,16 @@ void unloadCgLibrary() cgGetLastListing = NULL; cgCreateProgram = NULL; cgDestroyProgram = NULL; + cgGetParameterResourceIndex = NULL; + cgGetFirstParameter = NULL; + cgGetNextParameter = NULL; + cgGetParameterDirection = NULL; + cgGetParameterSemantic = NULL; + cgGetResourceString = NULL; + cgGetParameterVariability = NULL; + cgGetParameterType = NULL; + cgGetFirstStructParameter = NULL; + cgGetParameterName = NULL; //cgD3D9.dll cgD3D9SetDevice = NULL; cgD3D9BindProgram = NULL; @@ -319,6 +386,9 @@ void unloadCgLibrary() cgD3D9LoadProgram = NULL; cgD3D9SetUniformMatrix = NULL; cgD3D9SetUniform = NULL; + cgD3D9SetTexture = NULL; + cgD3D9GetVertexDeclaration = NULL; + cgD3D9SetSamplerState = NULL; //cggl.dll cgGLSetStateMatrixParameter = NULL; cgGLSetParameter2fv = NULL; @@ -328,4 +398,6 @@ void unloadCgLibrary() cgGLSetOptimalOptions = NULL; cgGLLoadProgram = NULL; cgGLBindProgram = NULL; + cgGLEnableClientState = NULL; + cgGLDisableClientState = NULL; } diff --git a/win32/cgFunctions.h b/win32/cgFunctions.h index 2d7ea3ac..500e5e41 100644 --- a/win32/cgFunctions.h +++ b/win32/cgFunctions.h @@ -205,6 +205,26 @@ typedef CG_API CGprogram (CGENTRY *CGCP)(CGcontext context, CGenum program_type, extern CGCP cgCreateProgram; typedef CG_API void (CGENTRY *CGDP)(CGprogram program); extern CGDP cgDestroyProgram; +typedef CG_API unsigned long (CGENTRY *CGGPRI)(CGparameter param); +extern CGGPRI cgGetParameterResourceIndex; +typedef CG_API CGparameter (CGENTRY *CGGFP)(CGprogram program, CGenum name_space); +extern CGGFP cgGetFirstParameter; +typedef CG_API CGparameter (CGENTRY *CGGNEP)(CGparameter current); +extern CGGNEP cgGetNextParameter; +typedef CG_API CGenum (CGENTRY *CGGPD)(CGparameter param); +extern CGGPD cgGetParameterDirection; +typedef CG_API const char * (CGENTRY *CGGPS)(CGparameter param); +extern CGGPS cgGetParameterSemantic; +typedef CG_API const char * (CGENTRY *CGGRS)(CGresource resource); +extern CGGRS cgGetResourceString; +typedef CG_API CGenum (CGENTRY *CGGPV)(CGparameter param); +extern CGGPV cgGetParameterVariability; +typedef CG_API CGtype (CGENTRY *CGGPT)(CGparameter param); +extern CGGPT cgGetParameterType; +typedef CG_API CGparameter (CGENTRY *CGGFSP)(CGparameter param); +extern CGGFSP cgGetFirstStructParameter; +typedef CG_API const char * (CGENTRY *CGGPN)(CGparameter param); +extern CGGPN cgGetParameterName; //cgD3D9.dll typedef CGD3D9DLL_API HRESULT (CGD3D9ENTRY *CGD3DSD)(IDirect3DDevice9 *pDevice); @@ -223,10 +243,18 @@ typedef CGD3D9DLL_API HRESULT (CGD3D9ENTRY *CGD3DSUM)(CGparameter param, const D extern CGD3DSUM cgD3D9SetUniformMatrix; typedef CGD3D9DLL_API HRESULT (CGD3D9ENTRY *CGD3DSU)(CGparameter param, const void *floats); extern CGD3DSU cgD3D9SetUniform; +typedef CGD3D9DLL_API HRESULT (CGD3D9ENTRY *CGD3DST)(CGparameter param, IDirect3DBaseTexture9 *tex); +extern CGD3DST cgD3D9SetTexture; +typedef CGD3D9DLL_API CGbool (CGD3D9ENTRY *CGD3DGVD)(CGprogram prog, D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH]); +extern CGD3DGVD cgD3D9GetVertexDeclaration; +typedef CGD3D9DLL_API HRESULT (CGD3D9ENTRY *CGD3DSSS)(CGparameter param, D3DSAMPLERSTATETYPE type, DWORD value); +extern CGD3DSSS cgD3D9SetSamplerState; //cggl.dll typedef CGGL_API void (CGGLENTRY *CGGLSSMP)(CGparameter param, CGGLenum matrix, CGGLenum transform); extern CGGLSSMP cgGLSetStateMatrixParameter; +typedef CGGL_API void (CGGLENTRY *CGGLSP1F)(CGparameter param, float x); +extern CGGLSP1F cgGLSetParameter1f; typedef CGGL_API void (CGGLENTRY *CGGLSP2FV)(CGparameter param, const float *v); extern CGGLSP2FV cgGLSetParameter2fv; typedef CGGL_API CGprofile (CGGLENTRY *CGGLGLP)(CGGLenum profile_type); @@ -241,8 +269,16 @@ typedef CGGL_API void (CGGLENTRY *CGGLLP)(CGprogram program); extern CGGLLP cgGLLoadProgram; typedef CGGL_API void (CGGLENTRY *CGGLBP)(CGprogram program); extern CGGLBP cgGLBindProgram; - - +typedef CGGL_API void (CGGLENTRY *CGGLSTP)(CGparameter param, GLuint texobj); +extern CGGLSTP cgGLSetTextureParameter; +typedef CGGL_API void (CGGLENTRY *CGGLETP)(CGparameter param); +extern CGGLETP cgGLEnableTextureParameter; +typedef CGGL_API void (CGGLENTRY *CGGLSPP)(CGparameter param, GLint fsize, GLenum type, GLsizei stride, const GLvoid *pointer); +extern CGGLSPP cgGLSetParameterPointer; +typedef CGGL_API void (CGGLENTRY *CGGLECS)(CGparameter param); +extern CGGLECS cgGLEnableClientState; +typedef CGGL_API void (CGGLENTRY *CGGLDCS)(CGparameter param); +extern CGGLDCS cgGLDisableClientState; //cgfunctions.cpp bool loadCgFunctions(); diff --git a/win32/docs/how2compile.txt b/win32/docs/how2compile.txt index 0e50be36..5d7e5e67 100644 --- a/win32/docs/how2compile.txt +++ b/win32/docs/how2compile.txt @@ -8,6 +8,8 @@ NOTE: Unicode support requires a special zlib build - see the end of the zlib en your own project file for earlier MSVC versions - A recent DirectX SDK. The official binary is compiled against the June 2008 SDK. + Note that as of the June 2010 release of the DirectX SDK, DirectDraw (which is + necessary to compile) has been removed. - zlib(optional) - The release binaries are built against a static zlib compiled against VC's multi-threaded C runtime and renamed to zlibmt.lib, to avoid linker conflicts. diff --git a/win32/docs/readme-windows.txt b/win32/docs/readme-windows.txt index 193e8faa..24a264a9 100644 --- a/win32/docs/readme-windows.txt +++ b/win32/docs/readme-windows.txt @@ -46,13 +46,13 @@ The original Snes9x project was founded by Gary Henderson and Jerremy Koot as a collaboration of their earlier attempts at SNES emulation (Snes96 and Snes97.) Over the years the project has grown and has collected some of the greatest talent in the emulation community (at least of the SNES variety) some of which -have been listed in the credits section, others have helped but have been loss +have been listed in the credits section, others have helped but have been lost in the course of time. Why Emulate the SNES? --------------------- Well, there are many reasons for this. The main reason is for nostalgic -purposes. In this day and age, it's hard to find an SNES and many good games. +purposes. In this day and age, it's hard to find a SNES and many good games. Plus, many of us over the course of time have lost our beloved consoles (may they R.I.P) but still have our original carts. With no other means to play them, we turn to emulators. Besides this there are many conveniences of doing this on @@ -114,8 +114,8 @@ is displayed. This will help to find out what the problem is. These colors do NOT signify whether a game will work or not. It is just a means for reference so we can understand what may or may not be a problem. Most often -the problem with games that don't work it's because they are corrupt or are a -bad dump and should be redumped. +the problem with games that don't work is that they are corrupt or are a bad dump +and should be redumped. SNES Joypad Emulation --------------------- @@ -148,7 +148,7 @@ DirectX 6.1b or later. DirectSound capable sound card. Certain games use added hardware which will require a faster machine. The specs -listed above is the minimum to use Snes9x in any playable form. It is +listed above are the minimum to use Snes9x in any playable form. It is recommended that you get a semi-modern machine with a 800MHz CPU if you want good results. A 1GHz CPU is recommended for those that want a near perfect experience. @@ -255,7 +255,7 @@ intent - ideal for saving your game just before a tricky bit! Freeze files and SRAM files are normally written to and read from the folder called Saves where your snes9x.exe is located, but sometimes this is not -desirable or possible, especially if it’s a CD-ROM, which is of course is +desirable or possible, especially if it's a CD-ROM, which of course is usually read-only! You can change the folder where Snes9x saves and loads freeze and SRAM files using the Settings Dialog, available from the Options menu. @@ -349,7 +349,7 @@ Snes9x also allows new cheats to be found using the Search for New Cheats dialog, again available from the Cheats menu. The easiest way to describe the dialog is to walk through an example. -Let’s give ourselves infinite health and lives on Ocean's Addams Family platform +Let's give ourselves infinite health and lives on Ocean's Addams Family platform game: Load up the game; keep pressing the start button (Return key by default) to skip @@ -361,8 +361,8 @@ Launch the Cheat Search dialog for the first time; Alt+A is its accelerator. Press the Reset button just in case you've used the dialog before, leave the Search Type and Data Size radio boxes at their default values and press OK. -Play the game for a while until you loose a life by just keep walking into -baddies, when the game restarts and the life counter displays 4, launch the +Play the game for a while until you loose a life by just keeping walking into +baddies; when the game restarts and the life counter displays 4, launch the Cheat Search dialog again but this time press the Search button rather than Reset. The number of items in the list will reduce, each line shows a memory location, its current value and its previous value; what we're looking for is @@ -394,7 +394,7 @@ the counter back to the value you chose! If the memory location you add a cheat on proves to be wrong, just go to the Cheat Code Editor dialog and delete the incorrect entry. -Now let’s try and find the Addams Family health counter. While two hearts are +Now let's try and find the Addams Family health counter. While two hearts are displayed on the screen, visit the Cheat Search dialog and press the Reset button followed by OK. Play the game until you loose a heart by touching a baddie, then visit the Cheat Search dialog again. @@ -406,7 +406,7 @@ with. Look at address line 7E00C3, its current value is 1 and its previous value was 2. Scrolling through the list doesn't reveal any other likely memory locations, -so let’s try our luck. Click on the 7E00C3 line, press the Add Cheat button and +so let's try our luck. Click on the 7E00C3 line, press the Add Cheat button and type in a new value of say 4 into the dialog that appears and press OK. Press OK on the Search for New Cheats dialog to return to the game. @@ -428,9 +428,9 @@ Movie support allows you to record your actions while playing a game. This can be used for your own personal playback or to show other people that you can do something without them having to be around when you did it. -Recording the Movie -------------------- -Simply click File menu and click on Movie. Click the Record button. Here you can +Recording a Movie +----------------- +Simply click the File menu and click on Movie. Click the Record button. Here you can decide when to start recording. If you want to record from the very start of a game, click on 'Record from reset.' If you want to start recording from where you are already in a game, click 'Record from now.' You can also choose which @@ -438,14 +438,14 @@ controllers to record. If you are playing by yourself leave joypad 1 as the only one selected. The more controllers you choose to record the larger the file size will be. -Playing Back the Movie ----------------------- +Playing Back a Movie +-------------------- To play back a movie you recorded, click File menu, Movie, Play and select the file to play. Make sure the movie was recorded with the same ROM that you have loaded. -Re-recording the Movie ----------------------- +Re-recording a Movie +-------------------- If you make a mistake while recording a movie, there is a movie re-record function. Simply create a freeze file anytime while recording. If you want to re-record, load the freeze file and it will bring up the message 'movie @@ -625,8 +625,8 @@ Snes9x: Hayazashi Nidan Morita Shougi Seta-11 Hayazashi Nidan Morita Shougi 2 Seta-18 -Problems with Sounds --------------------- +Problems with Sound +------------------- No sound coming from any SNES game using Snes9x? Could be any or all of these: - If all sound menu options are grayed out, or an error dialog about Snes9x not diff --git a/win32/render.cpp b/win32/render.cpp index f565de08..a5ac894b 100644 --- a/win32/render.cpp +++ b/win32/render.cpp @@ -2624,7 +2624,7 @@ void RenderBlarggNTSCRgb( SSurface Src, SSurface Dst, RECT *rect) void RenderBlarggNTSC( SSurface Src, SSurface Dst, RECT *rect) { SetRect(rect, 256, 239, 2); - rect->right = 604; + rect->right = SNES_NTSC_OUT_WIDTH(256); const unsigned int srcRowPixels = Src.Pitch/2; diff --git a/win32/rsrc/resource.h b/win32/rsrc/resource.h index ca767abd..04b0b0e8 100644 --- a/win32/rsrc/resource.h +++ b/win32/rsrc/resource.h @@ -81,7 +81,11 @@ #define IDC_HEADER 1067 #define IDC_HIRESAVI 1067 #define IDC_ROMLIST 1068 +#define IDC_REWIND_BUFFER 1068 #define IDC_MEM_TYPE 1069 +#define IDC_REWIND_BUFFER_SPIN 1069 +#define IDC_REWIND_GRANULARITY 1070 +#define IDC_REWIND_GRANULARITY_SPIN 1071 #define IDC_HOSTNAME 1086 #define IDC_PORTNUMBER 1087 #define IDC_CLEARHISTORY 1088 @@ -226,12 +230,17 @@ #define IDC_LABEL_UP4 1183 #define IDC_PORTNUMBLOCK 1184 #define IDC_LABEL_UP5 1184 +#define IDC_LABEL_RBUFFER 1184 #define IDC_CLIENTSETTINGSBLOCK 1185 #define IDC_LABEL_UP6 1185 +#define IDC_LABEL_RBUFFER_TEXT 1185 #define IDC_SERVERSETTINGSBLOCK 1186 #define IDC_LABEL_UP7 1186 +#define IDC_LABEL_RGRANU 1186 #define IDC_LABEL_PORTNUM 1187 #define IDC_LABEL_UP8 1187 +#define IDC_LABEL_RBUFFER_TEXT2 1187 +#define IDC_LABEL_GRANU_TEXT 1187 #define IDC_LABEL_PAUSEINTERVAL 1188 #define IDC_LABEL_UP9 1188 #define IDC_LABEL_PAUSEINTERVAL_TEXT 1189 @@ -485,13 +494,14 @@ #define ID_WINDOW_SIZE_3X 40171 #define ID_WINDOW_SIZE_4X 40172 #define ID_DEBUG_APU_TRACE 40173 +#define ID_EMULATION_BACKGROUNDINPUT 40174 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 151 -#define _APS_NEXT_COMMAND_VALUE 40174 +#define _APS_NEXT_COMMAND_VALUE 40175 #define _APS_NEXT_CONTROL_VALUE 3018 #define _APS_NEXT_SYMED_VALUE 101 #endif diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index d8288504..2aa4637f 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -96,10 +96,10 @@ CAPTION "APP - About Dialog" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,90,160,50,14 - EDITTEXT IDC_DISCLAIMER,7,7,218,148,ES_MULTILINE | ES_NOHIDESEL | ES_READONLY,WS_EX_STATICEDGE + EDITTEXT IDC_DISCLAIMER,7,7,218,148,ES_MULTILINE | ES_NOHIDESEL | ES_READONLY | WS_VSCROLL,WS_EX_STATICEDGE END -IDD_EMU_SETTINGS DIALOGEX 0, 0, 319, 154 +IDD_EMU_SETTINGS DIALOGEX 0, 0, 319, 184 STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU CAPTION "APP - Emulator Settings" FONT 8, "MS Sans Serif", 0, 0, 0x0 @@ -112,9 +112,17 @@ BEGIN CONTROL "Spin3",IDC_SPIN_MAX_SKIP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,298,70,11,13 EDITTEXT IDC_TURBO_SKIP,91,85,49,14,ES_AUTOHSCROLL | ES_NUMBER CONTROL "Spin4",IDC_SPIN_TURBO_SKIP,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,296,94,11,13 - CONTROL "Toggled Turbo Mode",IDC_TOGGLE_TURBO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,103,123,12 - DEFPUSHBUTTON "&OK",IDOK,215,136,46,14 - PUSHBUTTON "&Cancel",IDCANCEL,266,135,46,14 + EDITTEXT IDC_REWIND_BUFFER,91,102,49,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_REWIND_BUFFER_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,294,114,11,13 + EDITTEXT IDC_REWIND_GRANULARITY,91,120,49,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_REWIND_GRANULARITY_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS,293,131,11,13 + CONTROL "Toggled Turbo Mode",IDC_TOGGLE_TURBO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,136,123,12 + CONTROL "Pause When Inactive",IDC_INACTIVE_PAUSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,147,100,12 + CONTROL "Custom ROM Open Dialog",IDC_CUSTOMROMOPEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,158,117,12 + CONTROL "Hi-Res AVI Recording",IDC_HIRESAVI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,169,117,12 + DEFPUSHBUTTON "&OK",IDOK,215,168,46,14 + PUSHBUTTON "&Cancel",IDCANCEL,266,168,46,14 + COMBOBOX IDC_DIRCOMBO,7,29,44,30,CBS_DROPDOWNLIST | WS_TABSTOP RTEXT "Directory",IDC_LABEL_FREEZE,53,28,32,14,SS_CENTERIMAGE RTEXT "Auto-Save S-RAM",IDC_LABEL_ASRAM,21,47,64,14,SS_CENTERIMAGE RTEXT "Skip at most",IDC_LABEL_SMAX,40,66,45,14,SS_CENTERIMAGE @@ -122,13 +130,13 @@ BEGIN LTEXT "seconds after last change (0 disables auto-save)",IDC_LABEL_ASRAM_TEXT,146,47,161,14,SS_CENTERIMAGE LTEXT "frames in auto-frame rate mode",IDC_LABEL_SMAX_TEXT,146,66,138,14,SS_CENTERIMAGE LTEXT "frames in Turbo mode",IDC_LABEL_STURBO_TEXT,146,85,92,14,SS_CENTERIMAGE - CONTROL "Pause When Inactive",IDC_INACTIVE_PAUSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,114,100,12 LTEXT "Config file",IDC_STATIC,54,11,34,11 EDITTEXT IDC_CONFIG_NAME_BOX,91,9,49,14,ES_AUTOHSCROLL | ES_READONLY | ES_NUMBER LTEXT "all of Snes9x's settings are stored in this file",IDC_STATIC,147,11,160,11 - COMBOBOX IDC_DIRCOMBO,7,29,44,30,CBS_DROPDOWNLIST | WS_TABSTOP - CONTROL "Custom ROM Open Dialog",IDC_CUSTOMROMOPEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,125,117,12 - CONTROL "Hi-Res AVI Recording",IDC_HIRESAVI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,136,117,12 + RTEXT "Rewind Buffer",IDC_LABEL_RBUFFER,31,102,51,14,SS_CENTERIMAGE + LTEXT "MB (set to 0 to disable rewind support)",IDC_LABEL_RBUFFER_TEXT,145,102,131,14,SS_CENTERIMAGE + RTEXT "Rewind Granularity",IDC_LABEL_RGRANU,18,120,64,14,SS_CENTERIMAGE + LTEXT "frames",IDC_LABEL_GRANU_TEXT,145,120,131,14,SS_CENTERIMAGE END IDD_OPEN_ROM DIALOGEX 0, 0, 430, 223 @@ -364,13 +372,13 @@ BEGIN RTEXT "Description",IDC_STATIC,7,103,70,12,SS_CENTERIMAGE END -IDD_OPENMOVIE DIALOGEX 0, 0, 304, 223 +IDD_OPENMOVIE DIALOGEX 0, 0, 304, 166 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Play Movie" FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,187,200,50,14 - PUSHBUTTON "Cancel",IDCANCEL,246,200,50,14 + DEFPUSHBUTTON "OK",IDOK,187,149,50,14 + PUSHBUTTON "Cancel",IDCANCEL,246,149,50,14 EDITTEXT IDC_MOVIE_PATH,7,18,230,13,ES_AUTOHSCROLL LTEXT "Movie File",IDC_STATIC,7,7,33,8 PUSHBUTTON "&Browse...",IDC_BROWSE_MOVIE,248,17,48,14 @@ -382,54 +390,45 @@ BEGIN LTEXT "LENGTH",IDC_MOVIE_LENGTH,71,64,81,8 LTEXT "FRAMES",IDC_MOVIE_FRAMES,71,73,81,8 LTEXT "RERECORD",IDC_MOVIE_RERECORD,71,82,81,8 - LTEXT "Author Info:",IDC_LABEL_MOVIEINFOBOX,30,99,38,8 + LTEXT "Author Info:",IDC_LABEL_MOVIEINFOBOX,30,123,38,8 CONTROL "Open Read-Only",IDC_READONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,7,69,10 - LTEXT "Static",IDC_MOVIE_METADATA,70,99,226,21,WS_BORDER - GROUPBOX "Record Options",IDC_LABEL_STARTSETTINGS,7,133,77,61 - CONTROL "Record from now",IDC_RECORD_NOW,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP | WS_TABSTOP,11,169,70,10 - CONTROL "Record from reset",IDC_RECORD_RESET,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_TABSTOP,11,154,72,10 - CONTROL "Joypad 1",IDC_JOY1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,98,142,45,10 - CONTROL "Joypad 3",IDC_JOY3,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,98,162,45,10 - CONTROL "Joypad 2",IDC_JOY2,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,98,152,45,10 - CONTROL "Joypad 4",IDC_JOY4,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,98,172,45,10 - CONTROL "Joypad 5",IDC_JOY5,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,98,183,45,10 - GROUPBOX "Record Controllers",IDC_LABEL_CONTROLLERSETTINGS,89,133,69,61 - GROUPBOX "Emulator Sync Settings",IDC_LABEL_SYNCSETTINGS,163,133,133,61 - CONTROL "Allow Left+Right / Up+Down",IDC_ALLOWLEFTRIGHT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,153,118,11 - CONTROL "Sync samples with sound CPU",IDC_SYNC_TO_SOUND_CPU, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,166,117,10 - LTEXT " ",IDC_LOADEDFROMMOVIE,169,124,127,8 + LTEXT "Static",IDC_MOVIE_METADATA,70,123,226,21,WS_BORDER + GROUPBOX "Record Options",IDC_LABEL_STARTSETTINGS,204,54,95,41 + CONTROL "Record from now",IDC_RECORD_NOW,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_GROUP | WS_TABSTOP,208,76,70,10 + CONTROL "Record from reset",IDC_RECORD_RESET,"Button",BS_AUTORADIOBUTTON | WS_DISABLED | WS_TABSTOP,208,64,72,10 + CONTROL "Joypad 1",IDC_JOY1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,18,106,45,10 + CONTROL "Joypad 3",IDC_JOY3,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,116,106,45,10 + CONTROL "Joypad 2",IDC_JOY2,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,67,106,45,10 + CONTROL "Joypad 4",IDC_JOY4,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,165,106,45,10 + CONTROL "Joypad 5",IDC_JOY5,"Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,214,106,45,10 + GROUPBOX "Record Controllers",IDC_LABEL_CONTROLLERSETTINGS,12,95,272,25 LTEXT "Movie's ROM: CRC32=Unknown, Name=Unknown",IDC_MOVIEROMINFO,8,35,1024,8 LTEXT "Current ROM: CRC32=Unknown, Name=Unknown",IDC_CURRENTROMINFO,9,43,287,9 - LTEXT " ",IDC_PLAYWARN,10,203,167,15 + LTEXT " ",IDC_PLAYWARN,10,149,167,15 END -IDD_CREATEMOVIE DIALOGEX 0, 0, 303, 150 +IDD_CREATEMOVIE DIALOGEX 0, 0, 303, 118 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Record Movie" FONT 8, "MS Sans Serif", 0, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,187,129,50,14 - PUSHBUTTON "Cancel",IDCANCEL,246,129,50,14 + DEFPUSHBUTTON "OK",IDOK,187,96,50,14 + PUSHBUTTON "Cancel",IDCANCEL,246,96,50,14 EDITTEXT IDC_MOVIE_PATH,7,18,230,13,ES_AUTOHSCROLL LTEXT "Movie File",IDC_STATIC,7,7,33,8 PUSHBUTTON "&Browse...",IDC_BROWSE_MOVIE,248,17,48,14 - GROUPBOX "Record Options",IDC_LABEL_STARTSETTINGS,7,38,77,61 - CONTROL "Record from now",IDC_RECORD_NOW,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,65,70,10 - CONTROL "Record from reset",IDC_RECORD_RESET,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,11,52,72,10 - CONTROL "Joypad 1",IDC_JOY1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,98,47,45,10 - CONTROL "Joypad 3",IDC_JOY3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,98,67,45,10 - CONTROL "Joypad 2",IDC_JOY2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,98,57,45,10 - CONTROL "Joypad 4",IDC_JOY4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,98,77,45,10 - CONTROL "Joypad 5",IDC_JOY5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,98,87,45,10 - GROUPBOX "Record Controllers",IDC_LABEL_CONTROLLERSETTINGS,89,38,69,61 - EDITTEXT IDC_MOVIE_METADATA,67,105,229,14,ES_AUTOHSCROLL - LTEXT "Author Info:",IDC_STATIC,18,108,43,8,0,WS_EX_RIGHT - GROUPBOX "Emulator Sync Settings",IDC_LABEL_SYNCSETTINGS,163,38,133,61 - CONTROL "Allow Left+Right / Up+Down",IDC_ALLOWLEFTRIGHT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,62,118,10 - CONTROL "Sync samples with sound CPU",IDC_SYNC_TO_SOUND_CPU, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,172,75,117,10 - CONTROL "Clear SRAM",IDC_CLEARSRAM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,83,70,10 + GROUPBOX "Record Options",IDC_LABEL_STARTSETTINGS,7,50,77,61 + CONTROL "Record from now",IDC_RECORD_NOW,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,77,70,10 + CONTROL "Record from reset",IDC_RECORD_RESET,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,11,64,72,10 + CONTROL "Joypad 1",IDC_JOY1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,59,45,10 + CONTROL "Joypad 3",IDC_JOY3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,79,45,10 + CONTROL "Joypad 2",IDC_JOY2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,69,45,10 + CONTROL "Joypad 4",IDC_JOY4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,89,45,10 + CONTROL "Joypad 5",IDC_JOY5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,99,45,10 + GROUPBOX "Record Controllers",IDC_LABEL_CONTROLLERSETTINGS,97,50,69,61 + EDITTEXT IDC_MOVIE_METADATA,67,34,229,14,ES_AUTOHSCROLL + LTEXT "Author Info:",IDC_STATIC,18,37,43,8,0,WS_EX_RIGHT + CONTROL "Clear SRAM",IDC_CLEARSRAM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,95,70,10 END IDD_KEYCUSTOM DIALOGEX 0, 0, 349, 203 @@ -589,7 +588,7 @@ BEGIN BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 312 - BOTTOMMARGIN, 147 + BOTTOMMARGIN, 177 END IDD_OPEN_ROM, DIALOG @@ -654,12 +653,11 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 297 TOPMARGIN, 7 - BOTTOMMARGIN, 219 + BOTTOMMARGIN, 162 HORZGUIDE, 31 HORZGUIDE, 55 HORZGUIDE, 120 HORZGUIDE, 133 - HORZGUIDE, 191 END IDD_CREATEMOVIE, DIALOG @@ -667,7 +665,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 296 TOPMARGIN, 7 - BOTTOMMARGIN, 143 + BOTTOMMARGIN, 111 HORZGUIDE, 31 HORZGUIDE, 38 HORZGUIDE, 99 @@ -852,6 +850,8 @@ BEGIN MENUITEM "&Input Configuration...\tAlt+F7", 40022 MENUITEM "&Customize Hotkeys...\tAlt+F9", ID_OPTIONS_KEYCUSTOM MENUITEM SEPARATOR + MENUITEM "Enable Background Input", ID_EMULATION_BACKGROUNDINPUT + MENUITEM SEPARATOR MENUITEM "Use SNES Joypad(s)", IDM_SNES_JOYPAD MENUITEM "Use SNES Mouse", IDM_MOUSE_TOGGLE MENUITEM "Use Super Scope", IDM_SCOPE_TOGGLE diff --git a/win32/snes9xw.vcproj b/win32/snes9xw.vcproj index 3db6257f..533bf9d3 100644 --- a/win32/snes9xw.vcproj +++ b/win32/snes9xw.vcproj @@ -158,7 +158,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" WholeProgramOptimization="true" - AdditionalIncludeDirectories="$(ProjectDir),$(ProjectDir)..\,$(ProjectDir)..\..\,$(ProjectDir)..\..\zLib,$(ProjectDir)..\unzip,$(ProjectDir)..\..\FMOD\api\inc,$(ProjectDir)..\..\libPNG\src,$(ProjectDir)..\snes9x" + AdditionalIncludeDirectories="$(ProjectDir),$(ProjectDir)..\,$(ProjectDir)..\..\,$(ProjectDir)..\..\zLib,$(ProjectDir)..\unzip,$(ProjectDir)..\..\FMOD\api\inc,$(ProjectDir)..\..\libPNG\src,$(ProjectDir)..\apu\bapu" PreprocessorDefinitions="NDEBUG;HAVE_LIBPNG;JMA_SUPPORT;ZLIB;UNZIP_SUPPORT;__WIN32__;FMODEX_SUPPORT;NETPLAY_SUPPORT" StringPooling="true" RuntimeLibrary="0" @@ -255,7 +255,7 @@ - - - - - - - - - - - - - - - - @@ -2902,6 +2866,50 @@ /> + + + + + + + + + + + + + + + + + + + + @@ -3129,6 +3137,22 @@ + + + + + + + + @@ -3209,6 +3233,14 @@ RelativePath=".\cgFunctions.h" > + + + + @@ -4513,375 +4545,71 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - + - - - - + + + + + + + + + + - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + MAX_RECENT_GAMES_LIST_SIZE) GUI.MaxRecentGames = MAX_RECENT_GAMES_LIST_SIZE; + if(GUI.rewindGranularity==0) GUI.rewindGranularity = 1; bool gap = false; for(i=0;iInitialize(GUI.hWnd)) { S9xGraphicsDeinit(); S9xSetWinPixelFormat (); - S9xInitUpdate(); S9xGraphicsInit(); return true; } else { @@ -273,27 +272,27 @@ void WinDisplayApplyChanges() RECT CalculateDisplayRect(unsigned int sourceWidth,unsigned int sourceHeight, unsigned int displayWidth,unsigned int displayHeight) { - float xFactor; - float yFactor; - float minFactor; - float renderWidthCalc,renderHeightCalc; + double xFactor; + double yFactor; + double minFactor; + double renderWidthCalc,renderHeightCalc; int hExtend = GUI.HeightExtend ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT; - float snesAspect = (float)GUI.AspectWidth/hExtend; + double snesAspect = (double)GUI.AspectWidth/hExtend; RECT drawRect; if(GUI.Stretch) { if(GUI.AspectRatio) { //fix for hi-res images with FILTER_NONE //where we need to correct the aspect ratio - renderWidthCalc = (float)sourceWidth; - renderHeightCalc = (float)sourceHeight; + renderWidthCalc = (double)sourceWidth; + renderHeightCalc = (double)sourceHeight; if(renderWidthCalc/renderHeightCalc>snesAspect) renderWidthCalc = renderHeightCalc * snesAspect; else if(renderWidthCalc/renderHeightCalc @@ -277,7 +279,7 @@ INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); HRESULT CALLBACK EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext); -INT_PTR CALLBACK test(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); +VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); #define NOTKNOWN "Unknown Company " #define HEADER_SIZE 512 @@ -561,6 +563,8 @@ struct SCustomKeys CustomKeys = { {0,0}}, // Select save slot 9 {'R',CUSTKEY_CTRL_MASK|CUSTKEY_SHIFT_MASK}, // Reset Game {0,0}, // Toggle Cheats + {0,0}, + {'R',0}, // Rewind }; @@ -608,7 +612,7 @@ struct OpenMovieParams - +StateManager stateMan; std::vector dm; /*****************************************************************************/ @@ -1224,6 +1228,18 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) S9xReportControllers(); } } + if(wParam == CustomKeys.QuitS9X.key + && modifiers == CustomKeys.QuitS9X.modifiers) + { + PostMessage(GUI.hWnd,WM_CLOSE,(WPARAM)NULL,(LPARAM)(NULL)); + } + if(wParam == CustomKeys.Rewind.key + && modifiers == CustomKeys.Rewind.modifiers) + { + if(!GUI.rewinding) + S9xMessage (S9X_INFO, 0, GUI.rewindBufferSize?WINPROC_REWINDING_TEXT:WINPROC_REWINDING_DISABLED); + GUI.rewinding = true; + } //if(wParam == CustomKeys.BGLHack.key //&& modifiers == CustomKeys.BGLHack.modifiers) //{ @@ -1309,7 +1325,7 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) switch (wParam) { case VK_ESCAPE: - if(GUI.outputMethod==DIRECT3D && GUI.FullScreen && !GUI.EmulateFullscreen) + if(GUI.outputMethod!=DIRECTDRAW && GUI.FullScreen && !GUI.EmulateFullscreen) ToggleFullScreen(); else if (GetMenu (GUI.hWnd) == NULL) @@ -1393,7 +1409,7 @@ static bool DoOpenRomDialog(TCHAR filename [_MAX_PATH], bool noCustomDlg = false strcat0(lpfilterptr, FILE_INFO_ANY_FILE_TYPE); strcat0(lpfilterptr, TEXT("\0*.*\0\0")); - ZeroMemory((LPVOID)&ofn, sizeof(OPENFILENAME)); + memset((LPVOID)&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GUI.hWnd; ofn.lpstrFilter = lpfilter; @@ -1431,7 +1447,7 @@ LRESULT CALLBACK WinProc( unsigned int i; //bool showFPS; #ifdef NETPLAY_SUPPORT - char hostname [100]; + TCHAR hostname [100]; #endif switch (uMsg) { @@ -1440,7 +1456,7 @@ LRESULT CALLBACK WinProc( DragAcceptFiles(hWnd, TRUE); return 0; case WM_KEYDOWN: - if(GUI.BackgroundKeyHotkeys) + if(GUI.BackgroundInput && !GUI.InactivePause) break; case WM_CUSTKEYDOWN: case WM_SYSKEYDOWN: @@ -1454,11 +1470,11 @@ LRESULT CALLBACK WinProc( case WM_CUSTKEYUP: { int modifiers = 0; - if(GetAsyncKeyState(VK_MENU)) + if(GetAsyncKeyState(VK_MENU) || wParam == VK_MENU) modifiers |= CUSTKEY_ALT_MASK; - if(GetAsyncKeyState(VK_CONTROL)) + if(GetAsyncKeyState(VK_CONTROL)|| wParam == VK_CONTROL) modifiers |= CUSTKEY_CTRL_MASK; - if(GetAsyncKeyState(VK_SHIFT)) + if(GetAsyncKeyState(VK_SHIFT)|| wParam == VK_SHIFT) modifiers |= CUSTKEY_SHIFT_MASK; if(wParam == CustomKeys.FastForward.key @@ -1472,6 +1488,12 @@ LRESULT CALLBACK WinProc( { GUI.superscope_pause = 0; } + if(wParam == CustomKeys.Rewind.key + && modifiers == CustomKeys.Rewind.modifiers) + { + GUI.rewinding = false; + } + } break; @@ -1516,7 +1538,7 @@ LRESULT CALLBACK WinProc( szFileName[0] = TEXT('\0'); - ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) ); + memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) ); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GUI.hWnd; ofn.lpstrFilter = FILE_INFO_AVI_FILE_TYPE TEXT("\0*.avi\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0"); @@ -1754,6 +1776,12 @@ LRESULT CALLBACK WinProc( RestoreSNESDisplay (); break; + case ID_EMULATION_BACKGROUNDINPUT: + GUI.BackgroundInput = !GUI.BackgroundInput; + if(!GUI.hHotkeyTimer) + GUI.hHotkeyTimer = timeSetEvent (32, 0, (LPTIMECALLBACK)HotkeyTimer, 0, TIME_PERIODIC); + break; + case ID_FILE_LOADMULTICART: { #ifdef NETPLAY_SUPPORT @@ -1866,7 +1894,7 @@ LRESULT CALLBACK WinProc( S9xSetPause (PAUSE_NETPLAY_CONNECT); - if (!S9xNPConnectToServer (hostname, Settings.Port, + if (!S9xNPConnectToServer (_tToChar(hostname), Settings.Port, Memory.ROMName)) { S9xClearPause (PAUSE_NETPLAY_CONNECT); @@ -2342,9 +2370,9 @@ LRESULT CALLBACK WinProc( S9xClearPause(PAUSE_MENU); break; case WM_DISPLAYCHANGE: - if (!GUI.FullScreen) + if (!GUI.FullScreen && !(Settings.ForcedPause & PAUSE_TOGGLE_FULL_SCREEN)) { - //WinDisplayReset(); + WinDisplayReset(); } break; case WM_MOUSEMOVE: @@ -2551,7 +2579,7 @@ LRESULT CALLBACK WinProc( BOOL WinInit( HINSTANCE hInstance) { WNDCLASSEX wndclass; - ZeroMemory(&wndclass, sizeof(wndclass)); + memset(&wndclass, 0, sizeof(wndclass)); wndclass.cbSize = sizeof(wndclass); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; @@ -2669,7 +2697,7 @@ VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWO } counter++; } - if(GUI.BackgroundKeyHotkeys) + if(GUI.BackgroundInput && !GUI.InactivePause) { static int counter = 0; static uint32 joyState [256]; @@ -2687,7 +2715,11 @@ VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWO PostMessage(GUI.hWnd, WM_CUSTKEYDOWN, (WPARAM)(i),(LPARAM)(NULL)); } else - joyState[i] = 0; + if(joyState[i]) + { + joyState[i] = 0; + PostMessage(GUI.hWnd, WM_CUSTKEYUP, (WPARAM)(i),(LPARAM)(NULL)); + } } counter++; } @@ -3225,6 +3257,7 @@ int WINAPI WinMain( InitRenderFilters(); GUI.ControlForced = 0xff; + GUI.rewinding = false; S9xSetRecentGames (); @@ -3266,7 +3299,7 @@ int WINAPI WinMain( Settings.StopEmulation = TRUE; GUI.hFrameTimer = timeSetEvent (20, 0, (LPTIMECALLBACK)FrameTimer, 0, TIME_PERIODIC); - if(GUI.JoystickHotkeys || GUI.BackgroundKeyHotkeys) + if(GUI.JoystickHotkeys || GUI.BackgroundInput) GUI.hHotkeyTimer = timeSetEvent (32, 0, (LPTIMECALLBACK)HotkeyTimer, 0, TIME_PERIODIC); else GUI.hHotkeyTimer = 0; @@ -3287,7 +3320,6 @@ int WINAPI WinMain( ChangeInputDevice(); DWORD lastTime = timeGetTime(); - DWORD sSyncTime,sSyncWaited; MSG msg; @@ -3404,17 +3436,25 @@ int WINAPI WinMain( { ProcessInput(); - sSyncTime=timeGetTime(); - while(!S9xSyncSound()) { - Sleep(2); - sSyncWaited=timeGetTime(); - if(sSyncWaited-sSyncTime > 1000) { - S9xClearSamples(); - break; - } + ResetEvent(GUI.SoundSyncEvent); + if(WaitForSingleObject(GUI.SoundSyncEvent,1000) != WAIT_OBJECT_0) + S9xClearSamples(); } + if(GUI.rewindBufferSize +#ifdef NETPLAY_SUPPORT + &&!Settings.NetPlay +#endif + ) { + if(GUI.rewinding) { + GUI.rewinding = stateMan.pop(); + } else { + if(IPPU.TotalEmulatedFrames % GUI.rewindGranularity == 0) + stateMan.push(); + } + } + S9xMainLoop(); GUI.FrameCount++; } @@ -3490,10 +3530,7 @@ loop_exit: void FreezeUnfreeze (int slot, bool8 freeze) { - static char filename [_MAX_PATH + 1]; - char drive [_MAX_DRIVE + 1]; - char dir [_MAX_DIR + 1]; - char fname [_MAX_FNAME + 1]; + const char *filename; char ext [_MAX_EXT + 1]; #ifdef NETPLAY_SUPPORT @@ -3505,31 +3542,8 @@ void FreezeUnfreeze (int slot, bool8 freeze) } #endif - _splitpath (Memory.ROMFilename, drive, dir, fname, ext); - strcpy(filename, ""); - static char *digits = "t123456789"; - for(int oldDir = 0; oldDir <= 1; oldDir++) - { - for(int zmv = 0; zmv <= 1; zmv++) - { - if((!oldDir && !zmv) || (!freeze && _taccess (_tFromChar(filename), 0) != 0 && slot < 10)) - { - if(!zmv) - sprintf (ext, ".%03d", slot); - else - sprintf (ext, ".zs%c", digits [slot]); - if (GUI.FreezeFileDir [0]) - { - strcpy (filename, oldDir ? S9xGetDirectory(ROMFILENAME_DIR) : S9xGetDirectory(SNAPSHOT_DIR)); - strcat (filename, "\\"); - strcat (filename, fname); - strcat (filename, ext); - } - else - _makepath (filename, drive, dir, fname, ext); - } - } - } + snprintf(ext, _MAX_EXT, ".%03d", slot); + filename = S9xGetFilename(ext,SNAPSHOT_DIR); S9xSetPause (PAUSE_FREEZE_FILE); @@ -3583,7 +3597,7 @@ static void CheckMenuStates () MENUITEMINFO mii; unsigned int i; - ZeroMemory( &mii, sizeof( mii)); + memset( &mii, 0, sizeof( mii)); mii.cbSize = sizeof( mii); mii.fMask = MIIM_STATE; @@ -3789,6 +3803,9 @@ static void CheckMenuStates () mii.fState = (GUI.SoundChannelEnable & (1 << 7)) ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo (GUI.hMenu, ID_CHANNELS_CHANNEL8, FALSE, &mii); + mii.fState = GUI.BackgroundInput ? MFS_CHECKED : MFS_UNCHECKED; + SetMenuItemInfo (GUI.hMenu, ID_EMULATION_BACKGROUNDINPUT, FALSE, &mii); + UINT validFlag; enum controllers controller[2]; int8 ids[4]; @@ -3830,7 +3847,7 @@ static void CheckMenuStates () mii.fState = !Settings.StopEmulation ? MFS_ENABLED : MFS_DISABLED; SetMenuItemInfo (GUI.hMenu, ID_FILE_AVI_RECORDING, FALSE, &mii); - ZeroMemory(&mii, sizeof(mii)); + memset(&mii, 0, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_STRING; @@ -3899,6 +3916,8 @@ static bool LoadROM(const TCHAR *filename) { else S9xNPServerQueueSendingLoadROMRequest (Memory.ROMName); #endif + if(GUI.rewindBufferSize) + stateMan.init(GUI.rewindBufferSize * 1024 * 1024); } if(GUI.ControllerOption == SNES_SUPERSCOPE) @@ -4822,7 +4841,7 @@ INT_PTR CALLBACK DlgInfoProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) case 14:strcat(romtext, "Unknown region 14");break; default:strcat(romtext, "Unknown region 15");break; } - SendDlgItemMessageA(hDlg, IDC_ROM_DATA, WM_SETTEXT, 0, (LPARAM)romtext); + SendDlgItemMessage(hDlg, IDC_ROM_DATA, WM_SETTEXT, 0, (LPARAM)((TCHAR *)_tFromChar(romtext))); break; } case WM_CTLCOLORSTATIC: @@ -4921,6 +4940,10 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP,UDM_SETPOS,0, Settings.AutoMaxSkipFrames); SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_SETRANGE, 0, MAKELPARAM((short)600, (short)0)); SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP,UDM_SETPOS,0, Settings.TurboSkipFrames); + SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)4000, (short)0)); + SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN,UDM_SETPOS,0, GUI.rewindBufferSize); + SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_SETRANGE, 0, MAKELPARAM((short)300, (short)1)); + SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN,UDM_SETPOS,0, GUI.rewindGranularity); CheckDlgButton(hDlg,IDC_TOGGLE_TURBO,GUI.TurboModeToggle ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg,IDC_INACTIVE_PAUSE,GUI.InactivePause ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hDlg,IDC_CUSTOMROMOPEN,GUI.CustomRomOpen ? BST_CHECKED : BST_UNCHECKED); @@ -4967,7 +4990,7 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar LPMALLOC lpm=NULL; LPITEMIDLIST iidl=NULL; BROWSEINFO bi; - ZeroMemory(&bi, sizeof(BROWSEINFO)); + memset(&bi, 0, sizeof(BROWSEINFO)); TCHAR path[MAX_PATH]; _tfullpath(path, paths[which], MAX_PATH); TCHAR title[]=SETTINGS_TITLE_SELECTFOLDER; @@ -5013,6 +5036,13 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar Settings.TurboSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_TURBO_SKIP, UDM_GETPOS, 0,0); Settings.AutoMaxSkipFrames=SendDlgItemMessage(hDlg, IDC_SPIN_MAX_SKIP, UDM_GETPOS, 0,0); Settings.AutoSaveDelay=SendDlgItemMessage(hDlg, IDC_SRAM_SPIN, UDM_GETPOS, 0,0); + GUI.rewindGranularity = SendDlgItemMessage(hDlg, IDC_REWIND_GRANULARITY_SPIN, UDM_GETPOS, 0,0); + if(GUI.rewindGranularity==0) GUI.rewindGranularity = 1; + unsigned int newRewindBufSize = SendDlgItemMessage(hDlg, IDC_REWIND_BUFFER_SPIN, UDM_GETPOS, 0,0); + if(GUI.rewindBufferSize != newRewindBufSize) { + GUI.rewindBufferSize = newRewindBufSize; + if(!Settings.StopEmulation) stateMan.init(GUI.rewindBufferSize * 1024 * 1024); + } WinSaveConfigFile(); } @@ -5116,6 +5146,7 @@ void rominfo(const TCHAR *filename, TCHAR *namebuffer, TCHAR *sizebuffer) lstrcpy(namebuffer, ROM_ITEM_DESCNOTAVAILABLE); lstrcpy(sizebuffer, TEXT("? Mbits")); +#ifdef ZLIB if(IsCompressed(filename)) { unzFile uf = unzOpen(_tToChar(filename)); @@ -5155,6 +5186,7 @@ void rominfo(const TCHAR *filename, TCHAR *namebuffer, TCHAR *sizebuffer) } return; } +#endif struct _stat filestats; _tstat(filename, &filestats); @@ -5293,7 +5325,7 @@ void GetPathFromTree( HWND hDlg, UINT tree, TCHAR* selected, HTREEITEM hItem) TVITEM tv; TCHAR temp[MAX_PATH]; temp[0]=('\0'); - ZeroMemory(&tv, sizeof(TVITEM)); + memset(&tv, 0, sizeof(TVITEM)); HTREEITEM hTreeTemp=hItem; if(tv.iImage==7) @@ -5302,7 +5334,7 @@ void GetPathFromTree( HWND hDlg, UINT tree, TCHAR* selected, HTREEITEM hItem) tv.hItem=hTreeTemp; tv.iImage=6; TreeView_SetItem(GetDlgItem(hDlg, tree),&tv); - ZeroMemory(&tv, sizeof(TVITEM)); + memset(&tv, 0, sizeof(TVITEM)); } tv.mask=TVIF_HANDLE|TVIF_TEXT; @@ -5360,7 +5392,7 @@ void ExpandDir(TCHAR * selected, HTREEITEM hParent, HWND hDlg) { TCHAR temp[MAX_PATH]; WIN32_FIND_DATA wfd; - ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA)); + memset(&wfd, 0, sizeof(WIN32_FIND_DATA)); lstrcat(selected, TEXT("\\*")); HANDLE hFind=FindFirstFile(selected,&wfd); selected[(lstrlen(selected)-1)]=TEXT('\0'); @@ -5373,7 +5405,7 @@ void ExpandDir(TCHAR * selected, HTREEITEM hParent, HWND hDlg) { //skip these, add the rest. TV_INSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TV_INSERTSTRUCT)); + memset(&tvis, 0, sizeof(TV_INSERTSTRUCT)); tvis.hParent=hParent; tvis.hInsertAfter=TVI_SORT; tvis.item.mask = TVIF_STATE | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE; @@ -5391,7 +5423,7 @@ void ExpandDir(TCHAR * selected, HTREEITEM hParent, HWND hDlg) bool subdir=false; WIN32_FIND_DATA wfd2; - ZeroMemory(&wfd2, sizeof(WIN32_FIND_DATA)); + memset(&wfd2, 0, sizeof(WIN32_FIND_DATA)); HANDLE hFind2=FindFirstFile(temp,&wfd2); do { @@ -5408,7 +5440,7 @@ void ExpandDir(TCHAR * selected, HTREEITEM hParent, HWND hDlg) if(subdir) { TV_INSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TV_INSERTSTRUCT)); + memset(&tvis, 0, sizeof(TV_INSERTSTRUCT)); tvis.hParent=hNewTree; tvis.hInsertAfter=TVI_SORT; TreeView_InsertItem(GetDlgItem(hDlg, IDC_ROM_DIR),&tvis); @@ -5436,7 +5468,7 @@ void ListFilesFromFolder(HWND hDlg, RomDataList** prdl) TCHAR temp[MAX_PATH]; TCHAR selected[MAX_PATH]; // directory path temp[0]='\0'; - ZeroMemory(&tv, sizeof(TVITEM)); + memset(&tv, 0, sizeof(TVITEM)); HTREEITEM hTreeItem=TreeView_GetSelection(GetDlgItem(hDlg, IDC_ROM_DIR)); GetPathFromTree(hDlg, IDC_ROM_DIR, selected, hTreeItem); @@ -5448,7 +5480,7 @@ void ListFilesFromFolder(HWND hDlg, RomDataList** prdl) //Add items here. WIN32_FIND_DATA wfd; - ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA)); + memset(&wfd, 0, sizeof(WIN32_FIND_DATA)); lstrcat(selected, TEXT("\\*")); @@ -5461,7 +5493,7 @@ void ListFilesFromFolder(HWND hDlg, RomDataList** prdl) if(ExtensionIsValid(wfd.cFileName)) { RomDataList* newitem=new RomDataList; - ZeroMemory(newitem, sizeof(RomDataList)); + memset(newitem, 0, sizeof(RomDataList)); newitem->fname=new TCHAR[1+lstrlen(wfd.cFileName)]; lstrcpy(newitem->fname, wfd.cFileName); @@ -5540,8 +5572,6 @@ INT_PTR CALLBACK DlgMultiROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar case IDOK: GetDlgItemText(hDlg, IDC_MULTICART_EDITA, multiRomA, MAX_PATH); GetDlgItemText(hDlg, IDC_MULTICART_EDITB, multiRomB, MAX_PATH); - if(*multiRomA) _tfullpath(multiRomA, multiRomA, MAX_PATH); - if(*multiRomB) _tfullpath(multiRomB, multiRomB, MAX_PATH); EndDialog(hDlg, 1); return true; case IDCANCEL: @@ -5550,21 +5580,17 @@ INT_PTR CALLBACK DlgMultiROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar case IDC_MULTICART_SWAP: GetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom2, MAX_PATH); GetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom1, MAX_PATH); - if(*rom1) _tfullpath(rom1, rom1, MAX_PATH); - if(*rom2) _tfullpath(rom2, rom2, MAX_PATH); SetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom1); SetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom2); break; case IDC_MULTICART_BROWSEA: if(!DoOpenRomDialog(rom1, true)) break; - _tfullpath(rom1, rom1, MAX_PATH); SetDlgItemText(hDlg, IDC_MULTICART_EDITA, rom1); break; case IDC_MULTICART_BROWSEB: if(!DoOpenRomDialog(rom2, true)) break; - _tfullpath(rom2, rom2, MAX_PATH); SetDlgItemText(hDlg, IDC_MULTICART_EDITB, rom2); break; case IDC_MULTICART_CLEARA: @@ -5611,7 +5637,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara RECT listRect; WNDCLASSEX wcex; TCHAR tempclassname[]=TEXT("S9xSplitter"); - ZeroMemory(&wcex, sizeof(WNDCLASSEX)); + memset(&wcex, 0, sizeof(WNDCLASSEX)); wcex.cbSize=sizeof(WNDCLASSEX); wcex.hInstance=g_hInst; wcex.lpfnWndProc=DlgChildSplitProc; @@ -5633,7 +5659,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara LVCOLUMN col; static const LPTSTR temp1 = ROM_COLUMN_FILENAME; - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH; col.fmt=LVCFMT_LEFT; col.iOrder=0; @@ -5644,7 +5670,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara ListView_InsertColumn(romList, 0, &col); static const LPTSTR temp2 = ROM_COLUMN_DESCRIPTION; - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; col.fmt=LVCFMT_LEFT; col.iOrder=1; @@ -5657,7 +5683,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara static const LPTSTR temp3 = ROM_COLUMN_SIZE; - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; col.fmt=LVCFMT_LEFT; col.iOrder=2; @@ -5745,7 +5771,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara driveName[2]='\0'; TVINSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TVINSERTSTRUCT)); + memset(&tvis, 0, sizeof(TVINSERTSTRUCT)); tvis.hParent=NULL; tvis.hInsertAfter=TVI_ROOT; @@ -5776,7 +5802,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara if(driveType==DRIVE_REMOVABLE || driveType == DRIVE_CDROM || driveType == DRIVE_UNKNOWN) { TV_INSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TV_INSERTSTRUCT)); + memset(&tvis, 0, sizeof(TV_INSERTSTRUCT)); tvis.hParent=hTwee; tvis.hInsertAfter=TVI_SORT; TreeView_InsertItem(dirList,&tvis); @@ -5785,7 +5811,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara else { WIN32_FIND_DATA wfd2; - ZeroMemory(&wfd2, sizeof(WIN32_FIND_DATA)); + memset(&wfd2, 0, sizeof(WIN32_FIND_DATA)); HANDLE hFind2=FindFirstFile(temp,&wfd2); do { @@ -5802,7 +5828,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara if(subdir) { TV_INSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TV_INSERTSTRUCT)); + memset(&tvis, 0, sizeof(TV_INSERTSTRUCT)); tvis.hParent=hTwee; tvis.hInsertAfter=TVI_SORT; TreeView_InsertItem(dirList,&tvis); @@ -5832,7 +5858,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara temp2 = temp3; TVITEM tvi; - ZeroMemory(&tvi, sizeof(TVITEM)); + memset(&tvi, 0, sizeof(TVITEM)); tvi.mask=TVIF_TEXT; tvi.pszText=blah; tvi.cchTextMax=MAX_PATH; @@ -5888,7 +5914,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara if(Memory.ROMFilename[0]!='\0') { LVFINDINFO lvfi; - ZeroMemory(&lvfi, sizeof(LVFINDINFO)); + memset(&lvfi, 0, sizeof(LVFINDINFO)); TCHAR filename[_MAX_PATH]; TCHAR *tmp, *tmp2; lstrcpy(filename,_tFromChar(Memory.ROMFilename)); @@ -6011,7 +6037,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara case IDOK: { LVITEM lvi; - ZeroMemory(&lvi, sizeof(LVITEM)); + memset(&lvi, 0, sizeof(LVITEM)); //get selections int list_index = selectionMarkOverride == -1 ? ListView_GetSelectionMark(romList) : selectionMarkOverride; if(list_index!=-1 && (int)SendMessage(romList, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED)!=-1) @@ -6029,7 +6055,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara HTREEITEM hTreeTemp=TreeView_GetSelection(dirList); TVITEM tv; - ZeroMemory(&tv, sizeof(TVITEM)); + memset(&tv, 0, sizeof(TVITEM)); tv.mask=TVIF_HANDLE|TVIF_TEXT; tv.hItem=hTreeTemp; @@ -6325,7 +6351,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara else { TVITEM tv; - ZeroMemory(&tv, sizeof(TVITEM)); + memset(&tv, 0, sizeof(TVITEM)); HTREEITEM hTreeTemp=nmTv->itemNew.hItem; if(tv.iImage==6) @@ -6338,7 +6364,7 @@ INT_PTR CALLBACK DlgOpenROMProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara TV_INSERTSTRUCT tvis; - ZeroMemory(&tvis, sizeof(TV_INSERTSTRUCT)); + memset(&tvis, 0, sizeof(TV_INSERTSTRUCT)); tvis.hParent=nmTv->itemNew.hItem; tvis.hInsertAfter=TVI_SORT; TreeView_InsertItem(dirList,&tvis); @@ -6712,7 +6738,7 @@ void LoadExts(void) ExtList* curr; valid_ext=new ExtList; curr=valid_ext; - ZeroMemory(curr, sizeof(ExtList)); + memset(curr, 0, sizeof(ExtList)); ifstream in; #if (((defined(_MSC_VER) && _MSC_VER >= 1300)) || defined(__MINGW32__)) @@ -6744,7 +6770,7 @@ void LoadExts(void) { curr->next=new ExtList; curr=curr->next; - ZeroMemory(curr, sizeof(ExtList)); + memset(curr, 0, sizeof(ExtList)); if(_strnicmp(buffer+strlen(buffer)-1, "Y", 1)==0) curr->compressed=true; if(strlen(buffer)>1) @@ -6771,10 +6797,8 @@ void MakeExtFile(void) out.open("Valid.Ext"); out<<"N" <=TEXT('0') && buffer[j]<=TEXT('9')) || (buffer[j]>=TEXT('A') && buffer[j]<=TEXT('F')) || buffer[j]==TEXT('$')) + if( (buffer[j]>='0' && buffer[j]<='9') || (buffer[j]>='A' && buffer[j]<='F') || buffer[j]=='$') { buffer2[k]=buffer[j]; k++; } else index --; } - buffer2[k]=TEXT('\0'); + buffer2[k]='\0'; - if(has_sel&&!new_sel&&0!=lstrlen(buffer2)) + if(has_sel&&!new_sel&&0!=strlen(buffer2)) SetDlgItemTextA(hDlg, IDC_CHEAT_CODE, ""); if(new_sel!=0) @@ -8767,7 +8794,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) SendMessageA((HWND)lParam, (UINT) EM_SETSEL, (WPARAM) (index), index); SendMessageA(GetDlgItem(hDlg, IDC_CHEAT_ADDRESS), WM_GETTEXT, 7,(LPARAM)buffer); - if(lstrlen(buffer2)!=0 && lstrlen(buffer) !=0) + if(strlen(buffer2)!=0 && strlen(buffer) !=0) { if(has_sel) EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), true); @@ -8809,7 +8836,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) TCHAR buf[25]; LV_ITEM lvi; - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.mask=LVIF_TEXT; lvi.pszText=buf; @@ -8820,7 +8847,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) ScanAddress(lvi.pszText, scanned); Cheat.c[l].address = scanned; - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.iSubItem=1; lvi.mask=LVIF_TEXT; @@ -8832,7 +8859,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) _stscanf(lvi.pszText, TEXT("%02X"), &scanned); Cheat.c[l].byte = (uint8)(scanned & 0xff); - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.iSubItem=2; lvi.mask=LVIF_TEXT; @@ -8858,7 +8885,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) bool8 enabled; TCHAR buf[25]; LV_ITEM lvi; - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.mask=LVIF_TEXT; lvi.pszText=buf; @@ -8869,7 +8896,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) ScanAddress(lvi.pszText, scanned); address = scanned; - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.iSubItem=1; lvi.mask=LVIF_TEXT; @@ -8885,7 +8912,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) S9xAddCheat(enabled,true,address,byte); - ZeroMemory(&lvi, sizeof(LV_ITEM)); + memset(&lvi, 0, sizeof(LV_ITEM)); lvi.iItem= k; lvi.iSubItem=2; lvi.mask=LVIF_TEXT; @@ -9095,7 +9122,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara LVCOLUMN col; TCHAR temp[32]; lstrcpy(temp,TEXT("Address")); - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH; col.fmt=LVCFMT_LEFT; col.iOrder=0; @@ -9106,7 +9133,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDYS), 0, &col); lstrcpy(temp,TEXT("Curr. Value")); - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; col.fmt=LVCFMT_LEFT; col.iOrder=1; @@ -9118,7 +9145,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDYS), 1, &col); lstrcpy(temp,TEXT("Prev. Value")); - ZeroMemory(&col, sizeof(LVCOLUMN)); + memset(&col, 0, sizeof(LVCOLUMN)); col.mask=LVCF_FMT|LVCF_ORDER|LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; col.fmt=LVCFMT_LEFT; col.iOrder=2; @@ -9510,7 +9537,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara // int idx=-1; LVITEM lvi; static TCHAR buf[12]; // the following code assumes this variable is static, I think - ZeroMemory(&cht, sizeof(struct SCheat)); + memset(&cht, 0, sizeof(struct SCheat)); //retrieve and convert to SCheat @@ -9667,7 +9694,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara lstrcpy(szFileName, TEXT("watches")); _tfullpath(szPathName, S9xGetDirectoryT(CHEAT_DIR), MAX_PATH); - ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) ); + memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) ); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GUI.hWnd; ofn.lpstrFilter = FILE_INFO_TXT_FILE_TYPE TEXT("\0*.txt\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0"); @@ -9726,7 +9753,7 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara lstrcpy(szFileName, TEXT("watches")); _tfullpath(szPathName, S9xGetDirectoryT(CHEAT_DIR), MAX_PATH); - ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) ); + memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) ); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = GUI.hWnd; ofn.lpstrFilter = FILE_INFO_TXT_FILE_TYPE TEXT("\0*.txt\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0"); @@ -10017,7 +10044,7 @@ INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP TCHAR buf[23]; int temp=new_cheat->size; S9xCheatDataSize tmp = S9X_8_BITS; - ZeroMemory(new_cheat, sizeof(struct SCheat)); + memset(new_cheat, 0, sizeof(struct SCheat)); new_cheat->size=temp; GetDlgItemText(hDlg, IDC_NC_ADDRESS, buf, 7); ScanAddress(buf, new_cheat->address); @@ -10189,8 +10216,6 @@ static void set_movieinfo(const TCHAR* path, HWND hDlg) // if(m.SyncFlags & MOVIE_SYNC_DATA_EXISTS) { - SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, (m.SyncFlags & MOVIE_SYNC_LEFTRIGHT)!=0 ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0); - SendDlgItemMessage(hDlg,IDC_SYNC_TO_SOUND_CPU,BM_SETCHECK, (m.SyncFlags & MOVIE_SYNC_SYNCSOUND)!=0 ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0); // SetWindowText(GetDlgItem(hDlg, IDC_LOADEDFROMMOVIE), _T(MOVIE_LABEL_SYNC_DATA_FROM_MOVIE)); } @@ -10331,10 +10356,6 @@ INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(LOWORD(wParam)) { - case IDC_ALLOWLEFTRIGHT: - case IDC_SYNC_TO_SOUND_CPU: - SetWindowText(GetDlgItem(hDlg, IDC_LOADEDFROMMOVIE), TEXT("")); - break; case IDC_BROWSE_MOVIE: { OPENFILENAME ofn; @@ -10342,7 +10363,7 @@ INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) szFileName[0] = TEXT('\0'); - ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) ); + memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) ); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hDlg; ofn.lpstrFilter = MOVIE_FILETYPE_DESCRIPTION TEXT("\0*.smv\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0"); @@ -10390,8 +10411,6 @@ INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) GetDlgItemText(hDlg, IDC_MOVIE_PATH, op->Path, MAX_PATH); SetCurrentDirectory(movieDirectory); } - Settings.UpAndDown = IsDlgButtonChecked(hDlg, IDC_ALLOWLEFTRIGHT); - Settings.SoundSync = IsDlgButtonChecked(hDlg, IDC_SYNC_TO_SOUND_CPU); EndDialog(hDlg, 1); return true; @@ -10459,10 +10478,6 @@ INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara SetWindowText(GetDlgItem(hDlg, IDC_MOVIE_PATH), filename); } - SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, Settings.UpAndDown ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0); - SendDlgItemMessage(hDlg,IDC_SYNC_TO_SOUND_CPU,BM_SETCHECK, Settings.SoundSync ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0); - SetWindowText(GetDlgItem(hDlg, IDC_LOADEDFROMMOVIE), _T("")); - //EnableWindow(GetDlgItem(hDlg, IDC_SYNC_TO_SOUND_CPU), Settings.SoundDriver<1||Settings.SoundDriver>3); // can't sync sound to CPU unless using "Snes9x DirectSound" driver SendDlgItemMessage(hDlg,IDC_RECORD_RESET,BM_SETCHECK, (WPARAM)(GUI.MovieStartFromReset ? BST_CHECKED : BST_UNCHECKED), 0); @@ -10495,7 +10510,7 @@ INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara szFileName[0] = TEXT('\0'); - ZeroMemory( (LPVOID)&ofn, sizeof(OPENFILENAME) ); + memset( (LPVOID)&ofn, 0, sizeof(OPENFILENAME) ); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hDlg; ofn.lpstrFilter = MOVIE_FILETYPE_DESCRIPTION TEXT("\0*.smv\0") FILE_INFO_ANY_FILE_TYPE TEXT("\0*.*\0\0"); @@ -10541,12 +10556,7 @@ INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara else GUI.MovieStartFromReset = FALSE; - Settings.UpAndDown = IsDlgButtonChecked(hDlg, IDC_ALLOWLEFTRIGHT); - Settings.SoundSync = IsDlgButtonChecked(hDlg, IDC_SYNC_TO_SOUND_CPU); - op->SyncFlags = MOVIE_SYNC_DATA_EXISTS | MOVIE_SYNC_HASROMINFO; - if(Settings.UpAndDown) op->SyncFlags |= MOVIE_SYNC_LEFTRIGHT; - if(Settings.SoundSync) op->SyncFlags |= MOVIE_SYNC_SYNCSOUND; if(IsDlgButtonChecked(hDlg, IDC_CLEARSRAM) && IsDlgButtonChecked(hDlg, IDC_RECORD_RESET) && existsSRAM()) { diff --git a/win32/wsnes9x.h b/win32/wsnes9x.h index e99aacb3..fb7c81c6 100644 --- a/win32/wsnes9x.h +++ b/win32/wsnes9x.h @@ -320,6 +320,8 @@ struct sGUI { TCHAR D3DshaderFileName[MAX_PATH]; TCHAR OGLshaderFileName[MAX_PATH]; + bool OGLdisablePBOs; + bool IgnoreNextMouseMove; RECT window_size; bool window_maximized; @@ -337,7 +339,7 @@ struct sGUI { HACCEL Accelerators; bool NeedDepthConvert; bool DepthConverted; - bool BGR; + bool TurboModeToggle; bool InactivePause; bool CustomRomOpen; @@ -353,7 +355,7 @@ struct sGUI { int ControllerOption; int ValidControllerOptions; int SoundChannelEnable; - bool BackgroundKeyHotkeys, BackgroundKeyGamekeys; + bool BackgroundInput; bool JoystickHotkeys; bool MovieClearSRAM; bool MovieStartFromReset; @@ -367,6 +369,7 @@ struct sGUI { bool Mute; // used for sync sound synchronization CRITICAL_SECTION SoundCritSect; + HANDLE SoundSyncEvent; TCHAR RomDir [_MAX_PATH]; TCHAR ScreensDir [_MAX_PATH]; @@ -392,6 +395,11 @@ struct sGUI { long FrameCount; long LastFrameCount; unsigned long IdleCount; + + // rewinding + bool rewinding; + unsigned int rewindBufferSize; + unsigned int rewindGranularity; }; //TURBO masks @@ -463,6 +471,8 @@ struct SCustomKeys { SCustomKey SelectSave [10]; SCustomKey ResetGame; SCustomKey ToggleCheats; + SCustomKey QuitS9X; + SCustomKey Rewind; }; struct SJoypad { diff --git a/win32/zlib/zlib.vcproj b/win32/zlib/zlib.vcproj index 979ff284..d14adf81 100644 --- a/win32/zlib/zlib.vcproj +++ b/win32/zlib/zlib.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + +