;;;;SM = mapper game loading
;=== Include MemoryMap, VectorTable, HeaderInfo ===
.INCLUDE "mapper.inc"

;=== Global Variables ===
.INCLUDE "variables.asm"


Main:
  SEP #$20     ; 8 bit Accumulator, 16 bit X/Y
  REP #$10

  lda #$FF
  sta cursorX
  lda #$F0
  sta cursorY
  jump jPrintClearScreen
  
 	SetCursorPos 0, 0

	;SetCursorPos 27, 1
	;PrintString "FPGA STATUS = "
  ;lda CONFIGREADSTATUS
  ;sta errorCode
  ;PrintHexNum errorCode
  lda #$00
  sta DMAWRITELO
  sta DMAWRITEHI
  sta DMAWRITEBANK   ;;read file to beginning
  
CopyGame:
  lda #<gameName
  sta strPtr
  lda #>gameName
  sta strPtr+1
  ldy #strPtr
  PrintString "\n  %s"
  PrintString "\nCopying SPC file..."
  wai
  
  lda gameCluster
  sta sourceCluster
  lda gameCluster+1
  sta sourceCluster+1
  lda gameCluster+2
  sta sourceCluster+2
  lda gameCluster+3
  sta sourceCluster+3
  stz sectorCounter
  stz bankCounter

  jump jCardReadFile


  
  ;;PrintString "\nPC = "
  lda #$25
  sta DMAWRITELO
  lda #$00
  sta DMAWRITEHI
  sta DMAWRITEBANK   ;;PC - $25/26
  lda DMAREADDATA
  sta audioPC
  lda DMAREADDATA
  sta audioPC+1
 ;;// PrintHexNum audioPC+1
 ;;// PrintHexNum audioPC

  ;;//PrintString "  A = "
  lda DMAREADDATA
  sta audioA
  ;;//PrintHexNum audioA  ;A = $27

 ;; //PrintString "  X = "
  lda DMAREADDATA
  sta audioX
  ;;//PrintHexNum audioX  ;X = $28

  ;;//PrintString "  Y = "
  lda DMAREADDATA
  sta audioY
 ;; //PrintHexNum audioY  ;Y = $29

  ;;//PrintString "  PSW = "
  lda DMAREADDATA
  sta audioPSW
  ;;//PrintHexNum audioPSW  ;PSW = $2A
  
  ;;//PrintString "  SP = "
  lda DMAREADDATA
  sta audioSP
  ;;//PrintHexNum audioSP  ;SP = $2B

  lda #$2E
  sta DMAWRITELO   ;;start of song title
  ldx #$0000
CopySongTitle:
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$20
  bne CopySongTitle
  lda #$00
  sta tempEntry, x
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
 	SetCursorPos 0, 0
  PrintString "\n\n\n\nSong:\n%s"



  ldx #$0000        ;;start of game title
CopyGameTitle:
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$20
  bne CopyGameTitle
  lda #$00
  sta tempEntry, x
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
  PrintString "\n\nFrom:\n%s"


  ldx #$0000
CopyDumper:      ;;start of dumper
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$10
  bne CopyDumper
  lda #$00
  sta tempEntry, x
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
  PrintString "\n\nDumped By:\n%s"


  ldx #$0000       
CopyComments:      ;;start of comments
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$20
  bne CopyComments
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
  PrintString "\n\nComments:\n%s"


  ldx #$0000       
CopyDate:      ;;start of date
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$0B
  bne CopyDate
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
  PrintString "\n\nDate: %s"
  
  ldx #$0000
CopyTime:
  lda DMAREADDATA
  and #$0F
  sta spcSecs
  lda DMAREADDATA
  and #$0F
  sta spcSecs+1
  lda DMAREADDATA
  and #$0F
  sta spcSecs+2

  PrintString "\n\nPlaying Time: "
  PrintHexNum spcSecs+2
  PrintHexNum spcSecs+1
  PrintHexNum spcSecs+0


  lda DMAREADDATA
  and #$0F
  sta fadeSecs
  lda DMAREADDATA
  and #$0F
  sta fadeSecs+1
  PrintString "\n Fading Time: "
  PrintHexNum fadeSecs+1
  PrintHexNum fadeSecs+0


  
  
CheckTime:
  lda spcSecs
  bne CheckTimeDone 
  lda spcSecs+1
  bne CheckTimeDone  
  lda spcSecs+2
  bne CheckTimeDone  
CheckTimeFill:
  lda #$09
  sta spcSecs+0
  sta spcSecs+1
  sta spcSecs+2
CheckTimeDone:



AddFadeTime1:
  lda fadeSecs
  clc
  adc spcSecs
  sta spcSecs
  cmp #$0A
  bcs AddFadeTime1Overflow
  jmp AddFadeTime1Done
AddFadeTime1Overflow:
  lda spcSecs
  sec
  sbc #$0A
  sta spcSecs
  inc fadeSecs+1
AddFadeTime1Done:
AddFadeTime2:
  lda fadeSecs+1
  clc
  adc spcSecs+1
  sta spcSecs+1
  cmp #$0A
  bcs AddFadeTime2Overflow
  jmp AddFadeTime2Done
AddFadeTime2Overflow:
  lda spcSecs+1
  sec
  sbc #$0A
  sta spcSecs+1
  lda spcSecs+2
  cmp #$09
  beq AddFadeTime2Done
  inc spcSecs+2
AddFadeTime2Done:


  
  PrintString "\n  Total Time: "
  lda spcSecs+2
  and #$0F
  sta errorCode
  PrintHexNum errorCode
  PrintString ":"
  lda spcSecs+1
  and #$0F
  asl a
  asl a
  asl a
  asl a
  sta errorCode
  lda spcSecs
  and #$0F
  ora errorCode
  sta errorCode
  PrintHexNum errorCode
  
  
  
  lda #$B1
  sta DMAWRITELO   ;;start of artist
  ldx #$0000
CopyArtist:
  lda DMAREADDATA
  sta tempEntry, x
  inx
  cpx #$20
  bne CopyArtist
  lda #$00
  sta tempEntry, x
  lda #<tempEntry
  sta strPtr
  lda #>tempEntry
  sta strPtr+1
  ldy #strPtr
  PrintString "\n\nArtist:\n%s"

 	SetCursorPos 0, 0
  PrintString "\n\nLoading SPC700..."
  jsr LoadSPC
 	SetCursorPos 0, 0
  PrintString "\n\nSPC playing    "

  stz spcTimer
  stz spcTimer+1
  stz spcTimer+2
  stz spcTimer+3
  lda #$00
  sta Joy1Press+1
  
ForeverLoop:
  wai
 	SetCursorPos 0, 0
  PrintString "\n\nSPC playing    "

  lda spcTimer+3
  and #$0F
  sta errorCode
  PrintHexNum errorCode
  PrintString ":"
  lda spcTimer+2
  and #$0F
  asl a
  asl a
  asl a
  asl a
  sta errorCode
  lda spcTimer+1
  and #$0F
  ora errorCode
  sta errorCode
  PrintHexNum errorCode   ;;display corrected 00:00 time

IncTimer:
  lda spcTimer
  clc
  adc #$01
  sta spcTimer
  cmp #60
  bne CheckTimer    ;;frames
  lda #$00
  sta spcTimer
  
IncTimerSecs:
  lda spcTimer+1    ;;secs
  clc
  adc #$01
  sta spcTimer+1
  cmp #$0A
  bne CheckTimer
IncTimerTens:
  lda #$00
  sta spcTimer+1
  lda spcTimer+2    ;;tens
  clc
  adc #$01
  sta spcTimer+2
  cmp #$06
  bne CheckTimer
IncTimerMins:  
  lda #$00
  sta spcTimer+2
  lda spcTimer+3    ;;mins
  clc
  adc #$01
  sta spcTimer+3

CheckTimer:
  lda spcTimer+1
  cmp spcSecs
  bne StartCheck
  lda spcTimer+2
  cmp spcSecs+1
  bne StartCheck
  lda spcTimer+3
  cmp spcSecs+2
  bne StartCheck
;  jmp ResetSystem

StartCheck:
  lda Joy1Press+1         ;;check for start button  
  and #%00010000
  beq  StartCheckDone
                        ;;start pressed, reset to intro
ResetSystem:
  lda #%10000001
  sta CONFIGWRITESTATUS   ;;WRITE RESET HERE stay in boot mode
  PrintString "reset"

StartCheckDone:
  jmp ForeverLoop
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
;;;spc player
.define AUDIO_R0 $2140
.define AUDIO_R1 $2141
.define AUDIO_R2 $2142
.define AUDIO_R3 $2143

.define XY_8BIT $10
.define A_8BIT  $20

 ; The length of our init routine in bytes
.define SPC_INIT_CODE_LENGTH $27
 
 ; The length of our fastloader routine in bytes
.define SPC_FASL_LENGTH	   $33


.define spcFreeAddr $ff70
 
 .macro waitForAudio0M
 	sta	tempheader
 	-: 	cmp AUDIO_R0
 	bne 	-
 .endm

;;;spc player







.macro sendMusicBlockM ; srcSeg srcAddr destAddr len
  ; Store the source address \1:\2 in sourceAddr.
  lda     #\1
  sta     sourceBank
  lda     #\2
  sta     sourceHi
  lda     #\3
  sta     sourceLo

  ; Store the destination address in x.
  ; Store the length in y.
  lda #\4
  sta destHi
  lda #\5
  sta destLo

  lda #\6
  sta sourceBytes16+1
  lda #\7
  sta sourceBytes16
  jsr     CopyBlockToSPC
.endm



.macro sendMusicBlockMDMA ; srcSeg srcAddr destAddr len
  ; Store the source address \1:\2 in sourceAddr.
  lda     #\1
  sta     sourceBank
  lda     #\2
  sta     sourceHi
  lda     #\3
  sta     sourceLo

  ; Store the destination address in x.
  ; Store the length in y.
  lda #\4
  sta destHi
  lda #\5
  sta destLo

  lda #\6
  sta sourceBytes16+1
  lda #\7
  sta sourceBytes16

  jsr     CopyBlockToSPCDMA
.endm


.macro startSPCExecM ; startAddr
  ldx     #\1
  jsr     StartSPCExec
.endm





LoadSPC:

  wai

 	; Make sure echo is off 
 	lda	#$6c		; Register $6c (FLG)
 	sta.l	$7f0100
 	lda	#$20		; Bit 5 on (~ECEN)	; 
 	sta.l	$7f0101
 	sendMusicBlockM $7f $01 $00 $00 $f2 $00 $02



  lda #$01
  sta DMAWRITEBANK  ;;EDL at 01 01 7D
  lda #$01
  sta DMAWRITEHI
  lda #$7D
  sta DMAWRITELO
  ;;lda DMAREADDATA
  
  lda #20   ;;wait 1/3 seconds
-:
 	wai
 	dec	a   ;;wait for echo frames  
 	bne	-


  stz     $4200   ; Disable NMI
  sei             ; Disable IRQ

  ; Build code to initialize registers.
  jsr     MakeSPCInitCode

  ; Initialize DSP registers.
  jsr     InitDSP


  ;;skip first 2 bytes 
  sendMusicBlockMDMA $00 $01 $02   $00 $02   $00 $EE   ;;copy 02-EF
  ;                   source          dest    leng
;  PrintString "\n0002-00EF"

  ;;skip F0 test register

  ;do F1 later

  ;;skip F2 F3 dsp ports
  ;;skip  F4 F5 F6 F7 io ports

  ; Copy data tom SPC RAM addresses 00f8..00fc	
  sendMusicBlockMDMA $00 $01 $f8   $00 $f8  $00 $05
;  PrintString "\n00F8-00FC"


  sendMusicBlockMDMA $00 $02 $00   $01 $00   $FE $C0   ;;copy 0100 to ffbf (dont overwrite ipl)
  ;                   source         dest     length
;  PrintString "\n0100-FFBF"



  ; Copy init code to some region of SPC memory that we hope isn't in use.
  sendMusicBlockM $7f $01 $00   $ff $70    $00 $1c
;  PrintString "\ninit sent"




  ; Start SPC execution at init code region.
  startSPCExecM spcFreeAddr
;  PrintString "\nexec started"


  cli             ; Enable IRQ
  lda     #$81
  sta     $4200

  rts








InitDSP:
  ldx     #$007F              ; Reset DSP address counter.
   
InitDSPLoop:                   ;;copy one DSP register to $7F0100
  lda #$01
  sta DMAWRITEBANK            ;;DSP registers at $0101xx
  sta DMAWRITEHI

  txa
  sta DMAWRITELO
  lda DMAREADDATA
  sta errorCode

  txa                         ; Write DSP address register byte.
  sta $7f0100 
  lda errorCode          
  sta $7f0101       
  phx                         ; Save x on the stack.
  phy
  
	cpy	#$006c
	beq	skipreg    ;;skip flag register
	cpy	#$004c
	beq	skipreg    ;;skip voices on KON
	cpy	#$005c      ;set all voices off KOFF
	bne	+
	lda	#$ff
	sta	$7f0101
+:

  ; Send the address and data bytes to the DSP memory-mapped registers.
  sendMusicBlockM $7f $01 $00   $00 $f2    $00 $02

skipreg:
  ply
  plx


  dex
  cpx #$FFFF
  bne InitDSPLoop
  rts   






   
   
   
   
   
   
   
   

MakeSPCInitCode:
  lda	#$00
  ldx	#$0000		; Make sure A and X are both clear

;  lda	spcSongNr
;  asl	a
;  asl	a
;  asl	a
;  tax			; x = spcSongNr * 8

  ; Write code to set [00] byte.
  lda     #$8f        		; mov dp,#imm
  sta.l   $7f0100
  
  lda #$00
  sta DMAWRITEBANK  ;;00 byte at 00 01 00
  lda #$01
  sta DMAWRITEHI
  lda #$00
  sta DMAWRITELO
  lda DMAREADDATA
;  lda.l	$7f0000
  sta.l   $7f0101
  lda     #$00
  sta.l   $7f0102

  ; Write code to set [01] byte.
  lda     #$8f        		; mov dp,#imm
  sta.l   $7f0103
  lda DMAREADDATA
;  lda.l	$7f0001
  sta.l   $7f0104
  lda     #$01
  sta.l   $7f0105

  ; Write code to set s.
  lda     #$cd        		; mov x,#imm
  sta.l   $7f0106
  lda.l   audioSP  	; x init value	
  sta.l   $7f0107
  lda     #$bd        		; mov sp,x
  sta.l   $7f0108

  ; Write code to push psw
  lda     #$cd        		; mov x,#imm
  sta.l   $7f0109
  lda.l   audioPSW   	; psw init value
  sta.l   $7f010a
  lda     #$4d       		; push x
  sta.l   $7f010b




  ; Write code to set [$f0]
  lda	#$8f			; mov dp,#imm
  sta.l   $7f010c
  lda	#$0a
  sta.l	$7f010d
  lda	#$f0
  sta.l	$7f010e

  ; Write code to set [$f1] 
  lda     #$8f        		; mov dp,#imm
  sta.l   $7f010f

  lda #$00
  sta DMAWRITEBANK    ;;00 01 F1
  lda #$01
  sta DMAWRITEHI
  lda #$F1
  sta DMAWRITELO
  lda DMAREADDATA
;  lda.l	$7f00f1
  and	#$07			; Only keep the timer flags
  ora	#$80      ;;keep ipl enabled
  sta.l	$7f0110
  lda	#$f1		
  sta.l	$7f0111

  ; Write code to set a.
  lda     #$e8        		; mov a,#imm
  sta.l   $7f0112 
  lda.l   audioA 
  sta.l   $7f0113 

  ; Write code to set x.
  lda     #$cd       		; mov x,#imm
  sta.l   $7f0114 
  lda.l   audioX 
  sta.l   $7f0115 

  ; Write code to set y.
  lda     #$8d        		; mov y,#imm
  sta.l   $7f0116 
  lda.l   audioY
  sta.l   $7f0117 


	; Write code to set DSP reg $6c (FLG)
	lda	#$8f
	sta.l   $7f0118
	lda	#$6c
	sta.l   $7f0119
	lda	#$f2
	sta.l   $7f011a
	lda	#$8f
	sta.l   $7f011b
  lda #$01
  sta DMAWRITEBANK    ;;flg register at 01016c
  lda #$01
  sta DMAWRITEHI
  lda #$6C
  sta DMAWRITELO
  lda DMAREADDATA

;	lda.l   SPC_REG_ADDR+$406c
	sta.l   $7f011c
	lda	#$f3
	sta.l   $7f011d



  ; Write code to pull psw.
  lda     #$8e        		; pop psw
  sta.l   $7f0118 

  ; Write code to jump.
  lda     #$5f        		; jmp labs
  sta.l   $7f0119 
  lda.l   audioPC
  sta.l   $7f011a 
  lda.l   audioPC+1
  sta.l   $7f011b 
  rts






CopyBlockToSPC:
  ; Wait until audio0 is $aa
	lda     #$aa
	waitForAudio0M

  ldx destLo
	stx     AUDIO_R2		; Write it to APU Port2 as well
	
	; Transfer count to x.
  ldx sourceBytes16

 	; Send $01cc to AUDIO0 and wait for echo.
	lda	#$01
	sta     AUDIO_R1
	lda	#$cc
	sta     AUDIO_R0
	waitForAudio0M


transfer_blocks_loop:

	; Zero counter.
	ldy     #$0000
 CopyBlockToSPC_loop:
 	cpy	#$00E0			; Have we finished one chunk yet?
 	beq	transfer_blocks_next
 	
	lda     [sourceLo],y

	sta	AUDIO_R1
	
	; Counter -> A
	tya

	sta	AUDIO_R0

	; Wait for counter to echo back.
	waitForAudio0M

	; Update counter and number of bytes left to send.
	iny
	dex
	bne     CopyBlockToSPC_loop
 	jmp	transfer_blocks_done
transfer_blocks_next:
  lda destLo
  clc
  adc #$E0
  sta destLo
  lda destLo+1
  adc #$00
  sta destLo+1

  phx
  ldx destLo
 	stx     AUDIO_R2		; And write it to APU Port2
 	plx
 	
 	lda	#$01
 	sta	AUDIO_R1
 	lda	#$E2			; By adding 2 to the last value written we tell the SPC we're done with this chunk and want to start over
 	sta	AUDIO_R0
 	waitForAudio0M
 	
 	; Add $e0 to the source address as well
 	lda	sourceLo
 	clc
 	adc	#$E0
 	sta	sourceLo
  lda sourceLo+1
  adc #$00
  sta sourceLo+1
 	
 	jmp 	transfer_blocks_loop
 	
 transfer_blocks_done:
 	
	; Send the start of IPL ROM send routine as starting address.
	ldx     #$ffc9
	stx     AUDIO_R2
	
	; Tell the SPC we're done transfering for now
	lda     #0
	sta	AUDIO_R1
	lda	tempheader	; This value is filled out by waitForAudio0M
	clc
	adc	#$02		
	sta	AUDIO_R0

	; Wait for counter to echo back.
	waitForAudio0M

	rts



































	; Store the destination address in x.
	; Store the length in y.
 CopyBlockToSPCDMA:
 	
	; Wait until audio0 is $aa
	lda     #$AA
	waitForAudio0M

  ldx destLo
	stx     AUDIO_R2		; Write it to APU Port2 as well
	
	; Transfer count to x.
	ldx sourceBytes16

 	; Send $01cc to AUDIO0 and wait for echo.
	lda	#$01
	sta     AUDIO_R1
	lda	#$cc
	sta     AUDIO_R0
	waitForAudio0M

  lda sourceBank
  sta DMAWRITEBANK
  lda sourceHi
  sta DMAWRITEHI
  lda sourceLo
  sta DMAWRITELO

transfer_blocks_loopDMA:

	; Zero counter.
	ldy     #$0000
 CopyBlockToSPC_loopDMA:
 	cpy	#$00E0			; Have we finished one chunk yet?
 	beq	transfer_blocks_nextDMA
 	
  lda DMAREADDATA

	sta	AUDIO_R1
	
	; Counter -> A
	tya

	sta	AUDIO_R0

	; Wait for counter to echo back.
	waitForAudio0M

	; Update counter and number of bytes left to send.
	iny
	dex
	bne     CopyBlockToSPC_loopDMA
 	jmp	transfer_blocks_doneDMA
 transfer_blocks_nextDMA:

  lda destLo
  clc
  adc #$E0
  sta destLo
  lda destLo+1
  adc #$00
  sta destLo+1

  phx
  ldx destLo
 	stx     AUDIO_R2		; And write it to APU Port2
 	plx
  
 	lda	#$01
 	sta	AUDIO_R1
 	lda	#$E2			; By adding 2 to the last value written we tell the SPC we're done with this chunk and want to start over
 	sta	AUDIO_R0
 	waitForAudio0M

 	jmp 	transfer_blocks_loopDMA
 	
 transfer_blocks_doneDMA: 	
	; Send the start of IPL ROM send routine as starting address.
	ldx     #$ffc9
	stx     AUDIO_R2
	
	; Tell the SPC we're done transfering for now
	lda     #0
	sta	AUDIO_R1
	lda	tempheader	; This value is filled out by waitForAudio0M
	clc
	adc	#$02		
	sta	AUDIO_R0

	; Wait for counter to echo back.
	waitForAudio0M
	rts
  
  
  
  

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

StartSPCExec:
  ; Starting address is in x.
  lda #$00
  sta DMAWRITEBANK
  sta DMAWRITEHI
  lda #$F5
  sta DMAWRITELO
  lda DMAREADDATA
  sta errorCode
  lda DMAREADDATA
  sta errorCode+1
  lda DMAREADDATA
  sta errorCode+2
  lda DMAREADDATA   ;;read io ports from spc
  sta errorCode+3

  ; Wait until audio0 is 0xbbaa
  lda     #$aa
  waitForAudio0M

  ; Send the destination address to AUDIO2.
  stx     AUDIO_R2

  ; Send $00cc to AUDIO0 and wait for echo.
  lda     #$00
  sta     AUDIO_R1
  lda     #$cc
  sta     AUDIO_R0
  waitForAudio0M

  ;;init io ports
  lda errorCode+3
  sta AUDIO_R3
  lda errorCode+2
  sta AUDIO_R2
  lda errorCode+1
  sta AUDIO_R1
  lda errorCode+0
  sta AUDIO_R0

   rts
