Fix ARM aarch32.
[sbcl.git] / src / runtime / arm-assem.S
blobb4be68b9d3f3e63f4f8d5809afe07c81739511ee
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         .fpu vfp
20 call_into_lisp:
21         @@ At this point, we have:
22         @@ R0 - function
23         @@ R1 - pointer to args
24         @@ R2 - number of args (unboxed)
25         @@ There will be no more than three args, so we don't need to
26         @@ worry about parameters to be passed on the stack.
28         @@ All registers other than R0-R3 and R12 are callee-saves.
29         @@ Save R3 to get 8-byte alignemnt.
30         stmfd   sp!, {r3-r11, lr}
31         fstmfdd sp!, {d8-d15}
33         @@ Start by finding NIL.
34         ldr     reg_NULL, .known_nil
36         @@ Set up NARGS.
37         mov     reg_NARGS, r2, lsl #2
39         @@ Move args pointer out of the way of the args to be loaded.
40         mov     reg_R8, r1
42         @@ Move the function to its passing location.
43         mov     reg_LEXENV, r0
45         @@ Clear the boxed registers that don't already have something
46         @@ in them.
47         mov     reg_CODE, #0
48         mov     reg_R2, #0
50         @@ Find the lisp stack and frame pointers.  We're allocating a
51         @@ new lisp stack frame, so load the stack pointer into CFP.
52         @@ And we need the frame pointer, but OCFP is in use, so use
53         @@ NFP instead.
54         ldr     reg_NFP, .frame_pointer_address
55         ldr     reg_CFP, .stack_pointer_address
56         ldr     reg_NFP, [reg_NFP]
57         ldr     reg_CFP, [reg_CFP]
59         @@ Enter PSEUDO-ATOMIC.
60         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
62 #ifndef LISP_FEATURE_GENCGC
63         @@ Copy the current allocation pointer into the symbol.
64         ldr     reg_OCFP, =dynamic_space_free_pointer
65         ldr     reg_OCFP, [reg_OCFP]
66         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
67 #endif
69         @@ Clear FFCA, so the runtime knows that we're "in lisp".
70         ldr     reg_OCFP, =foreign_function_call_active
71         str     reg_R2, [reg_OCFP]
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         @@ Allocate our frame and set up the Lisp stack pointer
80         add     reg_OCFP, reg_CFP, #8
81         str     reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
83         @@ Set up the "frame link"
84         str     reg_NFP, [reg_OCFP, #-8]
86         @@ Set up the return address
87         ldr     reg_NL3, =.lra
88         str     reg_NL3, [reg_OCFP, #-4]
90         @@ Leave PSEUDO-ATOMIC and check for interrupts.
91         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
92         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
93         cmp     reg_OCFP, #0
94         blxne   reg_OCFP
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         @@ Load the closure-fun (or simple-fun-self), in case we're
104         @@ trying to call a closure.
105         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
107         @@ And, finally, call into Lisp!
108         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
110         .align 3
111         .equ    .lra, .+OTHER_POINTER_LOWTAG
112         .word   RETURN_PC_HEADER_WIDETAG
114         @@ Correct stack pointer for return processing.
115         streq   reg_OCFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
117         @@ Enter PSEUDO-ATOMIC.
118         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
120         @@ Save the lisp stack and frame pointers.
121         ldr     reg_NFP, .frame_pointer_address
122         str     reg_CFP, [reg_NFP]
123         ldr     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
124         ldr     reg_OCFP, .stack_pointer_address
125         str     reg_NFP, [reg_OCFP]
127         @@ Set FFCA, so the runtime knows that we're not "in lisp".
128         ldr     reg_OCFP, =foreign_function_call_active
129         str     pc, [reg_OCFP]
131 #ifndef LISP_FEATURE_GENCGC
132         @@ Copy the current allocation pointer out from the symbol.
133         ldr     reg_OCFP, =dynamic_space_free_pointer
134         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
135         str     reg_NFP, [reg_OCFP]
136 #endif
138         @@ Leave PSEUDO-ATOMIC and check for interrupts.
139         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
140         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
141         cmp     reg_OCFP, #0
142         blxne   reg_OCFP
144         @@ Restore saved registers.
145         fldmfdd sp!, {d8-d15}
146         ldmfd   sp!, {r3-r11, lr}
147         bx      lr
148         .size   call_into_lisp, .-call_into_lisp
149 .frame_pointer_address: .word   current_control_frame_pointer
150 .stack_pointer_address: .word   current_control_stack_pointer
153         .align
154         .global call_into_c
155         .type   call_into_c, %function
156 call_into_c:
157         @@ At this point, we have:
158         @@ R8 -- C function to call.  This routine doesn't support
159         @@       thumb interworking, but linkage-table does, so we
160         @@       don't have to.
161         @@ LR -- Return address within the code component.
162         @@ OCFP -- First C register argument.
163         @@ NARGS -- Second C register argument.
164         @@ NL2 -- Third C register argument.
165         @@ NL3 -- Fourth C register argument.
166         @@ All other C arguments are already stashed on the C stack.
168         @@ We need to convert our return address to a GC-safe format,
169         @@ build a stack frame to count for the "foreign" frame,
170         @@ switch to C mode, move the register arguments to the
171         @@ correct locations, call the C function, move the result to
172         @@ the correct location, switch back to Lisp mode, tear down
173         @@ our stack frame, restore the return address, and return to
174         @@ our caller.
176         @@ We have ONE unboxed scratch register: NFP.  Use it as a
177         @@ temporary while we convert the (unboxed) return address to
178         @@ a (fixnum) offset within the component.
179         sub     reg_NFP, reg_LR, reg_CODE
180         add     reg_NFP, reg_NFP, #OTHER_POINTER_LOWTAG
182         @@ Build a Lisp stack frame.  We need to stash our frame link,
183         @@ the code component, and our return offset.  Frame link goes
184         @@ in slot 0 (OCFP-SAVE-OFFSET), the offset (a FIXNUM) goes in
185         @@ slot 1 (LRA-SAVE-OFFSET), and reg_CODE goes in slot 2.  The
186         @@ debugger knows about this layout (see COMPUTE-CALLING-FRAME
187         @@ in SYS:SRC;CODE;DEBUG-INT.LISP).  The stack is aligned, so
188         @@ we can use R0 (a boxed register) as our temporary.
189         ldr     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
190         add     reg_R0, reg_R0, #12
191         str     reg_R0, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
192         str     reg_CFP, [reg_R0, #-12]
193         str     reg_NFP, [reg_R0, #-8]
194         str     reg_CODE, [reg_R0, #-4]
196         @@ Enter PSEUDO-ATOMIC.
197         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
199         @@ Save the lisp stack and frame pointers.
200         ldr     reg_NFP, .stack_pointer_address
201         str     reg_R0, [reg_NFP]
202         sub     reg_R0, reg_R0, #12
203         ldr     reg_NFP, .frame_pointer_address
204         str     reg_R0, [reg_NFP]
206         @@ We're done with R0, and we need to use OCFP when leaving
207         @@ pseudo-atomic, so move the first of the C register
208         @@ arguments to its final resting place now.
209         mov     r0, reg_OCFP
211         @@ Set FFCA, so the runtime knows that we're not "in lisp".
212         ldr     reg_NFP, =foreign_function_call_active
213         str     pc, [reg_NFP]
215 #ifndef LISP_FEATURE_GENCGC
216         @@ Copy the current allocation pointer out from the symbol.
217         ldr     reg_OCFP, =dynamic_space_free_pointer
218         ldr     reg_NFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
219         str     reg_NFP, [reg_OCFP]
220 #endif
222         @@ Leave PSEUDO-ATOMIC and check for interrupts.
223         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
224         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
225         cmp     reg_OCFP, #0
226         blxne   reg_OCFP
228         @@ Now that we're in C mode, move the remaining register args
229         @@ into place.
230         mov     r1, reg_NARGS
231         mov     r2, reg_NL2
232         mov     r3, reg_NL3
234         @@ And call the C function.  We don't support interworking
235         @@ here because we have to be able to pass the function
236         @@ pointer in a boxed register, but the linkage-table is quite
237         @@ capable of doing a tail-call to a Thumb routine.
238         @@
239         @@ R8 is important for undefined_alien_function.
240         blx      reg_R8
242         @@ We're back.  Our main tasks are to move the C return value
243         @@ to where Lisp expects it, and to re-establish the Lisp
244         @@ environment.
246         @@ Stash the return value into NARGS for Lisp.
247         mov     reg_NARGS, r0
248         @@ For returning long-long, and doubles with softfp.
249         mov     reg_NL3, r1
251         @@ Re-establish NIL.
252         ldr     reg_NULL, .known_nil
254         @@ Blank the boxed registers.
255         mov     reg_R0, #0
256         mov     reg_R1, #0
257         mov     reg_R2, #0
258         mov     reg_LEXENV, #0
259         mov     reg_R8, #0
260         mov     reg_CODE, #0
262         @@ Enter PSEUDO-ATOMIC.
263         str     pc, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
265         @@ Clear FFCA, so the runtime knows that we're "in lisp".
266         ldr     reg_OCFP, =foreign_function_call_active
267         str     reg_R2, [reg_OCFP]
269 #ifndef LISP_FEATURE_GENCGC
270         @@ Copy the current allocation pointer into the symbol.
271         ldr     reg_OCFP, =dynamic_space_free_pointer
272         ldr     reg_OCFP, [reg_OCFP]
273         str     reg_OCFP, STATIC_SYMBOL_VALUE(ALLOCATION_POINTER)
274 #endif
276         @@ Restore the Lisp stack and frame pointers, but store the
277         @@ control frame pointer in reg_NFP (saving a register move
278         @@ later).
279         ldr     reg_NFP, .stack_pointer_address
280         ldr     reg_CFP, [reg_NFP]
281         str     reg_CFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
282         ldr     reg_NFP, .frame_pointer_address
283         ldr     reg_NFP, [reg_NFP]
285         @@ Leave PSEUDO-ATOMIC and check for interrupts.
286         str     reg_NULL, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_ATOMIC)
287         ldr     reg_OCFP, STATIC_SYMBOL_VALUE(PSEUDO_ATOMIC_INTERRUPTED)
288         cmp     reg_OCFP, #0
289         blxne   reg_OCFP
291         @@ Restore our caller state from our stack frame.
292         ldr     reg_CODE, [reg_NFP, #8]
293         ldr     reg_NL2, [reg_NFP, #4]
294         ldr     reg_CFP, [reg_NFP]
295         str     reg_NFP, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
297         @@ Restore our return address... into the program counter.
298         sub     reg_NL2, reg_NL2, #OTHER_POINTER_LOWTAG
299         add     reg_PC, reg_NL2, reg_CODE
301         .size   call_into_c, .-call_into_c
304 /* Trampolines, like on SPARC, use Lisp calling conventions. */
305         .align  3
306         .global undefined_tramp
307         .type   undefined_tramp, %object
308         .word   SIMPLE_FUN_HEADER_WIDETAG
309         .equ    undefined_tramp, .+1
310         .word   undefined_tramp
311 .known_nil:
312         .word   NIL
313         .word   NIL
314         .word   NIL
315         .word   NIL
316         .word   NIL
318         @@ As in ppc-assem.S, point reg_CODE to the header with a
319         @@ function lowtag...  Which the address already has.
320         ldr     reg_CODE, =undefined_tramp
322         @@ The magic (undefined) "BREAK_POINT" instruction.
323         .word 0xe7f001f0
325         @@ Error arguments for an undefined function.
326         .byte   trap_Error
327         .byte   .error_args_end - . - 1
328         .byte   UNDEFINED_FUN_ERROR
329         @@ Need to indicate reg_LEXENV here, which is R3.  Encoding
330         @@ rules are to produce an "sc-offset" with the SC number in
331         @@ the low six bits and the offset (3 in our case) in the
332         @@ high $n$ bits.  sc_DescriptorReg happens to be 5, but we
333         @@ should use the constant for it.  So long as the overall
334         @@ value of the sc-offset is less than 254, we can use a
335         @@ single byte.  Overflowing that will take having the SC
336         @@ number being 30 or 31, and as of this writing the highest
337         @@ SC number is sc_CatchBlock at 16.  It would also take an
338         @@ offset of 7, not the 3 that we use for LEXENV.
339         .byte   sc_DescriptorReg + (0x40 * 3)
340 .error_args_end:
342         .align  3
343         .global undefined_alien_function
344         .type   undefined_alien_function, %object
345         .word   SIMPLE_FUN_HEADER_WIDETAG
346         .equ    undefined_alien_function, .+1
347         .word   undefined_alien_function
348         .word   NIL
349         .word   NIL
350         .word   NIL
351         .word   NIL
352         .word   NIL
353 undefined_alien_function:
354         ldr     reg_CODE, = undefined_alien_function
356         @@ The magic (undefined) "BREAK_POINT" instruction.
357         .word 0xe7f001f0
359         @@ Error arguments for an undefined function.
360         .byte   trap_Error
361         .byte   4
362         .byte   UNDEFINED_ALIEN_FUN_ERROR
363         @@ Encode unsigned R8, which comes from call_into_c
364         .byte   0xFE
365         .byte   0x11
366         .byte   0x02
368         .align  3
369         .global closure_tramp
370         .type   closure_tramp, %object
371         .word   SIMPLE_FUN_HEADER_WIDETAG
372         .equ    closure_tramp, .+1
373         .word   closure_tramp
374         .word   NIL
375         .word   NIL
376         .word   NIL
377         .word   NIL
378         .word   NIL
380         ldr     reg_LEXENV, [reg_LEXENV, #FDEFN_FUN_OFFSET]
381         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
382         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
384         .align  3
385         .global funcallable_instance_tramp
386         .type   funcallable_instance_tramp, %object
387         .word   SIMPLE_FUN_HEADER_WIDETAG
388         .equ    funcallable_instance_tramp, .+1
389         .word   funcallable_instance_tramp
390         .word   NIL
391         .word   NIL
392         .word   NIL
393         .word   NIL
394         .word   NIL
396         ldr     reg_LEXENV, [reg_LEXENV, #FUNCALLABLE_INSTANCE_FUNCTION_OFFSET]
397         ldr     reg_CODE, [reg_LEXENV, #CLOSURE_FUN_OFFSET]
398         add     reg_PC, reg_CODE, #SIMPLE_FUN_CODE_OFFSET
400         @@ FIXME-ARM: The following is random garbage, to make
401         @@ code/debug-int compile. To get the debugger working, this
402         @@ needs to be implemented.
403         .align
404         .global fun_end_breakpoint_guts
405         .type   fun_end_breakpoint_guts, %object
406 fun_end_breakpoint_guts:
407         .global fun_end_breakpoint_trap
408         .type   fun_end_breakpoint_trap, %function
409 fun_end_breakpoint_trap:
410         b       fun_end_breakpoint_trap
411         .global fun_end_breakpoint_end
412 fun_end_breakpoint_end:
414 #ifdef LISP_FEATURE_GENCGC
415         .align
416         .global alloc_tramp
417         .type   alloc_tramp, %function
418 alloc_tramp:
419         stmfd   sp!, {r4, r6, r12, lr}
421         ldr     r4, =foreign_function_call_active
422         str     pc, [r4]
424         ldr     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
425         add     r6, r4, #8*4
426         str     r6, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
428         @@ Create a new frame and save descriptor regs on the stack
429         @@ for the GC to see.
430         str     reg_CFP, [r4, #0]
431         str     reg_NULL, [r4, #4]
432         str     reg_CODE, [r4, #8]
433         add     r4, r4, #3*4
434         stmea   r4, {r0-reg_LEXENV, r8}
436         ldr     r0,  [sp, #4*4]
437         fstmfdd sp!, {d0-d7}
439         mov     lr, pc
440         ldr     pc,=alloc
442         fldmfdd sp!, {d0-d7}
443         str     r0,  [sp, #4*4]
444         ldr     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
445         ldmea   r4, {r0-reg_LEXENV, r8}
446         sub     r4, r4, #8*4
447         str     r4, STATIC_SYMBOL_VALUE(CONTROL_STACK_POINTER)
449         ldr     r4, =foreign_function_call_active
450         mov     r6, #0
451         str     r6, [r4]
453         ldmfd   sp!, {r4, r6, r12, lr}
454         bx      lr
456         .align
457         .global fpu_save
458         .type   fpu_save, %function
459 fpu_save:
460         fstmiad r0, {d0-d7}
461         bx      lr
463         .align
464         .global fpu_restore
465         .type   fpu_restore, %function
466 fpu_restore:
467         add     r0, r0, #16
468         fldmiad r0, {d0-d7}
469         bx      lr
471         .align
472         .global do_pending_interrupt
473         .type   do_pending_interrupt, %function
474 do_pending_interrupt:
475         .word 0xe7f001f0
476         .byte trap_PendingInterrupt
477         .byte 0
478         .byte 0
479         .byte 0
480         bx      lr
481 #endif