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#include <picolibc.h> 57 58#ifndef __DOXYGEN__ 59 60#include <avr/io.h> 61#include "macros.inc" 62 63/* ???: What was a reason to use aliases for common registers? 64 Check the address: is it a port number (value for IN/OUT)? */ 65#if AVR_STACK_POINTER_LO_ADDR != 0x3D \ 66 || AVR_STATUS_ADDR != 0x3F 67# error "Strange address of common registers SPL, SREG" 68#endif 69 70#define jmpb_hi r25 71#define jmpb_lo r24 72#define val_hi r23 73#define val_lo r22 74 75#define ret_lo r24 76#define ret_hi r25 77 78 ASSEMBLY_CLIB_SECTION 79 80 .global _U(setjmp) 81 .type _U(setjmp), @function 82 83_U(setjmp): 84 X_movw XL, jmpb_lo 85 ; save call-saved registers and frame pointer 86#if !defined(__AVR_TINY__) 87 .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 88#else 89 .irp .L_regno, 18,19,28,29 90#endif 91 st X+, r\.L_regno 92 .endr 93 ; get return address 94#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 95 pop __tmp_reg__ ; used below 96#endif 97 pop ZH 98 pop ZL 99 ; save stack pointer (after poping) 100 in ret_lo, AVR_STACK_POINTER_LO_ADDR 101 st X+, ret_lo 102#ifdef _HAVE_AVR_STACK_POINTER_HI 103 in ret_lo, AVR_STACK_POINTER_HI_ADDR 104 st X+, ret_lo 105#else 106 st X+, __zero_reg__ 107#endif 108 ; save status register (I flag) 109 in ret_lo, AVR_STATUS_ADDR 110 st X+, ret_lo 111 ; save return address 112 st X+, ZL 113 st X+, ZH 114 ; return zero 115 clr ret_lo 116 clr ret_hi 117#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 118 st X+, __tmp_reg__ 119 rjmp .L_jmp3 120#else 121 ijmp 122#endif 123 .size _U(setjmp), . - _U(setjmp) 124 125 .global _U(longjmp) 126 .type _U(longjmp), @function 127 128_U(longjmp): 129 X_movw XL, jmpb_lo 130 ; return value 131 X_movw ret_lo, val_lo 132 ; if zero, change to 1 133 cpi ret_lo, 1 134 cpc ret_hi, __zero_reg__ 135 adc ret_lo, __zero_reg__ 136 ; restore call-saved registers and frame pointer 137#if !defined(__AVR_TINY__) 138 .irp .L_regno, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,28,29 139#else 140 .irp .L_regno, 18,19,28,29 141#endif 142 ld r\.L_regno, X+ 143 .endr 144 ; restore stack pointer (SP value before the setjmp() call) and SREG 145 ld ZL, X+ 146 ld ZH, X+ 147 ld __tmp_reg__, X+ 148#if defined (__AVR_XMEGA__) && __AVR_XMEGA__ 149 /* A write to SPL will automatically disable interrupts for up to 4 150 instructions or until the next I/O memory write. */ 151 out AVR_STATUS_ADDR, __tmp_reg__ 152 out AVR_STACK_POINTER_LO_ADDR, ZL 153 out AVR_STACK_POINTER_HI_ADDR, ZH 154#else 155# ifdef _HAVE_AVR_STACK_POINTER_HI 156 /* interrupts disabled for shortest possible time (3 cycles) */ 157 cli 158 out AVR_STACK_POINTER_HI_ADDR, ZH 159# endif 160 /* Restore status register (including the interrupt enable flag). 161 Interrupts are re-enabled only after the next instruction. */ 162 out AVR_STATUS_ADDR, __tmp_reg__ 163 out AVR_STACK_POINTER_LO_ADDR, ZL 164#endif 165 ; get return address and jump 166 ld ZL, X+ 167 ld ZH, X+ 168#if defined(__AVR_3_BYTE_PC__) && __AVR_3_BYTE_PC__ 169 ld __tmp_reg__, X+ 170.L_jmp3: 171 push ZL 172 push ZH 173 push __tmp_reg__ 174 ret 175#else 176 ijmp 177#endif 178 .size _U(longjmp), . - _U(longjmp) 179 180#endif /* !__DOXYGEN__ */ 181