1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
9 * Copyright (C) 2006 Adam Gashlin (hcs)
10 * Copyright (C) 2004 Disch
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
21 * This is a perversion of Disch's excellent NotSoFatso.
30 /* arm doesn't benefit from IRAM? */
37 #define ICODE_INSTEAD_OF_INLINE
40 /* Maximum number of bytes to process in one iteration */
41 #define WAV_CHUNK_SIZE (1024*2)
43 static int16_t samples
[WAV_CHUNK_SIZE
] IBSS_ATTR
;
45 #define ZEROMEMORY(addr,size) memset(addr,0,size)
47 /* simple profiling with USEC_TIMER
55 #define CREATE_TIMER(name) uint32_t nsf_timer_##name##_start,\
56 nsf_timer_##name##_total
57 #define ENTER_TIMER(name) nsf_timer_##name##_start=USEC_TIMER
58 #define EXIT_TIMER(name) nsf_timer_##name##_total+=\
59 (USEC_TIMER-nsf_timer_##name##_start)
60 #define READ_TIMER(name) (nsf_timer_##name##_total)
61 #define RESET_TIMER(name) nsf_timer_##name##_total=0
63 #define PRINT_TIMER_PCT(bname,tname,nstr) ci->fdprintf(
64 logfd
,"%10ld ",READ_TIMER(bname
));\
65 ci
->fdprintf(logfd
,"(%3d%%) " nstr
"\t",\
66 ((uint64_t)READ_TIMER(bname
))*100/READ_TIMER(tname
))
71 CREATE_TIMER(squares
);
73 CREATE_TIMER(tnd_enter
);
74 CREATE_TIMER(tnd_tri
);
75 CREATE_TIMER(tnd_noise
);
76 CREATE_TIMER(tnd_dmc
);
81 void reset_profile_timers(void) {
87 RESET_TIMER(tnd_enter
);
89 RESET_TIMER(tnd_noise
);
98 void print_timers(char * path
, int track
) {
99 logfd
= ci
->open("/nsflog.txt",O_WRONLY
|O_CREAT
|O_APPEND
);
100 ci
->fdprintf(logfd
,"%s[%d]:\t",path
,track
);
101 ci
->fdprintf(logfd
,"%10ld total\t",READ_TIMER(total
));
102 PRINT_TIMER_PCT(cpu
,total
,"CPU");
103 PRINT_TIMER_PCT(apu
,total
,"APU");
104 ci
->fdprintf(logfd
,"\n\t");
105 PRINT_TIMER_PCT(squares
,apu
,"squares");
106 PRINT_TIMER_PCT(frame
,apu
,"frame");
107 PRINT_TIMER_PCT(mix
,apu
,"mix");
108 PRINT_TIMER_PCT(fds
,apu
,"FDS");
109 PRINT_TIMER_PCT(tnd
,apu
,"tnd");
110 ci
->fdprintf(logfd
,"\n\t\t");
111 PRINT_TIMER_PCT(tnd_enter
,tnd
,"enter");
112 PRINT_TIMER_PCT(tnd_tri
,tnd
,"triangle");
113 PRINT_TIMER_PCT(tnd_noise
,tnd
,"noise");
114 PRINT_TIMER_PCT(tnd_dmc
,tnd
,"DMC");
115 ci
->fdprintf(logfd
,"\n");
123 #define CREATE_TIMER(name)
124 #define ENTER_TIMER(name)
125 #define EXIT_TIMER(name)
126 #define READ_TIMER(name)
127 #define RESET_TIMER(name)
128 #define print_timers(path,track)
129 #define reset_profile_timers()
133 /* proper handling of multibyte values */
134 #ifdef ROCKBOX_LITTLE_ENDIAN
138 struct{ uint8_t l
; uint8_t h
; } B
;
144 struct{ uint8_t l
; uint8_t h
; uint16_t w
; } B
;
151 struct{ uint8_t h
; uint8_t l
; } B
;
157 struct{uint16_t w
; uint8_t h
; uint8_t l
; } B
;
162 #define NTSC_FREQUENCY 1789772.727273f
163 #define PAL_FREQUENCY 1652097.692308f
164 #define NTSC_NMIRATE 60.098814f
165 #define PAL_NMIRATE 50.006982f
167 #define NES_FREQUENCY 21477270
168 #define NTSC_FRAME_COUNTER_FREQ (NTSC_FREQUENCY / (NES_FREQUENCY / 89490.0f))
169 #define PAL_FRAME_COUNTER_FREQ (PAL_FREQUENCY / (NES_FREQUENCY / 89490.0f))
171 /****************** tables */
172 static const int32_t ModulationTable
[8] ICONST_ATTR
= {0,1,2,4,0,-4,-2,-1};
173 const uint16_t DMC_FREQ_TABLE
[2][0x10] = {
175 {0x1AC,0x17C,0x154,0x140,0x11E,0x0FE,0x0E2,0x0D6,0x0BE,0x0A0,0x08E,0x080,
176 0x06A,0x054,0x048,0x036},
178 {0x18C,0x160,0x13A,0x128,0x108,0x0EA,0x0D0,0x0C6,0x0B0,0x094,0x082,0x076,
179 0x062,0x04E,0x042,0x032}
182 const uint8_t DUTY_CYCLE_TABLE
[4] = {2,4,8,12};
184 const uint8_t LENGTH_COUNTER_TABLE
[0x20] = {
185 0x0A,0xFE,0x14,0x02,0x28,0x04,0x50,0x06,0xA0,0x08,0x3C,0x0A,0x0E,0x0C,0x1A,
186 0x0E,0x0C,0x10,0x18,0x12,0x30,0x14,0x60,0x16,0xC0,0x18,0x48,0x1A,0x10,0x1C,
190 const uint16_t NOISE_FREQ_TABLE
[0x10] = {
191 0x004,0x008,0x010,0x020,0x040,0x060,0x080,0x0A0,0x0CA,0x0FE,0x17C,0x1FC,
192 0x2FA,0x3F8,0x7F2,0xFE4
195 /****************** NSF loading ******************/
197 /* file format structs (both are little endian) */
202 uint8_t nHeaderExtra
;
205 uint8_t nInitialTrack
;
206 uint16_t nLoadAddress
;
207 uint16_t nInitAddress
;
208 uint16_t nPlayAddress
;
209 uint8_t szGameTitle
[32];
210 uint8_t szArtist
[32];
211 uint8_t szCopyright
[32];
213 uint8_t nBankSwitch
[8];
217 uint8_t nExpansion
[4];
220 struct NSFE_INFOCHUNK
222 uint16_t nLoadAddress
;
223 uint16_t nInitAddress
;
224 uint16_t nPlayAddress
;
228 uint8_t nStartingTrack
;
231 int32_t LoadFile(uint8_t *,size_t);
233 int32_t LoadFile_NESM(uint8_t *,size_t);
234 int32_t LoadFile_NSFE(uint8_t *,size_t);
239 int32_t bIsExtended
=0; /* 0 = NSF, 1 = NSFE */
240 uint8_t nIsPal
=0; /* 0 = NTSC, 1 = PAL,
241 2,3 = mixed NTSC/PAL (interpretted as NTSC) */
242 int32_t nfileLoadAddress
=0; /* The address to which the NSF code is
244 int32_t nfileInitAddress
=0; /* The address of the Init routine
245 (called at track change) */
246 int32_t nfilePlayAddress
=0; /* The address of the Play routine
247 (called several times a second) */
248 uint8_t nChipExtensions
=0; /* Bitwise representation of the external chips
251 /* old NESM speed stuff (blarg) */
252 int32_t nNTSC_PlaySpeed
=0;
253 int32_t nPAL_PlaySpeed
=0;
256 /* The number of tracks in the NSF (1 = 1 track, 5 = 5 tracks, etc) */
257 int32_t nTrackCount
=0;
258 /* The initial track (ZERO BASED: 0 = 1st track, 4 = 5th track, etc) */
259 int32_t nInitialTrack
=0;
262 uint8_t* pDataBuffer
=0; /* the buffer containing NSF code. */
263 int32_t nDataBufferSize
=0; /* the size of the above buffer. */
266 uint8_t nPlaylist
[256]; /* Each entry is the zero based index of the
268 int32_t nPlaylistSize
=0; /* the number of tracks in the playlist */
270 /* track time / fade */
271 int32_t nTrackTime
[256]; /* track times -1 if no track times specified */
272 int32_t nTrackFade
[256]; /* track fade times -1 if none are specified */
275 uint8_t szGameTitle
[0x101];
276 uint8_t szArtist
[0x101];
277 uint8_t szCopyright
[0x101];
278 uint8_t szRipper
[0x101];
280 /* bankswitching info */
281 uint8_t nBankswitch
[8]={0}; /* The initial bankswitching registers needed
282 * for some NSFs. If the NSF does not use
283 * bankswitching, these values will all be zero
286 int32_t LoadFile(uint8_t * inbuffer
, size_t size
)
288 if(!inbuffer
) return -1;
292 if(!memcmp(inbuffer
,"NESM",4)) ret
= LoadFile_NESM(inbuffer
,size
);
293 if(!memcmp(inbuffer
,"NSFE",4)) ret
= LoadFile_NSFE(inbuffer
,size
);
296 * Snake's revenge puts '00' for the initial track,
297 * which (after subtracting 1) makes it 256 or -1 (bad!)
298 * This prevents that crap
300 if(nInitialTrack
>= nTrackCount
)
302 if(nInitialTrack
< 0)
305 /* if there's no tracks... this is a crap NSF */
314 int32_t LoadFile_NESM(uint8_t* inbuffer
, size_t size
)
316 uint8_t ignoreversion
=1;
320 struct NESM_HEADER hdr
;
322 memcpy(&hdr
,inbuffer
,sizeof(hdr
));
324 /* confirm the header */
325 if(memcmp("NESM",&(hdr
.nHeader
),4)) return -1;
326 if(hdr
.nHeaderExtra
!= 0x1A) return -1;
327 /* stupid NSFs claim to be above version 1 >_> */
328 if((!ignoreversion
) && (hdr
.nVersion
!= 1)) return -1;
331 * NESM is generally easier to work with (but limited!)
332 * just move the data over from NESM_HEADER over to our member data
336 nIsPal
= hdr
.nNTSC_PAL
& 0x03;
337 nPAL_PlaySpeed
= letoh16(hdr
.nSpeedPAL
);
338 nNTSC_PlaySpeed
= letoh16(hdr
.nSpeedNTSC
);
339 nfileLoadAddress
= letoh16(hdr
.nLoadAddress
);
340 nfileInitAddress
= letoh16(hdr
.nInitAddress
);
341 nfilePlayAddress
= letoh16(hdr
.nPlayAddress
);
342 nChipExtensions
= hdr
.nExtraChip
;
345 nTrackCount
= hdr
.nTrackCount
;
346 nInitialTrack
= hdr
.nInitialTrack
- 1;
348 memcpy(nBankswitch
,hdr
.nBankSwitch
,8);
350 memcpy(szGameTitle
,hdr
.szGameTitle
,32);
351 memcpy(szArtist
,hdr
.szArtist
,32);
352 memcpy(szCopyright
,hdr
.szCopyright
,32);
354 /* read the NSF data */
357 pDataBuffer
=inbuffer
+0x80;
358 nDataBufferSize
=size
-0x80;
361 /* if we got this far... it was a successful read */
365 int32_t LoadFile_NSFE(uint8_t* inbuffer
, size_t size
)
367 /* the vars we'll be using */
372 uint8_t * nDataPos
= 0;
373 uint8_t bInfoFound
= 0;
374 uint8_t bEndFound
= 0;
375 uint8_t bBankFound
= 0;
378 struct NSFE_INFOCHUNK info
;
379 ZEROMEMORY(&info
,sizeof(struct NSFE_INFOCHUNK
));
380 ZEROMEMORY(nBankswitch
,8);
381 info
.nTrackCount
= 1; /* default values */
383 if (size
< 8) return -1; /* must have at least NSFE,NEND */
385 /* confirm the header! */
386 memcpy(&nChunkType
,inbuffer
,4);
388 if(memcmp(&nChunkType
,"NSFE",4)) return -1;
390 for (i
=0;i
<256;i
++) {
395 /* begin reading chunks */
398 memcpy(&nChunkSize
,inbuffer
,4);
399 nChunkSize
=letoh32(nChunkSize
);
401 memcpy(&nChunkType
,inbuffer
,4);
404 if(!memcmp(&nChunkType
,"INFO",4)) {
405 /* only one info chunk permitted */
406 if(bInfoFound
) return -1;
407 if(nChunkSize
< 8) return -1; /* minimum size */
410 nChunkUsed
= MIN((int32_t)sizeof(struct NSFE_INFOCHUNK
),
413 memcpy(&info
,inbuffer
,nChunkUsed
);
414 inbuffer
+=nChunkSize
;
417 nIsPal
= info
.nIsPal
& 3;
418 nfileLoadAddress
= letoh16(info
.nLoadAddress
);
419 nfileInitAddress
= letoh16(info
.nInitAddress
);
420 nfilePlayAddress
= letoh16(info
.nPlayAddress
);
421 nChipExtensions
= info
.nExt
;
422 nTrackCount
= info
.nTrackCount
;
423 nInitialTrack
= info
.nStartingTrack
;
425 nPAL_PlaySpeed
= (uint16_t)(1000000 / PAL_NMIRATE
);
426 nNTSC_PlaySpeed
= (uint16_t)(1000000 / NTSC_NMIRATE
);
427 } else if (!memcmp(&nChunkType
,"DATA",4)) {
428 if(!bInfoFound
) return -1;
429 if(nDataPos
) return -1;
430 if(nChunkSize
< 1) return -1;
432 nDataBufferSize
= nChunkSize
;
435 inbuffer
+=nChunkSize
;
436 } else if (!memcmp(&nChunkType
,"NEND",4)) {
438 } else if (!memcmp(&nChunkType
,"time",4)) {
439 if(!bInfoFound
) return -1;
440 for (nChunkUsed
=0; nChunkUsed
< MIN(nChunkSize
/ 4,nTrackCount
);
441 nChunkUsed
++,inbuffer
+=4) {
442 nTrackTime
[nChunkUsed
]=
443 ((uint32_t)inbuffer
[0])|
444 ((uint32_t)inbuffer
[1]<<8)|
445 ((uint32_t)inbuffer
[2]<<16)|
446 ((uint32_t)inbuffer
[3]<<24);
449 inbuffer
+=nChunkSize
-(nChunkUsed
*4);
451 /* negative signals to use default time */
452 for(; nChunkUsed
< nTrackCount
; nChunkUsed
++)
453 nTrackTime
[nChunkUsed
] = -1;
454 } else if (!memcmp(&nChunkType
,"fade",4)) {
455 if(!bInfoFound
) return -1;
456 for (nChunkUsed
=0; nChunkUsed
< MIN(nChunkSize
/ 4,nTrackCount
);
457 nChunkUsed
++,inbuffer
+=4) {
458 nTrackFade
[nChunkUsed
]=
459 ((uint32_t)inbuffer
[0])|
460 ((uint32_t)inbuffer
[1]<<8)|
461 ((uint32_t)inbuffer
[2]<<16)|
462 ((uint32_t)inbuffer
[3]<<24);
465 inbuffer
+=nChunkSize
-(nChunkUsed
*4);
467 /* negative signals to use default time */
468 for(; nChunkUsed
< nTrackCount
; nChunkUsed
++)
469 nTrackFade
[nChunkUsed
] = -1;
470 } else if (!memcmp(&nChunkType
,"BANK",4)) {
471 if(bBankFound
) return -1;
474 nChunkUsed
= MIN(8,nChunkSize
);
475 memcpy(nBankswitch
,inbuffer
,nChunkUsed
);
477 inbuffer
+=nChunkSize
;
478 } else if (!memcmp(&nChunkType
,"plst",4)) {
480 nPlaylistSize
= nChunkSize
;
481 if(nPlaylistSize
>= 1) {
483 memcpy(nPlaylist
,inbuffer
,nChunkSize
);
484 inbuffer
+=nChunkSize
;
486 } else if (!memcmp(&nChunkType
,"auth",4)) {
491 uint8_t* ar
[4] = {szGameTitle
,szArtist
,szCopyright
,szRipper
};
493 for(i
= 0; (ptr
-inbuffer
)<nChunkSize
&& i
< 4; i
++)
495 nChunkUsed
= strlen(ptr
) + 1;
496 memcpy(ar
[i
],ptr
,nChunkUsed
);
499 inbuffer
+=nChunkSize
;
500 } else if (!memcmp(&nChunkType
,"tlbl",4)) {
501 /* we unfortunately can't use these anyway */
502 inbuffer
+=nChunkSize
;
503 } else { /* unknown chunk */
504 nChunkType
= letoh32(nChunkType
)>>24; /* check the first byte */
505 /* chunk is vital... don't continue */
506 if((nChunkType
>= 'A') && (nChunkType
<= 'Z'))
508 /* otherwise, just skip it */
509 inbuffer
+=nChunkSize
;
510 } /* end if series */
514 * if we exited the while loop without a 'return', we must have hit an NEND
515 * chunk if this is the case, the file was layed out as it was expected.
516 * now.. make sure we found both an info chunk, AND a data chunk... since
517 * these are minimum requirements for a valid NSFE file
520 if(!bInfoFound
) return -1;
521 if(!nDataPos
) return -1;
523 /* if both those chunks existed, this file is valid.
524 Load the data if it's needed */
526 pDataBuffer
=nDataPos
;
528 /* return success! */
533 /****************** Audio Device Structures ******************/
538 uint8_t bEnvelopeEnable
;
539 uint8_t nEnvelopeSpeed
;
541 /* Volume Envelope */
542 uint8_t nVolEnv_Mode
;
543 uint8_t nVolEnv_Decay
;
544 uint8_t nVolEnv_Gain
;
545 int32_t nVolEnv_Timer
;
546 int32_t nVolEnv_Count
;
550 /* Sweep Envenlope */
552 uint8_t nSweep_Decay
;
553 int32_t nSweep_Timer
;
554 int32_t nSweep_Count
;
556 uint8_t bSweepEnv_On
;
558 /* Effector / LFO / Modulation Unit */
560 uint8_t bLFO_Enabled
;
561 union TWIN nLFO_Freq
;
562 /*float fLFO_Timer;*/
563 /*float fLFO_Count;*/
564 int32_t nLFO_Timer
; /* -17.14*/
565 int32_t nLFO_Count
; /* -17.14*/
567 uint8_t nLFO_Table
[0x40];
574 /*float fFreqCount;*/
575 int32_t nFreqCount
; /* -17.14 */
577 uint8_t nWaveTable
[0x40];
581 /* Output and Downsampling */
590 int16_t FDS_nOutputTable_L
[4][0x21][0x40];
594 /* Frequency Control */
595 union TWIN nFreqTimer
;
598 /* Channel Disabling */
599 uint8_t bChannelEnabled
;
607 /* Output and Downsampling */
611 int16_t FME07_nOutputTable_L
[0x10] IDATA_ATTR
;
615 /* All Channel Stuff */
617 uint8_t nActiveChannels
;
618 uint8_t bAutoIncrement
;
619 uint8_t nCurrentAddress
;
620 uint8_t nRAM
[0x100]; /* internal memory for registers/wave data */
621 int32_t nFrequencyLookupTable
[8]; /* lookup tbl for freq conversions */
624 * Individual channel stuff
626 /* Wavelength / Frequency */
627 union QUAD nFreqReg
[8];
628 int32_t nFreqTimer
[8];
629 int32_t nFreqCount
[8];
631 /* Wave data length / remaining */
632 uint8_t nWaveSize
[8];
633 uint8_t nWaveRemaining
[8];
635 /* Wave data position */
636 uint8_t nWavePosStart
[8];
644 uint8_t nPreVolume
[8];
645 uint8_t nPopCheck
[8];
651 int16_t N106_nOutputTable_L
[0x10][0x10];
656 /* Frequency Control */
657 union TWIN nFreqTimer
;
661 uint8_t bChannelEnabled
;
671 /* Output and Downsampling */
676 int16_t VRC6Pulse_nOutputTable_L
[0x10] IDATA_ATTR
;
681 /* Frequency Control */
682 union TWIN nFreqTimer
;
686 uint8_t bChannelEnabled
;
688 /* Phase Accumulator */
693 /* Output and Downsampling */
698 int16_t VRC6Saw_nOutputTable_L
[0x20] IDATA_ATTR
;
703 /* Programmable Timer */
704 union TWIN nFreqTimer
[2];
705 int32_t nFreqCount
[2];
708 uint8_t nLengthCount
[2];
709 uint8_t bLengthEnabled
[2];
710 uint8_t bChannelEnabled
[2];
714 uint8_t nDecayVolume
[2];
715 uint8_t bDecayEnable
[2];
716 uint8_t bDecayLoop
[2];
717 uint8_t nDecayTimer
[2];
718 uint8_t nDecayCount
[2];
721 uint8_t bSweepEnable
[2];
722 uint8_t bSweepMode
[2];
723 uint8_t bSweepForceSilence
[2];
724 uint8_t nSweepTimer
[2];
725 uint8_t nSweepCount
[2];
726 uint8_t nSweepShift
[2];
729 uint8_t nDutyCount
[2];
730 uint8_t nDutyCycle
[2];
732 /* Output and Downsampling */
736 int16_t Squares_nOutputTable_L
[0x10][0x10] IDATA_ATTR
;
745 /* Programmable Timer */
746 union TWIN nTriFreqTimer
;
747 int32_t nTriFreqCount
;
750 uint8_t nTriLengthCount
;
751 uint8_t bTriLengthEnabled
;
752 uint8_t bTriChannelEnabled
;
755 uint8_t nTriLinearCount
;
756 uint8_t nTriLinearLoad
;
757 uint8_t bTriLinearHalt
;
758 uint8_t bTriLinearControl
;
760 /* Tri-Step Generator / Output */
768 /* Programmable Timer */
769 uint16_t nNoiseFreqTimer
;
770 int32_t nNoiseFreqCount
;
773 uint8_t nNoiseLengthCount
;
774 uint8_t bNoiseLengthEnabled
;
775 uint8_t bNoiseChannelEnabled
;
778 uint8_t nNoiseVolume
;
779 uint8_t nNoiseDecayVolume
;
780 uint8_t bNoiseDecayEnable
;
781 uint8_t bNoiseDecayLoop
;
782 uint8_t nNoiseDecayTimer
;
783 uint8_t nNoiseDecayCount
;
785 /* Random Number Generator */
786 uint16_t nNoiseRandomShift
;
787 uint8_t bNoiseRandomMode
; /* 1 = 32k, 6 = 93-bit */
788 uint8_t bNoiseRandomOut
;
796 uint8_t bDMCIRQEnabled
;
797 uint8_t bDMCIRQPending
;
800 uint8_t nDMCDMABank_Load
;
801 uint16_t nDMCDMAAddr_Load
;
803 uint16_t nDMCDMAAddr
;
804 uint8_t* pDMCDMAPtr
[8];
808 uint16_t nDMCBytesRemaining
;
810 uint8_t nDMCDeltaBit
;
811 uint8_t bDMCDeltaSilent
;
812 uint8_t nDMCSampleBuffer
;
813 uint8_t bDMCSampleBufferEmpty
;
816 uint16_t nDMCFreqTimer
;
817 int32_t nDMCFreqCount
;
827 struct Wave_Squares mWave_Squares IDATA_ATTR
; /* Square channels 1 and 2 */
828 struct Wave_TND mWave_TND IDATA_ATTR
; /* Triangle/Noise/DMC channels */
829 struct VRC6PulseWave mWave_VRC6Pulse
[2] IDATA_ATTR
;
830 struct VRC6SawWave mWave_VRC6Saw IDATA_ATTR
;
831 struct N106Wave mWave_N106 IDATA_ATTR
;
832 struct FDSWave mWave_FDS IDATA_ATTR
;
833 struct FME07Wave mWave_FME07
[3] IDATA_ATTR
; /* FME-07's 3 pulse channels */
836 /****************** MMC5 ******************/
837 /* will include MMC5 sound channels some day,
838 currently only multiply is supported */
840 /****************** N106 (Disch loves this chip) ******************/
842 #ifdef ICODE_INSTEAD_OF_INLINE
843 void Wave_N106_DoTicks(const int32_t ticks
) ICODE_ATTR
;
844 void Wave_N106_DoTicks(const int32_t ticks
)
846 inline void Wave_N106_DoTicks(const int32_t ticks
);
847 inline void Wave_N106_DoTicks(const int32_t ticks
)
852 for(i
= (7 - mWave_N106
.nActiveChannels
); i
< 8; i
++)
854 if(!mWave_N106
.nFreqReg
[i
].D
)
856 /* written frequency of zero will cause divide by zero error
857 makes me wonder if the formula was supposed to be Reg+1 */
858 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
863 mWave_N106
.nMixL
[i
] =
864 N106_nOutputTable_L
[mWave_N106
.nVolume
[i
]]
865 [mWave_N106
.nOutput
[i
]];
867 if(mWave_N106
.nFreqTimer
[i
] < 0)
868 mWave_N106
.nFreqTimer
[i
] =
869 (mWave_N106
.nFrequencyLookupTable
[mWave_N106
.nActiveChannels
] /
870 mWave_N106
.nFreqReg
[i
].D
);
871 if(mWave_N106
.nFreqCount
[i
] > mWave_N106
.nFreqTimer
[i
])
872 mWave_N106
.nFreqCount
[i
] = mWave_N106
.nFreqTimer
[i
];
874 mWave_N106
.nFreqCount
[i
] -= ticks
<< 8;
875 while(mWave_N106
.nFreqCount
[i
] <= 0)
877 mWave_N106
.nFreqCount
[i
] += mWave_N106
.nFreqTimer
[i
];
878 if(mWave_N106
.nWaveRemaining
[i
])
880 mWave_N106
.nWaveRemaining
[i
]--;
881 mWave_N106
.nWavePos
[i
]++;
883 if(!mWave_N106
.nWaveRemaining
[i
])
885 mWave_N106
.nWaveRemaining
[i
] = mWave_N106
.nWaveSize
[i
];
886 mWave_N106
.nWavePos
[i
] = mWave_N106
.nWavePosStart
[i
];
887 if(mWave_N106
.nVolume
[i
] != mWave_N106
.nPreVolume
[i
])
889 if(++mWave_N106
.nPopCheck
[i
] >= 2)
891 mWave_N106
.nPopCheck
[i
] = 0;
892 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
897 mWave_N106
.nOutput
[i
] =
898 mWave_N106
.nRAM
[mWave_N106
.nWavePos
[i
]];
900 if(!mWave_N106
.nOutput
[i
])
902 mWave_N106
.nPopCheck
[i
] = 0;
903 mWave_N106
.nVolume
[i
] = mWave_N106
.nPreVolume
[i
];
910 /****************** VRC6 ******************/
912 #ifdef ICODE_INSTEAD_OF_INLINE
913 void Wave_VRC6_DoTicks(const int32_t ticks
) ICODE_ATTR
;
914 void Wave_VRC6_DoTicks(const int32_t ticks
)
916 inline void Wave_VRC6_DoTicks(const int32_t ticks
);
917 inline void Wave_VRC6_DoTicks(const int32_t ticks
)
922 for(i
= 0; i
< 2; i
++) {
924 if(mWave_VRC6Pulse
[i
].bChannelEnabled
) {
926 mWave_VRC6Pulse
[i
].nFreqCount
-= ticks
;
928 if(mWave_VRC6Pulse
[i
].nDutyCount
<=
929 mWave_VRC6Pulse
[i
].nDutyCycle
)
931 mWave_VRC6Pulse
[i
].nMixL
=
932 VRC6Pulse_nOutputTable_L
[mWave_VRC6Pulse
[i
].nVolume
];
935 mWave_VRC6Pulse
[i
].nMixL
= 0;
937 while(mWave_VRC6Pulse
[i
].nFreqCount
<= 0) {
938 mWave_VRC6Pulse
[i
].nFreqCount
+=
939 mWave_VRC6Pulse
[i
].nFreqTimer
.W
+ 1;
941 if(!mWave_VRC6Pulse
[i
].bDigitized
)
942 mWave_VRC6Pulse
[i
].nDutyCount
=
943 (mWave_VRC6Pulse
[i
].nDutyCount
+ 1) & 0x0F;
948 if(mWave_VRC6Saw
.bChannelEnabled
) {
950 mWave_VRC6Saw
.nFreqCount
-= ticks
;
952 mWave_VRC6Saw
.nMixL
=
953 VRC6Saw_nOutputTable_L
[mWave_VRC6Saw
.nAccum
>> 3];
955 while(mWave_VRC6Saw
.nFreqCount
<= 0) {
957 mWave_VRC6Saw
.nFreqCount
+= mWave_VRC6Saw
.nFreqTimer
.W
+ 1;
959 mWave_VRC6Saw
.nAccumStep
++;
960 if(mWave_VRC6Saw
.nAccumStep
== 14)
962 mWave_VRC6Saw
.nAccumStep
= 0;
963 mWave_VRC6Saw
.nAccum
= 0;
965 else if(!(mWave_VRC6Saw
.nAccumStep
& 1))
966 mWave_VRC6Saw
.nAccum
+= mWave_VRC6Saw
.nAccumRate
;
971 /****************** Square waves ******************/
974 #ifdef ICODE_INSTEAD_OF_INLINE
975 void Wave_Squares_ClockMajor(void) ICODE_ATTR
;
976 void Wave_Squares_ClockMajor()
978 inline void Wave_Squares_ClockMajor(void);
979 inline void Wave_Squares_ClockMajor()
982 if(mWave_Squares
.nDecayCount
[0])
983 mWave_Squares
.nDecayCount
[0]--;
986 mWave_Squares
.nDecayCount
[0] = mWave_Squares
.nDecayTimer
[0];
987 if(mWave_Squares
.nDecayVolume
[0])
988 mWave_Squares
.nDecayVolume
[0]--;
991 if(mWave_Squares
.bDecayLoop
[0])
992 mWave_Squares
.nDecayVolume
[0] = 0x0F;
995 if(mWave_Squares
.bDecayEnable
[0])
996 mWave_Squares
.nVolume
[0] = mWave_Squares
.nDecayVolume
[0];
999 if(mWave_Squares
.nDecayCount
[1])
1000 mWave_Squares
.nDecayCount
[1]--;
1003 mWave_Squares
.nDecayCount
[1] = mWave_Squares
.nDecayTimer
[1];
1004 if(mWave_Squares
.nDecayVolume
[1])
1005 mWave_Squares
.nDecayVolume
[1]--;
1008 if(mWave_Squares
.bDecayLoop
[1])
1009 mWave_Squares
.nDecayVolume
[1] = 0x0F;
1012 if(mWave_Squares
.bDecayEnable
[1])
1013 mWave_Squares
.nVolume
[1] = mWave_Squares
.nDecayVolume
[1];
1019 #ifdef ICODE_INSTEAD_OF_INLINE
1020 void Wave_Squares_CheckSweepForcedSilence(const int32_t i
) ICODE_ATTR
;
1021 void Wave_Squares_CheckSweepForcedSilence(const int32_t i
)
1023 inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i
);
1024 inline void Wave_Squares_CheckSweepForcedSilence(const int32_t i
)
1027 if(mWave_Squares
.nFreqTimer
[i
].W
< 8) {
1028 mWave_Squares
.bSweepForceSilence
[i
] = 1; return;
1030 if(!mWave_Squares
.bSweepMode
[i
] &&
1031 (( mWave_Squares
.nFreqTimer
[i
].W
+
1032 (mWave_Squares
.nFreqTimer
[i
].W
>> mWave_Squares
.nSweepShift
[i
]))
1033 >= 0x0800)) { mWave_Squares
.bSweepForceSilence
[i
] = 1; return; }
1035 mWave_Squares
.bSweepForceSilence
[i
] = 0;
1038 /* sweep / length */
1039 #ifdef ICODE_INSTEAD_OF_INLINE
1040 void Wave_Squares_ClockMinor(void) ICODE_ATTR
;
1041 void Wave_Squares_ClockMinor()
1043 inline void Wave_Squares_ClockMinor(void);
1044 inline void Wave_Squares_ClockMinor()
1047 /* unrolled a little loop
1049 for(i = 0; i < 2; i++)
1052 if(mWave_Squares
.bLengthEnabled
[0] && mWave_Squares
.nLengthCount
[0])
1053 mWave_Squares
.nLengthCount
[0]--;
1055 if(!mWave_Squares
.bSweepEnable
[0] || !mWave_Squares
.nLengthCount
[0] ||
1056 mWave_Squares
.bSweepForceSilence
[0] || !mWave_Squares
.nSweepShift
[0])
1059 if(mWave_Squares
.nSweepCount
[0])
1060 mWave_Squares
.nSweepCount
[0]--;
1063 mWave_Squares
.nSweepCount
[0] = mWave_Squares
.nSweepTimer
[0];
1064 if(mWave_Squares
.bSweepMode
[0]) mWave_Squares
.nFreqTimer
[0].W
-=
1065 (mWave_Squares
.nFreqTimer
[0].W
>> mWave_Squares
.nSweepShift
[0])+1;
1066 else mWave_Squares
.nFreqTimer
[0].W
+=
1067 (mWave_Squares
.nFreqTimer
[0].W
>> mWave_Squares
.nSweepShift
[0]);
1069 Wave_Squares_CheckSweepForcedSilence(0);
1074 if(mWave_Squares
.bLengthEnabled
[1] && mWave_Squares
.nLengthCount
[1])
1075 mWave_Squares
.nLengthCount
[1]--;
1077 if(!mWave_Squares
.bSweepEnable
[1] || !mWave_Squares
.nLengthCount
[1] ||
1078 mWave_Squares
.bSweepForceSilence
[1] || !mWave_Squares
.nSweepShift
[1])
1081 if(mWave_Squares
.nSweepCount
[1])
1082 mWave_Squares
.nSweepCount
[1]--;
1085 mWave_Squares
.nSweepCount
[1] = mWave_Squares
.nSweepTimer
[1];
1086 if(mWave_Squares
.bSweepMode
[1]) mWave_Squares
.nFreqTimer
[1].W
-=
1087 (mWave_Squares
.nFreqTimer
[1].W
>> mWave_Squares
.nSweepShift
[1]);
1088 else mWave_Squares
.nFreqTimer
[1].W
+=
1089 (mWave_Squares
.nFreqTimer
[1].W
>> mWave_Squares
.nSweepShift
[1]);
1091 Wave_Squares_CheckSweepForcedSilence(1);
1095 /****************** Triangle/noise/DMC ******************/
1097 /* decay (noise), linear (tri) */
1099 #ifdef ICODE_INSTEAD_OF_INLINE
1100 void Wave_TND_ClockMajor(void) ICODE_ATTR
;
1101 void Wave_TND_ClockMajor()
1103 inline void Wave_TND_ClockMajor(void);
1104 inline void Wave_TND_ClockMajor()
1108 if(mWave_TND
.nNoiseDecayCount
)
1109 mWave_TND
.nNoiseDecayCount
--;
1112 mWave_TND
.nNoiseDecayCount
= mWave_TND
.nNoiseDecayTimer
;
1113 if(mWave_TND
.nNoiseDecayVolume
)
1114 mWave_TND
.nNoiseDecayVolume
--;
1117 if(mWave_TND
.bNoiseDecayLoop
)
1118 mWave_TND
.nNoiseDecayVolume
= 0x0F;
1121 if(mWave_TND
.bNoiseDecayEnable
)
1122 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayVolume
;
1125 /* triangle's linear */
1126 if(mWave_TND
.bTriLinearHalt
)
1127 mWave_TND
.nTriLinearCount
= mWave_TND
.nTriLinearLoad
;
1128 else if(mWave_TND
.nTriLinearCount
)
1129 mWave_TND
.nTriLinearCount
--;
1131 if(!mWave_TND
.bTriLinearControl
)
1132 mWave_TND
.bTriLinearHalt
= 0;
1137 #ifdef ICODE_INSTEAD_OF_INLINE
1138 void Wave_TND_ClockMinor(void) ICODE_ATTR
;
1139 void Wave_TND_ClockMinor()
1141 inline void Wave_TND_ClockMinor(void);
1142 inline void Wave_TND_ClockMinor()
1145 if(mWave_TND
.bNoiseLengthEnabled
&& mWave_TND
.nNoiseLengthCount
)
1146 mWave_TND
.nNoiseLengthCount
--;
1148 if(mWave_TND
.bTriLengthEnabled
&& mWave_TND
.nTriLengthCount
)
1149 mWave_TND
.nTriLengthCount
--;
1154 /****************** NSF Core ******************/
1161 /* RAM: 0x0000 - 0x07FF */
1162 uint8_t pRAM
[0x800] IDATA_ATTR
;
1163 /* SRAM: 0x6000 - 0x7FFF (non-FDS only) */
1164 uint8_t pSRAM
[0x2000];
1165 /* ExRAM: 0x5C00 - 0x5FF5 (MMC5 only)
1166 * Also holds NSF player code (at 0x5000 - 0x500F) */
1167 uint8_t pExRAM
[0x1000];
1168 /* Full ROM buffer */
1169 uint8_t* pROM_Full IDATA_ATTR
;
1171 uint16_t main_nOutputTable_L
[0x8000];
1173 uint8_t* pROM
[10] IDATA_ATTR
;/* ROM banks (point to areas in pROM_Full) */
1174 /* 0x8000 - 0xFFFF */
1175 /* also includes 0x6000 - 0x7FFF (FDS only) */
1176 uint8_t* pStack
; /* the stack (points to areas in pRAM) */
1177 /* 0x0100 - 0x01FF */
1179 int32_t nROMSize
; /* size of this ROM file in bytes */
1180 int32_t nROMBankCount
; /* max number of 4k banks */
1181 int32_t nROMMaxSize
; /* size of allocated pROM_Full buffer */
1184 * Memory Proc Pointers
1187 typedef uint8_t ( *ReadProc
)(uint16_t);
1188 typedef void ( *WriteProc
)(uint16_t,uint8_t);
1189 ReadProc ReadMemory
[0x10] IDATA_ATTR
;
1190 WriteProc WriteMemory
[0x10] IDATA_ATTR
;
1193 * 6502 Registers / Mode
1196 uint8_t regA IDATA_ATTR
; /* Accumulator */
1197 uint8_t regX IDATA_ATTR
; /* X-Index */
1198 uint8_t regY IDATA_ATTR
; /* Y-Index */
1199 uint8_t regP IDATA_ATTR
; /* Processor Status */
1200 uint8_t regSP IDATA_ATTR
; /* Stack Pointer */
1201 uint16_t regPC IDATA_ATTR
; /* Program Counter */
1203 uint8_t bPALMode IDATA_ATTR
;/* 1 if in PAL emulation mode, 0 if in NTSC */
1204 uint8_t bCPUJammed IDATA_ATTR
; /* 0 = not jammed. 1 = really jammed.
1205 * 2 = 'fake' jammed */
1206 /* fake jam caused by the NSF code to signal
1207 * the end of the play/init routine */
1209 /* Multiplication Register, for MMC5 chip only (5205+5206) */
1210 uint8_t nMultIn_Low
;
1211 uint8_t nMultIn_High
;
1214 * NSF Preparation Information
1217 uint8_t nBankswitchInitValues
[10]; /* banks to swap to on tune init */
1218 uint16_t nPlayAddress
; /* Play routine address */
1219 uint16_t nInitAddress
; /* Init routine address */
1221 uint8_t nExternalSound
; /* external sound chips */
1224 float fNSFPlaybackSpeed
;
1230 uint8_t nFrameCounter
; /* Frame Sequence Counter */
1231 uint8_t nFrameCounterMax
; /* Frame Sequence Counter Size
1232 (3 or 4 depending on $4017.7) */
1233 uint8_t bFrameIRQEnabled
; /* TRUE if frame IRQs are enabled */
1234 uint8_t bFrameIRQPending
; /* TRUE if the frame sequencer is holding down
1237 uint8_t nFME07_Address
;
1240 * Timing and Counters
1242 /* fixed point -15.16 */
1244 int32_t nTicksUntilNextFrame
;
1245 int32_t nTicksPerPlay
;
1246 int32_t nTicksUntilNextPlay
;
1247 int32_t nTicksPerSample
;
1248 int32_t nTicksUntilNextSample
;
1250 uint32_t nCPUCycle IDATA_ATTR
;
1251 uint32_t nAPUCycle IDATA_ATTR
;
1254 uint32_t nTotalPlays
; /* number of times the play subroutine has been called
1255 (for tracking output time) */
1259 int32_t nSilentSamples
;
1260 int32_t nSilentSampleMax
;
1261 int32_t nSilenceTrackMS
;
1262 uint8_t bNoSilenceIfTime
;
1263 uint8_t bTimeNotDefault
;
1266 * Sound output options
1268 const int32_t nSampleRate
=44100;
1271 * Volume/fading/filter tracking
1274 uint32_t nStartFade
; /* play call to start fading out */
1275 uint32_t nEndFade
; /* play call to stop fading out (song is over) */
1276 uint8_t bFade
; /* are we fading? */
1281 * Designated Output Buffer
1283 uint8_t* pOutput IDATA_ATTR
;
1285 const uint8_t bDMCPopReducer
=1;
1286 uint8_t nDMCPop_Prev IDATA_ATTR
= 0;
1287 uint8_t bDMCPop_Skip IDATA_ATTR
= 0;
1288 uint8_t bDMCPop_SamePlay IDATA_ATTR
= 0;
1290 const uint8_t nForce4017Write
=0;
1291 const uint8_t bN106PopReducer
=0;
1292 const uint8_t bIgnore4011Writes
=0;
1294 const uint8_t bIgnoreBRK
=0;
1295 const uint8_t bIgnoreIllegalOps
=0;
1296 const uint8_t bNoWaitForReturn
=0;
1297 const uint8_t bPALPreference
=0;
1298 const uint8_t bCleanAXY
=0;
1299 const uint8_t bResetDuty
=0;
1305 int64_t nFilterAccL IDATA_ATTR
;
1306 int64_t nHighPass IDATA_ATTR
;
1308 int32_t nHighPassBase IDATA_ATTR
;
1310 uint8_t bHighPassEnabled IDATA_ATTR
;
1314 #define CLOCK_MAJOR() { Wave_Squares_ClockMajor(); Wave_TND_ClockMajor(); }
1315 #define CLOCK_MINOR() { Wave_Squares_ClockMinor(); Wave_TND_ClockMinor(); }
1317 #define EXTSOUND_VRC6 0x01
1318 #define EXTSOUND_VRC7 0x02
1319 #define EXTSOUND_FDS 0x04
1320 #define EXTSOUND_MMC5 0x08
1321 #define EXTSOUND_N106 0x10
1322 #define EXTSOUND_FME07 0x20
1324 #define SILENCE_THRESHOLD 3
1330 uint32_t Emulate6502(uint32_t runto
) ICODE_ATTR
;
1331 void EmulateAPU(uint8_t bBurnCPUCycles
) ICODE_ATTR
;
1333 int NSFCore_Initialize(void); /* 1 = initialized ok,
1334 0 = couldn't initialize (memory allocation error) */
1339 int LoadNSF(int32_t); /* grab data from an existing file
1340 1 = loaded ok, 0 = error loading */
1345 void SetTrack(uint8_t track
); /* Change tracks */
1350 /* fill a buffer with samples */
1351 int32_t GetSamples(uint8_t* buffer
, int32_t buffersize
);
1356 /* Set desired playback options (0 = bad options couldn't be set) */
1357 int SetPlaybackOptions(int32_t samplerate
);
1358 /* Speed throttling (0 = uses NSF specified speed) */
1359 void SetPlaybackSpeed(float playspersec
);
1361 float GetPlaybackSpeed(void);
1362 float GetMasterVolume(void);
1367 /* gets the number of 'play' routine calls executed */
1368 float GetPlayCalls(void);
1370 /* gets the output time (based on the given play rate,
1371 if basedplayspersec is zero, current playback speed is used */
1372 uint32_t GetWrittenTime(float basedplayspersec
);
1373 /* sets the number of 'plays' routines executed (for precise seeking) */
1374 void SetPlayCalls(float plays
);
1375 /* sets the written time (approx. seeking) */
1376 void SetWrittenTime(uint32_t ms
,float basedplays
);
1382 void StopFade(void); /* stops all fading (plays indefinitely) */
1383 uint8_t SongCompleted(void); /* song has faded out (samples have stopped
1385 /* parameters are play calls */
1386 void SetFade(int32_t fadestart
,int32_t fadestop
,uint8_t bNotDefault
);
1387 void SetFadeTime(uint32_t fadestart
,uint32_t fadestop
,float basedplays
,
1388 uint8_t bNotDefault
); /* parameters are in milliseconds */
1391 * Internal Functions
1393 void RebuildOutputTables(void);
1394 void RecalculateFade(void); /* called when fade status is changed. */
1395 void RecalcFilter(void);
1396 void RecalcSilenceTracker(void);
1398 void WriteMemory_VRC6(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1399 void WriteMemory_MMC5(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1400 void WriteMemory_N106(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1401 void WriteMemory_FME07(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1404 * Memory Read/Write routines
1407 uint8_t ReadMemory_RAM(uint16_t a
) ICODE_ATTR
;
1408 uint8_t ReadMemory_ExRAM(uint16_t a
) ICODE_ATTR
;
1409 uint8_t ReadMemory_SRAM(uint16_t a
) ICODE_ATTR
;
1410 uint8_t ReadMemory_pAPU(uint16_t a
) ICODE_ATTR
;
1411 uint8_t ReadMemory_ROM(uint16_t a
) ICODE_ATTR
;
1412 uint8_t ReadMemory_Default(uint16_t a
) ICODE_ATTR
;
1414 uint8_t ReadMemory_N106(uint16_t a
) ICODE_ATTR
;
1416 void WriteMemory_RAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1417 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1418 void WriteMemory_SRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1419 void WriteMemory_pAPU(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1420 void WriteMemory_FDSRAM(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1421 void WriteMemory_Default(uint16_t a
,uint8_t v
) ICODE_ATTR
;
1423 uint8_t ReadMemory_RAM(uint16_t a
) { return pRAM
[a
& 0x07FF]; }
1424 uint8_t ReadMemory_ExRAM(uint16_t a
) { return pExRAM
[a
& 0x0FFF]; }
1425 uint8_t ReadMemory_SRAM(uint16_t a
) { return pSRAM
[a
& 0x1FFF]; }
1426 uint8_t ReadMemory_ROM(uint16_t a
)
1427 { return pROM
[(a
>> 12) - 6][a
& 0x0FFF]; }
1428 uint8_t ReadMemory_Default(uint16_t a
) { return (a
>> 8); }
1430 void WriteMemory_RAM(uint16_t a
,uint8_t v
)
1431 { pRAM
[a
& 0x07FF] = v
; }
1432 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
);
1433 void WriteMemory_SRAM(uint16_t a
,uint8_t v
)
1434 { pSRAM
[a
& 0x1FFF] = v
; }
1435 void WriteMemory_FDSRAM(uint16_t a
,uint8_t v
)
1436 { pROM
[(a
>> 12) - 6][a
& 0x0FFF] = v
; }
1437 void WriteMemory_Default(uint16_t a
,uint8_t v
) { (void)a
; (void)v
; }
1440 /* Read Memory Procs */
1442 uint8_t ReadMemory_pAPU(uint16_t a
)
1449 if(mWave_Squares
.nLengthCount
[0]) ret
|= 0x01;
1450 if(mWave_Squares
.nLengthCount
[1]) ret
|= 0x02;
1451 if(mWave_TND
.nTriLengthCount
) ret
|= 0x04;
1452 if(mWave_TND
.nNoiseLengthCount
) ret
|= 0x08;
1453 if(mWave_TND
.nDMCBytesRemaining
) ret
|= 0x10;
1455 if(bFrameIRQPending
) ret
|= 0x40;
1456 if(mWave_TND
.bDMCIRQPending
) ret
|= 0x80;
1458 bFrameIRQPending
= 0;
1462 if(!(nExternalSound
& EXTSOUND_FDS
)) return 0x40;
1463 if(bPALMode
) return 0x40;
1465 if((a
>= 0x4040) && (a
<= 0x407F))
1466 return mWave_FDS
.nWaveTable
[a
& 0x3F] | 0x40;
1468 return (mWave_FDS
.nVolEnv_Gain
& 0x3F) | 0x40;
1470 return (mWave_FDS
.nSweep_Gain
& 0x3F) | 0x40;
1475 uint8_t ReadMemory_N106(uint16_t a
)
1478 return ReadMemory_pAPU(a
);
1480 uint8_t ret
= mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1)] |
1481 (mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1) + 1] << 4);
1482 if(mWave_N106
.bAutoIncrement
)
1483 mWave_N106
.nCurrentAddress
= (mWave_N106
.nCurrentAddress
+ 1) & 0x7F;
1489 /* Write Memory Procs */
1491 void WriteMemory_ExRAM(uint16_t a
,uint8_t v
)
1493 if(a
< 0x5FF6) /* Invalid */
1498 /* Swap out banks */
1501 /* stop it from swapping to a bank that doesn't exist */
1502 if(v
>= nROMBankCount
)
1505 pROM
[a
] = pROM_Full
+ (v
<< 12);
1507 /* Update the DMC's DMA pointer, as well */
1509 mWave_TND
.pDMCDMAPtr
[a
- 2] = pROM
[a
];
1512 void WriteMemory_pAPU(uint16_t a
,uint8_t v
)
1519 mWave_Squares
.nDutyCycle
[0] = DUTY_CYCLE_TABLE
[v
>> 6];
1520 mWave_Squares
.bLengthEnabled
[0] =
1521 !(mWave_Squares
.bDecayLoop
[0] = (v
& 0x20));
1522 mWave_Squares
.bDecayEnable
[0] = !(v
& 0x10);
1523 mWave_Squares
.nDecayTimer
[0] = (v
& 0x0F);
1525 if(!mWave_Squares
.bDecayEnable
[0])
1526 mWave_Squares
.nVolume
[0] = mWave_Squares
.nDecayTimer
[0];
1530 mWave_Squares
.bSweepEnable
[0] = (v
& 0x80);
1531 mWave_Squares
.nSweepTimer
[0] = (v
& 0x70) >> 4;
1532 mWave_Squares
.bSweepMode
[0] = v
& 0x08;
1533 mWave_Squares
.nSweepShift
[0] = v
& 0x07;
1534 Wave_Squares_CheckSweepForcedSilence(0);
1538 mWave_Squares
.nFreqTimer
[0].B
.l
= v
;
1539 Wave_Squares_CheckSweepForcedSilence(0);
1543 mWave_Squares
.nFreqTimer
[0].B
.h
= v
& 0x07;
1544 Wave_Squares_CheckSweepForcedSilence(0);
1546 mWave_Squares
.nDecayVolume
[0] = 0x0F;
1548 if(mWave_Squares
.bChannelEnabled
[0])
1549 mWave_Squares
.nLengthCount
[0] = LENGTH_COUNTER_TABLE
[v
>> 3];
1552 mWave_Squares
.nDutyCount
[0] = 0;
1558 mWave_Squares
.nDutyCycle
[1] = DUTY_CYCLE_TABLE
[v
>> 6];
1559 mWave_Squares
.bLengthEnabled
[1] =
1560 !(mWave_Squares
.bDecayLoop
[1] = (v
& 0x20));
1561 mWave_Squares
.bDecayEnable
[1] = !(v
& 0x10);
1562 mWave_Squares
.nDecayTimer
[1] = (v
& 0x0F);
1564 if(!mWave_Squares
.bDecayEnable
[1])
1565 mWave_Squares
.nVolume
[1] = mWave_Squares
.nDecayTimer
[1];
1569 mWave_Squares
.bSweepEnable
[1] = (v
& 0x80);
1570 mWave_Squares
.nSweepTimer
[1] = (v
& 0x70) >> 4;
1571 mWave_Squares
.bSweepMode
[1] = v
& 0x08;
1572 mWave_Squares
.nSweepShift
[1] = v
& 0x07;
1573 Wave_Squares_CheckSweepForcedSilence(1);
1577 mWave_Squares
.nFreqTimer
[1].B
.l
= v
;
1578 Wave_Squares_CheckSweepForcedSilence(1);
1582 mWave_Squares
.nFreqTimer
[1].B
.h
= v
& 0x07;
1583 Wave_Squares_CheckSweepForcedSilence(1);
1585 mWave_Squares
.nDecayVolume
[1] = 0x0F;
1587 if(mWave_Squares
.bChannelEnabled
[1])
1588 mWave_Squares
.nLengthCount
[1] = LENGTH_COUNTER_TABLE
[v
>> 3];
1591 mWave_Squares
.nDutyCount
[1] = 0;
1597 mWave_TND
.nTriLinearLoad
= v
& 0x7F;
1598 mWave_TND
.bTriLinearControl
= v
& 0x80;
1599 mWave_TND
.bTriLengthEnabled
= !(v
& 0x80);
1603 mWave_TND
.nTriFreqTimer
.B
.l
= v
;
1607 mWave_TND
.nTriFreqTimer
.B
.h
= v
& 0x07;
1608 mWave_TND
.bTriLinearHalt
= 1;
1610 if(mWave_TND
.bTriChannelEnabled
)
1611 mWave_TND
.nTriLengthCount
= LENGTH_COUNTER_TABLE
[v
>> 3];
1616 mWave_TND
.bNoiseLengthEnabled
=
1617 !(mWave_TND
.bNoiseDecayLoop
= (v
& 0x20));
1618 mWave_TND
.bNoiseDecayEnable
= !(v
& 0x10);
1619 mWave_TND
.nNoiseDecayTimer
= (v
& 0x0F);
1621 if(mWave_TND
.bNoiseDecayEnable
)
1622 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayVolume
;
1624 mWave_TND
.nNoiseVolume
= mWave_TND
.nNoiseDecayTimer
;
1628 mWave_TND
.nNoiseFreqTimer
= NOISE_FREQ_TABLE
[v
& 0x0F];
1629 mWave_TND
.bNoiseRandomMode
= (v
& 0x80) ? 6 : 1;
1633 if(mWave_TND
.bNoiseChannelEnabled
)
1634 mWave_TND
.nNoiseLengthCount
= LENGTH_COUNTER_TABLE
[v
>> 3];
1636 mWave_TND
.nNoiseDecayVolume
= 0x0F;
1637 if(mWave_TND
.bNoiseDecayEnable
)
1638 mWave_TND
.nNoiseVolume
= 0x0F;
1643 mWave_TND
.bDMCLoop
= v
& 0x40;
1644 mWave_TND
.bDMCIRQEnabled
= v
& 0x80;
1645 /* IRQ can't be pending if disabled */
1646 if(!mWave_TND
.bDMCIRQEnabled
)
1647 mWave_TND
.bDMCIRQPending
= 0;
1649 mWave_TND
.nDMCFreqTimer
= DMC_FREQ_TABLE
[bPALMode
][v
& 0x0F];
1653 if(bIgnore4011Writes
)
1658 if(bDMCPop_SamePlay
)
1659 mWave_TND
.nDMCOutput
= v
;
1667 if(nDMCPop_Prev
== v
) break;
1668 if(mWave_TND
.nDMCOutput
== v
) break;
1669 mWave_TND
.nDMCOutput
= nDMCPop_Prev
;
1671 bDMCPop_SamePlay
= 1;
1675 mWave_TND
.nDMCOutput
= v
;
1679 mWave_TND
.nDMCDMABank_Load
= (v
>> 6) | 0x04;
1680 mWave_TND
.nDMCDMAAddr_Load
= (v
<< 6) & 0x0FFF;
1684 mWave_TND
.nDMCLength
= (v
<< 4) + 1;
1687 /* All / General Purpose */
1689 mWave_TND
.bDMCIRQPending
= 0;
1691 if(v
& 0x01){ mWave_Squares
.bChannelEnabled
[0] = 1; }
1692 else { mWave_Squares
.bChannelEnabled
[0] =
1693 mWave_Squares
.nLengthCount
[0] = 0; }
1694 if(v
& 0x02){ mWave_Squares
.bChannelEnabled
[1] = 1; }
1695 else { mWave_Squares
.bChannelEnabled
[1] =
1696 mWave_Squares
.nLengthCount
[1] = 0; }
1697 if(v
& 0x04){ mWave_TND
.bTriChannelEnabled
= 1; }
1698 else { mWave_TND
.bTriChannelEnabled
=
1699 mWave_TND
.nTriLengthCount
= 0; }
1700 if(v
& 0x08){ mWave_TND
.bNoiseChannelEnabled
= 1; }
1701 else { mWave_TND
.bNoiseChannelEnabled
=
1702 mWave_TND
.nNoiseLengthCount
= 0; }
1706 if(!mWave_TND
.nDMCBytesRemaining
)
1709 mWave_TND
.nDMCDMAAddr
= mWave_TND
.nDMCDMAAddr_Load
;
1710 mWave_TND
.nDMCDMABank
= mWave_TND
.nDMCDMABank_Load
;
1711 mWave_TND
.nDMCBytesRemaining
= mWave_TND
.nDMCLength
;
1712 mWave_TND
.bDMCActive
= 1;
1716 mWave_TND
.nDMCBytesRemaining
= 0;
1720 bFrameIRQEnabled
= !(v
& 0x40);
1721 bFrameIRQPending
= 0;
1723 nFrameCounterMax
= (v
& 0x80) ? 4 : 3;
1724 nTicksUntilNextFrame
=
1725 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
)
1729 if(v
& 0x80) CLOCK_MINOR();
1733 if(!(nExternalSound
& EXTSOUND_FDS
)) return;
1734 if(bPALMode
) return;
1736 /* FDS Sound registers */
1738 if(a
< 0x4040) return;
1743 if(mWave_FDS
.bWaveWrite
)
1744 mWave_FDS
.nWaveTable
[a
- 0x4040] = v
;
1751 mWave_FDS
.nVolEnv_Mode
= (v
>> 6);
1754 mWave_FDS
.nVolEnv_Gain
= v
& 0x3F;
1755 if(!mWave_FDS
.nMainAddr
)
1757 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
1758 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
1759 else mWave_FDS
.nVolume
= 0x20;
1762 mWave_FDS
.nVolEnv_Decay
= v
& 0x3F;
1763 mWave_FDS
.nVolEnv_Timer
=
1764 ((mWave_FDS
.nVolEnv_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
1766 mWave_FDS
.bVolEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1767 mWave_FDS
.nEnvelopeSpeed
&& !(v
& 0x80);
1771 mWave_FDS
.nFreq
.B
.l
= v
;
1772 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1773 !mWave_FDS
.bWaveWrite
;
1777 mWave_FDS
.bEnabled
= !(v
& 0x80);
1778 mWave_FDS
.bEnvelopeEnable
= !(v
& 0x40);
1781 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
1782 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
1783 else mWave_FDS
.nVolume
= 0x20;
1785 mWave_FDS
.nFreq
.B
.h
= v
& 0x0F;
1786 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1787 !mWave_FDS
.bWaveWrite
;
1789 mWave_FDS
.bVolEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1790 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nVolEnv_Mode
& 2);
1791 mWave_FDS
.bSweepEnv_On
= mWave_FDS
.bEnvelopeEnable
&&
1792 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nSweep_Mode
& 2);
1797 mWave_FDS
.nSweep_Mode
= v
>> 6;
1799 mWave_FDS
.nSweep_Gain
= v
& 0x3F;
1800 mWave_FDS
.nSweep_Decay
= v
& 0x3F;
1801 mWave_FDS
.nSweep_Timer
=
1802 ((mWave_FDS
.nSweep_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
1803 mWave_FDS
.bSweepEnv_On
=
1804 mWave_FDS
.bEnvelopeEnable
&& mWave_FDS
.nEnvelopeSpeed
&&
1810 if(v
& 0x40) mWave_FDS
.nSweepBias
= (v
& 0x3F) - 0x40;
1811 else mWave_FDS
.nSweepBias
= v
& 0x3F;
1812 mWave_FDS
.nLFO_Addr
= 0;
1817 mWave_FDS
.nLFO_Freq
.B
.l
= v
;
1819 mWave_FDS
.bLFO_Enabled
&& mWave_FDS
.nLFO_Freq
.W
;
1820 if(mWave_FDS
.nLFO_Freq
.W
)
1821 mWave_FDS
.nLFO_Timer
= (0x10000<<14) / mWave_FDS
.nLFO_Freq
.W
;
1825 mWave_FDS
.bLFO_Enabled
= !(v
& 0x80);
1826 mWave_FDS
.nLFO_Freq
.B
.h
= v
& 0x0F;
1828 mWave_FDS
.bLFO_Enabled
&& mWave_FDS
.nLFO_Freq
.W
;
1829 if(mWave_FDS
.nLFO_Freq
.W
)
1830 mWave_FDS
.nLFO_Timer
= (0x10000<<14) / mWave_FDS
.nLFO_Freq
.W
;
1834 if(mWave_FDS
.bLFO_Enabled
) break;
1836 for(i
= 0; i
< 62; i
++)
1837 mWave_FDS
.nLFO_Table
[i
] = mWave_FDS
.nLFO_Table
[i
+ 2];
1838 mWave_FDS
.nLFO_Table
[62] = mWave_FDS
.nLFO_Table
[63] = v
& 7;
1842 mWave_FDS
.nMainVolume
= v
& 3;
1843 mWave_FDS
.bWaveWrite
= v
& 0x80;
1844 mWave_FDS
.bMain_On
= mWave_FDS
.nFreq
.W
&& mWave_FDS
.bEnabled
&&
1845 !mWave_FDS
.bWaveWrite
;
1849 mWave_FDS
.nEnvelopeSpeed
= v
;
1850 mWave_FDS
.bVolEnv_On
=
1851 mWave_FDS
.bEnvelopeEnable
&&
1852 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nVolEnv_Mode
& 2);
1853 mWave_FDS
.bSweepEnv_On
=
1854 mWave_FDS
.bEnvelopeEnable
&&
1855 mWave_FDS
.nEnvelopeSpeed
&& !(mWave_FDS
.nSweep_Mode
& 2);
1861 void WriteMemory_VRC6(uint16_t a
,uint8_t v
)
1865 if((a
< 0xA000) && (nExternalSound
& EXTSOUND_VRC7
)) return;
1866 else if(nExternalSound
& EXTSOUND_FDS
)
1867 WriteMemory_FDSRAM(a
,v
);
1873 mWave_VRC6Pulse
[0].nVolume
= v
& 0x0F;
1874 mWave_VRC6Pulse
[0].nDutyCycle
= (v
>> 4) & 0x07;
1875 mWave_VRC6Pulse
[0].bDigitized
= v
& 0x80;
1876 if(mWave_VRC6Pulse
[0].bDigitized
)
1877 mWave_VRC6Pulse
[0].nDutyCount
= 0;
1881 mWave_VRC6Pulse
[0].nFreqTimer
.B
.l
= v
;
1885 mWave_VRC6Pulse
[0].nFreqTimer
.B
.h
= v
& 0x0F;
1886 mWave_VRC6Pulse
[0].bChannelEnabled
= v
& 0x80;
1892 mWave_VRC6Pulse
[1].nVolume
= v
& 0x0F;
1893 mWave_VRC6Pulse
[1].nDutyCycle
= (v
>> 4) & 0x07;
1894 mWave_VRC6Pulse
[1].bDigitized
= v
& 0x80;
1895 if(mWave_VRC6Pulse
[1].bDigitized
)
1896 mWave_VRC6Pulse
[1].nDutyCount
= 0;
1900 mWave_VRC6Pulse
[1].nFreqTimer
.B
.l
= v
;
1904 mWave_VRC6Pulse
[1].nFreqTimer
.B
.h
= v
& 0x0F;
1905 mWave_VRC6Pulse
[1].bChannelEnabled
= v
& 0x80;
1910 mWave_VRC6Saw
.nAccumRate
= (v
& 0x3F);
1914 mWave_VRC6Saw
.nFreqTimer
.B
.l
= v
;
1918 mWave_VRC6Saw
.nFreqTimer
.B
.h
= v
& 0x0F;
1919 mWave_VRC6Saw
.bChannelEnabled
= v
& 0x80;
1924 void WriteMemory_MMC5(uint16_t a
,uint8_t v
)
1926 if((a
<= 0x5015) && !bPALMode
)
1928 /* no audio emulation */
1941 a
= nMultIn_Low
* nMultIn_High
;
1942 pExRAM
[0x205] = a
& 0xFF;
1943 pExRAM
[0x206] = a
>> 8;
1947 if(a
< 0x5C00) return;
1949 pExRAM
[a
& 0x0FFF] = v
;
1951 WriteMemory_ExRAM(a
,v
);
1954 void WriteMemory_N106(uint16_t a
,uint8_t v
)
1958 WriteMemory_pAPU(a
,v
);
1964 mWave_N106
.nCurrentAddress
= v
& 0x7F;
1965 mWave_N106
.bAutoIncrement
= (v
& 0x80);
1972 mWave_N106
.nRAM
[mWave_N106
.nCurrentAddress
<< 1] = v
& 0x0F;
1973 mWave_N106
.nRAM
[(mWave_N106
.nCurrentAddress
<< 1) + 1] = v
>> 4;
1974 a
= mWave_N106
.nCurrentAddress
;
1975 if(mWave_N106
.bAutoIncrement
)
1976 mWave_N106
.nCurrentAddress
=
1977 (mWave_N106
.nCurrentAddress
+ 1) & 0x7F;
1979 #define N106REGWRITE(ch,r0,r1,r2,r3,r4) \
1980 case r0: if(mWave_N106.nFreqReg[ch].B.l == v) break; \
1981 mWave_N106.nFreqReg[ch].B.l = v; \
1982 mWave_N106.nFreqTimer[ch] = -1; \
1984 case r1: if(mWave_N106.nFreqReg[ch].B.h == v) break; \
1985 mWave_N106.nFreqReg[ch].B.h = v; \
1986 mWave_N106.nFreqTimer[ch] = -1; \
1988 case r2: if(mWave_N106.nFreqReg[ch].B.w != (v & 3)){ \
1989 mWave_N106.nFreqReg[ch].B.w = v & 0x03; \
1990 mWave_N106.nFreqTimer[ch] = -1;} \
1991 mWave_N106.nWaveSize[ch] = 0x20 - (v & 0x1C); \
1993 case r3: mWave_N106.nWavePosStart[ch] = v; \
1995 case r4: mWave_N106.nPreVolume[ch] = v & 0x0F; \
1996 if(!bN106PopReducer) \
1997 mWave_N106.nVolume[ch] = v & 0x0F
2001 N106REGWRITE(0,0x40,0x42,0x44,0x46,0x47); break;
2002 N106REGWRITE(1,0x48,0x4A,0x4C,0x4E,0x4F); break;
2003 N106REGWRITE(2,0x50,0x52,0x54,0x56,0x57); break;
2004 N106REGWRITE(3,0x58,0x5A,0x5C,0x5E,0x5F); break;
2005 N106REGWRITE(4,0x60,0x62,0x64,0x66,0x67); break;
2006 N106REGWRITE(5,0x68,0x6A,0x6C,0x6E,0x6F); break;
2007 N106REGWRITE(6,0x70,0x72,0x74,0x76,0x77); break;
2008 N106REGWRITE(7,0x78,0x7A,0x7C,0x7E,0x7F);
2010 if(mWave_N106
.nActiveChannels
== v
) break;
2011 mWave_N106
.nActiveChannels
= v
;
2012 mWave_N106
.nFreqTimer
[0] = -1;
2013 mWave_N106
.nFreqTimer
[1] = -1;
2014 mWave_N106
.nFreqTimer
[2] = -1;
2015 mWave_N106
.nFreqTimer
[3] = -1;
2016 mWave_N106
.nFreqTimer
[4] = -1;
2017 mWave_N106
.nFreqTimer
[5] = -1;
2018 mWave_N106
.nFreqTimer
[6] = -1;
2019 mWave_N106
.nFreqTimer
[7] = -1;
2026 void WriteMemory_FME07(uint16_t a
,uint8_t v
)
2028 if((a
< 0xD000) && (nExternalSound
& EXTSOUND_FDS
))
2029 WriteMemory_FDSRAM(a
,v
);
2035 switch(nFME07_Address
)
2037 case 0x00: mWave_FME07
[0].nFreqTimer
.B
.l
= v
; break;
2038 case 0x01: mWave_FME07
[0].nFreqTimer
.B
.h
= v
& 0x0F; break;
2039 case 0x02: mWave_FME07
[1].nFreqTimer
.B
.l
= v
; break;
2040 case 0x03: mWave_FME07
[1].nFreqTimer
.B
.h
= v
& 0x0F; break;
2041 case 0x04: mWave_FME07
[2].nFreqTimer
.B
.l
= v
; break;
2042 case 0x05: mWave_FME07
[2].nFreqTimer
.B
.h
= v
& 0x0F; break;
2044 mWave_FME07
[0].bChannelEnabled
= !(v
& 0x01);
2045 mWave_FME07
[1].bChannelEnabled
= !(v
& 0x02);
2046 mWave_FME07
[2].bChannelEnabled
= !(v
& 0x03);
2048 case 0x08: mWave_FME07
[0].nVolume
= v
& 0x0F; break;
2049 case 0x09: mWave_FME07
[1].nVolume
= v
& 0x0F; break;
2050 case 0x0A: mWave_FME07
[2].nVolume
= v
& 0x0F; break;
2060 void EmulateAPU(uint8_t bBurnCPUCycles
)
2071 fulltick
+= (signed)(nCPUCycle
- nAPUCycle
);
2076 if(bFade
&& nSilentSampleMax
&& (nSilentSamples
>= nSilentSampleMax
))
2081 tick
= (nTicksUntilNextSample
+0xffff)>>16;
2089 ENTER_TIMER(squares
);
2090 /* Square generation */
2092 mWave_Squares
.nFreqCount
[0] -= tick
;
2093 mWave_Squares
.nFreqCount
[1] -= tick
;
2095 if((mWave_Squares
.nDutyCount
[0] < mWave_Squares
.nDutyCycle
[0]) &&
2096 mWave_Squares
.nLengthCount
[0] &&
2097 !mWave_Squares
.bSweepForceSilence
[0])
2098 square_out1
= mWave_Squares
.nVolume
[0];
2102 if((mWave_Squares
.nDutyCount
[1] < mWave_Squares
.nDutyCycle
[1]) &&
2103 mWave_Squares
.nLengthCount
[1] &&
2104 !mWave_Squares
.bSweepForceSilence
[1])
2105 square_out2
= mWave_Squares
.nVolume
[1];
2109 mWave_Squares
.nMixL
= Squares_nOutputTable_L
[square_out1
][square_out2
];
2111 if(mWave_Squares
.nFreqCount
[0]<=0)
2114 (-mWave_Squares
.nFreqCount
[0])/
2115 (mWave_Squares
.nFreqTimer
[0].W
+ 1) + 1;
2116 mWave_Squares
.nFreqCount
[0] =
2117 (mWave_Squares
.nFreqTimer
[0].W
+ 1)-
2118 (-mWave_Squares
.nFreqCount
[0])%
2119 (mWave_Squares
.nFreqTimer
[0].W
+ 1);
2120 mWave_Squares
.nDutyCount
[0] =
2121 (mWave_Squares
.nDutyCount
[0]+cycles
)%0x10;
2123 if(mWave_Squares
.nFreqCount
[1]<=0)
2126 (-mWave_Squares
.nFreqCount
[1])/
2127 (mWave_Squares
.nFreqTimer
[1].W
+ 1) + 1;
2128 mWave_Squares
.nFreqCount
[1] =
2129 (mWave_Squares
.nFreqTimer
[1].W
+ 1)-
2130 (-mWave_Squares
.nFreqCount
[1])%
2131 (mWave_Squares
.nFreqTimer
[1].W
+ 1);
2132 mWave_Squares
.nDutyCount
[1] = (mWave_Squares
.nDutyCount
[1]+cycles
)%
2135 /* end of Square generation */
2136 EXIT_TIMER(squares
);
2139 ENTER_TIMER(tnd_enter
);
2143 /* TND generation */
2145 if(mWave_TND
.nNoiseFreqTimer
) mWave_TND
.nNoiseFreqCount
-= tick
;
2147 if(mWave_TND
.nTriFreqTimer
.W
> 8)
2148 mWave_TND
.nTriFreqCount
-= tick
;
2150 tnd_out
= mWave_TND
.nTriOutput
<< 11;
2152 if(mWave_TND
.bNoiseRandomOut
&& mWave_TND
.nNoiseLengthCount
)
2153 tnd_out
|= mWave_TND
.nNoiseVolume
<< 7;
2155 tnd_out
|= mWave_TND
.nDMCOutput
;
2157 mWave_TND
.nMixL
= main_nOutputTable_L
[tnd_out
];
2159 EXIT_TIMER(tnd_enter
);
2161 ENTER_TIMER(tnd_tri
);
2165 if(mWave_TND
.nTriFreqCount
<=0)
2167 if(mWave_TND
.nTriLengthCount
&& mWave_TND
.nTriLinearCount
)
2169 do mWave_TND
.nTriStep
++;
2170 while ((mWave_TND
.nTriFreqCount
+=
2171 mWave_TND
.nTriFreqTimer
.W
+ 1) <= 0);
2172 mWave_TND
.nTriStep
&= 0x1F;
2174 if(mWave_TND
.nTriStep
& 0x10)
2175 mWave_TND
.nTriOutput
= mWave_TND
.nTriStep
^ 0x1F;
2176 else mWave_TND
.nTriOutput
= mWave_TND
.nTriStep
;
2177 } else mWave_TND
.nTriFreqCount
=mWave_TND
.nTriFreqTimer
.W
+1;
2180 EXIT_TIMER(tnd_tri
);
2182 ENTER_TIMER(tnd_noise
);
2186 if(mWave_TND
.nNoiseFreqTimer
&&
2187 mWave_TND
.nNoiseVolume
&& mWave_TND
.nNoiseFreqCount
<=0)
2189 mWave_TND
.nNoiseFreqCount
= mWave_TND
.nNoiseFreqTimer
;
2190 mWave_TND
.nNoiseRandomShift
<<= 1;
2191 mWave_TND
.bNoiseRandomOut
= (((mWave_TND
.nNoiseRandomShift
<<
2192 mWave_TND
.bNoiseRandomMode
) ^
2193 mWave_TND
.nNoiseRandomShift
) & 0x8000 ) ? 1 : 0;
2194 if(mWave_TND
.bNoiseRandomOut
)
2195 mWave_TND
.nNoiseRandomShift
|= 0x01;
2198 EXIT_TIMER(tnd_noise
);
2200 ENTER_TIMER(tnd_dmc
);
2203 if(mWave_TND
.bDMCActive
)
2205 mWave_TND
.nDMCFreqCount
-= tick
;
2206 while (mWave_TND
.nDMCFreqCount
<= 0) {
2207 if (!mWave_TND
.bDMCActive
) {
2208 mWave_TND
.nDMCFreqCount
= mWave_TND
.nDMCFreqTimer
;
2212 mWave_TND
.nDMCFreqCount
+= mWave_TND
.nDMCFreqTimer
;
2214 if(mWave_TND
.bDMCSampleBufferEmpty
&&
2215 mWave_TND
.nDMCBytesRemaining
)
2217 burned
+= 4; /* 4 cycle burn! */
2218 mWave_TND
.nDMCSampleBuffer
=
2219 mWave_TND
.pDMCDMAPtr
[mWave_TND
.nDMCDMABank
]
2220 [mWave_TND
.nDMCDMAAddr
];
2221 mWave_TND
.nDMCDMAAddr
++;
2222 if(mWave_TND
.nDMCDMAAddr
& 0x1000)
2224 mWave_TND
.nDMCDMAAddr
&= 0x0FFF;
2225 mWave_TND
.nDMCDMABank
=
2226 (mWave_TND
.nDMCDMABank
+ 1) & 0x07;
2229 mWave_TND
.bDMCSampleBufferEmpty
= 0;
2230 mWave_TND
.nDMCBytesRemaining
--;
2231 if(!mWave_TND
.nDMCBytesRemaining
)
2233 if(mWave_TND
.bDMCLoop
)
2235 mWave_TND
.nDMCDMABank
= mWave_TND
.nDMCDMABank_Load
;
2236 mWave_TND
.nDMCDMAAddr
= mWave_TND
.nDMCDMAAddr_Load
;
2237 mWave_TND
.nDMCBytesRemaining
=mWave_TND
.nDMCLength
;
2239 else if(mWave_TND
.bDMCIRQEnabled
)
2240 mWave_TND
.bDMCIRQPending
= 1;
2244 if(!mWave_TND
.nDMCDeltaBit
)
2246 mWave_TND
.nDMCDeltaBit
= 8;
2247 mWave_TND
.bDMCDeltaSilent
=mWave_TND
.bDMCSampleBufferEmpty
;
2248 mWave_TND
.nDMCDelta
= mWave_TND
.nDMCSampleBuffer
;
2249 mWave_TND
.bDMCSampleBufferEmpty
= 1;
2252 if(mWave_TND
.nDMCDeltaBit
) {
2253 mWave_TND
.nDMCDeltaBit
--;
2254 if(!mWave_TND
.bDMCDeltaSilent
)
2256 if(mWave_TND
.nDMCDelta
& 0x01)
2258 if(mWave_TND
.nDMCOutput
< 0x7E)
2259 mWave_TND
.nDMCOutput
+= 2;
2261 else if(mWave_TND
.nDMCOutput
> 1)
2262 mWave_TND
.nDMCOutput
-= 2;
2264 mWave_TND
.nDMCDelta
>>= 1;
2267 if(!mWave_TND
.nDMCBytesRemaining
&&
2268 mWave_TND
.bDMCSampleBufferEmpty
&&
2269 mWave_TND
.bDMCDeltaSilent
)
2270 mWave_TND
.bDMCActive
= mWave_TND
.nDMCDeltaBit
= 0;
2274 EXIT_TIMER(tnd_dmc
);
2276 /* end of TND generation */
2279 if(nExternalSound
&& !bPALMode
)
2281 if(nExternalSound
& EXTSOUND_VRC6
)
2282 Wave_VRC6_DoTicks(tick
);
2283 if(nExternalSound
& EXTSOUND_N106
)
2284 Wave_N106_DoTicks(tick
);
2285 if(nExternalSound
& EXTSOUND_FME07
)
2287 if (mWave_FME07
[0].bChannelEnabled
&&
2288 mWave_FME07
[0].nFreqTimer
.W
) {
2289 mWave_FME07
[0].nFreqCount
-= tick
;
2291 if(mWave_FME07
[0].nDutyCount
< 16)
2293 mWave_FME07
[0].nMixL
=
2294 FME07_nOutputTable_L
[mWave_FME07
[0].nVolume
];
2295 } else mWave_FME07
[0].nMixL
= 0;
2296 while(mWave_FME07
[0].nFreqCount
<= 0) {
2297 mWave_FME07
[0].nFreqCount
+=
2298 mWave_FME07
[0].nFreqTimer
.W
;
2300 mWave_FME07
[0].nDutyCount
=
2301 (mWave_FME07
[0].nDutyCount
+1)&0x1f;
2305 if (mWave_FME07
[1].bChannelEnabled
&&
2306 mWave_FME07
[1].nFreqTimer
.W
) {
2307 mWave_FME07
[1].nFreqCount
-= tick
;
2309 if(mWave_FME07
[1].nDutyCount
< 16)
2311 mWave_FME07
[1].nMixL
=
2312 FME07_nOutputTable_L
[mWave_FME07
[1].nVolume
];
2313 } else mWave_FME07
[1].nMixL
= 0;
2314 while(mWave_FME07
[1].nFreqCount
<= 0) {
2315 mWave_FME07
[1].nFreqCount
+=
2316 mWave_FME07
[1].nFreqTimer
.W
;
2318 mWave_FME07
[1].nDutyCount
=
2319 (mWave_FME07
[1].nDutyCount
+1)&0x1f;
2323 if (mWave_FME07
[2].bChannelEnabled
&&
2324 mWave_FME07
[2].nFreqTimer
.W
) {
2325 mWave_FME07
[2].nFreqCount
-= tick
;
2327 if(mWave_FME07
[2].nDutyCount
< 16)
2329 mWave_FME07
[2].nMixL
=
2330 FME07_nOutputTable_L
[mWave_FME07
[2].nVolume
];
2331 } else mWave_FME07
[2].nMixL
= 0;
2332 while(mWave_FME07
[2].nFreqCount
<= 0) {
2333 mWave_FME07
[2].nFreqCount
+=
2334 mWave_FME07
[2].nFreqTimer
.W
;
2336 mWave_FME07
[2].nDutyCount
=
2337 (mWave_FME07
[2].nDutyCount
+1)&0x1f;
2343 if(nExternalSound
& EXTSOUND_FDS
) {
2345 /* Volume Envelope Unit */
2346 if(mWave_FDS
.bVolEnv_On
)
2348 mWave_FDS
.nVolEnv_Count
-= tick
;
2349 while(mWave_FDS
.nVolEnv_Count
<= 0)
2351 mWave_FDS
.nVolEnv_Count
+= mWave_FDS
.nVolEnv_Timer
;
2352 if(mWave_FDS
.nVolEnv_Mode
) {
2353 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
2354 mWave_FDS
.nVolEnv_Gain
++;
2357 if(mWave_FDS
.nVolEnv_Gain
)
2358 mWave_FDS
.nVolEnv_Gain
--;
2363 /* Sweep Envelope Unit */
2364 if(mWave_FDS
.bSweepEnv_On
)
2366 mWave_FDS
.nSweep_Count
-= tick
;
2367 while(mWave_FDS
.nSweep_Count
<= 0)
2369 mWave_FDS
.nSweep_Count
+= mWave_FDS
.nSweep_Timer
;
2370 if(mWave_FDS
.nSweep_Mode
) {
2371 if(mWave_FDS
.nSweep_Gain
< 0x20)
2372 mWave_FDS
.nSweep_Gain
++;
2374 if(mWave_FDS
.nSweep_Gain
) mWave_FDS
.nSweep_Gain
--;
2379 /* Effector / LFO */
2380 int32_t subfreq
= 0;
2381 if(mWave_FDS
.bLFO_On
)
2383 mWave_FDS
.nLFO_Count
-= tick
<<14;
2384 while(mWave_FDS
.nLFO_Count
<= 0)
2386 mWave_FDS
.nLFO_Count
+= mWave_FDS
.nLFO_Timer
;
2387 if(mWave_FDS
.nLFO_Table
[mWave_FDS
.nLFO_Addr
] == 4)
2388 mWave_FDS
.nSweepBias
= 0;
2390 mWave_FDS
.nSweepBias
+=
2392 mWave_FDS
.nLFO_Table
[mWave_FDS
.nLFO_Addr
]
2394 mWave_FDS
.nLFO_Addr
= (mWave_FDS
.nLFO_Addr
+ 1) & 0x3F;
2397 while(mWave_FDS
.nSweepBias
> 63)
2398 mWave_FDS
.nSweepBias
-= 128;
2399 while(mWave_FDS
.nSweepBias
< -64)
2400 mWave_FDS
.nSweepBias
+= 128;
2402 register int32_t temp
=
2403 mWave_FDS
.nSweepBias
* mWave_FDS
.nSweep_Gain
;
2407 if(mWave_FDS
.nSweepBias
< 0) temp
--;
2413 if(temp
> 193) temp
-= 258;
2414 if(temp
< -64) temp
+= 256;
2416 subfreq
= mWave_FDS
.nFreq
.W
* temp
/ 64;
2420 if(mWave_FDS
.bMain_On
)
2423 FDS_nOutputTable_L
[mWave_FDS
.nMainVolume
]
2425 [mWave_FDS
.nWaveTable
[mWave_FDS
.nMainAddr
] ];
2427 if((subfreq
+ mWave_FDS
.nFreq
.W
) > 0)
2429 int32_t freq
= (0x10000<<14) / (subfreq
+ mWave_FDS
.nFreq
.W
);
2431 mWave_FDS
.nFreqCount
-= tick
<<14;
2432 while(mWave_FDS
.nFreqCount
<= 0)
2434 mWave_FDS
.nFreqCount
+= freq
;
2436 mWave_FDS
.nMainAddr
=
2437 (mWave_FDS
.nMainAddr
+ 1) & 0x3F;
2438 mWave_FDS
.nPopOutput
=
2439 mWave_FDS
.nWaveTable
[mWave_FDS
.nMainAddr
];
2440 if(!mWave_FDS
.nMainAddr
)
2442 if(mWave_FDS
.nVolEnv_Gain
< 0x20)
2443 mWave_FDS
.nVolume
= mWave_FDS
.nVolEnv_Gain
;
2444 else mWave_FDS
.nVolume
= 0x20;
2449 mWave_FDS
.nFreqCount
= mWave_FDS
.nLFO_Count
;
2451 else if(mWave_FDS
.bPopReducer
&& mWave_FDS
.nPopOutput
)
2453 mWave_FDS
.nMixL
= FDS_nOutputTable_L
[mWave_FDS
.nMainVolume
]
2455 [mWave_FDS
.nPopOutput
];
2457 mWave_FDS
.nPopCount
-= tick
;
2458 while(mWave_FDS
.nPopCount
<= 0)
2460 mWave_FDS
.nPopCount
+= 500;
2461 mWave_FDS
.nPopOutput
--;
2462 if(!mWave_FDS
.nPopOutput
)
2463 mWave_FDS
.nMainAddr
= 0;
2468 } /* end while fulltick */
2472 nCPUCycle
+= burned
;
2476 /* Frame Sequencer */
2479 nTicksUntilNextFrame
-= tick
<<16;
2480 while(nTicksUntilNextFrame
<= 0)
2482 nTicksUntilNextFrame
+=
2483 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
) *
2486 if(nFrameCounter
> nFrameCounterMax
)
2489 if(nFrameCounterMax
== 4)
2491 if(nFrameCounter
< 4)
2494 if(!(nFrameCounter
& 1))
2501 if(nFrameCounter
& 1)
2504 if((nFrameCounter
== 3) && bFrameIRQEnabled
)
2505 bFrameIRQPending
= 1;
2511 nTicksUntilNextSample
-= tick
<<16;
2512 if(nTicksUntilNextSample
<= 0)
2514 nTicksUntilNextSample
+= nTicksPerSample
;
2516 mixL
= mWave_Squares
.nMixL
;
2517 mixL
+= mWave_TND
.nMixL
;
2519 if(nExternalSound
&& !bPALMode
)
2521 if(nExternalSound
& EXTSOUND_VRC6
)
2523 mixL
+= (mWave_VRC6Pulse
[0].nMixL
);
2524 mixL
+= (mWave_VRC6Pulse
[1].nMixL
);
2525 mixL
+= (mWave_VRC6Saw
.nMixL
);
2527 if(nExternalSound
& EXTSOUND_N106
) {
2528 mixL
+= (mWave_N106
.nMixL
[0]);
2529 mixL
+= (mWave_N106
.nMixL
[1]);
2530 mixL
+= (mWave_N106
.nMixL
[2]);
2531 mixL
+= (mWave_N106
.nMixL
[3]);
2532 mixL
+= (mWave_N106
.nMixL
[4]);
2533 mixL
+= (mWave_N106
.nMixL
[5]);
2534 mixL
+= (mWave_N106
.nMixL
[6]);
2535 mixL
+= (mWave_N106
.nMixL
[7]);
2537 if(nExternalSound
& EXTSOUND_FME07
)
2539 mixL
+= (mWave_FME07
[0].nMixL
);
2540 mixL
+= (mWave_FME07
[1].nMixL
);
2541 mixL
+= (mWave_FME07
[2].nMixL
);
2543 if(nExternalSound
& EXTSOUND_FDS
)
2544 mixL
+= mWave_FDS
.nMixL
;
2548 diff
= ((int64_t)mixL
<< 25) - nFilterAccL
;
2549 nFilterAccL
+= (diff
* nHighPass
) >> 16;
2550 mixL
= (int32_t)(diff
>> 23);
2553 if(bFade
&& (fFadeVolume
< 1))
2554 mixL
= (int32_t)(mixL
* fFadeVolume
);
2556 if(mixL
< -32768) mixL
= -32768;
2557 if(mixL
> 32767) mixL
= 32767;
2559 *((uint16_t*)pOutput
) = (uint16_t)mixL
;
2566 nAPUCycle
= nCPUCycle
;
2575 * Initializes Memory
2578 int NSFCore_Initialize()
2582 /* why, yes, this was easier when they were in a struct */
2588 ZEROMEMORY(pRAM
,0x800);
2589 ZEROMEMORY(pSRAM
,0x2000);
2590 ZEROMEMORY(pExRAM
,0x1000);
2593 ZEROMEMORY(pROM
,10);
2601 * Memory Proc Pointers
2604 ZEROMEMORY(ReadMemory
,sizeof(ReadProc
)*0x10);
2605 ZEROMEMORY(WriteMemory
,sizeof(WriteProc
)*0x10);
2608 * 6502 Registers / Mode
2625 * NSF Preparation Information
2628 ZEROMEMORY(nBankswitchInitValues
,10);
2635 fNSFPlaybackSpeed
=0;
2647 * Timing and Counters
2649 nTicksUntilNextFrame
=0;
2652 nTicksUntilNextPlay
=0;
2655 nTicksUntilNextSample
=0;
2671 * Volume/fading/filter tracking
2699 ZEROMEMORY(&mWave_Squares
,sizeof(struct Wave_Squares
));
2700 ZEROMEMORY(&mWave_TND
,sizeof(struct Wave_TND
));
2701 ZEROMEMORY(mWave_VRC6Pulse
,sizeof(struct VRC6PulseWave
)*2);
2702 ZEROMEMORY(&mWave_VRC6Saw
,sizeof(struct VRC6SawWave
));
2703 ZEROMEMORY(&mWave_N106
,sizeof(struct N106Wave
));
2704 ZEROMEMORY(mWave_FME07
,sizeof(struct FME07Wave
)*3);
2705 ZEROMEMORY(&mWave_FDS
,sizeof(struct FDSWave
));
2707 /* end clear globals */
2709 // Default filter bases
2710 nHighPassBase
= 150;
2712 bHighPassEnabled
= 1;
2714 mWave_TND
.nNoiseRandomShift
= 1;
2715 for(i
= 0; i
< 8; i
++)
2716 mWave_TND
.pDMCDMAPtr
[i
] = pROM
[i
+ 2];
2719 SetPlaybackOptions(nSampleRate
);
2721 for(i
= 0; i
< 8; i
++)
2722 mWave_N106
.nFrequencyLookupTable
[i
] =
2723 ((((i
+ 1) * 45 * 0x40000) / (float)NES_FREQUENCY
) *
2724 (float)NTSC_FREQUENCY
) * 256.0;
2726 ZEROMEMORY(pRAM
,0x800);
2727 ZEROMEMORY(pSRAM
,0x2000);
2728 ZEROMEMORY(pExRAM
,0x1000);
2729 pStack
= pRAM
+ 0x100;
2737 int LoadNSF(int32_t datasize
)
2739 if(!pDataBuffer
) return 0;
2743 nExternalSound
= nChipExtensions
;
2745 bPALMode
= bPALPreference
;
2747 bPALMode
= nIsPal
& 1;
2749 SetPlaybackOptions(nSampleRate
);
2751 int32_t neededsize
= datasize
+ (nfileLoadAddress
& 0x0FFF);
2752 if(neededsize
& 0x0FFF) neededsize
+= 0x1000 - (neededsize
& 0x0FFF);
2753 if(neededsize
< 0x1000) neededsize
= 0x1000;
2755 uint8_t specialload
= 0;
2757 for(i
= 0; (i
< 8) && (!nBankswitch
[i
]); i
++);
2758 if(i
< 8) /* uses bankswitching */
2760 memcpy(&nBankswitchInitValues
[2],nBankswitch
,8);
2761 nBankswitchInitValues
[0] = nBankswitch
[6];
2762 nBankswitchInitValues
[1] = nBankswitch
[7];
2763 if(nExternalSound
& EXTSOUND_FDS
)
2765 if(!(nBankswitchInitValues
[0] || nBankswitchInitValues
[1]))
2768 * FDS sound with '00' specified for both $6000 and $7000 banks.
2769 * point this to an area of fresh RAM (sort of hackish solution
2770 * for those FDS tunes that don't quite follow the nsf specs.
2772 nBankswitchInitValues
[0] = (uint8_t)(neededsize
>> 12);
2773 nBankswitchInitValues
[1] = (uint8_t)(neededsize
>> 12) + 1;
2774 neededsize
+= 0x2000;
2778 else /* doesn't use bankswitching */
2780 if(nExternalSound
& EXTSOUND_FDS
)
2782 /* bad load address */
2783 if(nfileLoadAddress
< 0x6000) return 0;
2785 if(neededsize
< 0xA000)
2786 neededsize
= 0xA000;
2788 for(i
= 0; i
< 10; i
++)
2789 nBankswitchInitValues
[i
] = (uint8_t)i
;
2793 /* bad load address */
2794 if(nfileLoadAddress
< 0x8000) return 0;
2796 int32_t j
= (nfileLoadAddress
>> 12) - 6;
2797 for(i
= 0; i
< j
; i
++)
2798 nBankswitchInitValues
[i
] = 0;
2799 for(j
= 0; i
< 10; i
++, j
++)
2800 nBankswitchInitValues
[i
] = (uint8_t)j
;
2804 nROMSize
= neededsize
;
2805 nROMBankCount
= neededsize
>> 12;
2808 pROM_Full
= pDataBuffer
-(nfileLoadAddress
-0x6000);
2810 pROM_Full
= pDataBuffer
-(nfileLoadAddress
&0x0FFF);
2812 ZEROMEMORY(pRAM
,0x0800);
2813 ZEROMEMORY(pExRAM
,0x1000);
2814 ZEROMEMORY(pSRAM
,0x2000);
2816 nExternalSound
= nChipExtensions
;
2817 fNSFPlaybackSpeed
= (bPALMode
? PAL_NMIRATE
: NTSC_NMIRATE
);
2819 SetPlaybackSpeed(0);
2821 nPlayAddress
= nfilePlayAddress
;
2822 nInitAddress
= nfileInitAddress
;
2824 pExRAM
[0x00] = 0x20; /* JSR */
2825 pExRAM
[0x01] = nInitAddress
&0xff; /* Init Address */
2826 pExRAM
[0x02] = (nInitAddress
>>8)&0xff;
2827 pExRAM
[0x03] = 0xF2; /* JAM */
2828 pExRAM
[0x04] = 0x20; /* JSR */
2829 pExRAM
[0x05] = nPlayAddress
&0xff; /* Play Address */
2830 pExRAM
[0x06] = (nPlayAddress
>>8)&0xff;
2831 pExRAM
[0x07] = 0x4C; /* JMP */
2832 pExRAM
[0x08] = 0x03;/* $5003 (JAM right before the JSR to play address) */
2833 pExRAM
[0x09] = 0x50;
2835 regA
= regX
= regY
= 0;
2836 regP
= 0x04; /* I_FLAG */
2841 /* Reset Read/Write Procs */
2843 ReadMemory
[0] = ReadMemory
[1] = ReadMemory_RAM
;
2844 ReadMemory
[2] = ReadMemory
[3] = ReadMemory_Default
;
2845 ReadMemory
[4] = ReadMemory_pAPU
;
2846 ReadMemory
[5] = ReadMemory_ExRAM
;
2847 ReadMemory
[6] = ReadMemory
[7] = ReadMemory_SRAM
;
2849 WriteMemory
[0] = WriteMemory
[1] = WriteMemory_RAM
;
2850 WriteMemory
[2] = WriteMemory
[3] = WriteMemory_Default
;
2851 WriteMemory
[4] = WriteMemory_pAPU
;
2852 WriteMemory
[5] = WriteMemory_ExRAM
;
2853 WriteMemory
[6] = WriteMemory
[7] = WriteMemory_SRAM
;
2855 for(i
= 8; i
< 16; i
++)
2857 ReadMemory
[i
] = ReadMemory_ROM
;
2858 WriteMemory
[i
] = WriteMemory_Default
;
2861 if(nExternalSound
& EXTSOUND_FDS
)
2863 WriteMemory
[0x06] = WriteMemory_FDSRAM
;
2864 WriteMemory
[0x07] = WriteMemory_FDSRAM
;
2865 WriteMemory
[0x08] = WriteMemory_FDSRAM
;
2866 WriteMemory
[0x09] = WriteMemory_FDSRAM
;
2867 WriteMemory
[0x0A] = WriteMemory_FDSRAM
;
2868 WriteMemory
[0x0B] = WriteMemory_FDSRAM
;
2869 WriteMemory
[0x0C] = WriteMemory_FDSRAM
;
2870 WriteMemory
[0x0D] = WriteMemory_FDSRAM
;
2871 ReadMemory
[0x06] = ReadMemory_ROM
;
2872 ReadMemory
[0x07] = ReadMemory_ROM
;
2875 if(!bPALMode
) /* no expansion sound available on a PAL system */
2877 if(nExternalSound
& EXTSOUND_VRC6
)
2879 /* if both VRC6+VRC7... it MUST go to WriteMemory_VRC6
2880 * or register writes will be lost (WriteMemory_VRC6 calls
2881 * WriteMemory_VRC7 if needed) */
2882 WriteMemory
[0x09] = WriteMemory_VRC6
;
2883 WriteMemory
[0x0A] = WriteMemory_VRC6
;
2884 WriteMemory
[0x0B] = WriteMemory_VRC6
;
2886 if(nExternalSound
& EXTSOUND_N106
)
2888 WriteMemory
[0x04] = WriteMemory_N106
;
2889 ReadMemory
[0x04] = ReadMemory_N106
;
2890 WriteMemory
[0x0F] = WriteMemory_N106
;
2892 if(nExternalSound
& EXTSOUND_FME07
)
2894 WriteMemory
[0x0C] = WriteMemory_FME07
;
2895 WriteMemory
[0x0E] = WriteMemory_FME07
;
2899 /* MMC5 still has a multiplication reg that needs to be available on
2901 if(nExternalSound
& EXTSOUND_MMC5
)
2902 WriteMemory
[0x05] = WriteMemory_MMC5
;
2911 void SetTrack(uint8_t track
)
2920 regY
= bCleanAXY
? 0 : 0xCD;
2926 nCPUCycle
= nAPUCycle
= 0;
2930 for(i
= 0x4000; i
< 0x400F; i
++)
2931 WriteMemory_pAPU(i
,0);
2932 WriteMemory_pAPU(0x4010,0);
2933 WriteMemory_pAPU(0x4012,0);
2934 WriteMemory_pAPU(0x4013,0);
2935 WriteMemory_pAPU(0x4014,0);
2936 WriteMemory_pAPU(0x4015,0);
2937 WriteMemory_pAPU(0x4015,0x0F);
2938 WriteMemory_pAPU(0x4017,0);
2940 for(i
= 0; i
< 10; i
++)
2941 WriteMemory_ExRAM(0x5FF6 + i
,nBankswitchInitValues
[i
]);
2943 ZEROMEMORY(pRAM
,0x0800);
2944 ZEROMEMORY(pSRAM
,0x2000);
2945 ZEROMEMORY(&pExRAM
[0x10],0x0FF0);
2949 nTicksUntilNextSample
= nTicksPerSample
;
2950 nTicksUntilNextFrame
=
2951 (bPALMode
? PAL_FRAME_COUNTER_FREQ
: NTSC_FRAME_COUNTER_FREQ
)*0x10000;
2952 nTicksUntilNextPlay
= nTicksPerPlay
;
2955 /* Clear mixing vals */
2956 mWave_Squares
.nMixL
= 0;
2957 mWave_TND
.nMixL
= 0;
2958 mWave_VRC6Pulse
[0].nMixL
= 0;
2959 mWave_VRC6Pulse
[1].nMixL
= 0;
2960 mWave_VRC6Saw
.nMixL
= 0;
2962 /* Reset Tri/Noise/DMC */
2963 mWave_TND
.nTriStep
= mWave_TND
.nTriOutput
= 0;
2964 mWave_TND
.nDMCOutput
= 0;
2965 mWave_TND
.bNoiseRandomOut
= 0;
2966 mWave_Squares
.nDutyCount
[0] = mWave_Squares
.nDutyCount
[1] = 0;
2967 mWave_TND
.bDMCActive
= 0;
2968 mWave_TND
.nDMCBytesRemaining
= 0;
2969 mWave_TND
.bDMCSampleBufferEmpty
= 1;
2970 mWave_TND
.bDMCDeltaSilent
= 1;
2973 mWave_VRC6Pulse
[0].nVolume
= 0;
2974 mWave_VRC6Pulse
[1].nVolume
= 0;
2975 mWave_VRC6Saw
.nAccumRate
= 0;
2978 ZEROMEMORY(mWave_N106
.nRAM
,0x100);
2979 ZEROMEMORY(mWave_N106
.nVolume
,8);
2980 ZEROMEMORY(mWave_N106
.nOutput
,8);
2981 ZEROMEMORY(mWave_N106
.nMixL
,32);
2984 mWave_FME07
[0].nVolume
= 0;
2985 mWave_FME07
[1].nVolume
= 0;
2986 mWave_FME07
[2].nVolume
= 0;
2988 /* Clear FDS crap */
2990 mWave_FDS
.bEnvelopeEnable
= 0;
2991 mWave_FDS
.nEnvelopeSpeed
= 0xFF;
2992 mWave_FDS
.nVolEnv_Mode
= 2;
2993 mWave_FDS
.nVolEnv_Decay
= 0;
2994 mWave_FDS
.nVolEnv_Gain
= 0;
2995 mWave_FDS
.nVolume
= 0;
2996 mWave_FDS
.bVolEnv_On
= 0;
2997 mWave_FDS
.nSweep_Mode
= 2;
2998 mWave_FDS
.nSweep_Decay
= 0;
2999 mWave_FDS
.nSweep_Gain
= 0;
3000 mWave_FDS
.bSweepEnv_On
= 0;
3001 mWave_FDS
.nSweepBias
= 0;
3002 mWave_FDS
.bLFO_Enabled
= 0;
3003 mWave_FDS
.nLFO_Freq
.W
= 0;
3004 /* mWave_FDS.fLFO_Timer = 0;
3005 mWave_FDS.fLFO_Count = 0;*/
3006 mWave_FDS
.nLFO_Timer
= 0;
3007 mWave_FDS
.nLFO_Count
= 0;
3008 mWave_FDS
.nLFO_Addr
= 0;
3009 mWave_FDS
.bLFO_On
= 0;
3010 mWave_FDS
.nMainVolume
= 0;
3011 mWave_FDS
.bEnabled
= 0;
3012 mWave_FDS
.nFreq
.W
= 0;
3013 /* mWave_FDS.fFreqCount = 0;*/
3014 mWave_FDS
.nFreqCount
= 0;
3015 mWave_FDS
.nMainAddr
= 0;
3016 mWave_FDS
.bWaveWrite
= 0;
3017 mWave_FDS
.bMain_On
= 0;
3018 mWave_FDS
.nMixL
= 0;
3019 ZEROMEMORY(mWave_FDS
.nWaveTable
,0x40);
3020 ZEROMEMORY(mWave_FDS
.nLFO_Table
,0x40);
3022 mWave_FDS
.nSweep_Count
= mWave_FDS
.nSweep_Timer
=
3023 ((mWave_FDS
.nSweep_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
3024 mWave_FDS
.nVolEnv_Count
= mWave_FDS
.nVolEnv_Timer
=
3025 ((mWave_FDS
.nVolEnv_Decay
+ 1) * mWave_FDS
.nEnvelopeSpeed
* 8);
3037 * SetPlaybackOptions
3040 int SetPlaybackOptions(int32_t samplerate
)
3042 if(samplerate
< 2000) return 0;
3043 if(samplerate
> 96000) return 0;
3046 (bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / samplerate
* 0x10000;
3047 nTicksUntilNextSample
= nTicksPerSample
;
3050 RecalcSilenceTracker();
3059 void SetPlaybackSpeed(float playspersec
)
3063 playspersec
= fNSFPlaybackSpeed
;
3066 nTicksPerPlay
= nTicksUntilNextPlay
=
3067 (bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / playspersec
* 0x10000;
3074 float GetPlaybackSpeed()
3076 if(nTicksPerPlay
<= 0) return 0;
3077 return ((bPALMode
? PAL_FREQUENCY
: NTSC_FREQUENCY
) / (nTicksPerPlay
>>16));
3086 if(!nSampleRate
) return;
3088 nHighPass
= ((int64_t)nHighPassBase
<< 16) / nSampleRate
;
3090 if(nHighPass
> (1<<16)) nHighPass
= 1<<16;
3094 * RecalcSilenceTracker
3097 void RecalcSilenceTracker()
3099 if(nSilenceTrackMS
<= 0 || !nSampleRate
||
3100 (bNoSilenceIfTime
&& bTimeNotDefault
))
3102 nSilentSampleMax
= 0;
3106 nSilentSampleMax
= nSilenceTrackMS
* nSampleRate
/ 500;
3107 nSilentSampleMax
/= 2;
3110 void RebuildOutputTables(void) {
3117 for(i
= 0; i
< 3; i
++)
3122 for(i
= 0; i
< 0x8000; i
++)
3124 ftemp
= (l
[0] * (i
>> 11)) / 2097885;
3125 ftemp
+= (l
[1] * ((i
>> 7) & 0x0F)) / 3121455;
3126 ftemp
+= (l
[2] * (i
& 0x7F)) / 5772690;
3129 main_nOutputTable_L
[i
] = 0;
3131 main_nOutputTable_L
[i
] =
3132 (int16_t)(2396850 / ((1.0f
/ ftemp
) + 100));
3136 for(i
= 0; i
< 2; i
++)
3141 for(j
= 0; j
< 0x10; j
++)
3143 for(i
= 0; i
< 0x10; i
++)
3145 temp
= (int32_t)(l
[0] * j
);
3146 temp
+= (int32_t)(l
[1] * i
);
3149 Squares_nOutputTable_L
[j
][i
] = 0;
3151 Squares_nOutputTable_L
[j
][i
] = 1438200 / ((2072640 / temp
) + 100);
3155 /* VRC6 Pulse 1,2 */
3156 for(i
= 0; i
< 0x10; i
++)
3158 VRC6Pulse_nOutputTable_L
[i
] =
3162 for(i
= 0; i
< 0x20; i
++)
3164 VRC6Saw_nOutputTable_L
[i
] = 3750 * i
/ 0x1F;
3168 /* this amplitude is just a guess */
3170 for(i
= 0; i
< 0x10; i
++)
3172 for(j
= 0; j
< 0x10; j
++)
3174 N106_nOutputTable_L
[i
][j
] = (3000 * i
* j
) / 0xE1;
3178 /* FME-07 Square A,B,C */
3179 FME07_nOutputTable_L
[15] = 3000;
3180 FME07_nOutputTable_L
[0] = 0;
3181 for(i
= 14; i
> 0; i
--)
3183 FME07_nOutputTable_L
[i
] = FME07_nOutputTable_L
[i
+ 1] * 80 / 100;
3189 /* this base volume (4000) is just a guess to what sounds right.
3190 * Given the number of steps available in an FDS wave... it seems like
3191 * it should be much much more... but then it's TOO loud.
3193 for(i
= 0; i
< 0x21; i
++)
3195 for(j
= 0; j
< 0x40; j
++)
3197 FDS_nOutputTable_L
[0][i
][j
] =
3198 (4000 * i
* j
* 30) / (0x21 * 0x40 * 30);
3199 FDS_nOutputTable_L
[1][i
][j
] =
3200 (4000 * i
* j
* 20) / (0x21 * 0x40 * 30);
3201 FDS_nOutputTable_L
[2][i
][j
] =
3202 (4000 * i
* j
* 15) / (0x21 * 0x40 * 30);
3203 FDS_nOutputTable_L
[3][i
][j
] =
3204 (4000 * i
* j
* 12) / (0x21 * 0x40 * 30);
3213 float GetPlayCalls()
3215 if(!nTicksPerPlay
) return 0;
3217 return ((float)nTotalPlays
) +
3218 (1.0f
- (nTicksUntilNextPlay
*1.0f
/ nTicksPerPlay
));
3224 uint32_t GetWrittenTime(float basedplayspersec
/* = 0 */)
3226 if(basedplayspersec
<= 0)
3227 basedplayspersec
= GetPlaybackSpeed();
3229 if(basedplayspersec
<= 0)
3232 return (uint32_t)((GetPlayCalls() * 1000) / basedplayspersec
);
3248 uint8_t SongCompleted()
3250 if(!bFade
) return 0;
3251 if(nTotalPlays
>= nEndFade
) return 1;
3252 if(nSilentSampleMax
) return (nSilentSamples
>= nSilentSampleMax
);
3261 void SetFade(int32_t fadestart
,int32_t fadestop
,
3262 uint8_t bNotDefault
) /* play routine calls */
3264 if(fadestart
< 0) fadestart
= 0;
3265 if(fadestop
< fadestart
) fadestop
= fadestart
;
3267 nStartFade
= (uint32_t)fadestart
;
3268 nEndFade
= (uint32_t)fadestop
;
3270 bTimeNotDefault
= bNotDefault
;
3272 RecalcSilenceTracker();
3280 void SetFadeTime(uint32_t fadestart
,uint32_t fadestop
,float basedplays
,
3281 uint8_t bNotDefault
) /* time in MS */
3284 basedplays
= GetPlaybackSpeed();
3288 SetFade((int32_t)(fadestart
* basedplays
/ 1000),
3289 (int32_t)(fadestop
* basedplays
/ 1000),bNotDefault
);
3296 void RecalculateFade()
3300 /* make it hit silence a little before the song ends...
3301 otherwise we're not really fading OUT, we're just fading umm...
3303 int32_t temp
= (int32_t)(GetPlaybackSpeed() / 4);
3305 if(nEndFade
<= nStartFade
)
3307 nEndFade
= nStartFade
;
3310 else if((nEndFade
- temp
) <= nStartFade
)
3313 fFadeChange
= 1.0f
/ (nEndFade
- nStartFade
- temp
);
3315 if(nTotalPlays
< nStartFade
)
3317 else if(nTotalPlays
>= nEndFade
)
3321 fFadeVolume
= 1.0f
- ( (nTotalPlays
- nStartFade
+ 1) * fFadeChange
);
3328 int32_t GetSamples(uint8_t* buffer
,int32_t buffersize
)
3330 if(!buffer
) return 0;
3331 if(buffersize
< 16) return 0;
3332 if(bFade
&& (nTotalPlays
>= nEndFade
)) return 0;
3335 uint32_t runtocycle
=
3336 (uint32_t)((buffersize
/ 2) * nTicksPerSample
/ 0x10000);
3337 nCPUCycle
= nAPUCycle
= 0;
3342 /*tick = (uint32_t)ceil(fTicksUntilNextPlay);*/
3343 tick
= (nTicksUntilNextPlay
+0xffff)>>16;
3344 if((tick
+ nCPUCycle
) > runtocycle
)
3345 tick
= runtocycle
- nCPUCycle
;
3354 tick
= Emulate6502(tick
+ nCPUCycle
);
3358 nTicksUntilNextPlay
-= tick
<<16;
3359 if(nTicksUntilNextPlay
<= 0)
3361 nTicksUntilNextPlay
+= nTicksPerPlay
;
3362 if((bCPUJammed
== 2) || bNoWaitForReturn
)
3364 regX
= regY
= regA
= (bCleanAXY
? 0 : 0xCD);
3367 bDMCPop_SamePlay
= 0;
3369 if(nForce4017Write
== 1) WriteMemory_pAPU(0x4017,0x00);
3370 if(nForce4017Write
== 2) WriteMemory_pAPU(0x4017,0x80);
3373 if(bFade
&& (nTotalPlays
>= nStartFade
))
3375 fFadeVolume
-= fFadeChange
;
3378 if(nTotalPlays
>= nEndFade
)
3383 if(nCPUCycle
>= runtocycle
)
3387 nCPUCycle
= nAPUCycle
= 0;
3389 if(nSilentSampleMax
&& bFade
)
3391 int16_t* tempbuf
= (int16_t*)buffer
;
3392 while( ((uint8_t*)tempbuf
) < pOutput
)
3394 if( (*tempbuf
< -SILENCE_THRESHOLD
) ||
3395 (*tempbuf
> SILENCE_THRESHOLD
) )
3399 if(++nSilentSamples
>= nSilentSampleMax
)
3400 return (int32_t)( ((uint8_t*)tempbuf
) - buffer
);
3406 return (int32_t)(pOutput
- buffer
);
3409 /****************** 6502 emulation ******************/
3411 /* Memory reading/writing and other defines */
3413 /* reads zero page memory */
3414 #define Zp(a) pRAM[a]
3415 /* reads zero page memory in word form */
3416 #define ZpWord(a) (Zp(a) | (Zp((uint8_t)(a + 1)) << 8))
3418 #define Rd(a) ((ReadMemory[((uint16_t)(a)) >> 12])(a))
3419 /* reads memory in word form */
3420 #define RdWord(a) (Rd(a) | (Rd(a + 1) << 8))
3422 #define Wr(a,v) (WriteMemory[((uint16_t)(a)) >> 12])(a,v)
3423 /* writes zero paged memory */
3424 #define WrZ(a,v) pRAM[a] = v
3425 /* pushes a value onto the stack */
3426 #define PUSH(v) pStack[SP--] = v
3427 /* pulls a value from the stack */
3428 #define PULL(v) v = pStack[++SP]
3430 /* Addressing Modes */
3432 /* first set - gets the value that's being addressed */
3434 #define Ad_VlIm() val = Rd(PC.W); PC.W++
3436 #define Ad_VlZp() final.W = Rd(PC.W); val = Zp(final.W); PC.W++
3438 #define Ad_VlZx() front.W = final.W = Rd(PC.W); final.B.l += X; \
3439 val = Zp(final.B.l); PC.W++
3441 #define Ad_VlZy() front.W = final.W = Rd(PC.W); final.B.l += Y; \
3442 val = Zp(final.B.l); PC.W++
3444 #define Ad_VlAb() final.W = RdWord(PC.W); val = Rd(final.W); PC.W += 2
3445 /*Absolute, X [uses extra cycle if crossed page]*/
3446 #define Ad_VlAx() front.W = final.W = RdWord(PC.W); final.W += X; PC.W += 2;\
3447 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3448 /*Absolute, X [uses extra cycle if crossed page]*/
3449 #define Ad_VlAy() front.W = final.W = RdWord(PC.W); final.W += Y; PC.W += 2;\
3450 if(front.B.h != final.B.h) nCPUCycle++; val = Rd(final.W)
3452 #define Ad_VlIx() front.W = final.W = Rd(PC.W); final.B.l += X; PC.W++; \
3453 final.W = ZpWord(final.B.l); val = Rd(final.W)
3454 /*(Indirect), Y [uses extra cycle if crossed page]*/
3455 #define Ad_VlIy() val = Rd(PC.W); front.W = final.W = ZpWord(val); PC.W++;\
3456 final.W += Y; if(final.B.h != front.B.h) nCPUCycle++; \
3457 front.W = val; val = Rd(final.W)
3459 /* second set - gets the ADDRESS that the mode is referring to (for operators
3460 * that write to memory) note that AbsoluteX, AbsoluteY, and
3461 * IndirectY modes do NOT check for page boundary crossing here
3462 * since that extra cycle isn't added for operators that write to
3463 * memory (it only applies to ones that only read from memory.. in
3464 * which case the 1st set should be used)
3467 #define Ad_AdZp() final.W = Rd(PC.W); PC.W++
3469 #define Ad_AdZx() final.W = front.W = Rd(PC.W); final.B.l += X; PC.W++
3471 #define Ad_AdZy() final.W = front.W = Rd(PC.W); final.B.l += Y; PC.W++
3473 #define Ad_AdAb() final.W = RdWord(PC.W); PC.W += 2
3475 #define Ad_AdAx() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3478 #define Ad_AdAy() front.W = final.W = RdWord(PC.W); PC.W += 2; \
3481 #define Ad_AdIx() front.W = final.W = Rd(PC.W); PC.W++; final.B.l += X; \
3482 final.W = ZpWord(final.B.l)
3484 #define Ad_AdIy() front.W = Rd(PC.W); final.W = ZpWord(front.W) + Y; \
3487 /* third set - reads memory, performs the desired operation on the value, then
3488 * writes back to memory
3489 * used for operators that directly change memory (ASL, INC, DEC, etc)
3492 #define MRW_Zp(cmd) Ad_AdZp(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3494 #define MRW_Zx(cmd) Ad_AdZx(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3496 #define MRW_Zy(cmd) Ad_AdZy(); val = Zp(final.W); cmd(val); WrZ(final.W,val)
3498 #define MRW_Ab(cmd) Ad_AdAb(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3500 #define MRW_Ax(cmd) Ad_AdAx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3502 #define MRW_Ay(cmd) Ad_AdAy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3504 #define MRW_Ix(cmd) Ad_AdIx(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3506 #define MRW_Iy(cmd) Ad_AdIy(); val = Rd(final.W); cmd(val); Wr(final.W,val)
3508 /* Relative modes are special in that they're only used by branch commands
3509 * this macro handles the jump, and should only be called if the branch
3510 * condition was true if the branch condition was false, the PC must be
3514 #define RelJmp(cond) val = Rd(PC.W); PC.W++; final.W = PC.W + (int8_t)(val);\
3516 nCPUCycle += ((final.B.h != PC.B.h) ? 2 : 1);\
3521 #define C_FLAG 0x01 /* carry flag */
3522 #define Z_FLAG 0x02 /* zero flag */
3523 #define I_FLAG 0x04 /* mask interrupt flag */
3524 #define D_FLAG 0x08 /* decimal flag (decimal mode is unsupported on
3526 #define B_FLAG 0x10 /* break flag (not really in the status register
3527 It's value in ST is never used. When ST is
3528 put in memory (by an interrupt or PHP), this
3529 flag is set only if BRK was called)
3530 ** also when PHP is called due to a bug */
3531 #define R_FLAG 0x20 /* reserved flag (not really in the register.
3532 It's value is never used.
3533 Whenever ST is put in memory,
3534 this flag is always set) */
3535 #define V_FLAG 0x40 /* overflow flag */
3536 #define N_FLAG 0x80 /* sign flag */
3541 /* the number of CPU cycles used for each instruction */
3542 static const uint8_t CPU_Cycles
[0x100] = {
3543 7,6,0,8,3,3,5,5,3,2,2,2,4,4,6,6,
3544 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3545 6,6,0,8,3,3,5,5,4,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,3,2,2,2,3,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,4,2,2,2,5,4,6,6,
3550 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
3551 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
3552 2,6,0,6,4,4,4,4,2,5,2,5,5,5,5,5,
3553 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4,
3554 2,5,0,5,4,4,4,4,2,4,2,4,4,4,4,4,
3555 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6,
3556 2,5,0,8,4,4,6,6,2,4,2,7,4,4,7,7,
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 };
3560 /* the status of the NZ flags for the given value */
3561 static const uint8_t NZTable
[0x100] = {
3562 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,
3563 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,
3564 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,
3565 0,0,0,0,0,0,0,0,0,0,0,
3566 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
3567 N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,N_FLAG
,
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
};
3579 /* A quick macro for working with the above table */
3580 #define UpdateNZ(v) ST = (ST & ~(N_FLAG|Z_FLAG)) | NZTable[v]
3586 * These opcodes perform the action with the given value (changing that
3587 * value if necessary). Registers and flags associated with the operation
3588 * are changed accordingly. There are a few exceptions which will be noted
3594 Adds the value to the accumulator with carry
3596 - Decimal mode not supported on the NES
3597 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3600 tw.W = A + val + (ST & C_FLAG); \
3601 ST = (ST & (I_FLAG|D_FLAG)) | tw.B.h | NZTable[tw.B.l] | \
3602 ( (0x80 & ~(A ^ val) & (A ^ tw.B.l)) ? V_FLAG : 0 ); \
3606 Combines the value with the accumulator using a bitwise AND operation
3613 Left shifts the value 1 bit. The bit that gets shifted out goes to
3615 Changes: value, NZC */
3616 #define ASL(value) \
3617 tw.W = value << 1; \
3618 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | tw.B.h | NZTable[tw.B.l]; \
3622 Compares memory with the accumulator with an AND operation, but changes
3624 The two high bits of memory get transferred to the status reg
3625 Z is set if the AND operation yielded zero, otherwise it's cleared
3628 ST = (ST & ~(N_FLAG|V_FLAG|Z_FLAG)) | (val & (N_FLAG|V_FLAG)) | \
3629 ((A & val) ? 0 : Z_FLAG)
3632 Compares memory with the given register with a subtraction operation.
3633 Flags are set accordingly depending on the result:
3634 Reg < Memory: Z=0, C=0
3635 Reg = Memory: Z=1, C=1
3636 Reg > Memory: Z=0, C=1
3637 N is set according to the result of the subtraction operation
3640 NOTE -- CMP, CPX, CPY all share this same routine, so the desired
3641 register (A, X, or Y respectively) must be given when calling
3642 this macro... as well as the memory to compare it with. */
3645 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | (tw.B.h ? 0 : C_FLAG) | \
3649 Decriments a value by one.
3650 Changes: value, NZ */
3651 #define DEC(value) \
3656 Combines a value with the accumulator using a bitwise exclusive-OR
3664 Incriments a value by one.
3665 Changes: value, NZ */
3666 #define INC(value) \
3671 Shifts value one bit to the right. Bit that gets shifted out goes to
3673 Changes: value, NZC */
3674 #define LSR(value) \
3675 tw.W = value >> 1; \
3676 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3681 Combines a value with the accumulator using a bitwise inclusive-OR
3689 Rotates a value one bit to the left:
3690 C <- 7<-6<-5<-4<-3<-2<-1<-0 <- C
3691 Changes: value, NZC */
3692 #define ROL(value) \
3693 tw.W = (value << 1) | (ST & 0x01); \
3694 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | tw.B.h; \
3698 Rotates a value one bit to the right:
3699 C -> 7->6->5->4->3->2->1->0 -> C
3700 Changes: value, NZC */
3701 #define ROR(value) \
3702 tw.W = (value >> 1) | (ST << 7); \
3703 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[tw.B.l] | \
3708 Subtracts a value from the accumulator with borrow (inverted carry)
3710 - Decimal mode not supported on the NES
3711 - Due to a bug, NVZ flags are not altered if the Decimal flag is on
3714 tw.W = A - val - ((ST & C_FLAG) ? 0 : 1); \
3715 ST = (ST & (I_FLAG|D_FLAG)) | (tw.B.h ? 0 : C_FLAG) | NZTable[tw.B.l] | \
3716 (((A ^ val) & (A ^ tw.B.l) & 0x80) ? V_FLAG : 0); \
3719 /* Undocumented Opcodes
3721 * These opcodes are not included in the official specifications. However,
3722 * some of the unused opcode values perform operations which have since been
3728 Left shifts a value, then ORs the result with the accumulator
3729 Changes: value, A, NZC */
3730 #define ASO(value) \
3731 tw.W = value << 1; \
3733 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3737 Roll memory left 1 bit, then AND the result with the accumulator
3738 Changes: value, A, NZC */
3739 #define RLA(value) \
3740 tw.W = (value << 1) | (ST & 0x01); \
3742 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | tw.B.h; \
3746 Right shifts a value one bit, then EORs the result with the accumulator
3747 Changes: value, A, NZC */
3748 #define LSE(value) \
3749 tw.W = value >> 1; \
3751 ST = (ST & ~(N_FLAG|Z_FLAG|C_FLAG)) | NZTable[A] | (value & 0x01); \
3755 Roll memory right one bit, then ADC the result
3756 Changes: value, A, NVZC */
3757 #define RRA(value) \
3758 tw.W = (value >> 1) | (ST << 7); \
3759 ST = (ST & ~C_FLAG) | (value & 0x01); \
3764 ANDs the contents of the X and A registers and stores the result
3766 Changes: value [DOES NOT CHANGE X, A, or any flags] */
3767 #define AXS(value) \
3771 Decriments a value and compares it with the A register.
3772 Changes: value, NZC */
3773 #define DCM(value) \
3778 Incriments a value then SBCs it
3779 Changes: value, A, NVZC */
3780 #define INS(value) \
3785 #define AXA(value) \
3786 value = A & X & (Rd(PC.W - 1) + 1)
3789 /* The 6502 emulation function! */
3796 uint32_t Emulate6502(uint32_t runto
)
3798 /* If the CPU is jammed... don't bother */
3802 register union TWIN tw
; /* used in calculations */
3803 register uint8_t ST
= regP
;
3804 register union TWIN PC
;
3806 register uint8_t A
= regA
;
3807 register uint8_t X
= regX
;
3808 register uint8_t Y
= regY
;
3813 uint32_t ret
= nCPUCycle
;
3817 /* Start the loop */
3819 while(nCPUCycle
< runto
)
3824 nCPUCycle
+= CPU_Cycles
[op
];
3827 /* Documented Opcodes first */
3829 /* Flag setting/clearing */
3830 case 0x18: ST
&= ~C_FLAG
; break; /* CLC */
3831 case 0x38: ST
|= C_FLAG
; break; /* SEC */
3832 case 0x58: ST
&= ~I_FLAG
; break; /* CLI */
3833 case 0x78: ST
|= I_FLAG
; break; /* SEI */
3834 case 0xB8: ST
&= ~V_FLAG
; break; /* CLV */
3835 case 0xD8: ST
&= ~D_FLAG
; break; /* CLD */
3836 case 0xF8: ST
|= D_FLAG
; break; /* SED */
3838 /* Branch commands */
3839 case 0x10: RelJmp(!(ST
& N_FLAG
)); break; /* BPL */
3840 case 0x30: RelJmp( (ST
& N_FLAG
)); break; /* BMI */
3841 case 0x50: RelJmp(!(ST
& V_FLAG
)); break; /* BVC */
3842 case 0x70: RelJmp( (ST
& V_FLAG
)); break; /* BVS */
3843 case 0x90: RelJmp(!(ST
& C_FLAG
)); break; /* BCC */
3844 case 0xB0: RelJmp( (ST
& C_FLAG
)); break; /* BCS */
3845 case 0xD0: RelJmp(!(ST
& Z_FLAG
)); break; /* BNE */
3846 case 0xF0: RelJmp( (ST
& Z_FLAG
)); break; /* BEQ */
3848 /* Direct stack alteration commands (push/pull commands) */
3849 case 0x08: PUSH(ST
| R_FLAG
| B_FLAG
); break; /* PHP */
3850 case 0x28: PULL(ST
); break; /* PLP */
3851 case 0x48: PUSH(A
); break; /* PHA */
3852 case 0x68: PULL(A
); UpdateNZ(A
); break; /* PLA */
3854 /* Register Transfers */
3855 case 0x8A: A
= X
; UpdateNZ(A
); break; /* TXA */
3856 case 0x98: A
= Y
; UpdateNZ(A
); break; /* TYA */
3857 case 0x9A: SP
= X
; break; /* TXS */
3858 case 0xA8: Y
= A
; UpdateNZ(A
); break; /* TAY */
3859 case 0xAA: X
= A
; UpdateNZ(A
); break; /* TAX */
3860 case 0xBA: X
= SP
; UpdateNZ(X
); break; /* TSX */
3862 /* Other commands */
3865 case 0x61: Ad_VlIx(); ADC(); break;
3866 case 0x65: Ad_VlZp(); ADC(); break;
3867 case 0x69: Ad_VlIm(); ADC(); break;
3868 case 0x6D: Ad_VlAb(); ADC(); break;
3869 case 0x71: Ad_VlIy(); ADC(); break;
3870 case 0x75: Ad_VlZx(); ADC(); break;
3871 case 0x79: Ad_VlAy(); ADC(); break;
3872 case 0x7D: Ad_VlAx(); ADC(); break;
3875 case 0x21: Ad_VlIx(); AND(); break;
3876 case 0x25: Ad_VlZp(); AND(); break;
3877 case 0x29: Ad_VlIm(); AND(); break;
3878 case 0x2D: Ad_VlAb(); AND(); break;
3879 case 0x31: Ad_VlIy(); AND(); break;
3880 case 0x35: Ad_VlZx(); AND(); break;
3881 case 0x39: Ad_VlAy(); AND(); break;
3882 case 0x3D: Ad_VlAx(); AND(); break;
3885 case 0x0A: ASL(A
); break;
3886 case 0x06: MRW_Zp(ASL
); break;
3887 case 0x0E: MRW_Ab(ASL
); break;
3888 case 0x16: MRW_Zx(ASL
); break;
3889 case 0x1E: MRW_Ax(ASL
); break;
3892 case 0x24: Ad_VlZp(); BIT(); break;
3893 case 0x2C: Ad_VlAb(); BIT(); break;
3899 PC
.W
++; /*BRK has a padding byte*/
3900 PUSH(PC
.B
.h
); /*push high byte of the return address*/
3901 PUSH(PC
.B
.l
); /*push low byte of return address*/
3902 PUSH(ST
| R_FLAG
| B_FLAG
); /*push processor status with R|B flags*/
3903 ST
|= I_FLAG
; /*mask interrupts*/
3904 PC
.W
= RdWord(0xFFFE); /*read the IRQ vector and jump to it*/
3906 /* extra check to make sure we didn't hit an infinite BRK loop */
3907 if(!Rd(PC
.W
)) /* next command will be BRK */
3909 /* the CPU will endlessly loop...
3910 just jam it to ease processing power */
3917 case 0xC1: Ad_VlIx(); CMP(A
); break;
3918 case 0xC5: Ad_VlZp(); CMP(A
); break;
3919 case 0xC9: Ad_VlIm(); CMP(A
); break;
3920 case 0xCD: Ad_VlAb(); CMP(A
); break;
3921 case 0xD1: Ad_VlIy(); CMP(A
); break;
3922 case 0xD5: Ad_VlZx(); CMP(A
); break;
3923 case 0xD9: Ad_VlAy(); CMP(A
); break;
3924 case 0xDD: Ad_VlAx(); CMP(A
); break;
3927 case 0xE0: Ad_VlIm(); CMP(X
); break;
3928 case 0xE4: Ad_VlZp(); CMP(X
); break;
3929 case 0xEC: Ad_VlAb(); CMP(X
); break;
3932 case 0xC0: Ad_VlIm(); CMP(Y
); break;
3933 case 0xC4: Ad_VlZp(); CMP(Y
); break;
3934 case 0xCC: Ad_VlAb(); CMP(Y
); break;
3937 case 0xCA: DEC(X
); break; /* DEX */
3938 case 0x88: DEC(Y
); break; /* DEY */
3939 case 0xC6: MRW_Zp(DEC
); break;
3940 case 0xCE: MRW_Ab(DEC
); break;
3941 case 0xD6: MRW_Zx(DEC
); break;
3942 case 0xDE: MRW_Ax(DEC
); break;
3945 case 0x41: Ad_VlIx(); EOR(); break;
3946 case 0x45: Ad_VlZp(); EOR(); break;
3947 case 0x49: Ad_VlIm(); EOR(); break;
3948 case 0x4D: Ad_VlAb(); EOR(); break;
3949 case 0x51: Ad_VlIy(); EOR(); break;
3950 case 0x55: Ad_VlZx(); EOR(); break;
3951 case 0x59: Ad_VlAy(); EOR(); break;
3952 case 0x5D: Ad_VlAx(); EOR(); break;
3955 case 0xE8: INC(X
); break; /* INX */
3956 case 0xC8: INC(Y
); break; /* INY */
3957 case 0xE6: MRW_Zp(INC
); break;
3958 case 0xEE: MRW_Ab(INC
); break;
3959 case 0xF6: MRW_Zx(INC
); break;
3960 case 0xFE: MRW_Ax(INC
); break;
3964 case 0x4C: final
.W
= RdWord(PC
.W
); PC
.W
= final
.W
; val
= 0; break;
3965 /* Indirect JMP -- must take caution:
3966 Indirection at 01FF will read from 01FF and 0100 (not 0200) */
3967 case 0x6C: front
.W
= final
.W
= RdWord(PC
.W
);
3968 PC
.B
.l
= Rd(final
.W
); final
.B
.l
++;
3969 PC
.B
.h
= Rd(final
.W
); final
.W
= PC
.W
;
3974 final
.W
= RdWord(PC
.W
);
3975 PC
.W
++; /* JSR only increments the return address by one.
3976 It's incremented again upon RTS */
3977 PUSH(PC
.B
.h
); /* push high byte of return address */
3978 PUSH(PC
.B
.l
); /* push low byte of return address */
3983 case 0xA1: Ad_VlIx(); A
= val
; UpdateNZ(A
); break;
3984 case 0xA5: Ad_VlZp(); A
= val
; UpdateNZ(A
); break;
3985 case 0xA9: Ad_VlIm(); A
= val
; UpdateNZ(A
); break;
3986 case 0xAD: Ad_VlAb(); A
= val
; UpdateNZ(A
); break;
3987 case 0xB1: Ad_VlIy(); A
= val
; UpdateNZ(A
); break;
3988 case 0xB5: Ad_VlZx(); A
= val
; UpdateNZ(A
); break;
3989 case 0xB9: Ad_VlAy(); A
= val
; UpdateNZ(A
); break;
3990 case 0xBD: Ad_VlAx(); A
= val
; UpdateNZ(A
); break;
3993 case 0xA2: Ad_VlIm(); X
= val
; UpdateNZ(X
); break;
3994 case 0xA6: Ad_VlZp(); X
= val
; UpdateNZ(X
); break;
3995 case 0xAE: Ad_VlAb(); X
= val
; UpdateNZ(X
); break;
3996 case 0xB6: Ad_VlZy(); X
= val
; UpdateNZ(X
); break;
3997 case 0xBE: Ad_VlAy(); X
= val
; UpdateNZ(X
); break;
4000 case 0xA0: Ad_VlIm(); Y
= val
; UpdateNZ(Y
); break;
4001 case 0xA4: Ad_VlZp(); Y
= val
; UpdateNZ(Y
); break;
4002 case 0xAC: Ad_VlAb(); Y
= val
; UpdateNZ(Y
); break;
4003 case 0xB4: Ad_VlZx(); Y
= val
; UpdateNZ(Y
); break;
4004 case 0xBC: Ad_VlAx(); Y
= val
; UpdateNZ(Y
); break;
4007 case 0x4A: LSR(A
); break;
4008 case 0x46: MRW_Zp(LSR
); break;
4009 case 0x4E: MRW_Ab(LSR
); break;
4010 case 0x56: MRW_Zx(LSR
); break;
4011 case 0x5E: MRW_Ax(LSR
); break;
4016 /* --- Undocumented ---
4017 These opcodes perform the same action as NOP */
4018 case 0x1A: case 0x3A: case 0x5A:
4019 case 0x7A: case 0xDA: case 0xFA: break;
4022 case 0x01: Ad_VlIx(); ORA(); break;
4023 case 0x05: Ad_VlZp(); ORA(); break;
4024 case 0x09: Ad_VlIm(); ORA(); break;
4025 case 0x0D: Ad_VlAb(); ORA(); break;
4026 case 0x11: Ad_VlIy(); ORA(); break;
4027 case 0x15: Ad_VlZx(); ORA(); break;
4028 case 0x19: Ad_VlAy(); ORA(); break;
4029 case 0x1D: Ad_VlAx(); ORA(); break;
4032 case 0x2A: ROL(A
); break;
4033 case 0x26: MRW_Zp(ROL
); break;
4034 case 0x2E: MRW_Ab(ROL
); break;
4035 case 0x36: MRW_Zx(ROL
); break;
4036 case 0x3E: MRW_Ax(ROL
); break;
4039 case 0x6A: ROR(A
); break;
4040 case 0x66: MRW_Zp(ROR
); break;
4041 case 0x6E: MRW_Ab(ROR
); break;
4042 case 0x76: MRW_Zx(ROR
); break;
4043 case 0x7E: MRW_Ax(ROR
); break;
4047 PULL(ST
); /*pull processor status*/
4048 PULL(PC
.B
.l
); /*pull low byte of return address*/
4049 PULL(PC
.B
.h
); /*pull high byte of return address*/
4056 PC
.W
++; /* the return address is one less of what it needs */
4060 case 0xE1: Ad_VlIx(); SBC(); break;
4061 case 0xE5: Ad_VlZp(); SBC(); break;
4062 /* - Undocumented - EB performs the same operation as SBC immediate */
4064 case 0xE9: Ad_VlIm(); SBC(); break;
4065 case 0xED: Ad_VlAb(); SBC(); break;
4066 case 0xF1: Ad_VlIy(); SBC(); break;
4067 case 0xF5: Ad_VlZx(); SBC(); break;
4068 case 0xF9: Ad_VlAy(); SBC(); break;
4069 case 0xFD: Ad_VlAx(); SBC(); break;
4072 case 0x81: Ad_AdIx(); val
= A
; Wr(final
.W
,A
); break;
4073 case 0x85: Ad_AdZp(); val
= A
; WrZ(final
.W
,A
); break;
4074 case 0x8D: Ad_AdAb(); val
= A
; Wr(final
.W
,A
); break;
4075 case 0x91: Ad_AdIy(); val
= A
; Wr(final
.W
,A
); break;
4076 case 0x95: Ad_AdZx(); val
= A
; WrZ(final
.W
,A
); break;
4077 case 0x99: Ad_AdAy(); val
= A
; Wr(final
.W
,A
); break;
4078 case 0x9D: Ad_AdAx(); val
= A
; Wr(final
.W
,A
); break;
4081 case 0x86: Ad_AdZp(); val
= X
; WrZ(final
.W
,X
); break;
4082 case 0x8E: Ad_AdAb(); val
= X
; Wr(final
.W
,X
); break;
4083 case 0x96: Ad_AdZy(); val
= X
; WrZ(final
.W
,X
); break;
4086 case 0x84: Ad_AdZp(); val
= Y
; WrZ(final
.W
,Y
); break;
4087 case 0x8C: Ad_AdAb(); val
= Y
; Wr(final
.W
,Y
); break;
4088 case 0x94: Ad_AdZx(); val
= Y
; WrZ(final
.W
,Y
); break;
4090 /* Undocumented Opcodes */
4092 case 0x03: if(bIgnoreIllegalOps
) break; MRW_Ix(ASO
); break;
4093 case 0x07: if(bIgnoreIllegalOps
) break; MRW_Zp(ASO
); break;
4094 case 0x0F: if(bIgnoreIllegalOps
) break; MRW_Ab(ASO
); break;
4095 case 0x13: if(bIgnoreIllegalOps
) break; MRW_Iy(ASO
); break;
4096 case 0x17: if(bIgnoreIllegalOps
) break; MRW_Zx(ASO
); break;
4097 case 0x1B: if(bIgnoreIllegalOps
) break; MRW_Ay(ASO
); break;
4098 case 0x1F: if(bIgnoreIllegalOps
) break; MRW_Ax(ASO
); break;
4101 case 0x23: if(bIgnoreIllegalOps
) break; MRW_Ix(RLA
); break;
4102 case 0x27: if(bIgnoreIllegalOps
) break; MRW_Zp(RLA
); break;
4103 case 0x2F: if(bIgnoreIllegalOps
) break; MRW_Ab(RLA
); break;
4104 case 0x33: if(bIgnoreIllegalOps
) break; MRW_Iy(RLA
); break;
4105 case 0x37: if(bIgnoreIllegalOps
) break; MRW_Zx(RLA
); break;
4106 case 0x3B: if(bIgnoreIllegalOps
) break; MRW_Ay(RLA
); break;
4107 case 0x3F: if(bIgnoreIllegalOps
) break; MRW_Ax(RLA
); break;
4110 case 0x43: if(bIgnoreIllegalOps
) break; MRW_Ix(LSE
); break;
4111 case 0x47: if(bIgnoreIllegalOps
) break; MRW_Zp(LSE
); break;
4112 case 0x4F: if(bIgnoreIllegalOps
) break; MRW_Ab(LSE
); break;
4113 case 0x53: if(bIgnoreIllegalOps
) break; MRW_Iy(LSE
); break;
4114 case 0x57: if(bIgnoreIllegalOps
) break; MRW_Zx(LSE
); break;
4115 case 0x5B: if(bIgnoreIllegalOps
) break; MRW_Ay(LSE
); break;
4116 case 0x5F: if(bIgnoreIllegalOps
) break; MRW_Ax(LSE
); break;
4119 case 0x63: if(bIgnoreIllegalOps
) break; MRW_Ix(RRA
); break;
4120 case 0x67: if(bIgnoreIllegalOps
) break; MRW_Zp(RRA
); break;
4121 case 0x6F: if(bIgnoreIllegalOps
) break; MRW_Ab(RRA
); break;
4122 case 0x73: if(bIgnoreIllegalOps
) break; MRW_Iy(RRA
); break;
4123 case 0x77: if(bIgnoreIllegalOps
) break; MRW_Zx(RRA
); break;
4124 case 0x7B: if(bIgnoreIllegalOps
) break; MRW_Ay(RRA
); break;
4125 case 0x7F: if(bIgnoreIllegalOps
) break; MRW_Ax(RRA
); break;
4128 case 0x83: if(bIgnoreIllegalOps
) break; MRW_Ix(AXS
); break;
4129 case 0x87: if(bIgnoreIllegalOps
) break; MRW_Zp(AXS
); break;
4130 case 0x8F: if(bIgnoreIllegalOps
) break; MRW_Ab(AXS
); break;
4131 case 0x97: if(bIgnoreIllegalOps
) break; MRW_Zy(AXS
); break;
4134 case 0xA3: if(bIgnoreIllegalOps
) break;
4135 Ad_VlIx(); X
= A
= val
; UpdateNZ(A
); break;
4136 case 0xA7: if(bIgnoreIllegalOps
) break;
4137 Ad_VlZp(); X
= A
= val
; UpdateNZ(A
); break;
4138 case 0xAF: if(bIgnoreIllegalOps
) break;
4139 Ad_VlAb(); X
= A
= val
; UpdateNZ(A
); break;
4140 case 0xB3: if(bIgnoreIllegalOps
) break;
4141 Ad_VlIy(); X
= A
= val
; UpdateNZ(A
); break;
4142 case 0xB7: if(bIgnoreIllegalOps
) break;
4143 Ad_VlZy(); X
= A
= val
; UpdateNZ(A
); break;
4144 case 0xBF: if(bIgnoreIllegalOps
) break;
4145 Ad_VlAy(); X
= A
= val
; UpdateNZ(A
); break;
4148 case 0xC3: if(bIgnoreIllegalOps
) break; MRW_Ix(DCM
); break;
4149 case 0xC7: if(bIgnoreIllegalOps
) break; MRW_Zp(DCM
); break;
4150 case 0xCF: if(bIgnoreIllegalOps
) break; MRW_Ab(DCM
); break;
4151 case 0xD3: if(bIgnoreIllegalOps
) break; MRW_Iy(DCM
); break;
4152 case 0xD7: if(bIgnoreIllegalOps
) break; MRW_Zx(DCM
); break;
4153 case 0xDB: if(bIgnoreIllegalOps
) break; MRW_Ay(DCM
); break;
4154 case 0xDF: if(bIgnoreIllegalOps
) break; MRW_Ax(DCM
); break;
4157 case 0xE3: if(bIgnoreIllegalOps
) break; MRW_Ix(INS
); break;
4158 case 0xE7: if(bIgnoreIllegalOps
) break; MRW_Zp(INS
); break;
4159 case 0xEF: if(bIgnoreIllegalOps
) break; MRW_Ab(INS
); break;
4160 case 0xF3: if(bIgnoreIllegalOps
) break; MRW_Iy(INS
); break;
4161 case 0xF7: if(bIgnoreIllegalOps
) break; MRW_Zx(INS
); break;
4162 case 0xFB: if(bIgnoreIllegalOps
) break; MRW_Ay(INS
); break;
4163 case 0xFF: if(bIgnoreIllegalOps
) break; MRW_Ax(INS
); break;
4166 AND Accumulator with memory and LSR the result */
4167 case 0x4B: if(bIgnoreIllegalOps
) break;
4168 Ad_VlIm(); A
&= val
; LSR(A
); break;
4171 ANDs memory with the Accumulator and RORs the result */
4172 case 0x6B: if(bIgnoreIllegalOps
) break;
4173 Ad_VlIm(); A
&= val
; ROR(A
); break;
4176 Transfers X -> A, then ANDs A with memory */
4177 case 0x8B: if(bIgnoreIllegalOps
) break;
4178 Ad_VlIm(); A
= X
& val
; UpdateNZ(A
); break;
4181 OR the Accumulator with #EE, AND Accumulator with Memory,
4183 case 0xAB: if(bIgnoreIllegalOps
) break;
4184 Ad_VlIm(); X
= (A
&= (val
| 0xEE));
4188 ANDs A and X registers (does not change A), subtracts memory
4189 from result (CMP style, not SBC style) result is stored in X */
4190 case 0xCB: if(bIgnoreIllegalOps
) break;
4191 Ad_VlIm(); tw
.W
= (X
& A
) - val
; X
= tw
.B
.l
;
4192 ST
= (ST
& ~(N_FLAG
|Z_FLAG
|C_FLAG
)) | NZTable
[X
] |
4193 (tw
.B
.h
? C_FLAG
: 0); break;
4195 Skip Byte... or DOP - Double No-Op
4196 These bytes do nothing, but take a parameter (which can be
4198 case 0x04: case 0x14: case 0x34: case 0x44: case 0x54: case 0x64:
4199 case 0x80: case 0x82: case 0x89: case 0xC2: case 0xD4: case 0xE2:
4201 if(bIgnoreIllegalOps
) break;
4202 PC
.W
++; /* skip unused byte */
4206 Swip Word... or TOP - Tripple No-Op
4207 These bytes are the same as SKB, only they take a 2 byte parameter.
4208 This can be ignored in some cases, but the read needs to be
4209 performed in a some cases because an extra clock cycle may be used
4211 /* Absolute address... no need for operator */
4213 if(bIgnoreIllegalOps
) break;
4215 /* Absolute X address... may cross page, have to perform the read */
4216 case 0x1C: case 0x3C: case 0x5C: case 0x7C: case 0xDC: case 0xFC:
4217 if(bIgnoreIllegalOps
) break;
4221 Jams up CPU operation */
4222 case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52:
4223 case 0x62: case 0x72: case 0x92: case 0xB2: case 0xD2: case 0xF2:
4224 /*it's not -really- jammed... only the NSF code has ended*/
4225 if(PC
.W
== 0x5004) bCPUJammed
= 2;
4228 if(bIgnoreIllegalOps
) break;
4235 if(bIgnoreIllegalOps
) break;
4237 SP
= A
& X
& (Rd(PC
.W
- 1) + 1);
4243 if(bIgnoreIllegalOps
) break;
4245 Y
&= (Rd(PC
.W
- 1) + 1);
4251 if(bIgnoreIllegalOps
) break;
4253 X
&= (Rd(PC
.W
- 1) + 1);
4258 case 0x93: if(bIgnoreIllegalOps
) break; MRW_Iy(AXA
); break;
4259 case 0x9F: if(bIgnoreIllegalOps
) break; MRW_Ay(AXA
); break;
4262 case 0x0B: case 0x2B:
4263 if(bIgnoreIllegalOps
) break;
4266 ST
= (ST
& ~(N_FLAG
|Z_FLAG
|C_FLAG
)) |
4267 NZTable
[A
] | ((A
& 0x80) ? C_FLAG
: 0);
4272 if(bIgnoreIllegalOps
) break;
4274 X
= A
= (SP
&= val
);
4290 return (nCPUCycle
- ret
);
4293 /****************** rockbox interface ******************/
4295 void set_codec_track(int t
, int d
) {
4296 int track
,fade
,def
=0;
4299 /* for REPEAT_ONE we disable track limits */
4300 if (ci
->global_settings
->repeat_mode
!=REPEAT_ONE
) {
4301 if (!bIsExtended
|| nTrackTime
[t
]==-1) {track
=60*2*1000; def
=1;}
4302 else track
=nTrackTime
[t
];
4303 if (!bIsExtended
|| nTrackFade
[t
]==-1) fade
=5*1000;
4304 else fade
=nTrackFade
[t
];
4305 nSilenceTrackMS
=5000;
4306 SetFadeTime(track
,track
+fade
, fNSFPlaybackSpeed
,def
);
4308 ci
->id3
->elapsed
=d
*1000; /* d is track no to display */
4311 /* this is the codec entry point */
4312 enum codec_status
codec_main(void)
4317 int endofstream
; /* end of stream flag */
4320 char last_path
[MAX_PATH
];
4323 /* we only render 16 bits */
4324 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 16);
4326 ci
->configure(DSP_SET_FREQUENCY
, 44100);
4327 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
4329 RebuildOutputTables();
4337 DEBUGF("NSF: next_track\n");
4341 DEBUGF("NSF: after init\n");
4344 /* wait for track info to load */
4345 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
4348 codec_set_replaygain(ci
->id3
);
4350 /* Read the entire file */
4351 DEBUGF("NSF: request file\n");
4353 buf
= ci
->request_buffer(&n
, ci
->filesize
);
4354 if (!buf
|| n
< (size_t)ci
->filesize
) {
4355 DEBUGF("NSF: file load failed\n");
4360 if(!NSFCore_Initialize()) {
4361 DEBUGF("NSF: NSFCore_Initialize failed\n"); return CODEC_ERROR
;}
4363 if(LoadFile(buf
,ci
->filesize
)) {
4364 DEBUGF("NSF: LoadFile failed\n"); return CODEC_ERROR
;}
4365 if(!SetPlaybackOptions(44100)) {
4366 DEBUGF("NSF: SetPlaybackOptions failed\n"); return CODEC_ERROR
;}
4367 if(!LoadNSF(nDataBufferSize
)) {
4368 DEBUGF("NSF: LoadNSF failed\n"); return CODEC_ERROR
;}
4370 ci
->id3
->title
=szGameTitle
;
4371 ci
->id3
->artist
=szArtist
;
4372 ci
->id3
->album
=szCopyright
;
4373 if (usingplaylist
) {
4374 ci
->id3
->length
=nPlaylistSize
*1000;
4376 ci
->id3
->length
=nTrackCount
*1000;
4379 if (!dontresettrack
||strcmp(ci
->id3
->path
,last_path
)) {
4380 /* if this is the first time we're seeing this file, or if we haven't
4381 been asked to preserve the track number, default to the proper
4384 ci
->global_settings
->repeat_mode
!=REPEAT_ONE
&& nPlaylistSize
>0) {
4385 /* decide to use the playlist */
4388 set_codec_track(nPlaylist
[0],0);
4390 /* simply use the initial track */
4391 track
=nInitialTrack
;
4392 set_codec_track(track
,track
);
4395 /* if we've already been running this file assume track is set
4397 if (usingplaylist
) set_codec_track(nPlaylist
[track
],track
);
4398 else set_codec_track(track
,track
);
4400 strcpy(last_path
,ci
->id3
->path
);
4402 /* The main decoder loop */
4406 reset_profile_timers();
4408 while (!endofstream
) {
4411 if (ci
->stop_codec
|| ci
->new_track
) {
4415 if (ci
->seek_time
>0) {
4416 track
=ci
->seek_time
/1000;
4417 if (usingplaylist
) {
4418 if (track
>=nPlaylistSize
) break;
4420 if (track
>=nTrackCount
) break;
4422 ci
->seek_complete();
4428 written
=GetSamples((uint8_t*)samples
,WAV_CHUNK_SIZE
/2);
4431 if (!written
|| SongCompleted()) {
4432 print_timers(last_path
,track
);
4433 reset_profile_timers();
4436 if (usingplaylist
) {
4437 if (track
>=nPlaylistSize
) break;
4439 if (track
>=nTrackCount
) break;
4445 ci
->pcmbuf_insert(samples
, NULL
, written
>> 1);
4448 print_timers(last_path
,track
);
4450 if (ci
->request_next_track()) {
4451 if (ci
->global_settings
->repeat_mode
==REPEAT_ONE
) {
4452 /* in repeat one mode just advance to the next track */
4454 if (track
>=nTrackCount
) track
=0;
4456 /* at this point we can't tell if another file has been selected */
4459 /* otherwise do a proper load of the next file */
4463 goto next_track
; /* when we fall through here we'll reload the file */