diff options
Diffstat (limited to 'plugins/gme/game-music-emu-0.6pre/gme/Kss_Core.cpp')
-rw-r--r-- | plugins/gme/game-music-emu-0.6pre/gme/Kss_Core.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/plugins/gme/game-music-emu-0.6pre/gme/Kss_Core.cpp b/plugins/gme/game-music-emu-0.6pre/gme/Kss_Core.cpp new file mode 100644 index 00000000..01396016 --- /dev/null +++ b/plugins/gme/game-music-emu-0.6pre/gme/Kss_Core.cpp @@ -0,0 +1,214 @@ +// Game_Music_Emu 0.6-pre. http://www.slack.net/~ant/ + +#include "Kss_Core.h" + +#include "blargg_endian.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" + +Kss_Core::Kss_Core() : rom( Kss_Cpu::page_size ) +{ + memset( unmapped_read, 0xFF, sizeof unmapped_read ); +} + +Kss_Core::~Kss_Core() { } + +void Kss_Core::unload() +{ + rom.clear(); +} + +static blargg_err_t check_kss_header( void const* header ) +{ + if ( memcmp( header, "KSCC", 4 ) && memcmp( header, "KSSX", 4 ) ) + return blargg_err_file_type; + return blargg_ok; +} + +blargg_err_t Kss_Core::load_( Data_Reader& in ) +{ + memset( &header_, 0, sizeof header_ ); + assert( offsetof (header_t,msx_audio_vol) == header_t::size - 1 ); + RETURN_ERR( rom.load( in, header_t::base_size, &header_, 0 ) ); + + RETURN_ERR( check_kss_header( header_.tag ) ); + + header_.last_track [0] = 255; + if ( header_.tag [3] == 'C' ) + { + if ( header_.extra_header ) + { + header_.extra_header = 0; + set_warning( "Unknown data in header" ); + } + if ( header_.device_flags & ~0x0F ) + { + header_.device_flags &= 0x0F; + set_warning( "Unknown data in header" ); + } + } + else if ( header_.extra_header ) + { + if ( header_.extra_header != header_.ext_size ) + { + header_.extra_header = 0; + set_warning( "Invalid extra_header_size" ); + } + else + { + memcpy( header_.data_size, rom.begin(), header_.ext_size ); + } + } + + #ifndef NDEBUG + { + int ram_mode = header_.device_flags & 0x84; // MSX + if ( header_.device_flags & 0x02 ) // SMS + ram_mode = (header_.device_flags & 0x88); + + if ( ram_mode ) + dprintf( "RAM not supported\n" ); // TODO: support + } + #endif + + return blargg_ok; +} + +void Kss_Core::jsr( byte const (&addr) [2] ) +{ + ram [--cpu.r.sp] = idle_addr >> 8; + ram [--cpu.r.sp] = idle_addr & 0xFF; + cpu.r.pc = get_le16( addr ); +} + +blargg_err_t Kss_Core::start_track( int track ) +{ + memset( ram, 0xC9, 0x4000 ); + memset( ram + 0x4000, 0, sizeof ram - 0x4000 ); + + // copy driver code to lo RAM + static byte const bios [] = { + 0xD3, 0xA0, 0xF5, 0x7B, 0xD3, 0xA1, 0xF1, 0xC9, // $0001: WRTPSG + 0xD3, 0xA0, 0xDB, 0xA2, 0xC9 // $0009: RDPSG + }; + static byte const vectors [] = { + 0xC3, 0x01, 0x00, // $0093: WRTPSG vector + 0xC3, 0x09, 0x00, // $0096: RDPSG vector + }; + memcpy( ram + 0x01, bios, sizeof bios ); + memcpy( ram + 0x93, vectors, sizeof vectors ); + + // copy non-banked data into RAM + int load_addr = get_le16( header_.load_addr ); + int orig_load_size = get_le16( header_.load_size ); + int load_size = min( orig_load_size, rom.file_size() ); + load_size = min( load_size, (int) mem_size - load_addr ); + if ( load_size != orig_load_size ) + set_warning( "Excessive data size" ); + memcpy( ram + load_addr, rom.begin() + header_.extra_header, load_size ); + + rom.set_addr( -load_size - header_.extra_header ); + + // check available bank data + int const bank_size = this->bank_size(); + int max_banks = (rom.file_size() - load_size + bank_size - 1) / bank_size; + bank_count = header_.bank_mode & 0x7F; + if ( bank_count > max_banks ) + { + bank_count = max_banks; + set_warning( "Bank data missing" ); + } + //dprintf( "load_size : $%X\n", load_size ); + //dprintf( "bank_size : $%X\n", bank_size ); + //dprintf( "bank_count: %d (%d claimed)\n", bank_count, header_.bank_mode & 0x7F ); + + ram [idle_addr] = 0xFF; + cpu.reset( unmapped_write, unmapped_read ); + cpu.map_mem( 0, mem_size, ram, ram ); + + cpu.r.sp = 0xF380; + cpu.r.b.a = track; + cpu.r.b.h = 0; + next_play = play_period; + gain_updated = false; + jsr( header_.init_addr ); + + return blargg_ok; +} + +void Kss_Core::set_bank( int logical, int physical ) +{ + int const bank_size = this->bank_size(); + + int addr = 0x8000; + if ( logical && bank_size == 8 * 1024 ) + addr = 0xA000; + + physical -= header_.first_bank; + if ( (unsigned) physical >= (unsigned) bank_count ) + { + byte* data = ram + addr; + cpu.map_mem( addr, bank_size, data, data ); + } + else + { + int phys = physical * bank_size; + for ( int offset = 0; offset < bank_size; offset += cpu.page_size ) + cpu.map_mem( addr + offset, cpu.page_size, + unmapped_write, rom.at_addr( phys + offset ) ); + } +} + +void Kss_Core::cpu_out( time_t, addr_t addr, int data ) +{ + dprintf( "OUT $%04X,$%02X\n", addr, data ); +} + +int Kss_Core::cpu_in( time_t, addr_t addr ) +{ + dprintf( "IN $%04X\n", addr ); + return 0xFF; +} + +blargg_err_t Kss_Core::end_frame( time_t end ) +{ + while ( cpu.time() < end ) + { + time_t next = min( end, next_play ); + run_cpu( 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 ) + { + if ( !gain_updated ) + { + gain_updated = true; + update_gain(); + } + + jsr( header_.play_addr ); + } + } + } + + next_play -= end; + check( next_play >= 0 ); + cpu.adjust_time( -end ); + + return blargg_ok; +} |