void Nsf_Impl::write_bank( int bank, int data ) { // Find bank in ROM int offset = rom.mask_addr( data * bank_size ); if ( offset >= rom.size() ) special_event( "invalid bank" ); void const* rom_data = rom.at_addr( offset ); #if !NSF_EMU_APU_ONLY if ( bank < bank_count - fds_banks && fds_enabled() ) { // TODO: FDS bank switching is kind of hacky, might need to // treat ROM as RAM so changes won't get lost when switching. byte* out = sram(); if ( bank >= fds_banks ) { out = fdsram(); bank -= fds_banks; } memcpy( &out [bank * bank_size], rom_data, bank_size ); return; } #endif if ( bank >= fds_banks ) cpu.map_code( (bank + 6) * bank_size, bank_size, rom_data ); }
void Nsf_Impl::map_memory() { // Map standard things cpu.reset( unmapped_code() ); cpu.map_code( 0, 0x2000, low_ram, low_ram_size ); // mirrored four times cpu.map_code( sram_addr, sram_size, sram() ); // Determine initial banks byte banks [bank_count]; static byte const zero_banks [sizeof header_.banks] = { 0 }; if ( memcmp( header_.banks, zero_banks, sizeof zero_banks ) ) { banks [0] = header_.banks [6]; banks [1] = header_.banks [7]; memcpy( banks + fds_banks, header_.banks, sizeof header_.banks ); } else { // No initial banks, so assign them based on load_addr int first_bank = (get_addr( header_.load_addr ) - sram_addr) / bank_size; unsigned total_banks = rom.size() / bank_size; for ( int i = bank_count; --i >= 0; ) { int bank = i - first_bank; if ( (unsigned) bank >= total_banks ) bank = 0; banks [i] = bank; } } // Map banks for ( int i = (fds_enabled() ? 0 : fds_banks); i < bank_count; ++i ) write_bank( i, banks [i] ); // Map FDS RAM if ( fds_enabled() ) cpu.map_code( rom_addr, fdsram_size, fdsram() ); }
blargg_err_t Nsf_Impl::load_( Data_Reader& in ) { // pad ROM data with 0 RETURN_ERR( rom.load( in, header_.size, &header_, 0 ) ); if ( !header_.valid_tag() ) return blargg_err_file_type; RETURN_ERR( high_ram.resize( (fds_enabled() ? fdsram_offset + fdsram_size : fdsram_offset) ) ); addr_t load_addr = get_addr( header_.load_addr ); if ( load_addr < (fds_enabled() ? sram_addr : rom_addr) ) set_warning( "Load address is too low" ); rom.set_addr( load_addr % bank_size ); if ( header_.vers != 1 ) set_warning( "Unknown file version" ); set_play_period( header_.play_period() ); return blargg_ok; }
void Nsf_Impl::write_mem( addr_t addr, int data ) { (void) LOG_MEM( addr, "<", data ); int offset = addr - sram_addr; if ( (unsigned) offset < sram_size ) { sram() [offset] = data; } else { // after sram because CPU handles most low_ram accesses internally already int temp = addr & (low_ram_size-1); // also handles wrap-around if ( !(addr & 0xE000) ) { low_ram [temp] = data; } else { int bank = addr - banks_addr; if ( (unsigned) bank < bank_count ) { write_bank( bank, data ); } else if ( (unsigned) (addr - apu.io_addr) < apu.io_size ) { apu.write_register( time(), addr, data ); } else { #if !NSF_EMU_APU_ONLY // 0x8000-0xDFFF is writable int i = addr - 0x8000; if ( (unsigned) i < fdsram_size && fds_enabled() ) fdsram() [i] = data; else #endif cpu_write( addr, data ); } } } }