-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnake.psm
283 lines (246 loc) · 6.64 KB
/
snake.psm
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
; port id's of picoblaze input/output devices
CONSTANT column_port_id, 00
CONSTANT row_port_id, 01
CONSTANT data_port_id, 02
CONSTANT ps2_port_id, 03
CONSTANT rand_port_id, 04
; ps2 keycodes
CONSTANT keycode_left, 6B
CONSTANT keycode_right, 74
CONSTANT keycode_up, 75
CONSTANT keycode_down, 72
CONSTANT keycode_enter, 5A
; game constants
CONSTANT init_snake_len, 02
; register aliases
NAMEREG sA, reg_fb_col
NAMEREG sB, reg_fb_row
NAMEREG sC, reg_fb_data
NAMEREG sD, reg_ps2_data
NAMEREG sE, reg_counter1
NAMEREG sF, reg_score
NAMEREG s9, reg_isfood
NAMEREG s8, reg_snake_direction
NAMEREG s7, reg_snake_len
NAMEREG s6, reg_snake_head_row
NAMEREG s5, reg_snake_head_col
NAMEREG s4, reg_snake_tail_row
NAMEREG s3, reg_snake_tail_col
NAMEREG s2, reg_ram_index_head ; head writes the direction its going to this address
NAMEREG s1, reg_ram_index_tail ; tail takes the direction and erases
; reset vector - at address 0, program always starts here
ADDRESS 000
start_game:
CALL clear_fb
CALL load_food
CALL init_snake
ENABLE INTERRUPT
; infinite loop until the game is lost
main_game:
LOAD reg_isfood, 00 ; clear register that tell us whether the pixel is a food pixel
; head insertion
COMPARE reg_snake_direction, keycode_left
JUMP Z, add_to_snake_left
COMPARE reg_snake_direction, keycode_right
JUMP Z, add_to_snake_right
COMPARE reg_snake_direction, keycode_up
JUMP Z, add_to_snake_up
COMPARE reg_snake_direction, keycode_down
JUMP Z, add_to_snake_down
add_to_snake_left:
SUB reg_snake_head_col, 01
JUMP cont
add_to_snake_right:
ADD reg_snake_head_col, 01
JUMP cont
add_to_snake_up:
SUB reg_snake_head_row, 01
JUMP cont
add_to_snake_down:
ADD reg_snake_head_row, 01
JUMP cont
cont:
LOAD reg_fb_col, reg_snake_head_col
LOAD reg_fb_row, reg_snake_head_row
; check if within the bounds of our screen
LOAD s0, reg_fb_row
AND s0, 20
JUMP NZ, end_game
LOAD s0, reg_fb_col
SUB s0, 28
COMPARE s0, 00
JUMP Z, end_game
LOAD s0, reg_fb_col
AND s0, 40
COMPARE s0, 00
JUMP NZ, end_game
CALL fb_read
COMPARE reg_fb_data, 02 ; is read pixel a food pixel?
JUMP NZ, cont2
ADD reg_score, 01
LOAD reg_isfood, 01
cont2:
COMPARE reg_fb_data, 01 ; is read pixel snake?
JUMP NZ, cont4
JUMP end_game ; end game
cont4:
LOAD reg_fb_data, 01 ; code for snake pixel is 01
CALL fb_insert
STORE reg_snake_direction, (reg_ram_index_head) ; store the direction we went into scratchpad ram
ADD reg_ram_index_head, 01
; tail removal
COMPARE reg_isfood, 01 ; if we ate food, don't remove anything
JUMP Z, cont3
LOAD reg_fb_col, reg_snake_tail_col
LOAD reg_fb_row, reg_snake_tail_row
CALL fb_remove
FETCH s0, (reg_ram_index_tail) ; fetch direction to remove next from rom
ADD reg_ram_index_tail, 01
COMPARE s0, keycode_left
JUMP Z, remove_from_snake_left
COMPARE s0, keycode_right
JUMP Z, remove_from_snake_right
COMPARE s0, keycode_up
JUMP Z, remove_from_snake_up
COMPARE s0, keycode_down
JUMP Z, remove_from_snake_down
remove_from_snake_left:
SUB reg_snake_tail_col, 01
JUMP cont1
remove_from_snake_right:
ADD reg_snake_tail_col, 01
JUMP cont1
remove_from_snake_up:
SUB reg_snake_tail_row, 01
JUMP cont1
remove_from_snake_down:
ADD reg_snake_tail_row, 01
JUMP cont1
cont1:
cont3:
; randomly add food (or not add)
INPUT reg_isfood, rand_port_id
COMPARE reg_isfood, 07 ; compare with 10 (dec), because a third of the time the input will be smaller (random number from 0-30)
JUMP C, cont5
CALL food_insert
cont5:
OUTPUT reg_score, ps2_port_id
; output score
CALL delay
JUMP main_game
; routine that clears the screen and waits for input - enter for another game
end_game:
CALL clear_fb
another_game:
COMPARE reg_ps2_data, keycode_enter
JUMP Z, start_game
JUMP NZ, another_game
; 1s delay
delay:
LOAD s0, FF
LOAD reg_isfood, FF
LOAD reg_counter1, 40 ; 7f - 128 (1s) ; 40 - 64 (0.5s)
delayloop0:
delayloop1:
delayloop2:
SUB reg_isfood, 01
COMPARE reg_isfood, 00
JUMP NZ, delayloop2
SUB s0, 01
COMPARE s0, 00
JUMP NZ, delayloop1
SUB reg_counter1, 01
COMPARE reg_counter1, 00
JUMP NZ, delayloop0
RETURN
init_snake:
LOAD reg_score, 02
LOAD reg_snake_len, init_snake_len
LOAD reg_snake_direction, keycode_right
LOAD reg_ram_index_head, 01
LOAD reg_ram_index_tail, 00
LOAD s0, keycode_right ; load direction to remove next
STORE s0, 00 ; store direction to remove next
LOAD reg_snake_head_row, 02 ; snake head row
LOAD reg_snake_head_col, 03 ; snake head col
LOAD reg_snake_tail_row, 02 ; snake tail row
LOAD reg_snake_tail_col, 02 ; snake tail col
LOAD reg_fb_data, 01
LOAD reg_fb_row, 02
LOAD reg_fb_col, 02
CALL fb_insert
LOAD reg_fb_col, 03
CALL fb_insert
RETURN
; insert all the initial food
load_food:
LOAD reg_counter1, 10
food_loop:
CALL food_insert
SUB reg_counter1, 01
COMPARE reg_counter1, 00
JUMP NZ, food_loop
RETURN
; insert food at a random location : request two random numbers, insert 10 at location
food_insert:
INPUT reg_fb_col, rand_port_id
INPUT reg_fb_row, rand_port_id
CALL fb_read ; read pixel at wanted location to check if the snake is already occupying it
COMPARE reg_fb_data, 01 ; is read pixel a snake pixel?
JUMP Z, skipfood
LOAD reg_fb_data, 02
CALL fb_insert
skipfood:
RETURN
; clear ROM to all 0
clear_fb:
LOAD reg_fb_row, 00 ; outer loop counter
LOAD reg_fb_col, 00 ; inner loop counter
clear_outer_loop:
clear_inner_loop:
CALL fb_remove
ADD reg_fb_col, 01
COMPARE reg_fb_col, 28 ; decimal 40
JUMP NZ, clear_inner_loop
ADD reg_fb_row, 01
COMPARE reg_fb_row, 20 ; decimal 32
JUMP NZ, clear_outer_loop
RETURN
; frame buffer insert / remove routines
fb_insert:
;;;; do it manually before calling LOAD reg_fb_data, 01
OUTPUT reg_fb_row, row_port_id
OUTPUT reg_fb_col, column_port_id
OUTPUT reg_fb_data, data_port_id
RETURN
fb_remove:
;;;; do it manually before calling LOAD reg_fb_data, 00
LOAD reg_fb_data, 00
OUTPUT reg_fb_row, row_port_id
OUTPUT reg_fb_col, column_port_id
OUTPUT reg_fb_data, data_port_id
RETURN
fb_read:
OUTPUT reg_fb_row, row_port_id
OUTPUT reg_fb_col, column_port_id
INPUT reg_fb_data, data_port_id
RETURN
; interrupt service routine : load keycode into reg_direction from ps2 input if valid
isr:
INPUT reg_ps2_data, ps2_port_id
COMPARE reg_ps2_data, keycode_left
JUMP Z, load
COMPARE reg_ps2_data, keycode_right
JUMP Z, load
COMPARE reg_ps2_data, keycode_up
JUMP Z, load
COMPARE reg_ps2_data, keycode_down
JUMP NZ, fin
load:
LOAD reg_snake_direction, reg_ps2_data
fin:
; return from isr and enable interrupts
RETURNI ENABLE
; interrupt vector - at last address in the ROM
ADDRESS 3ff
JUMP isr