147 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
#
 | 
						|
 mes 2,EM_WSIZE,EM_PSIZE
 | 
						|
 | 
						|
 exp $setjmp
 | 
						|
 pro $setjmp,2*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.
 | 
						|
 | 
						|
 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 2*EM_WSIZE
 | 
						|
 | 
						|
 exp $longjmp
 | 
						|
 pro $longjmp,2*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
 | 
						|
 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 2*EM_WSIZE
 |