spcplay.a65 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. #include "memmap.i65"
  2. ; SPC Player
  3. ; SPC700 transfer and IO routines by Shay Green <gblargg@gmail.com>
  4. spcplayer:
  5. php
  6. sep #$30 : .as : .xs
  7. ldx #$0a ; Check if SPC header is present
  8. -
  9. lda @SPC_HEADER,x
  10. cmp @text_spcid,x
  11. beq +
  12. jmp spc_exit
  13. +
  14. dey
  15. bne -
  16. rep #$10 : .xl ; Now draw lots of stuff
  17. stz bar_wl
  18. dec bar_wl
  19. stz bar_xl
  20. dec bar_xl
  21. stz bar_yl
  22. dec bar_yl
  23. jsr backup_screen
  24. lda #^text_spcplay ; Loading window
  25. sta window_tbank
  26. ldx #!text_spcplay
  27. stx window_taddr
  28. lda @spcplay_win_x
  29. sta window_x
  30. lda @spcplay_win_y
  31. sta window_y
  32. lda @spcplay_win_w
  33. sta window_w
  34. lda @spcplay_win_h
  35. sta window_h
  36. jsr draw_window
  37. lda #^text_spcload ; Loading text
  38. ldx #!text_spcload
  39. sta print_bank
  40. stx print_src
  41. stz print_pal
  42. lda #29
  43. sta print_count
  44. lda #17
  45. sta print_y
  46. lda #17
  47. sta print_x
  48. jsr hiprint
  49. stz isr_done
  50. -
  51. lda isr_done ; Wait until text is being printed...
  52. beq -
  53. jsr spc700_load ; Load SPC into SPC700
  54. lda #^text_spcplay
  55. sta window_tbank
  56. ldx #!text_spcplay
  57. stx window_taddr
  58. lda @spcstart_win_x
  59. sta window_x
  60. lda @spcstart_win_y
  61. sta window_y
  62. lda @spcstart_win_w
  63. sta window_w
  64. lda @spcstart_win_h
  65. sta window_h
  66. jsr draw_window
  67. lda #^text_spcstarta
  68. ldx #!text_spcstarta
  69. sta print_bank
  70. stx print_src
  71. lda #$01
  72. sta print_pal
  73. lda #30
  74. sta print_count
  75. lda #15
  76. sta print_y
  77. lda #17
  78. sta print_x
  79. jsr hiprint
  80. lda #^text_spcstartb
  81. ldx #!text_spcstartb
  82. sta print_bank
  83. stx print_src
  84. lda #$01
  85. sta print_pal
  86. lda #07
  87. sta print_count
  88. lda #17
  89. sta print_y
  90. lda #12
  91. sta print_x
  92. jsr hiprint
  93. lda #$fe
  94. ldx #$004e
  95. sta print_bank
  96. stx print_src
  97. stz print_pal
  98. lda #32
  99. sta print_count
  100. lda #17
  101. sta print_y
  102. lda #20
  103. sta print_x
  104. jsr hiprint
  105. lda #^text_spcstartc
  106. ldx #!text_spcstartc
  107. sta print_bank
  108. stx print_src
  109. lda #$01
  110. sta print_pal
  111. lda #07
  112. sta print_count
  113. lda #18
  114. sta print_y
  115. lda #12
  116. sta print_x
  117. jsr hiprint
  118. lda #$fe
  119. ldx #$002e
  120. sta print_bank
  121. stx print_src
  122. stz print_pal
  123. lda #32
  124. sta print_count
  125. lda #18
  126. sta print_y
  127. lda #20
  128. sta print_x
  129. jsr hiprint
  130. lda #^text_spcstartd
  131. ldx #!text_spcstartd
  132. sta print_bank
  133. stx print_src
  134. lda #$01
  135. sta print_pal
  136. lda #07
  137. sta print_count
  138. lda #19
  139. sta print_y
  140. lda #12
  141. sta print_x
  142. jsr hiprint
  143. lda #$fe
  144. ldx #$00b0
  145. sta longptr+2
  146. sta print_bank
  147. stx longptr
  148. ldy #$00
  149. lda [longptr], y
  150. cmp #$41
  151. bpl +
  152. inx
  153. + stx print_src
  154. stz print_pal
  155. lda #32
  156. sta print_count
  157. lda #19
  158. sta print_y
  159. lda #20
  160. sta print_x
  161. jsr hiprint
  162. spc_playloop:
  163. lda isr_done ; SPC player loop
  164. lsr
  165. bcc spc_playloop
  166. jsr printtime
  167. stz isr_done
  168. jsr read_pad
  169. lda #$80
  170. and pad1trig+1
  171. bne spc_key_b
  172. bra spc_playloop
  173. spc_key_b:
  174. rep #$20 : .al
  175. tsc
  176. sta saved_sp ; Save SP for later re-entry
  177. lda #$fa50 ; Write reset signature
  178. sta @warm_signature
  179. sep #$20 : .as
  180. sei ; Blank screen & issue CMD_RESET command to Microcontroller...
  181. stz $2100 ; ...this is required, because there is no other way to stop S-SMP & S-DSP
  182. lda #CMD_RESET
  183. sta @MCU_CMD
  184. -
  185. bra - ; At this point, the SNES waits for an external reset from the Microcontroller
  186. spc_exit: ; Return from player in case of wrong SPC file data
  187. plp
  188. rts
  189. ;---------------------------------------
  190. spc700_load:
  191. php
  192. sep #$20 : .as
  193. rep #$10 : .xl
  194. sei ; Disable NMI & IRQ
  195. stz $4200 ; The SPC player code is really timing sensitive ;)
  196. jsr upload_dsp_regs ; Upload S-DSP registers
  197. jsr upload_high_ram ; Upload 63.5K of SPC700 ram
  198. jsr upload_low_ram ; Upload rest of ram
  199. jsr restore_final ; Restore SPC700 state & start execution
  200. lda #$81 ; VBlank NMI + Auto Joypad Read
  201. sta $4200 ; enable V-BLANK NMI
  202. cli
  203. plp
  204. rts
  205. ;---------------------------------------
  206. ; Uploads DSP registers and some other setup code
  207. upload_dsp_regs:
  208. ; ---- Begin upload
  209. ldy #$0002
  210. jsr spc_begin_upload
  211. ; ---- Upload loader
  212. ldx #$0000
  213. -
  214. lda @loader,x
  215. jsr spc_upload_byte
  216. inx
  217. cpy #31 ; size of loader
  218. bne -
  219. ; ---- Upload SP, PC & PSW
  220. lda @SPC_HEADER+43
  221. jsr spc_upload_byte
  222. lda @SPC_HEADER+38
  223. jsr spc_upload_byte
  224. lda @SPC_HEADER+37
  225. jsr spc_upload_byte
  226. lda @SPC_HEADER+42
  227. jsr spc_upload_byte
  228. ; ---- Upload DSP registers
  229. ldx #$0000
  230. -
  231. ; initialize FLG and KON ($6c/$4c) to avoid artifacts
  232. cpx #$4C
  233. bne +
  234. lda #$00
  235. bra upload_skip_load
  236. +
  237. cpx #$6C
  238. bne +
  239. lda #$E0
  240. bra upload_skip_load
  241. +
  242. lda @SPC_DSP_REGS,x
  243. upload_skip_load
  244. jsr spc_upload_byte
  245. inx
  246. cpx #128
  247. bne -
  248. ; --- Upload fixed values for $F1-$F3
  249. ldy #$00F1
  250. jsr spc_next_upload
  251. lda #$80 ; stop timers
  252. jsr spc_upload_byte
  253. lda #$6c ; get dspaddr set for later
  254. jsr spc_upload_byte
  255. lda #$60
  256. jsr spc_upload_byte
  257. ; ---- Upload $f8-$1ff
  258. ldy #$00F8
  259. jsr spc_next_upload
  260. ldx #$00F8
  261. -
  262. lda @SPC_DATA,x
  263. jsr spc_upload_byte
  264. inx
  265. cpx #$200
  266. bne -
  267. ; ---- Execute loader
  268. ldy #$0002
  269. jsr spc_execute
  270. rts
  271. ;---------------------------------------
  272. upload_high_ram:
  273. ldy #$0002
  274. jsr spc_begin_upload
  275. ; ---- Upload transfer routine
  276. ldx #$0000
  277. -
  278. lda @transfer,x
  279. jsr spc_upload_byte
  280. inx
  281. cpy #43 ; size of transfer routine
  282. bne -
  283. ldx #$023f ; prepare transfer address
  284. ; ---- Execute transfer routine
  285. ldy #$0002
  286. sty APUIO2
  287. stz APUIO1
  288. lda APUIO0
  289. inc
  290. inc
  291. sta APUIO0
  292. ; Wait for acknowledgement
  293. -
  294. cmp APUIO0
  295. bne -
  296. ; ---- Burst transfer of 63.5K using custom routine
  297. outer_transfer_loop:
  298. ldy #$003f ; 3
  299. inner_transfer_loop:
  300. lda @SPC_DATA,x ; 5 |
  301. sta APUIO0 ; 4 |
  302. lda @SPC_DATA+$40,x ; 5 |
  303. sta APUIO1 ; 4 |
  304. lda @SPC_DATA+$80,x ; 5 |
  305. sta APUIO2 ; 4 |
  306. lda @SPC_DATA+$C0,x ; 5 |
  307. sta APUIO3 ; 4 |
  308. tya ; 2 >> 38 cycles
  309. -
  310. cmp APUIO3 ; 4 |
  311. bne - ; 3 |
  312. dex ; 2 |
  313. dey ; 2 |
  314. bpl inner_transfer_loop ; 3 >> 14 cycles
  315. rep #$21 : .al ; 3 |
  316. txa ; 2 |
  317. adc #$140 ; 3 |
  318. tax ; 2 |
  319. sep #$20 : .as ; 3 |
  320. cpx #$003f ; 3 |
  321. bne outer_transfer_loop ; 3 >> 19 cycles
  322. rts
  323. ;---------------------------------------
  324. upload_low_ram:
  325. ; ---- Upload $0002-$00EF using IPL
  326. ldy #$0002
  327. jsr spc_begin_upload
  328. ldx #$0002
  329. -
  330. lda @SPC_DATA,x
  331. jsr spc_upload_byte
  332. inx
  333. cpx #$00F0
  334. bne -
  335. rts
  336. ;---------------------------------------
  337. ; Executes final restoration code
  338. restore_final:
  339. jsr start_exec_io ; prepare execution from I/O registers
  340. stz $420d ; SPC700 I/O code requires SLOW timing
  341. ; ---- Restore first two bytes of RAM
  342. lda @SPC_DATA
  343. xba
  344. lda #$e8 ; MOV A,#@SPC_DATA
  345. tax
  346. jsr exec_instr
  347. ldx #$00C4 ; MOV $00,A
  348. jsr exec_instr
  349. lda @SPC_DATA+1
  350. xba
  351. lda #$e8 ; MOV A,#@SPC_DATA+1
  352. tax
  353. jsr exec_instr
  354. ldx #$01C4 ; MOV $01,A
  355. jsr exec_instr
  356. ; ---- Restore SP
  357. lda @SPC_HEADER+43
  358. sec
  359. sbc #3
  360. xba
  361. lda #$cd ; MOV X,#@SPC_HEADER+43
  362. tax
  363. jsr exec_instr
  364. ldx #$bd ; MOV SP,X
  365. jsr exec_instr
  366. ; ---- Restore X
  367. lda @SPC_HEADER+40
  368. xba
  369. lda #$cd ; MOV X,#@SPC_HEADER+40
  370. tax
  371. jsr exec_instr
  372. ; ---- Restore Y
  373. lda @SPC_HEADER+41
  374. xba
  375. lda #$8d ; MOV Y,#@SPC_HEADER+41
  376. tax
  377. jsr exec_instr
  378. ; ---- Restore DSP FLG register
  379. lda @SPC_DSP_REGS+$6c
  380. xba
  381. lda #$e8 ; MOV A,#@SPC_DSP_REGS+$6c
  382. tax
  383. jsr exec_instr
  384. ldx #$f3C4 ; MOV $f3,A -> $f2 has been set-up before by SPC700 loader
  385. jsr exec_instr
  386. ; ---- wait a bit (the newer S-APU takes its time to ramp up the volume)
  387. lda #$10
  388. - pha
  389. jsr waitblank
  390. pla
  391. dec
  392. bne -
  393. ; ---- Restore DSP KON register
  394. lda #$4C
  395. xba
  396. lda #$e8 ; MOV A,#$4c
  397. tax
  398. jsr exec_instr
  399. ldx #$f2C4 ; MOV $f2,A
  400. jsr exec_instr
  401. lda @SPC_DSP_REGS+$4C
  402. xba
  403. lda #$e8 ; MOV A,#@SPC_DSP_REGS+$4c
  404. tax
  405. jsr exec_instr
  406. ldx #$f3C4 ; MOV $f3,A
  407. jsr exec_instr
  408. ; ---- Restore DSP register address
  409. lda @SPC_DATA+$F2
  410. xba
  411. lda #$e8 ; MOV A,#@SPC_DATA+$F2
  412. tax
  413. jsr exec_instr
  414. ldx #$f2C4 ; MOV dest,A
  415. jsr exec_instr
  416. ; ---- Restore CONTROL register
  417. lda @SPC_DATA+$F1
  418. and #$CF ; don't clear input ports
  419. xba
  420. lda #$e8 ; MOV A,#@SPC_DATA+$F1
  421. tax
  422. jsr exec_instr
  423. ldx #$f1C4 ; MOV $F1,A
  424. jsr exec_instr
  425. ;---- Restore A
  426. lda @SPC_HEADER+39
  427. xba
  428. lda #$e8 ; MOV A,#@SPC_HEADER+39
  429. tax
  430. jsr exec_instr
  431. ;---- Restore PSW and PC
  432. ldx #$7F00 ; NOP; RTI
  433. stx APUIO0
  434. lda #$FC ; Patch loop to execute instruction just written
  435. sta APUIO3
  436. ;---- restore IO ports $f4 - $f7
  437. rep #$20 : .al
  438. lda @SPC_DATA+$F4
  439. tax
  440. lda @SPC_DATA+$F6
  441. sta APUIO2
  442. stx APUIO0 ; last to avoid overwriting RETI before run
  443. sep #$20 : .as
  444. lda #$01
  445. sta $420d ; restore FAST CPU operation
  446. rts
  447. ;---------------------------------------
  448. spc_begin_upload:
  449. sty APUIO2 ; Set address
  450. ldy #$BBAA ; Wait for SPC
  451. -
  452. cpy APUIO0
  453. bne -
  454. lda #$CC ; Send acknowledgement
  455. sta APUIO1
  456. sta APUIO0
  457. - ; Wait for acknowledgement
  458. cmp APUIO0
  459. bne -
  460. ldy #0 ; Initialize index
  461. rts
  462. ;---------------------------------------
  463. spc_upload_byte:
  464. sta APUIO1
  465. tya ; Signal it's ready
  466. sta APUIO0
  467. - ; Wait for acknowledgement
  468. cmp APUIO0
  469. bne -
  470. iny
  471. rts
  472. ;---------------------------------------
  473. spc_next_upload:
  474. sty APUIO2
  475. ; Send command
  476. ; Special case operation has been fully tested.
  477. lda APUIO0
  478. inc
  479. inc
  480. bne +
  481. inc
  482. +
  483. sta APUIO1
  484. sta APUIO0
  485. ; Wait for acknowledgement
  486. -
  487. cmp APUIO0
  488. bne -
  489. ldy #0
  490. rts
  491. ;---------------------------------------
  492. spc_execute:
  493. sty APUIO2
  494. stz APUIO1
  495. lda APUIO0
  496. inc
  497. inc
  498. sta APUIO0
  499. ; Wait for acknowledgement
  500. -
  501. cmp APUIO0
  502. bne -
  503. rts
  504. ;---------------------------------------
  505. start_exec_io:
  506. ; Set execution address
  507. ldx #$00F5
  508. stx APUIO2
  509. stz APUIO1 ; NOP
  510. ldx #$FE2F ; BRA *-2
  511. ; Signal to SPC that we're ready
  512. lda APUIO0
  513. inc
  514. inc
  515. sta APUIO0
  516. ; Wait for acknowledgement
  517. -
  518. cmp APUIO0
  519. bne -
  520. ; Quickly write branch
  521. stx APUIO2
  522. rts
  523. ;---------------------------------------
  524. exec_instr:
  525. ; Replace instruction
  526. stx APUIO0
  527. lda #$FC
  528. sta APUIO3 ; 30
  529. ; SPC BRA loop takes 4 cycles, so it reads
  530. ; the branch offset every 4 SPC cycles (84 master).
  531. ; We must handle the case where it read just before
  532. ; the write above, and when it reads just after it.
  533. ; If it reads just after, we have at least 7 SPC
  534. ; cycles (147 master) to change restore the branch
  535. ; offset.
  536. ; 48 minimum, 90 maximum
  537. ora #0
  538. ora #0
  539. ora #0
  540. nop
  541. nop
  542. nop
  543. ; 66 delay, about the middle of the above limits
  544. phd ;4
  545. pld ;5
  546. ; Give plenty of extra time if single execution
  547. ; isn't needed, as this avoids such tight timing
  548. ; requirements.
  549. ; phd ;4
  550. ; pld ;5
  551. ; phd ;4
  552. ; pld ;5
  553. ; Patch loop to skip first two bytes
  554. lda #$FE ; 16
  555. sta APUIO3 ; 30
  556. ; 38 minimum (assuming 66 delay above)
  557. phd ; 4
  558. pld ; 5
  559. ; Give plenty of extra time if single execution
  560. ; isn't needed, as this avoids such tight timing
  561. ; requirements.
  562. phd
  563. pld
  564. phd
  565. pld
  566. rts