This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit b4d29329f6e5be30b78b45bd5044eec40bc06f2f Author: zhangyu117 <[email protected]> AuthorDate: Wed Jul 15 10:04:08 2026 +0800 libc/tricore: rewrite setjmp with asm format. Replace the inline assembly in arch_setjmp.c with standalone assembly sources: gnu/arch_setjmp.S for GCC and tasking/arch_setjmp.asm for TASKING. The PSW/PRS/IO repair in longjmp is kept. Signed-off-by: zhangyu117 <[email protected]> --- libs/libc/machine/tricore/CMakeLists.txt | 8 +- libs/libc/machine/tricore/Make.defs | 8 +- libs/libc/machine/tricore/arch_setjmp.c | 215 ---------------------- libs/libc/machine/tricore/gnu/arch_setjmp.S | 169 +++++++++++++++++ libs/libc/machine/tricore/tasking/arch_setjmp.asm | 178 ++++++++++++++++++ 5 files changed, 355 insertions(+), 223 deletions(-) diff --git a/libs/libc/machine/tricore/CMakeLists.txt b/libs/libc/machine/tricore/CMakeLists.txt index 47ceadc4905..5ccba6d5d20 100644 --- a/libs/libc/machine/tricore/CMakeLists.txt +++ b/libs/libc/machine/tricore/CMakeLists.txt @@ -26,10 +26,6 @@ if(CONFIG_LIBC_ATOMIC_ARCH) list(APPEND SRCS arch_atomic.c) endif() -if(CONFIG_ARCH_SETJMP_H) - list(APPEND SRCS arch_setjmp.c) -endif() - if(CONFIG_TRICORE_TOOLCHAIN_TASKING) set(TRICORE_SUBDIR tasking) set(ASM_EXT asm) @@ -38,6 +34,10 @@ else() set(ASM_EXT S) endif() +if(CONFIG_ARCH_SETJMP_H) + list(APPEND SRCS ${TRICORE_SUBDIR}/arch_setjmp.${ASM_EXT}) +endif() + if(CONFIG_LIBC_ARCH_MEMCPY) list(APPEND SRCS ${TRICORE_SUBDIR}/arch_memcpy.${ASM_EXT}) endif() diff --git a/libs/libc/machine/tricore/Make.defs b/libs/libc/machine/tricore/Make.defs index c56d689fb23..ad3c778a9a5 100644 --- a/libs/libc/machine/tricore/Make.defs +++ b/libs/libc/machine/tricore/Make.defs @@ -24,10 +24,6 @@ ifeq ($(CONFIG_LIBC_ATOMIC_ARCH),y) CSRCS += arch_atomic.c endif -ifeq ($(CONFIG_ARCH_SETJMP_H),y) -CSRCS += arch_setjmp.c -endif - ifeq ($(CONFIG_TRICORE_TOOLCHAIN_TASKING),y) TRICORE_SUBDIR = tasking else @@ -42,6 +38,10 @@ AFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)machine$(DELI AFLAGS += -Wa,-mtc18 +ifeq ($(CONFIG_ARCH_SETJMP_H),y) +ASRCS += arch_setjmp.S +endif + ifeq ($(CONFIG_LIBC_ARCH_MEMCPY),y) ASRCS += arch_memcpy.S endif diff --git a/libs/libc/machine/tricore/arch_setjmp.c b/libs/libc/machine/tricore/arch_setjmp.c deleted file mode 100644 index 41072d240f0..00000000000 --- a/libs/libc/machine/tricore/arch_setjmp.c +++ /dev/null @@ -1,215 +0,0 @@ -/**************************************************************************** - * libs/libc/machine/tricore/arch_setjmp.c - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <nuttx/compiler.h> -#include <arch/setjmp.h> - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -int setjmp(jmp_buf env) -{ - __asm__ __volatile__ ( -#ifdef CONFIG_TRICORE_TOOLCHAIN_TASKING - "st.a [a4]12, a11\n\t" - "movh.a a11, #@HIS(.Lsaveregs)\n\t" - "lea a11, [a11]@LOS(.Lsaveregs)\n\t" - "ret\n\t" - ".Lsaveregs:\n\t" - "st.a [a4]8, sp\n\t" - "st.a [a4]32, a12\n\t" - "st.a [a4]36, a13\n\t" - "st.a [a4]40, a14\n\t" - "st.a [a4]44, a15\n\t" - "st.w [a4]16, d8\n\t" - "st.w [a4]20, d9\n\t" - "st.w [a4]24, d10\n\t" - "st.w [a4]28, d11\n\t" - "st.w [a4]48, d12\n\t" - "st.w [a4]52, d13\n\t" - "st.w [a4]56, d14\n\t" - "st.w [a4]60, d15\n\t" - "mfcr d2, #0xfe00\n\t" - "st.w [a4]0, d2\n\t" - "mfcr d2, #0xfe04\n\t" - "st.w [a4]4, d2\n\t" - "ld.a a2, [a4]12\n\t" - "mov d2, #0\n\t" - "ji a2\n\t" -#else - "st.a [%%a4]12, %%a11\n\t" - "movh.a %%a11, hi:.Lsaveregs\n\t" - "lea %%a11, [%%a11] lo:.Lsaveregs\n\t" - "ret\n\t" - ".Lsaveregs:\n\t" - "st.a [%%a4]8, %%sp\n\t" - "st.a [%%a4]32, %%a12\n\t" - "st.a [%%a4]36, %%a13\n\t" - "st.a [%%a4]40, %%a14\n\t" - "st.a [%%a4]44, %%a15\n\t" - "st.w [%%a4]16, %%d8\n\t" - "st.w [%%a4]20, %%d9\n\t" - "st.w [%%a4]24, %%d10\n\t" - "st.w [%%a4]28, %%d11\n\t" - "st.w [%%a4]48, %%d12\n\t" - "st.w [%%a4]52, %%d13\n\t" - "st.w [%%a4]56, %%d14\n\t" - "st.w [%%a4]60, %%d15\n\t" - "mfcr %%d2, 0xfe00\n\t" - "st.w [%%a4]0, %%d2\n\t" - "mfcr %%d2, 0xfe04\n\t" - "st.w [%%a4]4, %%d2\n\t" - "ld.a %%a2, [%%a4]12\n\t" - "mov %%d2, 0\n\t" - "ji %%a2\n\t" -#endif - ::: "memory" - ); - return 0; -} - -/* The CSA unwind loop below uses `ret` in .Lupper to release one Upper - * Context per iteration. The hardware side-effect of `ret` is that the - * popped UC's PSW becomes the active PSW, which may put the CPU into - * user mode / wrong PRS even though longjmp itself runs in supervisor - * mode. The next access to env (a4) would then fault on the MPU, since - * jmp_buf may live in kernel-protected memory. - * - * To keep the unwind loop running in a known-safe context, the head of - * .Lloop forces PSW.IO=Supervisor and PSW.PRS=0 on every iteration. - * Once the loop terminates, the original PSW saved at setjmp time - * (env->psw) is restored before the indirect jump back to the setjmp - * call site. - * - * PSW layout on TC1.6.2 / TC1.8: - * bit 15 = PRS[2] - * bit 14 = S (alternate master tag selector, must preserve) - * bit 13:12 = PRS[1:0] - * bit 11:10 = IO (0b10 = Supervisor) - */ - -void longjmp(jmp_buf env, int val) -{ - __asm__ __volatile__ ( -#ifdef CONFIG_TRICORE_TOOLCHAIN_TASKING - "ld.w d5, [a4]0\n\t" - ".Lloop:\n\t" - "mfcr d3, #0xfe04\n\t" - "mov d2, #2\n\t" - "insert d3, d3, d2, #10, #4\n\t" - "mov d2, #0\n\t" - "insert d3, d3, d2, #15, #1\n\t" - "mtcr #0xfe04, d3\n\t" - "isync\n\t" - "mfcr d2, #0xfe00\n\t" - "jne d2, d5, .Lrelease\n\t" - "max.u d2, d4, #1\n\t" - "ld.a a2, [a4]12\n\t" - "ld.a sp, [a4]8\n\t" - "ld.a a12, [a4]32\n\t" - "ld.a a13, [a4]36\n\t" - "ld.a a14, [a4]40\n\t" - "ld.a a15, [a4]44\n\t" - "ld.w d8, [a4]16\n\t" - "ld.w d9, [a4]20\n\t" - "ld.w d10, [a4]24\n\t" - "ld.w d11, [a4]28\n\t" - "ld.w d12, [a4]48\n\t" - "ld.w d13, [a4]52\n\t" - "ld.w d14, [a4]56\n\t" - "ld.w d15, [a4]60\n\t" - "ld.w d3, [a4]4\n\t" - "mtcr #0xfe04, d3\n\t" - "isync\n\t" - "ji a2\n\t" - ".Lrelease:\n\t" - "jnz.t d2, #20, .Lupper\n\t" - "mov.aa a15, a4\n\t" - "mov d15, d4\n\t" - "mov d14, d5\n\t" - "rslcx\n\t" - "mov d4, d15\n\t" - "mov d5, d14\n\t" - "mov.aa a4, a15\n\t" - "j .Lloop\n\t" - ".Lupper:\n\t" - "movh.a a11, #@HIS(.Lloop)\n\t" - "lea a11, [a11]@LOS(.Lloop)\n\t" - "ret\n\t" -#else - "ld.w %%d5, [%%a4]0\n\t" - ".Lloop:\n\t" - "mfcr %%d3, 0xfe04\n\t" - "mov %%d2, 2\n\t" - "insert %%d3, %%d3, %%d2, 10, 4\n\t" - "mov %%d2, 0\n\t" - "insert %%d3, %%d3, %%d2, 15, 1\n\t" - "mtcr 0xfe04, %%d3\n\t" - "isync\n\t" - "mfcr %%d2, 0xfe00\n\t" - "jne %%d2, %%d5, .Lrelease\n\t" - "max.u %%d2, %%d4, 1\n\t" - "ld.a %%a2, [%%a4]12\n\t" - "ld.a %%sp, [%%a4]8\n\t" - "ld.a %%a12, [%%a4]32\n\t" - "ld.a %%a13, [%%a4]36\n\t" - "ld.a %%a14, [%%a4]40\n\t" - "ld.a %%a15, [%%a4]44\n\t" - "ld.w %%d8, [%%a4]16\n\t" - "ld.w %%d9, [%%a4]20\n\t" - "ld.w %%d10, [%%a4]24\n\t" - "ld.w %%d11, [%%a4]28\n\t" - "ld.w %%d12, [%%a4]48\n\t" - "ld.w %%d13, [%%a4]52\n\t" - "ld.w %%d14, [%%a4]56\n\t" - "ld.w %%d15, [%%a4]60\n\t" - "ld.w %%d3, [%%a4]4\n\t" - "mtcr 0xfe04, %%d3\n\t" - "isync\n\t" - "ji %%a2\n\t" - ".Lrelease:\n\t" - "jnz.t %%d2, 20, .Lupper\n\t" - "mov.aa %%a15, %%a4\n\t" - "mov %%d15, %%d4\n\t" - "mov %%d14, %%d5\n\t" - "rslcx\n\t" - "mov %%d4, %%d15\n\t" - "mov %%d5, %%d14\n\t" - "mov.aa %%a4, %%a15\n\t" - "j .Lloop\n\t" - ".Lupper:\n\t" - "movh.a %%a11, hi:.Lloop\n\t" - "lea %%a11, [%%a11] lo:.Lloop\n\t" - "ret\n\t" -#endif - ::: "memory" - ); - - __builtin_unreachable(); -} diff --git a/libs/libc/machine/tricore/gnu/arch_setjmp.S b/libs/libc/machine/tricore/gnu/arch_setjmp.S new file mode 100644 index 00000000000..54baa354f79 --- /dev/null +++ b/libs/libc/machine/tricore/gnu/arch_setjmp.S @@ -0,0 +1,169 @@ +/**************************************************************************** + * libs/libc/machine/tricore/gnu/arch_setjmp.S + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Name: setjmp + * + * Description: + * int setjmp(jmp_buf env) + * + * TriCore EABI: + * env -> %a4 return value -> %d2 + * + * jmp_buf layout (struct setjmp_buf_s, see arch/tricore/include/setjmp.h): + * 0: pcxi 4: psw 8: sp 12: a11 + * 16: d8 20: d9 24: d10 28: d11 + * 32: a12 36: a13 40: a14 44: a15 + * 48: d12 52: d13 56: d14 60: d15 + * + * On entry %a11 holds the caller's return address (TriCore call ABI). + * Save it into env[12] first, then repoint %a11 at .Lsaveregs and execute + * `ret' which jumps through %a11. The fall-through at .Lsaveregs stores + * the remaining callee-saved registers and the PCXI/PSW control registers, + * loads the saved return address into %a2, sets %d2 = 0, and jumps back + * to the caller. longjmp() returns through the same path with a nonzero + * %d2. + * + ****************************************************************************/ + + .text + .global setjmp + .type setjmp, %function + +setjmp: + st.a [%a4]12, %a11 /* save return address */ + movh.a %a11, hi:.Lsaveregs + lea %a11, [%a11] lo:.Lsaveregs + ret /* jump to .Lsaveregs via %a11 */ +.Lsaveregs: + st.a [%a4]8, %sp + st.a [%a4]32, %a12 + st.a [%a4]36, %a13 + st.a [%a4]40, %a14 + st.a [%a4]44, %a15 + st.w [%a4]16, %d8 + st.w [%a4]20, %d9 + st.w [%a4]24, %d10 + st.w [%a4]28, %d11 + st.w [%a4]48, %d12 + st.w [%a4]52, %d13 + st.w [%a4]56, %d14 + st.w [%a4]60, %d15 + mfcr %d2, 0xfe00 + st.w [%a4]0, %d2 /* save PCXI */ + mfcr %d2, 0xfe04 + st.w [%a4]4, %d2 /* save PSW */ + ld.a %a2, [%a4]12 /* %a2 = return address */ + mov %d2, 0 /* setjmp returns 0 */ + ji %a2 /* back to caller */ + .size setjmp, . - setjmp + +/**************************************************************************** + * Name: longjmp + * + * Description: + * void longjmp(jmp_buf env, int val) noreturn + * + * TriCore EABI: + * env -> %a4 val -> %d4 + * + * Unwind the CSA chain (releasing lower/upper contexts one at a time) + * until the active PCXI matches the one saved by setjmp. At that point + * the register banks are at the same depth as at setjmp time, so + * restoring the callee-saved registers, PSW and return address proceeds. + * The result passed back equals max(val, 1) per POSIX. + * The unwind loop forces PSW.IO = Supervisor and PSW.PRS[2] = 0 on every + * iteration so that the `ret'-released upper contexts do not drop the CPU + * into user mode while env is still being accessed. Once the loop exits, + * the original PSW saved at setjmp time is restored before the indirect + * jump back to the setjmp call site. + * + * PSW layout (TC1.6.2 / TC1.8): + * bit 15 = PRS[2] + * bit 14 = S (alternate master tag selector, preserve) + * bit 13:12 = PRS[1:0] + * bit 11:10 = IO (0b10 = Supervisor) + * + ****************************************************************************/ + + .global longjmp + .type longjmp, %function + +longjmp: + ld.w %d5, [%a4]0 /* %d5 = saved PCXI */ +.Lloop: + mfcr %d3, 0xfe04 /* %d3 = current PSW */ + mov %d2, 2 + insert %d3, %d3, %d2, 10, 4 /* PSW.IO = 2 (supervisor) */ + mov %d2, 0 + insert %d3, %d3, %d2, 15, 1 /* clear PSW.PRS[2] */ + mtcr 0xfe04, %d3 + isync + mfcr %d2, 0xfe00 /* %d2 = current PCXI */ + jne %d2, %d5, .Lrelease /* depth mismatch -> unwind one */ + + /* Matching depth: restore registers and return. */ + + max.u %d2, %d4, 1 /* %d2 = max(val, 1) */ + ld.a %a2, [%a4]12 /* %a2 = saved return address */ + ld.a %sp, [%a4]8 + ld.a %a12, [%a4]32 + ld.a %a13, [%a4]36 + ld.a %a14, [%a4]40 + ld.a %a15, [%a4]44 + ld.w %d8, [%a4]16 + ld.w %d9, [%a4]20 + ld.w %d10, [%a4]24 + ld.w %d11, [%a4]28 + ld.w %d12, [%a4]48 + ld.w %d13, [%a4]52 + ld.w %d14, [%a4]56 + ld.w %d15, [%a4]60 + ld.w %d3, [%a4]4 /* saved PSW */ + mtcr 0xfe04, %d3 + isync + ji %a2 /* return to setjmp call site */ + +.Lrelease: + jnz.t %d2, 20, .Lupper /* PCXI.UL = 1 -> release upper */ + + /* Release one lower context, preserving env/val across rslcx. */ + + mov.aa %a15, %a4 + mov %d15, %d4 + mov %d14, %d5 + rslcx + mov %d4, %d15 + mov %d5, %d14 + mov.aa %a4, %a15 + j .Lloop + +.Lupper: + /* Release one upper context via `ret' (restores the upper context + * from CSA and jumps through %a11). Point %a11 back at .Lloop so + * we re-enter the depth check after the release. + */ + + movh.a %a11, hi:.Lloop + lea %a11, [%a11] lo:.Lloop + ret + .size longjmp, . - longjmp diff --git a/libs/libc/machine/tricore/tasking/arch_setjmp.asm b/libs/libc/machine/tricore/tasking/arch_setjmp.asm new file mode 100644 index 00000000000..e6bc178bd2f --- /dev/null +++ b/libs/libc/machine/tricore/tasking/arch_setjmp.asm @@ -0,0 +1,178 @@ +;**************************************************************************** +; libs/libc/machine/tricore/tasking/arch_setjmp.asm +; +; SPDX-License-Identifier: Apache-2.0 +; +; Licensed to the Apache Software Foundation (ASF) under one or more +; contributor license agreements. See the NOTICE file distributed with +; this work for additional information regarding copyright ownership. The +; ASF licenses this file to you under the Apache License, Version 2.0 (the +; "License"); you may not use this file except in compliance with the +; License. You may obtain a copy of the License at +; +; http://www.apache.org/licenses/LICENSE-2.0 +; +; Unless required by applicable law or agreed to in writing, software +; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +; License for the specific language governing permissions and limitations +; under the License. +; +;**************************************************************************** +; +; Tasking (astc) port of the GNU arch_setjmp.S. Same instruction sequence; +; only the assembler syntax differs. Machine code matches the GNU version. +; +;**************************************************************************** +; Name: setjmp +; +; Description: +; int setjmp(jmp_buf env) +; +; TriCore EABI: +; env -> a4 return value -> d2 +; +; jmp_buf layout (struct setjmp_buf_s, arch/tricore/include/setjmp.h): +; 0: pcxi 4: psw 8: sp 12: a11 +; 16: d8 20: d9 24: d10 28: d11 +; 32: a12 36: a13 40: a14 44: a15 +; 48: d12 52: d13 56: d14 60: d15 +; +; On entry a11 holds the caller's return address (TriCore call ABI). +; Save it into env[12] first, then repoint a11 at .Lsaveregs and execute +; `ret' which jumps through a11. The fall-through at .Lsaveregs stores +; the remaining callee-saved registers and the PCXI/PSW control registers, +; loads the saved return address into a2, sets d2 = 0, and jumps back +; to the caller. longjmp() returns through the same path with a nonzero +; d2. +; +;**************************************************************************** + + .sdecl '.text.setjmp',code + .sect '.text.setjmp' + .global setjmp + +setjmp: .type func + st.a [a4]12, a11 ; save return address + movh.a a11, #@HIS(.Lsaveregs) + lea a11, [a11]@LOS(.Lsaveregs) + ret ; jump to .Lsaveregs via a11 +.Lsaveregs: + st.a [a4]8, sp + st.a [a4]32, a12 + st.a [a4]36, a13 + st.a [a4]40, a14 + st.a [a4]44, a15 + st.w [a4]16, d8 + st.w [a4]20, d9 + st.w [a4]24, d10 + st.w [a4]28, d11 + st.w [a4]48, d12 + st.w [a4]52, d13 + st.w [a4]56, d14 + st.w [a4]60, d15 + mfcr d2, #0xfe00 + st.w [a4]0, d2 ; save PCXI + mfcr d2, #0xfe04 + st.w [a4]4, d2 ; save PSW + ld.a a2, [a4]12 ; a2 = return address + mov d2, #0 ; setjmp returns 0 + ji a2 ; back to caller +.Lsetjmp_end: + + .size setjmp, .Lsetjmp_end-setjmp + +;**************************************************************************** +; Name: longjmp +; +; Description: +; void longjmp(jmp_buf env, int val) noreturn +; +; TriCore EABI: +; env -> a4 val -> d4 +; +; Unwind the CSA chain (releasing lower/upper contexts one at a time) +; until the active PCXI matches the one saved by setjmp. At that point +; the register banks are at the same depth as at setjmp time, so +; restoring the callee-saved registers, PSW and return address proceeds. +; The result passed back equals max(val, 1) per POSIX. +; +; The unwind loop forces PSW.IO = Supervisor and PSW.PRS[2] = 0 on every +; iteration so that the `ret'-released upper contexts do not drop the CPU +; into user mode while env is still being accessed. Once the loop exits, +; the original PSW saved at setjmp time is restored before the indirect +; jump back to the setjmp call site. +; +; PSW layout (TC1.6.2 / TC1.8): +; bit 15 = PRS[2] +; bit 14 = S (alternate master tag selector, preserve) +; bit 13:12 = PRS[1:0] +; bit 11:10 = IO (0b10 = Supervisor) +; +;**************************************************************************** + + .sdecl '.text.longjmp',code + .sect '.text.longjmp' + .global longjmp + +longjmp: .type func + ld.w d5, [a4]0 ; d5 = saved PCXI +.Lloop: + mfcr d3, #0xfe04 ; d3 = current PSW + mov d2, #2 + insert d3, d3, d2, #10, #4 ; PSW.IO = 2 (supervisor) + mov d2, #0 + insert d3, d3, d2, #15, #1 ; clear PSW.PRS[2] + mtcr #0xfe04, d3 + isync + mfcr d2, #0xfe00 ; d2 = current PCXI + jne d2, d5, .Lrelease ; depth mismatch -> unwind one + + ; Matching depth: restore registers and return. + + max.u d2, d4, #1 ; d2 = max(val, 1) + ld.a a2, [a4]12 ; a2 = saved return address + ld.a sp, [a4]8 + ld.a a12, [a4]32 + ld.a a13, [a4]36 + ld.a a14, [a4]40 + ld.a a15, [a4]44 + ld.w d8, [a4]16 + ld.w d9, [a4]20 + ld.w d10, [a4]24 + ld.w d11, [a4]28 + ld.w d12, [a4]48 + ld.w d13, [a4]52 + ld.w d14, [a4]56 + ld.w d15, [a4]60 + ld.w d3, [a4]4 ; saved PSW + mtcr #0xfe04, d3 + isync + ji a2 ; return to setjmp call site + +.Lrelease: + jnz.t d2, #20, .Lupper ; PCXI.UL = 1 -> release upper + + ; Release one lower context, preserving env/val across rslcx. + + mov.aa a15, a4 + mov d15, d4 + mov d14, d5 + rslcx + mov d4, d15 + mov d5, d14 + mov.aa a4, a15 + j .Lloop + +.Lupper: + ; Release one upper context via `ret' (restores the upper context + ; from CSA and jumps through a11). Point a11 back at .Lloop so + ; we re-enter the depth check after the release. + + movh.a a11, #@HIS(.Lloop) + lea a11, [a11]@LOS(.Lloop) + ret +.Llongjmp_end: + + .size longjmp, .Llongjmp_end-longjmp + .end
