4be362842b4f2218a0cc2c04ad7d2cbe76a48364
[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         /* Load the allocation pointer, preserving the low-bit of alloc */
126         lw      reg_BSP, dynamic_space_free_pointer
127         addu    reg_ALLOC, reg_BSP
128
129         /* Load the rest of the LISP state. */
130         lw      reg_BSP, current_binding_stack_pointer
131         lw      reg_CSP, current_control_stack_pointer
132         lw      reg_OCFP, current_control_frame_pointer
133
134         /* Check for interrupt */
135         .set    noreorder
136         bgez    reg_NL4, 1f
137          subu   reg_ALLOC, 1
138         break   0x0, 0x10
139 1:      .set    reorder
140
141         /* Pass in args */
142         move    reg_LEXENV, a0
143         move    reg_CFP, a1
144         sll     reg_NARGS, a2, 2
145         lw      reg_A0, 0(reg_CFP)
146         lw      reg_A1, 4(reg_CFP)
147         lw      reg_A2, 8(reg_CFP)
148         lw      reg_A3, 12(reg_CFP)
149         lw      reg_A4, 16(reg_CFP)
150         lw      reg_A5, 20(reg_CFP)
151
152         /* Calculate LRA */
153         la      reg_LRA, lra - RETURN_PC_RETURN_POINT_OFFSET
154
155         /* Indirect closure */
156         lw      reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
157
158         addu    reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
159
160         /* Mark us as in Lisp land. */
161         sw      zero, foreign_function_call_active
162
163         /* Jump into lisp land. */
164         jr      reg_LIP
165
166         .align  3
167         .set    noreorder
168 lra:    .word   RETURN_PC_HEADER_WIDETAG
169
170         /* Multiple value return spot, clear stack. */
171         move    reg_CSP, reg_OCFP
172         nop
173
174         /* Single value return spot. */
175
176         /* Nested lisp -> C calls may have clobbered gp. */
177         lw      gp, framesize-16(sp)
178
179         /* Set the pseudo-atomic flag. */
180         li      reg_NL4, 0
181         addu    reg_ALLOC, 1
182         .set    reorder
183
184         /* Mark us as in C land. */
185         sw      reg_CSP, foreign_function_call_active
186
187         /* Save LISP state. */
188         subu    reg_NL0, reg_ALLOC, 1
189         sw      reg_NL0, dynamic_space_free_pointer
190         sw      reg_BSP, current_binding_stack_pointer
191         sw      reg_CSP, current_control_stack_pointer
192         sw      reg_CFP, current_control_frame_pointer
193
194         /* Check for interrupt */
195         .set    noreorder
196         bgez    reg_NL4, 1f
197          subu   reg_ALLOC, 1
198         break   0x0, 0x10
199 1:      .set    reorder
200
201         /* Pass one return value back to C land. For a 64bit value, we may
202            need to clobber v1 aka reg_NL4. */
203         move    v0, reg_A0      # reg_CFUNC
204         move    v1, reg_A1      # reg_NL4
205
206         /* Restore C regs */
207         lw      ra, framesize-8(sp)
208         lw      s8, framesize-12(sp)
209         lw      s7, framesize-20(sp)
210         lw      s6, framesize-24(sp)
211         lw      s5, framesize-28(sp)
212         lw      s4, framesize-32(sp)
213         lw      s3, framesize-36(sp)
214         lw      s2, framesize-40(sp)
215         lw      s1, framesize-44(sp)
216         lw      s0, framesize-48(sp)
217
218         /* Restore C stack. */
219         addu    sp, framesize
220
221         /* Back we go. */
222         jr      ra
223
224         END(call_into_lisp)
225
226 /*
227  * Transfering control from Lisp into C
228  */
229         NESTED(call_into_c, 0, ra)
230         /* The C stack frame was already set up from lisp, and the
231            argument registers as well. We have to fake the correct
232            gp value for this function, though. */
233         .set    noreorder
234         /* reg_NL3 is AT. */
235         .set    noat
236         lui     gp, %hi(_gp_disp)
237         addiu   gp, %lo(_gp_disp)
238         lui     reg_NL3, %hi(call_into_c)
239         addiu   reg_NL3, %lo(call_into_c)
240         addu    gp, reg_NL3
241         .set    at
242         .set    reorder
243
244         /* Setup the lisp stack. */
245         move    reg_OCFP, reg_CFP
246         move    reg_CFP, reg_CSP
247         addu    reg_CSP, reg_CFP, 32
248
249         /* Set the pseudo-atomic flag. */
250         .set    noreorder
251         li      reg_NL4, 0
252         addu    reg_ALLOC, 1
253         .set    reorder
254
255         /* Mark us as in C land. */
256         sw      reg_CSP, foreign_function_call_active
257
258         /* Convert the return address to an offset and save it on the stack. */
259         subu    reg_NFP, reg_LIP, reg_CODE
260         addu    reg_NFP, OTHER_POINTER_LOWTAG
261         sw      reg_LRA, (reg_CFP)
262         sw      reg_CODE, 4(reg_CFP)
263         sw      gp, 8(reg_CFP)
264
265         /* Save LISP state. */
266         subu    reg_A0, reg_ALLOC, 1
267         sw      reg_A0, dynamic_space_free_pointer
268         sw      reg_BSP, current_binding_stack_pointer
269         sw      reg_CSP, current_control_stack_pointer
270         sw      reg_CFP, current_control_frame_pointer
271
272         /* Check for interrupt */
273         .set    noreorder
274         bgez    reg_NL4, 1f
275          subu   reg_ALLOC, 1
276         break   0x0, 0x10
277 1:      .set    reorder
278
279         /* Into C land we go. */
280         move    t9, reg_CFUNC           # reg_ALLOC
281         jalr    t9
282
283         lw      gp, 8(reg_CFP)
284
285         /* Pass 64bit return value to lisp land. */ 
286         move    reg_NL0, v0             # reg_CFUNC
287         move    reg_NL1, v1             # reg_NL4
288
289         /*
290          * Clear boxed descriptor registers before allowing an interrupt.
291          * We can't rely on C saving some of those registers, they might
292          * have been GCed in the meanwhile.
293          */
294         li      reg_A0, 0               # t0
295         li      reg_A1, 0               # t1
296         li      reg_A2, 0               # t2
297         li      reg_A3, 0               # t3
298         li      reg_A4, 0               # t4
299         li      reg_A5, 0               # t5
300         li      reg_FDEFN, 0            # t6
301         li      reg_LEXENV, 0           # t7
302         /*
303          * reg_NFP and reg_OCFP are pointing to fixed locations and are
304          * preserved by C.
305          */
306         li      reg_LRA, 0              # s2
307         li      reg_L0, 0               # s3
308         li      reg_L1, 0               # t8
309         li      reg_CODE, 0             # s8
310         li      reg_LIP, 0              # ra
311
312         /* Turn on pseudo-atomic. */
313         .set    noreorder
314         li      reg_NL4, 0
315         li      reg_ALLOC, 1
316         .set    reorder
317
318         /* Load the allocation pointer, preserving the low-bit of alloc */
319         lw      reg_BSP, dynamic_space_free_pointer
320         addu    reg_ALLOC, reg_BSP
321
322         lw      reg_BSP, current_binding_stack_pointer
323
324         /* Restore LRA & CODE */
325         lw      reg_LRA, (reg_CFP)
326         lw      reg_CODE, 4(reg_CFP)
327         subu    reg_LIP, reg_NFP, OTHER_POINTER_LOWTAG
328         addu    reg_LIP, reg_CODE
329
330         /* Check for interrupt */
331         .set    noreorder
332         bgez    reg_NL4, 1f
333          subu   reg_ALLOC, 1
334         break   0x0, 0x10
335 1:      .set    reorder
336
337         /* Reset the lisp stack. */
338         /* Note: OCFP and CFP are in saved regs. */
339         move    reg_CSP, reg_CFP
340         move    reg_CFP, reg_OCFP
341
342         /* Mark us as in Lisp land. */
343         sw      zero, foreign_function_call_active
344
345         /* Return to LISP. */
346         jr      reg_LIP
347         END(call_into_c)
348
349 /*
350  * Trampolines follow the Lisp calling convention.
351  *
352  * The undefined-function trampoline.
353  */
354         .align  3 /* minimum alignment for a lisp object */
355         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
356         .word   undefined_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
357         .word   NIL /* next */
358         .word   NIL /* name */
359         .word   NIL /* arglist */
360         .word   NIL /* type */
361         LEAF(undefined_tramp)
362         /* Point reg_CODE to the header and tag it as function, since
363            the debugger regards a function pointer in reg_CODE which
364            doesn't point to a code object as undefined function.  */
365         lui     reg_CODE, %hi(undefined_tramp)
366         addiu   reg_CODE, %lo(undefined_tramp)
367         addiu   reg_CODE, - 24 + FUN_POINTER_LOWTAG
368         .set    noreorder
369         b       1f
370          break  0x0, trap_Cerror
371         /* Error data length. */
372         .byte   4
373         /* Error number. */
374         .byte   UNDEFINED_FUN_ERROR
375         /* Magic value 254 means a 16bit little endian value follows.
376            See debug-var-io.lisp. */
377         .byte   254
378         /* reg_FDEFN is #14. */
379         .byte   ((14 << 5) + sc_DescriptorReg) % 0x100
380         .byte   ((14 << 5) + sc_DescriptorReg) / 0x100
381         .align  2
382         .set    reorder
383 1:      lw      reg_CODE, FDEFN_FUN_OFFSET(reg_FDEFN)
384         lw      reg_LIP, SIMPLE_FUN_CODE_OFFSET(reg_CODE)
385         jr      reg_LIP
386         END(undefined_tramp)
387
388 /*
389  * The closure trampoline.
390  */
391         .align  5 /* common MIPS cacheline size */
392         .word   0 /* pad 1 */
393         .word   0 /* pad 2 */
394         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
395         .word   closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
396         .word   NIL /* next */
397         .word   NIL /* name */
398         .word   NIL /* arglist */
399         .word   NIL /* type */
400         LEAF(closure_tramp)
401         lw      reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
402         lw      reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
403         addu    reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
404         jr      reg_LIP
405         END(closure_tramp)
406
407 /*
408  * Function-end breakpoint magic. This is truely magic, the code is
409  * copied and has to be relocatable. It also needs a properly aligned
410  * header tag after the fun_end_breakpoint_guts symbol.
411  */
412         .align  3 /* minimum alignment for a lisp object */
413         LEAF(fun_end_breakpoint_guts)
414         .set    noreorder
415         .word   RETURN_PC_HEADER_WIDETAG
416         b       multiple_value_return
417          nop
418         .set    reorder
419
420         /* single value return */
421
422         move    reg_OCFP, reg_CSP
423         addu    reg_CSP, 4
424         li      reg_NARGS, 4
425         move    reg_A1, reg_NIL
426         move    reg_A2, reg_NIL
427         move    reg_A3, reg_NIL
428         move    reg_A4, reg_NIL
429         move    reg_A5, reg_NIL
430
431 multiple_value_return:
432
433         FEXPORT(fun_end_breakpoint_trap)
434         break   0x0, trap_FunEndBreakpoint
435         b       multiple_value_return
436         EXPORT(fun_end_breakpoint_end)
437         END(fun_end_breakpoint_guts)