#
;
; (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
; See the copyright notice in the ACK home directory, in the file "Copyright".
;

;
; Module:	coroutine primitives
; Author:	Kees Bot, Edwin Scheffer, Ceriel Jacobs
; Version:	$Id$
;

 mes 2,EM_WSIZE,EM_PSIZE

 ; topsize takes care of two things:
 ; - given a stack-break,
 ;   it computes the size of the chunk of memory needed to save the stack;
 ; - also, if this stack-break = 0, it creates one, assuming that caller is
 ;   the stack-break.
 ;
 ; This implementation assumes a continuous stack growing downwards

 exp $topsize
#ifdef __sparc
 inp $topsize2
 pro $topsize, 0
 mes 11
 zer EM_PSIZE
 lal 0
 loi EM_PSIZE
 cal $topsize2
 asp 2*EM_PSIZE
 lfr EM_WSIZE
 ret EM_WSIZE
 end 0
 pro $topsize2, 3*EM_WSIZE+3*EM_PSIZE
#else
 pro $topsize, 3*EM_WSIZE+3*EM_PSIZE
#endif
 ; local space for line-number, ignoremask, filename, stack-break, size,
 ; and stack-pointer (see the topsave routine)
 mes 11
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE		; stack-break or 0
 zer EM_PSIZE
 cmp
 zne *1
 lxl 0
 dch			; local base of caller
#ifdef __sparc
 dch			; because of the extra layer
#endif
 lal 0
 loi EM_PSIZE
 sti EM_PSIZE
1
 lal 0
 loi EM_PSIZE
 loi EM_PSIZE
 lpb			; convert this local base to an argument base.
			; An implementation of a sort of "topsize" EM
			; instruction should take a local base, and save
			; the whole frame.

 lor 1			; stack-break  SP
 sbs EM_WSIZE		; stack-break-SP
 ret EM_WSIZE		; return size of block to be saved
 end 3*EM_WSIZE+3*EM_PSIZE

 exp $topsave
#ifdef __sparc
 inp $topsave2
 pro $topsave,0
 mes 11
 lal 0
 loi 2*EM_PSIZE
 cal $topsave2
 asp 2*EM_PSIZE
 lfr EM_WSIZE
 ret EM_WSIZE
 end 0
 pro $topsave2,0
#else
 pro $topsave, 0
#endif
 mes 11
 loe 0
 lae 4			; load line number and file name
 loi EM_PSIZE
 lim			; ignore mask
 lor 0			; LB
 lal 0
 loi EM_PSIZE		; stack-break
 lpb
 lor 1
 sbs EM_WSIZE
 loc EM_WSIZE
 adu EM_WSIZE		; gives size
 dup EM_WSIZE
 stl 0			; save size
 lor 1			; SP (the SP BEFORE pushing)
 lor 1			; SP (address of stack top to save)
 lal EM_PSIZE		; area
 loi EM_PSIZE
 lol 0			; size
 bls EM_WSIZE		; move whole block
 asp 3*EM_PSIZE+3*EM_WSIZE	; remove the lot from the stack
 loc 1
 ret EM_WSIZE			; return 1
 end 0

sv
 bss EM_PSIZE,0,0

 exp $topload
#ifdef __sparc
 inp $topload1
 pro $topload,0
 lal 0
 loi EM_PSIZE
 cal $topload1
 asp EM_PSIZE
 lfr EM_WSIZE
 ret EM_WSIZE
 end 0
 pro $topload1, 0
#else
 pro $topload, 0
#endif
 mes 11

 lal 0
 loi EM_PSIZE
 lae sv
 sti EM_PSIZE		; saved parameter

 lxl 0
2
 dup EM_PSIZE
 adp -3*EM_PSIZE
 lal 0
 loi EM_PSIZE		; compare target SP with current LB to see if we must
 loi EM_PSIZE
 cmp			; find another LB first
 zgt *1
 dch			; just follow dynamic chain to make sure we find
			; a legal one
 bra *2
1
 str 0

 lae sv
 loi EM_PSIZE
 loi EM_PSIZE		; load indirect to
 str 1			; restore SP
 asp -EM_PSIZE		; to stop int from complaining about non-existent memory
 lae sv
 loi EM_PSIZE		; source address
 lor 1
 adp EM_PSIZE		; destination address
 lae sv
 loi EM_PSIZE
 adp EM_PSIZE
 loi EM_WSIZE		; size of block
 bls EM_WSIZE
 asp EM_PSIZE+EM_WSIZE	; drop size + SP
 str 0			; restore local base
 sim			; ignore mask
 lae 4
 sti EM_PSIZE
 ste 0			; line and file
 loc 0
 ret EM_WSIZE
 end 0
