.include "c:\avrtools\appnotes\8535def.inc" ;.device AT90S8535 ; specifies to the assembler which chip we are using .def pgmem =r0 ; for reading text from memory .def status =r1 ;0x000000 ::: lower mem (0) / upper mem (1) ::: erase (0) / write (1) .def AnaLo =r2 ; for reading the ADC .def AnaHi =r3 ; .def timeout =r4 ; delay for slowing the game down .def reload =r5 ; helper for delay in timer 0 .def save =r6 ; saves SREG .def speedctr =r7 ; assists in speeding up the ball .def mc16uL =r8 ;multiplicand low byte .def mc16uH =r9 ;multiplicand high byte .def mp16uL =r10 ;multiplier low byte .def mp16uH =r11 ;multiplier high byte .def m16u0 =r10 ;result byte 0 (LSB) .def m16u1 =r11 ;result byte 1 .def m16u2 =r12 ;result byte 2 .def m16u3 =r13 ;result byte 3 (MSB) .def mcnt16u =r16 ;loop counter (temp) .def drem24uL =r8 ; remainder .def drem24uH =r9 .def dres24uL =r10 ; result .def dres24uM =r11 .def dres24uH =r12 .def dv24uH =r14 .def dv24uL =r15 ; divisor .def dcnt24u =r16 ; loop counter .def temp =r16 ; temporary register .def ballx =r17 ; ball position .def bally =r18 .def balldx =r19 ; ball velocity .def balldy =r20 .def cnt =r21 ; counter (all-purpose) .def temp1 =r22 ; extra temps .def temp2 =r23 ; .def score0 =r24 ; player 0 score .def score1 =r25 ; player 1 score .def addrl =r26 ; XL .def addrh =r27 ; XH .def paddle0 =r28 ; YL .def paddle1 =r29 ; YH ; ZL ; ZH used by timer 1 .equ speakerbit =7 .equ GAMEDELAY =20 ;20 mS game delay .equ timer1on =0b00010001 ;used when compare match interrupt for timer1 .equ timer1off=0b00000001 ;is toggled .equ R =9960 ; multiplier for ADC measurements .include "c:\users\eam23_jgo2\macros.asm" .cseg .org $0000 rjmp RESET ;reset entry vector reti ;IRQ0 reti ;IRQ1 reti ;t2 compare reti ;t2 ovfl reti ;t1 cap rjmp t1AMatch ;timer 1 compare match A - for sound reti ;t1 compare b reti ;t1 ovfl rjmp t0int ;t0 overflow reti reti reti reti reti reti reti RESET: ; stack pointer ldi Temp, low(RAMEND) out SPL, Temp ldi Temp, high(RAMEND) out SPH, Temp ;set up timer 0 for 1 mSec ticks (slows down game) ldi temp, 3 ;prescale timer by 64 out TCCR0, temp ldi temp,256-62 ;preload timer since mov Reload, temp out TCNT0, Reload ;62.5 x (64x.25) microSec = 1.0 mSec. ;set up timer 1 for compare match interrupt (plays sound) ldi temp, timer1off out TIMSK, temp ldi temp, 0b00001001 out TCCR1B, temp ; port A -> analog for two controllers ;set port B for LCD control and processor communication ldi temp, 0b10111111 out DDRB, temp clr temp out PORTB, temp ; port C -> data for LCD ; port D -> control buttons (start button), plus sound output on one pin. ldi temp, 0b10000000 out DDRD, temp clr temp out PORTD, temp ;turn off pullups sei ;Enable interrupts ;initialize LCD display graphics area starting at 0000h ; graphics home address = 0000h statusi 0x03 writei 0x00 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x42 ; start next line 0x1e bytes later statusi 0x03 writei 30 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x43 ;initialize LCD text area starting at 1400h statusi 0x03 writei 0x00 statusi 0x03 writei 0x14 statusi 0x03 commandi 0x40 statusi 0x03 writei 30 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x41 ;set display mode to "or" statusi 0x03 commandi 0x80 ;set display mode statusi 0x03 commandi 0x9C ;clear display rcall clrallmem ; initialize variables ldi score0, 0 ldi score1, 0 clt ; beginning of game flag ; play opening music ldi temp, low(30) out OCR1AH, temp ldi temp, high(30) out OCR1AL, temp ldi ZL,low(40) ldi ZH,high(40) ldi temp,timer1on out TIMSK,temp start1: tst ZL brne start1 ldi temp, low(70) out OCR1AH, temp ldi temp, high(70) out OCR1AL, temp ldi ZL,low(90) ldi ZH,high(90) ldi temp,timer1on out TIMSK,temp start2: tst ZL brne start2 ldi temp, low(30) out OCR1AH, temp ldi temp, high(30) out OCR1AL, temp ldi ZL,low(70) ldi ZH,high(70) ldi temp,timer1on out TIMSK,temp start3: tst ZL brne start3 ldi temp, low(75) out OCR1AH, temp ldi temp, high(75) out OCR1AL, temp ldi ZL,low(50) ldi ZH,high(50) ldi temp,timer1on out TIMSK,temp start4: tst ZL brne start4 ldi temp, low(20) out OCR1AH, temp ldi temp, high(20) out OCR1AL, temp ldi ZL,low(100) ldi ZH,high(100) ldi temp,timer1on out TIMSK,temp start5: tst ZL brne start5 ldi temp, low(50) out OCR1AH, temp ldi temp, high(50) out OCR1AL, temp ldi ZL,low(60) ldi ZH,high(60) ldi temp,timer1on out TIMSK,temp start6: tst ZL brne start6 nextGame: ; starting ball position ldi ballx, 120 ldi bally, 120 ; initial ball speed in y direction ldi balldy, 1 ; speed increases every 4 paddle hits ldi temp, 4 mov speedctr, temp ; display info on screen and wait for buttonpress rcall writelabels gameLoop: ldi temp, GAMEDELAY mov timeout, temp rcall delay rcall checkControl0 rcall checkControl1 rcall eraseball rcall updatexy rcall drawball rjmp gameLoop moveto: ; LCD helper subroutine ; move address pointer to location specified in addrl, addrh clr temp ;set PORTC to all inputs out DDRC, temp statuswait: ldi temp, 0b00010101 out PORTB, temp ;set control lines in temp, PINC ;read data nop nop andi temp, 3 ldi temp1, 0b00011101 out PORTB, temp1 ;set control lines cpi temp, 3 ;compare brne statuswait ;if status check fails, try again ldi temp, 0b00011010 ;return chip to read status to avoid double writing (VERY bad) out PORTB, temp ser temp ;set PORTC to all outputs out DDRC, temp out PORTC, addrl ;put data on PORTC ldi temp, 0b00010010 out PORTB, temp ;set control lines ldi temp, 0b00011010 out PORTB, temp ;bring /CE back up clr temp ;set PORTC to all inputs out DDRC, temp statuswait1: ldi temp, 0b00010101 out PORTB, temp ;set control lines in temp, PINC ;read data nop nop andi temp, 3 ldi temp1, 0b00011101 out PORTB, temp1 ;set control lines cpi temp, 3 ;compare brne statuswait1 ;if status check fails, try again ldi temp, 0b00011010 ;return chip to read status to avoid double writing (VERY bad) out PORTB, temp ser temp ;set PORTC to all outputs out DDRC, temp out PORTC, addrh ;put data on PORTC ldi temp, 0b00010010 out PORTB, temp ;set control lines ldi temp, 0b00011010 out PORTB, temp ;bring /CE back up clr temp ;set PORTC to all inputs out DDRC, temp statuswait2: ldi temp, 0b00010101 out PORTB, temp ;set control lines in temp, PINC ;read data nop nop andi temp, 3 ldi temp1, 0b00011101 out PORTB, temp1 ;set control lines cpi temp, 3 ;compare brne statuswait2 ;if status check fails, try again ldi temp, 0b00011010 ;return chip to read status to avoid double writing (VERY bad) out PORTB, temp ser temp ;set PORTC to all outputs out DDRC, temp ldi temp, 0x24 out PORTC, temp ;put command on PORTC ldi temp, 0b00010011 out PORTB, temp ;set control lines ldi temp, 0b00011011 out PORTB, temp ;pulse /CE back up ret drawBall: ; draws the ball on the screen at its current position ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y direction (what row) ; multiply bally * 30 mov temp, bally rcall mpy8u ; determine x byte (right shift 3) mov cnt, ballx lsr cnt lsr cnt lsr cnt add addrl, cnt ;Add low bytes clr cnt adc addrh, cnt ;Add high bytes with carry ; move address pointer to ball location rcall moveto ; set bits around location mov cnt, ballx andi cnt, 0b00000111 ; find out the last three bits, which tell how ; far over within the current byte to place the ball cpi cnt, 0 breq drawBall0 cpi cnt, 1 breq drawBall1 cpi cnt, 2 breq drawBall2 cpi cnt, 3 breq drawBall3 cpi cnt, 4 breq drawBall4 cpi cnt, 5 breq drawBall5 cpi cnt, 6 breq drawBall6 rjmp drawBall7 drawBall1: rjmp drawBall1_2 drawBall2: rjmp drawBall2_2 drawBall3: rjmp drawBall3_2 drawBall4: rjmp drawBall4_2 drawBall5: rjmp drawBall5_2 drawBall6: rjmp drawBall6_2 drawBall0: ldi temp2, 0b01100000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11110000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11110000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b01100000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall1_2: ldi temp2, 0b00110000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b01111000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b01111000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00110000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall2_2: ldi temp2, 0b00011000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00111100 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00111100 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00011000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall3_2: ldi temp2, 0b00001100 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00011110 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00011110 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00001100 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall4_2: ldi temp2, 0b00000110 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00001111 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00001111 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000110 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall5_2: ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte adiw addrl, 30 rcall moveto ldi temp2, 0b00000111 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000111 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ret drawBall6_2: ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawBall7: adiw addrl, 1 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 29 rcall moveto ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b11100000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte ldi temp2, 0b11100000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 31 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret status3: ; gets a status from the LCD with a return code of 0x03 (ready for next command) clr temp ;set PORTC to all inputs out DDRC, temp statuswait_status3: ldi temp, 0b00010101 out PORTB, temp ;set control lines in temp, PINC ;read data nop nop andi temp, 3 ldi temp1, 0b00011101 out PORTB, temp1 ;set control lines cpi temp, 3 ;compare brne statuswait_status3 ;if status check fails, try again ldi temp, 0b00011010 ;return chip to read status to avoid double writing (VERY bad) out PORTB, temp ret eraseBall: ; counterpart to drawBall, erases the ball at its current location ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y direction (what row) ; multiply bally * 30 mov temp, bally rcall mpy8u ; determine x byte (right shift 3) mov cnt, ballx lsr cnt lsr cnt lsr cnt add addrl, cnt ;Add low bytes clr cnt adc addrh, cnt ;Add high bytes with carry ; move address pointer to ball location rcall moveto ; set bits around location mov cnt, ballx andi cnt, 0b00000111 ; find out the last three bits, which tell how ; far over within the current byte to place the ball cpi cnt,5 brge eraseballhigh rjmp eraseballlow eraseballhigh: rjmp eraseballhigh2 eraseballlow: clr temp2 ;write all 0's to byte rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto clr temp2 ;write all 0's to byte rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto clr temp2 ;write all 0's to byte rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto clr temp2 ;write all 0's to byte rcall status3 write temp2 rcall status3 commandi 0xC4 ret eraseballhigh2: clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC4 ; C0 - bump along to next byte adiw addrl, 30 rcall moveto clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC4 ; C0 - bump along to next byte adiw addrl, 30 rcall moveto clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC4 ; C0 - bump along to next byte adiw addrl, 30 rcall moveto clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC0 ; C0 - bump along to next byte clr temp2 rcall status3 write temp2 rcall status3 commandi 0xC4 ; C0 - bump along to next byte ret ;******************************************** ;updatexy - updates ballx and bally according to balldx and balldy ; also checks for paddle hit ; also checks for wall bounce ; also checks for misses - ball fell off the end of the playing field. ; ****************************************** updatexy: ; first do y direction add bally,balldy cpi bally, 0 breq hit0 cpi bally, 250 ; if ball fell through 0 to 255 brcc hit0 cpi bally, 124 brcc hit124 rjmp updatex hit0: ;*turn on sound ldi temp, low(200) out OCR1AH, temp ldi temp, high(200) out OCR1AL, temp ldi ZL,low(10) ldi ZH,high(10) ldi temp,timer1on out TIMSK,temp neg bally ;just get two's comp of bally neg balldy rjmp updatex hit124: ;*turn on sound ldi temp, low(200) out OCR1AH, temp ldi temp, high(200) out OCR1AL, temp ldi ZL,low(10) ldi ZH,high(10) ldi temp,timer1on out TIMSK,temp subi bally,124 ;find difference with 127 neg bally ;and then subtract that from 127 subi bally,-124 neg balldy updatex: ; now update x direction add ballx, balldx cpi ballx, 240-8-4 ; check for paddle hit brcs skipPaddle1Check ; branch if ballx < 232 sbrc balldx,7 rjmp skipPaddle1Check ; ensure ball direction is correct mov temp, bally sub temp, paddle1 cpi temp, 16 ; paddle is 16 pixels long brcs hitxr skipPaddle1Check: cpi ballx,236 ;if it hits right wall, over 240 brcc p1miss cpi ballx, 8 ; check for paddle hit brcs paddle0Check cpi ballx, 5 brcs p0miss ret hitxr: ; hit right paddle cpi temp, 4 brcs hitxr1 cpi temp, 12 brcs hitxr2 subi balldx, -1 rjmp hitxr2 hitxr1: subi balldx, -1 hitxr2: subi ballx,228 ;find difference with 240 neg ballx ;and then subtract that from 240 subi ballx,-228 rjmp updateend paddle0Check: mov temp, bally sub temp, paddle0 cpi temp, 16 brcs hitxl ret ; miss paddle, keep ball moving, no bounce p1miss: sbrc balldx, 7 ; ensure ball direction is correct rjmp p0miss inc score0 rjmp screenflash ; flash screen, play bad noise p0miss: sbrs balldx, 7 ; ensure ball direction is correct rjmp p1miss inc score1 rjmp screenflash ; flash screen, play bad noise hitxl: ;bally is close to 0 edge neg ballx subi ballx,-16 updateend:; but hit ball too ldi temp, low(50) out OCR1AH, temp ldi temp, high(50) out OCR1AL, temp ldi ZL,low(20) ldi ZH,high(20) ldi temp,timer1on out TIMSK,temp neg balldx dec speedctr breq incBalldx ret incBalldx: cpi balldx, 8 breq skipIncBalldx cpi balldx, -8 breq skipIncBalldx sbrs balldx, 7 ; if negative, skip next inc balldx sbrc balldx, 7 dec balldx ldi temp, 4 mov speedctr, temp skipIncBalldx: ret ;*********************** ;clears lcd memory clrallmem: ;set the address pointer to the beginning of memory statusi 0x03 writei 0x00 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x24 ;Zero out counter ldi addrh,0 ldi addrl,0 ;set up autowrite statusi 0x03 commandi 0xB0 clrmemloop: ;inc counter addi16 addrh, addrl, 0x0001 ;write zero to memory statusi 0x08 writei 0x00 ;check loop status cpi16 addrh, addrl, 0x1680 brne clrmemloop ;return LCD controller to normal mode statusi 0x08 commandi 0xB2 ret checkControl0: ; checks the position of pot 0 ;set up analog converter to read channel zero ldi temp, 4 out ADMUX, temp rcall measure_resistance mov dres24uL, AnaLo mov dres24uM, AnaHi clr dres24uH ; divide by 130 ldi temp, 130 mov dv24uL, temp clr dv24uH rcall div24u rcall erasepaddle0 mov paddle0, dres24uL rcall drawpaddle0 ret checkControl1: ; checks the position of pot 1 ;set up analog converter to read channel three (channel one is dead?!) ldi temp, 6 out ADMUX, temp rcall measure_resistance mov dres24uL, AnaLo mov dres24uM, AnaHi clr dres24uH ldi temp, 130 mov dv24uL, temp clr dv24uH rcall div24u rcall erasepaddle1 mov paddle1, dres24uL rcall drawpaddle1 ret ;============================================= ;delay - 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 out TCNT0, Reload ; keeps clock ticking at 1 mSec dec timeout ;subtract another mSec noteyet:out SREG, save reti ;back to backgound tasks ;*********************************************************** ;Timer 1 interrupt (plays sound through the speaker) t1AMatch: ;interrupt on compare match with value in OCR1A in save,SREG sbic PIND, speakerbit ;toggle speaker output rjmp t1set sbi PORTD, speakerbit rjmp t1dec t1set: cbi PORTD, speakerbit t1dec: sbiw ZL,1 brne t1end ldi temp,timer1off ; turn off the noize once we reach 0 on the Z counter out TIMSK,temp t1end: out SREG,save reti ; draw paddle routines drawpaddle0: ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y (what row) ; multiply mov temp, paddle0 rcall mpy8u ; move address pointer to paddle location rcall moveto ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000011 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b00000001 rcall status3 write temp2 rcall status3 commandi 0xC4 ret drawpaddle1: ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y (what row) ; multiply mov temp, paddle1 rcall mpy8u adiw addrl, 29 ; move address pointer to paddle location rcall moveto ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b11000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 rcall moveto ldi temp2, 0b10000000 rcall status3 write temp2 rcall status3 commandi 0xC4 ret ; erase paddle routines erasepaddle0: ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y (what row) ; multiply mov temp, paddle0 rcall mpy8u ldi cnt, 16 eraseloop0: ; move address pointer to paddle location rcall moveto ldi temp2, 0b00000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 dec cnt brne eraseloop0 ret erasepaddle1: ldi addrh, 0 ldi addrl, 30 ; each graphic line is 30 bytes long ; determine y (what row) ; multiply mov temp, paddle1 rcall mpy8u ldi cnt, 16 adiw addrl, 29 eraseloop1: ; move address pointer to paddle location rcall moveto ldi temp2, 0b00000000 rcall status3 write temp2 rcall status3 commandi 0xC4 adiw addrl, 30 dec cnt brne eraseloop1 ret ; Helper for reading the ADC ; Code adapted from the Digital Voltmeter lab measure_resistance: ldi temp1, 0b11000101 ;start A to D conversion out ADCSR, temp1 await: in temp, ADCSR ;wait for A to D done andi temp, 0b01000000;by checking ADSC bit brne await ;this bit is cleared by the AtoD hardware in AnaLo, ADCL ;read the voltage in AnaHi, ADCH ldi temp,low(1250) ;put 1250 = 5V into denom mov dv24uL,temp ldi temp,high(1250) mov dv24uH,temp sub dv24uL,AnaLo ;find 1250 - Ana for resistance calculations sbc dv24uH,AnaHi ldi temp,low(R) ;multiplier = R mov mp16uL,temp ldi temp,high(R) mov mp16uH,temp mov mc16uL,AnaLo ;multiplicand = V mov mc16uH,AnaHi rcall mpy16u rcall div24u ;RV / vcc - v -> result is in r4,5 hopefully, r7 is 0 mov AnaLo,r10 ;mov result to AnaLo/Hi for printing to LCD mov AnaHi,r11 ret screenflash: ;** flashes the LCD after someone misses the ball ldi cnt,3 screenflash2: ;set the address pointer to the beginning of memory statusi 0x03 writei 0x00 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x24 ;Zero out counter ldi addrh,0 ldi addrl,0 ;set up autowrite statusi 0x03 commandi 0xB0 screenflashloop: ;inc counter addi16 addrh, addrl, 0x0001 ; play noise out OCR1AH, addrl out OCR1AL, addrh ldi ZL,low(10) ldi ZH,high(10) ldi temp,timer1on out TIMSK,temp ;write zero to memory statusi 0x08 writei 0xFF ;check loop status cpi16 addrh, addrl, 0x1680 brne screenflashloop ;return LCD controller to normal mode statusi 0x08 commandi 0xB2 ldi temp, 100 mov timeout, temp rcall delay ;set the address pointer to the beginning of memory statusi 0x03 writei 0x00 statusi 0x03 writei 0x00 statusi 0x03 commandi 0x24 ;Zero out counter ldi addrh,0 ldi addrl,0 ;set up autowrite statusi 0x03 commandi 0xB0 screenflashloop2: ;inc counter addi16 addrh, addrl, 0x0001 ;write zero to memory statusi 0x08 writei 0x00 ;check loop status cpi16 addrh, addrl, 0x1680 brne screenflashloop2 ;return LCD controller to normal mode statusi 0x08 commandi 0xB2 ldi temp, 100 mov timeout,temp rcall delay dec cnt tst cnt breq screenflashend rjmp screenflash2 screenflashend: rjmp nextGame writelabels: ; Writes labels on the screen before each new game ;set pointer to begin writing sbrc score0, 2 rjmp p0Win sbrc score1, 2 rjmp p1Win brtc firstgame sbrs balldx, 7 rjmp p1msg ldi R31, high(P0*2) ldi R30, low(P0*2) rjmp printMsg p1msg: ldi R31, high(P1*2) ldi R30, low(P1*2) rjmp printMsg firstgame: set ; turn off first game flag ldi R31, high(MSG*2) ldi R30, low(MSG*2) printMsg: ldi addrl, low(0x141E) ldi addrh, high(0x141E) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 rcall writepgmem ; move to print scores ldi addrl, low(0x15c2) ldi addrh, high(0x15c2) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 mov temp2, score0 ori temp2, 0b00010000 rcall status3 write temp2 rcall status3 commandi 0xC0 ; move to print scores ldi addrl, low(0x15df) ldi addrh, high(0x15df) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 mov temp2, score1 ori temp2, 0b00010000 rcall status3 write temp2 rcall status3 commandi 0xC0 ; wait for button press; randomize ball direction clr temp ldi balldx, 1 startpoll: ;waits for pind0 to be pushed dec bally ;if not, goes through random number generator tst bally ;for balldy and balldx and bally brne nextrandom ;(ballx is set to 120) ldi bally,128 nextrandom: ; generates a random direction for the ball inc temp sbrc temp,0 neg balldx sbrc temp,1 neg balldy sbic PIND,0 rjmp startpoll ;set pointer to begin erasing ldi R31, high(MSGCLR*2) ldi R30, low(MSGCLR*2) ldi addrl, low(0x141E) ldi addrh, high(0x141E) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 rcall writepgmem ret ; | | | MSG: .db " P O N G Push PD0 to begin Player 0 Player 1" P0: .db " M I S S Player 0 misses! " P1: .db " M I S S Player 1 misses! " P0W: .db " G A M E O V E R Player 0 wins! " P1W: .db " G A M E O V E R Player 1 wins! " MSGCLR: .db " " writepgmem: clr cnt ldi temp2, 0x20 writepgmemloop: inc cnt lpm ; puts in r0 = pgmem sub pgmem, temp2 ; offset for our display (ASCII 20h = 00h) addi16 R31, R30, 1 rcall status3 write pgmem rcall status3 commandi 0xC0 cpi cnt, 90 brne writepgmemloop ret p1Win: ldi R31, high(P1W*2) ldi R30, low(P1W*2) rjmp win p0Win: ldi R31, high(P0W*2) ldi R30, low(P0W*2) win: ldi addrl, low(0x141E) ldi addrh, high(0x141E) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 rcall writepgmem ; move to print scores ldi addrl, low(0x15c2) ldi addrh, high(0x15c2) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 mov temp2, score0 ori temp2, 0b00010000 rcall status3 write temp2 rcall status3 commandi 0xC0 ; move to print scores ldi addrl, low(0x15df) ldi addrh, high(0x15df) rcall status3 write addrl rcall status3 write addrh rcall status3 commandi 0x24 mov temp2, score1 ori temp2, 0b00010000 rcall status3 write temp2 rcall status3 commandi 0xC0 ; play music ldi temp, low(30) out OCR1AH, temp ldi temp, high(30) out OCR1AL, temp ldi ZL,low(40) ldi ZH,high(40) ldi temp,timer1on out TIMSK,temp win1: tst ZL brne win1 ldi temp, low(50) out OCR1AH, temp ldi temp, high(50) out OCR1AL, temp ldi ZL,low(60) ldi ZH,high(60) ldi temp,timer1on out TIMSK,temp win2: tst ZL brne win2 ldi temp, low(30) out OCR1AH, temp ldi temp, high(30) out OCR1AL, temp ldi ZL,low(40) ldi ZH,high(40) ldi temp,timer1on out TIMSK,temp win3: tst ZL brne win3 ldi temp, low(25) out OCR1AH, temp ldi temp, high(25) out OCR1AL, temp ldi ZL,low(90) ldi ZH,high(90) ldi temp,timer1on out TIMSK,temp win4: tst ZL brne win4 ldi temp, low(80) out OCR1AH, temp ldi temp, high(80) out OCR1AL, temp ldi ZL,low(60) ldi ZH,high(60) ldi temp,timer1on out TIMSK,temp win5: tst ZL brne win5 ldi temp, low(50) out OCR1AH, temp ldi temp, high(50) out OCR1AL, temp ldi ZL,low(90) ldi ZH,high(90) ldi temp,timer1on out TIMSK,temp endg: sbic PIND,0 rjmp endg rjmp RESET ;***** Code: 24x16 bit divide ; Adapted from Atmel 16x16 divide .def drem24uL=r8 ; remainder .def drem24uH=r9 .def dres24uL=r10 ; result .def dres24uM=r11 .def dres24uH=r12 .def dv24uL =r15 ; divisor .def dv24uH =r14 .def dcnt24u =r16 ; loop counter div24u: clr drem24uL ;clear remainder Low byte sub drem24uH,drem24uH;clear remainder High byte and carry ldi dcnt24u,25 ;init loop counter d24u_1: rol dres24uL ;shift left dividend rol dres24uM rol dres24uH dec dcnt24u ;decrement counter brne d24u_2 ;if done ret ; return d24u_2: rol drem24uL ;shift dividend into remainder rol drem24uH sub drem24uL,dv24uL ;remainder = remainder - divisor sbc drem24uH,dv24uH ; brcc d24u_3 ;if result negative add drem24uL,dv24uL ; restore remainder adc drem24uH,dv24uH clc ; clear carry to be shifted into result rjmp d24u_1 ;else d24u_3: sec ; set carry to be shifted into result rjmp d24u_1 ; the following code was obtained from Atmel ;*************************************************************************** ;* ;* "mpy8u" - 8x8 Bit Unsigned Multiplication ;* ;* This subroutine multiplies the two register variables mp8u and mc8u. ;* The result is placed in registers m8uH, m8uL ;* ;* Number of words :9 + return ;* Number of cycles :58 + return ;* Low registers used :None ;* High registers used :4 (mp8u,mc8u/m8uL,m8uH,mcnt8u) ;* ;* Note: Result Low byte and the multiplier share the same register. ;* This causes the multiplier to be overwritten by the result. ;* ;*************************************************************************** ;***** Subroutine Register Variables ;def mc8u =r16 ;multiplicand ;def mp8u =r17 ;multiplier ;.def m8uL =r17 ;result Low byte ;.def m8uH =r18 ;result High byte ;.def mcnt8u =r19 ;loop counter ;***** Code mpy8u: clr addrh ;clear result High byte ldi cnt, 8 ;init loop counter lsr addrl ;rotate multiplier m8u_1: brcc m8u_2 ;carry set add addrh,temp ; add multiplicand to result High byte m8u_2: ror addrh ;rotate right result High byte ror addrl ;rotate right result L byte and multiplier dec cnt ;decrement loop counter brne m8u_1 ;if not done, loop more reti ;***** Code for 16x16 bit multiply mpy16u:clr m16u3 ;clear 2 highest bytes of result clr m16u2 ldi mcnt16u,16 ;init loop counter lsr m16u1 ror m16u0 m16u_1:brcc noad8 ;if bit 0 of multiplier set add m16u2,mc16uL ;add multiplicand Low to byte 2 of res adc m16u3,mc16uH ;add multiplicand high to byte 3 of res noad8:ror m16u3 ;shift right result byte 3 ror m16u2 ;rotate right result byte 2 ror m16u1 ;rotate result byte 1 and multiplier High ror m16u0 ;rotate result byte 0 and multiplier Low dec mcnt16u ;decrement loop counter brne m16u_1 ;if not done, loop more ret