.section .ivr, "ax", @progbits
.align 1
ivr:
jmp _init_cpu
jmp _ivr_crcscan_nmi
jmp _ivr_bod_vlm
jmp _ivr_rtc_cnt
jmp _ivr_rtc_pit
jmp _ivr_ccl_ccl
jmp _ivr_porta_port
jmp _ivr_tca0_ovf
jmp _ivr_tca0_hunf
jmp _ivr_tca0_cmp0
jmp _ivr_tca0_cmp1
jmp _ivr_tca0_cmp2
jmp _ivr_tcb0_int
jmp _ivr_tcb1_int
jmp _ivr_twi0_twis
jmp _ivr_twi0_twim
jmp _ivr_spi0_int
jmp _ivr_usart0_rcx
jmp _ivr_usart0_dre
jmp _ivr_usart0_tcx
jmp _ivr_portd_port
jmp _ivr_ac0_ac
jmp _ivr_adc0_resrdy
jmp _ivr_adc0_wcomp
jmp _ivr_portc_port
jmp _ivr_tcb2_int
jmp _ivr_usart1_rcx
jmp _ivr_usart1_dre
jmp _ivr_usart1_tcx
jmp _ivr_portf_port
jmp _ivr_nvmctrl_ee
jmp _ivr_usart2_rcx
jmp _ivr_usart2_dre
jmp _ivr_usart2_tcx
jmp _ivr_portb_port
jmp _ivr_porte_port
jmp _ivr_tcb3_int
jmp _ivr_usart3_rcx
jmp _ivr_usart3_dre
jmp _ivr_usart3_tcx
_ivr_undefined:
reti
;;; CPU flags initialisation
_init_cpu:
cli ;;; Disable interrupts (the application will reenable when it wants)
ldi r16,0x01 ;;; Sleep = IDLE mode, ENABLED
sts 0x50,r16 ;;; Write sleep control flag
eor r1, r1 ;;; The compiler runtime expects 0 in r1
;;; Clear the BSS region
_init_zero_bss:
ldi r31, hi8(__bss_start) ;;; load BSS start into Z
ldi r30, lo8(__bss_start)
ldi r29, hi8(__bss_end) ;;; load BSS end into Y
ldi r28, lo8(__bss_end)
sub r28, r30 ;;; Y = Y-Z (== length in bytes)
sbc r29, r31
rjmp _init_zero_bss_loop_check
_init_zero_bss_loop:
st Z+, r1 ;;; Store zero @Z and postincrement
subi r28, 1 ;;; Decrement counter Y
sbci r29, 0
_init_zero_bss_loop_check:
brne _init_zero_bss_loop ;;; Loop iff Y != 0
;;; Inititalise RAM
_init_copy_memory:
ldi r31, hi8(__data_load_start) ;;; data segment start into Z
ldi r30, lo8(__data_load_start)
ldi r29, hi8(__data_load_end) ;;; data segment end into Y
ldi r28, lo8(__data_load_end)
ldi r27, hi8(__data_start) ;;; destination address into X
ldi r26, lo8(__data_start)
sub r28, r30 ;;; Y = Y-Z (== length in bytes)
sbc r29, r31
rjmp _init_copy_memory_loop_check
_init_copy_memory_loop:
lpm r0, Z+ ;;; Load from @Z and incremenent pointer
st X+, r0 ;;; Store to @X, increment pointer
subi r28, 1 ;;; Decrement counter Y
sbci r29, 0
_init_copy_memory_loop_check:
brne _init_copy_memory_loop ;;; Loop iff Y != 0
;;; Now jump into the application
_init_runtime:
;;; @todo reset the stack pointer
jmp _oxide_boot ;;; Jump to the application entry point
;;; By default, start all interrupt handlers as doing a no-op
;;; return. Since these symbols are weakly linked, user code can
;;; override each one on demand.
.macro _ivr_default name target=_ivr_undefined
.weak \name
.set \name, \target
.endm
_ivr_default _ivr_crcscan_nmi
_ivr_default _ivr_bod_vlm
_ivr_default _ivr_rtc_cnt
_ivr_default _ivr_rtc_pit
_ivr_default _ivr_ccl_ccl
_ivr_default _ivr_porta_port
_ivr_default _ivr_tca0_ovf
_ivr_default _ivr_tca0_hunf
_ivr_default _ivr_tca0_cmp0
_ivr_default _ivr_tca0_cmp1
_ivr_default _ivr_tca0_cmp2
_ivr_default _ivr_tcb0_int
_ivr_default _ivr_tcb1_int
_ivr_default _ivr_twi0_twis
_ivr_default _ivr_twi0_twim
_ivr_default _ivr_spi0_int
_ivr_default _ivr_usart0_rcx
_ivr_default _ivr_usart0_dre
_ivr_default _ivr_usart0_tcx
_ivr_default _ivr_portd_port
_ivr_default _ivr_ac0_ac
_ivr_default _ivr_adc0_resrdy
_ivr_default _ivr_adc0_wcomp
_ivr_default _ivr_portc_port
_ivr_default _ivr_tcb2_int
_ivr_default _ivr_usart1_rcx
_ivr_default _ivr_usart1_dre
_ivr_default _ivr_usart1_tcx
_ivr_default _ivr_portf_port
_ivr_default _ivr_nvmctrl_ee
_ivr_default _ivr_usart2_rcx
_ivr_default _ivr_usart2_dre
_ivr_default _ivr_usart2_tcx
_ivr_default _ivr_portb_port
_ivr_default _ivr_porte_port
_ivr_default _ivr_tcb3_int
_ivr_default _ivr_usart3_rcx
_ivr_default _ivr_usart3_dre
_ivr_default _ivr_usart3_tcx