1/* 2Copyright (c) 1990 The Regents of the University of California. 3All rights reserved. 4 5Redistribution and use in source and binary forms are permitted 6provided that the above copyright notice and this paragraph are 7duplicated in all such forms and that any documentation, 8and/or other materials related to such 9distribution and use acknowledge that the software was developed 10by the University of California, Berkeley. The name of the 11University may not be used to endorse or promote products derived 12from this software without specific prior written permission. 13THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17/* This is a simple version of setjmp and longjmp for MIPS 32 and 64. 18 19 Ian Lance Taylor, Cygnus Support, 13 May 1993. */ 20 21#include <picolibc.h> 22 23#ifdef __mips16 24/* This file contains 32 bit assembly code. */ 25 .set nomips16 26#endif 27 28#define GPR_LAYOUT \ 29 GPR_OFFSET ($16, 0); \ 30 GPR_OFFSET ($17, 1); \ 31 GPR_OFFSET ($18, 2); \ 32 GPR_OFFSET ($19, 3); \ 33 GPR_OFFSET ($20, 4); \ 34 GPR_OFFSET ($21, 5); \ 35 GPR_OFFSET ($22, 6); \ 36 GPR_OFFSET ($23, 7); \ 37 GPR_OFFSET ($29, 8); \ 38 GPR_OFFSET ($30, 9); \ 39 GPR_OFFSET ($31, 10) 40 41#define NUM_GPRS_SAVED 11 42 43#ifdef __mips_hard_float 44#if _MIPS_SIM == _ABIN32 45#define FPR_LAYOUT \ 46 FPR_OFFSET ($f20, 0); \ 47 FPR_OFFSET ($f22, 1); \ 48 FPR_OFFSET ($f24, 2); \ 49 FPR_OFFSET ($f26, 3); \ 50 FPR_OFFSET ($f28, 4); \ 51 FPR_OFFSET ($f30, 5); 52#elif _MIPS_SIM == _ABI64 53#define FPR_LAYOUT \ 54 FPR_OFFSET ($f24, 0); \ 55 FPR_OFFSET ($f25, 1); \ 56 FPR_OFFSET ($f26, 2); \ 57 FPR_OFFSET ($f27, 3); \ 58 FPR_OFFSET ($f28, 4); \ 59 FPR_OFFSET ($f29, 5); \ 60 FPR_OFFSET ($f30, 6); \ 61 FPR_OFFSET ($f31, 7); 62#elif __mips_fpr == 0 || __mips_fpr == 64 63 64/* This deals with the o32 FPXX and FP64 cases. Here we must use 65 SDC1 and LDC1 to access the FPRs. These instructions require 66 8-byte aligned addresses. 67 Unfortunately, the MIPS jmp_buf only guarantees 4-byte alignment 68 and this cannot be increased without breaking compatibility with 69 pre-existing objects built against newlib. There are 11 GPRS 70 saved in the jmp_buf so a buffer that happens to be 8-byte aligned 71 ends up leaving the FPR slots 4-byte aligned and an (only) 4-byte 72 aligned buffer leads to the FPR slots being 8-byte aligned! 73 74 To resolve this, we move the location of $31 to the last slot 75 in the jmp_buf when the overall buffer is 8-byte aligned. $31 76 is simply loaded/stored twice to avoid adding complexity to the 77 GPR_LAYOUT macro above as well as FPR_LAYOUT. 78 79 The location of the last slot is index 22 which is calculated 80 from there being 11 GPRs saved and then 12 FPRs saved so the 81 index of the last FPR is 11+11. 82 83 The base of the jmp_buf is modified in $4 to allow the 84 FPR_OFFSET macros to just use the usual constant slot numbers 85 regardless of whether the realignment happened or not. */ 86 87#define FPR_LAYOUT \ 88 and $8, $4, 4; \ 89 beq $8, $0, 1f; \ 90 GPR_OFFSET ($31, 22); \ 91 addiu $4, $4, -4; \ 921: \ 93 FPR_OFFSET ($f20, 0); \ 94 FPR_OFFSET ($f22, 2); \ 95 FPR_OFFSET ($f24, 4); \ 96 FPR_OFFSET ($f26, 6); \ 97 FPR_OFFSET ($f28, 8); \ 98 FPR_OFFSET ($f30, 10); 99#else /* Assuming _MIPS_SIM == _ABIO32 */ 100#define FPR_LAYOUT \ 101 FPR_OFFSET ($f20, 0); \ 102 FPR_OFFSET ($f21, 1); \ 103 FPR_OFFSET ($f22, 2); \ 104 FPR_OFFSET ($f23, 3); \ 105 FPR_OFFSET ($f24, 4); \ 106 FPR_OFFSET ($f25, 5); \ 107 FPR_OFFSET ($f26, 6); \ 108 FPR_OFFSET ($f27, 7); \ 109 FPR_OFFSET ($f28, 8); \ 110 FPR_OFFSET ($f29, 9); \ 111 FPR_OFFSET ($f30, 10); \ 112 FPR_OFFSET ($f31, 11); 113#endif 114#else 115#define FPR_LAYOUT 116#endif 117 118#ifdef __mips64 119#define BYTES_PER_WORD 8 120#define LOAD_GPR ld 121#define LOAD_FPR ldc1 122#define STORE_GPR sd 123#define STORE_FPR sdc1 124#else 125#define LOAD_GPR lw 126#define STORE_GPR sw 127#define BYTES_PER_WORD 4 128#if __mips_fpr == 0 || __mips_fpr == 64 129#define LOAD_FPR ldc1 130#define STORE_FPR sdc1 131#else 132#define LOAD_FPR lwc1 133#define STORE_FPR swc1 134#endif 135#endif 136 137#define GPOFF(INDEX) (INDEX * BYTES_PER_WORD) 138#define FPOFF(INDEX) ((INDEX + NUM_GPRS_SAVED) * BYTES_PER_WORD) 139 140/* int setjmp (jmp_buf); */ 141 .globl setjmp 142 .ent setjmp 143setjmp: 144 .frame $sp,0,$31 145 146#define GPR_OFFSET(REG, INDEX) STORE_GPR REG,GPOFF(INDEX)($4) 147#define FPR_OFFSET(REG, INDEX) STORE_FPR REG,FPOFF(INDEX)($4) 148 GPR_LAYOUT 149 FPR_LAYOUT 150#undef GPR_OFFSET 151#undef FPR_OFFSET 152 153 move $2,$0 154 j $31 155 156 .end setjmp 157 158/* volatile void longjmp (jmp_buf, int); */ 159 .globl longjmp 160 .ent longjmp 161longjmp: 162 .frame $sp,0,$31 163 164#define GPR_OFFSET(REG, INDEX) LOAD_GPR REG,GPOFF(INDEX)($4) 165#define FPR_OFFSET(REG, INDEX) LOAD_FPR REG,FPOFF(INDEX)($4) 166 GPR_LAYOUT 167 FPR_LAYOUT 168#undef GPR_OFFSET 169#undef FPR_OFFSET 170 171 bne $5,$0,1f 172 li $5,1 1731: 174 move $2,$5 175 j $31 176 177 .end longjmp 178