895128abb4fdcc5f63f71904acbd3dcc86c1b89f
[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/funcallable-instance.h"
11 #include "genesis/fdefn.h"
12 #include "genesis/static-symbols.h"
13 #include "genesis/simple-fun.h" 
14
15 #define load(sym, reg) \
16         sethi %hi(sym), reg; ld [reg+%lo(sym)], reg
17 #define store(reg, sym) \
18         sethi %hi(sym), reg_L0; st reg, [reg_L0+%lo(sym)]
19
20 /* FIXME */
21 #define FRAMESIZE 0x48
22 #define ST_FLUSH_WINDOWS 0x03
23         .seg    "text"
24         .global call_into_lisp
25         FUNCDEF(call_into_lisp)
26 call_into_lisp:
27         save    %sp, -FRAMESIZE, %sp
28
29         /* Flush all of C's register windows to the stack. */
30         ta      ST_FLUSH_WINDOWS
31
32         /* Save the return address. */
33         st      %i7, [%fp-4]
34
35         /* Clear the descriptor regs. (See sparc/vm.lisp) */
36         mov     reg_ZERO, reg_A0
37         mov     reg_ZERO, reg_A1
38         mov     reg_ZERO, reg_A2
39         mov     reg_ZERO, reg_A3
40         mov     reg_ZERO, reg_A4
41         mov     reg_ZERO, reg_A5
42         mov     reg_ZERO, reg_OCFP
43         mov     reg_ZERO, reg_LRA
44         mov     reg_ZERO, reg_CODE
45
46         /* Establish NIL */
47         set     NIL, reg_NIL
48
49         /* Set the pseudo-atomic flag. */
50         set     4, reg_ALLOC
51
52         /* Turn off foreign function call. */
53         sethi   %hi(foreign_function_call_active), reg_NL0
54         st      reg_ZERO, [reg_NL0+%lo(foreign_function_call_active)]
55
56         /* Load the rest of lisp state. */
57         load(dynamic_space_free_pointer, reg_NL0)
58         add     reg_NL0, reg_ALLOC, reg_ALLOC
59         load(current_binding_stack_pointer, reg_BSP)
60         load(current_control_stack_pointer, reg_CSP)
61         load(current_control_frame_pointer, reg_OCFP)
62
63         /* No longer atomic, and check for interrupt. */
64         sub     reg_ALLOC, 4, reg_ALLOC
65         andcc   reg_ALLOC, 3, reg_ZERO
66         
67         tne     PSEUDO_ATOMIC_TRAP
68         /* Pass in the args. */
69         sll     %i2, 2, reg_NARGS
70         mov     %i1, reg_CFP
71         mov     %i0, reg_LEXENV
72         ld      [reg_CFP+0], reg_A0
73         ld      [reg_CFP+4], reg_A1
74         ld      [reg_CFP+8], reg_A2
75         ld      [reg_CFP+12], reg_A3
76         ld      [reg_CFP+16], reg_A4
77         ld      [reg_CFP+20], reg_A5
78
79         /* Calculate LRA */
80         set     lra + OTHER_POINTER_LOWTAG, reg_LRA
81
82         /* Indirect closure */
83         ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
84
85         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
86         nop
87
88         .align  8
89 lra:
90         .word   RETURN_PC_HEADER_WIDETAG
91
92         /* Blow off any extra values. */
93         mov     reg_OCFP, reg_CSP
94         nop
95
96         /* Return the one value. */
97         mov     reg_A0, %i0
98
99         /* Turn on pseudo_atomic */
100         add     reg_ALLOC, 4, reg_ALLOC
101
102         /* Store LISP state */
103         andn    reg_ALLOC, 7, reg_NL1
104         store(reg_NL1,dynamic_space_free_pointer)
105         store(reg_BSP,current_binding_stack_pointer)
106         store(reg_CSP,current_control_stack_pointer)
107         store(reg_CFP,current_control_frame_pointer)
108
109         /* No longer in Lisp. */
110         store(reg_NL1,foreign_function_call_active)
111
112         /* Were we interrupted? */
113         sub     reg_ALLOC, 4, reg_ALLOC
114         andcc   reg_ALLOC, 3, reg_ZERO
115         tne     PSEUDO_ATOMIC_TRAP
116
117         /* Back to C we go. */
118         ld      [%sp+FRAMESIZE-4], %i7
119         ret
120         restore %sp, FRAMESIZE, %sp
121
122         .global call_into_c
123         FUNCDEF(call_into_c)
124 call_into_c:
125         /* Build a lisp stack frame */
126         mov     reg_CFP, reg_OCFP
127         mov     reg_CSP, reg_CFP
128         add     reg_CSP, 32, reg_CSP
129         st      reg_OCFP, [reg_CFP]
130         st      reg_CODE, [reg_CFP+8]
131
132         /* Turn on pseudo-atomic. */
133         add     reg_ALLOC, 4, reg_ALLOC
134
135         /* Convert the return address to an offset and save it on the stack. */
136         sub     reg_LIP, reg_CODE, reg_L0
137         add     reg_L0, OTHER_POINTER_LOWTAG, reg_L0
138         st      reg_L0, [reg_CFP+4]
139
140         /* Store LISP state */
141         store(reg_BSP,current_binding_stack_pointer)
142         store(reg_CSP,current_control_stack_pointer)
143         store(reg_CFP,current_control_frame_pointer)
144         /* Use reg_CFP as a work register, and restore it */
145         andn    reg_ALLOC, 7, reg_CFP
146         store(reg_CFP,dynamic_space_free_pointer)
147                 load(current_control_frame_pointer, reg_CFP)
148
149         /* No longer in Lisp. */
150         store(reg_CSP,foreign_function_call_active)
151
152         /* Were we interrupted? */
153         sub     reg_ALLOC, 4, reg_ALLOC
154         andcc   reg_ALLOC, 3, reg_ZERO
155         tne     PSEUDO_ATOMIC_TRAP
156
157         /* Into C we go. */
158         call    reg_CFUNC
159         nop
160
161         /*
162          * Note: C calling conventions (32-bit) say that %o0 and %o1
163          * are used to return function results.  In particular 64-bit
164          * results are in %o0 (hi) and %o1 (low).  
165          */
166         
167         /* Re-establish NIL */
168         set     NIL, reg_NIL
169
170         /* Atomic. */
171         set     4, reg_ALLOC
172
173         /* No longer in foreign function call. */
174         sethi   %hi(foreign_function_call_active), reg_NL2
175         st      reg_ZERO, [reg_NL2+%lo(foreign_function_call_active)]
176
177         /* Load the rest of lisp state. */
178         load(dynamic_space_free_pointer, reg_NL2)
179         add     reg_NL2, reg_ALLOC, reg_ALLOC
180         load(current_binding_stack_pointer, reg_BSP)
181         load(current_control_stack_pointer, reg_CSP)
182         load(current_control_frame_pointer, reg_CFP)
183
184         /* Get the return address back. */
185         ld      [reg_CFP+4], reg_LIP
186         ld      [reg_CFP+8], reg_CODE
187         add     reg_LIP, reg_CODE, reg_LIP
188         sub     reg_LIP, OTHER_POINTER_LOWTAG, reg_LIP
189
190         /* No longer atomic. */
191         sub     reg_ALLOC, 4, reg_ALLOC
192         andcc   reg_ALLOC, 3, reg_ZERO
193         tne     PSEUDO_ATOMIC_TRAP
194
195         /* Reset the lisp stack. */
196         /* Note: OCFP is in one of the locals, it gets preserved across C. */
197         mov     reg_CFP, reg_CSP
198         mov     reg_OCFP, reg_CFP
199
200         /* And back into lisp. */
201         ret
202         nop
203
204 /* Lisp calling convention. notice the first .byte line.
205  */             
206         .global undefined_tramp
207         FUNCDEF(undefined_tramp)
208         .align  8
209         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
210 undefined_tramp = . + 1
211         .word   undefined_tramp
212         .word   NIL
213         .word   NIL
214         .word   NIL
215         .word   NIL
216         .word   NIL
217
218         b       1f
219         unimp   trap_Cerror
220         .byte   4
221         .byte   UNDEFINED_FUN_ERROR
222         .byte   254, sc_DescriptorReg, 3
223         .align  4
224 1:
225         ld      [reg_FDEFN+FDEFN_RAW_ADDR_OFFSET], reg_CODE
226         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
227         nop
228
229 /* Lisp calling convention. Notice the first .byte line.
230  */             
231         .global closure_tramp
232         FUNCDEF(closure_tramp)
233         .align  8
234         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
235 closure_tramp = . + 1
236         .word   closure_tramp
237         .word   NIL
238         .word   NIL
239         .word   NIL
240         .word   NIL
241         .word   NIL
242
243         ld      [reg_FDEFN+FDEFN_FUN_OFFSET], reg_LEXENV
244         ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
245         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
246         nop
247
248         .global funcallable_instance_tramp
249         FUNCDEF(funcallable_instance_tramp)
250         .align 8
251         .word SIMPLE_FUN_HEADER_WIDETAG
252 funcallable_instance_tramp = . + 1
253         .word funcallable_instance_tramp
254         .word NIL
255         .word NIL
256         .word NIL
257         .word NIL
258         .word NIL
259
260         ld      [reg_LEXENV+FUNCALLABLE_INSTANCE_FUNCTION_OFFSET], reg_LEXENV
261         ld      [reg_LEXENV+CLOSURE_FUN_OFFSET], reg_CODE
262         jmp     reg_CODE+SIMPLE_FUN_CODE_OFFSET
263         nop
264 /*
265  * Function-end breakpoint magic.
266  */
267
268 /*
269  * For an explanation of the magic involved in function-end
270  * breakpoints, see the implementation in ppc-assem.S.
271  */
272
273         .text
274         .align  8
275         .global fun_end_breakpoint_guts
276 fun_end_breakpoint_guts:
277         .word   RETURN_PC_HEADER_WIDETAG + 0x800
278         b       1f
279         nop
280         mov     reg_CSP, reg_OCFP
281         add     4, reg_CSP, reg_CSP
282         mov     4, reg_NARGS
283         mov     reg_NIL, reg_A1
284         mov     reg_NIL, reg_A2
285         mov     reg_NIL, reg_A3
286         mov     reg_NIL, reg_A4
287         mov     reg_NIL, reg_A5
288 1:
289
290         .global fun_end_breakpoint_trap
291 fun_end_breakpoint_trap:
292         unimp   trap_FunEndBreakpoint
293         b       1b
294         nop
295
296         .global fun_end_breakpoint_end
297 fun_end_breakpoint_end:
298
299         .global sparc_flush_icache
300         FUNCDEF(sparc_flush_icache)
301 sparc_flush_icache:
302         add %o0,%o1,%o2
303 1:      iflush %o0                      ! flush instruction cache
304         add %o0,8,%o0
305         cmp %o0,%o2
306         blt 1b
307         nop
308         retl                            ! return from leaf routine
309         nop
310
311         .global do_pending_interrupt
312         FUNCDEF(do_pending_interrupt)
313 do_pending_interrupt:
314         unimp   trap_PendingInterrupt
315         retl
316         nop
317
318 /*
319  * Save the FPU state.  %o0 contains a pointer to where we can
320  * store our state.
321  */
322
323 /*
324  * Note we only save the 16 double-float registers (which saves
325  * the 32 single-float values too, I think).  If we're compiling for
326  * a sparc v9, the Lisp code can actually use all 32 double-float
327  * registers.  For later.
328  */
329         .global fpu_save
330         FUNCDEF(fpu_save)
331 fpu_save:
332         std     %f0, [%o0 + 4*0]
333         std     %f2, [%o0 + 4*2]
334         std     %f4, [%o0 + 4*4]
335         std     %f6, [%o0 + 4*6]
336         std     %f8, [%o0 + 4*8]
337         std     %f10, [%o0 + 4*10]
338         std     %f12, [%o0 + 4*12]
339         std     %f14, [%o0 + 4*14]
340         std     %f16, [%o0 + 4*16]
341         std     %f18, [%o0 + 4*18]
342         std     %f20, [%o0 + 4*20]
343         std     %f22, [%o0 + 4*22]
344         std     %f24, [%o0 + 4*24]
345         std     %f26, [%o0 + 4*26]
346         std     %f28, [%o0 + 4*28]
347         std     %f30, [%o0 + 4*30]
348 #ifdef FEATURE_SPARC_V9
349         std     %f32, [%o0 + 4*32]
350         std     %f34, [%o0 + 4*34]
351         std     %f36, [%o0 + 4*36]
352         std     %f38, [%o0 + 4*38]
353         std     %f40, [%o0 + 4*40]
354         std     %f42, [%o0 + 4*42]
355         std     %f44, [%o0 + 4*44]
356         std     %f46, [%o0 + 4*46]
357         std     %f48, [%o0 + 4*48]
358         std     %f50, [%o0 + 4*50]
359         std     %f52, [%o0 + 4*52]
360         std     %f54, [%o0 + 4*54]
361         std     %f56, [%o0 + 4*56]
362         std     %f58, [%o0 + 4*58]
363         std     %f60, [%o0 + 4*60]
364         std     %f62, [%o0 + 4*62]
365         st      %fsr, [%o0 + 4*64]
366 #else
367         st      %fsr, [%o0 + 4*32]
368 #endif
369         retl
370         nop
371
372         .global fpu_restore
373         FUNCDEF(fpu_restore)
374 fpu_restore:
375         ldd     [%o0 + 4*0], %f0
376         ldd     [%o0 + 4*2], %f2
377         ldd     [%o0 + 4*4], %f4
378         ldd     [%o0 + 4*6], %f6
379         ldd     [%o0 + 4*8], %f8
380         ldd     [%o0 + 4*10], %f10
381         ldd     [%o0 + 4*12], %f12
382         ldd     [%o0 + 4*14], %f14
383         ldd     [%o0 + 4*16], %f16
384         ldd     [%o0 + 4*18], %f18
385         ldd     [%o0 + 4*20], %f20
386         ldd     [%o0 + 4*22], %f22
387         ldd     [%o0 + 4*24], %f24
388         ldd     [%o0 + 4*26], %f26
389         ldd     [%o0 + 4*28], %f28
390         ldd     [%o0 + 4*30], %f30
391 #ifdef FEATURE_SPARC_V9
392         ldd     [%o0 + 4*32], %f32
393         ldd     [%o0 + 4*34], %f34
394         ldd     [%o0 + 4*36], %f36
395         ldd     [%o0 + 4*38], %f38
396         ldd     [%o0 + 4*40], %f40
397         ldd     [%o0 + 4*42], %f42
398         ldd     [%o0 + 4*44], %f44
399         ldd     [%o0 + 4*46], %f46
400         ldd     [%o0 + 4*48], %f48
401         ldd     [%o0 + 4*50], %f50
402         ldd     [%o0 + 4*52], %f52
403         ldd     [%o0 + 4*54], %f54
404         ldd     [%o0 + 4*56], %f56
405         ldd     [%o0 + 4*58], %f58
406         ldd     [%o0 + 4*60], %f60
407         ldd     [%o0 + 4*62], %f62
408         ld      [%o0 + 4*64], %fsr
409 #else
410         ld      [%o0 + 4*32], %fsr
411 #endif
412         retl
413         nop
414
415         .global save_context
416         FUNCDEF(save_context)
417 save_context:
418         ta      ST_FLUSH_WINDOWS        ! flush register windows
419         retl                            ! return from leaf routine
420         nop