This is my attempt at the AVR Pong final project.
https://wokwi.com/arduino/projects/294631094740845069
global main
.global __do_copy_data
#include <avr/io.h>
; DOWN PIN6 = PD6
; UP PIN 7 = PD7
;
; CS PIN 10 (green) = PB2
CS = PB2
; IN PIN 11 = PB3
; CLK PIN 13 = PB5
;
; [ "uno:10", "m1:CS", "green", [ "v-24", "*", "h-4" ] ],
; [ "uno:11", "m1:DIN", "orange", [ "v-20", "*", "h-8" ] ],
; [ "uno:13", "m1:CLK", "blue", [ "v-16", "*", "h-12" ] ],
;
.equ LED, PB5
BIT_UP = 7
BIT_DOWN = 6
#define tmpreg r16
#define tmpreg2 r17
#define TICKS r28
#define CLOCK Z
; Game status
.data
paddle_player:
.byte 0
paddle_comp:
.byte 0
ball_x:
.byte 0
ball_y:
.byte 0
ball_dirx:
.byte 0
ball_diry:
.byte 0
.text
init_game_status:
ldi tmpreg, 4
sts paddle_player, tmpreg
inc tmpreg
sts paddle_comp, tmpreg
sts ball_y, tmpreg
ldi tmpreg, 14
sts ball_x, tmpreg
ldi tmpreg, 0xff
sts ball_dirx, tmpreg
ldi tmpreg, 0xff
sts ball_diry, tmpreg
ret
clear_clock:
clr TICKS
ldi ZL, 0
ldi ZH, 0
ret
increment_clock:
;ADIW R30, 1
ADIW Z, 1
inc TICKS
ret
.global TIMER1_OVF_vect
TIMER1_OVF_vect:
push r0
in r0, _SFR_IO_ADDR(SREG)
push r0
rcall increment_clock
pop r0
out _SFR_IO_ADDR(SREG), r0
pop r0
reti
init_spi:
ldi r24, (1<<5) | (1<<3) | (1<<2)
out _SFR_IO_ADDR(DDRB), r24
ldi r24, (1<<2)
out _SFR_IO_ADDR(PORTB),r24 ; CS HIGH
ldi r24,0B01010001
out _SFR_IO_ADDR(SPCR),r24
ret
spi_wait:
; input r24
;break
push r0
out _SFR_IO_ADDR(SPDR), r24
check_status:
in r0, _SFR_IO_ADDR(SPSR)
sbrs r0, SPIF
rjmp check_status
pop r0
ret
init_buttons:
; set as input
ldi tmpreg, 0b11000000
clr tmpreg
out _SFR_IO_ADDR(DDRD), tmpreg
; enable pull up resistors
ldi tmpreg, (1<<BIT_DOWN) | (1 << BIT_UP)
out _SFR_IO_ADDR(PORTD), tmpreg
read_buttons:
clr r16
sbis _SFR_IO_ADDR(PIND), BIT_UP
ldi r16,1
sbis _SFR_IO_ADDR(PIND), BIT_DOWN
ldi r16,2
ret
update_paddles:
push r16
push r17
; move player paddles if buttons pressed
rcall read_buttons
cpi r16, 2
brne nxt
; paddle down = inc
lds r17, paddle_player
inc r17
cpi r17, 8
brsh 2f
sts paddle_player, r17
2:
rjmp done
nxt:
cpi r16, 1
brne done
lds r17, paddle_player
tst r17
breq done
dec r17
sts paddle_player, r17
done:
; computer paddles pseudo random
mov r16, ZL
andi r16, 0x7
tst r16
brne 5f
lds r17, paddle_comp
; randomize using clock upper byte
mov r16, ZH
andi r16, 0x7
cpi r16, 0x4
brsh 3f
inc r17
rjmp 4f
3:
dec r17
4:
andi r17, 0x7
sts paddle_comp, r17
5:
pop r17
pop r16
ret
test_draw_screen_pattern:
cbi _SFR_IO_ADDR(PORTB),CS
ldi r24, 1
rcall spi_wait
ldi r24, 0xaa
rcall spi_wait
ldi r24, 8
rcall spi_wait
ldi r24, 0xaa
rcall spi_wait
sbi _SFR_IO_ADDR(PORTB),CS
ret
draw_screen_row:
;r24 row 0 - TOP, row 7 - BOTTOM
;r22 left pattern
;r23 right pattern
push r24
inc r24
push r1
cbi _SFR_IO_ADDR(PORTB),CS
mov r1, r24
rcall spi_wait
mov r24, r22
rcall spi_wait
mov r24, r1
rcall spi_wait
mov r24, r23
rcall spi_wait
sbi _SFR_IO_ADDR(PORTB),CS
pop r1
pop r24
ret
test_draw_screen_pattern2:
ldi r24, 1
ldi r22, 0x1
ldi r23, 0x3
rcall draw_screen_row
ldi r24, 7
ldi r22, 0x3
ldi r23, 0x1
rcall draw_screen_row
ret
test_draw_screen_game:
ldi r24, 3
ldi r22, 6
ldi r20, 8
ldi r18, 6
rcall draw_screen_game
ret
is_paddle_row:
; r9 row tested
; r8 paddle middle
push r0
;middle
cp r8, r9
breq 1f
;paddle top (-1)
mov r0, r8
dec r0
cp r0, r9
breq 1f
;paddle_bottom (+1)
mov r0, r8
inc r0
cp r0, r9
1:
pop r0
ret
set_bit_16breg:
;input r0 = 0-15
;0 r22:r23 0x01:0x00
;1 r22:r23 0x02:0x00
;15 r22:r23 0x00:0x80
push r16
mov r16, r0
ldi r22,1
1:
tst r16
breq done_shifting
lsl r22
rol r23
dec r16
rjmp 1b
done_shifting:
pop r16
ret
draw_screen_game:
;input:
;r24 paddle_player
;r22 paddle_computer
;r20 ball_x 0..15
;r18 ball_y 0..7
push r24
push r22
push r20
push r18
push r17
push r16
mov r0, r24
mov r1, r22
; r24 looping 0-7
clr r24
1:
clr r22
clr r23
cp r18, r24
brne no_ball
push r0
mov r0, r20
rcall set_bit_16breg
pop r0
no_ball:
; player paddle
mov r8, r0
mov r9, r24
rcall is_paddle_row
brne skip_paddle1
ori r22, 0x01
skip_paddle1:
; computer paddle
mov r8, r1
mov r9, r24
rcall is_paddle_row
brne skip_paddle2
ori r23, 0x80
skip_paddle2:
rcall draw_screen_row
inc r24
cpi r24, 8
brne 1b
pop r16
pop r17
pop r18
pop r20
pop r22
pop r24
ret
draw_game_from_status:
lds r24, paddle_player
lds r22, paddle_comp
lds r20, ball_x
lds r18, ball_y
rcall draw_screen_game
ret
set_timer:
clr tmpreg
sts TCCR1A, tmpreg
ldi tmpreg, 1 << CS10
sts TCCR1B, tmpreg
ldi tmpreg, 1 << TOIE1
sts TIMSK1, tmpreg
ret
update_ball:
; update ball direction
lds tmpreg, ball_x
tst tmpreg
brne 1f
lds r8, paddle_player
lds r9, ball_y
rcall is_paddle_row
brne game_over
; going left to right now
ldi tmpreg, 1
sts ball_dirx, tmpreg
1:
lds tmpreg, ball_x
cpi tmpreg, 15
brne 2f
lds r8, paddle_comp
lds r9, ball_y
rcall is_paddle_row
brne game_over
; going right to left now
ldi tmpreg, 0xff ; -1
sts ball_dirx, tmpreg
2:
lds tmpreg, ball_y
tst tmpreg
brne 3f
; going down now
ldi tmpreg, 1
sts ball_diry, tmpreg
3:
lds tmpreg, ball_y
cpi tmpreg, 7
brne 4f
; going up now
ldi tmpreg, 0xff ; -1
sts ball_diry, tmpreg
4:
; update ball position
lds tmpreg, ball_x
lds tmpreg2, ball_dirx
add tmpreg, tmpreg2
sts ball_x, tmpreg
lds tmpreg, ball_y
lds tmpreg2, ball_diry
add tmpreg, tmpreg2
sts ball_y, tmpreg
ldi r24, 0
ret
game_over:
clr tmpreg
; stop ball
sts ball_dirx, tmpreg
sts ball_diry, tmpreg
ldi r24, 1
ret
main:
; initialize
rcall init_spi
rcall init_buttons
rcall clear_clock
rcall set_timer
rcall init_game_status
sei
game_loop:
; every few clock ticks we update
;cpi ZL, 20
cpi TICKS, 16
brlo 1f
rcall update_paddles
rcall update_ball
tst r24
brne end_of_game
cli
clr TICKS
sei
1:
;rcall test_draw_screen_game
rcall draw_game_from_status
rjmp game_loop
end_of_game:
; end of game
cli
rjmp end_of_game