-
Notifications
You must be signed in to change notification settings - Fork 0
/
pong.asm
500 lines (432 loc) · 8.9 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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
; Load the program at 0x4920
* = $4920
; Adresses on the machine
define ADDR_CONTROL $4900
define ADDR_TEXT_MODE_BACKGROUND_COLOR $4901
define ADDR_TEXT_MODE_FOREGROUND_COLOR $4902
define ADDR_EVENT_TYPE $4903
define ADDR_EVENT_ARG1 $4904
define ADDR_EVENT_ARG2 $4905
define ADDR_CLOCK1 $4906
define ADDR_CLOCK2 $4907
define ADDR_AUDIO1 $4908
define ADDR_AUDIO2 $4909
define ADDR_AUDIO3 $490A
define ADDR_DRAW_METHOD $490B
define ADDR_DRAW_ARG1 $490C
define ADDR_DRAW_ARG2 $490D
define ADDR_DRAW_ARG3 $490E
define ADDR_DRAW_ARG4 $490F
define ADDR_TIMER1_LO $4910
define ADDR_TIMER1_HI $4911
define ADDR_TIMER2_LO $4912
define ADDR_TIMER2_HI $4913
define ADDR_COUNTER1 $4914
define ADDR_COUNTER2 $4915
; Various constants used when interacting with the machine
define EVENT_UNSPECIFIED $00
define EVENT_KEYDOWN $01
define EVENT_KEYUP $02
define EVENT_MOUSEMOVE $03
define EVENT_MOUSEDOWN $04
define EVENT_MOUSEUP $05
define EVENT_CLOCK1 $06
define EVENT_CLOCK2 $07
define EVENT_TIMER1 $08
define EVENT_TIMER2 $09
define EVENT_COUNTER1 $0A
define EVENT_COUNTER2 $0B
define KEY_W $16
define KEY_S $12
define KEY_I $08
define KEY_K $0A
define BLUE $03
define YELLOW $FC
define WHITE $FF
define BLACK $00
define DRAW_RECTANGLE $00
define DRAW_SQUARE $01
define DRAW_DOT $02
define DRAW_LINE $03
define BRUSH_SET_BODY $80
define BRUSH_SET_OUTLINE $81
define RACKET_WIDTH 1
define RACKET_HEIGHT 8
define RACKET1_X 1
define RACKET2_X 62
define BALL_DIAMETER 1
define SCREEN_HEIGHT 36
define SCREEN_WIDTH 64
define RACKET_INITIAL_Y 14
define BALL_INITIAL_X 18
define BALL_INITIAL_Y 32
define WINNING_SCORE 10
define BEEP_SHORT_AUDIO $D9
define BEEP_LONG_AUDIO $D3
define SILENT_AUDIO $19
define RACKETY_MAX 28
define SCREEN_HEIGHT_M1 35
define SCREEN_HEIGHT_M2 34
define SCREEN_WIDTH_M1 63
define RACKET1_X_P1 2
define RACKET2_X_M1 61
define BALL_UPDATE_CLOCK $10
; Memory locations storing program variables
define V_RACKET1_POS $00
define V_RACKET2_POS $01
define V_SCORE1 $02
define V_SCORE2 $03
define V_BALL_POS_X $04
define V_BALL_POS_Y $05
define V_BALL_VEL_X $06
define V_BALL_VEL_Y $07
define V_INT_ARGUMENT_STORAGE $08
L_RST:
sei
jsr L_RESET_GAME
lda #BALL_UPDATE_CLOCK
sta ADDR_CLOCK1
cli
L_MAIN_LOOP:
wai
jmp L_MAIN_LOOP
L_IRQ:
lda ADDR_EVENT_TYPE
cmp #EVENT_KEYDOWN
beq L_IRQ_KEYDOWN
cmp #EVENT_CLOCK1
beq L_IRQ_CLOCK
cmp #EVENT_TIMER1
beq L_IRQ_TIMER
jmp L_IRQ_EXIT
L_IRQ_KEYDOWN:
jsr L_HANDLE_KEYPRESS
jmp L_IRQ_EXIT
L_IRQ_CLOCK:
jsr L_HANDLE_CLOCK
jmp L_IRQ_EXIT
L_IRQ_TIMER:
jsr L_STOP_BEEP
jmp L_IRQ_EXIT
L_IRQ_EXIT:
rti
L_START_SHORT_BEEP:
lda #BEEP_SHORT_AUDIO
sta ADDR_AUDIO1
lda #$00
sta ADDR_TIMER1_HI
lda #$0A
sta ADDR_TIMER1_LO
rts
L_START_LONG_BEEP:
lda #BEEP_LONG_AUDIO
sta ADDR_AUDIO1
lda #$00
sta ADDR_TIMER1_HI
lda #$1E
sta ADDR_TIMER1_LO
rts
L_STOP_BEEP:
lda #SILENT_AUDIO
sta ADDR_AUDIO1
rts
L_RESET_GAME:
lda #$00
sta V_SCORE1
lda #$00
sta V_SCORE2
jsr L_RESET_POSITIONS
rts
L_HANDLE_KEYPRESS:
lda ADDR_EVENT_ARG1
sta V_INT_ARGUMENT_STORAGE
cmp #KEY_W
beq L_HANDLE_KEYPRESS_W
cmp #KEY_S
beq L_HANDLE_KEYPRESS_S
cmp #KEY_I
beq L_HANDLE_KEYPRESS_I
cmp #KEY_K
beq L_HANDLE_KEYPRESS_K
jmp L_HANDLE_KEYPRESS_EXIT
L_HANDLE_KEYPRESS_W:
lda V_RACKET1_POS
cmp #$00
beq L_HANDLE_KEYPRESS_EXIT
clc
sbc #$01
sta V_RACKET1_POS
jmp L_HANDLE_KEYPRESS_EXIT
L_HANDLE_KEYPRESS_S:
lda V_RACKET1_POS
cmp #RACKETY_MAX
beq L_HANDLE_KEYPRESS_EXIT
clc
adc #$01
sta V_RACKET1_POS
jmp L_HANDLE_KEYPRESS_EXIT
L_HANDLE_KEYPRESS_I:
lda V_RACKET2_POS
cmp #$00
beq L_HANDLE_KEYPRESS_EXIT
clc
sbc #$01
sta V_RACKET2_POS
jmp L_HANDLE_KEYPRESS_EXIT
L_HANDLE_KEYPRESS_K:
lda V_RACKET2_POS
cmp #RACKETY_MAX
beq L_HANDLE_KEYPRESS_EXIT
clc
adc #$01
sta V_RACKET2_POS
jmp L_HANDLE_KEYPRESS_EXIT
L_HANDLE_KEYPRESS_EXIT:
rts
L_HANDLE_CLOCK:
jsr L_CHECK_SCORE
jsr L_UPDATE_BALL
jsr L_CHECK_BALL_COLLISIONS
jsr L_SET_COLOR_BLACK
jsr L_CLEAR_SCREEN
jsr L_SET_COLOR_WHITE
jsr L_DRAW_RACKETS
jsr L_DRAW_BALL
jsr L_DRAW_SCORE
rts
L_RESET_POSITIONS:
lda #RACKET_INITIAL_Y
sta V_RACKET1_POS
lda #RACKET_INITIAL_Y
sta V_RACKET2_POS
jsr L_RESET_BALL_POSITION
rts
L_RESET_BALL_POSITION:
lda #BALL_INITIAL_Y
sta V_BALL_POS_X
lda #BALL_INITIAL_X
sta V_BALL_POS_Y
lda #$01
sta V_BALL_VEL_X
lda #$01
sta V_BALL_VEL_Y
rts
L_UPDATE_BALL:
lda V_BALL_VEL_X
bne L_UPDATE_BALL_X_INC
lda V_BALL_POS_X
clc
sbc #$01
sta V_BALL_POS_X
jmp L_UPDATE_BALL_X_END
L_UPDATE_BALL_X_INC:
lda V_BALL_POS_X
clc
adc #$01
sta V_BALL_POS_X
jmp L_UPDATE_BALL_X_END
L_UPDATE_BALL_X_END:
lda V_BALL_VEL_Y
bne L_UPDATE_BALL_Y_INC
lda V_BALL_POS_Y
clc
sbc #$01
sta V_BALL_POS_Y
jmp L_UPDATE_BALL_Y_END
L_UPDATE_BALL_Y_INC:
lda V_BALL_POS_Y
clc
adc #$01
sta V_BALL_POS_Y
nop
jmp L_UPDATE_BALL_Y_END
L_UPDATE_BALL_Y_END:
rts
L_CHECK_BALL_COLLISIONS:
lda V_BALL_POS_Y
cmp #$00
bne L_CHECK_BALL_COLLISIONS_NO_TOP_HIT
lda #$01
sta V_BALL_VEL_Y
jsr L_START_SHORT_BEEP
L_CHECK_BALL_COLLISIONS_NO_TOP_HIT:
lda V_BALL_POS_Y
cmp #SCREEN_HEIGHT_M1
bne L_CHECK_BALL_COLLISIONS_NO_BOTTOM_HIT
lda #$00
sta V_BALL_VEL_Y
jsr L_START_SHORT_BEEP
L_CHECK_BALL_COLLISIONS_NO_BOTTOM_HIT:
lda V_BALL_POS_Y
cmp V_RACKET1_POS
bcc L_CHECK_BALL_COLLISIONS_NO_LEFT_HIT
lda V_BALL_POS_Y
clc
sbc V_RACKET1_POS
cmp #RACKET_HEIGHT
bcs L_CHECK_BALL_COLLISIONS_NO_LEFT_HIT
lda V_BALL_POS_X
cmp #RACKET1_X_P1
bne L_CHECK_BALL_COLLISIONS_NO_LEFT_HIT
lda #$01
sta V_BALL_VEL_X
jsr L_START_SHORT_BEEP
L_CHECK_BALL_COLLISIONS_NO_LEFT_HIT:
lda V_BALL_POS_Y
cmp V_RACKET2_POS
bcc L_CHECK_BALL_COLLISIONS_NO_RIGHT_HIT
lda V_BALL_POS_Y
clc
sbc V_RACKET2_POS
cmp #RACKET_HEIGHT
bcs L_CHECK_BALL_COLLISIONS_NO_RIGHT_HIT
lda V_BALL_POS_X
cmp #RACKET2_X_M1
bne L_CHECK_BALL_COLLISIONS_NO_RIGHT_HIT
lda #$00
sta V_BALL_VEL_X
jsr L_START_SHORT_BEEP
L_CHECK_BALL_COLLISIONS_NO_RIGHT_HIT:
lda V_BALL_POS_X
cmp #$00
bne L_CHECK_BALL_COLLISIONS_CHECK_RIGHT_GOAL
lda V_SCORE2
clc
adc #$01
sta V_SCORE2
jsr L_RESET_BALL_POSITION
jsr L_START_LONG_BEEP
L_CHECK_BALL_COLLISIONS_CHECK_RIGHT_GOAL:
lda V_BALL_POS_X
cmp #SCREEN_WIDTH_M1
bne L_CHECK_BALL_COLLISIONS_EXIT
lda V_SCORE1
clc
adc #$01
sta V_SCORE1
jsr L_RESET_BALL_POSITION
jsr L_START_LONG_BEEP
L_CHECK_BALL_COLLISIONS_EXIT:
rts
L_CHECK_SCORE:
lda V_SCORE1
cmp #$0A
beq L_CHECK_SCORE_RESET
lda V_SCORE2
cmp #$0A
beq L_CHECK_SCORE_RESET
jmp L_CHECK_SCORE_END
L_CHECK_SCORE_RESET:
jsr L_RESET_GAME
L_CHECK_SCORE_END:
rts
L_SET_COLOR_BLACK:
lda #BLACK
sta ADDR_DRAW_ARG1
lda #BRUSH_SET_BODY
sta ADDR_DRAW_METHOD
lda #BRUSH_SET_OUTLINE
sta ADDR_DRAW_METHOD
rts
L_SET_COLOR_WHITE:
lda #WHITE
sta ADDR_DRAW_ARG1
lda #BRUSH_SET_BODY
sta ADDR_DRAW_METHOD
lda #BRUSH_SET_OUTLINE
sta ADDR_DRAW_METHOD
rts
L_SET_COLOR_BLUE:
lda #BLUE
sta ADDR_DRAW_ARG1
lda #BRUSH_SET_BODY
sta ADDR_DRAW_METHOD
lda #BRUSH_SET_OUTLINE
sta ADDR_DRAW_METHOD
rts
L_SET_COLOR_YELLOW:
lda #YELLOW
sta ADDR_DRAW_ARG1
lda #BRUSH_SET_BODY
sta ADDR_DRAW_METHOD
lda #BRUSH_SET_OUTLINE
sta ADDR_DRAW_METHOD
rts
L_CLEAR_SCREEN:
lda #$00
sta ADDR_DRAW_ARG1
sta ADDR_DRAW_ARG2
lda #SCREEN_WIDTH
sta ADDR_DRAW_ARG3
lda #SCREEN_HEIGHT
sta ADDR_DRAW_ARG4
lda #DRAW_RECTANGLE
sta ADDR_DRAW_METHOD
rts
L_DRAW_RACKETS:
lda #RACKET1_X
sta ADDR_DRAW_ARG1
sta ADDR_DRAW_ARG3
lda V_RACKET1_POS
sta ADDR_DRAW_ARG2
clc
adc #RACKET_HEIGHT
sta ADDR_DRAW_ARG4
lda #DRAW_LINE
sta ADDR_DRAW_METHOD
lda #RACKET2_X
sta ADDR_DRAW_ARG1
sta ADDR_DRAW_ARG3
lda V_RACKET2_POS
sta ADDR_DRAW_ARG2
clc
adc #RACKET_HEIGHT
sta ADDR_DRAW_ARG4
lda #DRAW_LINE
sta ADDR_DRAW_METHOD
rts
L_DRAW_BALL:
lda V_BALL_POS_X
sta ADDR_DRAW_ARG1
lda V_BALL_POS_Y
sta ADDR_DRAW_ARG2
lda #DRAW_DOT
sta ADDR_DRAW_METHOD
rts
L_DRAW_SCORE:
jsr L_SET_COLOR_YELLOW
lda #$00
sta ADDR_DRAW_ARG1
lda #SCREEN_HEIGHT_M1
sta ADDR_DRAW_ARG2
lda V_SCORE1
sta ADDR_DRAW_ARG3
lda #SCREEN_HEIGHT_M1
sta ADDR_DRAW_ARG4
lda #DRAW_LINE
sta ADDR_DRAW_METHOD
jsr L_SET_COLOR_BLUE
lda #$00
sta ADDR_DRAW_ARG1
lda #SCREEN_HEIGHT_M2
sta ADDR_DRAW_ARG2
lda V_SCORE2
sta ADDR_DRAW_ARG3
lda #SCREEN_HEIGHT_M2
sta ADDR_DRAW_ARG4
lda #DRAW_LINE
sta ADDR_DRAW_METHOD
jsr L_SET_COLOR_WHITE
lda #$0A
sta ADDR_DRAW_ARG1
lda #SCREEN_HEIGHT_M2
sta ADDR_DRAW_ARG2
lda #DRAW_DOT
sta ADDR_DRAW_METHOD
lda #$0A
sta ADDR_DRAW_ARG1
lda #SCREEN_HEIGHT_M1
sta ADDR_DRAW_ARG2
lda #DRAW_DOT
sta ADDR_DRAW_METHOD
rts