Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source lib task_SPARC task hw_stack.c
Document Actions

hw_stack.c

by Michael L Powell last modified 2007-01-26 03:22

Click here to get the file

Size 22.3 kB - File type text/plain

File contents

/*ident	"@(#)cop4:sparc_task/task/hw_stack.c	1.1" */
/*******************************************************************************
 
C++ source for the C++ Language System, Release 3.0.  This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.

Copyright (c) 1991 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T.  All Rights Reserved.

THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

*******************************************************************************/
/*
 * Copyright (c) 1990, 1991 by Sun Microsystems, Inc.
 */

#include "hw_stack.h"

/* Machine-dependent asms and functions for task library.
 * Porting these requires intimate knowledge of the stack frame layout,
 * call and return sequences for the machine.
 */

////////////////////////// AT&T 3B series //////////////////////////
#ifdef	PROC_3B

asm("	.text");
asm("	.globl	SAVE_REGS");
asm("	.align	4");
asm("SAVE_REGS:");
asm("	save &6");
asm("	movw	0(%ap),%r1 ");		/* ptr to HW_REGS */
asm("	movw	-24(%fp),0(%r1) ");	/* move caller's r3 to arg.r3 */
asm("	movw	-20(%fp),4(%r1) ");	/* move caller's r4 to arg.r4 */
asm("	movw	-16(%fp),8(%r1) ");	/* move caller's r5 to arg.r5 */
asm("	movw	-12(%fp),12(%r1) ");	/* move caller's r6 to arg.r6 */
asm("	movw	-8(%fp),16(%r1) ");	/* move caller's r7 to arg.r7 */
asm("	movw	-4(%fp),20(%r1) ");	/* move caller's r8 to arg.r8 */
asm("	ret &6");

/* save_saved_regs copies n_saved regs saved in stack frame defined by fp
 * to a HW_REGS structure.
 */
void
save_saved_regs(HW_REGS *regsp, int* fp)
{
	FrameLayout layout(fp);
	register int* p = FIRST_SAVED_REG_P(fp, layout.n_saved);
	switch(layout.n_saved)  {	
		case 6:
			regsp->r3 = *p++;
			/* FALLTHROUGH */
		case 5:
			regsp->r4 = *p++;
			/* FALLTHROUGH */
		case 4:
			regsp->r5 = *p++;
			/* FALLTHROUGH */
		case 3:
			regsp->r6 = *p++;
			/* FALLTHROUGH */
		case 2:
			regsp->r7 = *p++;
			/* FALLTHROUGH */
		case 1:
			regsp->r8 = *p++;
			/* FALLTHROUGH */
		default:
			break;
	}
}

/* On the 3Bs, the current ap is the caller's sp, but we want caller's sp - 1
 * to point to last used word in stack, to correspond with sp's on 386, vax,
 * sun
 */
asm("	.text");
asm("	.globl	TOP");
asm("	.align	4");
asm("TOP:");
asm("	save &0");
asm("	movw	%ap,%r0");  /* caller's sp */
asm("	addw2	&4,%r0");   /* caller's sp - 1 */
asm("	ret &0");

/* These assembly language functions should be replaced by new-style
 * asms, when (if) they are implemented for C++.
 * for example:  
 * asm void
 * set_r3(p)
 * {
 *     % mem p;
 *     movw *p,%r3
 * }
 */

asm("	.text");
asm("	.globl	set_r3");
asm("	.align	4");
asm("set_r3:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r3 ");
asm("	ret &0");

asm("	.text");
asm("	.globl	set_r4");
asm("	.align	4");
asm("set_r4:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r4 ");
asm("	ret &0");

asm("	.text");
asm("	.globl	set_r5");
asm("	.align	4");
asm("set_r5:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r5 ");
asm("	ret &0");

asm("	.text");
asm("	.globl	set_r6");
asm("	.align	4");
asm("set_r6:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r6 ");
asm("	ret &0");

asm("	.text");
asm("	.globl	set_r7");
asm("	.align	4");
asm("set_r7:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r7 ");
asm("	ret &0");

asm("	.text");
asm("	.globl	set_r8");
asm("	.align	4");
asm("set_r8:");
asm("	save &0");
asm("	movw	0(%ap),%r1 ");		/* ptr to register saved in stack */
asm("	movw 0(%r1),%r8 ");
asm("	ret &0");

#ifdef	u3b

asm("	.text");
asm("	.globl	AP");
asm("	.align	4");
asm("AP:");
asm("	save &0");
asm("	movw	-48(%fp),%r0");  /* r0 = caller's ap */
asm("	ret &0");

asm("	.text");
asm("	.globl	FP");
asm("	.align	4");
asm("FP:");
asm("	save &0");
asm("	movw	-44(%fp),%r0");  /* r0 = caller's fp */
asm("	ret &0");

/* On the 3B20 the sp is restored from the current ap on a return
 * FUDGE_SP overwrites the saved ap with a new value (the 1st arg), causing
 * the caller's ap to be changed to the new value.
 * As a precaution, the 1st arg of caller is copied down to where new ap
 * will point.  (In case caller references 1st arg (implicit "this" arg)
 * to set return value.)
 * 2nd arg unnecessary on 3B20. 
 */
asm("	.text");
asm("	.globl	FUDGE_SP");
asm("	.align	4");
asm("FUDGE_SP:");
asm("	save &0");
asm("	movw	-48(%fp),%r1");		/* r1 = caller's ap */
asm("	movw	0(%ap),%r0");		/* r0 = 1st arg (de_ap) */
asm("	movw	0(%r1),0(%r0)");	/* *r0 = caller's 1st arg */
asm("	movw	0(%ap),-48(%fp)");	/* overwrite saved ap */
asm("	ret &0");

#else	/* BELLMAC_CHIP */


asm("	.text");
asm("	.globl	AP");
asm("	.align	4");
asm("AP:");
asm("	save &0");
asm("	movw	-32(%fp),%r0");  /* r0 = caller's ap */ 
asm("	ret &0");

asm("	.text");
asm("	.globl	FP");
asm("	.align	4");
asm("FP:");
asm("	save &0");
asm("	movw	-28(%fp),%r0");  /* r0 = caller's fp */ 
asm("	ret &0");

/* On BELLMAC_CHIP machines, sp is restored from current ap on return.
 * FUDGE_SP overwrites the saved ap with a new value (the 1st arg), causing
 * the caller's ap to be changed to the new value.
 * As a precaution, the 1st arg of caller is copied down to where new ap
 * will point.  (In case caller references 1st arg (implicit "this" arg)
 * to set return value.)
 * 2nd arg unnecessary on BELLMAC_CHIP machines.
 */ 
asm("	.text");
asm("	.globl	FUDGE_SP");
asm("	.align	4");
asm("FUDGE_SP:");
asm("	save &0");
asm("	movw	-32(%fp),%r1");		/* r1 = caller's ap */
asm("	movw	0(%ap),%r0");		/* r0 = 1st arg (de_ap) */
asm("	movw	0(%r1),0(%r0)");	/* *r0 = caller's 1st arg */
asm("	movw	0(%ap),-32(%fp)");	/* overwrite saved  ap */
asm("	ret &0");
#endif	/* BELLMAC_CHIP */
#endif	/* PROC_3B */

//////////////////////////// DEC VAX ////////////////////////////
#ifdef	vax
/* save all caller regs in HW_REGS structure */
asm("	.globl _SAVE_REGS");
asm("	.align	1");
asm("_SAVE_REGS:");
asm("	.word	0xfc0 ");	/* entry mask; save all user regs (r11-r6) */
asm("	movl	4(ap),r1 ");		/* ptr to HW_REGS */
asm("	movl	20(fp),0(r1) ");	/* move caller's r6 to arg.r6 */
asm("	movl	24(fp),4(r1) ");	/* move caller's r7 to arg.r7 */
asm("	movl	28(fp),8(r1) ");	/* move caller's r8 to arg.r8 */
asm("	movl	32(fp),12(r1) ");	/* move caller's r9 to arg.r9 */
asm("	movl	36(fp),16(r1) ");	/* move caller's r10 to arg.r10 */
asm("	movl	40(fp),20(r1) ");	/* move caller's r11 to arg.r11 */
asm("	ret");

asm("	.globl _FP");
asm("	.align	1");
asm("_FP:");
asm("	.word	0x0000");	/* entry mask; save no regs */
asm("	movl 12(fp),r0");	/* r0 = caller's fp */
asm("	ret");

/* On the vax, when there are no args, the current ap is the caller's sp */
asm("	.globl _TOP");
asm("	.align	1");
asm("_TOP:");
asm("	.word	0x0000");	/* entry mask; save no regs */
asm("	movl ap,r0");		/* r0 = caller's sp */
asm("	ret");
/* More general (independent of #args) would be:  addl3 $1,(ap),r0 # r0=nargs + 1
 *	ashl $2,r0,r0 # r0 = nargs * 4 (scale to bytes) addl2 ap,r0 #caller's sp
 */

asm("	.globl _set_r6");
asm("	.align	1");
asm("_set_r6:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r6 ");
asm("	ret");

asm("	.globl _set_r7");
asm("	.align	1");
asm("_set_r7:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r7 ");
asm("	ret");

asm("	.globl _set_r8");
asm("	.align	1");
asm("_set_r8:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r8 ");
asm("	ret");

asm("	.globl _set_r9");
asm("	.align	1");
asm("_set_r9:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r9 ");
asm("	ret");

asm("	.globl _set_r10");
asm("	.align	1");
asm("_set_r10:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r10 ");
asm("	ret");

asm("	.globl _set_r11");
asm("	.align	1");
asm("_set_r11:");
asm("	.word	0x0 ");			/*  save no regs  */
asm("	movl	4(ap),r1 ");		/* ptr to register saved in stack */
asm("	movl	(r1),r11 ");
asm("	ret");

#endif		/* vax */

///////////////////// Motorola-680x0/Sun-3 (&Sun-2) /////////////////////
#ifdef mc68000		/* Really, ifdef sun--stack frame layout
			 * is different on a UNIX PC, for example
			 */
asm("	.text");
asm("	.globl	_SAVE_REGS");
asm("_SAVE_REGS:");
asm("	link	a6,#-40");
asm("	moveml	#0x3cfc,sp@");		/* save d2-d7, a2-a5	*/
asm("	movl	a6@(8),a0");		/* a0 = arg--ptr to HW_REGS */
asm("	movl	a6@(-40),a0@");		/* move caller's d2 to arg.d2 */
asm("	movl	a6@(-36),a0@(4)");	/* move caller's d3 to arg.d3 */
asm("	movl	a6@(-32),a0@(8)");	/* move caller's d4 to arg.d4 */
asm("	movl	a6@(-28),a0@(12)");	/* move caller's d5 to arg.d5 */
asm("	movl	a6@(-24),a0@(16)");	/* move caller's d6 to arg.d6 */
asm("	movl	a6@(-20),a0@(20)");	/* move caller's d7 to arg.d7 */
asm("	movl	a6@(-16),a0@(32)");	/* move caller's a2 to arg.a2 */
asm("	movl	a6@(-12),a0@(36)");	/* move caller's a3 to arg.a3 */
asm("	movl	a6@(-8),a0@(40)");	/* move caller's a4 to arg.a4 */
asm("	movl	a6@(-4),a0@(44)");	/* move caller's a5 to arg.a5 */
asm("	moveml	a6@(-40),#0x3cfc");		/* restore d2-d7, a2-a5	*/
asm("	unlk	a6");
asm("	rts");

/*
 * Is there any reason why the regs get moveml'd onto the stack instead
 * of being used directly?  Wouldn't this be equivalent but shorter and
 * faster and harder to debug?  Oh...
 *
 * I think it was just blindly copied from the 3b version.
 *
 * Anyway, like this:
 */
#ifdef WHY_NOT
asm("	.text");
asm("	.globl	_SAVE_REGS");
asm("_SAVE_REGS:");
asm("	movl	sp@(4),a0");		/* a0 = arg--ptr to HW_REGS */
asm("	movl	d2,a0@");		/* move caller's d2 to arg.d2 */
asm("	movl	d3,a0@(4)");		/* move caller's d3 to arg.d3 */
asm("	movl	d4,a0@(8)");		/* move caller's d4 to arg.d4 */
asm("	movl	d5,a0@(12)");		/* move caller's d5 to arg.d5 */
asm("	movl	d6,a0@(16)");		/* move caller's d6 to arg.d6 */
asm("	movl	d7,a0@(20)");		/* move caller's d7 to arg.d7 */
asm("	movl	a2,a0@(32)");		/* move caller's a2 to arg.a2 */
asm("	movl	a3,a0@(36)");		/* move caller's a3 to arg.a3 */
asm("	movl	a4,a0@(40)");		/* move caller's a4 to arg.a4 */
asm("	movl	a5,a0@(44)");		/* move caller's a5 to arg.a5 */
asm("	rts");
#endif WHY_NOT

/* save_saved_regs copies regs saved in stack frame defined by fp
 * to a HW_REGS structure.  Uses FrameLayout() to find which regs are saved.
 */
void
save_saved_regs(HW_REGS *regsp, int* fp)
{
	FrameLayout layout(fp);
	register int* p = FIRST_SAVED_REG_P(fp,layout.offset);
	register int* rp = (int*)regsp;

	register unsigned short	mask = layout.mask;
	// start with d2, end with a5
	for (register int m = 0x4; m != 0x10000; m <<=1) {
		if (m & mask) {
			*rp++ = *p++;
		} else {
			rp++;
		}
	}
}

/* On the 68k, without a link inst, fp (a6) doesn't move on a call */
asm("	.text");
asm("	.globl	_FP");
asm("_FP:");
asm("	lea	a6@,a0");
asm("	movl	a0,d0");	/* for compilers that return everything in d0*/
asm("	rts");

/* On the 68k, a call (via jsr or bsr) pushes the pc on the stack;
   the caller's sp is the current sp + 1 */
asm("	.text");
asm("	.globl	_TOP");
asm("_TOP:");
asm("	lea	sp@(4),a0");
asm("	movl	a0,d0");	/* for compilers that return everything in d0*/
asm("	rts");

/* On the 68k, immediately before the rts, the sp is pointing at the
 * return pc on the stack.  The rts pops the pc off the stack.
 * To reset the sp correctly after fudging the stack, we'll save the
 * pointer to "skip's" return-pc in Skip_pc_p, and fudge_return() will
 * overwrite task::task's return pc with the address of fudge_sp,
 * a function that will reset the sp to Skip_pc_p, and then do the rts.
 * Ugly, but it should work.
 */
asm("   .data");
extern int *Skip_pc_p; 		// global to hold fudged return pc

//Note:  1st arg unnecessary on Sun-2/3
void
FUDGE_SP(int*, int* de_fp)
{
	Skip_pc_p = OLD_PC_P(de_fp);
}

asm("	.text");
asm("	.globl	_fudge_sp");
asm("_fudge_sp:");
asm("	movl	_Skip_pc_p,a7");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d2");
asm("_set_d2:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d2");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d3");
asm("_set_d3:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d3");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d4");
asm("_set_d4:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d4");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d5");
asm("_set_d5:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d5");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d6");
asm("_set_d6:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d6");
asm("	rts");

asm("	.text");
asm("	.globl	_set_d7");
asm("_set_d7:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,d7");
asm("	rts");

asm("	.text");
asm("	.globl	_set_a2");
asm("_set_a2:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,a2");
asm("	rts");

asm("	.text");
asm("	.globl	_set_a3");
asm("_set_a3:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,a3");
asm("	rts");

asm("	.text");
asm("	.globl	_set_a4");
asm("_set_a4:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,a4");
asm("	rts");

asm("	.text");
asm("	.globl	_set_a5");
asm("_set_a5:");
asm("	movl	sp@(4),a0");	/* arg is ptr to register saved in stack */
asm("	movl	a0@,a5");
asm("	rts");

#endif		/* mc68000 (sun) */

//////////////////////////// intel 80386/Sun-386 ////////////////////////////
#ifdef sun386		/* "Roadrunner" */

//
// I copied this section from the 68k version, but I don't quite trust
// what they did here.  I don't know why the 68k version decided it had
// to move all those registers to the stack before moving them into the
// HW_REGS.  Here, I don't bother to do so.  It's a leaf procedure,
// lacking a standard prolog.
//
// AT&T's (2.0 beta 4) i386 version of this does have a standard
// prolog/epilog -- does it need to?
//
asm("	.text");
asm("	.globl	SAVE_REGS");		/* Note no underscore */
asm("SAVE_REGS:");
asm("	movl	4(%esp),%eax");		/* eax = arg--ptr to HW_REGS */
asm("	movl	%edi,0(%eax)");		/* move caller's %edi to arg.edi */
asm("	movl	%esi,4(%eax)");		/* move caller's %esi to arg.esi */
asm("	movl	%ebx,8(%eax)");		/* move caller's %ebx to arg.ebx */
asm("	ret");

//
// save_saved_regs copies regs saved in stack frame defined by fp
// to a HW_REGS structure.  Uses FrameLayout() to find which regs are saved.
//
// AT&T's (2.0 beta 4) i386 version of this uses a mask and loop;
// their FIRST_SAVED_REG_P is different ( (fp-o-1) instead of what mine
// does (fp+o) ); and they use *p-- instead of *p++.   I think the
// differences cancel out.
//
void
save_saved_regs(HW_REGS *regsp, int* fp)
{
	FrameLayout layout(fp);
	register int* p = FIRST_SAVED_REG_P(fp,layout.offset);

	/* There are too few for a switch */
	if( layout.n_saved ) {
	        regsp->edi = *p++ ;
	}
	if( layout.n_saved >= 1 ) {
	        regsp->esi = *p++ ;
	}
	if( layout.n_saved >= 2 ) {
	        regsp->ebx = *p++ ;
	}

}

/* On the 386, fp (%ebp) doesn't move on a call */
asm("	.text");
asm("	.globl	FP");
asm("FP:");
asm("	movl 	%ebp, %eax");
asm("	ret");

/* On the 386, a call pushes the pc on the stack;
   the caller's sp is the current sp + 1 */
asm("	.text");
asm("	.globl	TOP");
asm("TOP:");
asm("	lea	4(%esp),%eax");
asm("	ret");

/* The 386 is just like the 68k in this respect ...
 * On the 386, immediately before the ret, the %esp is pointing at the
 * return pc on the stack.  The ret pops the pc off the stack.
 * To reset the sp correctly after fudging the stack, we'll save the
 * pointer to "skip's" return-pc in Skip_pc_p, and fudge_return() will
 * overwrite task::task's return pc with the address of fudge_sp,
 * a function that will reset the sp to Skip_pc_p, and then do the ret.
 * Ugly, but it should work.
 */

asm("    .data");		// make it writable
extern int *Skip_pc_p;		// global to hold fudged return pc 
//Note:  1st arg(AP) unnecessary on on sun-2/3/4/386 
void
FUDGE_SP(int*, int* de_fp)
{
	Skip_pc_p = OLD_PC_P(de_fp);
}

asm("	.text");
asm("	.globl	fudge_sp");
asm("fudge_sp:");
asm("	movl	Skip_pc_p,%esp");
asm("	ret");

asm("	.text");
asm("	.globl	set_edi");
asm("set_edi:");
asm("	movl	4(%esp),%eax");	/* arg is ptr to register saved in stack */
asm("	movl	%eax,%edi");
asm("	ret");

asm("	.text");
asm("	.globl	set_esi");
asm("set_esi:");
asm("	movl	4(%esp),%eax");	/* arg is ptr to register saved in stack */
asm("	movl	%eax,%esi");
asm("	ret");

asm("	.text");
asm("	.globl	set_ebx");
asm("set_ebx:");
asm("	movl	4(%esp),%eax");	/* arg is ptr to register saved in stack */
asm("	movl	%eax,%ebx");
asm("	ret");

#endif		/* sun386 */

//////////////////////////// Sun SPARC/Sun-4 ////////////////////////////
#ifdef sparc		/* "Sunrise" */

//
// SAVE_REGS is a leaf procedure, lacking a standard prolog/epilog.  It
// saves 6 parameters that might have been stored on the stack, and the
// 7 globals; compilers do not expect the out regs to be preserved across
// calls.  The corresponding register restore occurs inside "swap".
//
asm("	.text");
asm("	.globl	_SAVE_REGS");
asm("_SAVE_REGS:");

	/* unsigned long	global_regs[ N_GLOBAL_REGS ]; */
asm("	st	%g1, [%o0 +  0]");
asm("	st	%g2, [%o0 +  4]");
asm("	st	%g3, [%o0 +  8]");
asm("	st	%g4, [%o0 + 12]");
asm("	st	%g5, [%o0 + 16]");
asm("	st	%g6, [%o0 + 20]");
asm("	st	%g7, [%o0 + 24]");

	/* unsigned long	param_dump[ N_STK_PARAMS ]; */
asm("	ld	[%sp + 56], %o1");	// Get addr of caller's FP.
asm("	add	%o1, 68, %o1");		// Get addr of first stack param
asm("	add	%o0, 28, %o0");		// Get addr of param_dump[0]
asm("	ld	[%o1], %o2");		// Get first stack param
asm("	st	%o2, [%o0]");		// Store into param_dump[0].
asm("	ld	[%o1 + 4], %o2");	
asm("	st	%o2, [%o0 + 4]");
asm("	ld	[%o1 + 8], %o2");
asm("	st	%o2, [%o0 + 8]");
asm("	ld	[%o1 + 12], %o2");
asm("	st	%o2, [%o0 + 12]");
asm("	ld	[%o1 + 16], %o2");
asm("	st	%o2, [%o0 + 16]");
asm("	ld	[%o1 + 20], %o2");
asm("	st	%o2, [%o0 + 20]");

	/* leaf procedure return */
asm("	jmp	%o7 + 8");
asm("	 nop");				/* delay slot */

/*
 * Things seem a little less confusing on the SPARC if we tell the rest
 * of the task library code that the "FP" is %sp (instead of %fp).
 *
 * The stack copying and switching, etc, will not work on SPARC until
 * after the kernel flushes the registers in other register-windows to
 * the stack.  FP() does this.  It is called only from task::task,
 * at the very beginning of that routine.
 *
 * As of SunOS 4.0, T_FLUSH_WINDOWS is 0x83, which is the sum of
 * (T_SOFTWARE_TRAP + ST_FLUSH_WINDOWS).  We can't use the #defines
 * from <machine/trap.h> in an asm. 
 */
asm("	.text");
asm("	.globl	_FP");		// still need underscore, for now
asm("_FP:");
asm("	t	0x83");		// Flush regs to stack.
asm("	nop");
asm("	jmp	%o7 + 8");	// leaf proc return
asm("	 mov 	%sp, %o0");	//  note clever use of delay slot :-)

/* On the sparc, a call doesn't touch the stack.
   The caller's sp is the current sp. */
asm("	.text");
asm("	.globl	_TOP");
asm("_TOP:");
asm("	jmp	%o7 + 8");	// leaf proc return (no SAVE)
asm("	 mov 	%sp, %o0");	//  return the SP register

//
// The "Ugly, but it should work" code (see above, in 68k or 386 section)
// must be done with extreme care on a sparc.  When we want to skip an
// ancestor routine, we must flush the registers, restring the stuff, then
// return and reload.
//
asm("	 .data");	// Put it in the right section!
extern int*	Skip_pc_p;	// global to hold fudged return pc.
			// Set in FUDGE_SP, used by fudge_sp a few instructions
			// later.  Be careful not to add intervening insts.

// Note:  1st arg (AP) unnecessary on any Sun.
void
FUDGE_SP(int*, int* de_fp)
{
	Skip_pc_p = OLD_PC_P(de_fp);
}

asm("	.text");
asm("	.globl	_fudge_sp");
asm("_fudge_sp:");
asm("	jmp	%o7 + 8");
asm("	 mov	_Skip_pc_p,%sp");

#endif		/* sparc */



#ifdef uts


/*
 * FP() and AP() return the frame/arg pointer of the caller. In both
 * cases, this is the old value of r12.
 *
 * uts allows asm only inside functions.
 * Ordinarily we could simply load r0 and return, but because we're
 * in a C function, we have to make the compiler happy. A value is
 * returned through a redundant auto, which is assigned a dummy value 
 * to make the compiler shut up about "used but not set."
 * (Assignment is used instead  of initialization, due to a cfront quirk
 * which will delay initialization until right before use, overwriting
 * the asm work with 0).
 *
 */

extern "C" {

int *
FP()
{
	int	*fp;
	fp = 0;

	/*
	 * return the saved r12
	 */
	asm("	l	0, 48(12)");
	asm("	st	0, -4+$FP_len(13)");
	return fp;
}

int *
AP()
{
	int	*ap;
	ap = 0;

	/*
	 * return the saved r12
	 */
	asm("	l	0, 48(12)");
	asm("	st	0, -4+$AP_len(13)");
	return ap;
}

int *
TOP()
{
	int	*sp;
	sp = 0;

	/*
	 * return the saved r13
	 */

	asm("	l	0, 52(12)");
	asm("	st	0, -4+$TOP_len(13)");
	return sp;
}

void
set_r2(int*)
{
	asm("	l	2, 64(12)");		// get loc
	asm("	l	2, (2)");		// load r2 with contents
	asm("	st	2, 8(12)");		// overwrite save area
};

void
set_r3(int*)
{
	asm("	l	3, 64(12)");
	asm("	l	3, (3)");
	asm("	st	3, 12(12)");
}

void
set_r4(int*)
{
	asm("	l	4, 64(12)");
	asm("	l	4, (4)");
	asm("	st	4, 16(12)");
}

void
set_r5(int*)
{
	asm("	l	5, 64(12)");
	asm("	l	5, (5)");
	asm("	st	5, 20(12)");
}
void
set_r6(int*)
{
	asm("	l	6, 64(12)");
	asm("	l	6, (6)");
	asm("	st	6, 24(12)");
}

void
set_r7(int*)
{
	asm("	l	7, 64(12)");
	asm("	l	7, (7)");
	asm("	st	7, 28(12)");
};

void
set_r8(int*)
{
	asm("	l	8, 64(12)");
	asm("	l	8, (8)");
	asm("	st	8, 32(12)");
}

void
set_r9(int*)
{
	asm("	l	9, 64(12)");
	asm("	l	9, (9)");
	asm("	st	9, 36(12)");
}

void
set_r10(int*)
{
	asm("	l	10, 64(12)");
	asm("	l	10, (10)");
	asm("	st	10, 40(12)");
}

};

/*
 * saved_saved_regs copies regs saved in stack frame defined by fp
 * to a HW_REGS structure. Uses FrameLayout() to find which regs are saved.
 */
void
save_saved_regs(HW_REGS *regsp, int* fp)
{
	FrameLayout layout(fp);
	register int* p = FIRST_SAVED_REG_P(fp);
	register int* rp = (int*)regsp;
	register int r;

	for (r = 0; r < 16; r++, rp++, p++) {
		if (layout.begreg <= r && r <= layout.endreg) {
			*rp = *p;
		}
	}
}



#endif
« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: