runtime/: Keep dynamic_space_free_pointer in sync with *ALLOCATION-POINTER*.
[sbcl/nyef.git] / src / runtime / arm-assem.S
blobd57d6671fc42bcb8743cce8b5bd78db4bf4d2dd8
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         @@ Save off the C stack pointer.  Once for our return sequence,
69         @@ and once for the number stack.
70         stmea   reg_CFP!, {sp}
71         str     sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
73         @@ We need to set up the lisp stack pointer and the basics of
74         @@ our stack frame while we're still in P-A.  Any sooner and
75         @@ our stack frame can be clobbered by a stray interrupt, any
76         @@ later and we can end up with a half-configured stack frame
77         @@ when we catch a stray interrupt.
79         @@ Set up the Lisp stack pointer
80         mov     reg_CSP, reg_CFP
82         @@ Set up the "frame link"
83         stmea   reg_CSP!, {reg_NFP}
85         @@ Set up the return address
86         ldr     reg_NL3, =.lra
87         stmea   reg_CSP!, {reg_NL3}
89         @@ Leave PSEUDO-ATOMIC and check for interrupts.
90         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
91         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
92         cmp     reg_OCFP, reg_NULL
93         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
94         swilt   #0
96         @@ Load our function args.  Cleverness abounds!
97         rsb     reg_NL3, reg_NARGS, #8
98         add     pc, pc, reg_NL3
99         ldr     reg_R2, [reg_R8, #8]
100         ldr     reg_R1, [reg_R8, #4]
101         ldr     reg_R0, [reg_R8]
103         @@ And, finally, call into Lisp!
104         add     reg_PC, reg_LEXENV, #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         moveq   reg_CSP, reg_OCFP
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         ldr     reg_OCFP, .stack_pointer_address
119         str     reg_CFP, [reg_NFP]
120         str     reg_CSP, [reg_OCFP]
122         @@ Set FFCA, so the runtime knows that we're not "in lisp".
123         ldr     reg_OCFP, =foreign_function_call_active
124         str     pc, [reg_OCFP]
126         @@ Copy the current allocation pointer out from the symbol.
127         ldr     reg_OCFP, =dynamic_space_free_pointer
128         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
129         str     reg_NFP, [reg_OCFP]
131         @@ Restore the C stack pointer.
132         ldr     sp, [reg_CSP, #-4]
134         @@ Leave PSEUDO-ATOMIC and check for interrupts.
135         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
136         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
137         cmp     reg_OCFP, reg_NULL
138         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
139         swilt   #0
141         @@ Restore saved registers.
142         ldmfd   sp!, {r4-r11, lr}
143         bx      lr
144         .size   call_into_lisp, .-call_into_lisp
145 .frame_pointer_address: .word   current_control_frame_pointer
146 .stack_pointer_address: .word   current_control_stack_pointer
149         .align
150         .global call_into_c
151         .type   call_into_c, %function
152 call_into_c:
153         @@ At this point, we have:
154         @@ R8 -- C function to call.  This routine doesn't support
155         @@       thumb interworking, but linkage-table (when we get
156         @@       around to implementing it) will, so we don't have to.
157         @@ LR -- Return address within the code component.
158         @@ OCFP -- First C register argument.
159         @@ NARGS -- Second C register argument.
160         @@ NL2 -- Third C register argument.
161         @@ NL3 -- Fourth C register argument.
162         @@ All other C arguments are already stashed on the C stack.
164         @@ We need to convert our return address to a GC-safe format,
165         @@ build a stack frame to count for the "foreign" frame,
166         @@ switch to C mode, move the register arguments to the
167         @@ correct locations, call the C function, move the result to
168         @@ the correct location, switch back to Lisp mode, tear down
169         @@ our stack frame, restore the return address, and return to
170         @@ our caller.
172         @@ We have ONE unboxed scratch register: NFP.  Use it as a
173         @@ temporary while we convert the (unboxed) return address to
174         @@ a (fixnum) offset within the component.
175         sub     reg_NFP, reg_LR, reg_CODE
176         add     reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
178         @@ Build a Lisp stack frame.  We need to stash our frame link,
179         @@ the code component, and our return offset.  Frame link goes
180         @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
181         @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2.  The
182         @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
183         @@ in SYS:SRC;CODE;DEBUG-INT.LISP).  The stack is aligned, so
184         @@ we can use R0 (a boxed register) as our temporary.
185         mov     reg_R0, sp
186         add     sp, sp, #12
187         str     reg_CFP, [reg_R0]
188         str     reg_NFP, [reg_R0, #4]
189         str     reg_CODE, [reg_R0, #8]
191         @@ Enter PSEUDO-ATOMIC.
192         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
194         @@ Save the lisp stack and frame pointers.
195         ldr     reg_NFP, .frame_pointer_address
196         str     reg_R0, [reg_NFP]
197         ldr     reg_NFP, .stack_pointer_address
198         str     reg_CSP, [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         @@ Pick up the C stack pointer.
215         ldr     sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
217         @@ Leave PSEUDO-ATOMIC and check for interrupts.
218         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
219         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
220         cmp     reg_OCFP, reg_NULL
221         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
222         swilt   #0
224         @@ Now that we're in C mode, move the remaining register args
225         @@ into place.
226         mov     r1, reg_NARGS
227         mov     r2, reg_NL2
228         mov     r3, reg_NL3
230         @@ And call the C function.  We don't support interworking
231         @@ here because we have to be able to pass the function
232         @@ pointer in a boxed register, but the linkage-table is quite
233         @@ capable of doing a tail-call to a Thumb routine.  Oh, wait,
234         @@ we don't have a linkage-table yet.  Oops.
235         blx      reg_R8
237         @@ We're back.  Our main tasks are to move the C return value
238         @@ to where Lisp expects it, and to re-establish the Lisp
239         @@ environment.
241         @@ Stash the return value into NARGS for Lisp.
242         mov     reg_NARGS, r0
244         @@ Re-establish NIL.
245         ldr     reg_NULL, .known_nil
247         @@ Blank the boxed registers.
248         mov     reg_R0, #0
249         mov     reg_R1, #0
250         mov     reg_R2, #0
251         mov     reg_LEXENV, #0
252         mov     reg_R8, #0
253         mov     reg_CODE, #0
255         @@ Enter PSEUDO-ATOMIC.
256         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
258         @@ Clear FFCA, so the runtime knows that we're "in lisp".
259         ldr     reg_OCFP, =foreign_function_call_active
260         str     reg_R2, [reg_OCFP]
262         @@ Copy the current allocation pointer into the symbol.
263         ldr     reg_OCFP, =dynamic_space_free_pointer
264         ldr     reg_OCFP, [reg_OCFP]
265         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
267         @@ Save off the C stack pointer.
268         str     sp, STATIC_SYMBOL_VALUE(NUMBER_STACK_POINTER)
270         @@ Restore the Lisp stack and frame pointers, but store the
271         @@ control frame pointer in reg_NFP (saving a register move
272         @@ later).
273         ldr     reg_NFP, .stack_pointer_address
274         ldr     reg_CSP, [reg_NFP]
275         ldr     reg_NFP, .frame_pointer_address
276         ldr     reg_NFP, [reg_NFP]
278         @@ Leave PSEUDO-ATOMIC and check for interrupts.
279         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
280         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
281         cmp     reg_OCFP, reg_NULL
282         movlt   reg_OCFP, reg_OCFP, lsl #N_FIXNUM_TAG_BITS
283         swilt   #0
285         @@ Restore our caller state from our stack frame.
286         ldr     reg_CODE, [reg_NFP, #8]
287         ldr     reg_NL2, [reg_NFP, #4]
288         ldr     reg_CFP, [reg_NFP]
289         mov     reg_CSP, reg_NFP
291         @@ Restore our return address... into the program counter.
292         sub     reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
293         add     reg_PC, reg_NL2, reg_CODE
295         .size   call_into_c, .-call_into_c
298 /* Trampolines, like on SPARC, use Lisp calling conventions. */
299         .align  3
300         .global undefined_tramp
301         .type   undefined_tramp, %object
302         .word   SIMPLE_FUN_HEADER_WIDETAG
303         .equ    undefined_tramp, .+1
304         .word   undefined_tramp
305 .known_nil:
306         .word   NIL
307         .word   NIL
308         .word   NIL
309         .word   NIL
310         .word   NIL
312         @@ The magic (undefined) "BREAK_POINT" instruction.
313         .word 0xe7f001f0
315         @@ Error arguments for an undefined function.
316         .byte   trap_Error
317         .byte   .error_args_end - . - 1
318         .byte   UNDEFINED_FUN_ERROR
319         @@ Need to indicate reg_LEXENV here, which is R3.  Encoding
320         @@ rules are to produce an "sc-offset" with the SC number in
321         @@ the low five bits and the offset (3 in our case) in the
322         @@ high $n$ bits.  sc_DescriptorReg happens to be 5, but we
323         @@ should use the constant for it.  So long as the overall
324         @@ value of the sc-offset is less than 254, we can use a
325         @@ single byte.  Overflowing that will take having the SC
326         @@ number being 30 or 31, and as of this writing the highest
327         @@ SC number is sc_CatchBlock at 16.  It would also take an
328         @@ offset of 7, not the 3 that we use for LEXENV.
329         .byte   sc_DescriptorReg + (0x20 * 3)
330 .error_args_end:
332         .align  3
333         .global closure_tramp
334         .type   closure_tramp, %object
335         .word   SIMPLE_FUN_HEADER_WIDETAG
336         .equ    closure_tramp, .+1
337         .word   closure_tramp
338         .word   NIL
339         .word   NIL
340         .word   NIL
341         .word   NIL
342         .word   NIL
344         ldr     reg_LEXENV, [reg_LEXENV, #FDEFN_FUN_OFFSET]
345         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
346         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
348         .align  3
349         .global funcallable_instance_tramp
350         .type   funcallable_instance_tramp, %object
351         .word   SIMPLE_FUN_HEADER_WIDETAG
352         .equ    funcallable_instance_tramp, .+1
353         .word   funcallable_instance_tramp
354         .word   NIL
355         .word   NIL
356         .word   NIL
357         .word   NIL
358         .word   NIL
360         ldr     reg_LEXENV, [reg_LEXENV, #FUNCALLABLE_INSTANCE_FUNCTION_OFFSET]
361         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
362         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
364         @@ FIXME-ARM: The following is random garbage, to make
365         @@ code/debug-int compile. To get the debugger working, this
366         @@ needs to be implemented.
367         .align
368         .global fun_end_breakpoint_guts
369         .type   fun_end_breakpoint_guts, %object
370 fun_end_breakpoint_guts:
371         .global fun_end_breakpoint_trap
372         .type   fun_end_breakpoint_trap, %function
373 fun_end_breakpoint_trap:
374         b       fun_end_breakpoint_trap
375         .global fun_end_breakpoint_end
376 fun_end_breakpoint_end:
378         /* EOF */