blargg_err_t Sap_Emu::start_track_( int track ) { RETURN_ERR( Classic_Emu::start_track_( track ) ); core.setup_ram(); // Copy file data to RAM byte const* in = info_.rom_data; while ( file_end - in >= 5 ) { int start = get_le16( in ); int end = get_le16( in + 2 ); //dprintf( "Block $%04X-$%04X\n", start, end ); in += 4; int len = end - start + 1; if ( (unsigned) len > (unsigned) (file_end - in) ) { set_warning( "Invalid file data block" ); break; } memcpy( core.ram() + start, in, len ); in += len; if ( file_end - in >= 2 && in [0] == 0xFF && in [1] == 0xFF ) in += 2; } return core.start_track( track, info_ ); }
void Hes_Emu::cpu_write_vdp( int addr, int data ) { switch ( addr ) { case 0: vdp.latch = data & 0x1F; break; case 2: if ( vdp.latch == 5 ) { if ( data & 0x04 ) set_warning( "Scanline interrupt unsupported" ); run_until( time() ); vdp.control = data; irq_changed(); } else { debug_printf( "VDP not supported: $%02X <- $%02X\n", vdp.latch, data ); } break; case 3: debug_printf( "VDP MSB not supported: $%02X <- $%02X\n", vdp.latch, data ); break; } }
blargg_err_t Hes_Emu::run_clocks( blip_time_t& duration_, int ) { blip_time_t const duration = duration_; // cache if ( cpu::run( duration ) ) set_warning( "Emulation error (illegal instruction)" ); check( time() >= duration ); //check( time() - duration < 20 ); // Txx instruction could cause going way over run_until( duration ); // end time frame timer.last_time -= duration; vdp.next_vbl -= duration; #if GME_FRAME_HOOK_DEFINED last_frame_hook -= duration; #endif cpu::end_frame( duration ); ::adjust_time( irq.timer, duration ); ::adjust_time( irq.vdp, duration ); apu.end_frame( duration ); return 0; }
blargg_err_t Ay_Emu::load_mem_( byte const in [], int size ) { assert( offsetof (header_t,track_info [2]) == header_t::size ); RETURN_ERR( parse_header( in, size, &file ) ); set_track_count( file.header->max_track + 1 ); if ( file.header->vers > 2 ) set_warning( "Unknown file version" ); int const osc_count = Ay_Apu::osc_count + 1; // +1 for beeper set_voice_count( osc_count ); core.apu().volume( gain() ); static const char* const names [osc_count] = { "Wave 1", "Wave 2", "Wave 3", "Beeper" }; set_voice_names( names ); static int const types [osc_count] = { wave_type+0, wave_type+1, wave_type+2, mixed_type+1 }; set_voice_types( types ); return setup_buffer( spectrum_clock ); }
blargg_err_t Sap_Emu::load_mem_( byte const in [], int size ) { file_end = in + size; info_.warning = NULL; info_.type = 'B'; info_.stereo = false; info_.init_addr = -1; info_.play_addr = -1; info_.music_addr = -1; info_.fastplay = 312; RETURN_ERR( parse_info( in, size, &info_ ) ); set_warning( info_.warning ); set_track_count( info_.track_count ); set_voice_count( Sap_Apu::osc_count << info_.stereo ); core.apu_impl().volume( gain() ); static const char* const names [Sap_Apu::osc_count * 2] = { "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Wave 5", "Wave 6", "Wave 7", "Wave 8", }; set_voice_names( names ); static int const types [Sap_Apu::osc_count * 2] = { wave_type+1, wave_type+2, wave_type+3, wave_type+0, wave_type+5, wave_type+6, wave_type+7, wave_type+4, }; set_voice_types( types ); return setup_buffer( 1773447 ); }
blargg_err_t Gme_File::load_m3u_( blargg_err_t err ) { if ( !err ) { require( raw_track_count_ ); // file must be loaded first if ( playlist.size() ) track_count_ = playlist.size(); int line = playlist.first_error(); if ( line ) { // avoid using bloated printf() char* out = &playlist_warning [sizeof playlist_warning]; *--out = 0; do { *--out = line % 10 + '0'; } while ( (line /= 10) > 0 ); static const char str [] = "Problem in m3u at line "; out -= sizeof str - 1; memcpy( out, str, sizeof str - 1 ); set_warning( out ); } } return err; }
blargg_err_t Sap_Emu::start_track_( int track ) { RETURN_ERR( Classic_Emu::start_track_( track ) ); memset( &mem, 0, sizeof mem ); byte const* in = info.rom_data; while ( file_end - in >= 5 ) { unsigned start = get_le16( in ); unsigned end = get_le16( in + 2 ); //debug_printf( "Block $%04X-$%04X\n", start, end ); in += 4; if ( end < start ) { set_warning( "Invalid file data block" ); break; } long len = end - start + 1; if ( len > file_end - in ) { set_warning( "Invalid file data block" ); break; } memcpy( mem.ram + start, in, len ); in += len; if ( file_end - in >= 2 && in [0] == 0xFF && in [1] == 0xFF ) in += 2; } apu.reset( &apu_impl ); apu2.reset( &apu_impl ); cpu::reset( mem.ram ); time_mask = 0; // disables sound during init call_init( track ); time_mask = -1; next_play = play_period(); return 0; }
blargg_err_t load_( Data_Reader& in ) { blargg_err_t err = in.read( &h, Nsf_Emu::header_size ); if ( err ) return (err == in.eof_error ? gme_wrong_file_type : err); if ( h.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) ) set_warning( "Uses unsupported audio expansion hardware" ); set_track_count( h.track_count ); return check_nsf_header( &h ); }
blargg_err_t Hes_Emu::load_( Data_Reader& in ) { assert( offsetof (header_t,unused [4]) == header_size ); RETURN_ERR( rom.load( in, header_size, &header_, unmapped ) ); RETURN_ERR( check_hes_header( header_.tag ) ); if ( header_.vers != 0 ) set_warning( "Unknown file version" ); if ( memcmp( header_.data_tag, "DATA", 4 ) ) set_warning( "Data header missing" ); if ( memcmp( header_.unused, "\0\0\0\0", 4 ) ) set_warning( "Unknown header data" ); // File spec supports multiple blocks, but I haven't found any, and // many files have bad sizes in the only block, so it's simpler to // just try to load the damn data as best as possible. long addr = get_le32( header_.addr ); long size = get_le32( header_.size ); long const rom_max = 0x100000; if ( addr & ~(rom_max - 1) ) { set_warning( "Invalid address" ); addr &= rom_max - 1; } if ( (unsigned long) (addr + size) > (unsigned long) rom_max ) set_warning( "Invalid size" ); if ( size != rom.file_size() ) { if ( size <= rom.file_size() - 4 && !memcmp( rom.begin() + size, "DATA", 4 ) ) set_warning( "Multiple DATA not supported" ); else if ( size < rom.file_size() ) set_warning( "Extra file data" ); else set_warning( "Missing file data" ); } rom.set_addr( addr ); set_voice_count( apu.osc_count ); apu.volume( gain() ); return setup_buffer( 7159091 ); }
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; }
blargg_err_t Sgc_Core::end_frame( time_t t ) { RETURN_ERR( Sgc_Impl::end_frame( t ) ); apu_.end_frame( t ); if ( sega_mapping() && fm_accessed ) { if ( fm_apu_.supported() ) fm_apu_.end_frame( t ); else set_warning( "FM sound not supported" ); } return blargg_ok; }
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; }
blargg_err_t Ay_Emu::load_mem_( byte const* in, long size ) { assert( offsetof (header_t,track_info [2]) == header_size ); RETURN_ERR( parse_header( in, size, &file ) ); set_track_count( file.header->max_track + 1 ); if ( file.header->vers > 2 ) set_warning( "Unknown file version" ); set_voice_count( osc_count ); apu.volume( gain() ); return setup_buffer( spectrum_clock ); }
blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int ) { set_time( 0 ); while ( time() < duration ) { nes_time_t end = min( next_play, duration ); end = min( end, time() + 32767 ); // allows CPU to use 16-bit time delta if ( cpu::run( end ) ) { if ( r.pc != badop_addr ) { set_warning( "Emulation error (illegal instruction)" ); r.pc++; } else { play_ready = 1; if ( saved_state.pc != badop_addr ) { cpu::r = saved_state; saved_state.pc = badop_addr; } else { set_time( end ); } } } if ( time() >= next_play ) { nes_time_t period = (play_period + play_extra) / clock_divisor; play_extra = play_period - period * clock_divisor; next_play += period; if ( play_ready && !--play_ready ) { check( saved_state.pc == badop_addr ); if ( r.pc != badop_addr ) saved_state = cpu::r; r.pc = play_addr; low_mem [0x100 + r.sp--] = (badop_addr - 1) >> 8; low_mem [0x100 + r.sp--] = (badop_addr - 1) & 0xFF; GME_FRAME_HOOK( this ); } }
blargg_err_t Sap_Emu::load_mem_( byte const* in, long size ) { file_end = in + size; info.warning = 0; info.type = 'B'; info.stereo = false; info.init_addr = -1; info.play_addr = -1; info.music_addr = -1; info.fastplay = 312; RETURN_ERR( parse_info( in, size, &info ) ); set_warning( info.warning ); set_track_count( info.track_count ); set_voice_count( Sap_Apu::osc_count << info.stereo ); apu_impl.volume( gain() ); return setup_buffer( 1773447 ); }
blargg_err_t Gbs_Emu::load_( Data_Reader& in ) { RETURN_ERR( core_.load( in ) ); set_warning( core_.warning() ); set_track_count( header().track_count ); set_voice_count( Gb_Apu::osc_count ); core_.apu().volume( gain() ); static const char* const names [Gb_Apu::osc_count] = { "Square 1", "Square 2", "Wave", "Noise" }; set_voice_names( names ); static int const types [Gb_Apu::osc_count] = { wave_type+1, wave_type+2, wave_type+3, mixed_type+1 }; set_voice_types( types ); return setup_buffer( 4194304 ); }
blargg_err_t Nsf_Impl::start_track( int track ) { int speed_flags = 0; #if NSF_EMU_EXTRA_FLAGS speed_flags = header().speed_flags; #endif apu.reset( header().pal_only(), (speed_flags & 0x20) ? 0x3F : 0 ); apu.enable_w4011_( enable_w4011 ); apu.write_register( 0, 0x4015, 0x0F ); apu.write_register( 0, 0x4017, (speed_flags & 0x10) ? 0x80 : 0 ); // Clear memory memset( unmapped_code(), Nes_Cpu::halt_opcode, unmapped_size ); memset( low_ram, 0, low_ram_size ); memset( sram(), 0, sram_size ); map_memory(); // Arrange time of first call to play routine play_extra = 0; next_play = play_period; play_delay = initial_play_delay; saved_state.pc = idle_addr; // Setup for call to init routine cpu.r.a = track; cpu.r.x = header_.pal_only(); cpu.r.sp = 0xFF; jsr_then_stop( header_.init_addr ); if ( cpu.r.pc < get_addr( header_.load_addr ) ) set_warning( "Init address < load address" ); return blargg_ok; }
blargg_err_t Kss_Emu::load_( Data_Reader& in ) { RETURN_ERR( core.load( in ) ); set_warning( core.warning() ); set_track_count( get_le16( header().last_track ) + 1 ); core.scc_enabled = false; if ( header().device_flags & 0x02 ) // Sega Master System { int const osc_count = Sms_Apu::osc_count + Opl_Apu::osc_count; static const char* const names [osc_count] = { "Square 1", "Square 2", "Square 3", "Noise", "FM" }; set_voice_names( names ); static int const types [osc_count] = { wave_type+1, wave_type+3, wave_type+2, mixed_type+1, wave_type+0 }; set_voice_types( types ); // sms.psg set_voice_count( Sms_Apu::osc_count ); check( !core.sms.psg ); CHECK_ALLOC( core.sms.psg = BLARGG_NEW Sms_Apu ); // sms.fm if ( header().device_flags & 0x01 ) { set_voice_count( osc_count ); RETURN_ERR( new_opl_apu( Opl_Apu::type_smsfmunit, &core.sms.fm ) ); } } else // MSX { int const osc_count = Ay_Apu::osc_count + Opl_Apu::osc_count; static const char* const names [osc_count] = { "Square 1", "Square 2", "Square 3", "FM" }; set_voice_names( names ); static int const types [osc_count] = { wave_type+1, wave_type+3, wave_type+2, wave_type+0 }; set_voice_types( types ); // msx.psg set_voice_count( Ay_Apu::osc_count ); check( !core.msx.psg ); CHECK_ALLOC( core.msx.psg = BLARGG_NEW Ay_Apu ); if ( header().device_flags & 0x10 ) set_warning( "MSX stereo not supported" ); // msx.music if ( header().device_flags & 0x01 ) { set_voice_count( osc_count ); RETURN_ERR( new_opl_apu( Opl_Apu::type_msxmusic, &core.msx.music ) ); } // msx.audio if ( header().device_flags & 0x08 ) { set_voice_count( osc_count ); RETURN_ERR( new_opl_apu( Opl_Apu::type_msxaudio, &core.msx.audio ) ); } if ( !(header().device_flags & 0x80) ) { if ( !(header().device_flags & 0x84) ) core.scc_enabled = core.scc_enabled_true; // msx.scc check( !core.msx.scc ); CHECK_ALLOC( core.msx.scc = BLARGG_NEW Scc_Apu ); int const osc_count = Ay_Apu::osc_count + Scc_Apu::osc_count; static const char* const names [osc_count] = { "Square 1", "Square 2", "Square 3", "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Wave 5" }; set_voice_names( names ); static int const types [osc_count] = { wave_type+1, wave_type+3, wave_type+2, wave_type+0, wave_type+4, wave_type+5, wave_type+6, wave_type+7, }; set_voice_types( types ); set_voice_count( osc_count ); } } set_silence_lookahead( 6 ); if ( core.sms.fm || core.msx.music || core.msx.audio ) { if ( !Opl_Apu::supported() ) set_warning( "FM sound not supported" ); else set_silence_lookahead( 3 ); // Opl_Apu is really slow } return setup_buffer( ::clock_rate ); }
configuration::configuration(const char* file_name) { _warning = false; _file_name = std::string(file_name); FILE* fd = ::fopen(file_name, "rb"); if (fd == nullptr) { printf("Cannot open file %s, err=%s", file_name, strerror(errno)); return; } ::fseek(fd, 0, SEEK_END); int len = ftell(fd); if (len == -1 || len == 0) { printf("Cannot get length of %s, err=%s", file_name, strerror(errno)); ::fclose(fd); return; } int fileLength = len; _file_data.reset((char*)malloc(len+1)); char* fileData = _file_data.get(); ::fseek(fd, 0, SEEK_SET); auto sz = ::fread(fileData, len, 1, fd); ::fclose(fd); if (sz != 1) { printf("Cannot read correct data of %s, err=%s", file_name, strerror(errno)); return; } ((char*)fileData)[fileLength] = '\n'; // // parse mapped file and build conf map // std::map<std::string, conf>* pSection = nullptr; char *p, *pLine = (char*)"", *pNextLine, *pEnd, *pSectionName = nullptr, *pEqual; int lineno = 0; unsigned int indexInSection = 0; p = (char*)fileData; pEnd = p + fileLength; while (p < pEnd) { // // get line // lineno++; while (*p == ' ' || *p == '\t' || *p == '\r') p++; pLine = p; int shift = 0; while (*p != '\n' && p < pEnd) { if (*p == '#' || *p == ';') { if (p != pLine && *(p-1) == '^') { shift++; } else { *p = '\0'; } } if (shift > 0) { *(p-shift) = *p; } p++; } *(p-shift) = '\0'; pNextLine = ++p; // // parse line // p = pLine; if (*p == '\0') goto Next; // skip comment line or empty line pEqual = strchr(p, '='); if (nullptr == pEqual && *p != '[') { goto ConfReg; } if (nullptr != pEqual && *p == '[') goto err; // // conf // if (pEqual) { ConfReg: if (pSection == nullptr) { printf("configuration section not defined"); goto err; } if (pEqual) *pEqual = '\0'; char* pKey = utils::trim_string(p); char* pValue = pEqual ? utils::trim_string(++pEqual) : nullptr; if (*pKey == '\0') goto err; if (pSection->find((const char*)pKey) != pSection->end()) { auto it = pSection->find((const char*)pKey); printf("Warning: skip redefinition of option [%s] %s (line %u), already defined as [%s] %s (line %u)\n", pSectionName, pKey, lineno, it->second.section, it->second.key, it->second.line ); } else { conf cf; cf.section = (const char*)pSectionName; cf.key = (const char*)pKey; cf.value = pValue; cf.line = lineno; pSection->insert(std::make_pair(std::string(pKey), cf)); } } // // section // else { char* pRight = strchr(p, ']'); if (nullptr == pRight) goto err; *pRight = '\0'; p++; pSectionName = utils::trim_string(p); if (*pSectionName == '\0') goto err; bool old = set_warning(false); if (has_section((const char*)pSectionName)) { printf("RedefInition of section %s\n", pSectionName); set_warning(old); goto err; } set_warning(old); std::map<std::string, conf> sm; auto it = _configs.insert(config_map::value_type(std::string(pSectionName), sm)); assert (it.second); pSection = &it.first->second; indexInSection = 0; } // // iterate nextline // Next: p = pNextLine; } return; err: printf("Unexpected configure in %s(line %d): %s\n", file_name, lineno, pLine); exit(-2); }
int main (int argc, char **argv) { /* Local Vars */ int ret; int i; unsigned int len; gnutls_x509_crt_t cert[1]; char *subject = NULL; size_t subject_len; time_t expiration_time, activation_time; /* Set signal handling and alarm */ if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) critical("Setup SIGALRM trap failed!"); /* Process check arguments */ if (process_arguments(argc, argv) != OK) unknown("Parsing arguments failed!"); /* Start plugin timeout */ alarm(mp_timeout); /* Init GnuTLS */ gnutls_global_init(); for(i = 0; i < cert_files; i++) { if (mp_verbose) printf("Cert: %s\n", cert_file[i]); /* Read the Cert */ gnutls_datum_t data = { NULL, 0 }; ret = mp_slurp(cert_file[i], &(data.data)); data.size = ret; if (ret <= 0) { set_critical("Error loading cert file '%s'.", cert_file[i]); continue; } /* Load the Cert to a list. */ len = 1; ret = gnutls_x509_crt_list_import(cert, &len, &data, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); if (ret < 0) { set_critical("%s error: %s", cert_file[i], gnutls_strerror(ret)); continue; }; /* Read der Cert CN */ if (subject == NULL) { subject = mp_malloc(128); subject_len = 128; } ret = gnutls_x509_crt_get_dn_by_oid(cert[0], GNUTLS_OID_X520_COMMON_NAME, 0, 0, subject, &subject_len); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { subject_len+=1; subject = mp_realloc(subject, subject_len); ret = gnutls_x509_crt_get_dn_by_oid(cert[0], GNUTLS_OID_X520_COMMON_NAME, 0, 0, subject, &subject_len); } if (ret != 0) { set_critical("%s error: %s", cert_file[i], gnutls_strerror(ret)); continue; } if (mp_verbose) { printf(" * Subject: %s\n", subject); } /* Check expire time */ expiration_time = gnutls_x509_crt_get_expiration_time (cert[0]); activation_time = gnutls_x509_crt_get_activation_time (cert[0]); if (mp_verbose) { printf (" * Certificate is valid since: %s", ctime (&activation_time)); printf (" * Certificate expires: %s", ctime (&expiration_time)); } int days = (int)difftime(expiration_time, time(0))/86400; switch (get_status((expiration_time-time(0)), expire_thresholds)) { case STATE_OK: set_ok(cert_file[i]); break; case STATE_WARNING: set_warning("%s expires in %d day%s", cert_file[i], days, days==1?"":"s"); break; case STATE_CRITICAL: set_critical("%s expires in %d day%s", cert_file[i], days, days==1?"":"s"); break; } if (activation_time > time(0)) { int days = (int)difftime(activation_time, time(0))/86400; set_critical("%s activates in %d day%s", cert_file[i], days, days==1?"":"s"); } } // Dissconnect gnutls_global_deinit (); mp_exit("X509"); }
blargg_err_t Nsf_Emu::load_( Data_Reader& in ) { assert( offsetof (header_t,unused [4]) == header_size ); RETURN_ERR( rom.load( in, header_size, &header_, 0 ) ); set_track_count( header_.track_count ); RETURN_ERR( check_nsf_header( &header_ ) ); if ( header_.vers != 1 ) set_warning( "Unknown file version" ); // sound and memory blargg_err_t err = init_sound(); if ( err ) return err; // set up data nes_addr_t load_addr = get_le16( header_.load_addr ); init_addr = get_le16( header_.init_addr ); play_addr = get_le16( header_.play_addr ); if ( !load_addr ) load_addr = rom_begin; if ( !init_addr ) init_addr = rom_begin; if ( !play_addr ) play_addr = rom_begin; if ( load_addr < rom_begin || init_addr < rom_begin ) { const char* w = warning(); if ( !w ) w = "Corrupt file (invalid load/init/play address)"; return w; } rom.set_addr( load_addr % bank_size ); int total_banks = rom.size() / bank_size; // bank switching int first_bank = (load_addr - rom_begin) / bank_size; for ( int i = 0; i < bank_count; i++ ) { unsigned bank = i - first_bank; if ( bank >= (unsigned) total_banks ) bank = 0; initial_banks [i] = bank; if ( header_.banks [i] ) { // bank-switched memcpy( initial_banks, header_.banks, sizeof initial_banks ); break; } } pal_only = (header_.speed_flags & 3) == 1; #if !NSF_EMU_EXTRA_FLAGS header_.speed_flags = 0; #endif set_tempo( tempo() ); return setup_buffer( (long) (clock_rate_ + 0.5) ); }
blargg_err_t Nsf_Emu::init_sound() { if ( header_.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag) ) set_warning( "Uses unsupported audio expansion hardware" ); { #define APU_NAMES "Square 1", "Square 2", "Triangle", "Noise", "DMC" int const count = Nes_Apu::osc_count; static const char* const apu_names [count] = { APU_NAMES }; set_voice_count( count ); set_voice_names( apu_names ); } static int const types [] = { wave_type | 1, wave_type | 2, wave_type | 0, noise_type | 0, mixed_type | 1, wave_type | 3, wave_type | 4, wave_type | 5, wave_type | 6, wave_type | 7, wave_type | 8, wave_type | 9, wave_type |10, wave_type |11, wave_type |12, wave_type |13 }; set_voice_types( types ); // common to all sound chip configurations double adjusted_gain = gain(); #if NSF_EMU_APU_ONLY { if ( header_.chip_flags ) set_warning( "Uses unsupported audio expansion hardware" ); } #else { if ( header_.chip_flags & (namco_flag | vrc6_flag | fme7_flag) ) set_voice_count( Nes_Apu::osc_count + 3 ); if ( header_.chip_flags & namco_flag ) { namco = BLARGG_NEW Nes_Namco_Apu; CHECK_ALLOC( namco ); adjusted_gain *= 0.75; int const count = Nes_Apu::osc_count + Nes_Namco_Apu::osc_count; static const char* const names [count] = { APU_NAMES, "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Wave 5", "Wave 6", "Wave 7", "Wave 8" }; set_voice_count( count ); set_voice_names( names ); } if ( header_.chip_flags & vrc6_flag ) { vrc6 = BLARGG_NEW Nes_Vrc6_Apu; CHECK_ALLOC( vrc6 ); adjusted_gain *= 0.75; { int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count; static const char* const names [count] = { APU_NAMES, "Saw Wave", "Square 3", "Square 4" }; set_voice_count( count ); set_voice_names( names ); } if ( header_.chip_flags & namco_flag ) { int const count = Nes_Apu::osc_count + Nes_Vrc6_Apu::osc_count + Nes_Namco_Apu::osc_count; static const char* const names [count] = { APU_NAMES, "Saw Wave", "Square 3", "Square 4", "Wave 1", "Wave 2", "Wave 3", "Wave 4", "Wave 5", "Wave 6", "Wave 7", "Wave 8" }; set_voice_count( count ); set_voice_names( names ); } } if ( header_.chip_flags & fme7_flag ) { fme7 = BLARGG_NEW Nes_Fme7_Apu; CHECK_ALLOC( fme7 ); adjusted_gain *= 0.75; int const count = Nes_Apu::osc_count + Nes_Fme7_Apu::osc_count; static const char* const names [count] = { APU_NAMES, "Square 3", "Square 4", "Square 5" }; set_voice_count( count ); set_voice_names( names ); } if ( namco ) namco->volume( adjusted_gain ); if ( vrc6 ) vrc6 ->volume( adjusted_gain ); if ( fme7 ) fme7 ->volume( adjusted_gain ); } #endif apu.volume( adjusted_gain ); return 0; }
blargg_err_t Ay_Emu::start_track_( int track ) { RETURN_ERR( Classic_Emu::start_track_( track ) ); byte* const mem = core.mem(); memset( mem + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET memset( mem + 0x0100, 0xFF, 0x4000 - 0x100 ); memset( mem + core.ram_addr, 0x00, core.mem_size - core.ram_addr ); // locate data blocks byte const* const data = get_data( file, file.tracks + track * 4 + 2, 14 ); if ( !data ) return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); byte const* const more_data = get_data( file, data + 10, 6 ); if ( !more_data ) return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); byte const* blocks = get_data( file, data + 12, 8 ); if ( !blocks ) return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); // initial addresses unsigned addr = get_be16( blocks ); if ( !addr ) return BLARGG_ERR( BLARGG_ERR_FILE_CORRUPT, "file data missing" ); unsigned init = get_be16( more_data + 2 ); if ( !init ) init = addr; // copy blocks into memory do { blocks += 2; unsigned len = get_be16( blocks ); blocks += 2; if ( addr + len > core.mem_size ) { set_warning( "Bad data block size" ); len = core.mem_size - addr; } check( len ); byte const* in = get_data( file, blocks, 0 ); blocks += 2; if ( len > (unsigned) (file.end - in) ) { set_warning( "File data missing" ); len = file.end - in; } //dprintf( "addr: $%04X, len: $%04X\n", addr, len ); if ( addr < core.ram_addr && addr >= 0x400 ) // several tracks use low data dprintf( "Block addr in ROM\n" ); memcpy( mem + addr, in, len ); if ( file.end - blocks < 8 ) { set_warning( "File data missing" ); break; } } while ( (addr = get_be16( blocks )) != 0 ); // copy and configure driver static byte const passive [] = { 0xF3, // DI 0xCD, 0, 0, // CALL init 0xED, 0x5E, // LOOP: IM 2 0xFB, // EI 0x76, // HALT 0x18, 0xFA // JR LOOP }; static byte const active [] = { 0xF3, // DI 0xCD, 0, 0, // CALL init 0xED, 0x56, // LOOP: IM 1 0xFB, // EI 0x76, // HALT 0xCD, 0, 0, // CALL play 0x18, 0xF7 // JR LOOP }; memcpy( mem, passive, sizeof passive ); int const play_addr = get_be16( more_data + 4 ); if ( play_addr ) { memcpy( mem, active, sizeof active ); mem [ 9] = play_addr; mem [10] = play_addr >> 8; } mem [2] = init; mem [3] = init >> 8; mem [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) // start at spectrum speed change_clock_rate( spectrum_clock ); set_tempo( tempo() ); Ay_Core::registers_t r = { }; r.sp = get_be16( more_data ); r.b.a = r.b.b = r.b.d = r.b.h = data [8]; r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; r.alt.w = r.w; r.ix = r.iy = r.w.hl; core.start_track( r, play_addr ); return blargg_ok; }
blargg_err_t Ay_Emu::start_track_( int track ) { RETURN_ERR( Classic_Emu::start_track_( track ) ); memset( mem.ram + 0x0000, 0xC9, 0x100 ); // fill RST vectors with RET memset( mem.ram + 0x0100, 0xFF, 0x4000 - 0x100 ); memset( mem.ram + ram_start, 0x00, sizeof mem.ram - ram_start ); memset( mem.padding1, 0xFF, sizeof mem.padding1 ); memset( mem.ram + 0x10000, 0xFF, sizeof mem.ram - 0x10000 ); // locate data blocks byte const* const data = get_data( file, file.tracks + track * 4 + 2, 14 ); if ( !data ) return "File data missing"; byte const* const more_data = get_data( file, data + 10, 6 ); if ( !more_data ) return "File data missing"; byte const* blocks = get_data( file, data + 12, 8 ); if ( !blocks ) return "File data missing"; // initial addresses cpu::reset( mem.ram ); r.sp = get_be16( more_data ); r.b.a = r.b.b = r.b.d = r.b.h = data [8]; r.b.flags = r.b.c = r.b.e = r.b.l = data [9]; r.alt.w = r.w; r.ix = r.iy = r.w.hl; unsigned addr = get_be16( blocks ); if ( !addr ) return "File data missing"; unsigned init = get_be16( more_data + 2 ); if ( !init ) init = addr; // copy blocks into memory do { blocks += 2; unsigned len = get_be16( blocks ); blocks += 2; if ( addr + len > 0x10000 ) { set_warning( "Bad data block size" ); len = 0x10000 - addr; } check( len ); byte const* in = get_data( file, blocks, 0 ); blocks += 2; if ( len > blargg_ulong (file.end - in) ) { set_warning( "Missing file data" ); len = file.end - in; } //debug_printf( "addr: $%04X, len: $%04X\n", addr, len ); if ( addr < ram_start && addr >= 0x400 ) // several tracks use low data debug_printf( "Block addr in ROM\n" ); memcpy( mem.ram + addr, in, len ); if ( file.end - blocks < 8 ) { set_warning( "Missing file data" ); break; } } while ( (addr = get_be16( blocks )) != 0 ); // copy and configure driver static byte const passive [] = { 0xF3, // DI 0xCD, 0, 0, // CALL init 0xED, 0x5E, // LOOP: IM 2 0xFB, // EI 0x76, // HALT 0x18, 0xFA // JR LOOP }; static byte const active [] = { 0xF3, // DI 0xCD, 0, 0, // CALL init 0xED, 0x56, // LOOP: IM 1 0xFB, // EI 0x76, // HALT 0xCD, 0, 0, // CALL play 0x18, 0xF7 // JR LOOP }; memcpy( mem.ram, passive, sizeof passive ); unsigned play_addr = get_be16( more_data + 4 ); //debug_printf( "Play: $%04X\n", play_addr ); if ( play_addr ) { memcpy( mem.ram, active, sizeof active ); mem.ram [ 9] = play_addr; mem.ram [10] = play_addr >> 8; } mem.ram [2] = init; mem.ram [3] = init >> 8; mem.ram [0x38] = 0xFB; // Put EI at interrupt vector (followed by RET) memcpy( mem.ram + 0x10000, mem.ram, 0x80 ); // some code wraps around (ugh) beeper_delta = int (apu.amp_range * 0.65); last_beeper = 0; apu.reset(); next_play = play_period; // start at spectrum speed change_clock_rate( spectrum_clock ); set_tempo( tempo() ); spectrum_mode = false; cpc_mode = false; cpc_latch = 0; return 0; }
inline void Vgm_Emu::check_warning() { const char* w = core.warning(); if ( w ) set_warning( w ); }
// arguments: k1=v1;k2=v2;k3=v3; ... // e.g., // port = %port% // timeout = %timeout% // arguments: port=23466;timeout=1000 or arguments: ports=23466,timout=1000 bool configuration::load(const char* file_name, const char* arguments) { _file_name = std::string(file_name); FILE* fd = ::fopen(file_name, "rb"); if (fd == nullptr) { std::string cdir; dsn::utils::filesystem::get_current_directory(cdir); printf("ERROR: cannot open file %s in %s, err = %s\n", file_name, cdir.c_str(), strerror(errno)); return false; } ::fseek(fd, 0, SEEK_END); int len = ftell(fd); if (len == -1 || len == 0) { printf("ERROR: cannot get length of %s, err = %s\n", file_name, strerror(errno)); ::fclose(fd); return false; } _file_data.resize(len + 1); ::fseek(fd, 0, SEEK_SET); auto sz = ::fread((char*)_file_data.c_str(), len, 1, fd); ::fclose(fd); if (sz != 1) { printf("ERROR: cannot read correct data of %s, err = %s\n", file_name, strerror(errno)); return false; } _file_data[len] = '\n'; // replace data with arguments if (arguments != nullptr) { std::string str_arguments(arguments); std::replace(str_arguments.begin(), str_arguments.end(), ',', ';'); std::list<std::string> argkvs; utils::split_args(str_arguments.c_str(), argkvs, ';'); for (auto& kv : argkvs) { std::list<std::string> vs; utils::split_args(kv.c_str(), vs, '='); if (vs.size() != 2) { printf("ERROR: invalid configuration argument: '%s' in '%s'\n", kv.c_str(), arguments); return false; } std::string key = std::string("%") + *vs.begin() + std::string("%"); std::string value = *vs.rbegin(); _file_data = utils::replace_string(_file_data, key, value); } } // // parse mapped file and build conf map // std::map<std::string, conf*>* pSection = nullptr; char *p, *pLine = (char*)"", *pNextLine, *pEnd, *pSectionName = nullptr, *pEqual; int lineno = 0; // ATTENTION: arguments replace_string() may cause _file_data changed, // so set `p' and `pEnd' carefully. p = (char*)_file_data.c_str(); pEnd = p + _file_data.size(); while (p < pEnd) { // // get line // lineno++; while (*p == ' ' || *p == '\t' || *p == '\r') p++; pLine = p; int shift = 0; while (*p != '\n' && p < pEnd) { if (*p == '#' || *p == ';') { if (p != pLine && *(p-1) == '^') { shift++; } else { *p = '\0'; } } if (shift > 0) { *(p-shift) = *p; } p++; } *(p-shift) = '\0'; pNextLine = ++p; // // parse line // p = pLine; if (*p == '\0') goto Next; // skip comment line or empty line pEqual = strchr(p, '='); if (nullptr == pEqual && *p != '[') { goto ConfReg; } if (nullptr != pEqual && *p == '[') goto err; // // conf // if (pEqual) { ConfReg: if (pSection == nullptr) { printf("ERROR: configuration section not defined\n"); goto err; } if (pEqual) *pEqual = '\0'; char* pKey = utils::trim_string(p); char* pValue = pEqual ? utils::trim_string(++pEqual) : nullptr; if (*pKey == '\0') goto err; if (pSection->find((const char*)pKey) != pSection->end()) { auto it = pSection->find((const char*)pKey); printf("WARNING: skip redefinition of option [%s] %s (line %u), already defined as [%s] %s (line %u)\n", pSectionName, pKey, lineno, it->second->section.c_str(), it->second->key.c_str(), it->second->line ); } else { conf* cf = new conf; cf->section = (const char*)pSectionName; cf->key = pKey; cf->line = lineno; cf->present = true; if (pValue) { // if argument is not provided if (strlen(pValue) > 2 && *pValue == '%' && pValue[strlen(pValue) - 1] == '%') cf->value = ""; else cf->value = pValue; } else { cf->value = ""; } pSection->insert(std::make_pair(std::string(pKey), cf)); } } // // section // else { char* pRight = strchr(p, ']'); if (nullptr == pRight) goto err; *pRight = '\0'; p++; pSectionName = utils::trim_string(p); if (*pSectionName == '\0') goto err; bool old = set_warning(false); if (has_section((const char*)pSectionName)) { printf("ERROR: configuration section '[%s]' is redefined\n", pSectionName); set_warning(old); goto err; } set_warning(old); std::map<std::string, conf*> sm; auto it = _configs.insert(config_map::value_type(std::string(pSectionName), sm)); assert (it.second); pSection = &it.first->second; } // // iterate nextline // Next: p = pNextLine; } return true; err: printf("ERROR: unexpected configuration in %s(line %d): %s\n", file_name, lineno, pLine); return false; }
int main(int argc, char **argv) { #define FIND_LONG_OPTION(ARRAY) \ { \ for(i = 0; i < sizeof (ARRAY) / sizeof(struct option); i++) { \ struct option *o = (ARRAY) + i; \ if(o->arg < 2) { \ if(strcmp(arg, o->opt) == 0) { \ const char *a = o->arg ? *++v : argv[0]; \ if(o->arg && !a) { \ fprintf(stderr, "%s: option '%s' need an argument\n", argv[0], *v); \ return 1; \ } \ if(o->act) o->act(a); \ goto first_loop; \ } \ } else { \ size_t len = strlen(o->opt); \ if(strncmp(arg, o->opt, len) == 0) { \ if(arg[len] && arg[len] != '=') continue; \ if(!arg[len] || !arg[len + 1]) { \ fprintf(stderr, "%s: option '%s' need an argument\n", argv[0], *v); \ return 1; \ } \ const char *a = arg + len + 1; \ if(o->act) o->act(a); \ goto first_loop; \ } \ } \ } \ } #define UNRECOGNIZED_OPTION(O) \ do { \ fprintf(stderr, "%s: error: unrecognized option '%s'\n", \ argv[0], (O)); \ return 1; \ } while(0) int verbose = 0; int no_link = 0; int preprocess_only = -1; int no_warning = -1; int end_of_options = 0; const char *output_file = NULL; char **v = argv; init_argv(); const char *vs_path = getenv("VS_PATH"); if(!vs_path) vs_path = getenv("VSINSTALLDIR"); if(!getenv("INCLUDE")) { if(vs_path) { size_t len = strlen(vs_path); if(vs_path[len - 1] == '/' || vs_path[len - 1] == '\\') len--; char buffer[len + 12 + len + 24 + 1]; memcpy(buffer, vs_path, len); memcpy(buffer + len, "/VC/include;", 12); memcpy(buffer + len + 12, vs_path, len); strcpy(buffer + len + 12 + len, "/VC/PlatformSDK/include;"); setenv("INCLUDE", buffer, 0); } else { no_warning = find_argv(argv, "-w"); if(!no_warning) fprintf(stderr, "%s: warning: no system include path set\n", argv[0]); } } if(!getenv("LIB")) { if(vs_path) { size_t len = strlen(vs_path); if(vs_path[len - 1] == '/' || vs_path[len - 1] == '\\') len--; char buffer[len + 8 + len + 20 + 1]; memcpy(buffer, vs_path, len); memcpy(buffer + len, "/VC/lib;", 8); memcpy(buffer + len + 12, vs_path, len); strcpy(buffer + len + 12 + len, "/VC/PlatformSDK/lib;"); setenv("LIB", buffer, 0); } else { if(no_warning == -1) no_warning = find_argv(argv, "-w"); if(!no_warning) fprintf(stderr, "%s: warning: no system library path set\n", argv[0]); } } first_loop: while(*++v) { if(!end_of_options && **v == '-') { int i; if((*v)[1] == '-') { const char *arg = *v + 2; if(!*arg) { end_of_options = 1; continue; } FIND_LONG_OPTION(double_dash_long_options); if(strcmp(arg, "verbose") == 0) { verbose = 1; } else UNRECOGNIZED_OPTION(*v); } else { const char *arg = *v + 1; FIND_LONG_OPTION(singal_dash_long_options); switch(*arg) { case 0: goto not_an_option; case 'c': if(arg[1]) UNRECOGNIZED_OPTION(*v); add_to_argv("-c"); no_link = 1; break; case 'D': if(arg[1]) add_to_argv(*v); else { const char *d = *++v; if(!d) { fprintf(stderr, "%s: error: macro name missing after '-D'\n", argv[0]); return 1; } define(d); } break; case 'E': if(arg[1]) UNRECOGNIZED_OPTION(*v); add_to_argv("-E"); preprocess_only = 1; break; case 'f': if(arg[1]) set_feature(arg + 1); else { const char *feature = *++v; if(!feature) { fprintf(stderr, "%s: error: option '-f' need an argument\n", argv[0]); return -1; } set_feature(feature); } break; case 'g': // -g[coff][<level>] (level: 0~3) if(arg[1]) { const char *level = arg + 1; if(strncmp(level, "coff", 4) == 0) level += 4; if(*level && *level != '-') { int i = 0; do { if(!isdigit(level[i])) { fprintf(stderr, "%s: error: unrecognized debug output level \"%s\"\n", argv[0], level); return 1; } } while(level[++i]); /* if(i > 1 || *level > '3') { fprintf(stderr, "%s: error: debug output level %s is too high\n", argv[0], level); return 1; } if(*level == '0') break; */ int l = atoi(level); if(!l) break; if(l > 3) { fprintf(stderr, "%s: error: debug output level %s is too high\n", argv[0], level); return 1; } } } add_to_argv("-Zi"); break; case 'I': if(no_warning == -1) no_warning = find_argv(argv, "-w"); //if(arg[1]) add_to_argv(*v); if(arg[1]) add_include_path(arg + 1, no_warning); else { const char *path = *++v; if(!path) { fprintf(stderr, "%s: error: option '-I' need an argument\n", argv[0]); return 1; } add_include_path(path, no_warning); } break; case 'L': if(no_warning == -1) no_warning = find_argv(argv, "-w"); if(arg[1]) add_library_path(arg + 1, no_warning); else { const char *path = *++v; if(!path) { fprintf(stderr, "%s: error: option '-L' need an argument\n", argv[0]); return 1; } add_library_path(path, no_warning); } break; case 'l': if(arg[1]) add_library(arg + 1); else { const char *path = *++v; if(!path) { fprintf(stderr, "%s: error: option '-l' need an argument\n", argv[0]); return 1; } add_library(path); } break; case 'M': if(arg[1]) UNRECOGNIZED_OPTION(*v); add_to_argv("-showIncludes"); break; case 'm': if(arg[1]) set_machine(arg + 1); else { const char *machine = *++v; if(!machine) { fprintf(stderr, "%s: argument to `-m' is missing\n", argv[0]); return 1; } set_machine(machine); } break; case 'O': if(arg[1]) { const char *o = arg + 1; if(strcmp(o, "0") == 0) add_to_argv("-Od"); else if(strcmp(o, "1") == 0) add_to_argv("-O2"); else if(strcmp(o, "3") == 0) add_to_argv("-Ox"); else if(strcmp(o, "s") == 0) add_to_argv("-O1"); else if(strcmp(o, "fast") == 0) add_to_argv("-O2"); else add_to_argv(*v); } else add_to_argv("-O2"); break; case 'o': if(arg[1]) output_file = arg + 1; else { output_file = *++v; if(!output_file) { fprintf(stderr, "%s: error: option '-o' need an argument\n", argv[0]); return 1; } } break; case 'P': if(preprocess_only == -1) preprocess_only = find_argv(argv, "-E"); if(preprocess_only) add_to_argv("-EP"); break; case 's': if(arg[1]) UNRECOGNIZED_OPTION(*v); break; case 'U': if(arg[1]) add_to_argv(*v); else { const char *u = *++v; if(!u) { fprintf(stderr, "%s: error: macro name missing after '-U'\n", argv[0]); return 1; } undefine(u); } break; case 'v': if(arg[1]) UNRECOGNIZED_OPTION(*v); verbose = 1; break; case 'W': if(!arg[1]) { if(no_warning == -1) no_warning = find_argv(argv, "-w"); if(!no_warning) { fprintf(stderr, "%s: warning: option '-W' is deprecated; use '-Wextra' instead\n", argv[0]); } add_to_argv("-Wall"); break; } if(strncmp(arg, "Wa,", 3) == 0 || strncmp(arg, "Wp,", 3) == 0 || strncmp(arg, "Wl,", 3) == 0) { (*v)[3] = 0; // XXX fprintf(stderr, "%s: warning: option '%s' is not supported\n", argv[0], *v); break; } if(set_warning(arg + 1)) break; add_to_argv(*v); break; case 'w': if(arg[1]) UNRECOGNIZED_OPTION(*v); add_to_argv("-w"); no_warning = 1; break; case 'x': if(arg[1]) set_language(arg + 1); else { const char *lang = *++v; if(!lang) { fprintf(stderr, "%s: error: missing argument to ‘-x’", argv[0]); return 4; } set_language(lang); } break; default: fprintf(stderr, "%s: error: unrecognized option '%s'\n", argv[0], *v); return 1; } } } else { not_an_option: #if defined __INTERIX && !defined _NO_CONV_PATH if(**v == '/') { char buffer[PATH_MAX + 1]; if(unixpath2win(*v, 0, buffer, sizeof buffer) == 0) { add_input_file(buffer); } else { if(no_warning == -1) no_warning = find_argv(argv, "-w"); if(!no_warning) { fprintf(stderr, "%s: warning: cannot convert '%s' to Windows path name, %s\n", argv[0], *v, strerror(errno)); } add_input_file(*v); } } else #endif add_input_file(*v); } } setvbuf(stdout, NULL, _IOLBF, 0); if(preprocess_only == -1) preprocess_only = 0; if(no_warning == -1) no_warning = 0; if(last_language && last_language_unused && !no_warning) { fprintf(stderr, "%s: warning: '-x %s' after last input file has no effect\n", argv[0], last_language); } if(!first_input_file) { if(verbose) { if(!no_link) add_to_argv("-c"); start_cl(); return 0; } fprintf(stderr, "%s: no input files\n", argv[0]); return 1; } if(multiple_input_files && (preprocess_only || no_link)) { if(output_file) { fprintf(stderr, "%s: error: cannot specify -o with -c or -E with multiple files\n", argv[0]); return 4; } else if(no_link) { fprintf(stderr, "%s: error: '-c' with multiple files is currently not supported\n", argv[0]); return -1; } } if(!output_file && !preprocess_only) { if(no_link) { size_t len = strlen(first_input_file); int n = get_last_dot(first_input_file, len); if(n >= 0) len = n; char *p = malloc(len + 3); if(!p) { perror(argv[0]); return 1; } memcpy(p, first_input_file, len); strcpy(p + len, ".o"); output_file = p; } else output_file = DEFAULT_OUTPUT_FILENAME; } if(!verbose) add_to_argv("-nologo"); if(preprocess_only) { if(output_file) target.name = output_file; target.type = PREPROCESSED_SOURCE; } else set_output_file(output_file, no_link, no_warning); //if(no_static_link) add_to_argv("-MD"); add_to_argv(no_static_link ? "-MD" : "-MT"); add_libraries_to_argv(); if(verbose) print_argv(); return start_cl(); }