1/*
2 * QuickThreads -- Threads-building toolkit.
3 * Copyright (c) 1993 by David Keppel
4 *
5 * Permission to use, copy, modify and distribute this software and
6 * its documentation for any purpose and without fee is hereby
7 * granted, provided that the above copyright notice and this notice
8 * appear in all copies.  This software is provided as a
9 * proof-of-concept and for demonstration purposes; there is no
10 * representation about the suitability of this software for any
11 * purpose.
12 */
13
14#ifndef QUICKTHREADS_VAX_H
15#define QUICKTHREADS_VAX_H
16
17typedef unsigned long qt_word_t;
18
19/* Thread's initial stack layout on the VAX:
20
21   non-varargs:
22
23   +---
24   | arg[2]	=== `userf' on startup
25   | arg[1]	=== `pt' on startup
26   | arg[0]	=== `pu' on startup
27   | ...	=== `only' on startup.
28   +---
29   | ret pc	=== `qt_start' on startup
30   | fp		=== 0 on startup
31   | ap		=== 0 on startup
32   | <mask>
33   | 0 (handler)			<--- qt_t.sp
34   +---
35
36   When a non-varargs thread is started, it ``returns'' to the start
37   routine, which calls the client's `only' function.
38
39   The varargs case is clearly bad code.  The various values should be
40   stored in a save area and snarfed in to callee-save registers on
41   startup.  However, it's too painful to figure out the register
42   mask (right now), so do it the slow way.
43
44   +---
45   | arg[n-1]
46   | ..
47   | arg[0]
48   | nargs
49   +---
50   |		=== `cleanup'
51   |		=== `vuserf'
52   |		=== `startup'
53   |		=== `pt'
54   +---
55   | ret pc	=== `qt_start' on startup
56   | fp		=== 0 on startup
57   | ap		=== 0 on startup
58   | <mask>
59   | 0 (handler)			<--- qt_t.sp
60   +---
61
62   When a varargs thread is started, it ``returns'' to the `qt_vstart'
63   startup code.  The startup code pops all the extra arguments, then
64   calls the appropriate functions. */
65
66
67/* What to do to start a thread running. */
68extern void qt_start (void);
69extern void qt_vstart (void);
70
71
72/* Initial call frame for non-varargs and varargs cases. */
73#define QUICKTHREADS_STKBASE	(10 * 4)
74#define QUICKTHREADS_VSTKBASE	(9 * 4)
75
76
77/* Stack "must be" 4-byte aligned.  (Actually, no, but it's
78   easiest and probably fastest to do so.) */
79
80#define QUICKTHREADS_STKALIGN	(4)
81
82
83/* Where to place various arguments. */
84#define QUICKTHREADS_ONLY_INDEX	(5)
85#define QUICKTHREADS_USER_INDEX	(8)
86#define QUICKTHREADS_ARGT_INDEX	(7)
87#define QUICKTHREADS_ARGU_INDEX	(6)
88
89#define QUICKTHREADS_VSTARTUP_INDEX	(6)
90#define QUICKTHREADS_VUSERF_INDEX		(7)
91#define QUICKTHREADS_VCLEANUP_INDEX	(8)
92#define QUICKTHREADS_VARGT_INDEX		(5)
93
94
95/* Stack grows down.  The top of the stack is the first thing to
96   pop off (predecrement, postincrement). */
97#define QUICKTHREADS_GROW_DOWN
98
99
100extern void qt_error (void);
101
102#define QUICKTHREADS_VAX_GMASK_NOREGS	(0)
103
104/* Push on the error return address, null termination to call chains,
105   number of arguments to `only', register save mask (save no
106   registers). */
107
108#define QUICKTHREADS_ARGS_MD(sto) \
109    (QUICKTHREADS_SPUT (sto, 0, 0), \
110     QUICKTHREADS_SPUT (sto, 1, QUICKTHREADS_VAX_GMASK_NOREGS), \
111     QUICKTHREADS_SPUT (sto, 2, 0), \
112     QUICKTHREADS_SPUT (sto, 3, 0), \
113     QUICKTHREADS_SPUT (sto, 4, qt_start))
114
115#define QUICKTHREADS_VARGS_MD0(sto, nbytes) \
116    (QUICKTHREADS_SPUT (sto, (-(nbytes)/4)-1, (nbytes)/4), \
117     ((char *)(((sto)-4) - QUICKTHREADS_STKROUNDUP(nbytes))))
118
119#define QUICKTHREADS_VARGS_ADJUST(sp)	((char *)sp + 4)
120
121#define QUICKTHREADS_VARGS_MD1(sto) \
122    (QUICKTHREADS_SPUT (sto, 0, 0), \
123     QUICKTHREADS_SPUT (sto, 1, QUICKTHREADS_VAX_GMASK_NOREGS), \
124     QUICKTHREADS_SPUT (sto, 2, 0), \
125     QUICKTHREADS_SPUT (sto, 3, 0), \
126     QUICKTHREADS_SPUT (sto, 4, qt_vstart))
127
128#define QUICKTHREADS_VARGS_DEFAULT
129
130#endif /* QUICKTHREADS_VAX_H */
131