0.8.14.5: Join the foreign legion!
[sbcl.git] / src / runtime / sparc-assem.S
1 #define _ASM
2
3 #include "sparc-funcdef.h"
4
5 #define LANGUAGE_ASSEMBLY
6 #include "lispregs.h"
7 #include "globals.h"
8 #include "sbcl.h"
9 #include "genesis/closure.h"
10 #include "genesis/fdefn.h"
11 #include "genesis/static-symbols.h"
12 #include "genesis/simple-fun.h" 
13
14 #define load(sym, reg) \
15         sethi %hi(sym), reg; ld [reg+%lo(sym)], reg
16 #define store(reg, sym) \
17         sethi %hi(sym), reg_L0; st reg, [reg_L0+%lo(sym)]
18
19 /* FIXME */
20 #define FRAMESIZE 0x48
21 #define ST_FLUSH_WINDOWS 0x03
22         .seg    "text"
23         .global call_into_lisp
24         FUNCDEF(call_into_lisp)
25 call_into_lisp:
26         save    %sp, -FRAMESIZE, %sp
27
28         /* Flush all of C's register windows to the stack. */
29         ta      ST_FLUSH_WINDOWS
30
31         /* Save the return address. */
32         st      %i7, [%fp-4]
33
34         /* Clear the descriptor regs. (See sparc/vm.lisp) */
35         mov     reg_ZERO, reg_A0
36         mov     reg_ZERO, reg_A1
37         mov     reg_ZERO, reg_A2
38         mov     reg_ZERO, reg_A3
39         mov     reg_ZERO, reg_A4
40         mov     reg_ZERO, reg_A5
41         mov     reg_ZERO, reg_OCFP
42         mov     reg_ZERO, reg_LRA
43         mov     reg_ZERO, reg_CODE
44
45         /* Establish NIL */
46         set     NIL, reg_NIL
47
48         /* Set the pseudo-atomic flag. */
49         set     4, reg_ALLOC
50
51         /* Turn off foreign function call. */
52         sethi   %hi(foreign_function_call_active), reg_NL0
53         st      reg_ZERO, [reg_NL0+%lo(foreign_function_call_active)]
54
55         /* Load the rest of lisp state. */
56         load(dynamic_space_free_pointer, reg_NL0)
57         add     reg_NL0, reg_ALLOC, reg_ALLOC
58         load(current_binding_stack_pointer, reg_BSP)
59         load(current_control_stack_pointer, reg_CSP)
60         load(current_control_frame_pointer, reg_OCFP)
61
62         /* No longer atomic, and check for interrupt. */
63         sub     reg_ALLOC, 4, reg_ALLOC
64         andcc   reg_ALLOC, 3, reg_ZERO
65         
66         tne     PSEUDO_ATOMIC_TRAP
67         /* Pass in the args. */
68         sll     %i2, 2, reg_NARGS
69         mov     %i1, reg_CFP
70         mov     %i0, reg_LEXENV
71         ld      [reg_CFP+0], reg_A0
72         ld      [reg_CFP+4], reg_A1
73         ld      [reg_CFP+8], reg_A2
74         ld      [reg_CFP+12], reg_A3
75         ld      [reg_CFP+16], reg_A4
76         ld      [reg_CFP+20], reg_A5
77
78         /* Calculate LRA */
79         set     lra + OTHER_POINTER_LOWTAG, reg_LRA
80
81         /* Indirect closure */
82         ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
83
84         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
85         nop
86
87         .align  8
88 lra:
89         .word   RETURN_PC_HEADER_WIDETAG
90
91         /* Blow off any extra values. */
92         mov     reg_OCFP, reg_CSP
93         nop
94
95         /* Return the one value. */
96         mov     reg_A0, %i0
97
98         /* Turn on pseudo_atomic */
99         add     reg_ALLOC, 4, reg_ALLOC
100
101         /* Store LISP state */
102         andn    reg_ALLOC, 7, reg_NL1
103         store(reg_NL1,dynamic_space_free_pointer)
104         store(reg_BSP,current_binding_stack_pointer)
105         store(reg_CSP,current_control_stack_pointer)
106         store(reg_CFP,current_control_frame_pointer)
107
108         /* No longer in Lisp. */
109         store(reg_NL1,foreign_function_call_active)
110
111         /* Were we interrupted? */
112         sub     reg_ALLOC, 4, reg_ALLOC
113         andcc   reg_ALLOC, 3, reg_ZERO
114         tne     PSEUDO_ATOMIC_TRAP
115
116         /* Back to C we go. */
117         ld      [%sp+FRAMESIZE-4], %i7
118         ret
119         restore %sp, FRAMESIZE, %sp
120
121         .global call_into_c
122         FUNCDEF(call_into_c)
123 call_into_c:
124         /* Build a lisp stack frame */
125         mov     reg_CFP, reg_OCFP
126         mov     reg_CSP, reg_CFP
127         add     reg_CSP, 32, reg_CSP
128         st      reg_OCFP, [reg_CFP]
129         st      reg_CODE, [reg_CFP+8]
130
131         /* Turn on pseudo-atomic. */
132         add     reg_ALLOC, 4, reg_ALLOC
133
134         /* Convert the return address to an offset and save it on the stack. */
135         sub     reg_LIP, reg_CODE, reg_L0
136         add     reg_L0, OTHER_POINTER_LOWTAG, reg_L0
137         st      reg_L0, [reg_CFP+4]
138
139         /* Store LISP state */
140         store(reg_BSP,current_binding_stack_pointer)
141         store(reg_CSP,current_control_stack_pointer)
142         store(reg_CFP,current_control_frame_pointer)
143         /* Use reg_CFP as a work register, and restore it */
144         andn    reg_ALLOC, 7, reg_CFP
145         store(reg_CFP,dynamic_space_free_pointer)
146                 load(current_control_frame_pointer, reg_CFP)
147
148         /* No longer in Lisp. */
149         store(reg_CSP,foreign_function_call_active)
150
151         /* Were we interrupted? */
152         sub     reg_ALLOC, 4, reg_ALLOC
153         andcc   reg_ALLOC, 3, reg_ZERO
154         tne     PSEUDO_ATOMIC_TRAP
155
156         /* Into C we go. */
157         call    reg_CFUNC
158         nop
159
160         /*
161          * Note: C calling conventions (32-bit) say that %o0 and %o1
162          * are used to return function results.  In particular 64-bit
163          * results are in %o0 (hi) and %o1 (low).  
164          */
165         
166         /* Re-establish NIL */
167         set     NIL, reg_NIL
168
169         /* Atomic. */
170         set     4, reg_ALLOC
171
172         /* No longer in foreign function call. */
173         sethi   %hi(foreign_function_call_active), reg_NL2
174         st      reg_ZERO, [reg_NL2+%lo(foreign_function_call_active)]
175
176         /* Load the rest of lisp state. */
177         load(dynamic_space_free_pointer, reg_NL2)
178         add     reg_NL2, reg_ALLOC, reg_ALLOC
179         load(current_binding_stack_pointer, reg_BSP)
180         load(current_control_stack_pointer, reg_CSP)
181         load(current_control_frame_pointer, reg_CFP)
182
183         /* Get the return address back. */
184         ld      [reg_CFP+4], reg_LIP
185         ld      [reg_CFP+8], reg_CODE
186         add     reg_LIP, reg_CODE, reg_LIP
187         sub     reg_LIP, OTHER_POINTER_LOWTAG, reg_LIP
188
189         /* No longer atomic. */
190         sub     reg_ALLOC, 4, reg_ALLOC
191         andcc   reg_ALLOC, 3, reg_ZERO
192         tne     PSEUDO_ATOMIC_TRAP
193
194         /* Reset the lisp stack. */
195         /* Note: OCFP is in one of the locals, it gets preserved across C. */
196         mov     reg_CFP, reg_CSP
197         mov     reg_OCFP, reg_CFP
198
199         /* And back into lisp. */
200         ret
201         nop
202
203 /* Lisp calling convention. notice the first .byte line.
204  */             
205         .global undefined_tramp
206         FUNCDEF(undefined_tramp)
207         .align  8
208         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
209 undefined_tramp = . + 1
210         .word   undefined_tramp
211         .word   NIL
212         .word   NIL
213         .word   NIL
214         .word   NIL
215
216         b       1f
217         unimp   trap_Cerror
218         .byte   4
219         .byte   UNDEFINED_FUN_ERROR
220         .byte   254, sc_DescriptorReg, 3
221         .align  4
222 1:
223         ld      [reg_FDEFN+FDEFN_RAW_ADDR_OFFSET], reg_CODE
224         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
225         nop
226
227 /* Lisp calling convention. Notice the first .byte line.
228  */             
229         .global closure_tramp
230         FUNCDEF(closure_tramp)
231         .align  8
232         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
233 closure_tramp = . + 1
234         .word   closure_tramp
235         .word   NIL
236         .word   NIL
237         .word   NIL
238         .word   NIL
239
240         ld      [reg_FDEFN+FDEFN_FUN_OFFSET], reg_LEXENV
241         ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
242         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
243         nop
244
245
246 /*
247  * Function-end breakpoint magic.
248  */
249
250         .text
251         .align  8
252         .global fun_end_breakpoint_guts
253 fun_end_breakpoint_guts:
254         .word   RETURN_PC_HEADER_WIDETAG
255         b       1f
256         nop
257         mov     reg_CSP, reg_OCFP
258         add     4, reg_CSP, reg_CSP
259         mov     4, reg_NARGS
260         mov     reg_NIL, reg_A1
261         mov     reg_NIL, reg_A2
262         mov     reg_NIL, reg_A3
263         mov     reg_NIL, reg_A4
264         mov     reg_NIL, reg_A5
265 1:
266
267         .global fun_end_breakpoint_trap
268 fun_end_breakpoint_trap:
269         unimp   trap_FunEndBreakpoint
270         b       1b
271         nop
272
273         .global fun_end_breakpoint_end
274 fun_end_breakpoint_end:
275
276         .global sparc_flush_icache
277         FUNCDEF(sparc_flush_icache)
278 sparc_flush_icache:
279         add %o0,%o1,%o2
280 1:      iflush %o0                      ! flush instruction cache
281         add %o0,8,%o0
282         cmp %o0,%o2
283         blt 1b
284         nop
285         retl                            ! return from leaf routine
286         nop
287
288         .global save_context
289         FUNCDEF(save_context)
290 save_context:
291         ta      ST_FLUSH_WINDOWS        ! flush register windows
292         retl                            ! return from leaf routine
293         nop