0.9.2.49:
[sbcl.git] / src / runtime / mips-assem.S
1 #include "sbcl.h"
2 #include "lispregs.h"
3 #include "globals.h"
4 #include "genesis/fdefn.h"
5 #include "genesis/closure.h"
6 #include "genesis/return-pc.h"
7 #include "genesis/simple-fun.h"
8 #include "genesis/static-symbols.h"
9                 
10 #define zero $0
11 #define AT $1
12 #define v0 $2
13 #define v1 $3
14 #define a0 $4
15 #define a1 $5
16 #define a2 $6
17 #define a3 $7
18 #define t0 $8
19 #define t1 $9
20 #define t2 $10
21 #define t3 $11
22 #define t4 $12
23 #define t5 $13
24 #define t6 $14
25 #define t7 $15
26 #define s0 $16
27 #define s1 $17
28 #define s2 $18
29 #define s3 $19
30 #define s4 $20
31 #define s5 $21
32 #define s6 $22
33 #define s7 $23
34 #define t8 $24
35 #define t9 $25
36 #define k0 $26
37 #define k1 $27
38 #define gp $28
39 #define sp $29
40 #define s8 $30
41 #define ra $31
42
43 /*
44  * LEAF - declare leaf routine
45  */
46 #define LEAF(symbol)                                    \
47                 .globl  symbol;                         \
48                 .align  2;                              \
49                 .type   symbol,@function;               \
50                 .ent    symbol,0;                       \
51 symbol:         .frame  sp,0,ra
52
53 /*
54  * NESTED - declare nested routine entry point
55  */
56 #define NESTED(symbol, framesize, rpc)                  \
57                 .globl  symbol;                         \
58                 .align  2;                              \
59                 .type   symbol,@function;               \
60                 .ent    symbol,0;                       \
61 symbol:         .frame  sp, framesize, rpc
62
63 /*
64  * END - mark end of function
65  */
66 #define END(function)                                   \
67                 .end    function;                       \
68                 .size   function,.-function
69
70 /*
71  * EXPORT - export definition of symbol
72  */
73 #define EXPORT(symbol)                                  \
74                 .globl  symbol;                         \
75 symbol:
76
77 /*
78  * FEXPORT - export definition of a function symbol
79  */
80 #define FEXPORT(symbol)                                 \
81                 .globl  symbol;                         \
82                 .type   symbol,@function;               \
83 symbol:
84
85
86         .text
87         
88 /*
89  * Function to transfer control into lisp.
90  */
91 #define framesize 16*4
92         NESTED(call_into_lisp, framesize, ra)
93         .set    noreorder
94         .cpload t9
95         .set    reorder
96         subu    sp, framesize
97
98         /* Save all the C regs. */
99         .mask   0xc0ff0000, -8
100         sw      ra, framesize-8(sp)
101         sw      s8, framesize-12(sp)
102         /* No .cprestore, we don't want automatic gp restauration. */
103         sw      gp, framesize-16(sp)
104         sw      s7, framesize-20(sp)
105         sw      s6, framesize-24(sp)
106         sw      s5, framesize-28(sp)
107         sw      s4, framesize-32(sp)
108         sw      s3, framesize-36(sp)
109         sw      s2, framesize-40(sp)
110         sw      s1, framesize-44(sp)
111         sw      s0, framesize-48(sp)
112
113         li      reg_NIL, NIL
114
115         /* Clear unsaved boxed descriptor regs */
116         li      reg_FDEFN, 0            # t6
117         li      reg_L1, 0               # t8
118
119         /* Turn on pseudo-atomic. */
120         .set    noreorder
121         li      reg_NL4, 0
122         li      reg_ALLOC, 1
123         .set    reorder
124
125         /* Mark us as in Lisp land. */
126         sw      zero, foreign_function_call_active
127
128         /* Load the allocation pointer, preserving the low-bit of alloc */
129         lw      reg_BSP, dynamic_space_free_pointer
130         addu    reg_ALLOC, reg_BSP
131
132         /* Load the rest of the LISP state. */
133         lw      reg_BSP, current_binding_stack_pointer
134         lw      reg_CSP, current_control_stack_pointer
135         lw      reg_OCFP, current_control_frame_pointer
136
137         /* Check for interrupt */
138         .set    noreorder
139         bgez    reg_NL4, 1f
140          subu   reg_ALLOC, 1
141         break   0x10
142 1:      .set    reorder
143
144         /* Pass in args */
145         move    reg_LEXENV, a0
146         move    reg_CFP, a1
147         sll     reg_NARGS, a2, 2
148         lw      reg_A0, 0(reg_CFP)
149         lw      reg_A1, 4(reg_CFP)
150         lw      reg_A2, 8(reg_CFP)
151         lw      reg_A3, 12(reg_CFP)
152         lw      reg_A4, 16(reg_CFP)
153         lw      reg_A5, 20(reg_CFP)
154
155         /* Calculate LRA */
156         la      reg_LRA, lra - RETURN_PC_RETURN_POINT_OFFSET
157
158         /* Indirect closure */
159         lw      reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
160
161         /* Jump into lisp land. */
162         addu    reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
163         jr      reg_LIP
164
165         .align  2
166         .set    noreorder
167 lra:    .word   RETURN_PC_HEADER_WIDETAG
168
169         /* Multiple value return spot, clear stack. */
170         move    reg_CSP, reg_OCFP
171         nop
172
173         /* Single value return spot. */
174
175         /* Nested lisp -> C calls may have clobbered gp. */
176         lw      gp, framesize-16(sp)
177
178         /* Set the pseudo-atomic flag. */
179         li      reg_NL4, 0
180         addu    reg_ALLOC, 1
181         .set    reorder
182
183         /* Save LISP state. */
184         subu    reg_NL0, reg_ALLOC, 1
185         sw      reg_NL0, dynamic_space_free_pointer
186         sw      reg_BSP, current_binding_stack_pointer
187         sw      reg_CSP, current_control_stack_pointer
188         sw      reg_CFP, current_control_frame_pointer
189
190         /* Mark us as in C land. */
191         sw      reg_CSP, foreign_function_call_active
192
193         /* Check for interrupt */
194         .set    noreorder
195         bgez    reg_NL4, 1f
196          subu   reg_ALLOC, 1
197         break   0x10
198 1:      .set    reorder
199
200         /* Pass one return value back to C land. For a 64bit value, we may
201            need to clobber v1 aka reg_NL4. */
202         move    v0, reg_A0      # reg_CFUNC
203         move    v1, reg_A1      # reg_NL4
204
205         /* Restore C regs */
206         lw      ra, framesize-8(sp)
207         lw      s8, framesize-12(sp)
208         lw      s7, framesize-20(sp)
209         lw      s6, framesize-24(sp)
210         lw      s5, framesize-28(sp)
211         lw      s4, framesize-32(sp)
212         lw      s3, framesize-36(sp)
213         lw      s2, framesize-40(sp)
214         lw      s1, framesize-44(sp)
215         lw      s0, framesize-48(sp)
216
217         /* Restore C stack. */
218         addu    sp, framesize
219
220         /* Back we go. */
221         jr      ra
222
223         END(call_into_lisp)
224
225 /*
226  * Transfering control from Lisp into C
227  */
228         NESTED(call_into_c, 0, ra)
229         /* The C stack frame was already set up from lisp, and the
230            argument registers as well. We have to fake the correct
231            gp value for this function, though. */
232         .set    noreorder
233         /* reg_NL3 is AT. */
234         .set    noat
235         lui     gp, %hi(_gp_disp)
236         addiu   gp, %lo(_gp_disp)
237         lui     reg_NL3, %hi(call_into_c)
238         addiu   reg_NL3, %lo(call_into_c)
239         addu    gp, reg_NL3
240         .set    at
241         .set    reorder
242
243         move    reg_OCFP, reg_CFP
244         move    reg_CFP, reg_CSP
245         addu    reg_CSP, reg_CFP, 32
246
247         /* Set the pseudo-atomic flag. */
248         .set    noreorder
249         li      reg_NL4, 0
250         addu    reg_ALLOC, 1
251         .set    reorder
252
253         /* Convert the return address to an offset and save it on the stack. */
254         subu    reg_NFP, reg_LIP, reg_CODE
255         addu    reg_NFP, OTHER_POINTER_LOWTAG
256         sw      reg_NFP, (reg_CFP)
257         sw      reg_CODE, 4(reg_CFP)
258         sw      gp, 8(reg_CFP)
259
260         /* Save LISP state. */
261         subu    reg_A0, reg_ALLOC, 1
262         sw      reg_A0, dynamic_space_free_pointer
263         sw      reg_BSP, current_binding_stack_pointer
264         sw      reg_CSP, current_control_stack_pointer
265         sw      reg_CFP, current_control_frame_pointer
266
267         /* Mark us as in C land. */
268         sw      reg_CSP, foreign_function_call_active
269
270         /* Check for interrupt */
271         .set    noreorder
272         bgez    reg_NL4, 1f
273          subu   reg_ALLOC, 1
274         break   0x10
275 1:      .set    reorder
276
277         /* Into C land we go. */
278         move    t9, reg_CFUNC           # reg_ALLOC
279         jalr    t9
280
281         lw      gp, 8(reg_CFP)
282
283         /* Pass 64bit return value to lisp land. */ 
284         move    reg_NL0, v0             # reg_CFUNC
285         move    reg_NL1, v1             # reg_NL4
286
287         /* Clear unsaved boxed descriptor regs before allowing an interrupt */
288         li      reg_A0, 0               # t0
289         li      reg_A1, 0               # t1
290         li      reg_A2, 0               # t2
291         li      reg_A3, 0               # t3
292         li      reg_A4, 0               # t4
293         li      reg_A5, 0               # t5
294         li      reg_FDEFN, 0            # t6
295         li      reg_LEXENV, 0           # t7
296         li      reg_L1, 0               # t8
297         li      reg_LIP, 0              # ra
298
299         /* Turn on pseudo-atomic. */
300         .set    noreorder
301         li      reg_NL4, 0
302         li      reg_ALLOC, 1
303         .set    reorder
304
305         /* Mark us as in Lisp land. */
306         sw      zero, foreign_function_call_active
307
308         /* Load the allocation pointer, preserving the low-bit of alloc */
309         lw      reg_BSP, dynamic_space_free_pointer
310         addu    reg_ALLOC, reg_BSP
311
312         lw      reg_BSP, current_binding_stack_pointer
313
314         /* Restore LRA & CODE */
315         lw      reg_LIP, (reg_CFP)
316         lw      reg_CODE, 4(reg_CFP)
317         subu    reg_LIP, OTHER_POINTER_LOWTAG
318         addu    reg_LIP, reg_CODE
319
320         /* Check for interrupt */
321         .set    noreorder
322         bgez    reg_NL4, 1f
323          subu   reg_ALLOC, 1
324         break   0x10
325 1:      .set    reorder
326
327         /* Reset the lisp stack. */
328         /* Note: OCFP and CFP are in saved regs. */
329         move    reg_CSP, reg_CFP
330         move    reg_CFP, reg_OCFP
331
332         /* Return to LISP. */
333         jr      reg_LIP
334         END(call_into_c)
335
336 /*
337  * Trampolines follow the Lisp calling convention.
338  *
339  * The undefined-function trampoline.
340  */
341         .align  2
342         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
343         .word   undefined_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
344         .word   NIL /* next */
345         .word   NIL /* name */
346         .word   NIL /* arglist */
347         .word   NIL /* type */
348         LEAF(undefined_tramp)
349         break   trap_Error
350         .byte   4
351         .byte   UNDEFINED_FUN_ERROR
352         .byte   254
353         .byte   (0xc0 + sc_DescriptorReg)
354         .byte   1
355         .align  2
356         END(undefined_tramp)
357
358 /*
359  * The closure trampoline.
360  */
361         .align  2
362         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
363         .word   closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
364         .word   NIL /* next */
365         .word   NIL /* name */
366         .word   NIL /* arglist */
367         .word   NIL /* type */
368         LEAF(closure_tramp)
369         lw      reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
370         lw      reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
371         addu    reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
372         jr      reg_LIP
373         END(closure_tramp)
374
375 /*
376  * Function-end breakpoint magic.
377  */
378         .align  3
379         LEAF(fun_end_breakpoint_guts)
380         .set    noreorder
381         .word   RETURN_PC_HEADER_WIDETAG
382
383         b       multiple_value_return
384          nop
385         .set    reorder
386
387         move    reg_OCFP, reg_CSP
388         addu    reg_CSP, 4
389         li      reg_NARGS, 4
390         move    reg_A1, reg_NIL
391         move    reg_A2, reg_NIL
392         move    reg_A3, reg_NIL
393         move    reg_A4, reg_NIL
394         move    reg_A5, reg_NIL
395
396 multiple_value_return:
397
398         FEXPORT(fun_end_breakpoint_trap)
399         break   trap_FunEndBreakpoint
400         b       multiple_value_return
401         EXPORT(fun_end_breakpoint_end)
402         END(fun_end_breakpoint_guts)