/* encore.s -- Encore Multimax (NS32032) assembly code * * (This should also work for other NS32000 machines if they use the same * calling sequence and register conventions.) * * An Encore context array is laid out like this: * * saved sp register -------------------------| * saved fp register | * magic word for checking integrity | * unused stack space | * stack frame for continuing execution <--- saved sp,fp points here * current stack data, if any * stack frame for error handler in case of erroneous return * arguments from mpd_build_context call * * General registers 3-7 are saved in the stack frame when changing context, * along with fp and pc. We don't save r0-r2 because C doesn't expect * them to survive a function call. * Save both sp and fp so can use exit instruction. * note: I'm sure someone with an NS32000 manual could code this much better. */ #define MAGIC 618033989 /* any unlikely long integer */ #define REGS r3,r4,r5,r6,r7 /* registers C expects to survive call */ .data curr_stack: /* saves addr of current context (stack) */ .double dummy_stack dummy_stack: /* fake initial context */ .double -1 /* this sp should never be restored */ .double -1 /* this fp should never be restored */ .double MAGIC .text .align 1 /* mpd_build_context(code,stack,stksize,arg1,arg2,arg3,arg4) * -- create a new context. * * code is the entry point of the code to be executed in the context. * stack is a buffer for holding the stack. * stksize is the size of this buffer. * arg1-4 are the arguments. */ .globl _mpd_build_context _mpd_build_context: enter [],$0 /* save no registers */ sprd sp,r1 /* r1 = current sp */ movd 12(fp),r0 addd 16(fp),r0 /* r0 = end of stack */ lprd sp,r0 /* use sp to build stack buffer */ /* copy the arguments into the stack buffer */ movd 32(fp),tos movd 28(fp),tos movd 24(fp),tos movd 20(fp),tos /* build a stack frame to catch (invalid) return from code */ addr under,tos /* pc points to underflow handler */ /* build another stack frame to "return" to the given entry point */ movd 8(fp),tos /* pc = entry point */ movd $0,tos /* unused fp */ sprd sp,r0 /* save the sp for below */ save [REGS] /* save registers in user context block */ /* save pointers, and also magic word for detecting underflow */ movd 12(fp),r2 /* r2 = beginning of stack buffer */ sprd sp,0(r2) /* save pointer to new frame we just made */ movd r0,4(r2) /* save pointer to new frame we just made */ movd $MAGIC,8(r2) /* store magic word for checking integrity */ lprd sp,r1 /* restore our stack pointer */ exit [] ret $0 /* return */ /* mpd_chg_context(newstack) -- switch context to the specified stack */ .globl _mpd_chg_context _mpd_chg_context: enter [REGS],$0 /* save the registers C assumes are preserved */ /* fp is saved first */ movd curr_stack,r1 /* r1 = old stack */ movd 8(fp),r2 /* r2 = new stack */ movd r2,curr_stack /* save for next switch */ sprd sp,r0 cmpd r0,r1 /* catch current stack overflow */ bls over cmpd $MAGIC,8(r1) /* catch earlier overflow (maybe) */ bne over cmpd $MAGIC,8(r2) /* check that new stack looks okay */ bne bad sprd sp,0(r1) /* save old sp */ sprd fp,4(r1) /* save old fp */ lprd sp,0(r2) /* set sp for new context */ lprd fp,4(r2) /* set fp for new context */ exit [REGS] ret $0 /* return into new context */ /* mpd_check_stk() -- check that the stack is not overflowing */ .globl _mpd_check_stk _mpd_check_stk: sprd sp,r0 cmpd r0,curr_stack bls over ret $0 /* stack problem handlers (these calls do not return) */ over: bsr ?_mpd_stk_overflow under: bsr ?_mpd_stk_underflow bad: bsr ?_mpd_stk_corrupted