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