spcplay.a65 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  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. lda @SPC_DSP_REGS,x
  232. jsr spc_upload_byte
  233. inx
  234. cpx #128
  235. bne -
  236. ; --- Upload fixed values for $F1-$F3
  237. ldy #$00F1
  238. jsr spc_next_upload
  239. lda #$80 ; stop timers
  240. jsr spc_upload_byte
  241. lda #$6c ; get dspaddr set for later
  242. jsr spc_upload_byte
  243. lda #$60
  244. jsr spc_upload_byte
  245. ; ---- Upload $f8-$1ff
  246. ldy #$00F8
  247. jsr spc_next_upload
  248. ldx #$00F8
  249. -
  250. lda @SPC_DATA,x
  251. jsr spc_upload_byte
  252. inx
  253. cpx #$200
  254. bne -
  255. ; ---- Execute loader
  256. ldy #$0002
  257. jsr spc_execute
  258. rts
  259. ;---------------------------------------
  260. upload_high_ram:
  261. ldy #$0002
  262. jsr spc_begin_upload
  263. ; ---- Upload transfer routine
  264. ldx #$0000
  265. -
  266. lda @transfer,x
  267. jsr spc_upload_byte
  268. inx
  269. cpy #43 ; size of transfer routine
  270. bne -
  271. ldx #$023f ; prepare transfer address
  272. ; ---- Execute transfer routine
  273. ldy #$0002
  274. sty APUIO2
  275. stz APUIO1
  276. lda APUIO0
  277. inc
  278. inc
  279. sta APUIO0
  280. ; Wait for acknowledgement
  281. -
  282. cmp APUIO0
  283. bne -
  284. ; ---- Burst transfer of 63.5K using custom routine
  285. outer_transfer_loop:
  286. ldy #$003f ; 3
  287. inner_transfer_loop:
  288. lda @SPC_DATA,x ; 5 |
  289. sta APUIO0 ; 4 |
  290. lda @SPC_DATA+$40,x ; 5 |
  291. sta APUIO1 ; 4 |
  292. lda @SPC_DATA+$80,x ; 5 |
  293. sta APUIO2 ; 4 |
  294. lda @SPC_DATA+$C0,x ; 5 |
  295. sta APUIO3 ; 4 |
  296. tya ; 2 >> 38 cycles
  297. -
  298. cmp APUIO3 ; 4 |
  299. bne - ; 3 |
  300. dex ; 2 |
  301. dey ; 2 |
  302. bpl inner_transfer_loop ; 3 >> 14 cycles
  303. rep #$21 : .al ; 3 |
  304. txa ; 2 |
  305. adc #$140 ; 3 |
  306. tax ; 2 |
  307. sep #$20 : .as ; 3 |
  308. cpx #$003f ; 3 |
  309. bne outer_transfer_loop ; 3 >> 19 cycles
  310. rts
  311. ;---------------------------------------
  312. upload_low_ram:
  313. ; ---- Upload $0002-$00EF using IPL
  314. ldy #$0002
  315. jsr spc_begin_upload
  316. ldx #$0002
  317. -
  318. lda @SPC_DATA,x
  319. jsr spc_upload_byte
  320. inx
  321. cpx #$00F0
  322. bne -
  323. rts
  324. ;---------------------------------------
  325. ; Executes final restoration code
  326. restore_final:
  327. jsr start_exec_io ; prepare execution from I/O registers
  328. stz $420d ; SPC700 I/O code requires SLOW timing
  329. ; ---- Restore first two bytes of RAM
  330. lda @SPC_DATA
  331. xba
  332. lda #$e8 ; MOV A,#@SPC_DATA
  333. tax
  334. jsr exec_instr
  335. ldx #$00C4 ; MOV $00,A
  336. jsr exec_instr
  337. lda @SPC_DATA+1
  338. xba
  339. lda #$e8 ; MOV A,#@SPC_DATA+1
  340. tax
  341. jsr exec_instr
  342. ldx #$01C4 ; MOV $01,A
  343. jsr exec_instr
  344. ; ---- Restore SP
  345. lda @SPC_HEADER+43
  346. sec
  347. sbc #3
  348. xba
  349. lda #$cd ; MOV X,#@SPC_HEADER+43
  350. tax
  351. jsr exec_instr
  352. ldx #$bd ; MOV SP,X
  353. jsr exec_instr
  354. ; ---- Restore X
  355. lda @SPC_HEADER+40
  356. xba
  357. lda #$cd ; MOV X,#@SPC_HEADER+40
  358. tax
  359. jsr exec_instr
  360. ; ---- Restore Y
  361. lda @SPC_HEADER+41
  362. xba
  363. lda #$8d ; MOV Y,#@SPC_HEADER+41
  364. tax
  365. jsr exec_instr
  366. ; ---- Restore DSP FLG register
  367. lda @SPC_DSP_REGS+$6c
  368. xba
  369. lda #$e8 ; MOV A,#@SPC_DSP_REGS+$6c
  370. tax
  371. jsr exec_instr
  372. ldx #$f3C4 ; MOV $f3,A -> $f2 has been set-up before by SPC700 loader
  373. jsr exec_instr
  374. ; ---- Restore DSP KON register
  375. lda #$4C
  376. xba
  377. lda #$e8 ; MOV A,#$4c
  378. tax
  379. jsr exec_instr
  380. ldx #$f2C4 ; MOV $f2,A
  381. jsr exec_instr
  382. lda @SPC_DSP_REGS+$4C
  383. xba
  384. lda #$e8 ; MOV A,#@SPC_DSP_REGS+$4c
  385. tax
  386. jsr exec_instr
  387. ldx #$f3C4 ; MOV $f3,A
  388. jsr exec_instr
  389. ; ---- Restore DSP register address
  390. lda @SPC_DATA+$F2
  391. xba
  392. lda #$e8 ; MOV A,#@SPC_DATA+$F2
  393. tax
  394. jsr exec_instr
  395. ldx #$f2C4 ; MOV dest,A
  396. jsr exec_instr
  397. ; ---- Restore CONTROL register
  398. lda @SPC_DATA+$F1
  399. and #$CF ; don't clear input ports
  400. xba
  401. lda #$e8 ; MOV A,#@SPC_DATA+$F1
  402. tax
  403. jsr exec_instr
  404. ldx #$f1C4 ; MOV $F1,A
  405. jsr exec_instr
  406. ;---- Restore A
  407. lda @SPC_HEADER+39
  408. xba
  409. lda #$e8 ; MOV A,#@SPC_HEADER+39
  410. tax
  411. jsr exec_instr
  412. ;---- Restore PSW and PC
  413. ldx #$7F00 ; NOP; RTI
  414. stx APUIO0
  415. lda #$FC ; Patch loop to execute instruction just written
  416. sta APUIO3
  417. ;---- restore IO ports $f4 - $f7
  418. rep #$20 : .al
  419. lda @SPC_DATA+$F4
  420. tax
  421. lda @SPC_DATA+$F6
  422. sta APUIO2
  423. stx APUIO0 ; last to avoid overwriting RETI before run
  424. sep #$20 : .as
  425. lda #$01
  426. sta $420d ; restore FAST CPU operation
  427. rts
  428. ;---------------------------------------
  429. spc_begin_upload:
  430. sty APUIO2 ; Set address
  431. ldy #$BBAA ; Wait for SPC
  432. -
  433. cpy APUIO0
  434. bne -
  435. lda #$CC ; Send acknowledgement
  436. sta APUIO1
  437. sta APUIO0
  438. - ; Wait for acknowledgement
  439. cmp APUIO0
  440. bne -
  441. ldy #0 ; Initialize index
  442. rts
  443. ;---------------------------------------
  444. spc_upload_byte:
  445. sta APUIO1
  446. tya ; Signal it's ready
  447. sta APUIO0
  448. - ; Wait for acknowledgement
  449. cmp APUIO0
  450. bne -
  451. iny
  452. rts
  453. ;---------------------------------------
  454. spc_next_upload:
  455. sty APUIO2
  456. ; Send command
  457. ; Special case operation has been fully tested.
  458. lda APUIO0
  459. inc
  460. inc
  461. bne +
  462. inc
  463. +
  464. sta APUIO1
  465. sta APUIO0
  466. ; Wait for acknowledgement
  467. -
  468. cmp APUIO0
  469. bne -
  470. ldy #0
  471. rts
  472. ;---------------------------------------
  473. spc_execute:
  474. sty APUIO2
  475. stz APUIO1
  476. lda APUIO0
  477. inc
  478. inc
  479. sta APUIO0
  480. ; Wait for acknowledgement
  481. -
  482. cmp APUIO0
  483. bne -
  484. rts
  485. ;---------------------------------------
  486. start_exec_io:
  487. ; Set execution address
  488. ldx #$00F5
  489. stx APUIO2
  490. stz APUIO1 ; NOP
  491. ldx #$FE2F ; BRA *-2
  492. ; Signal to SPC that we're ready
  493. lda APUIO0
  494. inc
  495. inc
  496. sta APUIO0
  497. ; Wait for acknowledgement
  498. -
  499. cmp APUIO0
  500. bne -
  501. ; Quickly write branch
  502. stx APUIO2
  503. rts
  504. ;---------------------------------------
  505. exec_instr:
  506. ; Replace instruction
  507. stx APUIO0
  508. lda #$FC
  509. sta APUIO3 ; 30
  510. ; SPC BRA loop takes 4 cycles, so it reads
  511. ; the branch offset every 4 SPC cycles (84 master).
  512. ; We must handle the case where it read just before
  513. ; the write above, and when it reads just after it.
  514. ; If it reads just after, we have at least 7 SPC
  515. ; cycles (147 master) to change restore the branch
  516. ; offset.
  517. ; 48 minimum, 90 maximum
  518. ora #0
  519. ora #0
  520. ora #0
  521. nop
  522. nop
  523. nop
  524. ; 66 delay, about the middle of the above limits
  525. phd ;4
  526. pld ;5
  527. ; Give plenty of extra time if single execution
  528. ; isn't needed, as this avoids such tight timing
  529. ; requirements.
  530. ; phd ;4
  531. ; pld ;5
  532. ; phd ;4
  533. ; pld ;5
  534. ; Patch loop to skip first two bytes
  535. lda #$FE ; 16
  536. sta APUIO3 ; 30
  537. ; 38 minimum (assuming 66 delay above)
  538. phd ; 4
  539. pld ; 5
  540. ; Give plenty of extra time if single execution
  541. ; isn't needed, as this avoids such tight timing
  542. ; requirements.
  543. phd
  544. pld
  545. phd
  546. pld
  547. rts