]> git.donarmstrong.com Git - lilypond.git/blobdiff - guile18/qt/md/_sparc.s
Import guile-1.8 as multiple upstream tarball component
[lilypond.git] / guile18 / qt / md / _sparc.s
diff --git a/guile18/qt/md/_sparc.s b/guile18/qt/md/_sparc.s
new file mode 100644 (file)
index 0000000..1d8adc7
--- /dev/null
@@ -0,0 +1,142 @@
+/* sparc.s -- assembly support for the `qt' thread building kit. */
+
+/*
+ * QuickThreads -- Threads-building toolkit.
+ * Copyright (c) 1993 by David Keppel
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice and this notice
+ * appear in all copies.  This software is provided as a
+ * proof-of-concept and for demonstration purposes; there is no
+ * representation about the suitability of this software for any
+ * purpose.
+ */
+
+/* #include <machine/trap.h> */
+
+       .text
+       .align 4
+       .global _qt_blocki
+       .global _qt_block
+       .global _qt_abort
+       .global _qt_start
+       .global _qt_vstart
+
+/* Register assignment:
+// %o0:        incoming `helper' function to call after cswap
+//     also used as outgoing sp of old thread (qt_t *)
+// %o1, %o2:
+//     parameters to `helper' function called after cswap
+// %o3:        sp of new thread
+// %o5: tmp used to save old thread sp, while using %o0
+//     to call `helper' f() after cswap.
+//
+//
+// Aborting a thread is easy if there are no cached register window
+// frames: just switch to the new stack and away we go.  If there are
+// cached register window frames they must all be written back to the
+// old stack before we move to the new stack.  If we fail to do the
+// writeback then the old stack memory can be written with register
+// window contents e.g., after the stack memory has been freed and
+// reused.  
+//
+// If you don't believe this, try setting the frame pointer to zero
+// once we're on the new stack.  This will not affect correctnes
+// otherwise because the frame pointer will eventually get reloaded w/
+// the new thread's frame pointer.  But it will be zero briefly before
+// the reload.  You will eventually (100,000 cswaps later on a small
+// SPARC machine that I tried) get an illegal instruction trap  from
+// the kernel trying to flush a cached window to location 0x0.
+//
+// Solution: flush windows before switching stacks, which invalidates
+// all the other register windows.  We could do the trap
+// conditionally: if we're in the lowest frame of a thread, the fp is
+// zero already so we know there's nothing cached.  But we expect most
+// aborts will be done from a first function that does a `save', so we
+// will rarely save anything and always pay the cost of testing to see
+// if we should flush.
+//
+// All floating-point registers are caller-save, so this routine
+// doesn't need to do anything to save and restore them.
+//
+// `qt_block' and `qt_blocki' return the same value as the value
+// returned by the helper function.  We get this ``for free''
+// since we don't touch the return value register between the
+// return from the helper function and return from qt_block{,i}.
+*/
+
+_qt_block:
+_qt_blocki:
+       sub %sp, 8, %sp         /* Allocate save area for return pc. */
+       st %o7, [%sp+64]        /* Save return pc. */
+_qt_abort:
+       ta 0x03                 /* Save locals and ins. */
+       mov %sp, %o5            /* Remember old sp w/o chng ins/locals. */
+       sub %o3, 64, %sp        /* Allocate kwsa, switch stacks. */
+       call %o0, 0             /* Call `helper' routine. */
+       mov %o5, %o0            /* Pass old thread to qt_after_t() */
+                               /* .. along w/ args in %o1 & %o2. */
+
+       /* Restore callee-save regs.  The kwsa
+       // is on this stack, so offset all
+       // loads by sizeof(kwsa), 64 bytes.
+       */
+       ldd [%sp+ 0+64], %l0
+       ldd [%sp+ 8+64], %l2
+       ldd [%sp+16+64], %l4
+       ldd [%sp+24+64], %l6
+       ldd [%sp+32+64], %i0
+       ldd [%sp+40+64], %i2
+       ldd [%sp+48+64], %i4
+       ldd [%sp+56+64], %i6
+       ld [%sp+64+64], %o7     /* Restore return pc. */
+
+       retl                    /* Return to address in %o7. */
+       add %sp, 72, %sp        /* Deallocate kwsa, ret pc area. */
+
+
+/* The function calling conventions say there has to be a 1-word area
+// in the caller's stack to hold a pointer to space for aggregate
+// return values.  It also says there should be a 6-word area to hold
+// %o0..%o5 if the callee wants to save them (why?  I don't know...)
+// Round up to 8 words to maintain alignment.
+//
+// Parameter values were stored in callee-save regs and are moved to
+// the parameter registers.
+*/
+_qt_start:
+       mov %i1, %o0            /* `pu': Set up args to `only'. */
+       mov %i2, %o1            /* `pt'. */
+       mov %i4, %o2            /* `userf'. */
+       call %i5, 0             /* Call client function. */
+       sub %sp, 32, %sp        /* Allocate 6-word callee space. */
+
+       call _qt_error, 0       /* `only' erroniously returned. */
+       nop
+
+
+/* Same comments as `_qt_start' about allocating rounded-up 7-word
+// save areas. */
+
+_qt_vstart:
+       sub %sp, 32, %sp        /* Allocate 7-word callee space. */
+       call %i5, 0             /* call `startup'. */
+       mov %i2, %o0            /* .. with argument `pt'. */
+
+       add %sp, 32, %sp        /* Use 7-word space in varargs. */
+       ld [%sp+ 4+64], %o0     /* Load arg0 ... */
+       ld [%sp+ 8+64], %o1
+       ld [%sp+12+64], %o2
+       ld [%sp+16+64], %o3
+       ld [%sp+20+64], %o4
+       call %i4, 0             /* Call `userf'. */
+       ld [%sp+24+64], %o5
+
+                               /* Use 6-word space in varargs. */
+       mov %o0, %o1            /* Pass return value from userf */
+       call %i3, 0             /* .. when call `cleanup. */
+       mov %i2, %o0            /* .. along with argument `pt'. */
+
+       call _qt_error, 0       /* `cleanup' erroniously returned. */
+       nop