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#ifdef __mips16 22/* This file contains 32 bit assembly code. */ 23 .set nomips16 24#endif 25 26#define GPR_LAYOUT \ 27 GPR_OFFSET ($16, 0); \ 28 GPR_OFFSET ($17, 1); \ 29 GPR_OFFSET ($18, 2); \ 30 GPR_OFFSET ($19, 3); \ 31 GPR_OFFSET ($20, 4); \ 32 GPR_OFFSET ($21, 5); \ 33 GPR_OFFSET ($22, 6); \ 34 GPR_OFFSET ($23, 7); \ 35 GPR_OFFSET ($29, 8); \ 36 GPR_OFFSET ($30, 9); \ 37 GPR_OFFSET ($31, 10) 38 39#define NUM_GPRS_SAVED 11 40 41#ifdef __mips_hard_float 42#if _MIPS_SIM == _ABIN32 43#define FPR_LAYOUT \ 44 FPR_OFFSET ($f20, 0); \ 45 FPR_OFFSET ($f22, 1); \ 46 FPR_OFFSET ($f24, 2); \ 47 FPR_OFFSET ($f26, 3); \ 48 FPR_OFFSET ($f28, 4); \ 49 FPR_OFFSET ($f30, 5); 50#elif _MIPS_SIM == _ABI64 51#define FPR_LAYOUT \ 52 FPR_OFFSET ($f24, 0); \ 53 FPR_OFFSET ($f25, 1); \ 54 FPR_OFFSET ($f26, 2); \ 55 FPR_OFFSET ($f27, 3); \ 56 FPR_OFFSET ($f28, 4); \ 57 FPR_OFFSET ($f29, 5); \ 58 FPR_OFFSET ($f30, 6); \ 59 FPR_OFFSET ($f31, 7); 60#elif __mips_fpr == 0 || __mips_fpr == 64 61 62/* This deals with the o32 FPXX and FP64 cases. Here we must use 63 SDC1 and LDC1 to access the FPRs. These instructions require 64 8-byte aligned addresses. 65 Unfortunately, the MIPS jmp_buf only guarantees 4-byte alignment 66 and this cannot be increased without breaking compatibility with 67 pre-existing objects built against newlib. There are 11 GPRS 68 saved in the jmp_buf so a buffer that happens to be 8-byte aligned 69 ends up leaving the FPR slots 4-byte aligned and an (only) 4-byte 70 aligned buffer leads to the FPR slots being 8-byte aligned! 71 72 To resolve this, we move the location of $31 to the last slot 73 in the jmp_buf when the overall buffer is 8-byte aligned. $31 74 is simply loaded/stored twice to avoid adding complexity to the 75 GPR_LAYOUT macro above as well as FPR_LAYOUT. 76 77 The location of the last slot is index 22 which is calculated 78 from there being 11 GPRs saved and then 12 FPRs saved so the 79 index of the last FPR is 11+11. 80 81 The base of the jmp_buf is modified in $4 to allow the 82 FPR_OFFSET macros to just use the usual constant slot numbers 83 regardless of whether the realignment happened or not. */ 84 85#define FPR_LAYOUT \ 86 and $8, $4, 4; \ 87 beq $8, $0, 1f; \ 88 GPR_OFFSET ($31, 22); \ 89 addiu $4, $4, -4; \ 901: \ 91 FPR_OFFSET ($f20, 0); \ 92 FPR_OFFSET ($f22, 2); \ 93 FPR_OFFSET ($f24, 4); \ 94 FPR_OFFSET ($f26, 6); \ 95 FPR_OFFSET ($f28, 8); \ 96 FPR_OFFSET ($f30, 10); 97#else /* Assuming _MIPS_SIM == _ABIO32 */ 98#define FPR_LAYOUT \ 99 FPR_OFFSET ($f20, 0); \ 100 FPR_OFFSET ($f21, 1); \ 101 FPR_OFFSET ($f22, 2); \ 102 FPR_OFFSET ($f23, 3); \ 103 FPR_OFFSET ($f24, 4); \ 104 FPR_OFFSET ($f25, 5); \ 105 FPR_OFFSET ($f26, 6); \ 106 FPR_OFFSET ($f27, 7); \ 107 FPR_OFFSET ($f28, 8); \ 108 FPR_OFFSET ($f29, 9); \ 109 FPR_OFFSET ($f30, 10); \ 110 FPR_OFFSET ($f31, 11); 111#endif 112#else 113#define FPR_LAYOUT 114#endif 115 116#ifdef __mips64 117#define BYTES_PER_WORD 8 118#define LOAD_GPR ld 119#define LOAD_FPR ldc1 120#define STORE_GPR sd 121#define STORE_FPR sdc1 122#else 123#define LOAD_GPR lw 124#define STORE_GPR sw 125#define BYTES_PER_WORD 4 126#if __mips_fpr == 0 || __mips_fpr == 64 127#define LOAD_FPR ldc1 128#define STORE_FPR sdc1 129#else 130#define LOAD_FPR lwc1 131#define STORE_FPR swc1 132#endif 133#endif 134 135#define GPOFF(INDEX) (INDEX * BYTES_PER_WORD) 136#define FPOFF(INDEX) ((INDEX + NUM_GPRS_SAVED) * BYTES_PER_WORD) 137 138/* int setjmp (jmp_buf); */ 139 .globl setjmp 140 .ent setjmp 141setjmp: 142 .frame $sp,0,$31 143 144#define GPR_OFFSET(REG, INDEX) STORE_GPR REG,GPOFF(INDEX)($4) 145#define FPR_OFFSET(REG, INDEX) STORE_FPR REG,FPOFF(INDEX)($4) 146 GPR_LAYOUT 147 FPR_LAYOUT 148#undef GPR_OFFSET 149#undef FPR_OFFSET 150 151 move $2,$0 152 j $31 153 154 .end setjmp 155 156/* volatile void longjmp (jmp_buf, int); */ 157 .globl longjmp 158 .ent longjmp 159longjmp: 160 .frame $sp,0,$31 161 162#define GPR_OFFSET(REG, INDEX) LOAD_GPR REG,GPOFF(INDEX)($4) 163#define FPR_OFFSET(REG, INDEX) LOAD_FPR REG,FPOFF(INDEX)($4) 164 GPR_LAYOUT 165 FPR_LAYOUT 166#undef GPR_OFFSET 167#undef FPR_OFFSET 168 169 bne $5,$0,1f 170 li $5,1 1711: 172 move $2,$5 173 j $31 174 175 .end longjmp 176