-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.asm
541 lines (464 loc) · 16.3 KB
/
main.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
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
.cdecls C, LIST, "msp430g2553.h"
;-----------------------------------------------------------------------
; Registers
; R12-15 are reserved as working variables in functions
; Returns should be done at R15
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; Variables
;-----------------------------------------------------------------------
; TIME-KEEPING
.bss time, 2 ; 16-bit
; PSEUDO-RANDOM NUMBER GENERATOR
.bss randA, 2 ; 16-bit
.bss randB, 2 ; 16-bit
.bss randC, 2 ; 16-bit
.bss randX, 2 ; 16-bit
; SEQUENCE AND CONTROL
.bss seq, 32 ; 32 * 8-bit array
.bss seqPos, 2 ; 16-bit
.bss seqTop, 2 ; 16-bit
; SKILL LEVEL
.bss ledOnTime, 2 ; 16-bit
.bss ledOffTime, 2 ; 16-bit
.bss btnTime, 2 ; 16-bit
; GAME STATE MACHINE
.bss state, 2 ; 16-bit
.bss score, 2 ; 16-bit
; LCD DRIVER
.bss lcdBuffer, 32 ; 32 * 8-bit array
; Buzzer
.bss buzzDiv, 2 ; 1 MHz / buzzDiv = freq
.bss buzzEnable, 2 ; Set to enable
;-----------------------------------------------------------------------
; Strings
;-----------------------------------------------------------------------
_welcome .string "---SIMON SAYS--->>>>>>>><<<<<<<<", 0
_skilllvl .string " Skill Level E M H X", 0
_extreme .string " EXTREME ", 0
_hard .string " HARD ", 0
_medium .string " MEDIUM ", 0
_easy .string " EASY ", 0
_score .string "SCORE -> ----------------", 0
_end .string "ROUNDS -> SCORE -> ", 0
;-----------------------------------------------------------------------
; Skill Level Timings and String
;-----------------------------------------------------------------------
_skString .word _easy, _medium, _hard, _extreme
_skOnTime .word 200, 150, 100, 60
_skOffTime .word 400, 300, 200, 120
_skBtnTime .word 1600, 900, 700, 500
;-----------------------------------------------------------------------
; Definitions
;-----------------------------------------------------------------------
RESET .equ 0
SKILL_LEVEL .equ 1
GEN_SEQ .equ 2
PLAY_SEQ .equ 3
INPUT_SEQ .equ 4
OVER .equ 5
;-----------------------------------------------------------------------
.text ; Program Start
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; Functions
;-----------------------------------------------------------------------
;---------------------------
; delayMs
; delay = R15
;---------------------------
delayMs clr.w &time ; Reset time
$1 cmp.w R15, &time ; If time < R15
jl $1 ; continue delaying
ret ; Return
.newblock ; Undefine local labels
dly .macro delay
mov.w delay, R15
call #delayMs
.endm
;---------------------------
; randGet (X ABC)
; rand = R15
; Remember to initialize
; randA-C before calling
;---------------------------
randGet inc.w &randX ; > x++ <
; > a = (a^c^x) <
mov.w &randC, R15 ; c -> R15
xor.w &randX, R15 ; R15 -> c^x
xor.w R15, &randA ; a -> c^x^a
add.w &randA, &randB ; > b = (b+a) <
; > c = (c+(b>>1)^a)<
mov.w &randB, R15 ; b -> R15
rra.w R15 ; R15 -> (b>>1)
xor.w &randA, R15 ; R15 -> (b>>1)^a
add.w R15, &randC ; c -> (c+(b>>1)^a)
mov.w &randC, R15 ; Move random to R15
ret
;---------------------------
; btnRead
; btn = R15
;---------------------------
btnRead clr.w &P2DIR ; Configure P2 Inputs
mov.w #3, R15 ; Set iterator/counter
mov.w #8, R14 ; Put 1 to be rolled
$1 bit.w R14, &P2IN ; Test
jnz $2 ; If pushed return
dec.w R15 ; Decrease counter
rra.w R14 ; Roll to next button
jnz $1 ; If zero, no button pushed
$2 inv.w &P2DIR ; Configure P2 Outputs
ret ; Return
.newblock
;---------------------------
; LED Functions
; Uses R15
;---------------------------
_led .byte BIT4, BIT5, BIT6, BIT7 ; Look-up values for leds
ledOn .macro LED ; ledOn LED
mov.b LED, R15 ; Move to register
bic.b _led(R15), &P1OUT ; Turn on led
.endm
ledOff .macro LED ; ledOff LED
mov.b LED, R15 ; Move to register
bis.b _led(R15), &P1OUT ; Turn of led
.endm
ledTgl .macro LED ; ledOn LED
mov.b LED, R15 ; Move to register
xor.b _led(R15), &P1OUT ; Turn on led
.endm
;---------------------------
; seqGenerate
; Stores 32 random values
; on seq array (0-3)
;---------------------------
seqGenerate clr.w R14 ; Iterator
$1 call #randGet ; Random value -> R15
and.b #0x03, R15 ; Truncate R14 (0-3)
mov.b R15, seq(R14) ; Copy value into array
inc.w R14 ; Increment Iterator
cmp.w #32, R14 ; Loop 32 times
jne $1 ; If not 32, loop again
ret ; Return
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
; LCD Driver
;-----------------------------------------------------------------------
EN .equ BIT4
RS .equ BIT5
DATA .equ 0x0F
CLEAR .equ 0x01
;---------------------------
; lcdSendNib
; Takes nibble on R14 and
; sends it to the LCD
;---------------------------
lcdSendNib bic.b #DATA, &P2OUT ; Clear Data Pins
and.b #DATA, R14 ; Mask lower nibble
bis.b R14, &P2OUT ; Send Nibble
bis.b #EN, &P2OUT ; Trigger Enable
bic.b #EN, &P2OUT ;
ret ; Return
;---------------------------
; lcdWrite
; Writes data/cmd on R15 to
; LCD
;---------------------------
lcdWrite mov.b R15, R14 ; Send upper nibble
rra.b R14 ; R15 >> 4
rra.b R14 ;
rra.b R14 ;
rra.b R14 ;
call #lcdSendNib ; Send
mov.b R15, R14 ; Send lower nibble
call #lcdSendNib ; Send
ret ; Return
lcdWD .macro data ; Write Data to LCD
bis.b #RS, &P2OUT ; Set RS to Data Mode
mov.b data, R15 ; Move data to R15
call #lcdWrite ; Write
dly #1 ; Delay 1 ms
.endm
lcdWC .macro cmd ; Write Cmd to LCD
bic.b #RS, &P2OUT ; Set RS to Cmd Mode
mov.b cmd, R15 ; Move cmd to R15
call #lcdWrite ; Write
dly #5 ; Delay 5 ms
.endm
;---------------------------
; lcdWriteText
; Modifies the buffer array
; to be displayed.
; R14 -> x
; R13 -> string ptr
;---------------------------
lcdWriteText tst.b 0(R13) ; Test character
jz $1 ; If null, string ends
mov.b @R13+, lcdBuffer(R14) ; char -> buffer
inc.b R14 ; Increment buffer ptr
jmp lcdWriteText ; Next character
$1 call #lcdUpdate ; Update LCD
ret ; Return
.newblock ; Undefine local labels
lcdWT .macro str, x ; Write text to LCD
mov.w str, R13 ; Move into registers
mov.w x, R14 ;
call #lcdWriteText ;
.endm ;
;---------------------------
; lcdWriteInt (unsigned)
; R14 -> x (str pointer)
; R13 -> input integer
; R12 -> digit
; R11 -> iterator (stack)
;---------------------------
_test .word 10d, 100d, 1000d, 10000d
lcdWriteInt push R11 ; Register not reserved
mov.w #4, R11 ; Do 4 iterations
$1 dec.w R11 ; Decrement iterator
mov.w #0x30, R12 ; New digit '0'
rla.w R11 ; Multiply iterator (*2)
$2 cmp.w _test(R11), R13 ; if input >= test, cont
jl $3 ; Else, jump out
inc.w R12 ; Increment digit
sub.w _test(R11), R13 ; Subtract test from int
jmp $2 ; Continue digit loop
$3 rra.w R11 ; Restore iterator (/2)
mov.b R12, lcdBuffer(R14) ; Move digit into buffer
inc.w R14 ; Increment str pointer
tst.w R11 ; Continue loop
jnz $1 ; Until zero
add.b #0x30, R13 ; Add '0' to char
mov.b R13, lcdBuffer(R14) ; Copy last digit
pop R11 ; Restore register
call #lcdUpdate ; Update LCD
ret ; Return
.newblock ; Undefine local labels
lcdWI .macro int, x ; Write int to LCD
mov.w int, R13 ;
mov.w x, R14 ;
call #lcdWriteInt ;
.endm ;
;---------------------------
; lcdUpdate
; Send lcdBuffer to the
; display
;---------------------------
lcdUpdate clr.b R12 ; Clear pointer
lcdWC #0x80 ; Go home
$1 lcdWD lcdBuffer(R12) ; Write character
inc.b R12 ; Increment pointer
cmp #16, R12 ; Send first line
jne $1 ; Loop
lcdWC #0xC0 ; Go home
$2 lcdWD lcdBuffer(R12) ; Write character
inc.b R12 ; Increment pointer
cmp #32, R12 ; Send first line
jne $2 ; Loop
ret ; Return
.newblock ; Undefine local labels
;---------------------------
; lcdInit
; Initializes LCD
;---------------------------
lcdInit dly #100 ; Delay 100 ms for power
mov.b #0xFF, &P2DIR ; Set P2 to outputs
mov.b #3, R11 ; Iterator
$1 lcdWC #0x03 ; Change to 4-bit mode
dly #5 ; Wait 5 ms
dec.b R11
tst.b R11 ; If not 0
jnz $1 ; Loop
lcdWC #0x02 ; Really change to 4-bit
dly #5 ; Wait 5 ms
lcdWC #0x28 ; 4-bit, 2 line, 5x8
lcdWC #0x08 ; Instruction Flow
lcdWC #0x01 ; Clear LCD
lcdWC #0x06 ; Auto-Increment
lcdWC #0x0C ; Display On, No blink
ret ; Return
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
; Buzzer
;-----------------------------------------------------------------------
;---------------------------
; playNote (pNote, sNote)
;---------------------------
;_note .word 956, 851, 758, 716, 638, 568, 506, 478
_note .word 956, 758, 638, 506, 4000
playNote rla.w R15 ; Multiply pointer
mov.w _note(R15), &buzzDiv ; Set divider for freq
mov.w #1, &buzzEnable ; Enable buzzer
ret ; Return
pNote .macro note ; Play Macro
mov.b note, R15 ;
call #playNote ;
.endm ;
sNote .macro ; Stop Macro
mov.w #0, &buzzEnable ;
.endm ;
;-----------------------------------------------------------------------
; Main Programs
;-----------------------------------------------------------------------
Init mov.w #0x0280, SP ; Initialize Stack
mov.w #WDTPW+WDTHOLD, &WDTCTL ; Disable Watch Dog
Setup8Mhz mov.w #CALDCO_8MHZ, &DCOCTL ; Setup 8 Mhz
mov.w #CALBC1_8MHZ, &BCSCTL1 ;
SetupP1 bis.b #0xFF, &P1OUT ; Turn off leds
bis.b #0xFF, &P1DIR ; Enable outputs
SetupTick mov.w #1000, &TACCR1 ; 1ms ticks
mov.w #CCIE, &TACCTL1 ; Compare interrupt
clr.w &time ; Reset time
SetupBuzz mov.w #1000, &buzzDiv ; 1kHz Default Tone
mov.w #0, &buzzEnable ; Disable buzzer
mov.w &buzzDiv, &TACCR2 ;
mov.w #CCIE, &TACCTL2 ; Compare Interrupt
SetupTA mov.w #TASSEL_2+MC_2+ID_3, &TACTL ; SMCLK, div8, cont mode
eint ; Enable interrupts
SetupLCD call #lcdInit ; Initialize LCD
;-----------------------------------------------------------------------
InitVars mov.w #RESET, &state ; Set RESET state
;-----------------------------------------------------------------------
gameLoop mov.w &state, R13 ; R13 -> state
tst.w R13 ; reset
jeq reset ;
dec.w R13 ; skillLevel
jeq skillLevel ;
dec.w R13 ; genSeq
jeq genSeq ;
dec.w R13 ; playSeq
jeq playSeq ;
dec.w R13 ; inputSeq
jeq inputSeq ;
dec.w R13 ; over
jeq over ;
jmp gameLoop ; gameLoop
;-----------------------------------------------------------------------
reset lcdWT #_welcome, #0 ; Display Welcome
dly #2000 ; Wait 2s
mov.w &TAR, &randA ; Move first seed
mov.w #SKILL_LEVEL, &state ; Switch to Skill Level
jmp gameLoop ; Back to gameLoop
;-----------------------------------------------------------------------
skillLevel lcdWT #_skilllvl, #0 ; Display Skill Screen
$1 call #btnRead ; Check button
mov.w R15, R10 ; btn -> R15
cmp.w #-1, R10 ; If no button pushed,
jeq $1 ; check again
rla.w R10 ; Multiply by 2 ptr
lcdWT _skString(R10), #16 ; Show Skill Selected
mov.w _skOnTime(R10), &ledOnTime ; Set ledOnTime
mov.w _skOffTime(R10), &ledOffTime ; Set ledOffTime
mov.w _skBtnTime(R10), &btnTime ; Set btnTime
mov.w &TAR, &randB ; Move second seed
dly #2000 ; Wait 2s
mov.w #GEN_SEQ, &state ; Switch to Gen Sequence
jmp gameLoop ; Back to gameLoop
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
genSeq call #seqGenerate ; Generate new sequence
clr.w &seqTop ; Initialize variables
clr.w &seqPos ;
clr.w &score ;
lcdWT #_score, #0 ; Prepare screen
mov.w #PLAY_SEQ, &state ; Switch to Play Sequence
jmp gameLoop ; Back to gameLoop
;-----------------------------------------------------------------------
playSeq cmp.w &seqTop, &seqPos ; If seqPos > seqTop,
jeq notover? ; sequence is over.
jge over? ;
notover? mov.w &seqPos, R10 ; seqPos -> R10
ledOn seq(R10) ; Blink LED
pNote seq(R10)
dly &ledOnTime ;
ledOff seq(R10) ;
sNote
dly &ledOffTime ;
inc.w &seqPos ; Advance to next position
jmp gameLoop ; Back to gameLoop
over? clr.w &seqPos ; Clear position and
mov.w #INPUT_SEQ, &state ; change state
jmp gameLoop ; Back to gameLoop
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
inputSeq cmp.w &seqTop, &seqPos ; If seqPos > seqTop,
jeq notover? ; sequence is over.
jge over? ;
notover? mov.w &seqPos, R10 ; seqPos -> R10
clr.w &time ; Reset time
while? cmp.w &btnTime, &time ; while (time < btnTime)
jge lose? ; if (time > btnTime), loses
call #btnRead ; Read button
mov.w R15, R11 ; btn -> R11
cmp.w #-1, R15 ; If button is pressed, break
jne continue?
jmp while?
continue? ledOn R11 ; Blink pushed led
pNote R11
dly #60
ledOff R11
sNote
release? dly #50 ; Debounce
call #btnRead ; btn -> R15
cmp.w #-1, R15 ; while button is pressed
jne release?
cmp.b R11, seq(R10) ; if (btn != seq[seqPos]), wrong btn
jeq correct?
lose? mov.w #OVER, &state ; Game Over
jmp gameLoop
correct? inc.w &seqPos ; Correct button, continue
add.w #50, &score ; Increment score
lcdWI &score, #11 ; Display score
jmp gameLoop ; Back to gameLoop
over? inc.w &seqTop ; Sequence complete, increment top
clr.w &seqPos ; Clear Position
mov.w #PLAY_SEQ, &state ; Change state
dly #400 ; Delay before playing
jmp gameLoop ; Back to gameLoop
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
over lcdWT #_end, #0 ; Write end screen
lcdWI &seqTop, #11 ; Display score
lcdWI &score, #27 ; Display score
pNote #4
mov.w #20, R11
$2 ledOn seq(R10)
dly #25
ledOff seq(R10)
dly #25
dec.w R11
jnz $2
sNote
$1 call #btnRead ; Wait until btn push
cmp.w #-1, R15 ;
jeq $1 ;
mov.w #RESET, &state ; Switch to Reset
jmp gameLoop ; Back to gameLoop
.newblock ; Undefine local labels
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
TAX_ISR; ISR for CCRX
;-----------------------------------------------------------------------
add.w &TA0IV, PC ; Add TA offset vector
reti ; CCR0
jmp TA_TICKS ; CCR1 - Ticks
jmp TA_BUZZER ; CCR2 - Buzzer
reti ; CCR3
reti ; CCR4
reti ; Return from overflow
TA_TICKS inc.w &time ; Increment time
add.w #1000, &TACCR1 ; Offset until next int
reti
TA_BUZZER tst.w &buzzEnable ; Only generate wave if
jz DISABLED ; enabled
xor.b #BIT2, &P1OUT ; Generate wave
DISABLED add.w &buzzDiv, &TACCR2 ; Offset until next int
reti
;-----------------------------------------------------------------------
; Interrupt Vectors
;-----------------------------------------------------------------------
.sect ".reset"
.short Init
.sect ".int08"
.short TAX_ISR
.end