SOUND.DOC 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. From PARADIS@htu.tu-graz.ac.at Fri Mar 25 08:41:08 1994
  2. The Bloody SPC-700
  3. ------------------
  4. A try to stumble into the inner secret of a nasty chip.
  5. By Antitrack exclusively for the FAMIDEV development group.
  6. Chapter 1:
  7. ----------
  8. FACTS
  9. * The SPC 700 is a very stupid sound chip with about the worst
  10. handling
  11. that you have seen in your lifetime.
  12. * This chip is a co processor. He has a quite large instruction set
  13. (contrary to the Amiga's COPPER, who has a very small one) and 64KB
  14. RAM
  15. memory, of which you can use atleast 32KB. (or so)
  16. * All program and data that is supposed to be run by this chip must
  17. be'
  18. moved to the SPC's own ram with a small loop that pokes each byte of
  19. your SPC assembler program and (e.g. sample-)data into four memory
  20. locations : $2140 - $2143. They are your only chance to communicate
  21. with
  22. the SPC.
  23. * These four memory locations have different meanings for read and
  24. write;
  25. if you read (LDA) $2140, you get the data from memory loc. 00f4 (or
  26. so)
  27. of the sound chip.
  28. * On power-on, the SPC 700 jumps (much like the main processor) to a
  29. very
  30. small ROM area that resides from $ffc0 to $ffff inside the SPC.
  31. (This chip REALLY follows the black box principle, eh...) This
  32. program
  33. at $ffc0 is waiting to get the data in the right format on his
  34. input ports
  35. at $00f4/5/6/7 , which are $2140/1/2/3 from the 65c816's (e.g.
  36. your's )
  37. point of view.
  38. * Your main program will therefore have to follow the SPC's
  39. conditions and
  40. poke all the program and data for the SPC into 2140/1/2/3 in a
  41. special
  42. order.
  43. * When transmission is completed, you will also have transmitted the
  44. start
  45. address of your SPC code, and the SPC will start to execute your
  46. program
  47. there.
  48. --------------------QUESTIONS.
  49. Q: How do I move my program and data to the SPC then, what format do
  50. I have
  51. to use?
  52. A: First, your SPC data/code has to be moved from ROM to the extra
  53. RAM at
  54. e.g. $7f0000 . Dont ask me why it has to be in RAM, probably it doesnt
  55. but all the existing routines that send data to the SPC do something
  56. like
  57. that.
  58. Your data/code has to be in groups which I will call "chunks". A
  59. valid chunk
  60. looks like that:
  61. first word: number of bytes to transmit to SPC -+
  62. sec. word : start address where to move data to the SPC | one chunk
  63. byte 4-???? : your data/code -+
  64. You can have as many chunks as you want to , but the last chunk must
  65. be like
  66. that:
  67. first word : $0000
  68. second word: Start address of your code.
  69. Q: So if you are right, this means: After I transmitted all my code
  70. and
  71. data, and my own SPC code takes over the control, I might encounter
  72. problems
  73. if my SPC program has to communicate with the outer world (the
  74. 65c816).
  75. What if the main program wants to change sounds? What if a background
  76. melody
  77. shall always play on two voices, and extra two voices will be used for
  78. sound effects whenever the player sprite e.g. picks up an object?
  79. A: That is sure a point. Your own code will have to look at memory
  80. locations
  81. $00f4/00f5/00f6/00f7 , because they are the only accessible from
  82. outside
  83. at $2140/1/2/3. The easiest way would be: As soon as any of $f4-$f7
  84. change,
  85. jump into the Boot ROM at $ffc0 (?) so the SPC is executing his
  86. receive
  87. routine again. Then you *probably* can send another SPC chunk with new
  88. sound and code to the SPC....
  89. Q: This only helps if a complete new tune is to be played, this
  90. doesnt help
  91. if a melody using two voices shall still remain....
  92. A: Thats true. The best approach is to send own command bytes to the
  93. SPC and
  94. your SPC code has to check out $f4-$f7 constantly and react to it.....
  95. A command byte like $00 could mean: sound off,
  96. $01 : play tune 1
  97. .
  98. .
  99. .
  100. $0f : play tune $0f
  101. $10 : play jingle (fx) 01
  102. .
  103. .
  104. .
  105. $ff : jump to $ffc0 (??) the receive
  106. ROM routine
  107. Q: is there another approach?
  108. A: Yes there is. As you probably know, all important addresses of the
  109. SPC 700 reside inside its own RAM's zeropage:
  110. Address / register / usage
  111. 0000 Volume left
  112. 0001 Volume right
  113. 0002 Pitch low
  114. 0003 Pitch high (The total 14 bits of pitch
  115. height)
  116. 0004 SRCN Designates source number from 0-
  117. 255
  118. 0005 ADSR 1
  119. 0006 ADSR 2
  120. 0007 GAIN Envelope can be freely designated by
  121. your code
  122. 0008 ENVX Present val of envelope with DSP
  123. rewrites
  124. 0009 VALX Present wave height val
  125. (and so on...)
  126. Your approach would be to move only sample data there, and/or (lots
  127. of) very
  128. small chunks of data with a target address in the zeropage, and a
  129. starting
  130. address of e.g. $ffc0. The small chunks would access zeropage
  131. addresses e.g.
  132. for the volume etc and thus result in tones; if this is done every
  133. frame
  134. you might end up with a music player quite similar to the C64 styled
  135. ones.
  136. Q: So anyway, in what format exactly do I have to move data to the
  137. SPC?
  138. A: I have the following source code for you, but let me explain it a
  139. bit
  140. BEFORE you start to dig into it.
  141. I've already mentioned the general "chunk" format. The loop does the
  142. following:
  143. - move ram destination address to $2142/3 (akku: 16 bit)
  144. - move either #$00 or #$01 into 2141, this depends if you have more
  145. than $0100
  146. bytes of data for the SPC;
  147. - first time (first chunk you transmit): move constant #$cc into 2140
  148. - loop: poke each byte that you want to be transmitted into 2140
  149. (word)
  150. the higher 7-15 bits of your accu-word contain the number of bytes
  151. already
  152. moved (e.g. 00 on the start)
  153. - cmp $2140 with this number of bytes already moved (lower 8 bits of
  154. this
  155. number only!) and wait if its not equal.
  156. - until the loop is over.
  157. - for the next chunk header this is repeated, but not #$cc is moved
  158. into
  159. 2140 but "nn" (lobyte of number of bytes moved) +3 or +6 if it was
  160. 00 when
  161. +3 was used.
  162. EXAMPLE:
  163. move #$0400 to 2142 /word access
  164. move #$01 to 2141
  165. move #$cc to 2140
  166. move "gg00" to 2140 where "gg" is the first real code/data
  167. byte for
  168. the SPC
  169. wait till 2140 is #$00
  170. move hh01 to 2140 where "hh" is the second byte of code or
  171. data for SPC
  172. wait till 2140 is #$01
  173. move ii02 to 2140 where "ii" is the 3rd byte of data for the
  174. SPC....
  175. wait till 2140 is #$02
  176. lets say "ii" was the last byte. Now we add #$04 (3+carry) to
  177. #$02
  178. (#$02 being the number-1 of how many bytes we moved to the
  179. SPC), we
  180. will push it onto the stack), now :
  181. fetch the next header , poke target RAM address into $2142
  182. (word)
  183. poke 00 or 01 into 2141 depending of how many bytes to send,
  184. poke #$06 into 2140 (06 : number of bytes sent from last chunk-
  185. 1 + 3 )
  186. I think I got this scheme pretty much right this time. Now, is PLEASE
  187. someone
  188. going to donate their home-brewed SPC dis/assemblers to me? Oh pretty
  189. please,
  190. I hate silent SNES's ! :)
  191. Source code follows, reassembled from a PAN/Baseline demo "xmas wish
  192. 92/93":
  193. ----------------------------------------------------------------------
  194. ------
  195. ; entry to the code starts here
  196. SEP #$30 ; x y a set to 8 bit length
  197. LDA #$FF ; ff into audio0w (write)
  198. STA $2140
  199. REP #$10 ; x,y: 16 bit length
  200. LDX #$7FFF
  201. l0DB5B LDA $018000,X ; move rom music data to ram at $7f0000
  202. STA $7F0000,X
  203. LDA $028000,X ; move rom music data to ram at $7f0000
  204. STA $7F8000,X
  205. DEX
  206. BPL l0DB5B
  207. LDA #$80 ; screen on , probably not important at all
  208. STA $2100
  209. LDA #$00 ; 00fd/00fe/00ff point to the data that is
  210. now
  211. STA $00FD ; in ram at $7f0000
  212. LDA #$00
  213. STA $00FE
  214. LDA #$7F
  215. STA $00FF
  216. STZ $4200 ; disable nmi and timer h/v count
  217. SEI ; disable irq
  218. JSR l0DBCD ; unknown sub routine, labeled "RESTART"
  219. by PAN/ATX
  220. SEP #$30 ; all regs 8 bit
  221. l0DB8B LDA $2140 ; wait for reply from sound chip ?
  222. BNE l0DB8B
  223. LDA #$E0 ; audio3w ?
  224. STA $2143
  225. LDA #$FF ; send data to sound chip ?
  226. STA $2142 ; $ffe0 this could be an address within the
  227. ; sound chip ROM between $ffc0 and $ffff
  228. in the
  229. ; ROM mask.......
  230. LDA #$01 ; send data to sound chip ?
  231. STA $2141
  232. LDA #$01 ; send data to sound chip ?
  233. STA $2140
  234. l0DBA4 LDA $2140 ; wait for reply from sound chip ?
  235. CMP #$01 ; what a fuck of a protocol .... :(
  236. BNE l0DBA4
  237. l0DBAB LDA $2140 ; wait again for reply from soundchip ?
  238. CMP #$55
  239. BNE l0DBAB
  240. LDA $0207 ; aha ... move $0207 to sound chip ?
  241. STA $2141 ; probably sound number selector
  242. LDA #$07
  243. STA $2140 ; send data to sound chip
  244. l0DBBD LDA $2140 ; wait until sound chip accepted data?
  245. CMP #$07
  246. BNE l0DBBD
  247. l0DBC4 LDA $2140 ; wait for reply ?
  248. CMP #$55
  249. BNE l0DBC4
  250. CLI
  251. RTS
  252. l0DBCD PHP ; labeled "RESTART" by pan/ATX
  253. JSR l0DBD8 ;
  254. PLP
  255. LDA #$00 ; 00 into audio0w
  256. STA $2140
  257. RTS
  258. l0DBD8 PHP
  259. REP #$30 ; a,x,y 16 bit regs
  260. LDY #$0000 ; needed first time at lda [$fd],y :
  261. pointer to ram
  262. LDA #$BBAA
  263. l0DBE1 CMP $2140 ; wait for sound chip $2140/2141 ?
  264. BNE l0DBE1
  265. SEP #$20 ; akku 8 bit
  266. LDA #$CC
  267. BRA l0DC12 ; oh well, another mystery :-)
  268. ; jump here if overflow is set e.g. if more than $0100 data to move
  269. l0DBEC LDA [$FD],Y ; get data from ram pointer
  270. INY ; the accumulator is about to get "xx00"
  271. where
  272. XBA ; /"xx" is the byte from [fd],y (first
  273. data byte)
  274. LDA #$00 ; /and resides into bit 15-7 of accu,
  275. and 00 is
  276. BRA l0DBFF ; /#$00 (8bit number of bytes already
  277. sent)
  278. l0DBF4 XBA ; accu is now "nn??" ?? is old data from
  279. last loop
  280. LDA [$FD],Y ; accu is now "nnxx" with xx the newest
  281. data byte
  282. INY ; /for
  283. the SPC!
  284. XBA ; accu is now "xxnn"
  285. l0DBF9 CMP $2140 ; wait for sound chip to reply with "nn" !!
  286. BNE l0DBF9
  287. INC A ; increment number of bytes that were
  288. sent...
  289. ; accu is now "xxnn" with newest val for
  290. nn:=nn+1
  291. l0DBFF REP #$20 ; akku 16 bit
  292. STA $2140 ; poke "xxnn" to soundchip. xx is actual
  293. data,
  294. SEP #$20 ; akku 8 bit ! nn is the 8-bit cutted
  295. number of bytes
  296. DEX ! which were already sent!!
  297. BNE l0DBF4 ; as many times as xreg says...
  298. l0DC09 CMP $2140 ; byte "nn" will be replied from the SPC if
  299. data
  300. BNE l0DC09 ; received correctly!
  301. l0DC0E ADC #$03 ; compare accu with #$fb ADC WILL ADD #$04
  302. COZ
  303. ; CARRY IS ALWAYS SET AFTER THE CMP!!!
  304. ATTENTION!
  305. BEQ l0DC0E ; if accu was $fb then accu := $03 . (what
  306. for?)
  307. l0DC12 PHA ; push value accu+$04 to stack (or
  308. beginning: #$cc)
  309. REP #$20 ; accu = 16 bit
  310. LDA [$FD],Y ; get ram data 2 bytes
  311. INY ; point to next word
  312. INY
  313. TAX ; x:=a : number of bytes to transmit
  314. LDA [$FD],Y ; get ram data
  315. INY
  316. INY
  317. STA $2142 ; audio2w : possibly the dest. area in the
  318. spc700
  319. SEP #$20 ; accu 8 bit
  320. CPX #$0100 ; set carry if first ram data was >= 0100
  321. lda #$00 ;
  322. ROL ;
  323. STA $2141 ; if ram data >= 0100, poke "1" into reg 1
  324. otherw 0
  325. ADC #$7F ; SET OVERFLOW FLAG IF X>=$0100 !!!! (nice
  326. trick!)
  327. PLA
  328. STA $2140 ; $cc in the first case , nn+4 on all later
  329. cases
  330. l0DC32 CMP $2140 ; wait for snd chip reply
  331. BNE l0DC32
  332. BVS l0DBEC ; if there were more than $0100 data for the
  333. spc's RAM
  334. ; move them where they R supposed to belong
  335. to!
  336. PLP
  337. RTS
  338. PLA
  339. STA $2140 ; same shit, never been jumped into
  340. l0DC3F CMP $2140
  341. BNE l0DC3F
  342. BVS l0DBF9
  343. PLP
  344. RTS
  345. ; also lets look at 7f0000: the first few bytes at 7f0000 are:
  346. 7f0000: b7 0e 00 04 20 cd cf bd e8 00 5d af c8 f0 d0 fb 5d d5 00 01
  347. d5 00 02
  348. b7 0e should be number of bytes to transmit, 0400 the destination
  349. inside the
  350. spc....
  351. at this point I really need an SPC dis/assembler..... :(((
  352. Okay well my first source was incompetent, sure thing. But I think I
  353. could
  354. solve a lot of questions meanwhile.