1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2006 Adam Gashlin (hcs)
10 * Copyright (C) 2004 Disch
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 * This is a perversion of Disch's excellent NotSoFatso.
32 /* arm doesn't benefit from IRAM? */
39 #define ICODE_INSTEAD_OF_INLINE
42 /* Maximum number of bytes to process in one iteration */
43 #define WAV_CHUNK_SIZE (1024*2)
45 static int16_t samples
[WAV_CHUNK_SIZE
] IBSS_ATTR
;
47 #define ZEROMEMORY(addr,size) memset(addr,0,size)
49 /* simple profiling with USEC_TIMER
57 #define CREATE_TIMER(name) uint32_t nsf_timer_##name##_start,\
58 nsf_timer_##name##_total
59 #define ENTER_TIMER(name) nsf_timer_##name##_start=USEC_TIMER
60 #define EXIT_TIMER(name) nsf_timer_##name##_total+=\
61 (USEC_TIMER-nsf_timer_##name##_start)
62 #define READ_TIMER(name) (nsf_timer_##name##_total)
63 #define RESET_TIMER(name) nsf_timer_##name##_total=0
65 #define PRINT_TIMER_PCT(bname,tname,nstr) ci->fdprintf(
66 logfd
,"%10ld ",READ_TIMER(bname
));\
67 ci
->fdprintf(logfd
,"(%3d%%) " nstr
"\t",\
68 ((uint64_t)READ_TIMER(bname
))*100/READ_TIMER(tname
))
73 CREATE_TIMER(squares
);
75 CREATE_TIMER(tnd_enter
);
76 CREATE_TIMER(tnd_tri
);
77 CREATE_TIMER(tnd_noise
);
78 CREATE_TIMER(tnd_dmc
);
83 void reset_profile_timers(void) {
89 RESET_TIMER(tnd_enter
);
91 RESET_TIMER(tnd_noise
);
100 void print_timers(char * path
, int track
) {
101 logfd
= ci
->open("/nsflog.txt",O_WRONLY
|O_CREAT
|O_APPEND
);
102 ci
->fdprintf(logfd
,"%s[%d]:\t",path
,track
);
103 ci
->fdprintf(logfd
,"%10ld total\t",READ_TIMER(total
));
104 PRINT_TIMER_PCT(cpu
,total
,"CPU");
105 PRINT_TIMER_PCT(apu
,total
,"APU");
106 ci
->fdprintf(logfd
,"\n\t");
107 PRINT_TIMER_PCT(squares
,apu
,"squares");
108 PRINT_TIMER_PCT(frame
,apu
,"frame");
109 PRINT_TIMER_PCT(mix
,apu
,"mix");
110 PRINT_TIMER_PCT(fds
,apu
,"FDS");
111 PRINT_TIMER_PCT(tnd
,apu
,"tnd");
112 ci
->fdprintf(logfd
,"\n\t\t");
113 PRINT_TIMER_PCT(tnd_enter
,tnd
,"enter");
114 PRINT_TIMER_PCT(tnd_tri
,tnd
,"triangle");
115 PRINT_TIMER_PCT(tnd_noise
,tnd
,"noise");
116 PRINT_TIMER_PCT(tnd_dmc
,tnd
,"DMC");
117 ci
->fdprintf(logfd
,"\n");
125 #define CREATE_TIMER(name)
126 #define ENTER_TIMER(name)
127 #define EXIT_TIMER(name)
128 #define READ_TIMER(name)
129 #define RESET_TIMER(name)
130 #define print_timers(path,track)
131 #define reset_profile_timers()
135 /* proper handling of multibyte values */
136 #ifdef ROCKBOX_LITTLE_ENDIAN
140 struct{ uint8_t l
; uint8_t h
; } B
;
146 struct{ uint8_t l
; uint8_t h
; uint16_t w
; } B
;
153 struct{ uint8_t h
; uint8_t l
; } B
;
159 struct{uint16_t w
; uint8_t h
; uint8_t l
; } B
;
164 #define NTSC_FREQUENCY 1789772.727273f
165 #define PAL_FREQUENCY 1652097.692308f
166 #define NTSC_NMIRATE 60.098814f
167 #define PAL_NMIRATE 50.006982f
169 #define NES_FREQUENCY 21477270
170 #define NTSC_FRAME_COUNTER_FREQ (NTSC_FREQUENCY / (NES_FREQUENCY / 89490.0f))
171 #define PAL_FRAME_COUNTER_FREQ (PAL_FREQUENCY / (NES_FREQUENCY / 89490.0f))
173 /****************** tables */
174 static const int32_t ModulationTable
[8] ICONST_ATTR
= {0,1,2,4,0,-4,-2,-1};
175 const uint16_t DMC_FREQ_TABLE
[2][0x10] = {
177 {0x1AC,0x17C,0x154,0x140,0x11E,0x0FE,0x0E2,0x0D6,0x0BE,0x0A0,0x08E,0x080,
178 0x06A,0x054,0x048,0x036},
180 {0x18C,0x160,0x13A,0x128,0x108,0x0EA,0x0D0,0x0C6,0x0B0,0x094,0x082,0x076,
181 0x062,0x04E,0x042,0x032}
184 const uint8_t DUTY_CYCLE_TABLE
[4] = {2,4,8,12};
186 const uint8_t LENGTH_COUNTER_TABLE
[0x20] = {
187 0x0A,0xFE,0x14,0x02,0x28,0x04,0x50,0x06,0xA0,0x08,0x3C,0x0A,0x0E,0x0C,0x1A,
188 0x0E,0x0C,0x10,0x18,0x12,0x30,0x14,0x60,0x16,0xC0,0x18,0x48,0x1A,0x10,0x1C,
192 const uint16_t NOISE_FREQ_TABLE
[0x10] = {
193 0x004,0x008,0x010,0x020,0x040,0x060,0x080,0x0A0,0x0CA,0x0FE,0x17C,0x1FC,
194 0x2FA,0x3F8,0x7F2,0xFE4
197 /****************** NSF loading ******************/
199 /* file format structs (both are little endian) */
204 uint8_t nHeaderExtra
;
207 uint8_t nInitialTrack
;
208 uint16_t nLoadAddress
;
209 uint16_t nInitAddress
;
210 uint16_t nPlayAddress
;
211 uint8_t szGameTitle
[32];
212 uint8_t szArtist
[32];
213 uint8_t szCopyright
[32];
215 uint8_t nBankSwitch
[8];
219 uint8_t nExpansion
[4];
222 struct NSFE_INFOCHUNK
224 uint16_t nLoadAddress
;
225 uint16_t nInitAddress
;
226 uint16_t nPlayAddress
;
230 uint8_t nStartingTrack
;
233 int32_t LoadFile(uint8_t *,size_t);
235 int32_t LoadFile_NESM(uint8_t *,size_t);
236 int32_t LoadFile_NSFE(uint8_t *,size_t);
241 int32_t bIsExtended
=0; /* 0 = NSF, 1 = NSFE */
242 uint8_t nIsPal
=0; /* 0 = NTSC, 1 = PAL,
243 2,3 = mixed NTSC/PAL (interpretted as NTSC) */
244 int32_t nfileLoadAddress
=0; /* The address to which the NSF code is
246 int32_t nfileInitAddress
=0; /* The address of the Init routine
247 (called at track change) */
248 int32_t nfilePlayAddress
=0; /* The address of the Play routine
249 (called several times a second) */
250 uint8_t nChipExtensions
=0; /* Bitwise representation of the external chips
253 /* old NESM speed stuff (blarg) */
254 int32_t nNTSC_PlaySpeed
=0;
255 int32_t nPAL_PlaySpeed
=0;
258 /* The number of tracks in the NSF (1 = 1 track, 5 = 5 tracks, etc) */
259 int32_t nTrackCount
=0;
260 /* The initial track (ZERO BASED: 0 = 1st track, 4 = 5th track, etc) */
261 int32_t nInitialTrack
=0;
264 uint8_t* pDataBuffer
=0; /* the buffer containing NSF code. */
265 int32_t nDataBufferSize
=0; /* the size of the above buffer. */
268 uint8_t nPlaylist
[256]; /* Each entry is the zero based index of the
270 int32_t nPlaylistSize
=0; /* the number of tracks in the playlist */
272 /* track time / fade */
273 int32_t nTrackTime
[256]; /* track times -1 if no track times specified */
274 int32_t nTrackFade
[256]; /* track fade times -1 if none are specified */
277 uint8_t szGameTitle
[0x101];
278 uint8_t szArtist
[0x101];
279 uint8_t szCopyright
[0x101];
280 uint8_t szRipper
[0x101];
282 /* bankswitching info */
283 uint8_t nBankswitch
[8]={0}; /* The initial bankswitching registers needed
284 * for some NSFs. If the NSF does not use
285 * bankswitching, these values will all be zero
288 int32_t LoadFile(uint8_t * inbuffer
, size_t size
)
290 if(!inbuffer
) return -1;
294 if(!memcmp(inbuffer
,"NESM",4)) ret
= LoadFile_NESM(inbuffer
,size
);
295 if(!memcmp(inbuffer
,"NSFE",4)) ret
= LoadFile_NSFE(inbuffer
,size
);
298 * Snake's revenge puts '00' for the initial track,
299 * which (after subtracting 1) makes it 256 or -1 (bad!)
300 * This prevents that crap
302 if(nInitialTrack
>= nTrackCount
)
304 if(nInitialTrack
< 0)
307 /* if there's no tracks... this is a crap NSF */
316 int32_t LoadFile_NESM(uint8_t* inbuffer
, size_t size
)
318 uint8_t ignoreversion
=1;
322 struct NESM_HEADER hdr
;
324 memcpy(&hdr
,inbuffer
,sizeof(hdr
));
326 /* confirm the header */
327 if(memcmp("NESM",&(hdr
.nHeader
),4)) return -1;
328 if(hdr
.nHeaderExtra
!= 0x1A) return -1;
329 /* stupid NSFs claim to be above version 1 >_> */
330 if((!ignoreversion
) && (hdr
.nVersion
!= 1)) return -1;
333 * NESM is generally easier to work with (but limited!)
334 * just move the data over from NESM_HEADER over to our member data
338 nIsPal
= hdr
.nNTSC_PAL
& 0x03;
339 nPAL_PlaySpeed
= letoh16(hdr
.nSpeedPAL
);
340 nNTSC_PlaySpeed
= letoh16(hdr
.nSpeedNTSC
);
341 nfileLoadAddress
= letoh16(hdr
.nLoadAddress
);
342 nfileInitAddress
= letoh16(hdr
.nInitAddress
);
343 nfilePlayAddress
= letoh16(hdr
.nPlayAddress
);
344 nChipExtensions
= hdr
.nExtraChip
;
347 nTrackCount
= hdr
.nTrackCount
;
348 nInitialTrack
= hdr
.nInitialTrack
- 1;
350 memcpy(nBankswitch
,hdr
.nBankSwitch
,8);
352 memcpy(szGameTitle
,hdr
.szGameTitle
,32);
353 memcpy(szArtist
,hdr
.szArtist
,32);
354 memcpy(szCopyright
,hdr
.szCopyright
,32);
356 /* read the NSF data */
359 pDataBuffer
=inbuffer
+0x80;
360 nDataBufferSize
=size
-0x80;
363 /* if we got this far... it was a successful read */
367 int32_t LoadFile_NSFE(uint8_t* inbuffer
, size_t size
)
369 /* the vars we'll be using */
374 uint8_t * nDataPos
= 0;
375 uint8_t bInfoFound
= 0;
376 uint8_t bEndFound
= 0;
377 uint8_t bBankFound
= 0;
380 struct NSFE_INFOCHUNK info
;
381 ZEROMEMORY(&info
,sizeof(struct NSFE_INFOCHUNK
));
382 ZEROMEMORY(nBankswitch
,8);
383 info
.nTrackCount
= 1; /* default values */
385 if (size
< 8) return -1; /* must have at least NSFE,NEND */
387 /* confirm the header! */
388 memcpy(&nChunkType
,inbuffer
,4);
390 if(memcmp(&nChunkType
,"NSFE",4)) return -1;
392 for (i
=0;i
<256;i
++) {
397 /* begin reading chunks */
400 memcpy(&nChunkSize
,inbuffer
,4);
401 nChunkSize
=letoh32(nChunkSize
);
403 memcpy(&nChunkType
,inbuffer
,4);
406 if(!memcmp(&nChunkType
,"INFO",4)) {
407 /* only one info chunk permitted */
408 if(bInfoFound
) return -1;
409 if(nChunkSize
< 8) return -1; /* minimum size */
412 nChunkUsed
= MIN((int32_t)sizeof(struct NSFE_INFOCHUNK
),
415 memcpy(&info
,inbuffer
,nChunkUsed
);
416 inbuffer
+=nChunkSize
;
419 nIsPal
= info
.nIsPal
& 3;
420 nfileLoadAddress
= letoh16(info
.nLoadAddress
);
421 nfileInitAddress
= letoh16(info
.nInitAddress
);
422 nfilePlayAddress
= letoh16(info
.nPlayAddress
);
423 nChipExtensions
= info
.nExt
;
424 nTrackCount
= info
.nTrackCount
;
425 nInitialTrack
= info
.nStartingTrack
;
427 nPAL_PlaySpeed
= (uint16_t)(1000000 / PAL_NMIRATE
);
428 nNTSC_PlaySpeed
= (uint16_t)(1000000 / NTSC_NMIRATE
);
429 } else if (!memcmp(&nChunkType
,"DATA",4)) {
430 if(!bInfoFound
) return -1;
431 if(nDataPos
) return -1;
432 if(nChunkSize
< 1) return -1;
434 nDataBufferSize
= nChunkSize
;
437 inbuffer
+=nChunkSize
;
438 } else if (!memcmp(&nChunkType
,"NEND",4)) {
440 } else if (!memcmp(&nChunkType
,"time",4)) {
441 if(!bInfoFound
) return -1;
442 for (nChunkUsed
=0; nChunkUsed
< MIN(nChunkSize
/ 4,nTrackCount
);
443 nChunkUsed
++,inbuffer
+=4) {
444 nTrackTime
[nChunkUsed
]=
445 ((uint32_t)inbuffer
[0])|
446 ((uint32_t)inbuffer
[1]<<8)|
447 ((uint32_t)inbuffer
[2]<<16)|
448 ((uint32_t)inbuffer
[3]<<24);
451 inbuffer
+=nChunkSize
-(nChunkUsed
*4);
453 /* negative signals to use default time */
454 for(; nChunkUsed
< nTrackCount
; nChunkUsed
++)
455 nTrackTime
[nChunkUsed
] = -1;
456 } else if (!memcmp(&nChunkType
,"fade",4)) {
457 if(!bInfoFound
) return -1;
458 for (nChunkUsed
=0; nChunkUsed
< MIN(nChunkSize
/ 4,nTrackCount
);
459 nChunkUsed
++,inbuffer
+=4) {
460 nTrackFade
[nChunkUsed
]=
461 ((uint32_t)inbuffer
[0])|
462 ((uint32_t)inbuffer
[1]<<8)|
463 ((uint32_t)inbuffer
[2]<<16)|
464 ((uint32_t)inbuffer
[3]<<24);
467 inbuffer
+=nChunkSize
-(nChunkUsed
*4);
469 /* negative signals to use default time */
470 for(; nChunkUsed
< nTrackCount
; nChunkUsed
++)
471 nTrackFade
[nChunkUsed
] = -1;
472 } else if (!memcmp(&nChunkType
,"BANK",4)) {
473 if(bBankFound
) return -1;
476 nChunkUsed
= MIN(8,nChunkSize
);
477 memcpy(nBankswitch
,inbuffer
,nChunkUsed
);
479 inbuffer
+=nChunkSize
;
480 } else if (!memcmp(&nChunkType
,"plst",4)) {
482 nPlaylistSize
= nChunkSize
;
483 if(nPlaylistSize
>= 1) {
485 memcpy(nPlaylist
,inbuffer
,nChunkSize
);
486 inbuffer
+=nChunkSize
;
488 } else if (!memcmp(&nChunkType
,"auth",4)) {
493 uint8_t* ar
[4] = {szGameTitle
,szArtist
,szCopyright
,szRipper
};
495 for(i
= 0; (ptr
-inbuffer
)<nChunkSize
&& i
< 4; i
++)
497 nChunkUsed
= strlen(ptr
) + 1;
498 memcpy(ar
[i
],ptr
,nChunkUsed
);
501 inbuffer
+=nChunkSize
;
502 } else if (!memcmp(&nChunkType
,"tlbl",4)) {
503 /* we unfortunately can't use these anyway */
504 inbuffer
+=nChunkSize
;
505 } else { /* unknown chunk */
506 nChunkType
= letoh32(nChunkType
)>>24; /* check the first byte */
507 /* chunk is vital... don't continue */
508 if((nChunkType
>= 'A') && (nChunkType
<= 'Z'))
510 /* otherwise, just skip it */
511 inbuffer
+=nChunkSize
;
512 } /* end if series */
516 * if we exited the while loop without a 'return', we must have hit an NEND
517 * chunk if this is the case, the file was layed out as it was expected.
518 * now.. make sure we found both an info chunk, AND a data chunk... since
519 * these are minimum requirements for a valid NSFE file
522 if(!bInfoFound
) return -1;
523 if(!nDataPos
) return -1;
525 /* if both those chunks existed, this file is valid.
526 Load the data if it's needed */
528 pDataBuffer
=nDataPos
;
530 /* return success! */
535 /****************** Audio Device Structures ******************/
540 uint8_t bEnvelopeEnable
;
541 uint8_t nEnvelopeSpeed
;
543 /* Volume Envelope */
544 uint8_t nVolEnv_Mode
;
545 uint8_t nVolEnv_Decay
;
546 uint8_t nVolEnv_Gain
;
547 int32_t nVolEnv_Timer
;
548 int32_t nVolEnv_Count
;
552 /* Sweep Envenlope */
554 uint8_t nSweep_Decay
;
555 int32_t nSweep_Timer
;
556 int32_t nSweep_Count
;
558 uint8_t bSweepEnv_On
;
560 /* Effector / LFO / Modulation Unit */
562 uint8_t bLFO_Enabled
;
563 union TWIN nLFO_Freq
;
564 /*float fLFO_Timer;*/
565 /*float fLFO_Count;*/
566 int32_t nLFO_Timer
; /* -17.14*/
567 int32_t nLFO_Count
; /* -17.14*/
569 uint8_t nLFO_Table
[0x40];
576 /*float fFreqCount;*/
577 int32_t nFreqCount
; /* -17.14 */
579 uint8_t nWaveTable
[0x40];
583 /* Output and Downsampling */
592 int16_t FDS_nOutputTable_L
[4][0x21][0x40];
596 /* Frequency Control */
597 union TWIN nFreqTimer
;
600 /* Channel Disabling */
601 uint8_t bChannelEnabled
;
609 /* Output and Downsampling */
613 int16_t FME07_nOutputTable_L
[0x10] IDATA_ATTR
;
617 /* All Channel Stuff */
619 uint8_t nActiveChannels
;
620 uint8_t bAutoIncrement
;
621 uint8_t nCurrentAddress
;
622 uint8_t nRAM
[0x100]; /* internal memory for registers/wave data */
623 int32_t nFrequencyLookupTable
[8]; /* lookup tbl for freq conversions */
626 * Individual channel stuff
628 /* Wavelength / Frequency */
629 union QUAD nFreqReg
[8];
630 int32_t nFreqTimer
[8];
631 int32_t nFreqCount
[8];
633 /* Wave data length / remaining */
634 uint8_t nWaveSize
[8];
635 uint8_t nWaveRemaining
[8];
637 /* Wave data position */
638 uint8_t nWavePosStart
[8];
646 uint8_t nPreVolume
[8];
647 uint8_t nPopCheck
[8];
653 int16_t N106_nOutputTable_L
[0x10][0x10];
658 /* Frequency Control */
659 union TWIN nFreqTimer
;
663 uint8_t bChannelEnabled
;
673 /* Output and Downsampling */
678 int16_t VRC6Pulse_nOutputTable_L
[0x10] IDATA_ATTR
;
683 /* Frequency Control */
684 union TWIN nFreqTimer
;
688 uint8_t bChannelEnabled
;
690 /* Phase Accumulator */
695 /* Output and Downsampling */
700 int16_t VRC6Saw_nOutputTable_L
[0x20] IDATA_ATTR
;
705 /* Programmable Timer */
706 union TWIN nFreqTimer
[2];
707 int32_t nFreqCount
[2];
710 uint8_t nLengthCount
[2];
711 uint8_t bLengthEnabled
[2];
712 uint8_t bChannelEnabled
[2];
716 uint8_t nDecayVolume
[2];
717 uint8_t bDecayEnable
[2];
718 uint8_t bDecayLoop
[2];
719 uint8_t nDecayTimer
[2];
720 uint8_t nDecayCount
[2];
723 uint8_t bSweepEnable
[2];
724 uint8_t bSweepMode
[2];
725 uint8_t bSweepForceSilence
[2];
726 uint8_t nSweepTimer
[2];
727 uint8_t nSweepCount
[2];
728 uint8_t nSweepShift
[2];
731 uint8_t nDutyCount
[2];
732 uint8_t nDutyCycle
[2];
734 /* Output and Downsampling */
738 int16_t Squares_nOutputTable_L
[0x10][0x10] IDATA_ATTR
;
747 /* Programmable Timer */
748 union TWIN nTriFreqTimer
;
749 int32_t nTriFreqCount
;
752 uint8_t nTriLengthCount
;
753 uint8_t bTriLengthEnabled
;
754 uint8_t bTriChannelEnabled
;
757 uint8_t nTriLinearCount
;
758 uint8_t nTriLinearLoad
;
759 uint8_t bTriLinearHalt
;
760 uint8_t bTriLinearControl
;
762 /* Tri-Step Generator / Output */
770 /* Programmable Timer */
771 uint16_t nNoiseFreqTimer
;
772 int32_t nNoiseFreqCount
;
775 uint8_t nNoiseLengthCount
;
776 uint8_t bNoiseLengthEnabled
;
777 uint8_t bNoiseChannelEnabled
;
780 uint8_t nNoiseVolume
;
781 uint8_t nNoiseDecayVolume
;
782 uint8_t bNoiseDecayEnable
;
783 uint8_t bNoiseDecayLoop
;
784 uint8_t nNoiseDecayTimer
;
785 uint8_t nNoiseDecayCount
;
787 /* Random Number Generator */
788 uint16_t nNoiseRandomShift
;
789 uint8_t bNoiseRandomMode
; /* 1 = 32k, 6 = 93-bit */
790 uint8_t bNoiseRandomOut
;
798 uint8_t bDMCIRQEnabled
;
799 uint8_t bDMCIRQPending
;
802 uint8_t nDMCDMABank_Load
;
803 uint16_t nDMCDMAAddr_Load
;
805 uint16_t nDMCDMAAddr
;
806 uint8_t* pDMCDMAPtr
[8];
810 uint16_t nDMCBytesRemaining
;
812 uint8_t nDMCDeltaBit
;
813 uint8_t bDMCDeltaSilent
;
814 uint8_t nDMCSampleBuffer
;
815 uint8_t bDMCSampleBufferEmpty
;
818 uint16_t nDMCFreqTimer
;
819 int32_t nDMCFreqCount
;
829 struct Wave_Squares mWave_Squares IDATA_ATTR
; /* Square channels 1 and 2 */
830 struct Wave_TND mWave_TND IDATA_ATTR
; /* Triangle/Noise/DMC channels */
831 struct VRC6PulseWave mWave_VRC6Pulse
[2] IDATA_ATTR
;
832 struct VRC6SawWave mWave_VRC6Saw IDATA_ATTR
;
833 struct N106Wave mWave_N106 IDATA_ATTR
;
834 struct FDSWave mWave_FDS IDATA_ATTR
;
835 struct FME07Wave mWave_FME07
[3] IDATA_ATTR
; /* FME-07's 3 pulse channels */
838 /****************** MMC5 ******************/
839 /* will include MMC5 sound channels some day,
840 currently only multiply is supported */
842 /****************** N106 (Disch loves this chip) ******************/
844 #ifdef ICODE_INSTEAD_OF_INLINE
845 void Wave_N106_DoTicks(const int32_t ticks
) ICODE_ATTR
;
846 void Wave_N106_DoTicks(const int32_t ticks
)
848 inline void Wave_N106_DoTicks(const int32_t ticks
);
849 inline void Wave_N106_DoTicks(const int32_t ticks
)
854 for(i
= (7 - mWave_N106
.nActiveChannels
); i
< 8; i
++)
856 if(!mWave_N106
.nFreqReg
[i
].D
)
858 /* written frequency of zero will cause divide by zero error
859 makes me wonder if the formula was supposed to be Reg+1 */
860 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
865 mWave_N106
.nMixL
[i
] =
866 N106_nOutputTable_L
[mWave_N106
.nVolume
[i
]]
867 [mWave_N106
.nOutput
[i
]];
869 if(mWave_N106
.nFreqTimer
[i
] < 0)
870 mWave_N106
.nFreqTimer
[i
] =
871 (mWave_N106
.nFrequencyLookupTable
[mWave_N106
.nActiveChannels
] /
872 mWave_N106
.nFreqReg
[i
].D
);
873 if(mWave_N106
.nFreqCount
[i
] > mWave_N106
.nFreqTimer
[i
])
874 mWave_N106
.nFreqCount
[i
] = mWave_N106
.nFreqTimer
[i
];
876 mWave_N106
.nFreqCount
[i
] -= ticks
<< 8;
877 while(mWave_N106
.nFreqCount
[i
] <= 0)
879 mWave_N106
.nFreqCount
[i
] += mWave_N106
.nFreqTimer
[i
];
880 if(mWave_N106
.nWaveRemaining
[i
])
882 mWave_N106
.nWaveRemaining
[i
]--;
883 mWave_N106
.nWavePos
[i
]++;
885 if(!mWave_N106
.nWaveRemaining
[i
])
887 mWave_N106
.nWaveRemaining
[i
] = mWave_N106
.nWaveSize
[i
];
888 mWave_N106
.nWavePos
[i
] = mWave_N106
.nWavePosStart
[i
];
889 if(mWave_N106
.nVolume
[i
] != mWave_N106
.nPreVolume
[i
])
891 if(++mWave_N106
.nPopCheck
[i
] >= 2)
893 mWave_N106
.nPopCheck
[i
] = 0;
894 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
899 mWave_N106
.nOutput
[i
] =
900 mWave_N106
.nRAM
[mWave_N106
.nWavePos
[i
]];
902 if(!mWave_N106
.nOutput
[i
])
904 mWave_N106
.nPopCheck
[i
] = 0;
905 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
912 /****************** VRC6 ******************/
914 #ifdef ICODE_INSTEAD_OF_INLINE
915 void Wave_VRC6_DoTicks(const int32_t ticks
) ICODE_ATTR
;
916 void Wave_VRC6_DoTicks(const int32_t ticks
)
918 inline void Wave_VRC6_DoTicks(const int32_t ticks
);
919 inline void Wave_VRC6_DoTicks(const int32_t ticks
)
924 for(i
= 0; i
< 2; i
++) {
926 if(mWave_VRC6Pulse
[i
].bChannelEnabled
) {
928 mWave_VRC6Pulse
[i
].nFreqCount
-= ticks
;
930 if(mWave_VRC6Pulse
[i
].nDutyCount
<=
931 mWave_VRC6Pulse
[i
].nDutyCycle
)
933 mWave_VRC6Pulse
[i
].nMixL
=
934 VRC6Pulse_nOutputTable_L
[mWave_VRC6Pulse
[i
].nVolume
];
937 mWave_VRC6Pulse
[i
].nMixL
= 0;
939 while(mWave_VRC6Pulse
[i
].nFreqCount
<= 0) {
940 mWave_VRC6Pulse
[i
].nFreqCount
+=
941 mWave_VRC6Pulse
[i
].nFreqTimer
.W
+ 1;
943 if(!mWave_VRC6Pulse
[i
].bDigitized
)
944 mWave_VRC6Pulse
[i
].nDutyCount
=
945 (mWave_VRC6Pulse
[i
].nDutyCount
+ 1) & 0x0F;
950 if(mWave_VRC6Saw
.bChannelEnabled
) {
952 mWave_VRC6Saw
.nFreqCount
-= ticks
;
954 mWave_VRC6Saw
.nMixL
=
955 VRC6Saw_nOutputTable_L
[mWave_VRC6Saw
.nAccum
>> 3];
957 while(mWave_VRC6Saw
.nFreqCount
<= 0) {
959 mWave_VRC6Saw
.nFreqCount
+= mWave_VRC6Saw
.nFreqTimer
.W
+ 1;
961 mWave_VRC6Saw
.nAccumStep
++;
962 if(mWave_VRC6Saw
.nAccumStep
== 14)
964 mWave_VRC6Saw
.nAccumStep
= 0;
965 mWave_VRC6Saw
.nAccum
= 0;
967 else if(!(mWave_VRC6Saw
.nAccumStep
& 1))
968 mWave_VRC6Saw
.nAccum
+= mWave_VRC6Saw
.nAccumRate
;
973 /****************** Square waves ******************/
976 #ifdef ICODE_INSTEAD_OF_INLINE
977 void Wave_Squares_ClockMajor(void) ICODE_ATTR
;
978 void Wave_Squares_ClockMajor()
980 inline void Wave_Squares_ClockMajor(void);
981 inline void Wave_Squares_ClockMajor()
984 if(mWave_Squares
.nDecayCount
[0])
985 mWave_Squares
.nDecayCount
[0]--;
988 mWave_Squares
.nDecayCount
[0] = mWave_Squares
.nDecayTimer
[0];
989 if(mWave_Squares
.nDecayVolume
[0])
990 mWave_Squares
.nDecayVolume
[0]--;
993 if(mWave_Squares
.bDecayLoop
[0])
994 mWave_Squares
.nDecayVolume
[0] = 0x0F;
997 if(mWave_Squares
.bDecayEnable
[0])
998 mWave_Squares
.nVolume
[0] = mWave_Squares
.nDecayVolume
[0];
1001 if(mWave_Squares
.nDecayCount
[1])
1002 mWave_Squares
.nDecayCount
[1]--;
1005 mWave_Squares
.nDecayCount
[1] = mWave_Squares
.nDecayTimer
[1];
1006 if(mWave_Squares
.nDecayVolume
[1])
1007 mWave_Squares
.nDecayVolume
[1]--;
1010 if(mWave_Squares
.bDecayLoop
[1])
1011 mWave_Squares
.nDecayVolume
[1] = 0x0F;
1014 if(mWave_Squares
.bDecayEnable
[1])
1015 mWave_Squares
.nVolume
[1] = mWave_Squares
.nDecayVolume
[1];
1021 #ifdef ICODE_INSTEAD_OF_INLINE
1022 void Wave_Squares_CheckSweepForcedSilence(const int32_t i
) ICODE_ATTR
;
1023 void Wave_Squares_CheckSweepForcedSilence(const int32_t i
)
1025 inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i
);
1026 inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i
)
1029 if(mWave_Squares
.nFreqTimer
[i
].W
< 8) {
1030 mWave_Squares
.bSweepForceSilence
[i
] = 1; return;
1032 if(!mWave_Squares
.bSweepMode
[i
] &&
1033 (( mWave_Squares
.nFreqTimer
[i
].W
+
1034 (mWave_Squares
.nFreqTimer
[i
].W
>> mWave_Squares
.nSweepShift
[i
]))
1035 >= 0x0800)) { mWave_Squares
.bSweepForceSilence
[i
] = 1; return; }
1037 mWave_Squares
.bSweepForceSilence
[i
] = 0;
1040 /* sweep / length */
1041 #ifdef ICODE_INSTEAD_OF_INLINE
1042 void Wave_Squares_ClockMinor(void) ICODE_ATTR
;
1043 void Wave_Squares_ClockMinor()
1045 inline void Wave_Squares_ClockMinor(void);
1046 inline void Wave_Squares_ClockMinor()
1049 /* unrolled a little loop
1051 for(i = 0; i < 2; i++)
1054 if(mWave_Squares
.bLengthEnabled
[0] && mWave_Squares
.nLengthCount
[0])
1055 mWave_Squares
.nLengthCount
[0]--;
1057 if(!mWave_Squares
.bSweepEnable
[0] || !mWave_Squares
.nLengthCount
[0] ||
1058 mWave_Squares
.bSweepForceSilence
[0] || !mWave_Squares
.nSweepShift
[0])
1061 if(mWave_Squares
.nSweepCount
[0])
1062 mWave_Squares
.nSweepCount
[0]--;
1065 mWave_Squares
.nSweepCount
[0] = mWave_Squares
.nSweepTimer
[0];
1066 if(mWave_Squares
.bSweepMode
[0]) mWave_Squares
.nFreqTimer
[0].W
-=
1067 (mWave_Squares
.nFreqTimer
[0].W
>> mWave_Squares
.nSweepShift
[0])+1;
1068 else mWave_Squares
.nFreqTimer
[0].W
+=
1069 (mWave_Squares
.nFreqTimer
[0].W
>> mWave_Squares
.nSweepShift
[0]);
1071 Wave_Squares_CheckSweepForcedSilence(0);
1076 if(mWave_Squares
.bLengthEnabled
[1] && mWave_Squares
.nLengthCount
[1])
1077 mWave_Squares
.nLengthCount
[1]--;
1079 if(!mWave_Squares
.bSweepEnable
[1] || !mWave_Squares
.nLengthCount
[1] ||
1080 mWave_Squares
.bSweepForceSilence
[1] || !mWave_Squares
.nSweepShift
[1])
1083 if(mWave_Squares
.nSweepCount
[1])
1084 mWave_Squares
.nSweepCount
[1]--;
1087 mWave_Squares
.nSweepCount
[1] = mWave_Squares
.nSweepTimer
[1];
1088 if(mWave_Squares
.bSweepMode
[1]) mWave_Squares
.nFreqTimer
[1].W
-=
1089 (mWave_Squares
.nFreqTimer
[1].W
>> mWave_Squares
.nSweepShift
[1]);
1090 else mWave_Squares
.nFreqTimer
[1].W
+=
1091 (mWave_Squares
.nFreqTimer
[1].W
>> mWave_Squares
.nSweepShift
[1]);
1093 Wave_Squares_CheckSweepForcedSilence(1);
1097 /****************** Triangle/noise/DMC ******************/
1099 /* decay (noise), linear (tri) */
1101 #ifdef ICODE_INSTEAD_OF_INLINE
1102 void Wave_TND_ClockMajor(void) ICODE_ATTR
;
1103 void Wave_TND_ClockMajor()
1105 inline void Wave_TND_ClockMajor(void);
1106 inline void Wave_TND_ClockMajor()
1110 if(mWave_TND
.nNoiseDecayCount
)
1111 mWave_TND
.nNoiseDecayCount
--;
1114 mWave_TND
.nNoiseDecayCount
= mWave_TND
.nNoiseDecayTimer
;
1115 if(mWave_TND
.nNoiseDecayVolume
)
1116 mWave_TND
.nNoiseDecayVolume
--;
1119 if(mWave_TND
.bNoiseDecayLoop
)
1120 mWave_TND
.nNoiseDecayVolume
= 0x0F;
1123 if(mWave_TND
.bNoiseDecayEnable
)
1124 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayVolume
;
1127 /* triangle's linear */
1128 if(mWave_TND
.bTriLinearHalt
)
1129 mWave_TND
.nTriLinearCount
= mWave_TND
.nTriLinearLoad
;
1130 else if(mWave_TND
.nTriLinearCount
)
1131 mWave_TND
.nTriLinearCount
--;
1133 if(!mWave_TND
.bTriLinearControl
)
1134 mWave_TND
.bTriLinearHalt
= 0;
1139 #ifdef ICODE_INSTEAD_OF_INLINE
1140 void Wave_TND_ClockMinor(void) ICODE_ATTR
;
1141 void Wave_TND_ClockMinor()
1143 inline void Wave_TND_ClockMinor(void);
1144 inline void Wave_TND_ClockMinor()
1147 if(mWave_TND
.bNoiseLengthEnabled
&& mWave_TND
.nNoiseLengthCount
)
1148 mWave_TND
.nNoiseLengthCount
--;
1150 if(mWave_TND
.bTriLengthEnabled
&& mWave_TND
.nTriLengthCount
)
1151 mWave_TND
.nTriLengthCount
--;
1156 /****************** NSF Core ******************/
1163 /* RAM: 0x0000 - 0x07FF */
1164 uint8_t pRAM
[0x800] IDATA_ATTR
;
1165 /* SRAM: 0x6000 - 0x7FFF (non-FDS only) */
1166 uint8_t pSRAM
[0x2000];
1167 /* ExRAM: 0x5C00 - 0x5FF5 (MMC5 only)
1168 * Also holds NSF player code (at 0x5000 - 0x500F) */
1169 uint8_t pExRAM
[0x1000];
1170 /* Full ROM buffer */
1171 uint8_t* pROM_Full IDATA_ATTR
;
1173 uint16_t main_nOutputTable_L
[0x8000];
1175 uint8_t* pROM
[10] IDATA_ATTR
;/* ROM banks (point to areas in pROM_Full) */
1176 /* 0x8000 - 0xFFFF */
1177 /* also includes 0x6000 - 0x7FFF (FDS only) */
1178 uint8_t* pStack
; /* the stack (points to areas in pRAM) */
1179 /* 0x0100 - 0x01FF */
1181 int32_t nROMSize
; /* size of this ROM file in bytes */
1182 int32_t nROMBankCount
; /* max number of 4k banks */
1183 int32_t nROMMaxSize
; /* size of allocated pROM_Full buffer */
1186 * Memory Proc Pointers
1189 typedef uint8_t ( *ReadProc
)(uint16_t);
1190 typedef void ( *WriteProc
)(uint16_t,uint8_t);
1191 ReadProc ReadMemory
[0x10] IDATA_ATTR
;
1192 WriteProc WriteMemory
[0x10] IDATA_ATTR
;
1195 * 6502 Registers / Mode
1198 uint8_t regA IDATA_ATTR
; /* Accumulator */
1199 uint8_t regX IDATA_ATTR
; /* X-Index */
1200 uint8_t regY IDATA_ATTR
; /* Y-Index */
1201 uint8_t regP IDATA_ATTR
; /* Processor Status */
1202 uint8_t regSP IDATA_ATTR
; /* Stack Pointer */
1203 uint16_t regPC IDATA_ATTR
; /* Program Counter */
1205 uint8_t bPALMode IDATA_ATTR
;/* 1 if in PAL emulation mode, 0 if in NTSC */
1206 uint8_t bCPUJammed IDATA_ATTR
; /* 0 = not jammed. 1 = really jammed.
1207 * 2 = 'fake' jammed */
1208 /* fake jam caused by the NSF code to signal
1209 * the end of the play/init routine */
1211 /* Multiplication Register, for MMC5 chip only (5205+5206) */
1212 uint8_t nMultIn_Low
;
1213 uint8_t nMultIn_High
;
1216 * NSF Preparation Information
1219 uint8_t nBankswitchInitValues
[10]; /* banks to swap to on tune init */
1220 uint16_t nPlayAddress
; /* Play routine address */
1221 uint16_t nInitAddress
; /* Init routine address */
1223 uint8_t nExternalSound
; /* external sound chips */
1226 float fNSFPlaybackSpeed
;
1232 uint8_t nFrameCounter
; /* Frame Sequence Counter */
1233 uint8_t nFrameCounterMax
; /* Frame Sequence Counter Size
1234 (3 or 4 depending on $4017.7) */
1235 uint8_t bFrameIRQEnabled
; /* TRUE if frame IRQs are enabled */
1236 uint8_t bFrameIRQPending
; /* TRUE if the frame sequencer is holding down
1239 uint8_t nFME07_Address
;
1242 * Timing and Counters
1244 /* fixed point -15.16 */
1246 int32_t nTicksUntilNextFrame
;
1247 int32_t nTicksPerPlay
;
1248 int32_t nTicksUntilNextPlay
;
1249 int32_t nTicksPerSample
;
1250 int32_t nTicksUntilNextSample
;
1252 uint32_t nCPUCycle IDATA_ATTR
;
1253 uint32_t nAPUCycle IDATA_ATTR
;
1256 uint32_t nTotalPlays
; /* number of times the play subroutine has been called
1257 (for tracking output time) */
1261 int32_t nSilentSamples
;
1262 int32_t nSilentSampleMax
;
1263 int32_t nSilenceTrackMS
;
1264 uint8_t bNoSilenceIfTime
;
1265 uint8_t bTimeNotDefault
;
1268 * Sound output options
1270 const int32_t nSampleRate
=44100;
1273 * Volume/fading/filter tracking
1276 uint32_t nStartFade
; /* play call to start fading out */
1277 uint32_t nEndFade
; /* play call to stop fading out (song is over) */
1278 uint8_t bFade
; /* are we fading? */
1283 * Designated Output Buffer
1285 uint8_t* pOutput IDATA_ATTR
;
1287 const uint8_t bDMCPopReducer
=1;
1288 uint8_t nDMCPop_Prev IDATA_ATTR
= 0;
1289 uint8_t bDMCPop_Skip IDATA_ATTR
= 0;
1290 uint8_t bDMCPop_SamePlay IDATA_ATTR
= 0;
1292 const uint8_t nForce4017Write
=0;
1293 const uint8_t bN106PopReducer
=0;
1294 const uint8_t bIgnore4011Writes
=0;
1296 const uint8_t bIgnoreBRK
=0;
1297 const uint8_t bIgnoreIllegalOps
=0;
1298 const uint8_t bNoWaitForReturn
=0;
1299 const uint8_t bPALPreference
=0;
1300 const uint8_t bCleanAXY
=0;
1301 const uint8_t bResetDuty
=0;
1307 int64_t nFilterAccL IDATA_ATTR
;
1308 int64_t nHighPass IDATA_ATTR
;
1310 int32_t nHighPassBase IDATA_ATTR
;
1312 uint8_t bHighPassEnabled IDATA_ATTR
;
1316 #define CLOCK_MAJOR() { Wave_Squares_ClockMajor(); Wave_TND_ClockMajor(); }
1317 #define CLOCK_MINOR() { Wave_Squares_ClockMinor(); Wave_TND_ClockMinor(); }
1319 #define EXTSOUND_VRC6 0x01
1320 #define EXTSOUND_VRC7 0x02
1321 #define EXTSOUND_FDS 0x04
1322 #define EXTSOUND_MMC5 0x08
1323 #define EXTSOUND_N106 0x10
1324 #define EXTSOUND_FME07 0x20
1326 #define SILENCE_THRESHOLD 3
1332 uint32_t Emulate6502(uint32_t runto
) ICODE_ATTR
;
1333 void EmulateAPU(uint8_t bBurnCPUCycles
) ICODE_ATTR
;
1335 int NSFCore_Initialize(void); /* 1 = initialized ok,
1336 0 = couldn't initialize (memory allocation error) */
1341 int LoadNSF(int32_t); /* grab data from an existing file
1342 1 = loaded ok, 0 = error loading */
1347 void SetTrack(uint8_t track
); /* Change tracks */
1352 /* fill a buffer with samples */
1353 int32_t GetSamples(uint8_t* buffer
, int32_t buffersize
);
1358 /* Set desired playback options (0 = bad options couldn't be set) */
1359 int SetPlaybackOptions(int32_t samplerate
);
1360 /* Speed throttling (0 = uses NSF specified speed) */
1361 void SetPlaybackSpeed(float playspersec
);
1363 float GetPlaybackSpeed(void);
1364 float GetMasterVolume(void);
1369 /* gets the number of 'play' routine calls executed */
1370 float GetPlayCalls(void);
1372 /* gets the output time (based on the given play rate,
1373 if basedplayspersec is zero, current playback speed is used */
1374 uint32_t GetWrittenTime(float basedplayspersec
);
1375 /* sets the number of 'plays' routines executed (for precise seeking) */
1376 void SetPlayCalls(float plays
);
1377 /* sets the written time (approx. seeking) */
1378 void SetWrittenTime(uint32_t ms
,float basedplays
);
1384 void StopFade(void); /* stops all fading (plays indefinitely) */
1385 uint8_t SongCompleted(void); /* song has faded out (samples have stopped
1387 /* parameters are play calls */
1388 void SetFade(int32_t fadestart
,int32_t fadestop
,uint8_t bNotDefault
);
1389 void SetFadeTime(uint32_t fadestart
,uint32_t fadestop
,float basedplays
,
1390 uint8_t bNotDefault
); /* parameters are in milliseconds */
1393 * Internal Functions
1395 void RebuildOutputTables(void);
1396 void RecalculateFade(void); /* called when fade status is changed. */
1397 void RecalcFilter(void);
1398 void RecalcSilenceTracker(void);
1400 void WriteMemory_VRC6(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1401 void WriteMemory_MMC5(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1402 void WriteMemory_N106(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1403 void WriteMemory_FME07(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1406 * Memory Read/Write routines
1409 uint8_t ReadMemory_RAM(uint16_t a
) ICODE_ATTR
;
1410 uint8_t ReadMemory_ExRAM(uint16_t a
) ICODE_ATTR
;
1411 uint8_t ReadMemory_SRAM(uint16_t a
) ICODE_ATTR
;
1412 uint8_t ReadMemory_pAPU(uint16_t a
) ICODE_ATTR
;
1413 uint8_t ReadMemory_ROM(uint16_t a
) ICODE_ATTR
;
1414 uint8_t ReadMemory_Default(uint16_t a
) ICODE_ATTR
;
1416 uint8_t ReadMemory_N106(uint16_t a
) ICODE_ATTR
;
1418 void WriteMemory_RAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1419 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1420 void WriteMemory_SRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1421 void WriteMemory_pAPU(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1422 void WriteMemory_FDSRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1423 void WriteMemory_Default(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1425 uint8_t ReadMemory_RAM(uint16_t a
) { return pRAM
[a
& 0x07FF]; }
1426 uint8_t ReadMemory_ExRAM(uint16_t a
) { return pExRAM
[a
& 0x0FFF]; }
1427 uint8_t ReadMemory_SRAM(uint16_t a
) { return pSRAM
[a
& 0x1FFF]; }
1428 uint8_t ReadMemory_ROM(uint16_t a
)
1429 { return pROM
[(a
>> 12) - 6][a
& 0x0FFF]; }
1430 uint8_t ReadMemory_Default(uint16_t a
) { return (a
>> 8); }
1432 void WriteMemory_RAM(uint16_t a
,uint8_t v
)
1433 { pRAM
[a
& 0x07FF] = v
; }
1434 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
);
1435 void WriteMemory_SRAM(uint16_t a
,uint8_t v
)
1436 { pSRAM
[a
& 0x1FFF] = v
; }
1437 void WriteMemory_FDSRAM(uint16_t a
,uint8_t v
)
1438 { pROM
[(a
>> 12) - 6][a
& 0x0FFF] = v
; }
1439 void WriteMemory_Default(uint16_t a
,uint8_t v
) { (void)a
; (void)v
; }
1442 /* Read Memory Procs */
1444 uint8_t ReadMemory_pAPU(uint16_t a
)
1451 if(mWave_Squares
.nLengthCount
[0]) ret
|= 0x01;
1452 if(mWave_Squares
.nLengthCount
[1]) ret
|= 0x02;
1453 if(mWave_TND
.nTriLengthCount
) ret
|= 0x04;
1454 if(mWave_TND
.nNoiseLengthCount
) ret
|= 0x08;
1455 if(mWave_TND
.nDMCBytesRemaining
) ret
|= 0x10;
1457 if(bFrameIRQPending
) ret
|= 0x40;
1458 if(mWave_TND
.bDMCIRQPending
) ret
|= 0x80;
1460 bFrameIRQPending
= 0;
1464 if(!(nExternalSound
& EXTSOUND_FDS
)) return 0x40;
1465 if(bPALMode
) return 0x40;
1467 if((a
>= 0x4040) && (a
<= 0x407F))
1468 return mWave_FDS
.nWaveTable
[a
& 0x3F] | 0x40;
1470 return (mWave_FDS
.nVolEnv_Gain
& 0x3F) | 0x40;
1472 return (mWave_FDS
.nSweep_Gain
& 0x3F) | 0x40;
1477 uint8_t ReadMemory_N106(uint16_t a
)
1480 return ReadMemory_pAPU(a
);
1482 uint8_t ret
= mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1)] |
1483 (mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1) + 1] << 4);
1484 if(mWave_N106
.bAutoIncrement
)
1485 mWave_N106
.nCurrentAddress
= (mWave_N106
.nCurrentAddress
+ 1) & 0x7F;
1491 /* Write Memory Procs */
1493 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
)
1495 if(a
< 0x5FF6) /* Invalid */
1500 /* Swap out banks */
1503 /* stop it from swapping to a bank that doesn't exist */
1504 if(v
>= nROMBankCount
)
1507 pROM
[a
] = pROM_Full
+ (v
<< 12);
1509 /* Update the DMC's DMA pointer, as well */
1511 mWave_TND
.pDMCDMAPtr
[a
- 2] = pROM
[a
];
1514 void WriteMemory_pAPU(uint16_t a
,uint8_t v
)
1521 mWave_Squares
.nDutyCycle
[0] = DUTY_CYCLE_TABLE
[v
>> 6];
1522 mWave_Squares
.bLengthEnabled
[0] =
1523 !(mWave_Squares
.bDecayLoop
[0] = (v
& 0x20));
1524 mWave_Squares
.bDecayEnable
[0] = !(v
& 0x10);
1525 mWave_Squares
.nDecayTimer
[0] = (v
& 0x0F);
1527 if(!mWave_Squares
.bDecayEnable
[0])
1528 mWave_Squares
.nVolume
[0] = mWave_Squares
.nDecayTimer
[0];
1532 mWave_Squares
.bSweepEnable
[0] = (v
& 0x80);
1533 mWave_Squares
.nSweepTimer
[0] = (v
& 0x70) >> 4;
1534 mWave_Squares
.bSweepMode
[0] = v
& 0x08;
1535 mWave_Squares
.nSweepShift
[0] = v
& 0x07;
1536 Wave_Squares_CheckSweepForcedSilence(0);
1540 mWave_Squares
.nFreqTimer
[0].B
.l
= v
;
1541 Wave_Squares_CheckSweepForcedSilence(0);
1545 mWave_Squares
.nFreqTimer
[0].B
.h
= v
& 0x07;
1546 Wave_Squares_CheckSweepForcedSilence(0);
1548 mWave_Squares
.nDecayVolume
[0] = 0x0F;
1550 if(mWave_Squares
.bChannelEnabled
[0])
1551 mWave_Squares
.nLengthCount
[0] = LENGTH_COUNTER_TABLE
[v
>> 3];
1554 mWave_Squares
.nDutyCount
[0] = 0;
1560 mWave_Squares
.nDutyCycle
[1] = DUTY_CYCLE_TABLE
[v
>> 6];
1561 mWave_Squares
.bLengthEnabled
[1] =
1562 !(mWave_Squares
.bDecayLoop
[1] = (v
& 0x20));
1563 mWave_Squares
.bDecayEnable
[1] = !(v
& 0x10);
1564 mWave_Squares
.nDecayTimer
[1] = (v
& 0x0F);
1566 if(!mWave_Squares
.bDecayEnable
[1])
1567 mWave_Squares
.nVolume
[1] = mWave_Squares
.nDecayTimer
[1];
1571 mWave_Squares
.bSweepEnable
[1] = (v
& 0x80);
1572 mWave_Squares
.nSweepTimer
[1] = (v
& 0x70) >> 4;
1573 mWave_Squares
.bSweepMode
[1] = v
& 0x08;
1574 mWave_Squares
.nSweepShift
[1] = v
& 0x07;
1575 Wave_Squares_CheckSweepForcedSilence(1);
1579 mWave_Squares
.nFreqTimer
[1].B
.l
= v
;
1580 Wave_Squares_CheckSweepForcedSilence(1);
1584 mWave_Squares
.nFreqTimer
[1].B
.h
= v
& 0x07;
1585 Wave_Squares_CheckSweepForcedSilence(1);
1587 mWave_Squares
.nDecayVolume
[1] = 0x0F;
1589 if(mWave_Squares
.bChannelEnabled
[1])
1590 mWave_Squares
.nLengthCount
[1] = LENGTH_COUNTER_TABLE
[v
>> 3];
1593 mWave_Squares
.nDutyCount
[1] = 0;
1599 mWave_TND
.nTriLinearLoad
= v
& 0x7F;
1600 mWave_TND
.bTriLinearControl
= v
& 0x80;
1601 mWave_TND
.bTriLengthEnabled
= !(v
& 0x80);
1605 mWave_TND
.nTriFreqTimer
.B
.l
= v
;
1609 mWave_TND
.nTriFreqTimer
.B
.h
= v
& 0x07;
1610 mWave_TND
.bTriLinearHalt
= 1;
1612 if(mWave_TND
.bTriChannelEnabled
)
1613 mWave_TND
.nTriLengthCount
= LENGTH_COUNTER_TABLE
[v
>> 3];
1618 mWave_TND
.bNoiseLengthEnabled
=
1619 !(mWave_TND
.bNoiseDecayLoop
= (v
& 0x20));
1620 mWave_TND
.bNoiseDecayEnable
= !(v
& 0x10);
1621 mWave_TND
.nNoiseDecayTimer
= (v
& 0x0F);
1623 if(mWave_TND
.bNoiseDecayEnable
)
1624 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayVolume
;
1626 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayTimer
;
1630 mWave_TND
.nNoiseFreqTimer
= NOISE_FREQ_TABLE
[v
& 0x0F];
1631 mWave_TND
.bNoiseRandomMode
= (v
& 0x80) ? 6 : 1;
1635 if(mWave_TND
.bNoiseChannelEnabled
)
1636 mWave_TND
.nNoiseLengthCount
= LENGTH_COUNTER_TABLE
[v
>> 3];
1638 mWave_TND
.nNoiseDecayVolume
= 0x0F;
1639 if(mWave_TND
.bNoiseDecayEnable
)
1640 mWave_TND
.nNoiseVolume
= 0x0F;
1645 mWave_TND
.bDMCLoop
= v
& 0x40;
1646 mWave_TND
.bDMCIRQEnabled
= v
& 0x80;
1647 /* IRQ can't be pending if disabled */
1648 if(!mWave_TND
.bDMCIRQEnabled
)
1649 mWave_TND
.bDMCIRQPending
= 0;
1651 mWave_TND
.nDMCFreqTimer
= DMC_FREQ_TABLE
[bPALMode
][v
& 0x0F];
1655 if(bIgnore4011Writes
)
1660 if(bDMCPop_SamePlay
)
1661 mWave_TND
.nDMCOutput
= v
;
1669 if(nDMCPop_Prev
== v
) break;
1670 if(mWave_TND
.nDMCOutput
== v
) break;
1671 mWave_TND
.nDMCOutput
= nDMCPop_Prev
;
1673 bDMCPop_SamePlay
= 1;
1677 mWave_TND
.nDMCOutput
= v
;
1681 mWave_TND
.nDMCDMABank_Load
= (v
>> 6) | 0x04;
1682 mWave_TND
.nDMCDMAAddr_Load
= (v
<< 6) & 0x0FFF;
1686 mWave_TND
.nDMCLength
= (v
<< 4) + 1;
1689 /* All / General Purpose */
1691 mWave_TND
.bDMCIRQPending
= 0;
1693 if(v
& 0x01){ mWave_Squares
.bChannelEnabled
[0] = 1; }
1694 else { mWave_Squares
.bChannelEnabled
[0] =
1695 mWave_Squares
.nLengthCount
[0] = 0; }
1696 if(v
& 0x02){ mWave_Squares
.bChannelEnabled
[1] = 1; }
1697 else { mWave_Squares
.bChannelEnabled
[1] =
1698 mWave_Squares
.nLengthCount
[1] = 0; }
1699 if(v
& 0x04){ mWave_TND
.bTriChannelEnabled
= 1; }
1700 else { mWave_TND
.bTriChannelEnabled
=
1701 mWave_TND
.nTriLengthCount
= 0; }
1702 if(v
& 0x08){ mWave_TND
.bNoiseChannelEnabled
= 1; }
1703 else { mWave_TND
.bNoiseChannelEnabled
=
1704 mWave_TND
.nNoiseLengthCount
= 0; }
1708 if(!mWave_TND
.nDMCBytesRemaining
)
1711 mWave_TND
.nDMCDMAAddr
= mWave_TND
.nDMCDMAAddr_Load
;
1712 mWave_TND
.nDMCDMABank
= mWave_TND
.nDMCDMABank_Load
;
1713 mWave_TND
.nDMCBytesRemaining
= mWave_TND
.nDMCLength
;
1714 mWave_TND
.bDMCActive
= 1;
1718 mWave_TND
.nDMCBytesRemaining
= 0;
1722 bFrameIRQEnabled
= !(v
& 0x40);
1723 bFrameIRQPending
= 0;
1725 nFrameCounterMax
= (v
& 0x80) ? 4 : 3;
1726 nTicksUntilNextFrame
=
1727 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
)
1731 if(v
& 0x80) CLOCK_MINOR();
1735 if(!(nExternalSound
& EXTSOUND_FDS
)) return;
1736 if(bPALMode
) return;
1738 /* FDS Sound registers */
1740 if(a
< 0x4040) return;
1745 if(mWave_FDS
.bWaveWrite
)
1746 mWave_FDS
.nWaveTable
[a
- 0x4040] = v
;
1753 mWave_FDS
.nVolEnv_Mode
= (v
>> 6);
1756 mWave_FDS
.nVolEnv_Gain
= v
& 0x3F;
1757 if(!mWave_FDS
.nMainAddr
)
1759 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
1760 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
1761 else mWave_FDS
.nVolume
= 0x20;
1764 mWave_FDS
.nVolEnv_Decay
= v
& 0x3F;
1765 mWave_FDS
.nVolEnv_Timer
=
1766 ((mWave_FDS
.nVolEnv_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
1768 mWave_FDS
.bVolEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1769 mWave_FDS
.nEnvelopeSpeed
&& !(v
& 0x80);
1773 mWave_FDS
.nFreq
.B
.l
= v
;
1774 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1775 !mWave_FDS
.bWaveWrite
;
1779 mWave_FDS
.bEnabled
= !(v
& 0x80);
1780 mWave_FDS
.bEnvelopeEnable
= !(v
& 0x40);
1783 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
1784 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
1785 else mWave_FDS
.nVolume
= 0x20;
1787 mWave_FDS
.nFreq
.B
.h
= v
& 0x0F;
1788 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1789 !mWave_FDS
.bWaveWrite
;
1791 mWave_FDS
.bVolEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1792 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nVolEnv_Mode
& 2);
1793 mWave_FDS
.bSweepEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1794 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nSweep_Mode
& 2);
1799 mWave_FDS
.nSweep_Mode
= v
>> 6;
1801 mWave_FDS
.nSweep_Gain
= v
& 0x3F;
1802 mWave_FDS
.nSweep_Decay
= v
& 0x3F;
1803 mWave_FDS
.nSweep_Timer
=
1804 ((mWave_FDS
.nSweep_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
1805 mWave_FDS
.bSweepEnv_On
=
1806 mWave_FDS
.bEnvelopeEnable
&& mWave_FDS
.nEnvelopeSpeed
&&
1812 if(v
& 0x40) mWave_FDS
.nSweepBias
= (v
& 0x3F) - 0x40;
1813 else mWave_FDS
.nSweepBias
= v
& 0x3F;
1814 mWave_FDS
.nLFO_Addr
= 0;
1819 mWave_FDS
.nLFO_Freq
.B
.l
= v
;
1821 mWave_FDS
.bLFO_Enabled
&& mWave_FDS
.nLFO_Freq
.W
;
1822 if(mWave_FDS
.nLFO_Freq
.W
)
1823 mWave_FDS
.nLFO_Timer
= (0x10000<<14) / mWave_FDS
.nLFO_Freq
.W
;
1827 mWave_FDS
.bLFO_Enabled
= !(v
& 0x80);
1828 mWave_FDS
.nLFO_Freq
.B
.h
= v
& 0x0F;
1830 mWave_FDS
.bLFO_Enabled
&& mWave_FDS
.nLFO_Freq
.W
;
1831 if(mWave_FDS
.nLFO_Freq
.W
)
1832 mWave_FDS
.nLFO_Timer
= (0x10000<<14) / mWave_FDS
.nLFO_Freq
.W
;
1836 if(mWave_FDS
.bLFO_Enabled
) break;
1838 for(i
= 0; i
< 62; i
++)
1839 mWave_FDS
.nLFO_Table
[i
] = mWave_FDS
.nLFO_Table
[i
+ 2];
1840 mWave_FDS
.nLFO_Table
[62] = mWave_FDS
.nLFO_Table
[63] = v
& 7;
1844 mWave_FDS
.nMainVolume
= v
& 3;
1845 mWave_FDS
.bWaveWrite
= v
& 0x80;
1846 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1847 !mWave_FDS
.bWaveWrite
;
1851 mWave_FDS
.nEnvelopeSpeed
= v
;
1852 mWave_FDS
.bVolEnv_On
=
1853 mWave_FDS
.bEnvelopeEnable
&&
1854 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nVolEnv_Mode
& 2);
1855 mWave_FDS
.bSweepEnv_On
=
1856 mWave_FDS
.bEnvelopeEnable
&&
1857 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nSweep_Mode
& 2);
1863 void WriteMemory_VRC6(uint16_t a
,uint8_t v
)
1867 if((a
< 0xA000) && (nExternalSound
& EXTSOUND_VRC7
)) return;
1868 else if(nExternalSound
& EXTSOUND_FDS
)
1869 WriteMemory_FDSRAM(a
,v
);
1875 mWave_VRC6Pulse
[0].nVolume
= v
& 0x0F;
1876 mWave_VRC6Pulse
[0].nDutyCycle
= (v
>> 4) & 0x07;
1877 mWave_VRC6Pulse
[0].bDigitized
= v
& 0x80;
1878 if(mWave_VRC6Pulse
[0].bDigitized
)
1879 mWave_VRC6Pulse
[0].nDutyCount
= 0;
1883 mWave_VRC6Pulse
[0].nFreqTimer
.B
.l
= v
;
1887 mWave_VRC6Pulse
[0].nFreqTimer
.B
.h
= v
& 0x0F;
1888 mWave_VRC6Pulse
[0].bChannelEnabled
= v
& 0x80;
1894 mWave_VRC6Pulse
[1].nVolume
= v
& 0x0F;
1895 mWave_VRC6Pulse
[1].nDutyCycle
= (v
>> 4) & 0x07;
1896 mWave_VRC6Pulse
[1].bDigitized
= v
& 0x80;
1897 if(mWave_VRC6Pulse
[1].bDigitized
)
1898 mWave_VRC6Pulse
[1].nDutyCount
= 0;
1902 mWave_VRC6Pulse
[1].nFreqTimer
.B
.l
= v
;
1906 mWave_VRC6Pulse
[1].nFreqTimer
.B
.h
= v
& 0x0F;
1907 mWave_VRC6Pulse
[1].bChannelEnabled
= v
& 0x80;
1912 mWave_VRC6Saw
.nAccumRate
= (v
& 0x3F);
1916 mWave_VRC6Saw
.nFreqTimer
.B
.l
= v
;
1920 mWave_VRC6Saw
.nFreqTimer
.B
.h
= v
& 0x0F;
1921 mWave_VRC6Saw
.bChannelEnabled
= v
& 0x80;
1926 void WriteMemory_MMC5(uint16_t a
,uint8_t v
)
1928 if((a
<= 0x5015) && !bPALMode
)
1930 /* no audio emulation */
1943 a
= nMultIn_Low
* nMultIn_High
;
1944 pExRAM
[0x205] = a
& 0xFF;
1945 pExRAM
[0x206] = a
>> 8;
1949 if(a
< 0x5C00) return;
1951 pExRAM
[a
& 0x0FFF] = v
;
1953 WriteMemory_ExRAM(a
,v
);
1956 void WriteMemory_N106(uint16_t a
,uint8_t v
)
1960 WriteMemory_pAPU(a
,v
);
1966 mWave_N106
.nCurrentAddress
= v
& 0x7F;
1967 mWave_N106
.bAutoIncrement
= (v
& 0x80);
1974 mWave_N106
.nRAM
[mWave_N106
.nCurrentAddress
<< 1] = v
& 0x0F;
1975 mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1) + 1] = v
>> 4;
1976 a
= mWave_N106
.nCurrentAddress
;
1977 if(mWave_N106
.bAutoIncrement
)
1978 mWave_N106
.nCurrentAddress
=
1979 (mWave_N106
.nCurrentAddress
+ 1) & 0x7F;
1981 #define N106REGWRITE(ch,r0,r1,r2,r3,r4) \
1982 case r0: if(mWave_N106.nFreqReg[ch].B.l == v) break; \
1983 mWave_N106.nFreqReg[ch].B.l = v; \
1984 mWave_N106.nFreqTimer[ch] = -1; \
1986 case r1: if(mWave_N106.nFreqReg[ch].B.h == v) break; \
1987 mWave_N106.nFreqReg[ch].B.h = v; \
1988 mWave_N106.nFreqTimer[ch] = -1; \
1990 case r2: if(mWave_N106.nFreqReg[ch].B.w != (v & 3)){ \
1991 mWave_N106.nFreqReg[ch].B.w = v & 0x03; \
1992 mWave_N106.nFreqTimer[ch] = -1;} \
1993 mWave_N106.nWaveSize[ch] = 0x20 - (v & 0x1C); \
1995 case r3: mWave_N106.nWavePosStart[ch] = v; \
1997 case r4: mWave_N106.nPreVolume[ch] = v & 0x0F; \
1998 if(!bN106PopReducer) \
1999 mWave_N106.nVolume[ch] = v & 0x0F
2003 N106REGWRITE(0,0x40,0x42,0x44,0x46,0x47); break;
2004 N106REGWRITE(1,0x48,0x4A,0x4C,0x4E,0x4F); break;
2005 N106REGWRITE(2,0x50,0x52,0x54,0x56,0x57); break;
2006 N106REGWRITE(3,0x58,0x5A,0x5C,0x5E,0x5F); break;
2007 N106REGWRITE(4,0x60,0x62,0x64,0x66,0x67); break;
2008 N106REGWRITE(5,0x68,0x6A,0x6C,0x6E,0x6F); break;
2009 N106REGWRITE(6,0x70,0x72,0x74,0x76,0x77); break;
2010 N106REGWRITE(7,0x78,0x7A,0x7C,0x7E,0x7F);
2012 if(mWave_N106
.nActiveChannels
== v
) break;
2013 mWave_N106
.nActiveChannels
= v
;
2014 mWave_N106
.nFreqTimer
[0] = -1;
2015 mWave_N106
.nFreqTimer
[1] = -1;
2016 mWave_N106
.nFreqTimer
[2] = -1;
2017 mWave_N106
.nFreqTimer
[3] = -1;
2018 mWave_N106
.nFreqTimer
[4] = -1;
2019 mWave_N106
.nFreqTimer
[5] = -1;
2020 mWave_N106
.nFreqTimer
[6] = -1;
2021 mWave_N106
.nFreqTimer
[7] = -1;
2028 void WriteMemory_FME07(uint16_t a
,uint8_t v
)
2030 if((a
< 0xD000) && (nExternalSound
& EXTSOUND_FDS
))
2031 WriteMemory_FDSRAM(a
,v
);
2037 switch(nFME07_Address
)
2039 case 0x00: mWave_FME07
[0].nFreqTimer
.B
.l
= v
; break;
2040 case 0x01: mWave_FME07
[0].nFreqTimer
.B
.h
= v
& 0x0F; break;
2041 case 0x02: mWave_FME07
[1].nFreqTimer
.B
.l
= v
; break;
2042 case 0x03: mWave_FME07
[1].nFreqTimer
.B
.h
= v
& 0x0F; break;
2043 case 0x04: mWave_FME07
[2].nFreqTimer
.B
.l
= v
; break;
2044 case 0x05: mWave_FME07
[2].nFreqTimer
.B
.h
= v
& 0x0F; break;
2046 mWave_FME07
[0].bChannelEnabled
= !(v
& 0x01);
2047 mWave_FME07
[1].bChannelEnabled
= !(v
& 0x02);
2048 mWave_FME07
[2].bChannelEnabled
= !(v
& 0x03);
2050 case 0x08: mWave_FME07
[0].nVolume
= v
& 0x0F; break;
2051 case 0x09: mWave_FME07
[1].nVolume
= v
& 0x0F; break;
2052 case 0x0A: mWave_FME07
[2].nVolume
= v
& 0x0F; break;
2062 void EmulateAPU(uint8_t bBurnCPUCycles
)
2073 fulltick
+= (signed)(nCPUCycle
- nAPUCycle
);
2078 if(bFade
&& nSilentSampleMax
&& (nSilentSamples
>= nSilentSampleMax
))
2083 tick
= (nTicksUntilNextSample
+0xffff)>>16;
2091 ENTER_TIMER(squares
);
2092 /* Square generation */
2094 mWave_Squares
.nFreqCount
[0] -= tick
;
2095 mWave_Squares
.nFreqCount
[1] -= tick
;
2097 if((mWave_Squares
.nDutyCount
[0] < mWave_Squares
.nDutyCycle
[0]) &&
2098 mWave_Squares
.nLengthCount
[0] &&
2099 !mWave_Squares
.bSweepForceSilence
[0])
2100 square_out1
= mWave_Squares
.nVolume
[0];
2104 if((mWave_Squares
.nDutyCount
[1] < mWave_Squares
.nDutyCycle
[1]) &&
2105 mWave_Squares
.nLengthCount
[1] &&
2106 !mWave_Squares
.bSweepForceSilence
[1])
2107 square_out2
= mWave_Squares
.nVolume
[1];
2111 mWave_Squares
.nMixL
= Squares_nOutputTable_L
[square_out1
][square_out2
];
2113 if(mWave_Squares
.nFreqCount
[0]<=0)
2116 (-mWave_Squares
.nFreqCount
[0])/
2117 (mWave_Squares
.nFreqTimer
[0].W
+ 1) + 1;
2118 mWave_Squares
.nFreqCount
[0] =
2119 (mWave_Squares
.nFreqTimer
[0].W
+ 1)-
2120 (-mWave_Squares
.nFreqCount
[0])%
2121 (mWave_Squares
.nFreqTimer
[0].W
+ 1);
2122 mWave_Squares
.nDutyCount
[0] =
2123 (mWave_Squares
.nDutyCount
[0]+cycles
)%0x10;
2125 if(mWave_Squares
.nFreqCount
[1]<=0)
2128 (-mWave_Squares
.nFreqCount
[1])/
2129 (mWave_Squares
.nFreqTimer
[1].W
+ 1) + 1;
2130 mWave_Squares
.nFreqCount
[1] =
2131 (mWave_Squares
.nFreqTimer
[1].W
+ 1)-
2132 (-mWave_Squares
.nFreqCount
[1])%
2133 (mWave_Squares
.nFreqTimer
[1].W
+ 1);
2134 mWave_Squares
.nDutyCount
[1] = (mWave_Squares
.nDutyCount
[1]+cycles
)%
2137 /* end of Square generation */
2138 EXIT_TIMER(squares
);
2141 ENTER_TIMER(tnd_enter
);
2145 /* TND generation */
2147 if(mWave_TND
.nNoiseFreqTimer
) mWave_TND
.nNoiseFreqCount
-= tick
;
2149 if(mWave_TND
.nTriFreqTimer
.W
> 8)
2150 mWave_TND
.nTriFreqCount
-= tick
;
2152 tnd_out
= mWave_TND
.nTriOutput
<< 11;
2154 if(mWave_TND
.bNoiseRandomOut
&& mWave_TND
.nNoiseLengthCount
)
2155 tnd_out
|= mWave_TND
.nNoiseVolume
<< 7;
2157 tnd_out
|= mWave_TND
.nDMCOutput
;
2159 mWave_TND
.nMixL
= main_nOutputTable_L
[tnd_out
];
2161 EXIT_TIMER(tnd_enter
);
2163 ENTER_TIMER(tnd_tri
);
2167 if(mWave_TND
.nTriFreqCount
<=0)
2169 if(mWave_TND
.nTriLengthCount
&& mWave_TND
.nTriLinearCount
)
2171 do mWave_TND
.nTriStep
++;
2172 while ((mWave_TND
.nTriFreqCount
+=
2173 mWave_TND
.nTriFreqTimer
.W
+ 1) <= 0);
2174 mWave_TND
.nTriStep
&= 0x1F;
2176 if(mWave_TND
.nTriStep
& 0x10)
2177 mWave_TND
.nTriOutput
= mWave_TND
.nTriStep
^ 0x1F;
2178 else mWave_TND
.nTriOutput
= mWave_TND
.nTriStep
;
2179 } else mWave_TND
.nTriFreqCount
=mWave_TND
.nTriFreqTimer
.W
+1;
2182 EXIT_TIMER(tnd_tri
);
2184 ENTER_TIMER(tnd_noise
);
2188 if(mWave_TND
.nNoiseFreqTimer
&&
2189 mWave_TND
.nNoiseVolume
&& mWave_TND
.nNoiseFreqCount
<=0)
2191 mWave_TND
.nNoiseFreqCount
= mWave_TND
.nNoiseFreqTimer
;
2192 mWave_TND
.nNoiseRandomShift
<<= 1;
2193 mWave_TND
.bNoiseRandomOut
= (((mWave_TND
.nNoiseRandomShift
<<
2194 mWave_TND
.bNoiseRandomMode
) ^
2195 mWave_TND
.nNoiseRandomShift
) & 0x8000 ) ? 1 : 0;
2196 if(mWave_TND
.bNoiseRandomOut
)
2197 mWave_TND
.nNoiseRandomShift
|= 0x01;
2200 EXIT_TIMER(tnd_noise
);
2202 ENTER_TIMER(tnd_dmc
);
2205 if(mWave_TND
.bDMCActive
)
2207 mWave_TND
.nDMCFreqCount
-= tick
;
2208 while (mWave_TND
.nDMCFreqCount
<= 0) {
2209 if (!mWave_TND
.bDMCActive
) {
2210 mWave_TND
.nDMCFreqCount
= mWave_TND
.nDMCFreqTimer
;
2214 mWave_TND
.nDMCFreqCount
+= mWave_TND
.nDMCFreqTimer
;
2216 if(mWave_TND
.bDMCSampleBufferEmpty
&&
2217 mWave_TND
.nDMCBytesRemaining
)
2219 burned
+= 4; /* 4 cycle burn! */
2220 mWave_TND
.nDMCSampleBuffer
=
2221 mWave_TND
.pDMCDMAPtr
[mWave_TND
.nDMCDMABank
]
2222 [mWave_TND
.nDMCDMAAddr
];
2223 mWave_TND
.nDMCDMAAddr
++;
2224 if(mWave_TND
.nDMCDMAAddr
& 0x1000)
2226 mWave_TND
.nDMCDMAAddr
&= 0x0FFF;
2227 mWave_TND
.nDMCDMABank
=
2228 (mWave_TND
.nDMCDMABank
+ 1) & 0x07;
2231 mWave_TND
.bDMCSampleBufferEmpty
= 0;
2232 mWave_TND
.nDMCBytesRemaining
--;
2233 if(!mWave_TND
.nDMCBytesRemaining
)
2235 if(mWave_TND
.bDMCLoop
)
2237 mWave_TND
.nDMCDMABank
= mWave_TND
.nDMCDMABank_Load
;
2238 mWave_TND
.nDMCDMAAddr
= mWave_TND
.nDMCDMAAddr_Load
;
2239 mWave_TND
.nDMCBytesRemaining
=mWave_TND
.nDMCLength
;
2241 else if(mWave_TND
.bDMCIRQEnabled
)
2242 mWave_TND
.bDMCIRQPending
= 1;
2246 if(!mWave_TND
.nDMCDeltaBit
)
2248 mWave_TND
.nDMCDeltaBit
= 8;
2249 mWave_TND
.bDMCDeltaSilent
=mWave_TND
.bDMCSampleBufferEmpty
;
2250 mWave_TND
.nDMCDelta
= mWave_TND
.nDMCSampleBuffer
;
2251 mWave_TND
.bDMCSampleBufferEmpty
= 1;
2254 if(mWave_TND
.nDMCDeltaBit
) {
2255 mWave_TND
.nDMCDeltaBit
--;
2256 if(!mWave_TND
.bDMCDeltaSilent
)
2258 if(mWave_TND
.nDMCDelta
& 0x01)
2260 if(mWave_TND
.nDMCOutput
< 0x7E)
2261 mWave_TND
.nDMCOutput
+= 2;
2263 else if(mWave_TND
.nDMCOutput
> 1)
2264 mWave_TND
.nDMCOutput
-= 2;
2266 mWave_TND
.nDMCDelta
>>= 1;
2269 if(!mWave_TND
.nDMCBytesRemaining
&&
2270 mWave_TND
.bDMCSampleBufferEmpty
&&
2271 mWave_TND
.bDMCDeltaSilent
)
2272 mWave_TND
.bDMCActive
= mWave_TND
.nDMCDeltaBit
= 0;
2276 EXIT_TIMER(tnd_dmc
);
2278 /* end of TND generation */
2281 if(nExternalSound
&& !bPALMode
)
2283 if(nExternalSound
& EXTSOUND_VRC6
)
2284 Wave_VRC6_DoTicks(tick
);
2285 if(nExternalSound
& EXTSOUND_N106
)
2286 Wave_N106_DoTicks(tick
);
2287 if(nExternalSound
& EXTSOUND_FME07
)
2289 if (mWave_FME07
[0].bChannelEnabled
&&
2290 mWave_FME07
[0].nFreqTimer
.W
) {
2291 mWave_FME07
[0].nFreqCount
-= tick
;
2293 if(mWave_FME07
[0].nDutyCount
< 16)
2295 mWave_FME07
[0].nMixL
=
2296 FME07_nOutputTable_L
[mWave_FME07
[0].nVolume
];
2297 } else mWave_FME07
[0].nMixL
= 0;
2298 while(mWave_FME07
[0].nFreqCount
<= 0) {
2299 mWave_FME07
[0].nFreqCount
+=
2300 mWave_FME07
[0].nFreqTimer
.W
;
2302 mWave_FME07
[0].nDutyCount
=
2303 (mWave_FME07
[0].nDutyCount
+1)&0x1f;
2307 if (mWave_FME07
[1].bChannelEnabled
&&
2308 mWave_FME07
[1].nFreqTimer
.W
) {
2309 mWave_FME07
[1].nFreqCount
-= tick
;
2311 if(mWave_FME07
[1].nDutyCount
< 16)
2313 mWave_FME07
[1].nMixL
=
2314 FME07_nOutputTable_L
[mWave_FME07
[1].nVolume
];
2315 } else mWave_FME07
[1].nMixL
= 0;
2316 while(mWave_FME07
[1].nFreqCount
<= 0) {
2317 mWave_FME07
[1].nFreqCount
+=
2318 mWave_FME07
[1].nFreqTimer
.W
;
2320 mWave_FME07
[1].nDutyCount
=
2321 (mWave_FME07
[1].nDutyCount
+1)&0x1f;
2325 if (mWave_FME07
[2].bChannelEnabled
&&
2326 mWave_FME07
[2].nFreqTimer
.W
) {
2327 mWave_FME07
[2].nFreqCount
-= tick
;
2329 if(mWave_FME07
[2].nDutyCount
< 16)
2331 mWave_FME07
[2].nMixL
=
2332 FME07_nOutputTable_L
[mWave_FME07
[2].nVolume
];
2333 } else mWave_FME07
[2].nMixL
= 0;
2334 while(mWave_FME07
[2].nFreqCount
<= 0) {
2335 mWave_FME07
[2].nFreqCount
+=
2336 mWave_FME07
[2].nFreqTimer
.W
;
2338 mWave_FME07
[2].nDutyCount
=
2339 (mWave_FME07
[2].nDutyCount
+1)&0x1f;
2345 if(nExternalSound
& EXTSOUND_FDS
) {
2347 /* Volume Envelope Unit */
2348 if(mWave_FDS
.bVolEnv_On
)
2350 mWave_FDS
.nVolEnv_Count
-= tick
;
2351 while(mWave_FDS
.nVolEnv_Count
<= 0)
2353 mWave_FDS
.nVolEnv_Count
+= mWave_FDS
.nVolEnv_Timer
;
2354 if(mWave_FDS
.nVolEnv_Mode
) {
2355 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
2356 mWave_FDS
.nVolEnv_Gain
++;
2359 if(mWave_FDS
.nVolEnv_Gain
)
2360 mWave_FDS
.nVolEnv_Gain
--;
2365 /* Sweep Envelope Unit */
2366 if(mWave_FDS
.bSweepEnv_On
)
2368 mWave_FDS
.nSweep_Count
-= tick
;
2369 while(mWave_FDS
.nSweep_Count
<= 0)
2371 mWave_FDS
.nSweep_Count
+= mWave_FDS
.nSweep_Timer
;
2372 if(mWave_FDS
.nSweep_Mode
) {
2373 if(mWave_FDS
.nSweep_Gain
< 0x20)
2374 mWave_FDS
.nSweep_Gain
++;
2376 if(mWave_FDS
.nSweep_Gain
) mWave_FDS
.nSweep_Gain
--;
2381 /* Effector / LFO */
2382 int32_t subfreq
= 0;
2383 if(mWave_FDS
.bLFO_On
)
2385 mWave_FDS
.nLFO_Count
-= tick
<<14;
2386 while(mWave_FDS
.nLFO_Count
<= 0)
2388 mWave_FDS
.nLFO_Count
+= mWave_FDS
.nLFO_Timer
;
2389 if(mWave_FDS
.nLFO_Table
[mWave_FDS
.nLFO_Addr
] == 4)
2390 mWave_FDS
.nSweepBias
= 0;
2392 mWave_FDS
.nSweepBias
+=
2394 mWave_FDS
.nLFO_Table
[mWave_FDS
.nLFO_Addr
]
2396 mWave_FDS
.nLFO_Addr
= (mWave_FDS
.nLFO_Addr
+ 1) & 0x3F;
2399 while(mWave_FDS
.nSweepBias
> 63)
2400 mWave_FDS
.nSweepBias
-= 128;
2401 while(mWave_FDS
.nSweepBias
< -64)
2402 mWave_FDS
.nSweepBias
+= 128;
2404 register int32_t temp
=
2405 mWave_FDS
.nSweepBias
* mWave_FDS
.nSweep_Gain
;
2409 if(mWave_FDS
.nSweepBias
< 0) temp
--;
2415 if(temp
> 193) temp
-= 258;
2416 if(temp
< -64) temp
+= 256;
2418 subfreq
= mWave_FDS
.nFreq
.W
* temp
/ 64;
2422 if(mWave_FDS
.bMain_On
)
2425 FDS_nOutputTable_L
[mWave_FDS
.nMainVolume
]
2427 [mWave_FDS
.nWaveTable
[mWave_FDS
.nMainAddr
] ];
2429 if((subfreq
+ mWave_FDS
.nFreq
.W
) > 0)
2431 int32_t freq
= (0x10000<<14) / (subfreq
+ mWave_FDS
.nFreq
.W
);
2433 mWave_FDS
.nFreqCount
-= tick
<<14;
2434 while(mWave_FDS
.nFreqCount
<= 0)
2436 mWave_FDS
.nFreqCount
+= freq
;
2438 mWave_FDS
.nMainAddr
=
2439 (mWave_FDS
.nMainAddr
+ 1) & 0x3F;
2440 mWave_FDS
.nPopOutput
=
2441 mWave_FDS
.nWaveTable
[mWave_FDS
.nMainAddr
];
2442 if(!mWave_FDS
.nMainAddr
)
2444 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
2445 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
2446 else mWave_FDS
.nVolume
= 0x20;
2451 mWave_FDS
.nFreqCount
= mWave_FDS
.nLFO_Count
;
2453 else if(mWave_FDS
.bPopReducer
&& mWave_FDS
.nPopOutput
)
2455 mWave_FDS
.nMixL
= FDS_nOutputTable_L
[mWave_FDS
.nMainVolume
]
2457 [mWave_FDS
.nPopOutput
];
2459 mWave_FDS
.nPopCount
-= tick
;
2460 while(mWave_FDS
.nPopCount
<= 0)
2462 mWave_FDS
.nPopCount
+= 500;
2463 mWave_FDS
.nPopOutput
--;
2464 if(!mWave_FDS
.nPopOutput
)
2465 mWave_FDS
.nMainAddr
= 0;
2470 } /* end while fulltick */
2474 nCPUCycle
+= burned
;
2478 /* Frame Sequencer */
2481 nTicksUntilNextFrame
-= tick
<<16;
2482 while(nTicksUntilNextFrame
<= 0)
2484 nTicksUntilNextFrame
+=
2485 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
) *
2488 if(nFrameCounter
> nFrameCounterMax
)
2491 if(nFrameCounterMax
== 4)
2493 if(nFrameCounter
< 4)
2496 if(!(nFrameCounter
& 1))
2503 if(nFrameCounter
& 1)
2506 if((nFrameCounter
== 3) && bFrameIRQEnabled
)
2507 bFrameIRQPending
= 1;
2513 nTicksUntilNextSample
-= tick
<<16;
2514 if(nTicksUntilNextSample
<= 0)
2516 nTicksUntilNextSample
+= nTicksPerSample
;
2518 mixL
= mWave_Squares
.nMixL
;
2519 mixL
+= mWave_TND
.nMixL
;
2521 if(nExternalSound
&& !bPALMode
)
2523 if(nExternalSound
& EXTSOUND_VRC6
)
2525 mixL
+= (mWave_VRC6Pulse
[0].nMixL
);
2526 mixL
+= (mWave_VRC6Pulse
[1].nMixL
);
2527 mixL
+= (mWave_VRC6Saw
.nMixL
);
2529 if(nExternalSound
& EXTSOUND_N106
) {
2530 mixL
+= (mWave_N106
.nMixL
[0]);
2531 mixL
+= (mWave_N106
.nMixL
[1]);
2532 mixL
+= (mWave_N106
.nMixL
[2]);
2533 mixL
+= (mWave_N106
.nMixL
[3]);
2534 mixL
+= (mWave_N106
.nMixL
[4]);
2535 mixL
+= (mWave_N106
.nMixL
[5]);
2536 mixL
+= (mWave_N106
.nMixL
[6]);
2537 mixL
+= (mWave_N106
.nMixL
[7]);
2539 if(nExternalSound
& EXTSOUND_FME07
)
2541 mixL
+= (mWave_FME07
[0].nMixL
);
2542 mixL
+= (mWave_FME07
[1].nMixL
);
2543 mixL
+= (mWave_FME07
[2].nMixL
);
2545 if(nExternalSound
& EXTSOUND_FDS
)
2546 mixL
+= mWave_FDS
.nMixL
;
2550 diff
= ((int64_t)mixL
<< 25) - nFilterAccL
;
2551 nFilterAccL
+= (diff
* nHighPass
) >> 16;
2552 mixL
= (int32_t)(diff
>> 23);
2555 if(bFade
&& (fFadeVolume
< 1))
2556 mixL
= (int32_t)(mixL
* fFadeVolume
);
2558 if(mixL
< -32768) mixL
= -32768;
2559 if(mixL
> 32767) mixL
= 32767;
2561 *((uint16_t*)pOutput
) = (uint16_t)mixL
;
2568 nAPUCycle
= nCPUCycle
;
2577 * Initializes Memory
2580 int NSFCore_Initialize()
2584 /* why, yes, this was easier when they were in a struct */
2590 ZEROMEMORY(pRAM
,0x800);
2591 ZEROMEMORY(pSRAM
,0x2000);
2592 ZEROMEMORY(pExRAM
,0x1000);
2595 ZEROMEMORY(pROM
,10);
2603 * Memory Proc Pointers
2606 ZEROMEMORY(ReadMemory
,sizeof(ReadProc
)*0x10);
2607 ZEROMEMORY(WriteMemory
,sizeof(WriteProc
)*0x10);
2610 * 6502 Registers / Mode
2627 * NSF Preparation Information
2630 ZEROMEMORY(nBankswitchInitValues
,10);
2637 fNSFPlaybackSpeed
=0;
2649 * Timing and Counters
2651 nTicksUntilNextFrame
=0;
2654 nTicksUntilNextPlay
=0;
2657 nTicksUntilNextSample
=0;
2673 * Volume/fading/filter tracking
2701 ZEROMEMORY(&mWave_Squares
,sizeof(struct Wave_Squares
));
2702 ZEROMEMORY(&mWave_TND
,sizeof(struct Wave_TND
));
2703 ZEROMEMORY(mWave_VRC6Pulse
,sizeof(struct VRC6PulseWave
)*2);
2704 ZEROMEMORY(&mWave_VRC6Saw
,sizeof(struct VRC6SawWave
));
2705 ZEROMEMORY(&mWave_N106
,sizeof(struct N106Wave
));
2706 ZEROMEMORY(mWave_FME07
,sizeof(struct FME07Wave
)*3);
2707 ZEROMEMORY(&mWave_FDS
,sizeof(struct FDSWave
));
2709 /* end clear globals */
2711 // Default filter bases
2712 nHighPassBase
= 150;
2714 bHighPassEnabled
= 1;
2716 mWave_TND
.nNoiseRandomShift
= 1;
2717 for(i
= 0; i
< 8; i
++)
2718 mWave_TND
.pDMCDMAPtr
[i
] = pROM
[i
+ 2];
2721 SetPlaybackOptions(nSampleRate
);
2723 for(i
= 0; i
< 8; i
++)
2724 mWave_N106
.nFrequencyLookupTable
[i
] =
2725 ((((i
+ 1) * 45 * 0x40000) / (float)NES_FREQUENCY
) *
2726 (float)NTSC_FREQUENCY
) * 256.0;
2728 ZEROMEMORY(pRAM
,0x800);
2729 ZEROMEMORY(pSRAM
,0x2000);
2730 ZEROMEMORY(pExRAM
,0x1000);
2731 pStack
= pRAM
+ 0x100;
2739 int LoadNSF(int32_t datasize
)
2741 if(!pDataBuffer
) return 0;
2745 nExternalSound
= nChipExtensions
;
2747 bPALMode
= bPALPreference
;
2749 bPALMode
= nIsPal
& 1;
2751 SetPlaybackOptions(nSampleRate
);
2753 int32_t neededsize
= datasize
+ (nfileLoadAddress
& 0x0FFF);
2754 if(neededsize
& 0x0FFF) neededsize
+= 0x1000 - (neededsize
& 0x0FFF);
2755 if(neededsize
< 0x1000) neededsize
= 0x1000;
2757 uint8_t specialload
= 0;
2759 for(i
= 0; (i
< 8) && (!nBankswitch
[i
]); i
++);
2760 if(i
< 8) /* uses bankswitching */
2762 memcpy(&nBankswitchInitValues
[2],nBankswitch
,8);
2763 nBankswitchInitValues
[0] = nBankswitch
[6];
2764 nBankswitchInitValues
[1] = nBankswitch
[7];
2765 if(nExternalSound
& EXTSOUND_FDS
)
2767 if(!(nBankswitchInitValues
[0] || nBankswitchInitValues
[1]))
2770 * FDS sound with '00' specified for both $6000 and $7000 banks.
2771 * point this to an area of fresh RAM (sort of hackish solution
2772 * for those FDS tunes that don't quite follow the nsf specs.
2774 nBankswitchInitValues
[0] = (uint8_t)(neededsize
>> 12);
2775 nBankswitchInitValues
[1] = (uint8_t)(neededsize
>> 12) + 1;
2776 neededsize
+= 0x2000;
2780 else /* doesn't use bankswitching */
2782 if(nExternalSound
& EXTSOUND_FDS
)
2784 /* bad load address */
2785 if(nfileLoadAddress
< 0x6000) return 0;
2787 if(neededsize
< 0xA000)
2788 neededsize
= 0xA000;
2790 for(i
= 0; i
< 10; i
++)
2791 nBankswitchInitValues
[i
] = (uint8_t)i
;
2795 /* bad load address */
2796 if(nfileLoadAddress
< 0x8000) return 0;
2798 int32_t j
= (nfileLoadAddress
>> 12) - 6;
2799 for(i
= 0; i
< j
; i
++)
2800 nBankswitchInitValues
[i
] = 0;
2801 for(j
= 0; i
< 10; i
++, j
++)
2802 nBankswitchInitValues
[i
] = (uint8_t)j
;
2806 nROMSize
= neededsize
;
2807 nROMBankCount
= neededsize
>> 12;
2810 pROM_Full
= pDataBuffer
-(nfileLoadAddress
-0x6000);
2812 pROM_Full
= pDataBuffer
-(nfileLoadAddress
&0x0FFF);
2814 ZEROMEMORY(pRAM
,0x0800);
2815 ZEROMEMORY(pExRAM
,0x1000);
2816 ZEROMEMORY(pSRAM
,0x2000);
2818 nExternalSound
= nChipExtensions
;
2819 fNSFPlaybackSpeed
= (bPALMode
? PAL_NMIRATE
: NTSC_NMIRATE
);
2821 SetPlaybackSpeed(0);
2823 nPlayAddress
= nfilePlayAddress
;
2824 nInitAddress
= nfileInitAddress
;
2826 pExRAM
[0x00] = 0x20; /* JSR */
2827 pExRAM
[0x01] = nInitAddress
&0xff; /* Init Address */
2828 pExRAM
[0x02] = (nInitAddress
>>8)&0xff;
2829 pExRAM
[0x03] = 0xF2; /* JAM */
2830 pExRAM
[0x04] = 0x20; /* JSR */
2831 pExRAM
[0x05] = nPlayAddress
&0xff; /* Play Address */
2832 pExRAM
[0x06] = (nPlayAddress
>>8)&0xff;
2833 pExRAM
[0x07] = 0x4C; /* JMP */
2834 pExRAM
[0x08] = 0x03;/* $5003 (JAM right before the JSR to play address) */
2835 pExRAM
[0x09] = 0x50;
2837 regA
= regX
= regY
= 0;
2838 regP
= 0x04; /* I_FLAG */
2843 /* Reset Read/Write Procs */
2845 ReadMemory
[0] = ReadMemory
[1] = ReadMemory_RAM
;
2846 ReadMemory
[2] = ReadMemory
[3] = ReadMemory_Default
;
2847 ReadMemory
[4] = ReadMemory_pAPU
;
2848 ReadMemory
[5] = ReadMemory_ExRAM
;
2849 ReadMemory
[6] = ReadMemory
[7] = ReadMemory_SRAM
;
2851 WriteMemory
[0] = WriteMemory
[1] = WriteMemory_RAM
;
2852 WriteMemory
[2] = WriteMemory
[3] = WriteMemory_Default
;
2853 WriteMemory
[4] = WriteMemory_pAPU
;
2854 WriteMemory
[5] = WriteMemory_ExRAM
;
2855 WriteMemory
[6] = WriteMemory
[7] = WriteMemory_SRAM
;
2857 for(i
= 8; i
< 16; i
++)
2859 ReadMemory
[i
] = ReadMemory_ROM
;
2860 WriteMemory
[i
] = WriteMemory_Default
;
2863 if(nExternalSound
& EXTSOUND_FDS
)
2865 WriteMemory
[0x06] = WriteMemory_FDSRAM
;
2866 WriteMemory
[0x07] = WriteMemory_FDSRAM
;
2867 WriteMemory
[0x08] = WriteMemory_FDSRAM
;
2868 WriteMemory
[0x09] = WriteMemory_FDSRAM
;
2869 WriteMemory
[0x0A] = WriteMemory_FDSRAM
;
2870 WriteMemory
[0x0B] = WriteMemory_FDSRAM
;
2871 WriteMemory
[0x0C] = WriteMemory_FDSRAM
;
2872 WriteMemory
[0x0D] = WriteMemory_FDSRAM
;
2873 ReadMemory
[0x06] = ReadMemory_ROM
;
2874 ReadMemory
[0x07] = ReadMemory_ROM
;
2877 if(!bPALMode
) /* no expansion sound available on a PAL system */
2879 if(nExternalSound
& EXTSOUND_VRC6
)
2881 /* if both VRC6+VRC7... it MUST go to WriteMemory_VRC6
2882 * or register writes will be lost (WriteMemory_VRC6 calls
2883 * WriteMemory_VRC7 if needed) */
2884 WriteMemory
[0x09] = WriteMemory_VRC6
;
2885 WriteMemory
[0x0A] = WriteMemory_VRC6
;
2886 WriteMemory
[0x0B] = WriteMemory_VRC6
;
2888 if(nExternalSound
& EXTSOUND_N106
)
2890 WriteMemory
[0x04] = WriteMemory_N106
;
2891 ReadMemory
[0x04] = ReadMemory_N106
;
2892 WriteMemory
[0x0F] = WriteMemory_N106
;
2894 if(nExternalSound
& EXTSOUND_FME07
)
2896 WriteMemory
[0x0C] = WriteMemory_FME07
;
2897 WriteMemory
[0x0E] = WriteMemory_FME07
;
2901 /* MMC5 still has a multiplication reg that needs to be available on
2903 if(nExternalSound
& EXTSOUND_MMC5
)
2904 WriteMemory
[0x05] = WriteMemory_MMC5
;
2913 void SetTrack(uint8_t track
)
2922 regY
= bCleanAXY
? 0 : 0xCD;
2928 nCPUCycle
= nAPUCycle
= 0;
2932 for(i
= 0x4000; i
< 0x400F; i
++)
2933 WriteMemory_pAPU(i
,0);
2934 WriteMemory_pAPU(0x4010,0);
2935 WriteMemory_pAPU(0x4012,0);
2936 WriteMemory_pAPU(0x4013,0);
2937 WriteMemory_pAPU(0x4014,0);
2938 WriteMemory_pAPU(0x4015,0);
2939 WriteMemory_pAPU(0x4015,0x0F);
2940 WriteMemory_pAPU(0x4017,0);
2942 for(i
= 0; i
< 10; i
++)
2943 WriteMemory_ExRAM(0x5FF6 + i
,nBankswitchInitValues
[i
]);
2945 ZEROMEMORY(pRAM
,0x0800);
2946 ZEROMEMORY(pSRAM
,0x2000);
2947 ZEROMEMORY(&pExRAM
[0x10],0x0FF0);
2951 nTicksUntilNextSample
= nTicksPerSample
;
2952 nTicksUntilNextFrame
=
2953 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
)*0x10000;
2954 nTicksUntilNextPlay
= nTicksPerPlay
;
2957 /* Clear mixing vals */
2958 mWave_Squares
.nMixL
= 0;
2959 mWave_TND
.nMixL
= 0;
2960 mWave_VRC6Pulse
[0].nMixL
= 0;
2961 mWave_VRC6Pulse
[1].nMixL
= 0;
2962 mWave_VRC6Saw
.nMixL
= 0;
2964 /* Reset Tri/Noise/DMC */
2965 mWave_TND
.nTriStep
= mWave_TND
.nTriOutput
= 0;
2966 mWave_TND
.nDMCOutput
= 0;
2967 mWave_TND
.bNoiseRandomOut
= 0;
2968 mWave_Squares
.nDutyCount
[0] = mWave_Squares
.nDutyCount
[1] = 0;
2969 mWave_TND
.bDMCActive
= 0;
2970 mWave_TND
.nDMCBytesRemaining
= 0;
2971 mWave_TND
.bDMCSampleBufferEmpty
= 1;
2972 mWave_TND
.bDMCDeltaSilent
= 1;
2975 mWave_VRC6Pulse
[0].nVolume
= 0;
2976 mWave_VRC6Pulse
[1].nVolume
= 0;
2977 mWave_VRC6Saw
.nAccumRate
= 0;
2980 ZEROMEMORY(mWave_N106
.nRAM
,0x100);
2981 ZEROMEMORY(mWave_N106
.nVolume
,8);
2982 ZEROMEMORY(mWave_N106
.nOutput
,8);
2983 ZEROMEMORY(mWave_N106
.nMixL
,32);
2986 mWave_FME07
[0].nVolume
= 0;
2987 mWave_FME07
[1].nVolume
= 0;
2988 mWave_FME07
[2].nVolume
= 0;
2990 /* Clear FDS crap */
2992 mWave_FDS
.bEnvelopeEnable
= 0;
2993 mWave_FDS
.nEnvelopeSpeed
= 0xFF;
2994 mWave_FDS
.nVolEnv_Mode
= 2;
2995 mWave_FDS
.nVolEnv_Decay
= 0;
2996 mWave_FDS
.nVolEnv_Gain
= 0;
2997 mWave_FDS
.nVolume
= 0;
2998 mWave_FDS
.bVolEnv_On
= 0;
2999 mWave_FDS
.nSweep_Mode
= 2;
3000 mWave_FDS
.nSweep_Decay
= 0;
3001 mWave_FDS
.nSweep_Gain
= 0;
3002 mWave_FDS
.bSweepEnv_On
= 0;
3003 mWave_FDS
.nSweepBias
= 0;
3004 mWave_FDS
.bLFO_Enabled
= 0;
3005 mWave_FDS
.nLFO_Freq
.W
= 0;
3006 /* mWave_FDS.fLFO_Timer = 0;
3007 mWave_FDS.fLFO_Count = 0;*/
3008 mWave_FDS
.nLFO_Timer
= 0;
3009 mWave_FDS
.nLFO_Count
= 0;
3010 mWave_FDS
.nLFO_Addr
= 0;
3011 mWave_FDS
.bLFO_On
= 0;
3012 mWave_FDS
.nMainVolume
= 0;
3013 mWave_FDS
.bEnabled
= 0;
3014 mWave_FDS
.nFreq
.W
= 0;
3015 /* mWave_FDS.fFreqCount = 0;*/
3016 mWave_FDS
.nFreqCount
= 0;
3017 mWave_FDS
.nMainAddr
= 0;
3018 mWave_FDS
.bWaveWrite
= 0;
3019 mWave_FDS
.bMain_On
= 0;
3020 mWave_FDS
.nMixL
= 0;
3021 ZEROMEMORY(mWave_FDS
.nWaveTable
,0x40);
3022 ZEROMEMORY(mWave_FDS
.nLFO_Table
,0x40);
3024 mWave_FDS
.nSweep_Count
= mWave_FDS
.nSweep_Timer
=
3025 ((mWave_FDS
.nSweep_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
3026 mWave_FDS
.nVolEnv_Count
= mWave_FDS
.nVolEnv_Timer
=
3027 ((mWave_FDS
.nVolEnv_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
3039 * SetPlaybackOptions
3042 int SetPlaybackOptions(int32_t samplerate
)
3044 if(samplerate
< 2000) return 0;
3045 if(samplerate
> 96000) return 0;
3048 (bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / samplerate
* 0x10000;
3049 nTicksUntilNextSample
= nTicksPerSample
;
3052 RecalcSilenceTracker();
3061 void SetPlaybackSpeed(float playspersec
)
3065 playspersec
= fNSFPlaybackSpeed
;
3068 nTicksPerPlay
= nTicksUntilNextPlay
=
3069 (bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / playspersec
* 0x10000;
3076 float GetPlaybackSpeed()
3078 if(nTicksPerPlay
<= 0) return 0;
3079 return ((bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / (nTicksPerPlay
>>16));
3088 if(!nSampleRate
) return;
3090 nHighPass
= ((int64_t)nHighPassBase
<< 16) / nSampleRate
;
3092 if(nHighPass
> (1<<16)) nHighPass
= 1<<16;
3096 * RecalcSilenceTracker
3099 void RecalcSilenceTracker()
3101 if(nSilenceTrackMS
<= 0 || !nSampleRate
||
3102 (bNoSilenceIfTime
&& bTimeNotDefault
))
3104 nSilentSampleMax
= 0;
3108 nSilentSampleMax
= nSilenceTrackMS
* nSampleRate
/ 500;
3109 nSilentSampleMax
/= 2;
3112 void RebuildOutputTables(void) {
3119 for(i
= 0; i
< 3; i
++)
3124 for(i
= 0; i
< 0x8000; i
++)
3126 ftemp
= (l
[0] * (i
>> 11)) / 2097885;
3127 ftemp
+= (l
[1] * ((i
>> 7) & 0x0F)) / 3121455;
3128 ftemp
+= (l
[2] * (i
& 0x7F)) / 5772690;
3131 main_nOutputTable_L
[i
] = 0;
3133 main_nOutputTable_L
[i
] =
3134 (int16_t)(2396850 / ((1.0f
/ ftemp
) + 100));
3138 for(i
= 0; i
< 2; i
++)
3143 for(j
= 0; j
< 0x10; j
++)
3145 for(i
= 0; i
< 0x10; i
++)
3147 temp
= (int32_t)(l
[0] * j
);
3148 temp
+= (int32_t)(l
[1] * i
);
3151 Squares_nOutputTable_L
[j
][i
] = 0;
3153 Squares_nOutputTable_L
[j
][i
] = 1438200 / ((2072640 / temp
) + 100);
3157 /* VRC6 Pulse 1,2 */
3158 for(i
= 0; i
< 0x10; i
++)
3160 VRC6Pulse_nOutputTable_L
[i
] =
3164 for(i
= 0; i
< 0x20; i
++)
3166 VRC6Saw_nOutputTable_L
[i
] = 3750 * i
/ 0x1F;
3170 /* this amplitude is just a guess */
3172 for(i
= 0; i
< 0x10; i
++)
3174 for(j
= 0; j
< 0x10; j
++)
3176 N106_nOutputTable_L
[i
][j
] = (3000 * i
* j
) / 0xE1;
3180 /* FME-07 Square A,B,C */
3181 FME07_nOutputTable_L
[15] = 3000;
3182 FME07_nOutputTable_L
[0] = 0;
3183 for(i
= 14; i
> 0; i
--)
3185 FME07_nOutputTable_L
[i
] = FME07_nOutputTable_L
[i
+ 1] * 80 / 100;
3191 /* this base volume (4000) is just a guess to what sounds right.
3192 * Given the number of steps available in an FDS wave... it seems like
3193 * it should be much much more... but then it's TOO loud.
3195 for(i
= 0; i
< 0x21; i
++)
3197 for(j
= 0; j
< 0x40; j
++)
3199 FDS_nOutputTable_L
[0][i
][j
] =
3200 (4000 * i
* j
* 30) / (0x21 * 0x40 * 30);
3201 FDS_nOutputTable_L
[1][i
][j
] =
3202 (4000 * i
* j
* 20) / (0x21 * 0x40 * 30);
3203 FDS_nOutputTable_L
[2][i
][j
] =
3204 (4000 * i
* j
* 15) / (0x21 * 0x40 * 30);
3205 FDS_nOutputTable_L
[3][i
][j
] =
3206 (4000 * i
* j
* 12) / (0x21 * 0x40 * 30);
3215 float GetPlayCalls()
3217 if(!nTicksPerPlay
) return 0;
3219 return ((float)nTotalPlays
) +
3220 (1.0f
- (nTicksUntilNextPlay
*1.0f
/ nTicksPerPlay
));
3226 uint32_t GetWrittenTime(float basedplayspersec
/* = 0 */)
3228 if(basedplayspersec
<= 0)
3229 basedplayspersec
= GetPlaybackSpeed();
3231 if(basedplayspersec
<= 0)
3234 return (uint32_t)((GetPlayCalls() * 1000) / basedplayspersec
);
3250 uint8_t SongCompleted()
3252 if(!bFade
) return 0;
3253 if(nTotalPlays
>= nEndFade
) return 1;
3254 if(nSilentSampleMax
) return (nSilentSamples
>= nSilentSampleMax
);
3263 void SetFade(int32_t fadestart
,int32_t fadestop
,
3264 uint8_t bNotDefault
) /* play routine calls */
3266 if(fadestart
< 0) fadestart
= 0;
3267 if(fadestop
< fadestart
) fadestop
= fadestart
;
3269 nStartFade
= (uint32_t)fadestart
;
3270 nEndFade
= (uint32_t)fadestop
;
3272 bTimeNotDefault
= bNotDefault
;
3274 RecalcSilenceTracker();
3282 void SetFadeTime(uint32_t fadestart
,uint32_t fadestop
,float basedplays
,
3283 uint8_t bNotDefault
) /* time in MS */
3286 basedplays
= GetPlaybackSpeed();
3290 SetFade((int32_t)(fadestart
* basedplays
/ 1000),
3291 (int32_t)(fadestop
* basedplays
/ 1000),bNotDefault
);
3298 void RecalculateFade()
3302 /* make it hit silence a little before the song ends...
3303 otherwise we're not really fading OUT, we're just fading umm...
3305 int32_t temp
= (int32_t)(GetPlaybackSpeed() / 4);
3307 if(nEndFade
<= nStartFade
)
3309 nEndFade
= nStartFade
;
3312 else if((nEndFade
- temp
) <= nStartFade
)
3315 fFadeChange
= 1.0f
/ (nEndFade
- nStartFade
- temp
);
3317 if(nTotalPlays
< nStartFade
)
3319 else if(nTotalPlays
>= nEndFade
)
3323 fFadeVolume
= 1.0f
- ( (nTotalPlays
- nStartFade
+ 1) * fFadeChange
);
3330 int32_t GetSamples(uint8_t* buffer
,int32_t buffersize
)
3332 if(!buffer
) return 0;
3333 if(buffersize
< 16) return 0;
3334 if(bFade
&& (nTotalPlays
>= nEndFade
)) return 0;
3337 uint32_t runtocycle
=
3338 (uint32_t)((buffersize
/ 2) * nTicksPerSample
/ 0x10000);
3339 nCPUCycle
= nAPUCycle
= 0;
3344 /*tick = (uint32_t)ceil(fTicksUntilNextPlay);*/
3345 tick
= (nTicksUntilNextPlay
+0xffff)>>16;
3346 if((tick
+ nCPUCycle
) > runtocycle
)
3347 tick
= runtocycle
- nCPUCycle
;
3356 tick
= Emulate6502(tick
+ nCPUCycle
);
3360 nTicksUntilNextPlay
-= tick
<<16;
3361 if(nTicksUntilNextPlay
<= 0)
3363 nTicksUntilNextPlay
+= nTicksPerPlay
;
3364 if((bCPUJammed
== 2) || bNoWaitForReturn
)
3366 regX
= regY
= regA
= (bCleanAXY
? 0 : 0xCD);
3369 bDMCPop_SamePlay
= 0;
3371 if(nForce4017Write
== 1) WriteMemory_pAPU(0x4017,0x00);
3372 if(nForce4017Write
== 2) WriteMemory_pAPU(0x4017,0x80);
3375 if(bFade
&& (nTotalPlays
>= nStartFade
))
3377 fFadeVolume
-= fFadeChange
;
3380 if(nTotalPlays
>= nEndFade
)
3385 if(nCPUCycle
>= runtocycle
)
3389 nCPUCycle
= nAPUCycle
= 0;
3391 if(nSilentSampleMax
&& bFade
)
3393 int16_t* tempbuf
= (int16_t*)buffer
;
3394 while( ((uint8_t*)tempbuf
) < pOutput
)
3396 if( (*tempbuf
< -SILENCE_THRESHOLD
) ||
3397 (*tempbuf
> SILENCE_THRESHOLD
) )
3401 if(++nSilentSamples
>= nSilentSampleMax
)
3402 return (int32_t)( ((uint8_t*)tempbuf
) - buffer
);
3408 return (int32_t)(pOutput
- buffer
);
3411 /****************** 6502 emulation ******************/
3413 /* Memory reading/writing and other defines */
3415 /* reads zero page memory */
3416 #define Zp(a) pRAM[a]
3417 /* reads zero page memory in word form */
3418 #define ZpWord(a) (Zp(a) | (Zp((uint8_t)(a + 1)) << 8))
3420 #define Rd(a) ((ReadMemory[((uint16_t)(a)) >> 12])(a))
3421 /* reads memory in word form */
3422 #define RdWord(a) (Rd(a) | (Rd(a + 1) << 8))
3424 #define Wr(a,v) (WriteMemory[((uint16_t)(a)) >> 12])(a,v)
3425 /* writes zero paged memory */
3426 #define WrZ(a,v) pRAM[a] = v
3427 /* pushes a value onto the stack */
3428 #define PUSH(v) pStack[SP--] = v
3429 /* pulls a value from the stack */
3430 #define PULL(v) v = pStack[++SP]
3432 /* Addressing Modes */
3434 /* first set - gets the value that's being addressed */
3436 #define Ad_VlIm() val = Rd(PC.W); PC.W++
3438 #define Ad_VlZp() final.W = Rd(PC.W); val = Zp(final.W); PC.W++
3440 #define Ad_VlZx() front.W = final.W = Rd(PC.W); final.B.l += X; \
3441 val = Zp(final.B.l); PC.W++
3443 #define Ad_VlZy() front.W = final.W = Rd(PC.W); final.B.l += Y; \
3444 val = Zp(final.B.l); PC.W++
3446 #define Ad_VlAb() final.W = RdWord(PC.W); val = Rd(final.W); PC.W += 2
3447 /*Absolute, X [uses extra cycle if crossed page]*/
3448 #define Ad_VlAx() front.W = final.W = RdWord(PC.W); final.W += X; PC.W += 2;\
3449 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3450 /*Absolute, X [uses extra cycle if crossed page]*/
3451 #define Ad_VlAy() front.W = final.W = RdWord(PC.W); final.W += Y; PC.W += 2;\
3452 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3454 #define Ad_VlIx() front.W = final.W = Rd(PC.W); final.B.l += X; PC.W++; \
3455 final.W = ZpWord(final.B.l); val = Rd(final.W)
3456 /*(Indirect), Y [uses extra cycle if crossed page]*/
3457 #define Ad_VlIy() val = Rd(PC.W); front.W = final.W = ZpWord(val); PC.W++;\
3458 final.W += Y; if(final.B.h != front.B.h) nCPUCycle++; \
3459 front.W = val; val = Rd(final.W)
3461 /* second set - gets the ADDRESS that the mode is referring to (for operators
3462 * that write to memory) note that AbsoluteX, AbsoluteY, and
3463 * IndirectY modes do NOT check for page boundary crossing here
3464 * since that extra cycle isn't added for operators that write to
3465 * memory (it only applies to ones that only read from memory.. in
3466 * which case the 1st set should be used)
3469 #define Ad_AdZp() final.W = Rd(PC.W); PC.W++
3471 #define Ad_AdZx() final.W = front.W = Rd(PC.W); final.B.l += X; PC.W++
3473 #define Ad_AdZy() final.W = front.W = Rd(PC.W); final.B.l += Y; PC.W++
3475 #define Ad_AdAb() final.W = RdWord(PC.W); PC.W += 2
3477 #define Ad_AdAx() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3480 #define Ad_AdAy() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3483 #define Ad_AdIx() front.W = final.W = Rd(PC.W); PC.W++; final.B.l += X; \
3484 final.W = ZpWord(final.B.l)
3486 #define Ad_AdIy() front.W = Rd(PC.W); final.W = ZpWord(front.W) + Y; \
3489 /* third set - reads memory, performs the desired operation on the value, then
3490 * writes back to memory
3491 * used for operators that directly change memory (ASL, INC, DEC, etc)
3494 #define MRW_Zp(cmd) Ad_AdZp(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3496 #define MRW_Zx(cmd) Ad_AdZx(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3498 #define MRW_Zy(cmd) Ad_AdZy(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3500 #define MRW_Ab(cmd) Ad_AdAb(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3502 #define MRW_Ax(cmd) Ad_AdAx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3504 #define MRW_Ay(cmd) Ad_AdAy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3506 #define MRW_Ix(cmd) Ad_AdIx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3508 #define MRW_Iy(cmd) Ad_AdIy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3510 /* Relative modes are special in that they're only used by branch commands
3511 * this macro handles the jump, and should only be called if the branch
3512 * condition was true if the branch condition was false, the PC must be
3516 #define RelJmp(cond) val = Rd(PC.W); PC.W++; final.W = PC.W + (int8_t)(val);\
3518 nCPUCycle += ((final.B.h != PC.B.h) ? 2 : 1);\
3523 #define C_FLAG 0x01 /* carry flag */
3524 #define Z_FLAG 0x02 /* zero flag */
3525 #define I_FLAG 0x04 /* mask interrupt flag */
3526 #define D_FLAG 0x08 /* decimal flag (decimal mode is unsupported on
3528 #define B_FLAG 0x10 /* break flag (not really in the status register
3529 It's value in ST is never used. When ST is
3530 put in memory (by an interrupt or PHP), this
3531 flag is set only if BRK was called)
3532 ** also when PHP is called due to a bug */
3533 #define R_FLAG 0x20 /* reserved flag (not really in the register.
3534 It's value is never used.
3535 Whenever ST is put in memory,
3536 this flag is always set) */
3537 #define V_FLAG 0x40 /* overflow flag */
3538 #define N_FLAG 0x80 /* sign flag */
3543 /* the number of CPU cycles used for each instruction */
3544 static const uint8_t CPU_Cycles
[0x100] = {
3545 7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6,
3546 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3547 6,6,0,8,3,3,5,5,4,2,2,2,4,4,6,6,
3548 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3549 6,6,0,8,3,3,5,5,3,2,2,2,3,4,6,6,
3550 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3551 6,6,0,8,3,3,5,5,4,2,2,2,5,4,6,6,
3552 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3553 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
3554 2,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5,
3555 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
3556 2,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4,
3557 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
3558 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3559 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
3560 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7 };
3562 /* the status of the NZ flags for the given value */
3563 static const uint8_t NZTable
[0x100] = {
3564 Z_FLAG
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3565 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3566 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3567 0,0,0,0,0,0,0,0,0,0,0,
3568 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3569 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3570 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3571 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3572 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3573 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3574 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3575 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3576 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3577 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3578 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3579 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
};
3581 /* A quick macro for working with the above table */
3582 #define UpdateNZ(v) ST = (ST & ~(N_FLAG|Z_FLAG)) | NZTable[v]
3588 * These opcodes perform the action with the given value (changing that
3589 * value if necessary). Registers and flags associated with the operation
3590 * are changed accordingly. There are a few exceptions which will be noted
3596 Adds the value to the accumulator with carry
3598 - Decimal mode not supported on the NES
3599 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3602 tw.W = A + val + (ST & C_FLAG); \
3603 ST = (ST & (I_FLAG|D_FLAG)) | tw.B.h | NZTable[tw.B.l] | \
3604 ( (0x80 & ~(A ^ val) & (A ^ tw.B.l)) ? V_FLAG : 0 ); \
3608 Combines the value with the accumulator using a bitwise AND operation
3615 Left shifts the value 1 bit. The bit that gets shifted out goes to
3617 Changes: value, NZC */
3618 #define ASL(value) \
3619 tw.W = value << 1; \
3620 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | tw.B.h | NZTable[tw.B.l]; \
3624 Compares memory with the accumulator with an AND operation, but changes
3626 The two high bits of memory get transferred to the status reg
3627 Z is set if the AND operation yielded zero, otherwise it's cleared
3630 ST = (ST & ~(N_FLAG|V_FLAG|Z_FLAG)) | (val & (N_FLAG|V_FLAG)) | \
3631 ((A & val) ? 0 : Z_FLAG)
3634 Compares memory with the given register with a subtraction operation.
3635 Flags are set accordingly depending on the result:
3636 Reg < Memory: Z=0, C=0
3637 Reg = Memory: Z=1, C=1
3638 Reg > Memory: Z=0, C=1
3639 N is set according to the result of the subtraction operation
3642 NOTE -- CMP, CPX, CPY all share this same routine, so the desired
3643 register (A, X, or Y respectively) must be given when calling
3644 this macro... as well as the memory to compare it with. */
3647 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | (tw.B.h ? 0 : C_FLAG) | \
3651 Decriments a value by one.
3652 Changes: value, NZ */
3653 #define DEC(value) \
3658 Combines a value with the accumulator using a bitwise exclusive-OR
3666 Incriments a value by one.
3667 Changes: value, NZ */
3668 #define INC(value) \
3673 Shifts value one bit to the right. Bit that gets shifted out goes to
3675 Changes: value, NZC */
3676 #define LSR(value) \
3677 tw.W = value >> 1; \
3678 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3683 Combines a value with the accumulator using a bitwise inclusive-OR
3691 Rotates a value one bit to the left:
3692 C <- 7<-6<-5<-4<-3<-2<-1<-0 <- C
3693 Changes: value, NZC */
3694 #define ROL(value) \
3695 tw.W = (value << 1) | (ST & 0x01); \
3696 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | tw.B.h; \
3700 Rotates a value one bit to the right:
3701 C -> 7->6->5->4->3->2->1->0 -> C
3702 Changes: value, NZC */
3703 #define ROR(value) \
3704 tw.W = (value >> 1) | (ST << 7); \
3705 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3710 Subtracts a value from the accumulator with borrow (inverted carry)
3712 - Decimal mode not supported on the NES
3713 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3716 tw.W = A - val - ((ST & C_FLAG) ? 0 : 1); \
3717 ST = (ST & (I_FLAG|D_FLAG)) | (tw.B.h ? 0 : C_FLAG) | NZTable[tw.B.l] | \
3718 (((A ^ val) & (A ^ tw.B.l) & 0x80) ? V_FLAG : 0); \
3721 /* Undocumented Opcodes
3723 * These opcodes are not included in the official specifications. However,
3724 * some of the unused opcode values perform operations which have since been
3730 Left shifts a value, then ORs the result with the accumulator
3731 Changes: value, A, NZC */
3732 #define ASO(value) \
3733 tw.W = value << 1; \
3735 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3739 Roll memory left 1 bit, then AND the result with the accumulator
3740 Changes: value, A, NZC */
3741 #define RLA(value) \
3742 tw.W = (value << 1) | (ST & 0x01); \
3744 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3748 Right shifts a value one bit, then EORs the result with the accumulator
3749 Changes: value, A, NZC */
3750 #define LSE(value) \
3751 tw.W = value >> 1; \
3753 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | (value & 0x01); \
3757 Roll memory right one bit, then ADC the result
3758 Changes: value, A, NVZC */
3759 #define RRA(value) \
3760 tw.W = (value >> 1) | (ST << 7); \
3761 ST = (ST & ~C_FLAG) | (value & 0x01); \
3766 ANDs the contents of the X and A registers and stores the result
3768 Changes: value [DOES NOT CHANGE X, A, or any flags] */
3769 #define AXS(value) \
3773 Decriments a value and compares it with the A register.
3774 Changes: value, NZC */
3775 #define DCM(value) \
3780 Incriments a value then SBCs it
3781 Changes: value, A, NVZC */
3782 #define INS(value) \
3787 #define AXA(value) \
3788 value = A & X & (Rd(PC.W - 1) + 1)
3791 /* The 6502 emulation function! */
3798 uint32_t Emulate6502(uint32_t runto
)
3800 /* If the CPU is jammed... don't bother */
3804 register union TWIN tw
; /* used in calculations */
3805 register uint8_t ST
= regP
;
3806 register union TWIN PC
;
3808 register uint8_t A
= regA
;
3809 register uint8_t X
= regX
;
3810 register uint8_t Y
= regY
;
3815 uint32_t ret
= nCPUCycle
;
3819 /* Start the loop */
3821 while(nCPUCycle
< runto
)
3826 nCPUCycle
+= CPU_Cycles
[op
];
3829 /* Documented Opcodes first */
3831 /* Flag setting/clearing */
3832 case 0x18: ST
&= ~C_FLAG
; break; /* CLC */
3833 case 0x38: ST
|= C_FLAG
; break; /* SEC */
3834 case 0x58: ST
&= ~I_FLAG
; break; /* CLI */
3835 case 0x78: ST
|= I_FLAG
; break; /* SEI */
3836 case 0xB8: ST
&= ~V_FLAG
; break; /* CLV */
3837 case 0xD8: ST
&= ~D_FLAG
; break; /* CLD */
3838 case 0xF8: ST
|= D_FLAG
; break; /* SED */
3840 /* Branch commands */
3841 case 0x10: RelJmp(!(ST
& N_FLAG
)); break; /* BPL */
3842 case 0x30: RelJmp( (ST
& N_FLAG
)); break; /* BMI */
3843 case 0x50: RelJmp(!(ST
& V_FLAG
)); break; /* BVC */
3844 case 0x70: RelJmp( (ST
& V_FLAG
)); break; /* BVS */
3845 case 0x90: RelJmp(!(ST
& C_FLAG
)); break; /* BCC */
3846 case 0xB0: RelJmp( (ST
& C_FLAG
)); break; /* BCS */
3847 case 0xD0: RelJmp(!(ST
& Z_FLAG
)); break; /* BNE */
3848 case 0xF0: RelJmp( (ST
& Z_FLAG
)); break; /* BEQ */
3850 /* Direct stack alteration commands (push/pull commands) */
3851 case 0x08: PUSH(ST
| R_FLAG
| B_FLAG
); break; /* PHP */
3852 case 0x28: PULL(ST
); break; /* PLP */
3853 case 0x48: PUSH(A
); break; /* PHA */
3854 case 0x68: PULL(A
); UpdateNZ(A
); break; /* PLA */
3856 /* Register Transfers */
3857 case 0x8A: A
= X
; UpdateNZ(A
); break; /* TXA */
3858 case 0x98: A
= Y
; UpdateNZ(A
); break; /* TYA */
3859 case 0x9A: SP
= X
; break; /* TXS */
3860 case 0xA8: Y
= A
; UpdateNZ(A
); break; /* TAY */
3861 case 0xAA: X
= A
; UpdateNZ(A
); break; /* TAX */
3862 case 0xBA: X
= SP
; UpdateNZ(X
); break; /* TSX */
3864 /* Other commands */
3867 case 0x61: Ad_VlIx(); ADC(); break;
3868 case 0x65: Ad_VlZp(); ADC(); break;
3869 case 0x69: Ad_VlIm(); ADC(); break;
3870 case 0x6D: Ad_VlAb(); ADC(); break;
3871 case 0x71: Ad_VlIy(); ADC(); break;
3872 case 0x75: Ad_VlZx(); ADC(); break;
3873 case 0x79: Ad_VlAy(); ADC(); break;
3874 case 0x7D: Ad_VlAx(); ADC(); break;
3877 case 0x21: Ad_VlIx(); AND(); break;
3878 case 0x25: Ad_VlZp(); AND(); break;
3879 case 0x29: Ad_VlIm(); AND(); break;
3880 case 0x2D: Ad_VlAb(); AND(); break;
3881 case 0x31: Ad_VlIy(); AND(); break;
3882 case 0x35: Ad_VlZx(); AND(); break;
3883 case 0x39: Ad_VlAy(); AND(); break;
3884 case 0x3D: Ad_VlAx(); AND(); break;
3887 case 0x0A: ASL(A
); break;
3888 case 0x06: MRW_Zp(ASL
); break;
3889 case 0x0E: MRW_Ab(ASL
); break;
3890 case 0x16: MRW_Zx(ASL
); break;
3891 case 0x1E: MRW_Ax(ASL
); break;
3894 case 0x24: Ad_VlZp(); BIT(); break;
3895 case 0x2C: Ad_VlAb(); BIT(); break;
3901 PC
.W
++; /*BRK has a padding byte*/
3902 PUSH(PC
.B
.h
); /*push high byte of the return address*/
3903 PUSH(PC
.B
.l
); /*push low byte of return address*/
3904 PUSH(ST
| R_FLAG
| B_FLAG
); /*push processor status with R|B flags*/
3905 ST
|= I_FLAG
; /*mask interrupts*/
3906 PC
.W
= RdWord(0xFFFE); /*read the IRQ vector and jump to it*/
3908 /* extra check to make sure we didn't hit an infinite BRK loop */
3909 if(!Rd(PC
.W
)) /* next command will be BRK */
3911 /* the CPU will endlessly loop...
3912 just jam it to ease processing power */
3919 case 0xC1: Ad_VlIx(); CMP(A
); break;
3920 case 0xC5: Ad_VlZp(); CMP(A
); break;
3921 case 0xC9: Ad_VlIm(); CMP(A
); break;
3922 case 0xCD: Ad_VlAb(); CMP(A
); break;
3923 case 0xD1: Ad_VlIy(); CMP(A
); break;
3924 case 0xD5: Ad_VlZx(); CMP(A
); break;
3925 case 0xD9: Ad_VlAy(); CMP(A
); break;
3926 case 0xDD: Ad_VlAx(); CMP(A
); break;
3929 case 0xE0: Ad_VlIm(); CMP(X
); break;
3930 case 0xE4: Ad_VlZp(); CMP(X
); break;
3931 case 0xEC: Ad_VlAb(); CMP(X
); break;
3934 case 0xC0: Ad_VlIm(); CMP(Y
); break;
3935 case 0xC4: Ad_VlZp(); CMP(Y
); break;
3936 case 0xCC: Ad_VlAb(); CMP(Y
); break;
3939 case 0xCA: DEC(X
); break; /* DEX */
3940 case 0x88: DEC(Y
); break; /* DEY */
3941 case 0xC6: MRW_Zp(DEC
); break;
3942 case 0xCE: MRW_Ab(DEC
); break;
3943 case 0xD6: MRW_Zx(DEC
); break;
3944 case 0xDE: MRW_Ax(DEC
); break;
3947 case 0x41: Ad_VlIx(); EOR(); break;
3948 case 0x45: Ad_VlZp(); EOR(); break;
3949 case 0x49: Ad_VlIm(); EOR(); break;
3950 case 0x4D: Ad_VlAb(); EOR(); break;
3951 case 0x51: Ad_VlIy(); EOR(); break;
3952 case 0x55: Ad_VlZx(); EOR(); break;
3953 case 0x59: Ad_VlAy(); EOR(); break;
3954 case 0x5D: Ad_VlAx(); EOR(); break;
3957 case 0xE8: INC(X
); break; /* INX */
3958 case 0xC8: INC(Y
); break; /* INY */
3959 case 0xE6: MRW_Zp(INC
); break;
3960 case 0xEE: MRW_Ab(INC
); break;
3961 case 0xF6: MRW_Zx(INC
); break;
3962 case 0xFE: MRW_Ax(INC
); break;
3966 case 0x4C: final
.W
= RdWord(PC
.W
); PC
.W
= final
.W
; val
= 0; break;
3967 /* Indirect JMP -- must take caution:
3968 Indirection at 01FF will read from 01FF and 0100 (not 0200) */
3969 case 0x6C: front
.W
= final
.W
= RdWord(PC
.W
);
3970 PC
.B
.l
= Rd(final
.W
); final
.B
.l
++;
3971 PC
.B
.h
= Rd(final
.W
); final
.W
= PC
.W
;
3976 final
.W
= RdWord(PC
.W
);
3977 PC
.W
++; /* JSR only increments the return address by one.
3978 It's incremented again upon RTS */
3979 PUSH(PC
.B
.h
); /* push high byte of return address */
3980 PUSH(PC
.B
.l
); /* push low byte of return address */
3985 case 0xA1: Ad_VlIx(); A
= val
; UpdateNZ(A
); break;
3986 case 0xA5: Ad_VlZp(); A
= val
; UpdateNZ(A
); break;
3987 case 0xA9: Ad_VlIm(); A
= val
; UpdateNZ(A
); break;
3988 case 0xAD: Ad_VlAb(); A
= val
; UpdateNZ(A
); break;
3989 case 0xB1: Ad_VlIy(); A
= val
; UpdateNZ(A
); break;
3990 case 0xB5: Ad_VlZx(); A
= val
; UpdateNZ(A
); break;
3991 case 0xB9: Ad_VlAy(); A
= val
; UpdateNZ(A
); break;
3992 case 0xBD: Ad_VlAx(); A
= val
; UpdateNZ(A
); break;
3995 case 0xA2: Ad_VlIm(); X
= val
; UpdateNZ(X
); break;
3996 case 0xA6: Ad_VlZp(); X
= val
; UpdateNZ(X
); break;
3997 case 0xAE: Ad_VlAb(); X
= val
; UpdateNZ(X
); break;
3998 case 0xB6: Ad_VlZy(); X
= val
; UpdateNZ(X
); break;
3999 case 0xBE: Ad_VlAy(); X
= val
; UpdateNZ(X
); break;
4002 case 0xA0: Ad_VlIm(); Y
= val
; UpdateNZ(Y
); break;
4003 case 0xA4: Ad_VlZp(); Y
= val
; UpdateNZ(Y
); break;
4004 case 0xAC: Ad_VlAb(); Y
= val
; UpdateNZ(Y
); break;
4005 case 0xB4: Ad_VlZx(); Y
= val
; UpdateNZ(Y
); break;
4006 case 0xBC: Ad_VlAx(); Y
= val
; UpdateNZ(Y
); break;
4009 case 0x4A: LSR(A
); break;
4010 case 0x46: MRW_Zp(LSR
); break;
4011 case 0x4E: MRW_Ab(LSR
); break;
4012 case 0x56: MRW_Zx(LSR
); break;
4013 case 0x5E: MRW_Ax(LSR
); break;
4018 /* --- Undocumented ---
4019 These opcodes perform the same action as NOP */
4020 case 0x1A: case 0x3A: case 0x5A:
4021 case 0x7A: case 0xDA: case 0xFA: break;
4024 case 0x01: Ad_VlIx(); ORA(); break;
4025 case 0x05: Ad_VlZp(); ORA(); break;
4026 case 0x09: Ad_VlIm(); ORA(); break;
4027 case 0x0D: Ad_VlAb(); ORA(); break;
4028 case 0x11: Ad_VlIy(); ORA(); break;
4029 case 0x15: Ad_VlZx(); ORA(); break;
4030 case 0x19: Ad_VlAy(); ORA(); break;
4031 case 0x1D: Ad_VlAx(); ORA(); break;
4034 case 0x2A: ROL(A
); break;
4035 case 0x26: MRW_Zp(ROL
); break;
4036 case 0x2E: MRW_Ab(ROL
); break;
4037 case 0x36: MRW_Zx(ROL
); break;
4038 case 0x3E: MRW_Ax(ROL
); break;
4041 case 0x6A: ROR(A
); break;
4042 case 0x66: MRW_Zp(ROR
); break;
4043 case 0x6E: MRW_Ab(ROR
); break;
4044 case 0x76: MRW_Zx(ROR
); break;
4045 case 0x7E: MRW_Ax(ROR
); break;
4049 PULL(ST
); /*pull processor status*/
4050 PULL(PC
.B
.l
); /*pull low byte of return address*/
4051 PULL(PC
.B
.h
); /*pull high byte of return address*/
4058 PC
.W
++; /* the return address is one less of what it needs */
4062 case 0xE1: Ad_VlIx(); SBC(); break;
4063 case 0xE5: Ad_VlZp(); SBC(); break;
4064 /* - Undocumented - EB performs the same operation as SBC immediate */
4066 case 0xE9: Ad_VlIm(); SBC(); break;
4067 case 0xED: Ad_VlAb(); SBC(); break;
4068 case 0xF1: Ad_VlIy(); SBC(); break;
4069 case 0xF5: Ad_VlZx(); SBC(); break;
4070 case 0xF9: Ad_VlAy(); SBC(); break;
4071 case 0xFD: Ad_VlAx(); SBC(); break;
4074 case 0x81: Ad_AdIx(); val
= A
; Wr(final
.W
,A
); break;
4075 case 0x85: Ad_AdZp(); val
= A
; WrZ(final
.W
,A
); break;
4076 case 0x8D: Ad_AdAb(); val
= A
; Wr(final
.W
,A
); break;
4077 case 0x91: Ad_AdIy(); val
= A
; Wr(final
.W
,A
); break;
4078 case 0x95: Ad_AdZx(); val
= A
; WrZ(final
.W
,A
); break;
4079 case 0x99: Ad_AdAy(); val
= A
; Wr(final
.W
,A
); break;
4080 case 0x9D: Ad_AdAx(); val
= A
; Wr(final
.W
,A
); break;
4083 case 0x86: Ad_AdZp(); val
= X
; WrZ(final
.W
,X
); break;
4084 case 0x8E: Ad_AdAb(); val
= X
; Wr(final
.W
,X
); break;
4085 case 0x96: Ad_AdZy(); val
= X
; WrZ(final
.W
,X
); break;
4088 case 0x84: Ad_AdZp(); val
= Y
; WrZ(final
.W
,Y
); break;
4089 case 0x8C: Ad_AdAb(); val
= Y
; Wr(final
.W
,Y
); break;
4090 case 0x94: Ad_AdZx(); val
= Y
; WrZ(final
.W
,Y
); break;
4092 /* Undocumented Opcodes */
4094 case 0x03: if(bIgnoreIllegalOps
) break; MRW_Ix(ASO
); break;
4095 case 0x07: if(bIgnoreIllegalOps
) break; MRW_Zp(ASO
); break;
4096 case 0x0F: if(bIgnoreIllegalOps
) break; MRW_Ab(ASO
); break;
4097 case 0x13: if(bIgnoreIllegalOps
) break; MRW_Iy(ASO
); break;
4098 case 0x17: if(bIgnoreIllegalOps
) break; MRW_Zx(ASO
); break;
4099 case 0x1B: if(bIgnoreIllegalOps
) break; MRW_Ay(ASO
); break;
4100 case 0x1F: if(bIgnoreIllegalOps
) break; MRW_Ax(ASO
); break;
4103 case 0x23: if(bIgnoreIllegalOps
) break; MRW_Ix(RLA
); break;
4104 case 0x27: if(bIgnoreIllegalOps
) break; MRW_Zp(RLA
); break;
4105 case 0x2F: if(bIgnoreIllegalOps
) break; MRW_Ab(RLA
); break;
4106 case 0x33: if(bIgnoreIllegalOps
) break; MRW_Iy(RLA
); break;
4107 case 0x37: if(bIgnoreIllegalOps
) break; MRW_Zx(RLA
); break;
4108 case 0x3B: if(bIgnoreIllegalOps
) break; MRW_Ay(RLA
); break;
4109 case 0x3F: if(bIgnoreIllegalOps
) break; MRW_Ax(RLA
); break;
4112 case 0x43: if(bIgnoreIllegalOps
) break; MRW_Ix(LSE
); break;
4113 case 0x47: if(bIgnoreIllegalOps
) break; MRW_Zp(LSE
); break;
4114 case 0x4F: if(bIgnoreIllegalOps
) break; MRW_Ab(LSE
); break;
4115 case 0x53: if(bIgnoreIllegalOps
) break; MRW_Iy(LSE
); break;
4116 case 0x57: if(bIgnoreIllegalOps
) break; MRW_Zx(LSE
); break;
4117 case 0x5B: if(bIgnoreIllegalOps
) break; MRW_Ay(LSE
); break;
4118 case 0x5F: if(bIgnoreIllegalOps
) break; MRW_Ax(LSE
); break;
4121 case 0x63: if(bIgnoreIllegalOps
) break; MRW_Ix(RRA
); break;
4122 case 0x67: if(bIgnoreIllegalOps
) break; MRW_Zp(RRA
); break;
4123 case 0x6F: if(bIgnoreIllegalOps
) break; MRW_Ab(RRA
); break;
4124 case 0x73: if(bIgnoreIllegalOps
) break; MRW_Iy(RRA
); break;
4125 case 0x77: if(bIgnoreIllegalOps
) break; MRW_Zx(RRA
); break;
4126 case 0x7B: if(bIgnoreIllegalOps
) break; MRW_Ay(RRA
); break;
4127 case 0x7F: if(bIgnoreIllegalOps
) break; MRW_Ax(RRA
); break;
4130 case 0x83: if(bIgnoreIllegalOps
) break; MRW_Ix(AXS
); break;
4131 case 0x87: if(bIgnoreIllegalOps
) break; MRW_Zp(AXS
); break;
4132 case 0x8F: if(bIgnoreIllegalOps
) break; MRW_Ab(AXS
); break;
4133 case 0x97: if(bIgnoreIllegalOps
) break; MRW_Zy(AXS
); break;
4136 case 0xA3: if(bIgnoreIllegalOps
) break;
4137 Ad_VlIx(); X
= A
= val
; UpdateNZ(A
); break;
4138 case 0xA7: if(bIgnoreIllegalOps
) break;
4139 Ad_VlZp(); X
= A
= val
; UpdateNZ(A
); break;
4140 case 0xAF: if(bIgnoreIllegalOps
) break;
4141 Ad_VlAb(); X
= A
= val
; UpdateNZ(A
); break;
4142 case 0xB3: if(bIgnoreIllegalOps
) break;
4143 Ad_VlIy(); X
= A
= val
; UpdateNZ(A
); break;
4144 case 0xB7: if(bIgnoreIllegalOps
) break;
4145 Ad_VlZy(); X
= A
= val
; UpdateNZ(A
); break;
4146 case 0xBF: if(bIgnoreIllegalOps
) break;
4147 Ad_VlAy(); X
= A
= val
; UpdateNZ(A
); break;
4150 case 0xC3: if(bIgnoreIllegalOps
) break; MRW_Ix(DCM
); break;
4151 case 0xC7: if(bIgnoreIllegalOps
) break; MRW_Zp(DCM
); break;
4152 case 0xCF: if(bIgnoreIllegalOps
) break; MRW_Ab(DCM
); break;
4153 case 0xD3: if(bIgnoreIllegalOps
) break; MRW_Iy(DCM
); break;
4154 case 0xD7: if(bIgnoreIllegalOps
) break; MRW_Zx(DCM
); break;
4155 case 0xDB: if(bIgnoreIllegalOps
) break; MRW_Ay(DCM
); break;
4156 case 0xDF: if(bIgnoreIllegalOps
) break; MRW_Ax(DCM
); break;
4159 case 0xE3: if(bIgnoreIllegalOps
) break; MRW_Ix(INS
); break;
4160 case 0xE7: if(bIgnoreIllegalOps
) break; MRW_Zp(INS
); break;
4161 case 0xEF: if(bIgnoreIllegalOps
) break; MRW_Ab(INS
); break;
4162 case 0xF3: if(bIgnoreIllegalOps
) break; MRW_Iy(INS
); break;
4163 case 0xF7: if(bIgnoreIllegalOps
) break; MRW_Zx(INS
); break;
4164 case 0xFB: if(bIgnoreIllegalOps
) break; MRW_Ay(INS
); break;
4165 case 0xFF: if(bIgnoreIllegalOps
) break; MRW_Ax(INS
); break;
4168 AND Accumulator with memory and LSR the result */
4169 case 0x4B: if(bIgnoreIllegalOps
) break;
4170 Ad_VlIm(); A
&= val
; LSR(A
); break;
4173 ANDs memory with the Accumulator and RORs the result */
4174 case 0x6B: if(bIgnoreIllegalOps
) break;
4175 Ad_VlIm(); A
&= val
; ROR(A
); break;
4178 Transfers X -> A, then ANDs A with memory */
4179 case 0x8B: if(bIgnoreIllegalOps
) break;
4180 Ad_VlIm(); A
= X
& val
; UpdateNZ(A
); break;
4183 OR the Accumulator with #EE, AND Accumulator with Memory,
4185 case 0xAB: if(bIgnoreIllegalOps
) break;
4186 Ad_VlIm(); X
= (A
&= (val
| 0xEE));
4190 ANDs A and X registers (does not change A), subtracts memory
4191 from result (CMP style, not SBC style) result is stored in X */
4192 case 0xCB: if(bIgnoreIllegalOps
) break;
4193 Ad_VlIm(); tw
.W
= (X
& A
) - val
; X
= tw
.B
.l
;
4194 ST
= (ST
& ~(N_FLAG
|Z_FLAG
|C_FLAG
)) | NZTable
[X
] |
4195 (tw
.B
.h
? C_FLAG
: 0); break;
4197 Skip Byte... or DOP - Double No-Op
4198 These bytes do nothing, but take a parameter (which can be
4200 case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
4201 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2:
4203 if(bIgnoreIllegalOps
) break;
4204 PC
.W
++; /* skip unused byte */
4208 Swip Word... or TOP - Tripple No-Op
4209 These bytes are the same as SKB, only they take a 2 byte parameter.
4210 This can be ignored in some cases, but the read needs to be
4211 performed in a some cases because an extra clock cycle may be used
4213 /* Absolute address... no need for operator */
4215 if(bIgnoreIllegalOps
) break;
4217 /* Absolute X address... may cross page, have to perform the read */
4218 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
4219 if(bIgnoreIllegalOps
) break;
4223 Jams up CPU operation */
4224 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52:
4225 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
4226 /*it's not -really- jammed... only the NSF code has ended*/
4227 if(PC
.W
== 0x5004) bCPUJammed
= 2;
4230 if(bIgnoreIllegalOps
) break;
4237 if(bIgnoreIllegalOps
) break;
4239 SP
= A
& X
& (Rd(PC
.W
- 1) + 1);
4245 if(bIgnoreIllegalOps
) break;
4247 Y
&= (Rd(PC
.W
- 1) + 1);
4253 if(bIgnoreIllegalOps
) break;
4255 X
&= (Rd(PC
.W
- 1) + 1);
4260 case 0x93: if(bIgnoreIllegalOps
) break; MRW_Iy(AXA
); break;
4261 case 0x9F: if(bIgnoreIllegalOps
) break; MRW_Ay(AXA
); break;
4264 case 0x0B: case 0x2B:
4265 if(bIgnoreIllegalOps
) break;
4268 ST
= (ST
& ~(N_FLAG
|Z_FLAG
|C_FLAG
)) |
4269 NZTable
[A
] | ((A
& 0x80) ? C_FLAG
: 0);
4274 if(bIgnoreIllegalOps
) break;
4276 X
= A
= (SP
&= val
);
4292 return (nCPUCycle
- ret
);
4295 /****************** rockbox interface ******************/
4297 static void set_codec_track(int t
, int d
) {
4298 int track
,fade
,def
=0;
4301 /* for REPEAT_ONE we disable track limits */
4302 if (ci
->global_settings
->repeat_mode
!=REPEAT_ONE
) {
4303 if (!bIsExtended
|| nTrackTime
[t
]==-1) {track
=60*2*1000; def
=1;}
4304 else track
=nTrackTime
[t
];
4305 if (!bIsExtended
|| nTrackFade
[t
]==-1) fade
=5*1000;
4306 else fade
=nTrackFade
[t
];
4307 nSilenceTrackMS
=5000;
4308 SetFadeTime(track
,track
+fade
, fNSFPlaybackSpeed
,def
);
4310 ci
->id3
->elapsed
=d
*1000; /* d is track no to display */
4313 /* this is the codec entry point */
4314 enum codec_status
codec_main(void)
4319 int endofstream
; /* end of stream flag */
4322 char last_path
[MAX_PATH
];
4325 /* we only render 16 bits */
4326 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 16);
4328 ci
->configure(DSP_SET_FREQUENCY
, 44100);
4329 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
4331 RebuildOutputTables();
4339 DEBUGF("NSF: next_track\n");
4343 DEBUGF("NSF: after init\n");
4346 /* wait for track info to load */
4347 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
4350 codec_set_replaygain(ci
->id3
);
4352 /* Read the entire file */
4353 DEBUGF("NSF: request file\n");
4355 buf
= ci
->request_buffer(&n
, ci
->filesize
);
4356 if (!buf
|| n
< (size_t)ci
->filesize
) {
4357 DEBUGF("NSF: file load failed\n");
4362 if(!NSFCore_Initialize()) {
4363 DEBUGF("NSF: NSFCore_Initialize failed\n"); return CODEC_ERROR
;}
4365 if(LoadFile(buf
,ci
->filesize
)) {
4366 DEBUGF("NSF: LoadFile failed\n"); return CODEC_ERROR
;}
4367 if(!SetPlaybackOptions(44100)) {
4368 DEBUGF("NSF: SetPlaybackOptions failed\n"); return CODEC_ERROR
;}
4369 if(!LoadNSF(nDataBufferSize
)) {
4370 DEBUGF("NSF: LoadNSF failed\n"); return CODEC_ERROR
;}
4372 ci
->id3
->title
=szGameTitle
;
4373 ci
->id3
->artist
=szArtist
;
4374 ci
->id3
->album
=szCopyright
;
4375 if (usingplaylist
) {
4376 ci
->id3
->length
=nPlaylistSize
*1000;
4378 ci
->id3
->length
=nTrackCount
*1000;
4381 if (!dontresettrack
||strcmp(ci
->id3
->path
,last_path
)) {
4382 /* if this is the first time we're seeing this file, or if we haven't
4383 been asked to preserve the track number, default to the proper
4386 ci
->global_settings
->repeat_mode
!=REPEAT_ONE
&& nPlaylistSize
>0) {
4387 /* decide to use the playlist */
4390 set_codec_track(nPlaylist
[0],0);
4392 /* simply use the initial track */
4393 track
=nInitialTrack
;
4394 set_codec_track(track
,track
);
4397 /* if we've already been running this file assume track is set
4399 if (usingplaylist
) set_codec_track(nPlaylist
[track
],track
);
4400 else set_codec_track(track
,track
);
4402 strcpy(last_path
,ci
->id3
->path
);
4404 /* The main decoder loop */
4408 reset_profile_timers();
4410 while (!endofstream
) {
4413 if (ci
->stop_codec
|| ci
->new_track
) {
4417 if (ci
->seek_time
>0) {
4418 track
=ci
->seek_time
/1000;
4419 if (usingplaylist
) {
4420 if (track
>=nPlaylistSize
) break;
4422 if (track
>=nTrackCount
) break;
4424 ci
->seek_complete();
4430 written
=GetSamples((uint8_t*)samples
,WAV_CHUNK_SIZE
/2);
4433 if (!written
|| SongCompleted()) {
4434 print_timers(last_path
,track
);
4435 reset_profile_timers();
4438 if (usingplaylist
) {
4439 if (track
>=nPlaylistSize
) break;
4441 if (track
>=nTrackCount
) break;
4447 ci
->pcmbuf_insert(samples
, NULL
, written
>> 1);
4450 print_timers(last_path
,track
);
4452 if (ci
->request_next_track()) {
4453 if (ci
->global_settings
->repeat_mode
==REPEAT_ONE
) {
4454 /* in repeat one mode just advance to the next track */
4456 if (track
>=nTrackCount
) track
=0;
4458 /* at this point we can't tell if another file has been selected */
4461 /* otherwise do a proper load of the next file */
4465 goto next_track
; /* when we fall through here we'll reload the file */