forked from nanochess/lights
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lights.asm
305 lines (271 loc) · 5.81 KB
/
lights.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
;
; Follow the lights
;
; by Oscar Toledo G.
;
; Creation date: Jan/16/2020.
; Revision date: Jan/17/2020.
; Added victory tune after 31 good lights.
;
;
; Very useful info gathered from:
; https://www.waitingforfriday.com/?p=586
;
cpu 8086
%ifdef com_file
org 0x0100
%else
org 0x7c00
%endif
old_time: equ 0x00 ; Old ticks
button: equ 0x02 ; Button pressed
next_seq: equ 0x04 ; Next seq. number
timing: equ 0x06 ; Current timing
memory: equ 0x08 ; Start of memory
memory_end: equ 0x28 ; End of memory
start:
xor ax,ax
mov cx,memory_end/2
.0:
push ax ; Zero word initialize
loop .0 ; Repeat until completed
mov al,0x02 ; Text mode 80x25
int 0x10 ; Set up video mode
mov bp,sp ; Setup BP (Base Pointer)
in al,0x40 ; Get a pseudorandom number
xchg ax,si ; Put into SI
cld ; Clear Direction flag.
mov ax,0xb800 ; Point to video segment
mov ds,ax
mov es,ax
call show_buttons ; Show buttons
restart_game:
xor ax,ax ; Restart sequence
mov [bp+next_seq],ax
game_loop:
mov cl,15 ; Wait 0.8 seconds.
call wait_ticks
;
; Add a new light to sequence
;
mov di,[bp+next_seq] ; Curr. position.
mov ax,97 ; Generate random number
mul si
add ax,23
xchg ax,si ; SI = next seed.
; Notice it uses the
; high byte because the
; random period is
; longer.
and ah,0x03 ; Extract random from AH
add ah,0x31 ; Add ASCII 1
mov [bp+di+memory],ah ; Save into memory
mov ax,8 ; 8 approx 0.42 secs.
cmp di,5 ; For 5 or fewer lights.
jb .2
mov al,6 ; 6 approx 0.32 secs.
cmp di,13 ; For 13 or fewer lights.
jb .2
mov al,4 ; 4 approx 0.22 secs.
.2:
mov [bp+timing],ax
cmp di,31 ; Doing the 31st light?
je victory ; Yes, jump to victory.
inc byte [bp+next_seq]
;
; Show current sequence
;
xor di,di ; Restart counter
.1: mov al,[bp+di+memory] ; Read light
push di
mov [bp+button],al ; Push button
call show_buttons ; Show
mov cx,[bp+timing] ; Wait
call wait_ticks
call speaker_off ; Turn off
mov byte [bp+button],0
call show_buttons ; Depress button
call wait_tick
pop di
inc di ; Increase counter
cmp di,[bp+next_seq]
jne .1
;
; Empty keyboard buffer
;
.9:
mov ah,0x01 ; Check for key pressed.
int 0x16
je .8 ; No, jump.
mov ah,0x00 ; Read key.
int 0x16
jmp .9 ; Repeat loop
.8:
;
; Comparison of player input with
; sequence.
;
xor di,di ; Restart counter
.4: mov ah,0x00 ; Wait for a key
int 0x16
cmp al,0x1b ; Esc pressed?
je exit_game ; Yes, jump.
cmp al,0x31 ; Less than ASCII 1?
jb .4 ; Yes, jump.
cmp al,0x35 ; Higher than ASCII 4?
jnb .4 ; Yes, jump.
push ax
push di
mov [bp+button],al ; Push button
call show_buttons ; Show
mov cx,[bp+timing] ; Wait
call wait_ticks
call speaker_off ; Turn off
mov byte [bp+button],0
call show_buttons ; Depress button
call wait_tick
pop di
pop ax
cmp al,[bp+di+memory] ; Good hit?
jne wrong ; No, jump
inc di ; Increase counter
cmp di,[bp+next_seq]
jne .4
jmp game_loop
;
; Player defeat by wrong button
;
wrong: mov cx,28409 ; 1193180 / 42
call speaker ; Failure tone
mov cl,27 ; 1.5 secs
call wait_ticks
call speaker_off ; Turn off
mov cl,27 ; 1.5 secs
call wait_ticks
jmp restart_game ; Restart game
;
; Victory
;
victory:
mov al,'2' ; Victory tune
mov cx,14 ; 14 notes
.1: push cx
push ax
mov byte [bp+button],al
call show_buttons ; Play
mov cl,2 ; Wait 0.1 secs.
call wait_ticks
mov byte [bp+button],0 ; Depress
call show_buttons
pop ax
inc ax ; Next note
cmp al,'5' ; If goes to 5...
jne .2
mov al,'1' ; ...go back to 1.
.2:
pop cx
loop .1
jmp wrong ; Finish and restart
;
; Exit game
;
exit_game:
mov ax,0x0002 ; Clear screen by...
int 0x10 ; ...mode setup.
int 0x20 ; Exit to DOS / bootOS.
;
; Show game buttons
;
show_buttons:
mov di,0x0166 ; Top left on screen
mov bx,0x312f ; ASCII 1, white on green
mov cx,2873 ; 1193180 / 415.305 hz
call show_button
mov di,0x0192 ; Top right on screen
mov bx,0x324f ; ASCII 2, white on red
mov cx,3835 ; 1193180 / 311.127 hz
call show_button
mov di,0x0846 ; Bottom left on screen
mov bx,0x336f ; ASCII 3, white on brown
mov cx,4812 ; 1193180 / 247.942 hz
call show_button
mov di,0x0872 ; Bottom right on screen
mov bx,0x343f ; ASCII 4, white on turquoise
mov cx,5746 ; 1193180 / 207.652 hz
; Fall-through
show_button:
mov al,0x20 ; Fill with spaces
cmp bh,[bp+button] ; Is it pressed?
jne .0 ; No, jump.
call speaker ; Yes, play sound.
mov al,0xb0 ; Semi-filled block
.0:
mov cx,10 ; 10 rows high.
.1: push cx
mov ah,bl ; Set attribute byte.
mov cl,20 ; 20 columns width.
rep stosw ; Fill on screen
add di,160-20*2 ; Go to next row
pop cx
loop .1 ; Repeat until filled
mov al,bh ; Get button number
mov [di+20-5*160],ax ; Put on center
ret ; Return
;
; Wait for one tick
;
wait_tick:
mov cl,1
;
; Wait for several ticks
;
; Input:
; CL = Number of ticks
;
wait_ticks:
mov ch,0
.0:
push cx ; Save counter
.1:
mov ah,0x00 ; Read ticks
int 0x1a ; Call BIOS
cmp dx,[bp+old_time] ; Wait for tick change
je .1
mov [bp+old_time],dx ; Save new tick
pop cx ; Restore counter
loop .0 ; Loop until complete
ret ; Return
;
; Generate sound on PC speaker
;
; Input:
; CX = Frequency value.
; (calculate 1193180/freq = req. value)
;
speaker:
mov al,0xb6 ; Setup timer 2
out 0x43,al
mov al,cl ; Low byte of timer count
out 0x42,al
mov al,ch ; High byte of timer count
out 0x42,al
in al,0x61
or al,0x03 ; Wire PC speaker to timer 2
out 0x61,al
ret
;
; Turn speaker off
;
speaker_off:
in al,0x61
and al,0xfc ; Turn off
out 0x61,al
ret
;
; Boot sector signature
;
%ifdef com_file
%else
times 510-($-$$) db 0x4f
db 0x55,0xaa ; Make it a bootable sector
%endif