Commit | Line | Data |
---|---|---|
24a647d7 MD |
1 | /* mips.s -- assembly support. */ |
2 | ||
3 | /* | |
4 | * QuickThreads -- Threads-building toolkit. | |
5 | * Copyright (c) 1993 by David Keppel | |
6 | * | |
7 | * Permission to use, copy, modify and distribute this software and | |
8 | * its documentation for any purpose and without fee is hereby | |
9 | * granted, provided that the above copyright notice and this notice | |
10 | * appear in all copies. This software is provided as a | |
11 | * proof-of-concept and for demonstration purposes; there is no | |
12 | * representation about the suitability of this software for any | |
13 | * purpose. | |
14 | */ | |
15 | ||
16 | /* Callee-save $16-$23, $30-$31. | |
17 | * | |
18 | * $25 is used as a procedure value pointer, used to discover constants | |
19 | * in a callee. Thus, each caller here sets $25 before the call. | |
20 | * | |
21 | * On startup, restore regs so retpc === call to a function to start. | |
22 | * We're going to call a function ($4) from within this routine. | |
23 | * We're passing 3 args, therefore need to allocate 12 extra bytes on | |
24 | * the stack for a save area. The start routine needs a like 16-byte | |
25 | * save area. Must be doubleword aligned (_mips r3000 risc | |
26 | * architecture_, gerry kane, pg d-23). | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Modified by Assar Westerlund <assar@sics.se> to support Irix 5.x | |
31 | * calling conventions for dynamically-linked code. | |
32 | */ | |
33 | ||
34 | /* Make this position-independent code. */ | |
35 | .option pic2 | |
36 | ||
37 | .globl qt_block | |
38 | .globl qt_blocki | |
39 | .globl qt_abort | |
40 | .globl qt_start | |
41 | .globl qt_vstart | |
42 | ||
43 | /* | |
44 | ** $4: ptr to function to call once curr is suspended | |
45 | ** and control is on $7's stack. | |
46 | ** $5: 1'th arg to $4. | |
47 | ** $6: 2'th arg to $4 | |
48 | ** $7: sp of thread to suspend. | |
49 | ** | |
50 | ** Totally gross hack: The MIPS calling convention reserves | |
51 | ** 4 words on the stack for a0..a3. This routine "ought" to | |
52 | ** allocate space for callee-save registers plus 4 words for | |
53 | ** the helper function, but instead we use the 4 words | |
54 | ** provided by the function that called us (we don't need to | |
55 | ** save our argument registers). So what *appears* to be | |
56 | ** allocating only 40 bytes is actually allocating 56, by | |
57 | ** using the caller's 16 bytes. | |
58 | ** | |
59 | ** The helper routine returns a value that is passed on as the | |
60 | ** return value from the blocking routine. Since we don't | |
61 | ** touch $2 between the helper's return and the end of | |
62 | ** function, we get this behavior for free. | |
63 | */ | |
64 | qt_blocki: | |
65 | sub $sp,$sp,40 /* Allocate reg save space. */ | |
66 | sw $16, 0+16($sp) | |
67 | sw $17, 4+16($sp) | |
68 | sw $18, 8+16($sp) | |
69 | sw $19,12+16($sp) | |
70 | sw $20,16+16($sp) | |
71 | sw $21,20+16($sp) | |
72 | sw $22,24+16($sp) | |
73 | sw $23,28+16($sp) | |
74 | sw $30,32+16($sp) | |
75 | sw $31,36+16($sp) | |
76 | add $2, $sp,$0 /* $2 <= old sp to pass to func@$4. */ | |
77 | qt_abort: | |
78 | add $sp, $7,$0 /* $sp <= new sp. */ | |
79 | .set noreorder | |
80 | add $25, $4,$0 /* Set helper function procedure value. */ | |
81 | jal $31,$25 /* Call helper func@$4 . */ | |
82 | add $4, $2,$0 /* $a0 <= pass old sp as a parameter. */ | |
83 | .set reorder | |
84 | lw $31,36+16($sp) /* Restore callee-save regs... */ | |
85 | lw $30,32+16($sp) | |
86 | lw $23,28+16($sp) | |
87 | lw $22,24+16($sp) | |
88 | lw $21,20+16($sp) | |
89 | lw $20,16+16($sp) | |
90 | lw $19,12+16($sp) | |
91 | lw $18, 8+16($sp) | |
92 | lw $17, 4+16($sp) | |
93 | lw $16, 0+16($sp) /* Restore callee-save */ | |
94 | ||
95 | add $sp,$sp,40 /* Deallocate reg save space. */ | |
96 | j $31 /* Return to caller. */ | |
97 | ||
98 | /* | |
99 | ** Non-varargs thread startup. | |
100 | ** Note: originally, 56 bytes were allocated on the stack. | |
101 | ** The thread restore routine (_blocki/_abort) removed 40 | |
102 | ** of them, which means there is still 16 bytes for the | |
103 | ** argument area required by the MIPS calling convention. | |
104 | */ | |
105 | qt_start: | |
106 | add $4, $16,$0 /* Load up user function pu. */ | |
107 | add $5, $17,$0 /* ... user function pt. */ | |
108 | add $6, $18,$0 /* ... user function userf. */ | |
109 | add $25, $19,$0 /* Set `only' procedure value. */ | |
110 | jal $31,$25 /* Call `only'. */ | |
111 | la $25,qt_error /* Set `qt_error' procedure value. */ | |
112 | j $25 | |
113 | ||
114 | ||
115 | /* | |
116 | ** Save calle-save floating-point regs $f20-$f30 | |
117 | ** See comment in `qt_block' about calling conventinos and | |
118 | ** reserved space. Use the same trick here, but here we | |
119 | ** actually have to allocate all the bytes since we have to | |
120 | ** leave 4 words leftover for `qt_blocki'. | |
121 | ** | |
122 | ** Return value from `qt_block' is the same as the return from | |
123 | ** `qt_blocki'. We get that for free since we don't touch $2 | |
124 | ** between the return from `qt_blocki' and the return from | |
125 | ** `qt_block'. | |
126 | */ | |
127 | qt_block: | |
128 | sub $sp, $sp,56 /* 6 8-byte regs, saved ret pc, aligned. */ | |
129 | swc1 $f20, 0+16($sp) | |
130 | swc1 $f22, 8+16($sp) | |
131 | swc1 $f24, 16+16($sp) | |
132 | swc1 $f26, 24+16($sp) | |
133 | swc1 $f28, 32+16($sp) | |
134 | swc1 $f30, 40+16($sp) | |
135 | sw $31, 48+16($sp) | |
136 | jal qt_blocki | |
137 | lwc1 $f20, 0+16($sp) | |
138 | lwc1 $f22, 8+16($sp) | |
139 | lwc1 $f24, 16+16($sp) | |
140 | lwc1 $f26, 24+16($sp) | |
141 | lwc1 $f28, 32+16($sp) | |
142 | lwc1 $f30, 40+16($sp) | |
143 | lw $31, 48+16($sp) | |
144 | add $sp, $sp,56 | |
145 | j $31 | |
146 | ||
147 | ||
148 | /* | |
149 | ** First, call `startup' with the `pt' argument. | |
150 | ** | |
151 | ** Next, call the user's function with all arguments. | |
152 | ** Note that we don't know whether args were passed in | |
153 | ** integer regs, fp regs, or on the stack (See Gerry Kane | |
154 | ** "MIPS R2000 RISC Architecture" pg D-22), so we reload | |
155 | ** all the registers, possibly with garbage arguments. | |
156 | ** | |
157 | ** Finally, call `cleanup' with the `pt' argument and with | |
158 | ** the return value from the user's function. It is an error | |
159 | ** for `cleanup' to return. | |
160 | */ | |
161 | qt_vstart: | |
162 | add $4, $17,$0 /* `pt' is arg0 to `startup'. */ | |
163 | add $25, $18,$0 /* Set `startup' procedure value. */ | |
164 | jal $31, $25 /* Call `startup'. */ | |
165 | ||
166 | add $sp, $sp,16 /* Free extra save space. */ | |
167 | lw $4, 0($sp) /* Load up args. */ | |
168 | lw $5, 4($sp) | |
169 | lw $6, 8($sp) | |
170 | lw $7, 12($sp) | |
171 | lwc1 $f12, 0($sp) /* Load up fp args. */ | |
172 | lwc1 $f14, 8($sp) | |
173 | add $25, $19,$0 /* Set `userf' procedure value. */ | |
174 | jal $31,$25 /* Call `userf'. */ | |
175 | ||
176 | add $4, $17,$0 /* `pt' is arg0 to `cleanup'. */ | |
177 | add $5, $2,$0 /* Ret. val is arg1 to `cleanup'. */ | |
178 | add $25, $16,$0 /* Set `cleanup' procedure value. */ | |
179 | jal $31, $25 /* Call `cleanup'. */ | |
180 | ||
181 | la $25,qt_error /* Set `qt_error' procedure value. */ | |
182 | j $25 |