diff options
Diffstat (limited to 'qt/md/axp.c')
-rw-r--r-- | qt/md/axp.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/qt/md/axp.c b/qt/md/axp.c new file mode 100644 index 000000000..26c15c0ea --- /dev/null +++ b/qt/md/axp.c @@ -0,0 +1,133 @@ +/* + * 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 <stdarg.h> +#include "qt.h" + + +/* Varargs is harder on the AXP. Parameters are saved on the stack as + something like (stack grows down to low memory; low at bottom of + picture): + + | : + | arg6 + +--- + | iarg5 + | : + | iarg3 <-- va_list._a0 + va_list._offset + | : + | iarg0 <-- va_list._a0 + +--- + | farg5 + | : + | farg0 + +--- + + When some of the arguments have known type, there is no need to + save all of them in the struct. So, for example, if the routine is + called + + zork (int a0, float a1, int a2, ...) + { + va_list ap; + va_start (ap, a2); + qt_vargs (... &ap ...); + } + + then offset is set to 3 * 8 (8 === sizeof machine word) = 24. + + What this means for us is that the user's routine needs to be + called with an arg list where some of the words in the `any type' + parameter list have to be split and moved up in to the int/fp + region. + + Ways in which this can fail: + - The user might not know the size of the pushed arguments anyway. + - Structures have funny promotion rules. + - Probably lots of other things. + + All in all, we never promised varargs would work reliably. */ + + + +#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE) + +#define QT_VARGS_MD0(sp, vabytes) \ + ((qt_t *)(((char *)(sp)) - 6*2*8 - QT_STKROUNDUP(vabytes))) + +extern void qt_vstart(void); +#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_R26, qt_vstart)) + + +/* Different machines use different implementations for varargs. + Unfortunately, the code below ``looks in to'' the varargs + structure, `va_list', and thus depends on the conventions. + The following #defines try to deal with it but don't catch + everything. */ + +#ifdef __GNUC__ +#define _a0 __base +#define _offset __offset +#else +#ifdef __OSF1__ +#define _a0 a0 +#define _offset offset +#endif +#endif /* def __GNUC__ */ + + + struct qt_t * +qt_vargs (struct qt_t *qsp, int nbytes, struct va_list *vargs, + void *pt, qt_function_t *startup, + qt_function_t *vuserf, qt_function_t *cleanup) +{ + va_list ap; + int i; + int max; /* Maximum *words* of args to copy. */ + int tmove; /* *Words* of args moved typed->typed. */ + qt_word_t *sp; + + ap = *(va_list *)vargs; + qsp = QT_VARGS_MD0 (qsp, nbytes); + sp = (qt_word_t *)qsp; + + tmove = 6 - ap._offset/sizeof(qt_word_t); + + /* Copy from one typed area to the other. */ + for (i=0; i<tmove; ++i) { + /* Integer args: */ + sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; + /* Fp args: */ + sp[i] = ((qt_word_t *)(ap._a0 + ap._offset))[i-6]; + } + + max = nbytes/sizeof(qt_word_t); + + /* Copy from the untyped area to the typed area. Split each arg. + in to integer and floating-point save areas. */ + for (; i<6 && i<max; ++i) { + sp[i] = sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; + } + + /* Copy from the untyped area to the other untyped area. */ + for (; i<max; ++i) { + sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i]; + } + + QT_VARGS_MD1 (QT_VADJ(sp)); + QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt); + QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup); + QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf); + QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup); + return ((qt_t *)QT_VADJ(sp)); +} |