/* --- Copyright University of Sussex 1994. All rights reserved. ----------
 * File:        C.mips/src/alisp.s
 * Purpose:     Assembler support for Common Lisp on MIPS R2000/R3000
 * Author:      Robert Duncan and Simon Nichols, Feb 9 1990 (see revisions)
 */


#_<

#_INCLUDE 'declare.ph'

constant _setstklen_diff; ;;; forward

lconstant macro (
	;;; size of a boolean: we can use this to compute the address of
	;;; nil as an offset from false, on the assumption that poplink
	;;; generates structures in the order: false, true, nil
	_BOOL_SIZE = @@(struct BOOLEAN)++,
);

>_#

#_INCLUDE 'pop_regdef.h'

_NIL_OFFS = 2 * _BOOL_SIZE


/************************* wrapping structures ************************/

	.data
	.word	Ldata_size
	.word	C_LAB(Sys$-objmod_pad_key)
Ldata_start:

/**********************************************************************/


	.text

;;; _SETSTKLEN:
;;;	adjusts the number of results returned by a Lisp function.
;;;	The subroutine takes the length of the userstack before the function
;;;	call and the number of results expected (both as popints).
;;;	The actual stacklength is adjusted to fit either by erasing items
;;;	or by pushing -nil-.

;;; Call:
;;;	_setstklen(SAVED_STACKLENGTH, NRESULTS);

;;; Registers used:
;;;	t0	SAVED_STACKLENGTH
;;;	t1	NRESULTS
;;;	t2	desired stacklength
;;;	a0	desired stack pointer

;;; Usage:
;;;	implements the I_SETSTACKLENGTH instruction. Where NRESULTS is
;;;	available to the run-time assembler, the code for SETSTKLEN is
;;;	expanded inline and a jump made direct to SETSTKLEN_DIFF
;;;	if necessary.

DEF_C_LAB (_setstklen)

	.ent	$setstklen
$setstklen:

	lw	t0, 4(usp)
	lw	t1, (usp)
	addu	usp, 8

	;;; Load _userhi to a0

	lw	a0, _SVB_OFFS(_userhi)(svb)

	;;; Compute desired stacklength (SAVED_STACKLENGTH + NRESULTS) in t2.
	;;; The two arguments are in popint words; subtracting 6 from the
	;;; total converts to sysint bytes.

	addu	t2, t0, t1
	subu	t2, 6

	;;; Compute the desired stack pointer (_userhi - desired_length)
	;;; in a0

	subu	a0, t2

	;;; Compare desired and actual stack pointers: if different,
	;;; jump to fix

	bne	a0, usp, $setstklen_diff
	j	ra

	.end	$setstklen


DEF_C_LAB (_setstklen_diff)

	.ent	$setstklen_diff
$setstklen_diff:

	;;; Desired and actual stack pointers are different:
	;;; push or pop results according to direction of difference

	blt	usp, a0, 2f

	;;; Actual stack is too short: push nils until the desired size
	;;; is reached

	la	t0, _NIL_OFFS(false)
1:	subu	usp, 4
	sw	t0, (usp)
	bne	usp, a0, 1b
	j	ra

2:	;;; Actual stack is too long: erase the extra results simply by
	;;; setting USP to the desired value

	move	usp, a0
	j	ra

	.end	$setstklen_diff


/***************** end labels for wrapping structures *****************/

	.data
Ldata_end:
Ldata_size = 0 ##PATCH## Ldata_size Ldata_end Ldata_start

/**********************************************************************/


/* --- Revision History ---------------------------------------------------
--- Robert John Duncan, Mar 15 1994
	Removed the wrapping structure from the text section
--- Robert John Duncan, Mar  9 1994
	Added directives for position-independent code. Changed to access
	nil through the false register.
--- Robert John Duncan, Mar  8 1994
	Added .ent/.end directives.
--- Robert John Duncan, Jul  4 1990
	Added extern declarations for special vars
 */
