Coverage Report

Created: 2026-08-14 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}