github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/targets/avr.S (about) 1 ; This file provides common code across AVRs that cannot be implemented directly 2 ; in Go. 3 ; The reset vector is device-specific and is generated by tools/gen-device-avr.py. 4 5 ; These definitions are necessary because LLVM does not yet know these register 6 ; aliases. See: https://reviews.llvm.org/D96492 7 #define xl r26 8 #define xh r27 9 #define yl r28 10 #define yh r29 11 #define zl r30 12 #define zh r31 13 14 ; Ugly hack until https://reviews.llvm.org/D137572 is merged. 15 #if !defined(__AVR_HAVE_ELPM__) && defined(__flash1) 16 #define __AVR_HAVE_ELPM__ 17 #endif 18 19 ; Startup code 20 .section .text.__vector_RESET 21 .global __vector_RESET 22 __vector_RESET: 23 clr r1 ; r1 is expected to be 0 by the C calling convention 24 25 ; Set up the stack pointer. 26 ldi xl, lo8(_stack_top) 27 ldi xh, hi8(_stack_top) 28 out 0x3d, xl; SPL 29 out 0x3e, xh; SPH 30 31 ; Subtract one from the stack pointer, so it doesn't point in the .data section. 32 push r0 33 34 ; Initialize .data 35 init_data: 36 ldi xl, lo8(_sdata) 37 ldi xh, hi8(_sdata) 38 ldi yl, lo8(_edata) 39 ldi yh, hi8(_edata) 40 ldi zl, lo8(_sidata) 41 ldi zh, hi8(_sidata) 42 #ifdef __AVR_HAVE_ELPM__ 43 ldi r16, hh8(_sidata) ; RAMPZ = hh8(_sidata) 44 out 0x3b, r16 45 #endif 46 init_data_loop: 47 cp xl, yl ; if x == y 48 cpc xh, yh 49 breq init_data_end ; goto main 50 #ifdef __AVR_HAVE_ELPM__ 51 elpm r0, Z+ ; r0 = *(z++) 52 #else 53 lpm r0, Z+ ; r0 = *(z++) 54 #endif 55 st X+, r0 ; *(x++) = r0 56 rjmp init_data_loop ; goto init_data_loop 57 init_data_end: 58 59 ; main will be placed right after here by the linker script so there's no 60 ; need to jump. 61 62 63 ; The only thing this WDT handler really does is disable itself, to get out of 64 ; sleep mode. 65 .section .text.__vector_WDT 66 .global __vector_WDT 67 __vector_WDT: 68 push r16 69 70 clr r16 71 wdr ; Reset watchdog 72 out 0x34, r16 ; Clear reset reason (MCUSR) 73 74 ; part 1: set WDCE and WDE to enable editing WDTCSR 75 lds r16, 0x60 ; r16 = WDTCSR 76 ori r16, 0x18 ; r16 |= WDCE | WDE 77 sts 0x60, r16 ; WDTCSR = r16 78 79 ; part 2: within 4 clock cycles, set the new value for WDTCSR 80 clr r16 81 sts 0x60, r16 ; WDTCSR = 0 82 83 pop r16 84 reti