#
 mes 2,EM_WSIZE,EM_PSIZE

 exp $setjmp
 pro $setjmp,3*EM_WSIZE

; setjmp saves the StackPointer and the LocalBase, and the chunk of
; memory between the StackPointer and the ArgumentBase, + its size in a
; buffer, pointed to by the parameter.
; longjump can then restore this buffer and return.
; Notice that this does not work on EM implementations in which every
; procedure frame has a different fragment in memory, because in this case
; the ArgumentBase will point into the fragment of the caller.
; What really is needed is a way to find out the size of the return
; status block.
; On EM-implementations in which the stack grows upwards it is untested,
; as there are no such implementations available now.
; This implementation of setjmp/longjmp
; depends on the assumption that the routine calling
; setjmp does not have register variables, and that it saves all registers
; that are available for variables.

#ifdef __BSD4_2
 loc 0
 cal $sigblock
 asp EM_WSIZE
 lfr EM_WSIZE
 stl -3*EM_WSIZE
#endif
 loc 0
 stl -2*EM_WSIZE
 lor 1		; load StackPointer
 lal 0
 loi EM_PSIZE
 sti EM_PSIZE	; save it
 lxl 0		; load LocalBase
 lal 0
 loi EM_PSIZE
 adp EM_PSIZE
 sti EM_PSIZE	; save it
 lxa 0		; load ArgumentBase
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE	; load saved StackPointer
 sbs EM_WSIZE	; gives size of block that is to be saved, or negative size
 dup EM_WSIZE
 zgt *5
 ngi EM_WSIZE
 loc 1
 stl -2*EM_WSIZE; one if the stack grows upwards
5
 stl -EM_WSIZE	; save size of block in local
 lol -EM_WSIZE
 lal 0
 loi EM_PSIZE
 adp 2*EM_PSIZE
 sti EM_WSIZE	; and also in the buffer
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE	; load saved StackPointer
 lol -2*EM_WSIZE; positive if the stack grows upwards
 zle *6
 asp EM_PSIZE
 lxa 0
 adp EM_WSIZE	; in this case the source address = ArgumentBase+EM_WSIZE
6
 lal 0
 loi EM_PSIZE
 adp 2*EM_PSIZE+EM_WSIZE
		; destination address
 lol -EM_WSIZE	; count
 bls EM_WSIZE	; block copy
 loc 0
 ret EM_WSIZE
 end 3*EM_WSIZE

 exp $longjmp
 pro $longjmp,3*EM_WSIZE

; first, find out wether the stack grows upwards
 loc 0
 stl -2*EM_WSIZE
 lxa 0
 lxl 0
 cmp
 zge *7
 loc 1
 stl -2*EM_WSIZE; this local contains 1 if it does, otherwise it contains 0
7
; then, adjust StackPointer until it is below the saved StackPointer (or
; above if it grows upwards)
; then push parameters
; then copy the saved block in its proper place
; notice that the parameters can not be used anymore now
; then restore the LocalBase and the Stackpointer and return.
1
 loc 0
2
 lor 1
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE	; saved StackPointer
 cmp		; compare with current one
 lol -2*EM_WSIZE
 zle *8
 zlt *1
 bra *10
8
 zgt *1
10
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE	; push saved StackPointer
 lol EM_PSIZE	; push value to be returned by longjmp
 lal 0
 loi EM_PSIZE
 adp EM_PSIZE
 loi EM_PSIZE	; push saved LocalBase
 lal 0
 loi EM_PSIZE
 adp 2*EM_PSIZE+EM_WSIZE
		; source address
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE	; saved stackpointer
 lol -2*EM_WSIZE
 zle *9		; if not positive, this is the destination address,
		; otherwise subtract the size of the saved area and add EM_WSIZE
 adp EM_WSIZE
 lal 0
 loi EM_PSIZE
 adp 2*EM_PSIZE
 loi EM_WSIZE
 ngi EM_WSIZE
 ads EM_WSIZE
9		; destination address
 lal 0
 loi EM_PSIZE
 adp 2*EM_PSIZE
 loi EM_WSIZE	; size
 bls EM_WSIZE	; now we have a frame exactly as it was in setjmp,
		; and exactly at the same place
 str 0		; restore LocalBase
 stl -EM_WSIZE	; saves the return value
 str 1		; restores the StackPointer
#ifdef __BSD4_2
 lol -3*EM_WSIZE
 cal $sigsetmask
 asp EM_WSIZE
 lfr EM_WSIZE
 asp EM_WSIZE
#endif
 lol -EM_WSIZE
 dup EM_WSIZE
 zne *3
		; of course, longjmp may not return 0!
 asp EM_WSIZE
 loc 1
3
 ret EM_WSIZE
 end 3*EM_WSIZE
