f9ca519bd11eba0a54b31a633451b1404ab7bbaa
[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   0x0, 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   0x0, 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         /* Setup the lisp stack. */
244         move    reg_OCFP, reg_CFP
245         move    reg_CFP, reg_CSP
246         addu    reg_CSP, reg_CFP, 32
247
248         /* Set the pseudo-atomic flag. */
249         .set    noreorder
250         li      reg_NL4, 0
251         addu    reg_ALLOC, 1
252         .set    reorder
253
254         /* Convert the return address to an offset and save it on the stack. */
255         subu    reg_NFP, reg_LIP, reg_CODE
256         addu    reg_NFP, OTHER_POINTER_LOWTAG
257         sw      reg_LRA, (reg_CFP)
258         sw      reg_CODE, 4(reg_CFP)
259         sw      gp, 8(reg_CFP)
260
261         /* Save LISP state. */
262         subu    reg_A0, reg_ALLOC, 1
263         sw      reg_A0, dynamic_space_free_pointer
264         sw      reg_BSP, current_binding_stack_pointer
265         sw      reg_CSP, current_control_stack_pointer
266         sw      reg_CFP, current_control_frame_pointer
267
268         /* Mark us as in C land. */
269         sw      reg_CSP, foreign_function_call_active
270
271         /* Check for interrupt */
272         .set    noreorder
273         bgez    reg_NL4, 1f
274          subu   reg_ALLOC, 1
275         break   0x0, 0x10
276 1:      .set    reorder
277
278         /* Into C land we go. */
279         move    t9, reg_CFUNC           # reg_ALLOC
280         jalr    t9
281
282         lw      gp, 8(reg_CFP)
283
284         /* Pass 64bit return value to lisp land. */ 
285         move    reg_NL0, v0             # reg_CFUNC
286         move    reg_NL1, v1             # reg_NL4
287
288         /*
289          * Clear boxed descriptor registers before allowing an interrupt.
290          * We can't rely on C saving some of those registers, they might
291          * have been GCed in the meanwhile.
292          */
293         li      reg_A0, 0               # t0
294         li      reg_A1, 0               # t1
295         li      reg_A2, 0               # t2
296         li      reg_A3, 0               # t3
297         li      reg_A4, 0               # t4
298         li      reg_A5, 0               # t5
299         li      reg_FDEFN, 0            # t6
300         li      reg_LEXENV, 0           # t7
301         /*
302          * reg_NFP and reg_OCFP are pointing to fixed locations and are
303          * preserved by C.
304          */
305         li      reg_LRA, 0              # s2
306         li      reg_L0, 0               # s3
307         li      reg_L1, 0               # t8
308         li      reg_CODE, 0             # s8
309         li      reg_LIP, 0              # ra
310
311         /* Turn on pseudo-atomic. */
312         .set    noreorder
313         li      reg_NL4, 0
314         li      reg_ALLOC, 1
315         .set    reorder
316
317         /* Mark us as in Lisp land. */
318         sw      zero, foreign_function_call_active
319
320         /* Load the allocation pointer, preserving the low-bit of alloc */
321         lw      reg_BSP, dynamic_space_free_pointer
322         addu    reg_ALLOC, reg_BSP
323
324         lw      reg_BSP, current_binding_stack_pointer
325
326         /* Restore LRA & CODE */
327         lw      reg_LRA, (reg_CFP)
328         lw      reg_CODE, 4(reg_CFP)
329         subu    reg_LIP, reg_NFP, OTHER_POINTER_LOWTAG
330         addu    reg_LIP, reg_CODE
331
332         /* Check for interrupt */
333         .set    noreorder
334         bgez    reg_NL4, 1f
335          subu   reg_ALLOC, 1
336         break   0x0, 0x10
337 1:      .set    reorder
338
339         /* Reset the lisp stack. */
340         /* Note: OCFP and CFP are in saved regs. */
341         move    reg_CSP, reg_CFP
342         move    reg_CFP, reg_OCFP
343
344         /* Return to LISP. */
345         jr      reg_LIP
346         END(call_into_c)
347
348 /*
349  * Trampolines follow the Lisp calling convention.
350  *
351  * The undefined-function trampoline.
352  */
353         .align  3 /* minimum alignment for a lisp object */
354         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
355         .word   undefined_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
356         .word   NIL /* next */
357         .word   NIL /* name */
358         .word   NIL /* arglist */
359         .word   NIL /* type */
360         LEAF(undefined_tramp)
361         /* Point reg_CODE to the header and tag it as function, since
362            the debugger regards a function pointer in reg_CODE which
363            doesn't point to a code object as undefined function.  */
364         lui     reg_CODE, %hi(undefined_tramp)
365         addiu   reg_CODE, %lo(undefined_tramp)
366         addiu   reg_CODE, - 24 + FUN_POINTER_LOWTAG
367         .set    noreorder
368         b       1f
369          break  0x0, trap_Cerror
370         /* Error data length. */
371         .byte   4
372         /* Error number. */
373         .byte   UNDEFINED_FUN_ERROR
374         /* Magic value 254 means a 16bit little endian value follows.
375            See debug-var-io.lisp. */
376         .byte   254
377         /* reg_FDEFN is #14. */
378         .byte   ((14 << 5) + sc_DescriptorReg) % 0x100
379         .byte   ((14 << 5) + sc_DescriptorReg) / 0x100
380         .align  2
381         .set    reorder
382 1:      lw      reg_CODE, FDEFN_FUN_OFFSET(reg_FDEFN)
383         lw      reg_LIP, SIMPLE_FUN_CODE_OFFSET(reg_CODE)
384         jr      reg_LIP
385         END(undefined_tramp)
386
387 /*
388  * The closure trampoline.
389  */
390         .align  5 /* common MIPS cacheline size */
391         .word   0 /* pad 1 */
392         .word   0 /* pad 2 */
393         .word   SIMPLE_FUN_HEADER_WIDETAG /* header */
394         .word   closure_tramp - SIMPLE_FUN_CODE_OFFSET /* self */
395         .word   NIL /* next */
396         .word   NIL /* name */
397         .word   NIL /* arglist */
398         .word   NIL /* type */
399         LEAF(closure_tramp)
400         lw      reg_LEXENV, FDEFN_FUN_OFFSET(reg_FDEFN)
401         lw      reg_CODE, CLOSURE_FUN_OFFSET(reg_LEXENV)
402         addu    reg_LIP, reg_CODE, SIMPLE_FUN_CODE_OFFSET
403         jr      reg_LIP
404         END(closure_tramp)
405
406 /*
407  * Function-end breakpoint magic.
408  */
409         .align  3 /* minimum alignment for a lisp object */
410         .set    noreorder
411         .word   RETURN_PC_HEADER_WIDETAG
412         LEAF(fun_end_breakpoint_guts)
413         b       multiple_value_return
414          nop
415         .set    reorder
416
417         /* single value return */
418
419         move    reg_OCFP, reg_CSP
420         addu    reg_CSP, 4
421         li      reg_NARGS, 4
422         move    reg_A1, reg_NIL
423         move    reg_A2, reg_NIL
424         move    reg_A3, reg_NIL
425         move    reg_A4, reg_NIL
426         move    reg_A5, reg_NIL
427
428 multiple_value_return:
429
430         FEXPORT(fun_end_breakpoint_trap)
431         break   trap_FunEndBreakpoint
432         b       multiple_value_return
433         EXPORT(fun_end_breakpoint_end)
434         END(fun_end_breakpoint_guts)