Simple SNES shoot-'em-up game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

394 lines
8.1 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. .INCLUDE "header.asm"
  2. .INCLUDE "init.asm"
  3. .INCLUDE "registers.asm"
  4. ; The JSR and RTS instructions add a total of 12 cycles of overhead. For
  5. ; short, commonly-used functions, it makes sense to declare them as macros,
  6. ; which get inlined by the assembler at the point of use. This saves on
  7. ; CPU cycles, at the cost of code size.
  8. .MACRO ConvertXCoordinate
  9. ; Data in: world x-coordinate, in A register.
  10. ; Data out: SNES scroll data, in C (the 16-bit A register).
  11. rep #%00100000 ; 16-bit A
  12. eor #$FFFF ; Flip bits
  13. ina
  14. sep #%00100000 ; 8-bit A
  15. .ENDM
  16. .MACRO ConvertYCoordinate
  17. ; Data in: world y-coordinate, in A register.
  18. ; Data out: SNES scroll data, in C (the 16-bit A register).
  19. rep #%00100000 ; 16-bit A
  20. eor #$FFFF ; Flip bits
  21. sep #%00100000 ; 8-bit A
  22. .ENDM
  23. .BANK 0 SLOT 0
  24. .ORG 0
  25. .SECTION "MainCode"
  26. ; Memory layout:
  27. ; 00-0F: scratch space for functions.
  28. ; 10-11: controller state of joypad #1.
  29. ; 12-13: controller state of joypad #2.
  30. ; 14-17: 32-bit counter of vblanks.
  31. ; 20-21: (x, y) coordinates of player.
  32. ; 22-24: RGB color values to use for background color, from [0-31].
  33. Start:
  34. InitializeSNES
  35. jsr LoadPaletteAndTileData
  36. ; Turn on the screen.
  37. ; Format: x000bbbb
  38. ; x: 0 = screen on, 1 = screen off, bbbb: Brightness ($0-$F)
  39. lda #%00001111
  40. sta INIDISP
  41. ; Enable NMI interrupt & joypad.
  42. ; n-vh---j n: NMI interrupt enable v: vertical counter enable
  43. ; h: horizontal counter enable j: joypad enable
  44. lda #%10000001
  45. sta NMITIMEN
  46. ; Store zeroes to the controller status registers.
  47. ; TODO(mcmillen): is this needed? I think the system will overwrite these
  48. ; automatically.
  49. stz JOY1H
  50. stz JOY1L
  51. ; Write something recognizable into our scratch space.
  52. jsr FillScratch
  53. ; Start the background color as a dark blue.
  54. lda #16
  55. sta $24
  56. MainLoop:
  57. wai ; Wait for interrupt.
  58. jmp MainLoop
  59. LoadPaletteAndTileData:
  60. ; For more details on DMA, see:
  61. ; http://wiki.superfamicom.org/snes/show/Grog%27s+Guide+to+DMA+and+HDMA+on+the+SNES
  62. ; http://wiki.superfamicom.org/snes/show/Making+a+Small+Game+-+Tic-Tac-Toe
  63. ;
  64. ; A lot of the graphics-related registers are explained in Qwertie's doc:
  65. ; http://emu-docs.org/Super%20NES/General/snesdoc.html
  66. ; ... but be careful, because there are some errors in this doc.
  67. ;
  68. ; bazz's tutorial (available from http://wiki.superfamicom.org/snes/) is
  69. ; quite helpful with palette / sprites / DMA, especially starting at
  70. ; http://wiki.superfamicom.org/snes/show/Working+with+VRAM+-+Loading+the+Palette
  71. ; 16-bit X/Y registers. Used for DMA source address & transfer size, both of
  72. ; which want 16-bit values.
  73. ; TODO(mcmillen): change back to 8-bit when we're done?
  74. rep #%00010000
  75. ; 8-bit A/B registers. Used for DMA source bank & destination address.
  76. sep #%00100000
  77. ; We only need one palette entry, so we just initialize it manually.
  78. ; We could also do this with a DMA transfer (like we do with the tile data
  79. ; below), but it seems overkill for just one entry :)
  80. lda #34 ; Set the 34th palette entry.
  81. sta CGADDR
  82. lda.l PaletteData
  83. sta CGDATA
  84. lda.l PaletteData + 1
  85. sta CGDATA
  86. ; DMA 0 source address & bank.
  87. ldx #TileData
  88. stx DMA0SRC
  89. lda #:TileData
  90. sta DMA0SRCBANK
  91. ; DMA 0 transfer size.
  92. ldy #(15 * 16 *2) ; Also see the helpful "480 bytes" comment in tiles.asm.
  93. sty DMA0SIZE
  94. ; DMA 0 control register.
  95. ; Transfer type 001 = 2 addresses, LH.
  96. lda #%00000001
  97. sta DMA0CTRL
  98. ; DMA 0 destination.
  99. lda #$18 ; Upper-byte is assumed to be $21, so this is $2118 & $2119.
  100. sta DMA0DST
  101. ; $2116 sets the word address for accessing VRAM.
  102. ldy #$0000
  103. sty VMADDR
  104. ; Enable DMA channel 0.
  105. lda #%00000001
  106. sta DMAENABLE
  107. ; VRAM writing mode. Increments the address every time we write to $2119.
  108. lda #%10000000
  109. sta VMAIN
  110. ; Set word address for accessing VRAM to $6000.
  111. ldx #$6000 ; BG 2 starts here.
  112. stx VMADDR
  113. ldx #$000A ; Stick one tile into BG2.
  114. stx VMDATA
  115. ; Set up the screen. 16x16 tiles for BG2, 8x8 tiles elsewhere, mode 0.
  116. lda #%00100000
  117. sta BGMODE
  118. ; $2108 is the BG2 VRAM location register.
  119. ; This tells it that the BG2 data starts at $6000.
  120. lda #%01100000
  121. sta BG2SC
  122. stz BG12NBA
  123. ; Main screen: enable BG2.
  124. lda #%00000010
  125. sta MSENABLE
  126. rts
  127. VBlankHandler:
  128. jsr VBlankCounter ; DEBUG
  129. jsr JoypadHandler
  130. jsr SetBackgroundColor
  131. jsr SetPlayerPosition
  132. rti
  133. VBlankCounter:
  134. ; Increment a counter of how many VBlanks we've done.
  135. inc $14
  136. lda $14
  137. cmp #$00
  138. bne VBlankCounterDone
  139. inc $15
  140. lda $15
  141. cmp #$00
  142. bne VBlankCounterDone
  143. inc $16
  144. lda $16
  145. cmp #$00
  146. bne VBlankCounterDone
  147. inc $17
  148. VBlankCounterDone:
  149. rts
  150. JoypadHandler:
  151. jsr JoypadDebug ; DEBUG
  152. JoypadUp:
  153. lda JOY1H
  154. and #$08 ; Up
  155. cmp #$08
  156. bne JoypadDown ; Button not pressed.
  157. lda $21
  158. cmp #0
  159. beq JoypadDown ; Value saturated.
  160. dec $21
  161. dec $21
  162. JoypadDown:
  163. lda JOY1H
  164. and #$04
  165. cmp #$04
  166. bne JoypadLeft ; Button not pressed.
  167. lda $21
  168. cmp #(224 - 16)
  169. beq JoypadLeft ; Value saturated.
  170. inc $21
  171. inc $21
  172. JoypadLeft:
  173. lda JOY1H
  174. and #$02 ; Left
  175. cmp #$02
  176. bne JoypadRight ; Button not pressed.
  177. lda $20
  178. cmp #0
  179. beq JoypadRight ; Value saturated.
  180. dec $20
  181. dec $20
  182. JoypadRight:
  183. lda JOY1H
  184. and #$01
  185. cmp #$01 ; Right
  186. bne JoypadB ; Button not pressed.
  187. lda $20
  188. cmp #(256 - 16)
  189. beq JoypadB ; Value saturated.
  190. inc $20
  191. inc $20
  192. JoypadB:
  193. lda JOY1H
  194. and #$80 ; B
  195. cmp #$80
  196. bne JoypadA ; Button not pressed.
  197. lda $22
  198. cmp #0
  199. beq JoypadA ; Value saturated.
  200. dec $22
  201. JoypadA:
  202. lda JOY1L
  203. and #$80 ; A
  204. cmp #$80
  205. bne JoypadY ; Button not pressed.
  206. lda $22
  207. cmp #31
  208. beq JoypadY ; Value saturated.
  209. inc $22
  210. JoypadY:
  211. lda JOY1H
  212. and #$40 ; Y
  213. cmp #$40
  214. bne JoypadX ; Button not pressed.
  215. lda $23
  216. cmp #0
  217. beq JoypadX ; Value saturated.
  218. dec $23
  219. JoypadX:
  220. lda JOY1L
  221. and #$40 ; X
  222. cmp #$40
  223. bne JoypadL ; Button not pressed.
  224. lda $23
  225. cmp #31
  226. beq JoypadL ; Value saturated.
  227. inc $23
  228. JoypadL:
  229. lda JOY1L
  230. and #$20 ; L
  231. cmp #$20
  232. bne JoypadR ; Button not pressed.
  233. lda $24
  234. cmp #0
  235. beq JoypadR ; Value saturated.
  236. dec $24
  237. JoypadR:
  238. lda JOY1L
  239. and #$10 ; R
  240. cmp #$10
  241. bne JoypadDone ; Button not pressed.
  242. lda $24
  243. cmp #31
  244. beq JoypadDone ; Value saturated.
  245. inc $24
  246. ; TODO(mcmillen): have Start and Select do something too.
  247. JoypadDone:
  248. rts
  249. JoypadDebug:
  250. ; Load joypad registers into RAM for easier inspection.
  251. lda JOY1L
  252. sta $10
  253. lda JOY1H
  254. sta $11
  255. lda JOY2L
  256. sta $12
  257. lda JOY2H
  258. sta $13
  259. rts
  260. SetBackgroundColor:
  261. ; $22 $23 $24 are (R, G, B), each ranging from [0-31].
  262. ; The palette color format is 15-bit: [0bbbbbgg][gggrrrrr]
  263. ; Set the background color.
  264. ; Entry 0 corresponds to the SNES background color.
  265. stz CGADDR
  266. ; Compute and the low-order byte and store it in CGDATA.
  267. lda $23 ; Green.
  268. .rept 5
  269. asl
  270. .endr
  271. ora $22 ; Red.
  272. sta CGDATA
  273. ; Compute the high-order byte and store it in CGDATA.
  274. lda $24 ; Blue.
  275. .rept 2
  276. asl
  277. .endr
  278. sta $00
  279. lda $23 ; Green.
  280. .rept 3
  281. lsr
  282. .endr
  283. ora $00
  284. sta CGDATA
  285. rts
  286. SetPlayerPosition:
  287. ; Make sure the high byte of A is zeroed out.
  288. lda #$00
  289. xba
  290. ; Get player x and convert it to a scroll offset.
  291. lda $0020
  292. ConvertXCoordinate
  293. sta BG2HOFS
  294. xba
  295. sta BG2HOFS
  296. ; Make sure the high byte of A is zeroed out.
  297. lda #$00
  298. xba
  299. ; Get player y and convert it to a scroll offset.
  300. lda $0021
  301. ConvertYCoordinate
  302. sta BG2VOFS
  303. xba
  304. sta BG2VOFS
  305. rts
  306. FillScratch:
  307. lda #$42 ; B
  308. ldx #0
  309. FillScratchLoop:
  310. sta $00,X
  311. inx
  312. cpx #$10
  313. bne FillScratchLoop
  314. rts
  315. .ENDS
  316. .BANK 1 SLOT 0
  317. .ORG 0
  318. .SECTION "TileData"
  319. .INCLUDE "tiles.asm"
  320. .ENDS