aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/runtime/asm_avr.S
blob: 23a3d496103973c8e42c9d859ef889ea390da661 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
.section .text.tinygo_scanCurrentStack
.global tinygo_scanCurrentStack
.type tinygo_scanCurrentStack, %function
tinygo_scanCurrentStack:
    // Save callee-saved registers.
    push r29 // Y
    push r28 // Y
    push r17
    push r16
    push r15
    push r14
    push r13
    push r12
    push r11
    push r10
    push r9
    push r8
    push r7
    push r6
    push r5
    push r4
    push r3
    push r2

    // Scan the stack.
    in  r24, 0x3d; SPL
    in  r25, 0x3e; SPH
#if __AVR_ARCH__ == 2 || __AVR_ARCH__ == 25
    rcall tinygo_scanstack
#else
    call tinygo_scanstack
#endif

    // Restore callee-saved registers.
    pop r2
    pop r3
    pop r4
    pop r5
    pop r6
    pop r7
    pop r8
    pop r9
    pop r10
    pop r11
    pop r12
    pop r13
    pop r14
    pop r15
    pop r16
    pop r17
    pop r28 // Y
    pop r29 // Y


.section .text.tinygo_longjmp
.global tinygo_longjmp
tinygo_longjmp:
    ; Move the *DeferFrame pointer to the X register.
    mov r26, r24
    mov r27, r25

    ; Load the stack pointer
    ld r24, X+
    ld r25, X+

    ; Switch to the given stack pointer.
    in r0, 0x3f   ; SREG
    cli           ; disable interrupts
    out 0x3d, r24 ; SPL
    out 0x3f, r0  ; re-enable interrupts (with one instruction delay)
    out 0x3e, r25 ; SPH

    ; Load the new PC
    ld r30, X+
    ld r31, X+

    ; Load the new Y register
    ld r28, X+
    ld r29, X+

    ; Jump to the PC (stored in the Z register)
    icall