/*
 * Copyright (c) 1995, 1996, 1998 Cygnus Support
 *
 * The authors hereby grant permission to use, copy, modify, distribute,
 * and license this software and its documentation for any purpose, provided
 * that existing copyright notices are retained in all copies and that this
 * notice is included verbatim in any distributions. No written agreement,
 * license, or royalty fee is required for any of the authorized uses.
 * Modifications to this software may be copyrighted by their authors
 * and need not follow the licensing terms described here, provided that
 * the new terms are clearly indicated on the first page of each file where
 * they apply.
 */

#include "asm.h"
#include "slite.h"

	.text
	.align 4

/* 
 *  The trap table has to be the first code in a boot PROM.  But because
 *  the Memory Configuration comes up thinking we only have 4K of PROM, we
 *  cannot have a full trap table and still have room left over to 
 *  reprogram the Memory Configuration register correctly.  This file
 *  uses an abbreviated trap which has every entry which might be used
 *  before RTEMS installs its own trap table.
 */
	.globl	_trap_table
_trap_table:
  TRAP(SYM(ercinit));				! 00 reset trap 
  BAD_TRAP;                                     ! 01 instruction access exception
  TRAP(SYM(no_fpu));				! 02 illegal instruction
  BAD_TRAP;                                     ! 03 privileged instruction
  BAD_TRAP;                                     ! 04 fp disabled
  TRAP(SYM(win_overflow));			! 05 window overflow
  TRAP(SYM(win_underflow));			! 06 window underflow
  BAD_TRAP;                                     ! 07 memory address not aligned
  BAD_TRAP;                                     ! 08 fp exception
  BAD_TRAP;                                     ! 09 data access exception
  BAD_TRAP;					! 0A tag overflow

  /* Trap levels from 0B to 0x10 are not defined (used for MEC init) */

SYM(ercinit):
  sethi         %hi(_ERC32_MEC), %g1		! 0B
  sethi         %hi(0x001C1000), %g2
  or            %g1,%lo(0x001C1000),%g1
  st            %g2, [%g1 + 0x10]
  st            %g0, [%g1 + 0x18]			! 0C
  nop
  nop
  nop

  TRAP(SYM(hard_reset));			! 0D undefined
  BAD_TRAP;                                     ! 0E undefined
  BAD_TRAP;                                     ! 0F undefined
  BAD_TRAP;                                     ! 10 undefined

  /* 
   *  ERC32 defined traps
   */

  BAD_TRAP;                                     ! 11 masked errors
  BAD_TRAP;                                     ! 12 external 1
  BAD_TRAP;                                     ! 13 external 2
  BAD_TRAP;                                     ! 14 UART A RX/TX
  BAD_TRAP;                                     ! 15 UART B RX/TX
  BAD_TRAP;                                     ! 16 correctable memory error
  BAD_TRAP;                                     ! 17 UART error
  BAD_TRAP;                                     ! 18 DMA access error
  BAD_TRAP;                                     ! 19 DMA timeout
  BAD_TRAP;                                     ! 1A external 3
  BAD_TRAP;                                     ! 1B external 4
  BAD_TRAP;                                     ! 1C general purpose timer
  BAD_TRAP;                                     ! 1D real time clock
  BAD_TRAP;                                     ! 1E external 5
  BAD_TRAP;                                     ! 1F watchdog timeout


  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 20 - 23 undefined
  BAD_TRAP;                                     ! 24 cp_disabled
            BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 25 - 27 undefined
  BAD_TRAP;                                     ! 28 cp_exception
            BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 29 - 2B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 2C - 2F undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 30 - 33 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 34 - 37 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 38 - 3B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 3C - 3F undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 40 - 43 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 44 - 47 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 48 - 4B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 4C - 4F undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 50 - 53 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 54 - 57 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 58 - 5B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 5C - 5F undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 60 - 63 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 64 - 67 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 68 - 6B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 6C - 6F undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 70 - 73 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 74 - 77 undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 78 - 7B undefined
  BAD_TRAP; BAD_TRAP; BAD_TRAP; BAD_TRAP;       ! 7C - 7F undefined

  /* 
   *  Software traps
   *
   *  NOTE: At the risk of being redundant... this is not a full
   *        table.  The setjmp on the SPARC requires a window flush trap
   *        handler and RTEMS will preserve the entries that were
   *        installed before.
   */

  SOFT_TRAP;					! 80
#if 0
  SOFT_TRAP;					! 81
#else
  TRAP(SYM(trap_low))				! 81
#endif
  SOFT_TRAP;					! 82
  TRAP(SYM(win_flush));				! 83 flush windows SW trap
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 84 - 87
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 88 - 8B
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 8C - 8F
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 90 - 93
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 94 - 97
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 98 - 9B
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! 9C - 9F
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! A0 - A3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! A4 - A7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! A8 - AB
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! AC - AF
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! B0 - B3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! B4 - B7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! B8 - BB
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! BC - BF
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! C0 - C3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! C4 - C7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! C8 - CB
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! CC - CF
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! D0 - D3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! D4 - D7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! D8 - DB
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! DC - DF
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! E0 - E3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! E4 - E7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! E8 - EB
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! EC - EF
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! F0 - F3
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! F4 - F7
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! F8 - FB 
  SOFT_TRAP; SOFT_TRAP; SOFT_TRAP; SOFT_TRAP;   ! FC - FF

/*
 * Startup code for standalone system. Wash IU and FPU (if present)
 * registers. The registers have to be written to initiate the parity
 * bits.
 */
	.globl	SYM(hard_reset)
SYM(hard_reset):

        sethi	%hi(0x01FE0),%o0
        or	%o0,%lo(0x01FE0),%o0
        mov     %o0, %psr		! Set valid PSR
        nop

        mov     %g0, %wim		! Set window invalid mask register
        mov     %g0, %y			! Init Y-register
        nop
        sethi   %hi(SYM(hard_reset)), %g1

        mov     %g1, %tbr		! Set TBR
        sethi	%hi(SP_INIT),%sp
        or      %g0, 1, %o0
        ld      [%g0], %f0		! Check if FPU is present

        tst     %o0
        bz      fixiu
        nop
        ba      fixfpu

! FPU disabled trap address

        clr     %i0
        jmpl    %l2, %g0
        rett    %l2 + 4
        nop
        

! Wash register files (fix for 90C601E & 90C602E)

fixfpu:

        ld      [%g0], %f0
        ld      [%g0], %f1
        ld      [%g0], %f2
        ld      [%g0], %f3
        ld      [%g0], %f4
        ld      [%g0], %f5
        ld      [%g0], %f6
        ld      [%g0], %f7
        ld      [%g0], %f8
        ld      [%g0], %f9
        ld      [%g0], %f10
        ld      [%g0], %f11
        ld      [%g0], %f12
        ld      [%g0], %f13
        ld      [%g0], %f14
        ld      [%g0], %f15
        ld      [%g0], %f16
        ld      [%g0], %f17
        ld      [%g0], %f18
        ld      [%g0], %f19
        ld      [%g0], %f20
        ld      [%g0], %f21
        ld      [%g0], %f22
        ld      [%g0], %f23
        ld      [%g0], %f24
        ld      [%g0], %f25
        ld      [%g0], %f26
        ld      [%g0], %f27
        ld      [%g0], %f28
        ld      [%g0], %f29
        ld      [%g0], %f30
        ld      [%g0], %f31

fixiu:
        clr     %g1
        clr     %g2
        clr     %g3
        clr     %g4
        clr     %g5
        clr     %g6
        clr     %g7
        set     8,%g1
wl0:
        clr     %i0
        clr     %i1
        clr     %i2
        clr     %i3
        clr     %i4
        clr     %i5
        clr     %i6
        clr     %i7
        clr     %l0
        clr     %l1
        clr     %l2
        clr     %l3
        clr     %l4
        clr     %l5
        clr     %l6
        clr     %l7
        save
        subcc   %g1, 1, %g1
        bne     wl0
        nop

!
! Start the real-time clock with a tick of 150 clocks
!

rtc:

        set     0x1f80000, %l0		! MEC register base
        set     149, %l1
        st      %l1, [%l0 + 0x84]	! RTC scaler = 149
        set     0x0d00, %l1
        st      %l1, [%l0 + 0x98]	! Start RTC

        st      %g0, [%l0 + 0x64]	! Disable watchdog for now
        ld      [%l0], %g1
        or      %g1, 1, %g1
        st      %g1, [%l0]		! Enable power-down mode

_init:
	set     PSR_INIT, %g1		! Initialize psr
        mov     %g1, %psr
        set     WIM_INIT, %g1		! Initialize WIM
        mov     %g1, %wim               
        set     _trap_table, %g1	! Initialize TBR
        mov     %g1, %tbr
        nop;nop;nop                     

        set     PSR_INIT, %g1
        wr      %g1, 0x20, %psr		! enable traps
        nop; nop; nop;

	call	SYM(start)
	nop
	
/*
 * Register window overflow handler.  Come here when save would move us
 * into the invalid window.  This routine runs with traps disabled, and
 * must be careful not to touch the condition codes, as PSR is never
 * restored.
 *
 * We are called with %l0 = wim, %l1 = pc, %l2 = npc
 */
	.globl SYM(win_overflow)
SYM(win_overflow):
        mov     %g1, %l3		! Save g1, we use it to hold the wim
        srl     %l0, 1, %g1		! Rotate wim right
        sll     %l0, NUMBER_OF_REGISTER_WINDOWS - 1, %l0
        or      %l0, %g1, %g1

        save    %g0, %g0, %g0		! Slip into next window
        mov     %g1, %wim		! Install the new wim
	nop
	nop
	nop

        std     %l0, [%sp + 0 * 4]	! save L & I registers
        std     %l2, [%sp + 2 * 4]
        std     %l4, [%sp + 4 * 4]
        std     %l6, [%sp + 6 * 4]

        std     %i0, [%sp + 8 * 4]
        std     %i2, [%sp + 10 * 4]
        std     %i4, [%sp + 12 * 4]
        std     %i6, [%sp + 14 * 4]

        restore                         ! Go back to trap window.
        mov     %l3, %g1		! Restore %g1

        jmpl    %l1, %g0
        rett    %l2

/*
 * Register window underflow handler.  Come here when restore would move us
 * into the invalid window.  This routine runs with traps disabled, and
 * must be careful not to touch the condition codes, as PSR is never
 * restored.
 *
 * We are called with %l0 = wim, %l1 = pc, %l2 = npc
 */
	.globl SYM(win_underflow)
SYM(win_underflow):
        sll     %l0, 1, %l3		! Rotate wim left
        srl     %l0, NUMBER_OF_REGISTER_WINDOWS - 1, %l0
        or      %l0, %l3, %l0

        mov     %l0, %wim		! Install the new wim

        restore                         ! Users window
        restore                         ! His callers window

        ldd     [%sp + 0 * 4], %l0	! restore L & I registers
        ldd     [%sp + 2 * 4], %l2
        ldd     [%sp + 4 * 4], %l4
        ldd     [%sp + 6 * 4], %l6

        ldd     [%sp + 8 * 4], %i0
        ldd     [%sp + 10 * 4], %i2
        ldd     [%sp + 12 * 4], %i4
        ldd     [%sp + 14 * 4], %i6

        save    %g0, %g0, %g0		! Back to trap window
        save    %g0, %g0, %g0

        jmpl    %l1, %g0
        rett    %l2

/*
 * Register window flush handler, triggered by a "ta 3" instruction.
 * We are called with %l0 = wim, %l1 = pc, %l2 = npc
 */
	.globl	SYM(win_flush)
SYM(win_flush):
	mov	%psr, %l0
	or	%l0,0xf00,%l3		! Disable interrupts
	mov	%l3,%psr
	nop
	nop
	nop
	mov	%wim, %l3

	srl	%l3, %l0, %l4		! wim >> cwp
	cmp	%l4, 1
	bne	flush_window_fine	! Branch if not in the invalid window
	nop

/* Handle window overflow. We can't trap here. */

	mov	%g1, %l4		! Save g1, we use it to hold the wim
	srl	%l3, 1, %g1		! Rotate wim right
        sll     %l3, NUMBER_OF_REGISTER_WINDOWS - 1, %l3
        or      %l3, %g1, %g1
	mov	%g0, %wim		! Clear wim so that subsequent save
	nop				!  wont trap
	nop
	nop
	save	%g0, %g0, %g0		! Slip into next window
	mov	%g1, %wim		! Install the new wim

	std	%l0, [%sp + 0 * 4]	! save L & I registers
	std	%l2, [%sp + 2 * 4]
	std	%l4, [%sp + 4 * 4]
	std	%l6, [%sp + 6 * 4]

	std	%i0, [%sp + 8 * 4]
	std	%i2, [%sp + 10 * 4]
	std	%i4, [%sp + 12 * 4]
	std	%i6, [%sp + 14 * 4]

	restore				! Go back to trap window.
	mov	%l4, %g1		! Restore %g1

flush_window_fine:
	mov	%psr,%l5		! enable traps
	or	%l5,0x20,%l5
	mov	%l5, %psr
	nop
	nop
	nop

	set	save_buf,%l5
	st	%l2,[%l5]

	! The stack pointer currently contains a bogus value [when a trap
	! occurs CWP is decremented and points to an unused window].
	! Give it something useful before we flush every window.
	! This does what a "save %sp,-64,$sp" would, except that CWP has
	! already been decremented.
	add	%fp, -64, %sp

	save %sp, -64, %sp		! Flush user register window to stack
	save %sp, -64, %sp
	save %sp, -64, %sp
	save %sp, -64, %sp
	save %sp, -64, %sp
	save %sp, -64, %sp
	save %sp, -64, %sp
	save %sp, -64, %sp
	restore
	restore
	restore
	restore
	restore
	restore
	restore
	restore

	restore				! Make sure we have a valid window
	save %g0, %g0, %g0

	set	save_buf, %l2		! Get our return address back
	ld	[%l2],%l2

	mov	%psr,%l5		! disable traps for rett
	andn	%l5,0x20,%l5
	mov	%l5,%psr
	nop
	nop
	nop

	jmpl	%l2, %g0
	rett	%l2+4

/*
 * Read the TBR.
 */
       .globl SYM(rdtbr)
SYM(rdtbr):
        mov     %tbr, %o0
	nop
        retl
	nop

/*
 * Read the psr
 */
	.globl	SYM(read_psr)
SYM(read_psr):
	mov	%psr, %o0
	nop
        retl
	nop

/*
 * Write the PSR.
 */

	.globl	SYM(write_psr)
SYM(write_psr):
	mov %i0, %psr
	nop
	nop
	nop
	retl
	nop
/*
 * Come here when no fpu exists.  This just skips the offending
 * instruction.
 */
	.globl	SYM(no_fpu)
SYM(no_fpu):
        jmpl %l2, %g0
        rett %l2+4

        .globl SYM(fltr_proto)
        .align 4
SYM(fltr_proto):                    ! First level trap routine prototype
        sethi 0, %l0
        jmpl 0+%l0, %g0
        nop
        nop

/*
 * Trap handler for memory errors.  This just sets mem_err to be
 * non-zero.  It assumes that l1 is non-zero.  This should be safe,
 * as it is doubtful that 0 would ever contain code that could mem
 * fault.  This routine will skip past the faulting instruction after
 * setting mem_err.
 */
	.globl	SYM(fltr_set_mem_err)
SYM(fltr_set_mem_err):
	sethi	%hi(SYM(mem_err)), %l0
	st	%l1, [%l0 + %lo(SYM(mem_err))]
	jmpl	%l2, %g0
	rett	%l2+4

        .data
        .align  4
	.ascii	"DaTa"
	.long	SYM(sdata)
in_trap_handler:
	.word	0
save_buf:	
	.word	0	/* place to save %g1 */
	.word	0	/* place to save %g2 */

	.text
	.align 4

/*
 * This function is called when any SPARC trap (except window overflow
 * or underflow) occurs.  It makes sure that the invalid register
 * window is still available before jumping into C code.  It will also
 * restore the world if you return from handle_exception.
 */
	.globl SYM(trap_low)
SYM(trap_low):
	mov	%psr, %l0
	mov	%wim, %l3

	srl	%l3, %l0, %l4		! wim >> cwp
	cmp	%l4, 1
	bne	window_fine		! Branch if not in the invalid window
	nop

        mov     %g1, %l4		! Save g1, we use it to hold the wim
        srl     %l3, 1, %g1		! Rotate wim right
        sll     %l3, 8-1, %l5
        or      %l5, %g1, %g1
		
	save	%g0, %g0, %g0		! Slip into next window
	mov	%g1, %wim		! Install the new wim

	std	%l0, [%sp + 0 * 4]	! save L & I registers
	std	%l2, [%sp + 2 * 4]
	std	%l4, [%sp + 4 * 4]
	std	%l6, [%sp + 6 * 4]

	std	%i0, [%sp + 8 * 4]
	std	%i2, [%sp + 10 * 4]
	std	%i4, [%sp + 12 * 4]
	std	%i6, [%sp + 14 * 4]

	restore				! Go back to trap window.
	mov	%l4, %g1		! Restore g1

window_fine:
	sethi	%hi(in_trap_handler), %l4
	ld	[%lo(in_trap_handler) + %l4], %l5
	tst	%l5
	bg	recursive_trap
	inc	%l5

	/* use the stack we set in the linker script */
	sethi	%hi(__trap_stack), %l6
        or      %l6,%lo(__trap_stack),%l6
	mov	%l6, %sp		! set the stack pointer

recursive_trap:
	st	%l5, [%lo(in_trap_handler) + %l4]

	sub	%sp,(16+1+6+1+72)*4,%sp	! Make room for input & locals
 					! + hidden arg + arg spill
					! + doubleword alignment
					! + registers[72] local var

	std	%g0, [%sp + (24 + 0) * 4] ! registers[Gx]
	std	%g2, [%sp + (24 + 2) * 4]
	std	%g4, [%sp + (24 + 4) * 4]
	std	%g6, [%sp + (24 + 6) * 4]

	std	%i0, [%sp + (24 + 8) * 4] ! registers[Ox]
	std	%i2, [%sp + (24 + 10) * 4]
	std	%i4, [%sp + (24 + 12) * 4]
	std	%i6, [%sp + (24 + 14) * 4]
					 ! F0->F31 not implemented
	mov	%y, %l4
	mov	%tbr, %l5
	st	%l4, [%sp + (24 + 64) * 4] ! Y
	st	%l0, [%sp + (24 + 65) * 4] ! PSR
	st	%l3, [%sp + (24 + 66) * 4] ! WIM
	st	%l5, [%sp + (24 + 67) * 4] ! TBR
	st	%l1, [%sp + (24 + 68) * 4] ! PC
	st	%l2, [%sp + (24 + 69) * 4] ! NPC
					 ! CPSR and FPSR not implemented

	or	%l0, 0xf20, %l4
	mov	%l4, %psr		! Turn on traps, disable interrupts

	call	SYM(handle_exception)
	add	%sp, 24 * 4, %o0	! Pass address of registers

/* Reload all of the registers that aren't on the stack */

	ld	[%sp + (24 + 1) * 4], %g1  ! registers[Gx]
	ldd	[%sp + (24 + 2) * 4], %g2
	ldd	[%sp + (24 + 4) * 4], %g4
	ldd	[%sp + (24 + 6) * 4], %g6

	ldd	[%sp + (24 + 8) * 4], %i0  ! registers[Ox]
	ldd	[%sp + (24 + 10) * 4], %i2
	ldd	[%sp + (24 + 12) * 4], %i4
	ldd	[%sp + (24 + 14) * 4], %i6

	ldd	[%sp + (24 + 64) * 4], %l0 ! Y & PSR
	ldd	[%sp + (24 + 68) * 4], %l2 ! PC & NPC

	restore				! Ensure that previous window is valid
	save	%g0, %g0, %g0		!  by causing a window_underflow trap

	mov	%l0, %y
	mov	%l1, %psr		! Make sure that traps are disabled
					! for rett

	sethi	%hi(in_trap_handler), %l4
	ld	[%lo(in_trap_handler) + %l4], %l5
	dec	%l5
	st	%l5, [%lo(in_trap_handler) + %l4]

	jmpl	%l2, %g0		! Restore old PC
	rett	%l3			! Restore old nPC