//_
//_ simon for stk500 (in avrasm)
//_ by renesis/efnet
//_ 2007.06.19
//_
//_ based on:
//_ simon for stk500 (in c)
//_ by ^dx^/efnet
//_
//_ device definitions
.include "m8515def.inc" // ATMega8515, 8MHz (internal RC)
//_ register definitions
.def temp =r16 // general use
.def temp2 =r17
.def temp3 =r18
.def buttons =r19 // button buffer
.def random =r20 // random buffer
.def level =r21 // game level counter
//_ program constants
.equ game_length =6 // game length, in number of levels
.equ game_gap_time =20 // time between simon input and simon output modes * 0.01sec
.equ led_flash_time =15 // simon blink on time * 0.01sec
.equ led_dead_time =5 // off time between simon blinks * 0.01sec
.equ led_winblink_time =5 // win blink halfcycle time * 0.01sec
.equ led_loseblink_time =33 // lose blink halfcycle time * 0.01sec
.equ led_start_pattern =$aa // stk500 LED splash patterns
.equ led_wina_pattern =$aa // LED are active low
.equ led_winb_pattern =$55
.equ led_losea_pattern =$fc
.equ led_loseb_pattern =$ff
.equ button_soft_reset =led_losea_pattern // soft reset button pattern (active low)
.equ led_port =portb // led port definitions
.equ led_ddr =ddrb
.equ button_port =portd // button port definitions
.equ button_ddr =ddrd
.equ button_pin =pind
.equ delaytime_10ms =10000 // compare value @ 8MHz,prescale=/8 (100KHz|10us)
//_ sram allocation
.dseg
randtab: .byte game_length // random button/LED table
.cseg
//_ vector table
.org $0
rjmp reset // poweron/reset
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
//_ delay 100ms (timer1 based)
delay_10ms:
push temp // store temp register on stack
clr temp // clear timer count reg
out tcnt1h,temp // buffered 16bit register, WRITE HIGH BYTE FIRST
out tcnt1l,temp
in temp,tifr // reset ocf1a in timer flag register
sbr temp,(1<<ocf1a) // (logical 1 resets flag)
out tifr,temp
delay_10ms0: // loop until ocf1a is set
in temp,tifr
sbrs temp,ocf1a
rjmp delay_10ms0
pop temp // get stored temp register value
ret
//_ delay macros (uses temp register)
.macro delay_x10ms
ldi temp,@0 // macro input is delay multiplier
delay_x10ms0:
rcall delay_10ms
dec temp
brne delay_x10ms0
.endmacro
//_ stk500 LEDs (uses temp register)
.macro led_setup
ser temp // setup LED port output high
out led_port,temp // LED are NPN buffered, active low
out led_ddr,temp
.endmacro
.macro led_on_start
ldi temp,led_start_pattern
out led_port,temp
.endmacro
.macro led_on_wina
ldi temp,led_wina_pattern
out led_port,temp
.endmacro
.macro led_on_winb
ldi temp,led_winb_pattern
out led_port,temp
.endmacro
.macro led_on_losea
ldi temp,led_losea_pattern
out led_port,temp
.endmacro
.macro led_on_loseb
ldi temp,led_loseb_pattern
out led_port,temp
.endmacro
.macro led_on_byte
out led_port,@0
.endmacro
.macro led_on_all
clr temp
out led_port,temp
.endmacro
.macro led_off_all
ser temp
out led_port,temp
.endmacro
//_ stk500 buttons + random
button_wait:
push temp // store temp register on stack
rcall chk_soft_reset // check for program reset
button_wait0: // wait for buttons clear
in temp,button_pin
cpi temp,$ff
brne button_wait0
in random,tcnt1l // import low byte from running timer1
button_wait1:
inc random // inc value each button polling
in buttons,button_pin
cpi buttons,$ff
breq button_wait1
in temp,tcnt1l // when button press detected, import low byte of running timer1
eor temp,random // xor the the modified original and new timer low bytes
andi temp,$07 // mask off the last 3 bits
ldi random,$01
button_wait2: // use the masked bits as a left shift count
cpi temp,$00
breq button_wait3
dec temp
lsl random
rjmp button_wait2
button_wait3:
ldi temp,$ff // invert the value for active low usability
eor random,temp
pop temp // get stored temp register value
ret
//_ check for soft reset
chk_soft_reset:
in buttons,button_pin
cpi buttons,button_soft_reset
breq reset
ret
//_ program init
reset:
ldi temp,low(ramend) // setup stack pointer
out spl,temp
ldi temp,high(ramend)
out sph,temp
clr temp // initialize delay timer
out tccr1a,temp // mode=CTC,top=OCR1A,prescale=/8
ldi temp,(1<<WGM12)|(1<<CS11)
out tccr1b,temp
ldi temp,high(delaytime_10ms) // setup compare register
out ocr1ah,temp // buffered 16bit register, WRITE HIGH BYTE FIRST
ldi temp,low(delaytime_10ms)
out ocr1al,temp
led_setup // setup stk500 LEDs
led_on_start // game start LED splash ($55)
clr level // init game level register
mov temp3,level // init randtab pointer
ldi ZH,high(randtab)
ldi ZL,low(randtab)
rcall button_wait // wait for user input to start game
st Z+,random // store as next in random table
//_ program mainloop
deathloop:
inc level
cpi level,game_length+1
breq winloop
delay_x10ms game_gap_time
rcall simon_out
delay_x10ms game_gap_time
rcall simon_in
rjmp deathloop
//_ simon output loop
simon_out:
mov temp3,level // copy level for counter use
ldi ZH,high(randtab) // init randtab pointer
ldi ZL,low(randtab)
simon_out0:
led_off_all // switch of all LED
delay_x10ms led_dead_time
ld random,Z+ // pull value from randtab, post inc
led_on_byte random // flash LED for randtab byte
delay_x10ms led_flash_time
dec temp3 // decrement copied level counter
brne simon_out0 // continue looping if not zero
led_off_all
ret
//_ simon input loop
simon_in:
mov temp3,level // copy level for counter use
ldi ZH,high(randtab) // init randtab pointer
ldi ZL,low(randtab)
simon_in0:
rcall button_wait // wait for button press
mov temp2,random // copy random value for possible storage later
led_on_byte buttons // flash LED corresponding to pressed button
delay_x10ms led_flash_time
led_off_all
delay_x10ms led_dead_time
ld random,Z+ // pull value from randtab, post inc
cp buttons,random // compare the randtab value and buttons
brne loseloop // game lost if not equal
dec temp3 // decrement copied level counter
brne simon_in0 // continue looping if not zero
st Z,temp2 // store copied random value to randtab
ret
//_ game won loop
winloop:
led_on_wina // do win blink sequence
delay_x10ms (led_winblink_time)
led_on_winb
delay_x10ms (led_winblink_time)
rcall chk_soft_reset // check for program reset
rjmp winloop
//_ game lost loop
loseloop:
led_on_losea // do lose blink sequence
delay_x10ms (led_loseblink_time)
led_on_loseb
delay_x10ms (led_loseblink_time)
rcall chk_soft_reset // check for program reset
rjmp loseloop
//_ program end