/* $Id$ */

/*	The Return Status Block contains, in push order:
	FIL, LIN, LB, PC, PI, rsbcode
*/

#include	"logging.h"
#include	"global.h"
#include	"mem.h"
#include	"rsb.h"
#include	"proctab.h"
#include	"linfil.h"
#include	"shadow.h"
#include	"segment.h"
#include	"text.h"
#include	"warn.h"
#include	"whatever.h"

/* offsets to be added to a local base */
int rsb_rsbcode;
int rsb_PI;
int rsb_PC;
int rsb_LB;
int rsb_LIN;
int rsb_FIL;
int rsbsize;

void init_rsb(void)
{
	rsb_rsbcode = 0;
	rsb_PI = wsize;
	rsb_PC = rsb_PI + psize;
	rsb_LB = rsb_PC + psize;
	rsb_LIN = rsb_LB + psize;
	rsb_FIL = rsb_LIN + LINSIZE;
	rsbsize = rsb_FIL + psize;
}

void pushrsb(int rsbcode)
{
	/* fill Return Status Block */
	incSP((size)rsbsize);

	st_stdp(SP + rsb_FIL, getFIL());
	st_prot(SP + rsb_FIL, psize);

	st_stn(SP + rsb_LIN, (long)getLIN(), LINSIZE);
	st_prot(SP + rsb_LIN, LINSIZE);

	st_stdp(SP + rsb_LB, LB);
	st_prot(SP + rsb_LB, psize);

	st_stip(SP + rsb_PC, PC);
	st_prot(SP + rsb_PC, psize);

	st_stn(SP + rsb_PI, PI, psize);
	st_prot(SP + rsb_PI, psize);

	st_stw(SP + rsb_rsbcode, (long)rsbcode);
	st_prot(SP + rsb_rsbcode, wsize);

	newLB(SP);
}

/*ARGSUSED*/
int poprsb(int rtt) /* set to 1 if working for RTT */
{
	/* pops the RSB and returns the rsbcode, for further testing */
	register int rsbcode;

#ifdef	LOGGING
	{
		/* check SP */
		register ptr properSP = LB - proctab[PI].pr_nloc;

		if (SP < properSP)
			warning(rtt ? WRTTSTL : WRETSTL);
		if (SP > properSP)
			warning(rtt ? WRTTSTS : WRETSTS);
	}
#endif	/* LOGGING */

	/* discard stack up to RSB */
	newSP(LB);

	/* get RSB code and test it for applicability */
	rsbcode = st_lduw(SP + rsb_rsbcode);
	if ((rsbcode & RSBMASK) != RSBCODE)	/* no RSB at all */
		return rsbcode;

	if (rsbcode != RSB_STP) {
		/*	Restore registers PI, PC, LB, LIN and FIL
			from Return Status Block
		*/
		PI = st_lds(SP + rsb_PI, psize);
		newPC(st_ldip(SP + rsb_PC));
		newLB(st_lddp(SP + rsb_LB));
		putLIN((long) st_ldu(SP + rsb_LIN, LINSIZE));
		putFIL(st_lddp(SP + rsb_FIL));

		/* remove RSB */
		st_dec(rsbsize);

		pop_frames();
	}

	return rsbcode;
}

