Replace %CODE-ENTRY-POINTS with an array, remove %SIMPLE-FUN-NEXT.
[sbcl.git] / src / runtime / arm-assem.S
blob667e95fa5b294003e9ab2b01ea942414518168e0
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 .known_nil:
17         .word   NIL
18         .align
19         .global call_into_lisp
20         .type   call_into_lisp, %function
21         .fpu vfp
22 call_into_lisp:
23         @@ At this point, we have:
24         @@ R0 - function
25         @@ R1 - pointer to args
26         @@ R2 - number of args (unboxed)
27         @@ There will be no more than three args, so we don't need to
28         @@ worry about parameters to be passed on the stack.
30         @@ All registers other than R0-R3 and R12 are callee-saves.
31         @@ Save R3 to get 8-byte alignemnt.
32         stmfd   sp!, {r3-r11, lr}
33         fstmfdd sp!, {d8-d15}
35         @@ Start by finding NIL.
36         ldr     reg_NULL, .known_nil
38         @@ Set up NARGS.
39         mov     reg_NARGS, r2, lsl #2
41         @@ Move args pointer out of the way of the args to be loaded.
42         mov     reg_R8, r1
44         @@ Move the function to its passing location.
45         mov     reg_LEXENV, r0
47         @@ Clear the boxed registers that don't already have something
48         @@ in them.
49         mov     reg_CODE, #0
50         mov     reg_R2, #0
52         @@ Find the lisp stack and frame pointers.  We're allocating a
53         @@ new lisp stack frame, so load the stack pointer into CFP.
54         @@ And we need the frame pointer, but OCFP is in use, so use
55         @@ NFP instead.
56         ldr     reg_NFP, .frame_pointer_address
57         ldr     reg_CFP, .stack_pointer_address
58         ldr     reg_NFP, [reg_NFP]
59         ldr     reg_CFP, [reg_CFP]
61         @@ Enter PSEUDO-ATOMIC.
62         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
64 #ifndef LISP_FEATURE_GENCGC
65         @@ Copy the current allocation pointer into the symbol.
66         ldr     reg_OCFP, =dynamic_space_free_pointer
67         ldr     reg_OCFP, [reg_OCFP]
68         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
69 #endif
71         @@ Clear FFCA, so the runtime knows that we're "in lisp".
72         ldr     reg_OCFP, =foreign_function_call_active
73         str     reg_R2, [reg_OCFP]
75         @@ We need to set up the lisp stack pointer and the basics of
76         @@ our stack frame while we're still in P-A.  Any sooner and
77         @@ our stack frame can be clobbered by a stray interrupt, any
78         @@ later and we can end up with a half-configured stack frame
79         @@ when we catch a stray interrupt.
81         @@ Allocate our frame and set up the Lisp stack pointer
82         add     reg_OCFP, reg_CFP, #8
83         str     reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
85         @@ Set up the "frame link"
86         str     reg_NFP, [reg_OCFP, #-8]
88         @@ Set up the return address
89         ldr     reg_NL3, =.lra
90         str     reg_NL3, [reg_OCFP, #-4]
92         @@ Leave PSEUDO-ATOMIC and check for interrupts.
93         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
94         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
95         cmp     reg_OCFP, #0
96         blxne   reg_OCFP
98         @@ Load our function args.  Cleverness abounds!
99         rsb     reg_NL3, reg_NARGS, #8
100         add     pc, pc, reg_NL3
101         ldr     reg_R2, [reg_R8, #8]
102         ldr     reg_R1, [reg_R8, #4]
103         ldr     reg_R0, [reg_R8]
105         @@ Load the closure-fun (or simple-fun-self), in case we're
106         @@ trying to call a closure.
107         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
109         @@ And, finally, call into Lisp!
110         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
112         .align 3
113         .equ    .lra, .+OTHER_POINTER_LOWTAG
114         .word   RETURN_PC_HEADER_WIDETAG
116         @@ Correct stack pointer for return processing.
117         streq   reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
119         @@ Enter PSEUDO-ATOMIC.
120         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
122         @@ Save the lisp stack and frame pointers.
123         ldr     reg_NFP, .frame_pointer_address
124         str     reg_CFP, [reg_NFP]
125         ldr     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
126         ldr     reg_OCFP, .stack_pointer_address
127         str     reg_NFP, [reg_OCFP]
129         @@ Set FFCA, so the runtime knows that we're not "in lisp".
130         ldr     reg_OCFP, =foreign_function_call_active
131         str     pc, [reg_OCFP]
133 #ifndef LISP_FEATURE_GENCGC
134         @@ Copy the current allocation pointer out from the symbol.
135         ldr     reg_OCFP, =dynamic_space_free_pointer
136         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
137         str     reg_NFP, [reg_OCFP]
138 #endif
140         @@ Leave PSEUDO-ATOMIC and check for interrupts.
141         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
142         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
143         cmp     reg_OCFP, #0
144         blxne   reg_OCFP
146         @@ Restore saved registers.
147         fldmfdd sp!, {d8-d15}
148         ldmfd   sp!, {r3-r11, lr}
149         bx      lr
150         .size   call_into_lisp, .-call_into_lisp
151 .frame_pointer_address: .word   current_control_frame_pointer
152 .stack_pointer_address: .word   current_control_stack_pointer
155         .align
156         .global call_into_c
157         .type   call_into_c, %function
158 call_into_c:
159         @@ At this point, we have:
160         @@ R8 -- C function to call.  This routine doesn't support
161         @@       thumb interworking, but linkage-table does, so we
162         @@       don't have to.
163         @@ LR -- Return address within the code component.
164         @@ OCFP -- First C register argument.
165         @@ NARGS -- Second C register argument.
166         @@ NL2 -- Third C register argument.
167         @@ NL3 -- Fourth C register argument.
168         @@ All other C arguments are already stashed on the C stack.
170         @@ We need to convert our return address to a GC-safe format,
171         @@ build a stack frame to count for the "foreign" frame,
172         @@ switch to C mode, move the register arguments to the
173         @@ correct locations, call the C function, move the result to
174         @@ the correct location, switch back to Lisp mode, tear down
175         @@ our stack frame, restore the return address, and return to
176         @@ our caller.
178         @@ We have ONE unboxed scratch register: NFP.  Use it as a
179         @@ temporary while we convert the (unboxed) return address to
180         @@ a (fixnum) offset within the component.
181         sub     reg_NFP, reg_LR, reg_CODE
182         add     reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
184         @@ Build a Lisp stack frame.  We need to stash our frame link,
185         @@ the code component, and our return offset.  Frame link goes
186         @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
187         @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2.  The
188         @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
189         @@ in SYS:SRC;CODE;DEBUG-INT.LISP).  The stack is aligned, so
190         @@ we can use R0 (a boxed register) as our temporary.
191         ldr     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
192         add     reg_R0, reg_R0, #12
193         str     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
194         str     reg_CFP, [reg_R0, #-12]
195         str     reg_NFP, [reg_R0, #-8]
196         str     reg_CODE, [reg_R0, #-4]
198         @@ Enter PSEUDO-ATOMIC.
199         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
201         @@ Save the lisp stack and frame pointers.
202         ldr     reg_NFP, .stack_pointer_address
203         str     reg_R0, [reg_NFP]
204         sub     reg_R0, reg_R0, #12
205         ldr     reg_NFP, .frame_pointer_address
206         str     reg_R0, [reg_NFP]
208         @@ We're done with R0, and we need to use OCFP when leaving
209         @@ pseudo-atomic, so move the first of the C register
210         @@ arguments to its final resting place now.
211         mov     r0, reg_OCFP
213         @@ Set FFCA, so the runtime knows that we're not "in lisp".
214         ldr     reg_NFP, =foreign_function_call_active
215         str     pc, [reg_NFP]
217 #ifndef LISP_FEATURE_GENCGC
218         @@ Copy the current allocation pointer out from the symbol.
219         ldr     reg_OCFP, =dynamic_space_free_pointer
220         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
221         str     reg_NFP, [reg_OCFP]
222 #endif
224         @@ Leave PSEUDO-ATOMIC and check for interrupts.
225         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
226         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
227         cmp     reg_OCFP, #0
228         blxne   reg_OCFP
230         @@ Now that we're in C mode, move the remaining register args
231         @@ into place.
232         mov     r1, reg_NARGS
233         mov     r2, reg_NL2
234         mov     r3, reg_NL3
236         @@ And call the C function.  We don't support interworking
237         @@ here because we have to be able to pass the function
238         @@ pointer in a boxed register, but the linkage-table is quite
239         @@ capable of doing a tail-call to a Thumb routine.
240         @@
241         @@ R8 is important for undefined_alien_function.
242         blx      reg_R8
244         @@ We're back.  Our main tasks are to move the C return value
245         @@ to where Lisp expects it, and to re-establish the Lisp
246         @@ environment.
248         @@ Stash the return value into NARGS for Lisp.
249         mov     reg_NARGS, r0
250         @@ For returning long-long, and doubles with softfp.
251         mov     reg_NL3, r1
253         @@ Re-establish NIL.
254         ldr     reg_NULL, .known_nil
256         @@ Blank the boxed registers.
257         mov     reg_R0, #0
258         mov     reg_R1, #0
259         mov     reg_R2, #0
260         mov     reg_LEXENV, #0
261         mov     reg_R8, #0
262         mov     reg_CODE, #0
264         @@ Enter PSEUDO-ATOMIC.
265         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
267         @@ Clear FFCA, so the runtime knows that we're "in lisp".
268         ldr     reg_OCFP, =foreign_function_call_active
269         str     reg_R2, [reg_OCFP]
271 #ifndef LISP_FEATURE_GENCGC
272         @@ Copy the current allocation pointer into the symbol.
273         ldr     reg_OCFP, =dynamic_space_free_pointer
274         ldr     reg_OCFP, [reg_OCFP]
275         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
276 #endif
278         @@ Restore the Lisp stack and frame pointers, but store the
279         @@ control frame pointer in reg_NFP (saving a register move
280         @@ later).
281         ldr     reg_NFP, .stack_pointer_address
282         ldr     reg_CFP, [reg_NFP]
283         str     reg_CFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
284         ldr     reg_NFP, .frame_pointer_address
285         ldr     reg_NFP, [reg_NFP]
287         @@ Leave PSEUDO-ATOMIC and check for interrupts.
288         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
289         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
290         cmp     reg_OCFP, #0
291         blxne   reg_OCFP
293         @@ Restore our caller state from our stack frame.
294         ldr     reg_CODE, [reg_NFP, #8]
295         ldr     reg_NL2, [reg_NFP, #4]
296         ldr     reg_CFP, [reg_NFP]
297         str     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
299         @@ Restore our return address... into the program counter.
300         sub     reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
301         add     reg_PC, reg_NL2, reg_CODE
303         .size   call_into_c, .-call_into_c
305         @@ FIXME-ARM: The following is random garbage, to make
306         @@ code/debug-int compile. To get the debugger working, this
307         @@ needs to be implemented.
308         .align
309         .global fun_end_breakpoint_guts
310         .type   fun_end_breakpoint_guts, %object
311 fun_end_breakpoint_guts:
312         .global fun_end_breakpoint_trap
313         .type   fun_end_breakpoint_trap, %function
314 fun_end_breakpoint_trap:
315         b       fun_end_breakpoint_trap
316         .global fun_end_breakpoint_end
317 fun_end_breakpoint_end:
319 #ifdef LISP_FEATURE_GENCGC
320         .align
321         .global alloc_tramp
322         .type   alloc_tramp, %function
323 alloc_tramp:
324         stmfd   sp!, {r4, r6, r12, lr}
326         ldr     r4, =foreign_function_call_active
327         str     pc, [r4]
329         ldr     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
330         add     r6, r4, #8*4
331         str     r6, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
333         @@ Create a new frame and save descriptor regs on the stack
334         @@ for the GC to see.
335         str     reg_CFP, [r4, #0]
336         str     reg_NULL, [r4, #4]
337         str     reg_CODE, [r4, #8]
338         add     r4, r4, #3*4
339         stmea   r4, {r0-reg_LEXENV, r8}
341         ldr     r0,  [sp, #4*4]
342         fstmfdd sp!, {d0-d7}
344         mov     lr, pc
345         ldr     pc,=alloc
347         fldmfdd sp!, {d0-d7}
348         str     r0,  [sp, #4*4]
349         ldr     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
350         ldmea   r4, {r0-reg_LEXENV, r8}
351         sub     r4, r4, #8*4
352         str     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
354         ldr     r4, =foreign_function_call_active
355         mov     r6, #0
356         str     r6, [r4]
358         ldmfd   sp!, {r4, r6, r12, lr}
359         bx      lr
361         .align
362         .global do_pending_interrupt
363         .type   do_pending_interrupt, %function
364 do_pending_interrupt:
365 #if defined(LISP_FEATURE_LINUX)
366         .word 0xe7f001f0
367 #elif defined(LISP_FEATURE_NETBSD)
368         .word 0xe7ffdefe
369 #endif
370         .byte trap_PendingInterrupt
371         .byte 0
372         .byte 0
373         .byte 0
374         bx      lr
375 #endif