giomba
eaef011cbd
This does not work as expected, and I don't understand why. Clock cycle count seems ok, but if there are no changes in the pixels, it seems to go faster
161 lines
3.1 KiB
ArmAsm
161 lines
3.1 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
|
|
|
|
; 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
|
|
|
|
|