1/* Copyright (c) 2002, Marek Michalkiewicz 2 All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are met: 6 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above copyright 10 notice, this list of conditions and the following disclaimer in 11 the documentation and/or other materials provided with the 12 distribution. 13 * Neither the name of the copyright holders nor the names of 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 POSSIBILITY OF SUCH DAMAGE. */ 28 29/* $Id: setjmp.S 2484 2015-08-17 06:34:41Z pitchumani $ */ 30 31 32 33/* 34 setjmp.S 35 36 Contributors: 37 Created by Marek Michalkiewicz <marekm@linux.org.pl> 38 */ 39 40/* 41 jmp_buf: 42 offset size description 43 0 16/2 call-saved registers (r2-r17) 44 (AVR_TINY arch has only 2 call saved registers (r18,r19)) 45 16/2 2 frame pointer (r29:r28) 46 18/4 2 stack pointer (SPH:SPL) 47 20/6 1 status register (SREG) 48 21/7 2/3 return address (PC) (2 bytes used for <=128Kw flash) 49 23/24/9 = total size (AVR_TINY arch always has 2 bytes PC) 50 All multibytes are stored as little-endian. 51 52 int setjmp(jmp_buf __jmpb); 53 void longjmp(jmp_buf __jmpb, int __val) __attribute__((noreturn)); 54 */ 55 56#ifndef __DOXYGEN__ 57 58#include <avr/io.h> 59#include "macros.inc" 60 61/* ???: What was a reason to use aliases for common registers? 62 Check the address: is it a port number (value for IN/OUT)? */ 63#if AVR_STACK_POINTER_LO_ADDR != 0x3D \ 64 || AVR_STATUS_ADDR != 0x3F 65# error "Strange address of common registers SPL, SREG" 66#endif 67 68#define jmpb_hi r25 69#define jmpb_lo r24 70#define val_hi r23 71#define val_lo r22 72 73#define ret_lo r24 74#define ret_hi r25 75 76 ASSEMBLY_CLIB_SECTION 77 78 .global _U(setjmp) 79 .type _U(setjmp), @function 80 81_U(setjmp): 82 X_movw XL, jmpb_lo 83 ; save call-saved registers and frame pointer 84#if !defined(__AVR_TINY__) 85 .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 86#else 87 .irp .L_regno, 18,19,28,29 88#endif 89 st X+, r\.L_regno 90 .endr 91 ; get return address 92#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 93 pop __tmp_reg__ ; used below 94#endif 95 pop ZH 96 pop ZL 97 ; save stack pointer (after poping) 98 in ret_lo, AVR_STACK_POINTER_LO_ADDR 99 st X+, ret_lo 100#ifdef _HAVE_AVR_STACK_POINTER_HI 101 in ret_lo, AVR_STACK_POINTER_HI_ADDR 102 st X+, ret_lo 103#else 104 st X+, __zero_reg__ 105#endif 106 ; save status register (I flag) 107 in ret_lo, AVR_STATUS_ADDR 108 st X+, ret_lo 109 ; save return address 110 st X+, ZL 111 st X+, ZH 112 ; return zero 113 clr ret_lo 114 clr ret_hi 115#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 116 st X+, __tmp_reg__ 117 rjmp .L_jmp3 118#else 119 ijmp 120#endif 121 .size _U(setjmp), . - _U(setjmp) 122 123 .global _U(longjmp) 124 .type _U(longjmp), @function 125 126_U(longjmp): 127 X_movw XL, jmpb_lo 128 ; return value 129 X_movw ret_lo, val_lo 130 ; if zero, change to 1 131 cpi ret_lo, 1 132 cpc ret_hi, __zero_reg__ 133 adc ret_lo, __zero_reg__ 134 ; restore call-saved registers and frame pointer 135#if !defined(__AVR_TINY__) 136 .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 137#else 138 .irp .L_regno, 18,19,28,29 139#endif 140 ld r\.L_regno, X+ 141 .endr 142 ; restore stack pointer (SP value before the setjmp() call) and SREG 143 ld ZL, X+ 144 ld ZH, X+ 145 ld __tmp_reg__, X+ 146#if defined (__AVR_XMEGA__) && __AVR_XMEGA__ 147 /* A write to SPL will automatically disable interrupts for up to 4 148 instructions or until the next I/O memory write. */ 149 out AVR_STATUS_ADDR, __tmp_reg__ 150 out AVR_STACK_POINTER_LO_ADDR, ZL 151 out AVR_STACK_POINTER_HI_ADDR, ZH 152#else 153# ifdef _HAVE_AVR_STACK_POINTER_HI 154 /* interrupts disabled for shortest possible time (3 cycles) */ 155 cli 156 out AVR_STACK_POINTER_HI_ADDR, ZH 157# endif 158 /* Restore status register (including the interrupt enable flag). 159 Interrupts are re-enabled only after the next instruction. */ 160 out AVR_STATUS_ADDR, __tmp_reg__ 161 out AVR_STACK_POINTER_LO_ADDR, ZL 162#endif 163 ; get return address and jump 164 ld ZL, X+ 165 ld ZH, X+ 166#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 167 ld __tmp_reg__, X+ 168.L_jmp3: 169 push ZL 170 push ZH 171 push __tmp_reg__ 172 ret 173#else 174 ijmp 175#endif 176 .size _U(longjmp), . - _U(longjmp) 177 178#endif /* !__DOXYGEN__ */ 179