summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp')
-rw-r--r--plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp225
1 files changed, 225 insertions, 0 deletions
diff --git a/plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp b/plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp
new file mode 100644
index 00000000..01c8ae4f
--- /dev/null
+++ b/plugins/gme/game-music-emu-0.6pre/gme/Sgc_Impl.cpp
@@ -0,0 +1,225 @@
+// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/
+
+#include "Sgc_Impl.h"
+
+/* Copyright (C) 2006-2009 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 const* Sgc_Impl::coleco_bios;
+
+Sgc_Impl::Sgc_Impl() :
+ rom( bank_size )
+{
+ assert( offsetof (header_t,copyright [32]) == header_t::size );
+}
+
+Sgc_Impl::~Sgc_Impl()
+{ }
+
+bool Sgc_Impl::header_t::valid_tag() const
+{
+ return 0 == memcmp( tag, "SGC\x1A", 4 );
+}
+
+blargg_err_t Sgc_Impl::load_( Data_Reader& in )
+{
+ RETURN_ERR( rom.load( in, header_.size, &header_, 0 ) );
+
+ if ( !header_.valid_tag() )
+ return blargg_err_file_type;
+
+ if ( header_.vers != 1 )
+ set_warning( "Unknown file version" );
+
+ if ( header_.system > 2 )
+ set_warning( "Unknown system" );
+
+ addr_t load_addr = get_le16( header_.load_addr );
+ if ( load_addr < 0x400 )
+ set_warning( "Invalid load address" );
+
+ rom.set_addr( load_addr );
+ play_period = clock_rate() / 60;
+
+ if ( sega_mapping() )
+ {
+ RETURN_ERR( ram.resize( 0x2000 + Sgc_Cpu::page_padding ) );
+ RETURN_ERR( ram2.resize( bank_size + Sgc_Cpu::page_padding ) );
+ }
+ else
+ {
+ RETURN_ERR( ram.resize( 0x400 + Sgc_Cpu::page_padding ) );
+ }
+
+ RETURN_ERR( vectors.resize( Sgc_Cpu::page_size + Sgc_Cpu::page_padding ) );
+
+ // TODO: doesn't need to be larger than page size, if we do mapping calls right
+ RETURN_ERR( unmapped_write.resize( bank_size ) );
+
+ return blargg_ok;
+}
+
+void Sgc_Impl::unload()
+{
+ rom.clear();
+ vectors.clear();
+ ram.clear();
+ ram2.clear();
+ unmapped_write.clear();
+ Gme_Loader::unload();
+}
+
+blargg_err_t Sgc_Impl::start_track( int track )
+{
+ memset( ram .begin(), 0, ram .size() );
+ memset( ram2.begin(), 0, ram2.size() );
+ memset( vectors.begin(), 0xFF, vectors.size() );
+ cpu.reset( unmapped_write.begin(), rom.unmapped() );
+
+ if ( sega_mapping() )
+ {
+ vectors_addr = 0x10000 - Sgc_Cpu::page_size;
+ idle_addr = vectors_addr;
+ for ( int i = 1; i < 8; ++i )
+ {
+ vectors [i*8 + 0] = 0xC3; // JP addr
+ vectors [i*8 + 1] = header_.rst_addrs [i*2 + 0];
+ vectors [i*8 + 2] = header_.rst_addrs [i*2 + 1];
+ }
+
+ cpu.map_mem( 0xC000, 0x2000, ram.begin() );
+ cpu.map_mem( vectors_addr, cpu.page_size, unmapped_write.begin(), vectors.begin() );
+
+ bank2 = NULL;
+ for ( int i = 0; i < 4; ++i )
+ cpu_write( 0xFFFC + i, header_.mapping [i] );
+ }
+ else
+ {
+ if ( !coleco_bios )
+ return BLARGG_ERR( BLARGG_ERR_CALLER, "Coleco BIOS not set" );
+
+ vectors_addr = 0;
+ cpu.map_mem( 0, 0x2000, unmapped_write.begin(), coleco_bios );
+ for ( int i = 0; i < 8; ++i )
+ cpu.map_mem( 0x6000 + i*0x400, 0x400, ram.begin() );
+
+ idle_addr = 0x2000;
+ cpu.map_mem( 0x2000, cpu.page_size, unmapped_write.begin(), vectors.begin() );
+
+ for ( int i = 0; i < 0x8000 / bank_size; ++i )
+ {
+ int addr = 0x8000 + i*bank_size;
+ cpu.map_mem( addr, bank_size, unmapped_write.begin(), rom.at_addr( addr ) );
+ }
+ }
+
+ cpu.r.sp = get_le16( header_.stack_ptr );
+ cpu.r.b.a = track;
+ next_play = play_period;
+
+ jsr( header_.init_addr );
+
+ return blargg_ok;
+}
+
+// Emulation
+
+void Sgc_Impl::jsr( byte const (&addr) [2] )
+{
+ *cpu.write( --cpu.r.sp ) = idle_addr >> 8;
+ *cpu.write( --cpu.r.sp ) = idle_addr & 0xFF;
+ cpu.r.pc = get_le16( addr );
+}
+
+void Sgc_Impl::set_bank( int bank, void const* data )
+{
+ //dprintf( "map bank %d to %p\n", bank, (byte*) data - rom.at_addr( 0 ) );
+ cpu.map_mem( bank * bank_size, bank_size, unmapped_write.begin(), data );
+}
+
+void Sgc_Impl::cpu_write( addr_t addr, int data )
+{
+ if ( (addr ^ 0xFFFC) > 3 || !sega_mapping() )
+ {
+ *cpu.write( addr ) = data;
+ return;
+ }
+
+ switch ( addr )
+ {
+ case 0xFFFC:
+ cpu.map_mem( 2 * bank_size, bank_size, ram2.begin() );
+ if ( data & 0x08 )
+ break;
+
+ bank2 = ram2.begin();
+ // FALL THROUGH
+
+ case 0xFFFF: {
+ bool rom_mapped = (cpu.read( 2 * bank_size ) == bank2);
+ bank2 = rom.at_addr( data * bank_size );
+ if ( rom_mapped )
+ set_bank( 2, bank2 );
+ break;
+ }
+
+ case 0xFFFD:
+ set_bank( 0, rom.at_addr( data * bank_size ) );
+ break;
+
+ case 0xFFFE:
+ set_bank( 1, rom.at_addr( data * bank_size ) );
+ break;
+ }
+}
+
+int Sgc_Impl::cpu_in( addr_t addr )
+{
+ dprintf( "in %02X\n", addr );
+ return 0;
+}
+
+void Sgc_Impl::cpu_out( time_t, addr_t addr, int )
+{
+ dprintf( "out %02X\n", addr & 0xFF );
+}
+
+blargg_err_t Sgc_Impl::end_frame( time_t end )
+{
+ while ( cpu.time() < end )
+ {
+ time_t next = min( end, next_play );
+ if ( run_cpu( next ) )
+ {
+ set_warning( "Unsupported CPU instruction" );
+ cpu.set_time( next );
+ }
+
+ if ( cpu.r.pc == idle_addr )
+ cpu.set_time( next );
+
+ if ( cpu.time() >= next_play )
+ {
+ next_play += play_period;
+ if ( cpu.r.pc == idle_addr )
+ jsr( header_.play_addr );
+ }
+ }
+
+ next_play -= end;
+ check( next_play >= 0 );
+ cpu.adjust_time( -end );
+
+ return blargg_ok;
+}