-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathpong.asm
273 lines (253 loc) · 5.37 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
; Author: Lucas Avanço (avanco89 at gmail)
; based on "thin red line by Kirk Israel"
; based on Stella Programming Guide
processor 6502
include vcs.h
org $F000
; Variables (memory region: $80 to $FF)
YPosBall = $80
BallSize = $81
DirectionBall = $82
Top = $83
Down = $84
BallLeftRight = $85
Player0Pos = $86
Player1Pos = $87
Player0Size = $88
Player1Size = $89
Player0ActualSize = $90
Player1ActualSize = $91
LifePlayer0 = $92
LifePlayer1 = $93
Start ; init stuff:
SEI ; no interruptions
CLD ; clear BCD Math Bit
LDX #$FF ; X to up
TXS ; stack pointer = X
LDA #0
ClearMem
STA 0,X ; MEM[X+0] = Accumulator value
DEX ; X--
BNE ClearMem
LDA #190
STA YPosBall
LDA #194
STA Top ; it will allow change ball direction to down
LDA #6
STA Down ; it will allow change ball direction to up
LDA #0
STA BallSize
STA DirectionBall ; 0: down, 1: up
LDA #$10
STA BallLeftRight ; $10: left, $F0: right
LDA #110
STA Player0Pos
STA Player1Pos
LDA #0
STA Player0Size ; draw controller
STA Player1Size
LDA #30
STA Player0ActualSize ; true size
STA Player1ActualSize
LDA #30
STA LifePlayer0
STA LifePlayer1
SetColors
LDA #$44
STA COLUBK ; background color
LDA #$21 ; defining PlayField size (D0) and Ball size (D4, D5)
STA CTRLPF
LDA #$10
STA PF0
LDA #$10 ; ball color
STA COLUPF
MainLoop
LDA #2 ; VSYNC D1 = 1 --> turn off electron beam,
; position it at the top of the screen
STA VSYNC ; VSYNC must be sent for at least 3 scanlines
STA WSYNC ; by TIA
STA WSYNC
STA WSYNC
LDA #0
STA VSYNC ; the time is over
LDA #43 ; 37 scanlines * 76 machine cycles = 2812
; 2812 + 5 cycles(init timer) + 3 cycles(STA WSYNC) + 6 cycles(loop check)
; Finally we have 2812-14=2798 cycles while VBLANK scanlines, and 2798/64=43
STA TIM64T
LDA #2
STA VBLANK
; game logic, timer is running
LDA DirectionBall
BNE BallUp
DEC YPosBall
LDA Down
CMP YPosBall
BNE EndBallUpDown
BallUp
LDA #1
STA DirectionBall
INC YPosBall
LDA Top
CMP YPosBall
BNE EndBallUpDown
LDA #0
STA DirectionBall
EndBallUpDown
; input control Player0: down and up
LDA #%00010000 ;Up?
BIT SWCHA
BNE SkipMoveDown0
INC Player0Pos
INC Player0Pos
SkipMoveDown0
LDA #%00100000 ;Down?
BIT SWCHA
BNE SkipMoveUp0
DEC Player0Pos
DEC Player0Pos
SkipMoveUp0
; input control Player1: down and up
LDA #%00000001 ;Up?
BIT SWCHA
BNE SkipMoveDown1
INC Player1Pos
INC Player1Pos
SkipMoveDown1
LDA #%00000010 ;Down?
BIT SWCHA
BNE SkipMoveUp1
DEC Player1Pos
DEC Player1Pos
SkipMoveUp1
;check collision: Player0 and Ball
LDA #%1000000
BIT CXP0FB
BEQ NoCollisionP0Ball
LDA #$10 ; ball must go left
STA BallLeftRight
NoCollisionP0Ball
;check collision: Player1 and Ball
LDA #%1000000
BIT CXP1FB
BEQ NoCollisionP1Ball
LDA #$F0 ; ball must go right
STA BallLeftRight
NoCollisionP1Ball
;check collision: Ball and PlayField
LDA #%10000000
BIT CXBLPF
BEQ NoCollisionBallPF
STA CXCLR ; clear all collisions
LDX #$10
CPX BallLeftRight ; check ball direction and decide who fail and will suffer punishment
BEQ Player1Penalty
Player0Penalty
DEC Player0ActualSize
DEC LifePlayer0
BEQ EndGame
JMP NoCollisionBallPF
Player1Penalty
DEC Player1ActualSize
DEC LifePlayer1
BEQ EndGame
JMP NoCollisionBallPF
NoCollisionBallPF
STA CXCLR ; clear all collisions
JMP WaitVBlankEnd
EndGame
JMP Start
WaitVBlankEnd
LDA INTIM ; load timer
BNE WaitVBlankEnd ; killing time if the timer != 0
; 37 VBLANK scanlines has gone
STA WSYNC
STA RESP1
LDY #191 ; count scanlines
STA WSYNC ; wait for scanline end, we do not wanna begin at the middle of one
STA VBLANK ; VBLANK D1 = 0
LDA BallLeftRight ; speed
STA HMBL
LDA #$00 ; speed
STA GRP0 ; D0 to D7 are considered
STA GRP1
STA WSYNC
STA HMOVE ; strobe register like WSYNC
ScanLoop
STA WSYNC
; check if we are at ball position, scanline
CPY YPosBall
BEQ ActiveBallSize
LDA BallSize
BNE DrawingBall
NoBall
LDA #0
STA ENABL
JMP OutBall
ActiveBallSize
LDA #8
STA BallSize
DrawingBall
LDA #2
STA ENABL
DEC BallSize
OutBall
; check Player0 position
CPY Player0Pos
BEQ ActivePlayer0Size
LDA Player0Size
BNE DrawingPlayer0
NoPlayer0
LDA #0
STA GRP0
JMP OutPlayer0
ActivePlayer0Size
LDA Player0ActualSize
STA Player0Size
DrawingPlayer0
LDA #2
STA GRP0
DEC Player0Size
OutPlayer0
; check Player1 position
CPY Player1Pos
BEQ ActivePlayer1Size
LDA Player1Size
BNE DrawingPlayer1
NoPlayer1
LDA #0
STA GRP1
JMP OutPlayer1
ActivePlayer1Size
LDA Player1ActualSize
STA Player1Size
DrawingPlayer1
LDA #2
STA GRP1
DEC Player1Size
OutPlayer1
DEY
BNE ScanLoop
LDA #2
STA WSYNC
STA VBLANK ; turn it on, actual tv picture has gone
; Overscan
LDX #30
OverScanWait
STA WSYNC
DEX
BNE OverScanWait
JMP MainLoop
; Kirk Israel words:
; OK, last little bit of crap to take care of.
; there are two special memory locations, $FFFC and $FFFE
; When the atari starts up, a "reset" is done (which has nothing to do with
; the reset switch on the console!) When this happens, the 6502 looks at
; memory location $FFFC (and by extension its neighbor $FFFD, since it's
; seaching for both bytes of a full memory address) and then goes to the
; location pointed to by $FFFC/$FFFD...so our first .word Start tells DASM
; to put the binary data that we labeled "Start" at the location we established
; with org. And then we do it again for $FFFE/$FFFF, which is for a special
; event called a BRK which you don't have to worry about now.
org $FFFC
.word Start
.word Start