Add sb-mpfr contrib.
[sbcl/nyef.git] / src / runtime / arm-assem.S
blob1b8c5ee7c8d202258d02a6f3c57be45e981a1fea
1 #define LANGUAGE_ASSEMBLY
3 #include "lispregs.h"
4 #include "globals.h"
5 #include "sbcl.h"
7 #include "genesis/closure.h"
8 #include "genesis/funcallable-instance.h"
9 #include "genesis/fdefn.h"
10 #include "genesis/static-symbols.h"
11 #include "genesis/simple-fun.h"
12 #include "genesis/symbol.h"
14 #define STATIC_SYMBOL_VALUE(sym) [reg_NULL, #(((sym)-NIL)+SYMBOL_VALUE_OFFSET)]
16         .align
17         .global call_into_lisp
18         .type   call_into_lisp, %function
19 call_into_lisp:
20         @@ At this point, we have:
21         @@ R0 - function
22         @@ R1 - pointer to args
23         @@ R2 - number of args (unboxed)
24         @@ There will be no more than three args, so we don't need to
25         @@ worry about parameters to be passed on the stack.
27         @@ All registers other than R0-R3 and R12 are callee-saves.
28         stmfd   sp!, {r4-r11, lr}
30         @@ Start by finding NIL.
31         ldr     reg_NULL, .known_nil
33         @@ Set up NARGS.
34         mov     reg_NARGS, r2, lsl #2
36         @@ Move args pointer out of the way of the args to be loaded.
37         mov     reg_R8, r1
39         @@ Move the function to its passing location.
40         mov     reg_LEXENV, r0
42         @@ Clear the boxed registers that don't already have something
43         @@ in them.
44         mov     reg_CODE, #0
45         mov     reg_R2, #0
47         @@ Find the lisp stack and frame pointers.  We're allocating a
48         @@ new lisp stack frame, so load the stack pointer into CFP.
49         @@ And we need the frame pointer, but OCFP is in use, so use
50         @@ NFP instead.
51         ldr     reg_NFP, .frame_pointer_address
52         ldr     reg_CFP, .stack_pointer_address
53         ldr     reg_NFP, [reg_NFP]
54         ldr     reg_CFP, [reg_CFP]
56         @@ Enter PSEUDO-ATOMIC.
57         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
59         @@ Copy the current allocation pointer into the symbol.
60         ldr     reg_OCFP, =dynamic_space_free_pointer
61         ldr     reg_OCFP, [reg_OCFP]
62         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
64         @@ Clear FFCA, so the runtime knows that we're "in lisp".
65         ldr     reg_OCFP, =foreign_function_call_active
66         str     reg_R2, [reg_OCFP]
68         @@ We need to set up the lisp stack pointer and the basics of
69         @@ our stack frame while we're still in P-A.  Any sooner and
70         @@ our stack frame can be clobbered by a stray interrupt, any
71         @@ later and we can end up with a half-configured stack frame
72         @@ when we catch a stray interrupt.
74         @@ Allocate our frame and set up the Lisp stack pointer
75         add     reg_OCFP, reg_CFP, #8
76         str     reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
78         @@ Set up the "frame link"
79         str     reg_NFP, [reg_OCFP, #-8]
81         @@ Set up the return address
82         ldr     reg_NL3, =.lra
83         str     reg_NL3, [reg_OCFP, #-4]
85         @@ Leave PSEUDO-ATOMIC and check for interrupts.
86         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
87         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
88         cmp     reg_OCFP, reg_NULL
89         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
90         swilt   #0
92         @@ Load our function args.  Cleverness abounds!
93         rsb     reg_NL3, reg_NARGS, #8
94         add     pc, pc, reg_NL3
95         ldr     reg_R2, [reg_R8, #8]
96         ldr     reg_R1, [reg_R8, #4]
97         ldr     reg_R0, [reg_R8]
99         @@ Load the closure-fun (or simple-fun-self), in case we're
100         @@ trying to call a closure.
101         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
103         @@ And, finally, call into Lisp!
104         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
106         .align 3
107         .equ    .lra, .+OTHER_POINTER_LOWTAG
108         .word   RETURN_PC_HEADER_WIDETAG
110         @@ Correct stack pointer for return processing.
111         streq   reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
113         @@ Enter PSEUDO-ATOMIC.
114         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
116         @@ Save the lisp stack and frame pointers.
117         ldr     reg_NFP, .frame_pointer_address
118         str     reg_CFP, [reg_NFP]
119         ldr     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
120         ldr     reg_OCFP, .stack_pointer_address
121         str     reg_NFP, [reg_OCFP]
123         @@ Set FFCA, so the runtime knows that we're not "in lisp".
124         ldr     reg_OCFP, =foreign_function_call_active
125         str     pc, [reg_OCFP]
127         @@ Copy the current allocation pointer out from the symbol.
128         ldr     reg_OCFP, =dynamic_space_free_pointer
129         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
130         str     reg_NFP, [reg_OCFP]
132         @@ Leave PSEUDO-ATOMIC and check for interrupts.
133         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
134         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
135         cmp     reg_OCFP, reg_NULL
136         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
137         swilt   #0
139         @@ Restore saved registers.
140         ldmfd   sp!, {r4-r11, lr}
141         bx      lr
142         .size   call_into_lisp, .-call_into_lisp
143 .frame_pointer_address: .word   current_control_frame_pointer
144 .stack_pointer_address: .word   current_control_stack_pointer
147         .align
148         .global call_into_c
149         .type   call_into_c, %function
150 call_into_c:
151         @@ At this point, we have:
152         @@ R8 -- C function to call.  This routine doesn't support
153         @@       thumb interworking, but linkage-table does, so we
154         @@       don't have to.
155         @@ LR -- Return address within the code component.
156         @@ OCFP -- First C register argument.
157         @@ NARGS -- Second C register argument.
158         @@ NL2 -- Third C register argument.
159         @@ NL3 -- Fourth C register argument.
160         @@ All other C arguments are already stashed on the C stack.
162         @@ We need to convert our return address to a GC-safe format,
163         @@ build a stack frame to count for the "foreign" frame,
164         @@ switch to C mode, move the register arguments to the
165         @@ correct locations, call the C function, move the result to
166         @@ the correct location, switch back to Lisp mode, tear down
167         @@ our stack frame, restore the return address, and return to
168         @@ our caller.
170         @@ We have ONE unboxed scratch register: NFP.  Use it as a
171         @@ temporary while we convert the (unboxed) return address to
172         @@ a (fixnum) offset within the component.
173         sub     reg_NFP, reg_LR, reg_CODE
174         add     reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
176         @@ Build a Lisp stack frame.  We need to stash our frame link,
177         @@ the code component, and our return offset.  Frame link goes
178         @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
179         @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2.  The
180         @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
181         @@ in SYS:SRC;CODE;DEBUG-INT.LISP).  The stack is aligned, so
182         @@ we can use R0 (a boxed register) as our temporary.
183         ldr     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
184         add     reg_R0, reg_R0, #12
185         str     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
186         str     reg_CFP, [reg_R0, #-12]
187         str     reg_NFP, [reg_R0, #-8]
188         str     reg_CODE, [reg_R0, #-4]
190         @@ Enter PSEUDO-ATOMIC.
191         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
193         @@ Save the lisp stack and frame pointers.
194         ldr     reg_NFP, .stack_pointer_address
195         str     reg_R0, [reg_NFP]
196         sub     reg_R0, reg_R0, #12
197         ldr     reg_NFP, .frame_pointer_address
198         str     reg_R0, [reg_NFP]
200         @@ We're done with R0, and we need to use OCFP when leaving
201         @@ pseudo-atomic, so move the first of the C register
202         @@ arguments to its final resting place now.
203         mov     r0, reg_OCFP
205         @@ Set FFCA, so the runtime knows that we're not "in lisp".
206         ldr     reg_NFP, =foreign_function_call_active
207         str     pc, [reg_NFP]
209         @@ Copy the current allocation pointer out from the symbol.
210         ldr     reg_OCFP, =dynamic_space_free_pointer
211         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
212         str     reg_NFP, [reg_OCFP]
214         @@ Leave PSEUDO-ATOMIC and check for interrupts.
215         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
216         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
217         cmp     reg_OCFP, reg_NULL
218         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
219         swilt   #0
221         @@ Now that we're in C mode, move the remaining register args
222         @@ into place.
223         mov     r1, reg_NARGS
224         mov     r2, reg_NL2
225         mov     r3, reg_NL3
227         @@ And call the C function.  We don't support interworking
228         @@ here because we have to be able to pass the function
229         @@ pointer in a boxed register, but the linkage-table is quite
230         @@ capable of doing a tail-call to a Thumb routine.
231         blx      reg_R8
233         @@ We're back.  Our main tasks are to move the C return value
234         @@ to where Lisp expects it, and to re-establish the Lisp
235         @@ environment.
237         @@ Stash the return value into NARGS for Lisp.
238         mov     reg_NARGS, r0
239         @@ For returning long-long, and doubles with softfp.
240         mov     reg_NL3, r1
242         @@ Re-establish NIL.
243         ldr     reg_NULL, .known_nil
245         @@ Blank the boxed registers.
246         mov     reg_R0, #0
247         mov     reg_R1, #0
248         mov     reg_R2, #0
249         mov     reg_LEXENV, #0
250         mov     reg_R8, #0
251         mov     reg_CODE, #0
253         @@ Enter PSEUDO-ATOMIC.
254         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
256         @@ Clear FFCA, so the runtime knows that we're "in lisp".
257         ldr     reg_OCFP, =foreign_function_call_active
258         str     reg_R2, [reg_OCFP]
260         @@ Copy the current allocation pointer into the symbol.
261         ldr     reg_OCFP, =dynamic_space_free_pointer
262         ldr     reg_OCFP, [reg_OCFP]
263         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
265         @@ Restore the Lisp stack and frame pointers, but store the
266         @@ control frame pointer in reg_NFP (saving a register move
267         @@ later).
268         ldr     reg_NFP, .stack_pointer_address
269         ldr     reg_CFP, [reg_NFP]
270         str     reg_CFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
271         ldr     reg_NFP, .frame_pointer_address
272         ldr     reg_NFP, [reg_NFP]
274         @@ Leave PSEUDO-ATOMIC and check for interrupts.
275         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
276         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
277         cmp     reg_OCFP, reg_NULL
278         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
279         swilt   #0
281         @@ Restore our caller state from our stack frame.
282         ldr     reg_CODE, [reg_NFP, #8]
283         ldr     reg_NL2, [reg_NFP, #4]
284         ldr     reg_CFP, [reg_NFP]
285         str     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
287         @@ Restore our return address... into the program counter.
288         sub     reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
289         add     reg_PC, reg_NL2, reg_CODE
291         .size   call_into_c, .-call_into_c
294 /* Trampolines, like on SPARC, use Lisp calling conventions. */
295         .align  3
296         .global undefined_tramp
297         .type   undefined_tramp, %object
298         .word   SIMPLE_FUN_HEADER_WIDETAG
299         .equ    undefined_tramp, .+1
300         .word   undefined_tramp
301 .known_nil:
302         .word   NIL
303         .word   NIL
304         .word   NIL
305         .word   NIL
306         .word   NIL
308         @@ The magic (undefined) "BREAK_POINT" instruction.
309         .word 0xe7f001f0
311         @@ Error arguments for an undefined function.
312         .byte   trap_Error
313         .byte   .error_args_end - . - 1
314         .byte   UNDEFINED_FUN_ERROR
315         @@ Need to indicate reg_LEXENV here, which is R3.  Encoding
316         @@ rules are to produce an "sc-offset" with the SC number in
317         @@ the low six bits and the offset (3 in our case) in the
318         @@ high $n$ bits.  sc_DescriptorReg happens to be 5, but we
319         @@ should use the constant for it.  So long as the overall
320         @@ value of the sc-offset is less than 254, we can use a
321         @@ single byte.  Overflowing that will take having the SC
322         @@ number being 30 or 31, and as of this writing the highest
323         @@ SC number is sc_CatchBlock at 16.  It would also take an
324         @@ offset of 7, not the 3 that we use for LEXENV.
325         .byte   sc_DescriptorReg + (0x40 * 3)
326 .error_args_end:
328         .align  3
329         .global closure_tramp
330         .type   closure_tramp, %object
331         .word   SIMPLE_FUN_HEADER_WIDETAG
332         .equ    closure_tramp, .+1
333         .word   closure_tramp
334         .word   NIL
335         .word   NIL
336         .word   NIL
337         .word   NIL
338         .word   NIL
340         ldr     reg_LEXENV, [reg_LEXENV, #FDEFN_FUN_OFFSET]
341         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
342         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
344         .align  3
345         .global funcallable_instance_tramp
346         .type   funcallable_instance_tramp, %object
347         .word   SIMPLE_FUN_HEADER_WIDETAG
348         .equ    funcallable_instance_tramp, .+1
349         .word   funcallable_instance_tramp
350         .word   NIL
351         .word   NIL
352         .word   NIL
353         .word   NIL
354         .word   NIL
356         ldr     reg_LEXENV, [reg_LEXENV, #FUNCALLABLE_INSTANCE_FUNCTION_OFFSET]
357         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
358         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
360         @@ FIXME-ARM: The following is random garbage, to make
361         @@ code/debug-int compile. To get the debugger working, this
362         @@ needs to be implemented.
363         .align
364         .global fun_end_breakpoint_guts
365         .type   fun_end_breakpoint_guts, %object
366 fun_end_breakpoint_guts:
367         .global fun_end_breakpoint_trap
368         .type   fun_end_breakpoint_trap, %function
369 fun_end_breakpoint_trap:
370         b       fun_end_breakpoint_trap
371         .global fun_end_breakpoint_end
372 fun_end_breakpoint_end:
374         /* EOF */