/*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 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