;NSF Mapper
;R $3E00-$3E01 - INIT address
;R $3E02-$3E03 - PLAY address
;R $3E04/$3E06 - NTSC speed value
;R $3E05/$3E07 - PAL speed value
;R $3E08-$3E0F - Initial bankswitch values
;R $3E10 - Song Number (start at 0)
;R $3E11 - NTSC/PAL setting (0 for NTSC, 1 for PAL)
;W $3E10-$3E11 - IRQ counter (for PLAY)
;R $3E12 - IRQ status (0=INIT, 1=STOP, 2+=PLAY)
;W $3E12 - IRQ enable (for PLAY)
;R $3E13 - Sound chip info
;W $3E13 - clear watchdog timer

.org $3F00
.db $FF,$FF,$FF			;pad to 256 bytes
stop:		JSR silence	;silence extra channels, kill play timer and silence internal sound
reset:		SEI
		LDX #$FF
		STX $4017	;kill frame IRQs
		INX
		STX $4015	;silence all sound channels
		STX $2000	;we don't rely on the presence of a PPU
		STX $2001	;but we don't want it getting in the way
		STX $3E12	;kill PLAY timer
		CLI
loop:		JMP loop

irq:		PHA
		TXA
		PHA
		TYA
		PHA
		LDX $3E12	;check IRQ status
		BEQ init
		DEX
		BEQ stop	;"Proper" way to play a tune
		JSR song_play	;1) Call the play address of the music at periodic intervals determined by the speed words.
		PLA
		TAY
		PLA
		TAX
		PLA
		RTI

.module	silence
silence:	LDA $3E13	;X=0 coming in, must also be coming out
		LSR A
		BCC _1
		STX $9002
		STX $A002
		STX $B002	;stop VRC6
_1:		LSR A
		BCC _2
		LDY #$20
__2:		STY $9010
		STX $9030	;stop VRC7
		INY
		CPY #$26
		BNE __2
_2:		LSR A
		BCC _3
		LDY #$80
		STY $4083
		STY $4087
		STY $4089	;stop FDS
_3:		LSR A
		BCC _4
		STX $5015	;stop MMC5
_4:		LSR A
		BCC _5
		DEX
		STX $F800
		INX
		STX $4800	;stop Namco-106
_5:		LSR A
		BCC _6
		LDY #$07
		STY $C000
		STY $E000	;stop FME-7
_6:		RTS

.module	init			;"Proper" way to init a tune
init:		JSR silence
		TXA		;(X=0)
		DEX
		TXS		;clear the stack
		STX $5FF7	;1.5) Map RAM to $6000-$7FFF
		DEX
		STX $5FF6	;(banks FE/FF are treated as RAM)

		LDX #$7F
		STA $00
		STX $01
		TAY
		LDX #$27
_1:		STA ($00),Y	;1) Clear all RAM at $0000-$07FF.
		INY		;2) Clear all RAM at $6000-$7FFF.
		BNE _1
		DEX
		BMI _2
		DEC $01
		CPX #$07
		BNE _1
		STX $01
		BEQ _1

_2:		LDX #$14
_3:		DEX
		STA $4000,X	;3) Init the sound registers by writing $00 to $4000-$4013
		BNE _3

		LDX #$07
_4:		LDA $3E08,X	;5) If this is a banked tune, load the bank values from the header into $5FF8-$5FFF.
		STA $5FF8,X	;For this player, *all* tunes are considered banked (the loader will fill in appropriate values)
		DEX
		BPL _4

		LDY #$0F	;4) Set volume register $4015 to $0F.
		STY $4015

		LDA $3E13	;For FDS games, banks E/F also get mapped to 6/7
		AND #$04	;For non-FDS games, we don't want to do this
		BEQ _6
		LDA $3E0E	;if these are zero, let's leave them as plain RAM
		BEQ _5
		STA $5FF6
_5:		LDA $3E0F	;TODO - need to allow FDS NSF data to be writeable
		BEQ _6
		STA $5FF7

_6:		LDX $3E11	;4.5) Set up the PLAY timer. Which word to use is determined by which mode you are in - PAL or NTSC.
		LDA $3E04,X
		STA $3E10
		LDA $3E06,X
		STA $3E11
		STY $3E12
		LDA $3E12	;if we have a pending IRQ here, we need to cancel it NOW
		CLI		;re-enable interrupts now - this way, we can allow the init routine to not return (ex: for raw PCM)

		LDA $3E10	;6) Set the accumulator and X registers for the desired song.
		JSR song_init	;7) Call the music init routine.
		STA $3E13	;kill the watchdog timer (and fire a 'Play' interrupt after 1 frame; otherwise, it'll wait 4 frames)
		JMP loop	;we don't actually RTI from here; this way, the init code is faster

.module	song
song_init:	JMP ($3E00)
song_play:	JMP ($3E02)
.dw reset,irq	;no NMI vector
.end
