-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpong.asm
423 lines (313 loc) · 10.1 KB
/
pong.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
.inesprg 1 ; 1x 16KB PRG code
.ineschr 1 ; 1x 8KB CHR data
.inesmap 0 ; mapper 0 = NROM, no bank swapping
.inesmir 1 ; background mirroring
;;;;;;;;;;;;;;;
;; DECLARE SOME VARIABLES HERE
.rsset $0000 ;;start variables at ram location 0
gamestate .rs 1 ; .rs 1 means reserve one byte of space
ballx .rs 1 ; ball horizontal position
bally .rs 1 ; ball vertical position
ballup .rs 1 ; 1 = ball moving up
balldown .rs 1 ; 1 = ball moving down
ballleft .rs 1 ; 1 = ball moving left
ballright .rs 1 ; 1 = ball moving right
ballspeedx .rs 1 ; ball horizontal speed per frame
ballspeedy .rs 1 ; ball vertical speed per frame
paddle1ytop .rs 1 ; player 1 paddle top vertical position
paddle2ybot .rs 1 ; player 2 paddle bottom vertical position
buttons1 .rs 1 ; player 1 gamepad buttons, one bit per button
buttons2 .rs 1 ; player 2 gamepad buttons, one bit per button
score1 .rs 1 ; player 1 score, 0-15
score2 .rs 1 ; player 2 score, 0-15
;; DECLARE SOME CONSTANTS HERE
STATETITLE = $00 ; displaying title screen
STATEPLAYING = $01 ; move paddles/ball, check for collisions
STATEGAMEOVER = $02 ; displaying game over screen
RIGHTWALL = $F4 ; when ball reaches one of these, do something
TOPWALL = $20
BOTTOMWALL = $E0
LEFTWALL = $04
PADDLE1X = $08 ; horizontal position for paddles, doesnt move
PADDLE2X = $F0
;;;;;;;;;;;;;;;;;;
.bank 0
.org $C000
RESET:
SEI ; disable IRQs
CLD ; disable decimal mode
LDX #$40
STX $4017 ; disable APU frame IRQ
LDX #$FF
TXS ; Set up stack
INX ; now X = 0
STX $2000 ; disable NMI
STX $2001 ; disable rendering
STX $4010 ; disable DMC IRQs
vblankwait1: ; First wait for vblank to make sure PPU is ready
BIT $2002
BPL vblankwait1
clrmem:
LDA #$00
STA $0000, x
STA $0100, x
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
LDA #$FE
STA $0200, x
INX
BNE clrmem
vblankwait2: ; Second wait for vblank, PPU is ready after this
BIT $2002
BPL vblankwait2
LoadPalettes:
LDA $2002 ; read PPU status to reset the high/low latch
LDA #$3F
STA $2006 ; write the high byte of $3F00 address
LDA #$00
STA $2006 ; write the low byte of $3F00 address
LDX #$00 ; start out at 0
LoadPalettesLoop:
LDA palette, x ; load data from address (palette + the value in x)
; 1st time through loop it will load palette+0
; 2nd time through loop it will load palette+1
; 3rd time through loop it will load palette+2
; etc
STA $2007 ; write to PPU
INX ; X = X + 1
CPX #$20 ; Compare X to hex $10, decimal 16 - copying 16 bytes = 4 sprites
BNE LoadPalettesLoop ; Branch to LoadPalettesLoop if compare was Not Equal to zero
; if compare was equal to 32, keep going down
;;;Set some initial ball stats
LDA #$01
STA balldown
STA ballright
LDA #$00
STA ballup
STA ballleft
LDA #$50
STA bally
LDA #$80
STA ballx
LDA #$02
STA ballspeedx
STA ballspeedy
;;:Set starting game state
LDA #STATEPLAYING
STA gamestate
LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
STA $2000
LDA #%00011110 ; enable sprites, enable background, no clipping on left side
STA $2001
Forever:
JMP Forever ;jump back to Forever, infinite loop, waiting for NMI
NMI:
LDA #$00
STA $2003 ; set the low byte (00) of the RAM address
LDA #$02
STA $4014 ; set the high byte (02) of the RAM address, start the transfer
JSR DrawScore
;;This is the PPU clean up section, so rendering the next frame starts properly.
LDA #%10010000 ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
STA $2000
LDA #%00011110 ; enable sprites, enable background, no clipping on left side
STA $2001
LDA #$00 ;;tell the ppu there is no background scrolling
STA $2005
STA $2005
;;;all graphics updates done by here, run game engine
JSR ReadController1 ;;get the current button data for player 1
JSR ReadController2 ;;get the current button data for player 2
GameEngine:
LDA gamestate
CMP #STATETITLE
BEQ EngineTitle ;;game is displaying title screen
LDA gamestate
CMP #STATEGAMEOVER
BEQ EngineGameOver ;;game is displaying ending screen
LDA gamestate
CMP #STATEPLAYING
BEQ EnginePlaying ;;game is playing
GameEngineDone:
JSR UpdateSprites ;;set ball/paddle sprites from positions
RTI ; return from interrupt
;;;;;;;;
EngineTitle:
;;if start button pressed
;; turn screen off
;; load game screen
;; set starting paddle/ball position
;; go to Playing State
;; turn screen on
JMP GameEngineDone
;;;;;;;;;
EngineGameOver:
;;if start button pressed
;; turn screen off
;; load title screen
;; go to Title State
;; turn screen on
JMP GameEngineDone
;;;;;;;;;;;
EnginePlaying:
MoveBallRight:
LDA ballright
BEQ MoveBallRightDone ;;if ballright=0, skip this section
LDA ballx
CLC
ADC ballspeedx ;;ballx position = ballx + ballspeedx
STA ballx
LDA ballx
CMP #RIGHTWALL
BCC MoveBallRightDone ;;if ball x < right wall, still on screen, skip next section
LDA #$00
STA ballright
LDA #$01
STA ballleft ;;bounce, ball now moving left
;;in real game, give point to player 1, reset ball
MoveBallRightDone:
MoveBallLeft:
LDA ballleft
BEQ MoveBallLeftDone ;;if ballleft=0, skip this section
LDA ballx
SEC
SBC ballspeedx ;;ballx position = ballx - ballspeedx
STA ballx
LDA ballx
CMP #LEFTWALL
BCS MoveBallLeftDone ;;if ball x > left wall, still on screen, skip next section
LDA #$01
STA ballright
LDA #$00
STA ballleft ;;bounce, ball now moving right
;;in real game, give point to player 2, reset ball
MoveBallLeftDone:
MoveBallUp:
LDA ballup
BEQ MoveBallUpDone ;;if ballup=0, skip this section
LDA bally
SEC
SBC ballspeedy ;;bally position = bally - ballspeedy
STA bally
LDA bally
CMP #TOPWALL
BCS MoveBallUpDone ;;if ball y > top wall, still on screen, skip next section
LDA #$01
STA balldown
LDA #$00
STA ballup ;;bounce, ball now moving down
MoveBallUpDone:
MoveBallDown:
LDA balldown
BEQ MoveBallDownDone ;;if ballup=0, skip this section
LDA bally
CLC
ADC ballspeedy ;;bally position = bally + ballspeedy
STA bally
LDA bally
CMP #BOTTOMWALL
BCC MoveBallDownDone ;;if ball y < bottom wall, still on screen, skip next section
LDA #$00
STA balldown
LDA #$01
STA ballup ;;bounce, ball now moving down
MoveBallDownDone:
MovePaddleUp:
;;if up button pressed
;; if paddle top > top wall
;; move paddle top and bottom up
MovePaddleUpDone:
MovePaddleDown:
;;if down button pressed
;; if paddle bottom < bottom wall
;; move paddle top and bottom down
MovePaddleDownDone:
CheckPaddleCollision:
;;if ball x < paddle1x
;; if ball y > paddle y top
;; if ball y < paddle y bottom
;; bounce, ball now moving left
CheckPaddleCollisionDone:
JMP GameEngineDone
UpdateSprites:
LDA bally ;;update all ball sprite info
STA $0200
LDA #$30
STA $0201
LDA #$00
STA $0202
LDA ballx
STA $0203
;;update paddle sprites
RTS
DrawScore:
;;draw score on screen using background tiles
;;or using many sprites
RTS
;; Reading the input is done by the followin pattern where the sate of
;; all buttons is stored in one byte
; Accumulator buttons data
;bit: 7 6 5 4 3 2 1 0 Carry 7 6 5 4 3 2 1 0 Carry
;read button A 0 0 0 0 0 0 0 A 0 0 0 0 0 0 0 0 0 0
;LSR A 0 0 0 0 0 0 0 0 A 0 0 0 0 0 0 0 0 A
;ROL buttons 0 0 0 0 0 0 0 0 A 0 0 0 0 0 0 0 A 0
;read button B 0 0 0 0 0 0 0 B 0 0 0 0 0 0 0 0 A 0
;LSR A 0 0 0 0 0 0 0 0 B 0 0 0 0 0 0 0 A B
;ROL buttons 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B 0
;read button SEL 0 0 0 0 0 0 0 SEL 0 0 0 0 0 0 0 0 A 0
;LSR A 0 0 0 0 0 0 0 0 SEL 0 0 0 0 0 0 0 A SEL
;ROL buttons 0 0 0 0 0 0 0 0 0 0 0 0 0 0 A B SEL 0
;read button STA 0 0 0 0 0 0 0 STA 0 0 0 0 0 0 0 0 A 0
;LSR A 0 0 0 0 0 0 0 0 STA 0 0 0 0 0 0 0 A STA
;ROL buttons 0 0 0 0 0 0 0 0 0 0 0 0 0 A B SEL STA 0
ReadController1:
LDA #$01
STA $4016
LDA #$00
STA $4016
LDX #$08
ReadController1Loop:
LDA $4016
LSR A ; bit0 -> Carry
ROL buttons1 ; bit0 <- Carry
DEX
BNE ReadController1Loop
RTS
ReadController2:
LDA #$01
STA $4016
LDA #$00
STA $4016
LDX #$08
ReadController2Loop:
LDA $4017
LSR A ; bit0 -> Carry
ROL buttons2 ; bit0 <- Carry
DEX
BNE ReadController2Loop
RTS
;;;;;;;;;;;;;;
.bank 1
.org $E000
palette:
.db $22,$29,$1A,$0F, $22,$36,$17,$0F, $22,$30,$21,$0F, $22,$27,$17,$0F ;;background palette
.db $22,$1C,$15,$14, $22,$02,$38,$3C, $22,$1C,$15,$14, $22,$02,$38,$3C ;;sprite palette
sprites:
;vert tile attr horiz
.db $80, $32, $00, $80 ;sprite 0
.db $80, $33, $00, $88 ;sprite 1
.db $88, $34, $00, $80 ;sprite 2
.db $88, $35, $00, $88 ;sprite 3
.org $FFFA ;first of the three vectors starts here
.dw NMI ;when an NMI happens (once per frame if enabled) the
;processor will jump to the label NMI:
.dw RESET ;when the processor first turns on or is reset, it will jump
;to the label RESET:
.dw 0 ;external interrupt IRQ is not used in this tutorial
;;;;;;;;;;;;;;
.bank 2
.org $0000
.incbin "assets/mario.chr" ;includes 8KB graphics file from SMB1