/src/vlc/contrib/contrib-build/game-music-emu/gme/Nsf_Emu.cpp
Line | Count | Source |
1 | | // Game_Music_Emu https://bitbucket.org/mpyne/game-music-emu/ |
2 | | |
3 | | #include "Nsf_Emu.h" |
4 | | |
5 | | #include "blargg_endian.h" |
6 | | #include <string.h> |
7 | | #include <stdio.h> |
8 | | #include <algorithm> |
9 | | |
10 | | #if !NSF_EMU_APU_ONLY |
11 | | #include "Nes_Namco_Apu.h" |
12 | | #include "Nes_Vrc6_Apu.h" |
13 | | #include "Nes_Fme7_Apu.h" |
14 | | #include "Nes_Fds_Apu.h" |
15 | | #include "Nes_Mmc5_Apu.h" |
16 | | #include "Nes_Vrc7_Apu.h" |
17 | | #endif |
18 | | |
19 | | /* Copyright (C) 2003-2006 Shay Green. This module is free software; you |
20 | | can redistribute it and/or modify it under the terms of the GNU Lesser |
21 | | General Public License as published by the Free Software Foundation; either |
22 | | version 2.1 of the License, or (at your option) any later version. This |
23 | | module is distributed in the hope that it will be useful, but WITHOUT ANY |
24 | | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
25 | | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
26 | | details. You should have received a copy of the GNU Lesser General Public |
27 | | License along with this module; if not, write to the Free Software Foundation, |
28 | | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
29 | | |
30 | | #include "blargg_source.h" |
31 | | |
32 | | static int const vrc6_flag = 0x01; |
33 | | static int const vrc7_flag = 0x02; |
34 | | static int const fds_flag = 0x04; |
35 | | static int const mmc5_flag = 0x08; |
36 | | static int const namco_flag = 0x10; |
37 | | static int const fme7_flag = 0x20; |
38 | | |
39 | | static long const clock_divisor = 12; |
40 | | |
41 | | using std::min; |
42 | | using std::max; |
43 | | |
44 | | Nsf_Emu::equalizer_t const Nsf_Emu::nes_eq = |
45 | | Music_Emu::make_equalizer( -1.0, 80 ); |
46 | | Nsf_Emu::equalizer_t const Nsf_Emu::famicom_eq = |
47 | | Music_Emu::make_equalizer( -15.0, 80 ); |
48 | | |
49 | | int Nsf_Emu::pcm_read( void* emu, nes_addr_t addr ) |
50 | 0 | { |
51 | 0 | return *((Nsf_Emu*) emu)->cpu::get_code( addr ); |
52 | 0 | } |
53 | | |
54 | | Nsf_Emu::Nsf_Emu() |
55 | 873 | { |
56 | 873 | vrc6 = 0; |
57 | 873 | namco = 0; |
58 | 873 | fme7 = 0; |
59 | 873 | fds = 0; |
60 | 873 | mmc5 = 0; |
61 | 873 | vrc7 = 0; |
62 | | |
63 | 873 | set_type( gme_nsf_type ); |
64 | 873 | set_silence_lookahead( 6 ); |
65 | 873 | apu.dmc_reader( pcm_read, this ); |
66 | 873 | Music_Emu::set_equalizer( nes_eq ); |
67 | 873 | set_gain( 1.4 ); |
68 | 873 | memset( unmapped_code, Nes_Cpu::bad_opcode, sizeof unmapped_code ); |
69 | 873 | } |
70 | | |
71 | 873 | Nsf_Emu::~Nsf_Emu() { unload(); } |
72 | | |
73 | | void Nsf_Emu::unload() |
74 | 1.77k | { |
75 | 1.77k | #if !NSF_EMU_APU_ONLY |
76 | 1.77k | { |
77 | 1.77k | delete vrc6; |
78 | 1.77k | vrc6 = 0; |
79 | | |
80 | 1.77k | delete namco; |
81 | 1.77k | namco = 0; |
82 | | |
83 | 1.77k | delete fme7; |
84 | 1.77k | fme7 = 0; |
85 | | |
86 | 1.77k | delete fds; |
87 | 1.77k | fds = 0; |
88 | | |
89 | 1.77k | delete mmc5; |
90 | 1.77k | mmc5 = 0; |
91 | | |
92 | 1.77k | delete vrc7; |
93 | 1.77k | vrc7 = 0; |
94 | 1.77k | } |
95 | 1.77k | #endif |
96 | | |
97 | 1.77k | rom.clear(); |
98 | 1.77k | Music_Emu::unload(); |
99 | 1.77k | } |
100 | | |
101 | | // Track info |
102 | | |
103 | | static void copy_nsf_fields( Nsf_Emu::header_t const& h, track_info_t* out ) |
104 | 5.33k | { |
105 | 5.33k | GME_COPY_FIELD( h, out, game ); |
106 | 5.33k | GME_COPY_FIELD( h, out, author ); |
107 | 5.33k | GME_COPY_FIELD( h, out, copyright ); |
108 | 5.33k | if ( h.chip_flags ) |
109 | 5.11k | Gme_File::copy_field_( out->system, "Famicom" ); |
110 | 5.33k | } |
111 | | |
112 | | blargg_err_t Nsf_Emu::track_info_( track_info_t* out, int ) const |
113 | 5.33k | { |
114 | 5.33k | copy_nsf_fields( header_, out ); |
115 | 5.33k | return 0; |
116 | 5.33k | } |
117 | | |
118 | | static blargg_err_t check_nsf_header( void const* header ) |
119 | 866 | { |
120 | 866 | if ( memcmp( header, "NESM\x1A", 5 ) ) |
121 | 5 | return gme_wrong_file_type; |
122 | 861 | return 0; |
123 | 866 | } |
124 | | |
125 | | struct Nsf_File : Gme_Info_ |
126 | | { |
127 | | Nsf_Emu::header_t h; |
128 | | |
129 | 0 | Nsf_File() { set_type( gme_nsf_type ); } |
130 | | |
131 | | blargg_err_t load_( Data_Reader& in ) |
132 | 0 | { |
133 | 0 | blargg_err_t err = in.read( &h, Nsf_Emu::header_size ); |
134 | 0 | if ( err ) |
135 | 0 | return (err == in.eof_error ? gme_wrong_file_type : err); |
136 | | |
137 | 0 | if ( h.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag | fds_flag | mmc5_flag | vrc7_flag) ) |
138 | 0 | set_warning( "Uses unsupported audio expansion hardware" ); |
139 | |
|
140 | 0 | set_track_count( h.track_count ); |
141 | 0 | return check_nsf_header( &h ); |
142 | 0 | } |
143 | | |
144 | | blargg_err_t track_info_( track_info_t* out, int ) const |
145 | 0 | { |
146 | 0 | copy_nsf_fields( h, out ); |
147 | 0 | return 0; |
148 | 0 | } |
149 | | }; |
150 | | |
151 | 868 | static Music_Emu* new_nsf_emu () { return BLARGG_NEW Nsf_Emu ; } |
152 | 0 | static Music_Emu* new_nsf_file() { return BLARGG_NEW Nsf_File; } |
153 | | |
154 | | static gme_type_t_ const gme_nsf_type_ = { "Nintendo NES", 0, &new_nsf_emu, &new_nsf_file, "NSF", 1 }; |
155 | | extern gme_type_t const gme_nsf_type = &gme_nsf_type_; |
156 | | |
157 | | |
158 | | // Setup |
159 | | |
160 | | void Nsf_Emu::set_tempo_( double t ) |
161 | 1.69k | { |
162 | 1.69k | unsigned playback_rate = get_le16( header_.ntsc_speed ); |
163 | 1.69k | unsigned standard_rate = 0x411A; |
164 | 1.69k | clock_rate_ = 1789772.72727; |
165 | 1.69k | play_period = 262 * 341L * 4 - 2; // two fewer PPU clocks every four frames |
166 | | |
167 | 1.69k | if ( pal_only ) |
168 | 1.13k | { |
169 | 1.13k | play_period = 33247 * clock_divisor; |
170 | 1.13k | clock_rate_ = 1662607.125; |
171 | 1.13k | standard_rate = 0x4E20; |
172 | 1.13k | playback_rate = get_le16( header_.pal_speed ); |
173 | 1.13k | } |
174 | | |
175 | 1.69k | if ( !playback_rate ) |
176 | 74 | playback_rate = standard_rate; |
177 | | |
178 | 1.69k | if ( playback_rate != standard_rate || t != 1.0 ) |
179 | 1.61k | play_period = long (playback_rate * clock_rate_ / (1000000.0 / clock_divisor * t)); |
180 | | |
181 | 1.69k | apu.set_tempo( t ); |
182 | 1.69k | } |
183 | | |
184 | | blargg_err_t Nsf_Emu::init_sound() |
185 | 861 | { |
186 | 861 | if ( header_.chip_flags & ~(namco_flag | vrc6_flag | fme7_flag | fds_flag | mmc5_flag | vrc7_flag) ) |
187 | 656 | set_warning( "Uses unsupported audio expansion hardware" ); |
188 | | |
189 | | #ifdef NSF_EMU_APU_ONLY |
190 | | int const count_total = Nes_Apu::osc_count; |
191 | | #else |
192 | 861 | int const count_total = Nes_Apu::osc_count + Nes_Namco_Apu::osc_count + |
193 | 861 | Nes_Vrc6_Apu::osc_count + Nes_Fme7_Apu::osc_count + |
194 | 861 | Nes_Fds_Apu::osc_count + Nes_Mmc5_Apu::osc_count + |
195 | 861 | Nes_Vrc7_Apu::osc_count; |
196 | 861 | #endif |
197 | | |
198 | 861 | apu_names.resize( count_total ); |
199 | | |
200 | 861 | int count = 0; |
201 | | |
202 | 861 | { |
203 | 861 | apu_names[count + 0] = "Square 1"; |
204 | 861 | apu_names[count + 1] = "Square 2"; |
205 | 861 | apu_names[count + 2] = "Triangle"; |
206 | 861 | apu_names[count + 3] = "Noise"; |
207 | 861 | apu_names[count + 4] = "DMC"; |
208 | 861 | apu_names[count + 5] = "FM"; |
209 | 861 | count += Nes_Apu::osc_count; |
210 | 861 | } |
211 | | |
212 | 861 | static int const types [] = { |
213 | 861 | wave_type | 1, wave_type | 2, wave_type | 0, |
214 | 861 | noise_type | 0, mixed_type | 1, |
215 | 861 | wave_type | 3, wave_type | 4, wave_type | 5, |
216 | 861 | wave_type | 6, wave_type | 7, wave_type | 8, wave_type | 9, |
217 | 861 | wave_type |10, wave_type |11, wave_type |12, wave_type |13 |
218 | 861 | }; |
219 | 861 | set_voice_types( types ); // common to all sound chip configurations |
220 | | |
221 | 861 | double adjusted_gain = gain(); |
222 | | |
223 | | #if NSF_EMU_APU_ONLY |
224 | | { |
225 | | if ( header_.chip_flags ) |
226 | | set_warning( "Uses unsupported audio expansion hardware" ); |
227 | | } |
228 | | #else |
229 | 861 | { |
230 | 861 | if ( header_.chip_flags & vrc6_flag ) |
231 | 582 | { |
232 | 582 | vrc6 = BLARGG_NEW Nes_Vrc6_Apu; |
233 | 582 | CHECK_ALLOC( vrc6 ); |
234 | 582 | adjusted_gain *= 0.75; |
235 | | |
236 | 582 | apu_names[count + 0] = "Saw Wave"; |
237 | 582 | apu_names[count + 1] = "Square 3"; |
238 | 582 | apu_names[count + 2] = "Square 4"; |
239 | | |
240 | 582 | count += Nes_Vrc6_Apu::osc_count; |
241 | 582 | } |
242 | | |
243 | 861 | if ( header_.chip_flags & namco_flag ) |
244 | 20 | { |
245 | 20 | namco = BLARGG_NEW Nes_Namco_Apu; |
246 | 20 | CHECK_ALLOC( namco ); |
247 | 20 | adjusted_gain *= 0.75; |
248 | | |
249 | 20 | apu_names[count + 0] = "Wave 1"; |
250 | 20 | apu_names[count + 1] = "Wave 2"; |
251 | 20 | apu_names[count + 2] = "Wave 3"; |
252 | 20 | apu_names[count + 3] = "Wave 4"; |
253 | 20 | apu_names[count + 4] = "Wave 5"; |
254 | 20 | apu_names[count + 5] = "Wave 6"; |
255 | 20 | apu_names[count + 6] = "Wave 7"; |
256 | 20 | apu_names[count + 7] = "Wave 8"; |
257 | | |
258 | 20 | count += Nes_Namco_Apu::osc_count; |
259 | 20 | } |
260 | | |
261 | 861 | if ( header_.chip_flags & fme7_flag ) |
262 | 176 | { |
263 | 176 | fme7 = BLARGG_NEW Nes_Fme7_Apu; |
264 | 176 | CHECK_ALLOC( fme7 ); |
265 | 176 | adjusted_gain *= 0.75; |
266 | | |
267 | 176 | apu_names[count + 0] = "Square 3"; |
268 | 176 | apu_names[count + 1] = "Square 4"; |
269 | 176 | apu_names[count + 2] = "Square 5"; |
270 | | |
271 | 176 | count += Nes_Fme7_Apu::osc_count; |
272 | 176 | } |
273 | | |
274 | 861 | if ( header_.chip_flags & fds_flag ) |
275 | 594 | { |
276 | 594 | fds = BLARGG_NEW Nes_Fds_Apu; |
277 | 594 | CHECK_ALLOC( fds ); |
278 | 594 | adjusted_gain *= 0.75; |
279 | | |
280 | 594 | apu_names[count + 0] = "Wave"; |
281 | | |
282 | 594 | count += Nes_Fds_Apu::osc_count; |
283 | 594 | } |
284 | | |
285 | 861 | if ( header_.chip_flags & mmc5_flag ) |
286 | 512 | { |
287 | 512 | mmc5 = BLARGG_NEW Nes_Mmc5_Apu; |
288 | 512 | CHECK_ALLOC( mmc5 ); |
289 | 512 | adjusted_gain *= 0.75; |
290 | | |
291 | 512 | apu_names[count + 0] = "Square 3"; |
292 | 512 | apu_names[count + 1] = "Square 4"; |
293 | 512 | apu_names[count + 2] = "PCM"; |
294 | | |
295 | 512 | count += Nes_Mmc5_Apu::osc_count; |
296 | 512 | } |
297 | | |
298 | 861 | if ( header_.chip_flags & vrc7_flag ) |
299 | 25 | { |
300 | 25 | vrc7 = BLARGG_NEW Nes_Vrc7_Apu; |
301 | 25 | CHECK_ALLOC( vrc7 ); |
302 | 25 | RETURN_ERR( vrc7->init() ); |
303 | 25 | adjusted_gain *= 0.75; |
304 | | |
305 | 25 | apu_names[count + 0] = "FM 1"; |
306 | 25 | apu_names[count + 1] = "FM 2"; |
307 | 25 | apu_names[count + 2] = "FM 3"; |
308 | 25 | apu_names[count + 3] = "FM 4"; |
309 | 25 | apu_names[count + 4] = "FM 5"; |
310 | 25 | apu_names[count + 5] = "FM 6"; |
311 | | |
312 | 25 | count += Nes_Vrc7_Apu::osc_count; |
313 | 25 | } |
314 | | |
315 | 861 | if ( namco ) namco->volume( adjusted_gain ); |
316 | 861 | if ( vrc6 ) vrc6 ->volume( adjusted_gain ); |
317 | 861 | if ( fme7 ) fme7 ->volume( adjusted_gain ); |
318 | 861 | if ( fds ) fds ->volume( adjusted_gain ); |
319 | 861 | if ( mmc5 ) mmc5 ->volume( adjusted_gain ); |
320 | 861 | if ( vrc7 ) vrc7 ->volume( adjusted_gain ); |
321 | 861 | } |
322 | 0 | #endif |
323 | | |
324 | 0 | set_voice_count( count ); |
325 | 861 | set_voice_names( &apu_names[0] ); |
326 | | |
327 | 861 | apu.volume( adjusted_gain ); |
328 | | |
329 | 861 | return 0; |
330 | 861 | } |
331 | | |
332 | | blargg_err_t Nsf_Emu::load_( Data_Reader& in ) |
333 | 868 | { |
334 | 868 | blaarg_static_assert( offsetof (header_t,unused [4]) == header_size, "NSF Header layout incorrect!" ); |
335 | 868 | RETURN_ERR( rom.load( in, header_size, &header_, 0 ) ); |
336 | | |
337 | 866 | set_track_count( header_.track_count ); |
338 | 866 | RETURN_ERR( check_nsf_header( &header_ ) ); |
339 | | |
340 | 861 | if ( header_.vers != 1 ) |
341 | 16 | set_warning( "Unknown file version" ); |
342 | | |
343 | | // sound and memory |
344 | 861 | blargg_err_t err = init_sound(); |
345 | 861 | if ( err ) |
346 | 0 | return err; |
347 | | |
348 | | // set up data |
349 | 861 | nes_addr_t load_addr = get_le16( header_.load_addr ); |
350 | 861 | init_addr = get_le16( header_.init_addr ); |
351 | 861 | play_addr = get_le16( header_.play_addr ); |
352 | 861 | if ( !load_addr ) load_addr = rom_begin; |
353 | 861 | if ( !init_addr ) init_addr = rom_begin; |
354 | 861 | if ( !play_addr ) play_addr = rom_begin; |
355 | 861 | if ( load_addr < rom_begin || init_addr < rom_begin ) |
356 | 13 | { |
357 | 13 | const char* w = warning(); |
358 | 13 | if ( !w ) |
359 | 4 | w = "Corrupt file (invalid load/init/play address)"; |
360 | 13 | return w; |
361 | 13 | } |
362 | | |
363 | 848 | rom.set_addr( load_addr % bank_size ); |
364 | 848 | int total_banks = rom.size() / bank_size; |
365 | | |
366 | | // bank switching |
367 | 848 | int first_bank = (load_addr - rom_begin) / bank_size; |
368 | 1.49k | for ( int i = 0; i < bank_count; i++ ) |
369 | 1.47k | { |
370 | 1.47k | unsigned bank = i - first_bank; |
371 | 1.47k | if ( bank >= (unsigned) total_banks ) |
372 | 594 | bank = 0; |
373 | 1.47k | initial_banks [i] = bank; |
374 | | |
375 | 1.47k | if ( header_.banks [i] ) |
376 | 832 | { |
377 | | // bank-switched |
378 | 832 | memcpy( initial_banks, header_.banks, sizeof initial_banks ); |
379 | 832 | break; |
380 | 832 | } |
381 | 1.47k | } |
382 | | |
383 | 848 | pal_only = (header_.speed_flags & 3) == 1; |
384 | | |
385 | 848 | #if !NSF_EMU_EXTRA_FLAGS |
386 | 848 | header_.speed_flags = 0; |
387 | 848 | #endif |
388 | | |
389 | 848 | set_tempo( tempo() ); |
390 | | |
391 | 848 | return setup_buffer( (long) (clock_rate_ + 0.5) ); |
392 | 861 | } |
393 | | |
394 | | void Nsf_Emu::update_eq( blip_eq_t const& eq ) |
395 | 1.72k | { |
396 | 1.72k | apu.treble_eq( eq ); |
397 | | |
398 | 1.72k | #if !NSF_EMU_APU_ONLY |
399 | 1.72k | { |
400 | 1.72k | if ( namco ) namco->treble_eq( eq ); |
401 | 1.72k | if ( vrc6 ) vrc6 ->treble_eq( eq ); |
402 | 1.72k | if ( fme7 ) fme7 ->treble_eq( eq ); |
403 | 1.72k | if ( fds ) fds ->treble_eq( eq ); |
404 | 1.72k | if ( mmc5 ) mmc5 ->treble_eq( eq ); |
405 | 1.72k | if ( vrc7 ) vrc7 ->treble_eq( eq ); |
406 | 1.72k | } |
407 | 1.72k | #endif |
408 | 1.72k | } |
409 | | |
410 | | void Nsf_Emu::set_voice( int i, Blip_Buffer* buf, Blip_Buffer*, Blip_Buffer* ) |
411 | 8.85k | { |
412 | 8.85k | if ( i < Nes_Apu::osc_count ) |
413 | 4.24k | { |
414 | 4.24k | apu.osc_output( i, buf ); |
415 | 4.24k | return; |
416 | 4.24k | } |
417 | 4.61k | i -= Nes_Apu::osc_count; |
418 | | |
419 | 4.61k | #if !NSF_EMU_APU_ONLY |
420 | 4.61k | #define HANDLE_CHIP(class, object) \ |
421 | 9.67k | if ( object ) \ |
422 | 9.67k | { \ |
423 | 4.68k | if ( i < class::osc_count ) \ |
424 | 4.68k | { \ |
425 | 2.89k | object->osc_output( i, buf ); \ |
426 | 2.89k | return; \ |
427 | 2.89k | } \ |
428 | 4.68k | i -= class::osc_count; \ |
429 | 1.78k | } |
430 | 4.61k | #define HANDLE_CHIP_VRC6(class, object) \ |
431 | 4.61k | if ( object ) \ |
432 | 4.61k | { \ |
433 | 3.83k | if ( i < class::osc_count ) \ |
434 | 3.83k | { \ |
435 | | /* put saw first */ \ |
436 | 1.71k | if ( --i < 0 ) \ |
437 | 1.71k | i = 2; \ |
438 | 1.71k | object->osc_output( i, buf ); \ |
439 | 1.71k | return; \ |
440 | 1.71k | } \ |
441 | 3.83k | i -= class::osc_count; \ |
442 | 2.11k | } |
443 | 4.61k | { |
444 | 4.61k | HANDLE_CHIP_VRC6(Nes_Vrc6_Apu, vrc6); |
445 | 2.89k | HANDLE_CHIP(Nes_Namco_Apu, namco); |
446 | 2.75k | HANDLE_CHIP(Nes_Fme7_Apu, fme7); |
447 | 2.23k | HANDLE_CHIP(Nes_Fds_Apu, fds); |
448 | 1.65k | HANDLE_CHIP(Nes_Mmc5_Apu, mmc5); |
449 | 138 | HANDLE_CHIP(Nes_Vrc7_Apu, vrc7); |
450 | 0 | } |
451 | 0 | #undef HANDLE_CHIP |
452 | 0 | #undef HANDLE_CHIP_VRC6 |
453 | 0 | #endif |
454 | 0 | } |
455 | | |
456 | | // Emulation |
457 | | |
458 | | // see nes_cpu_io.h for read/write functions |
459 | | |
460 | | void Nsf_Emu::cpu_write_misc( nes_addr_t addr, int data ) |
461 | 34.6M | { |
462 | 34.6M | #if !NSF_EMU_APU_ONLY |
463 | 34.6M | { |
464 | 34.6M | if ( fds ) |
465 | 13.7M | { |
466 | 13.7M | if ( (unsigned) (addr - fds->io_addr) < fds->io_size ) |
467 | 226 | { |
468 | 226 | fds->write( time(), addr, data); |
469 | 226 | return; |
470 | 226 | } |
471 | 13.7M | } |
472 | | |
473 | 34.6M | if ( namco ) |
474 | 19.1k | { |
475 | 19.1k | switch ( addr ) |
476 | 19.1k | { |
477 | 0 | case Nes_Namco_Apu::data_reg_addr: |
478 | 0 | namco->write_data( time(), data ); |
479 | 0 | return; |
480 | | |
481 | 0 | case Nes_Namco_Apu::addr_reg_addr: |
482 | 0 | namco->write_addr( data ); |
483 | 0 | return; |
484 | 19.1k | } |
485 | 19.1k | } |
486 | | |
487 | 34.6M | if ( addr >= Nes_Fme7_Apu::latch_addr && fme7 ) |
488 | 2.62M | { |
489 | 2.62M | switch ( addr & Nes_Fme7_Apu::addr_mask ) |
490 | 2.62M | { |
491 | 1.31M | case Nes_Fme7_Apu::latch_addr: |
492 | 1.31M | fme7->write_latch( data ); |
493 | 1.31M | return; |
494 | | |
495 | 1.31M | case Nes_Fme7_Apu::data_addr: |
496 | 1.31M | fme7->write_data( time(), data ); |
497 | 1.31M | return; |
498 | 2.62M | } |
499 | 2.62M | } |
500 | | |
501 | 32.0M | if ( vrc6 ) |
502 | 13.7M | { |
503 | 13.7M | unsigned reg = addr & (Nes_Vrc6_Apu::addr_step - 1); |
504 | 13.7M | unsigned osc = unsigned (addr - Nes_Vrc6_Apu::base_addr) / Nes_Vrc6_Apu::addr_step; |
505 | 13.7M | if ( osc < Nes_Vrc6_Apu::osc_count && reg < Nes_Vrc6_Apu::reg_count ) |
506 | 0 | { |
507 | 0 | vrc6->write_osc( time(), osc, reg, data ); |
508 | 0 | return; |
509 | 0 | } |
510 | 13.7M | } |
511 | | |
512 | 32.0M | if ( mmc5 ) |
513 | 8.37M | { |
514 | 8.37M | if ( (unsigned) (addr - mmc5->regs_addr) < mmc5->regs_size) |
515 | 0 | { |
516 | 0 | mmc5->write_register( time(), addr, data ); |
517 | 0 | return; |
518 | 0 | } |
519 | | |
520 | 8.37M | int m = addr - 0x5205; |
521 | 8.37M | if ( (unsigned) m < 2 ) |
522 | 0 | { |
523 | 0 | mmc5_mul [m] = data; |
524 | 0 | return; |
525 | 0 | } |
526 | | |
527 | 8.37M | int i = addr - 0x5C00; |
528 | 8.37M | if ( (unsigned) i < mmc5->exram_size ) |
529 | 455 | { |
530 | 455 | mmc5->exram [i] = data; |
531 | 455 | return; |
532 | 455 | } |
533 | 8.37M | } |
534 | | |
535 | 32.0M | if ( vrc7 ) |
536 | 4.01k | { |
537 | 4.01k | if ( addr == 0x9010 ) |
538 | 0 | { |
539 | 0 | vrc7->write_reg( data ); |
540 | 0 | return; |
541 | 0 | } |
542 | | |
543 | 4.01k | if ( (unsigned) (addr - 0x9028) <= 0x08 ) |
544 | 0 | { |
545 | 0 | vrc7->write_data( time(), data ); |
546 | 0 | return; |
547 | 0 | } |
548 | 4.01k | } |
549 | 32.0M | } |
550 | 32.0M | #endif |
551 | | |
552 | | // unmapped write |
553 | | |
554 | | #ifndef NDEBUG |
555 | | { |
556 | | // some games write to $8000 and $8001 repeatedly |
557 | | if ( addr == 0x8000 || addr == 0x8001 ) return; |
558 | | |
559 | | // probably namco sound mistakenly turned on in mck |
560 | | if ( addr == 0x4800 || addr == 0xF800 ) return; |
561 | | |
562 | | // memory mapper? |
563 | | if ( addr == 0xFFF8 ) return; |
564 | | |
565 | | debug_printf( "write_unmapped( 0x%04X, 0x%02X )\n", (unsigned) addr, (unsigned) data ); |
566 | | } |
567 | | #endif |
568 | 32.0M | } |
569 | | |
570 | | blargg_err_t Nsf_Emu::start_track_( int track ) |
571 | 5.33k | { |
572 | 5.33k | RETURN_ERR( Classic_Emu::start_track_( track ) ); |
573 | | |
574 | 5.33k | memset( low_mem, 0, sizeof low_mem ); |
575 | 5.33k | memset( sram, 0, sizeof sram ); |
576 | | |
577 | 5.33k | cpu::reset( unmapped_code ); // also maps low_mem |
578 | 5.33k | cpu::map_code( sram_addr, sizeof sram, sram ); |
579 | 48.0k | for ( int i = 0; i < bank_count; ++i ) |
580 | 42.6k | cpu_write( bank_select_addr + i, initial_banks [i] ); |
581 | | |
582 | 5.33k | apu.reset( pal_only, (header_.speed_flags & 0x20) ? 0x3F : 0 ); |
583 | 5.33k | apu.write_register( 0, 0x4015, 0x0F ); |
584 | 5.33k | apu.write_register( 0, 0x4017, (header_.speed_flags & 0x10) ? 0x80 : 0 ); |
585 | 5.33k | #if !NSF_EMU_APU_ONLY |
586 | 5.33k | if ( mmc5 ) |
587 | 3.39k | { |
588 | 3.39k | mmc5_mul [0] = 0; |
589 | 3.39k | mmc5_mul [1] = 0; |
590 | 3.39k | memset( mmc5->exram, 0, mmc5->exram_size ); |
591 | 3.39k | } |
592 | | |
593 | 5.33k | { |
594 | 5.33k | if ( namco ) namco->reset(); |
595 | 5.33k | if ( vrc6 ) vrc6 ->reset(); |
596 | 5.33k | if ( fme7 ) fme7 ->reset(); |
597 | 5.33k | if ( fds ) fds ->reset(); |
598 | 5.33k | if ( mmc5 ) mmc5 ->reset(); |
599 | 5.33k | if ( vrc7 ) vrc7 ->reset(); |
600 | 5.33k | } |
601 | 5.33k | #endif |
602 | | |
603 | 5.33k | play_ready = 4; |
604 | 5.33k | play_extra = 0; |
605 | 5.33k | next_play = play_period / clock_divisor; |
606 | | |
607 | 5.33k | saved_state.pc = badop_addr; |
608 | 5.33k | low_mem [0x1FF] = (badop_addr - 1) >> 8; |
609 | 5.33k | low_mem [0x1FE] = (badop_addr - 1) & 0xFF; |
610 | 5.33k | r.sp = 0xFD; |
611 | 5.33k | r.pc = init_addr; |
612 | 5.33k | r.a = track; |
613 | 5.33k | r.x = pal_only; |
614 | | |
615 | 5.33k | return 0; |
616 | 5.33k | } |
617 | | |
618 | | blargg_err_t Nsf_Emu::run_clocks( blip_time_t& duration, int ) |
619 | 859k | { |
620 | 859k | set_time( 0 ); |
621 | 156M | while ( time() < duration ) |
622 | 155M | { |
623 | 155M | nes_time_t end = min( (blip_time_t) next_play, duration ); |
624 | 155M | end = min( end, time() + 32767 ); // allows CPU to use 16-bit time delta |
625 | 155M | if ( cpu::run( end ) ) |
626 | 140M | { |
627 | 140M | if ( r.pc != badop_addr ) |
628 | 128M | { |
629 | 128M | set_warning( "Emulation error (illegal instruction)" ); |
630 | 128M | r.pc++; |
631 | 128M | } |
632 | 11.9M | else |
633 | 11.9M | { |
634 | 11.9M | play_ready = 1; |
635 | 11.9M | if ( saved_state.pc != badop_addr ) |
636 | 127k | { |
637 | 127k | cpu::r = saved_state; |
638 | 127k | saved_state.pc = badop_addr; |
639 | 127k | } |
640 | 11.7M | else |
641 | 11.7M | { |
642 | 11.7M | set_time( end ); |
643 | 11.7M | } |
644 | 11.9M | } |
645 | 140M | } |
646 | | |
647 | 155M | if ( time() >= next_play ) |
648 | 24.9M | { |
649 | 24.9M | nes_time_t period = (play_period + play_extra) / clock_divisor; |
650 | 24.9M | play_extra = play_period - period * clock_divisor; |
651 | 24.9M | next_play += period; |
652 | 24.9M | if ( play_ready && !--play_ready ) |
653 | 10.6M | { |
654 | 10.6M | check( saved_state.pc == badop_addr ); |
655 | 10.6M | if ( r.pc != badop_addr ) |
656 | 129k | saved_state = cpu::r; |
657 | | |
658 | 10.6M | r.pc = play_addr; |
659 | 10.6M | low_mem [0x100 + r.sp--] = (badop_addr - 1) >> 8; |
660 | 10.6M | low_mem [0x100 + r.sp--] = (badop_addr - 1) & 0xFF; |
661 | 10.6M | GME_FRAME_HOOK( this ); |
662 | 10.6M | } |
663 | 24.9M | } |
664 | 155M | } |
665 | | |
666 | 859k | if ( cpu::error_count() ) |
667 | 130k | { |
668 | 130k | cpu::clear_error_count(); |
669 | 130k | set_warning( "Emulation error (illegal instruction)" ); |
670 | 130k | } |
671 | | |
672 | 859k | duration = time(); |
673 | 859k | next_play -= duration; |
674 | 859k | check( next_play >= 0 ); |
675 | 859k | if ( next_play < 0 ) |
676 | 161 | next_play = 0; |
677 | | |
678 | 859k | apu.end_frame( duration ); |
679 | | |
680 | 859k | #if !NSF_EMU_APU_ONLY |
681 | 859k | { |
682 | 859k | if ( namco ) namco->end_frame( duration ); |
683 | 859k | if ( vrc6 ) vrc6 ->end_frame( duration ); |
684 | 859k | if ( fme7 ) fme7 ->end_frame( duration ); |
685 | 859k | if ( fds ) fds ->end_frame( duration ); |
686 | 859k | if ( mmc5 ) mmc5 ->end_frame( duration ); |
687 | 859k | if ( vrc7 ) vrc7 ->end_frame( duration ); |
688 | 859k | } |
689 | 859k | #endif |
690 | | |
691 | 859k | return 0; |
692 | 859k | } |