#include #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 ; r0 always holds 0 clr r0 call setup_c sei ; global interrupt enable 1: 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 breq enter ; +23 jmp int_horizontal_sync_end # 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 clr r0 ldi zl, pm_lo8(line_jump_table) ldi zh, pm_hi8(line_jump_table) lds r29, line add zl, r29 adc zh, r0 add zl, r29 adc zh, r0 ijmp # ; 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 .global jump_table_return_address jump_table_return_address: 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