143 lines
2.8 KiB
ArmAsm
143 lines
2.8 KiB
ArmAsm
#include <avr/io.h>
|
|
#include "macro.h"
|
|
#include "const.h"
|
|
|
|
.text
|
|
|
|
.global main
|
|
main:
|
|
ldi r16, 0x30 ; port B, pin 4 and 5 as output
|
|
sts DDRB, r16
|
|
|
|
; set interrupt vectors at address 0x0, not bootloader
|
|
; timing is important, see atmel datasheet
|
|
ldi r16, (1 << IVCE)
|
|
ldi r17, 0
|
|
out IO(MCUCR), r16
|
|
out IO(MCUCR), r17
|
|
|
|
ldi r16, 0xa ; external interrupt 0 and 1, falling edge
|
|
sts EICRA, r16
|
|
|
|
ldi r16, 0x3 ; external interrupt 0 and 1, mask enable
|
|
sts EIMSK, r16
|
|
|
|
ldi r16, 0x02 ; don't connect output pins to timer, CTC[1:0] mode
|
|
sts TCCR0A, r16
|
|
ldi r16, 0x01 ; CTC[2] mode, no prescaler
|
|
sts TCCR0B, r16
|
|
|
|
; init variables
|
|
ldi r16, 0
|
|
sts frame, r16
|
|
sts frame + 1, r16
|
|
sts line + 1, r16
|
|
ldi r16, 1
|
|
sts line, r16
|
|
|
|
call setup_c
|
|
|
|
sei ; global interrupt enable
|
|
|
|
1:
|
|
call loop_c
|
|
rjmp 1b
|
|
|
|
.global int_horizontal_sync
|
|
int_horizontal_sync: ; +3
|
|
push r31 ; +5
|
|
in r31, IO(SREG) ; +6, status register
|
|
push r31 ; +8
|
|
push r30 ; +10
|
|
|
|
; if (line >= VERTICAL_OFFSET), then enter
|
|
lds r30, line ; +12
|
|
lds r31, line + 1 ; +14
|
|
adiw z, 1 ; +16
|
|
sts line, r30 ; +18
|
|
sts line + 1, r31 ; +20
|
|
cpi r31, 0 ; +21
|
|
brne enter ; +22, +23
|
|
cpi r30, VERTICAL_OFFSET ; +23
|
|
brlo int_horizontal_sync_end ; +24
|
|
|
|
enter:
|
|
; here, +23 or +24 cycles have passed since horizontal sync
|
|
; so, there are still ~168 cycles before first useful data
|
|
ldi r31, 0
|
|
sts TCNT0, r31
|
|
ldi r31, HORIZONTAL_OFFSET ; set counter TOP
|
|
sts OCR0A, r31
|
|
|
|
ldi r31, 0x7 ; clear any pending interrupt
|
|
sts TIFR0, r31
|
|
|
|
lds r31, TIMSK0
|
|
ori r31, 0x02 ; mask enable interrupt timer A
|
|
sts TIMSK0, r31
|
|
|
|
int_horizontal_sync_end:
|
|
pop r30
|
|
pop r31
|
|
out IO(SREG), r31
|
|
pop r31
|
|
reti
|
|
|
|
.global int_timer_0
|
|
int_timer_0:
|
|
; here we are at the beginning of the visible line
|
|
push r31
|
|
in r31, IO(SREG)
|
|
push r31
|
|
push r30
|
|
push r29
|
|
|
|
; turn off interrupt
|
|
lds r31, TIMSK0
|
|
andi r31, 0xfd ; mask disable interrupt timer A
|
|
sts TIMSK0, r31
|
|
|
|
; draw things
|
|
ldi r30, lo8(line_buffer)
|
|
ldi r31, hi8(line_buffer)
|
|
|
|
.rept LINE_BUFFER_SIZE
|
|
ld r29, z+
|
|
out IO(PORTB), r29
|
|
nop
|
|
.endr
|
|
|
|
pop r29
|
|
pop r30
|
|
pop r31
|
|
out IO(SREG), r31
|
|
pop r31
|
|
reti
|
|
|
|
.global int_vertical_sync
|
|
int_vertical_sync:
|
|
push r31
|
|
in r31, IO(SREG)
|
|
push r31
|
|
push r30
|
|
|
|
lds r31, frame + 1
|
|
lds r30, frame
|
|
adiw z, 1
|
|
sts frame + 1, r31
|
|
sts frame, r30
|
|
|
|
ldi r30, 1
|
|
ldi r31, 0
|
|
sts line, r30
|
|
sts line + 1, r31
|
|
|
|
int_vertical_sync_end:
|
|
pop r30
|
|
pop r31
|
|
out IO(SREG), r31
|
|
pop r31
|
|
reti
|
|
|
|
|