;Chris Otto Andy Boyd

;Tic-Tac-Toe Logic
 
 

;;***************************************

;;***** Final Project on 8515 *************

;;***************************************

;Fully interrupt driven

;Strings can come from flash or RAM.
 
 

.include "c:\users\ca\4414def.inc"
 
 

.device AT90S4414
 

.def save =r1  ;saves the SREG in ISRs

.def reload =r2  ;timer 0 interval

.def lcdstat =r3
.def key  =r4
 

.def temp =r16 ;temporary register

.def charcnt =r17 ;a counter to use in message

.def savSREG =r8 ;save the status register

.def TXbusy =r19 ;transmit busy flag

.def RXchar =r20 ;a received character

.def TXflash =r21 ;text to be sent is in flash if <>0

.def TXram =r22 ;recieved counter
.def timeout =r23
.def temp2 =r24
.def butnum =r25 ;input number in hex
.def temp3 =r26
 

;-------------------------------------------------
;tic tac toe registers
;-------------------------------------------------
.def Xreg1 =r27
.def Xreg2 =r28
.def Yreg1 =r29
.def Yreg2 =r18
.def currentmove=r20
.def moves =r17
.def valid =r26

;-------------------------------------------------
;Chess Registers
;-------------------------------------------------
.def startrow=r27
.def endrow =r28
.def startcol=r29
.def endcol =r18
.def type =r20
.def color =r26

;***** Other equates

.equ lcdrs =PD6  ;LCD rs pin connected to PD6

.equ lcdrw =PD5  ;LCD r/w pin connected to PD5

.equ lcde =PD4  ;LCD e pin connected to PD4

.equ baud96 =25 ;9600 baud constant for 4Mhz crystal

.equ white ='w'
.equ black ='b'

.equ pawn ='P'

.equ rook ='R'

.equ knight ='K'
.equ bishop ='B'
.equ king ='U'
.equ queen ='Q'
 
 

;**************************************

.dseg
 
 

;define variable strings to be tranmitted from RAM

board: .byte 3 ;board counter
tic0: .byte 2 ;boardnumber
tic1: .byte 6 ;first tic row + a zero terminate
tic2: .byte 6 ;second tic row + a zero terminate
tic3: .byte 6 ;third tic row + a zero terminate

chess1: .byte 26 ;1 row chess
chess2: .byte 26 ;2 row chess
chess3: .byte 26 ;3 row chess
chess4: .byte 30 ;4 row chess
chess5: .byte 30 ;5 row chess
chess6: .byte 30 ;6 row chess
chess7: .byte 30 ;7 row chess
chess8: .byte 30 ;8 chess
 

;**************************************

.cseg
 
 

.org $0000

 rjmp  RESET ;reset entry vector

 reti

 reti

 reti

 reti

 reti

 reti

 rjmp t0int

 reti

 rjmp RXdone ;UART receive done

 rjmp TXempty ;UART buffer empty

 rjmp  TXdone ;UART transmit done

 reti
 
 

;define fixed strings to be tranmitted from flash- zero terminated

ticln: .db "-----", 0x00
chln: .db "------------------------", 0x00

crlf: .db 0x0d, 0x0a, 0x00 ;carrage return/line feed

;The following table is used to convert raw button-press high/low

;values to a sequence number. Invalid codes caused by multiple

;button presses are ignored.

keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111

 .db 0b11011110, 0b11011101, 0b11011011, 0b11010111

 .db 0b10111110, 0b10111101, 0b10111011, 0b10110111

 .db 0b01111110, 0b01111101, 0b01111011, 0b01110111
 

asciikey:
 .db "123A456B789C*0#D"

welcome:
 .db " A-Tic B-Chess",0x00
invalid:
 .db "Not a valid move-",0x00
xmove: .db "X make a move",0x00

ymove: .db "O make a move",0x00

cats: .db " Tie - Cats Game",0x00
xwin: .db "X WINS!", 0x00
ywin: .db "O WINS!", 0x00
 
 

RESET: ldi temp, LOW(RAMEND) ;setup stack pointer

 out  SPL, temp

 ldi temp, HIGH(RAMEND)

 out SPH, temp
 
 

 ser Temp
 out DDRB, Temp
 ldi Temp,0x00
 out PortB, Temp
 

        ;set up timer 0 for 1 mSec ticks
 
 
        ldi     Temp, 3         ;prescale timer by 64
        out     TCCR0, Temp
        ldi     Temp,256-62   ;preload timer since
        out     TCNT0, Temp  ;62.5 x (64x.25) microSec = 1.0 mSec.
 ldi Temp, 0b00000010
 out     TIMSK, Temp
 

 ;initial conditions

 

 clr TXbusy  ;start out not busy on TX
 
 
 

 ;setup UART -- enable TXempty & RXdone int, and RX, TX pins

 ldi  temp, 0b10111000

 out  UCR, temp

 ;set baud rate to 9600

 ldi temp, baud96

 out UBRR, temp
 

 ;intialize text pointer BEFORE turning on interrupts
 ;because RESET causes the TX empty flag to be SET
 ldi ZL, LOW(ticln<<1) ;do shift to convert word-addr to byte
 ldi  ZH, HIGH(ticln<<1)

 
 

;---------------------------------------------------------------------------------------
;initial tic-tac-toe board and chess board
;---------------------------------------------------------------------------------------
.include "c:\users\ca\initial.asm"
 

 sei

 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 
;----------------------------------------------------------------------------------------
;this is where we start
;----------------------------------------------------------------------------------------
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

Begin: ldi ZL, LOW(welcome<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(welcome<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 
choose: rcall getkey
 ldi timeout, 255
 rcall delay
 ldi timeout, 255
 rcall delay
 cpi RXchar,'A'
 breq TicTacToeinit
 cpi RXchar,'B'
 ;breq Chessinit
 rjmp choose

TicTacToeinit:
 clr moves
 clr Xreg1
 clr Xreg2
 clr Yreg1
 clr Yreg2
 clr  currentmove
 rcall PrTicBd
 

Xturn:
 
 ldi ZL, LOW(xmove<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(xmove<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 
 
 rcall getkey
 ldi timeout, 255
 rcall delay
 ldi timeout, 255
 rcall delay
  mov currentmove,RXchar
 subi currentmove,0x30
 
 rcall TicValid
 cpi Valid, 0
 brne illegalx
 
 inc moves
 
 ldi ZL,LOW(tic0) ;store move number
 ldi ZH,HIGH(tic0)
 mov temp, moves
 subi temp, -48
 st z,temp
 
 rcall setXreg1 ;gives control of piece to X
chkwinX:ldi temp,'X'
 rcall TicBdUpdate
 rcall winX
 cpi Xreg1,255
 breq newgame
 
 rjmp Yturn

setXreg1:
 cpi currentmove,1
 breq set1
 cpi currentmove,2
 breq set2
 cpi currentmove,3
 breq set3
 cpi currentmove,4
 breq set4
 cpi currentmove,5
 breq set5
 cpi currentmove,6
 breq set6
 cpi currentmove,7
 breq set7
 cpi currentmove,8
 breq set8
 cpi currentmove,9
 breq set9
set1: ori Xreg1,0b10000000
 ret
set2: ori Xreg1,0b01000000
 ret
set3: ori Xreg1,0b00100000
 ret
set4: ori Xreg1,0b00010000
 ret
set5: ori Xreg1,0b00001000
 ret
set6: ori Xreg1,0b00000100
 ret
set7: ori Xreg1,0b00000010
 ret
set8: ori Xreg1,0b00000001
 ret
set9: ori Xreg2,0b11111111
 ret
 

illegalx:ldi ZL, LOW(invalid<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(invalid<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ldi timeout,255
 rcall delay
 ldi timeout, 255
 rcall delay

 rjmp Xturn

illegaly:ldi ZL, LOW(invalid<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(invalid<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ldi timeout,255
 rcall delay
 ldi timeout, 255
 rcall delay
 rjmp Yturn

newgame:rjmp reset

Yturn:
 
 ldi ZL, LOW(ymove<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(ymove<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 
 rcall getkey
 ldi timeout, 255
 rcall delay
 ldi timeout, 255
 rcall delay
 mov currentmove,RXchar
 subi currentmove,0x30

 rcall TicValid
 cpi Valid, 0
 brne illegaly
 
 inc  moves
 
 ldi ZL,LOW(tic0) ;store move number
 ldi ZH,HIGH(tic0)
 mov temp, moves
 subi temp, -48
 st z,temp
 
 rcall setYreg1 ;gives control of piece to Y
chkwinY:ldi temp,'O'
 rcall TicBdUpdate
 rcall winY
 cpi Yreg1,255
 breq newgame
 
 rjmp Xturn
setYreg1:
 cpi currentmove,1
 breq yset1
 cpi currentmove,2
 breq yset2
 cpi currentmove,3
 breq yset3
 cpi currentmove,4
 breq yset4
 cpi currentmove,5
 breq yset5
 cpi currentmove,6
 breq yset6
 cpi currentmove,7
 breq yset7
 cpi currentmove,8
 breq yset8
 cpi currentmove,9
 breq yset9
yset1: ori Yreg1,0b10000000
 ret
yset2: ori Yreg1,0b01000000
 ret
yset3: ori Yreg1,0b00100000
 ret
yset4: ori Yreg1,0b00010000
 ret
yset5: ori Yreg1,0b00001000
 ret
yset6: ori Yreg1,0b00000100
 ret
yset7: ori Yreg1,0b00000010
 ret
yset8: ori Yreg1,0b00000001
 ret
yset9: ori Yreg2,0b11111111
 ret
;---------------------------------------------------------------------------
;chech for winning conditions
;---------------------------------------------------------------------------

winX: mov temp, Xreg1
 andi temp,0b11100000
 cpi temp,0b11100000
 breq Xmatch
 mov temp, Xreg1
 andi temp,0b00011100
 cpi temp,0b00011100
 breq Xmatch
 mov temp, Xreg1
 andi temp,0b10010010
 cpi  temp,0b10010010
 breq Xmatch
 mov temp, Xreg1
 andi temp,0b01001001
 cpi temp,0b01001001
 breq Xmatch
 mov temp, Xreg1
 andi temp,0b00101010
 cpi temp,0b00101010
 breq Xmatch
 cpi Xreg2, 255
 brne Xend
 mov temp,Xreg1
 andi temp,0b00000011
 cpi temp,0b00000011
 breq Xmatch
 mov temp, Xreg1
 andi temp,0b00100100
 cpi temp,0b00100100
 breq Xmatch
 mov temp,Xreg1
 andi temp,0b10001000
 cpi temp,0b10001000
 breq Xmatch
 cpi moves,9
 breq catscase
Xend: cpi moves,9
 breq catscase
 ret
Xmatch: ser Xreg1
 ser Xreg2
 ldi ZL, LOW(xwin<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(xwin<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ret
 
catscase:
 ser Xreg1
 ser Xreg2
 ldi ZL, LOW(cats<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(cats<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ret

winY: mov temp, Yreg1
 andi temp,0b11100000
 cpi temp,0b11100000
 breq Ymatch
 mov temp, Yreg1
 andi temp,0b00011100
 cpi temp,0b00011100
 breq Ymatch
 mov temp, Yreg1
 andi temp,0b10010010
 cpi  temp,0b10010010
 breq Ymatch
 mov temp, Yreg1
 andi temp,0b01001001
 cpi temp,0b01001001
 breq Ymatch
 mov temp, Yreg1
 andi temp,0b00101010
 cpi temp,0b00101010
 breq Ymatch
 cpi Yreg2, 255
 brne Yend
 mov temp,Yreg1
 andi temp,0b00000011
 cpi temp,0b00000011
 breq Ymatch
 mov temp, Yreg1
 andi temp,0b00100100
 cpi temp,0b00100100
 breq Ymatch
 mov temp,Yreg1
 andi temp,0b10001000
 cpi temp,0b10001000
 breq Ymatch
Yend: ret
Ymatch: ser Yreg1
 ser Yreg2
 ldi ZL, LOW(ywin<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(ywin<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 ret

;------------------------------------------------------------------------
;Check for valid moves
;------------------------------------------------------------------------

TicValid:
 

 clr Valid
 cpi currentmove,1
 breq valid1
 cpi currentmove,2
 breq valid2
 cpi currentmove,3
 breq valid3
 cpi currentmove,4
 breq valid4
 cpi currentmove,5
 breq valid5
 cpi currentmove,6
 breq valid6
 cpi currentmove,7
 breq valid7
 cpi currentmove,8
 breq valid8
 cpi currentmove,9
 breq valid9

 cpi currentmove,1
 brlo nogood
 cpi currentmove,0xa
 brge nogood

valid1: sbrc Yreg1,7
 rjmp nogood
 sbrc Xreg1,7
 rjmp nogood
 ret
valid2: sbrc Yreg1,6
 rjmp nogood
 sbrc Xreg1,6
 rjmp nogood
 ret
valid3: sbrc Yreg1,5
 rjmp nogood
 sbrc Xreg1,5
 rjmp nogood
 ret
valid4: sbrc Yreg1,4
 rjmp nogood
 sbrc Xreg1,4
 rjmp nogood
 ret
valid5: sbrc Yreg1,3
 rjmp nogood
 sbrc Xreg1,3
 rjmp nogood
 ret
valid6: sbrc Yreg1,2
 rjmp nogood
 sbrc Xreg1,2
 rjmp nogood
 ret
valid7: sbrc Yreg1,1
 rjmp nogood
 sbrc Xreg1,1
 rjmp nogood
 ret
valid8: sbrc Yreg1,0
 rjmp nogood
 sbrc Xreg1,0
 rjmp nogood
 ret
valid9: sbrc Yreg2,0
 rjmp nogood
 sbrc Xreg2,0
 rjmp nogood
 ret
nogood: ldi valid, 1
 ret
;------------------------------------------------------------------------
;Update board
;------------------------------------------------------------------------
TicBdUpdate:
 ldi ZL, LOW(tic1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(tic1)
 mov temp2,currentmove
 subi temp2,1
 lsl temp2
jumpto: cpi temp2,0
 breq putit
 dec temp2
 ld temp3,z
 st z+,temp3
 rjmp jumpto
putit: st z,temp
 rcall PrTicBd
 ret
 

;----------------------------------------------------------------------------------------
;Print Board for Tic-Tac-Toe
;----------------------------------------------------------------------------------------

PrTicBd:
 ;print tic-tac-toe board
 
 ;setup ptr for <crlf> string
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 ;line1
 ldi ZL, LOW(tic0)
 ldi ZH, HIGH(tic0)
 ld r0,Z
 out UDR, r0
 clr TXflash
 ser TXbusy
 sbi UCR, UDRIE
 rcall TXwait

 ;setup ptr for <crlf> string
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 ;line1
 ldi ZL, LOW(tic1)
 ldi ZH, HIGH(tic1)
 ld r0, Z
 out UDR, r0
 clr TXflash
 ser TXbusy
 sbi UCR, UDRIE
 rcall TXwait

 rcall Ticline

 ;line2
 ldi ZL, LOW(tic2)
 ldi ZH, HIGH(tic2)
 ld r0, Z
 out UDR, r0
 clr TXflash
 ser TXbusy
 sbi UCR, UDRIE
 rcall TXwait

 rcall Ticline

 ;line3
 ldi ZL, LOW(tic3)
 ldi ZH, HIGH(tic3)
 ld r0, Z
 out UDR, r0
 clr TXflash
 ser TXbusy
 sbi UCR, UDRIE
 rcall TXwait
 
 ;setup ptr for <crlf> string
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 
 ret

Ticline:
 ;setup ptr for <crlf> string
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait
 

 ;setup ptr for <----> string
 ldi ZL, LOW(ticln<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(ticln<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt
 rcall TXwait

 ;setup ptr for <crlf> string
 ldi ZL, LOW(crlf<<1)  ;shifted becuase pgm memory is words

 ldi ZH, HIGH(crlf<<1)

 lpm

 out UDR, r0  ;trigger the UART TX

 ser TXflash  ;text string in flash memory

 ser TXbusy  ;and set the TX busy flag

 sbi UCR, UDRIE ;enable the TXempty interrupt

 rcall TXwait

 
 ret

 
;************************************************************************************************

;interrupt routines

;************************************************************************************************
 

sendTxt:
 tst TXram
 brne _sndRAM
 lpm
 rjmp _sndFLSH
_sndRAM: ld r0,Z
_sndFlsh:tst r0
 breq _sndEND
 cpi charcnt,8
 brne _writit
 ldi temp, 0xC0
 ;rcall lcdcmd
_writit:mov temp, r0
 ;rcall lcdput
 inc charcnt
 adiw ZL,1
 rjmp sendTxt
_sndEND:ret

; UART needs a character

TXempty:in savSREG, SREG ;save processor status

 tst TXflash  ;Is the string in flash memory?

 breq TXram  ;If not, it is in RAM

 inc ZL  ;get the next char from flash

 lpm   ;and put it in r0

 rjmp TXfls

TXram:  inc ZL  ;get the next char from RAM

 ld r0,Z

TXfls: tst r0  ;if char is zero then exit

 breq TXend

 out  UDR, r0  ;otherwise transmit it

 rjmp TXexit  ;exit until next char

TXend: clr TXbusy  ;no more chars

 cbi UCR, UDRIE ;clear the TXempty interrupt

TXexit: out SREG, savSREG ;restore proc status

 reti   ;back to pgm
 
 

; TX done -- buffer is empty  -- unused here

TXdone: in savSREG, SREG ;save processor status

 out SREG, savSREG ;restore proc status

 reti   ;back to pgm
 
 

; UART read a character

RXdone: in savSREG, SREG ;save processor status

 in RXchar, UDR ;get the character

 out SREG, savSREG ;restore proc status

 reti   ;back to pgm
 
 

;*****************************

;subroutine
 
 

TXwait: tst TXbusy  ;now wait for the tranmission to finish

 brne TXwait

 ret
 
 

;****************getkey function*******************************
getkey:
 push temp
 push temp2
loop:  clr temp2
 ldi  timeout,30
 rcall delay
 ldi temp, 0x0f ;set lower four lines to output
 out  DDRA, temp
 ldi temp, 0xf0 ;and turn on the pullups on the inputs
 out PORTA, temp
 nop   ;Need some time for the pullups to
 nop   ;charge the port pins
 nop
 nop
 in temp, PINA ;read the high nibble
 mov key, temp ;and store it (with zeros in the low nibble)
 

  ldi temp, 0xf0 ;set upper four lines to outputs
 out  DDRA, temp
 ldi temp, 0x0f ;and turn on pullups on the inputs
 out PORTA, temp
 
 nop   ;As before wait for the pin to charge
 nop
 nop
 nop
 in temp, PINA ;read the low nibble
 or key, temp ;combine to make key code
 ldi temp,0xff
 cp key,temp
 breq illegal
 
 ;At the point the raw key code should have exactly one zero each in
 ;the lower and upper nibbles. Any other number of zeros indicates
 ;either no-button pressed or multiple-button pressed.

 ;Now search the table for a match to the raw key code
 ;and exit with a button number
 
 ldi ZL, low(keytbl*2) ;table pointer in FLASH
 ldi ZH, high(keytbl*2) ;so convert from word to byte addr
 ldi butnum, 0
tbllp:  lpm   ;get the table entry
 cp key, r0  ;match?
 breq foundit
 inc butnum  ;if not, have we exhaused the
 cpi butnum, 0x10 ;table
 breq illegal
 adiw ZL, 1  ;if not, get the next table entry
 rjmp tbllp

foundit:;now lookup from ascii table
 ldi ZL, low(asciikey*2) ;table pointer in FLASH
 ldi ZH, high(asciikey*2) ;so convert from word to byte addr
 clr  temp
 add ZL,butnum
 adc ZH,temp
 lpm
 mov RXchar,r0
 out  PORTB, butnum
 pop temp2
 pop temp
 ret

illegal:;nothing found, return to waiting
 tst temp2
 brne _getdone
 rjmp loop
 
_getdone:
 pop temp2
 pop temp
 ret
 
 
 
 

;=============================================

; subroutine waits for time equal to value in register timeout

;the register 'timeout' should be loaded before the call
 
 
 

delay: tst timeout

 brne delay
 

 ret
 
 

;=============================================
 

;***** Timer 0 overflow interrupt handler
 

;timer 0 ISR (timer-zero overflow)

;Enters every 1.0 mSec
 
 

t0int: in save, SREG
 push temp
 ldi     temp,256-62

 out  TCNT0, temp ; keeps clock ticking at 1 mSec
 
 

 dec  timeout  ;subtract another mSec
 
 

 out SREG, save
 pop  temp

 reti   ;back to backgound tasks