1 #define LANGUAGE_ASSEMBLY
6 #include "genesis/simple-fun.h"
7 #include "genesis/fdefn.h"
8 #include "genesis/closure.h"
9 #include "genesis/static-symbols.h"
11 #define FUNCDEF(x) .text ; \
15 #define GFUNCDEF(x) .globl x ; \
18 #define SET_SIZE(x) .size x,.-x
20 /* Load a register from a global, using the register as an intermediary */
21 /* The register will be a fixnum for one instruction, so this is gc-safe */
23 #define load(reg,global) \
24 lis reg,global@ha; lwz reg,global@l(reg)
25 #define store(reg,temp,global) \
26 lis temp,global@ha; stw reg,global@l(temp)
28 #define FIRST_SAVE_FPR 14 /* lowest-numbered non-volatile FPR */
29 #define FIRST_SAVE_GPR 14 /* lowest-numbered non-volatile GPR */
30 #define NFPR_SAVE_BYTES(n) ((32-(n))*8)
31 #define NGPR_SAVE_BYTES(n) ((32-(~1&((n)+1)))*4)
32 #define FRAME_ARG_BYTES(n) (((((n)+2)*4)+15)&~15)
34 #define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \
35 (NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words+savecr))
36 #define SAVE_FPR(n) stfd n,-8*(32-(n))(11)
37 #define SAVE_GPR(n) stw n,-4*(32-(n))(11)
38 #define FULL_FRAME_SIZE FRAME_SIZE(FIRST_SAVE_GPR,FIRST_SAVE_FPR,0,1)
40 #define RESTORE_FPR(n) lfd n,-8*(32-(n))(11)
41 #define RESTORE_GPR(n) lwz n,-4*(32-(n))(11)
42 #define C_FULL_PROLOG \
46 stwu 1,-FULL_FRAME_SIZE(1) ; \
65 la 11,-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \
86 #define C_FULL_EPILOG \
87 la 11,FULL_FRAME_SIZE-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(1) ; \
106 la 11,NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \
135 * Function to transfer control into lisp. The lisp object to invoke is
136 * passed as the first argument, which puts it in NL0
139 GFUNCDEF(call_into_lisp)
143 /* store(reg_POLL,11,saver2) */
144 /* Initialize tagged registers */
161 ori reg_NULL,reg_NULL,NIL@l
163 /* Turn on pseudo-atomic */
167 store(reg_ZERO,reg_NL4,foreign_function_call_active)
168 load(reg_NL4,dynamic_space_free_pointer)
169 add reg_ALLOC,reg_ALLOC,reg_NL4
170 load(reg_BSP,current_binding_stack_pointer)
171 load(reg_CSP,current_control_stack_pointer)
172 load(reg_OCFP,current_control_frame_pointer)
174 /* No longer atomic, and check for interrupt */
175 add reg_ALLOC,reg_ALLOC,reg_NL3
178 /* Pass in the arguments */
181 mr reg_LEXENV,reg_NL0
182 lwz reg_A0,0(reg_CFP)
183 lwz reg_A1,4(reg_CFP)
184 lwz reg_A2,8(reg_CFP)
185 lwz reg_A3,12(reg_CFP)
189 addi reg_LRA,reg_LRA,lra@l
190 addi reg_LRA,reg_LRA,OTHER_POINTER_LOWTAG
192 /* Function is an indirect closure */
193 lwz reg_CODE,SIMPLE_FUN_SELF_OFFSET(reg_LEXENV)
194 addi reg_LIP,reg_CODE,6*4-FUN_POINTER_LOWTAG
196 slwi reg_NARGS,reg_NL2,2
201 .long RETURN_PC_HEADER_WIDETAG
203 /* Blow off any extra values. */
207 /* Return the one value. */
211 /* Turn on pseudo-atomic */
213 la reg_ALLOC,4(reg_ALLOC)
215 /* Store lisp state */
216 clrrwi reg_NL1,reg_ALLOC,3
217 store(reg_NL1,reg_NL2,dynamic_space_free_pointer)
218 /* store(reg_POLL,reg_NL2,poll_flag) */
219 /* load(reg_NL2,current_thread) */
220 store(reg_BSP,reg_NL2,current_binding_stack_pointer)
221 store(reg_CSP,reg_NL2,current_control_stack_pointer)
222 store(reg_CFP,reg_NL2,current_control_frame_pointer)
223 /* load(reg_POLL,saver2) */
225 /* No longer in Lisp. */
226 store(reg_NL1,reg_NL2,foreign_function_call_active)
228 /* Check for interrupt */
229 add reg_ALLOC,reg_ALLOC,reg_NL3
237 SET_SIZE(call_into_lisp)
240 GFUNCDEF(call_into_c)
241 /* We're kind of low on unboxed, non-dedicated registers here:
242 most of the unboxed registers may have outgoing C args in them.
243 CFUNC is going to have to go in the CTR in a moment, anyway
244 so we'll free it up soon. reg_NFP is preserved by lisp if it
245 has a meaningful value in it, so we can use it. reg_NARGS is
246 free when it's not holding a copy of the "real" reg_NL3, which
247 gets tied up by the pseudo-atomic mechanism */
250 /* Build a lisp stack frame */
253 la reg_CSP,32(reg_CSP)
254 stw reg_OCFP,0(reg_CFP)
255 stw reg_CODE,8(reg_CFP)
256 /* The pseudo-atomic mechanism wants to use reg_NL3, but that
257 may be an outgoing C argument. Copy reg_NL3 to something that's
258 unboxed and -not- one of the C argument registers */
261 /* Turn on pseudo-atomic */
263 la reg_ALLOC,4(reg_ALLOC)
265 /* Convert the return address to an offset and save it on the stack. */
266 sub reg_NFP,reg_LIP,reg_CODE
267 la reg_NFP,OTHER_POINTER_LOWTAG(reg_NFP)
268 stw reg_NFP,4(reg_CFP)
270 /* Store Lisp state */
271 clrrwi reg_NFP,reg_ALLOC,3
272 store(reg_NFP,reg_CFUNC,dynamic_space_free_pointer)
273 /* load(reg_CFUNC,current_thread) */
275 store(reg_BSP,reg_CFUNC,current_binding_stack_pointer)
276 store(reg_CSP,reg_CFUNC,current_control_stack_pointer)
277 store(reg_CFP,reg_CFUNC,current_control_frame_pointer)
279 /* No longer in Lisp */
280 store(reg_CSP,reg_CFUNC,foreign_function_call_active)
281 /* load(reg_POLL,saver2) */
282 /* Disable pseudo-atomic; check pending interrupt */
283 add reg_ALLOC,reg_ALLOC,reg_NL3
290 /* Re-establish NIL */
292 ori reg_NULL,reg_NULL,NIL@l
296 /* If we GC'ed during the FF code (as the result of a callback ?)
297 the tagged lisp registers may now contain garbage (since the
298 registers were saved by C and not seen by the GC.) Put something
299 harmless in all such registers before allowing an interrupt */
303 /* reg_OCFP was pointing to a control stack frame & was preserved by C */
318 /* No long in foreign function call. */
319 store(reg_ZERO,reg_NL2,foreign_function_call_active)
321 /* The free pointer may have moved */
322 load(reg_NL4,dynamic_space_free_pointer)
323 add reg_ALLOC,reg_ALLOC,reg_NL4
325 /* The BSP wasn't preserved by C, so load it */
326 load(reg_BSP,current_binding_stack_pointer)
328 /* Other lisp stack/frame pointers were preserved by C.
329 I can't imagine why they'd have moved */
331 /* Get the return address back. */
332 lwz reg_LIP,4(reg_CFP)
333 lwz reg_CODE,8(reg_CFP)
334 add reg_LIP,reg_CODE,reg_LIP
335 la reg_LIP,-OTHER_POINTER_LOWTAG(reg_LIP)
337 /* No longer atomic */
338 add reg_ALLOC,reg_ALLOC,reg_NL3
342 /* Reset the lisp stack. */
346 /* And back into Lisp. */
349 SET_SIZE(call_into_c)
351 GFUNCDEF(xundefined_tramp)
352 .globl undefined_tramp
353 .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG
357 .long undefined_tramp
362 twllei reg_ZERO,trap_Cerror
364 .byte UNDEFINED_FUN_ERROR
365 .byte 254, sc_DescriptorReg+0x40, 1 /* 140? sparc says sc_descriptorReg */
367 1: lwz reg_CODE,FDEFN_RAW_ADDR_OFFSET(reg_FDEFN)
368 la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE)
372 SET_SIZE(xundefined_tramp)
374 GFUNCDEF(xclosure_tramp)
376 .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG
385 lwz reg_LEXENV,FDEFN_FUN_OFFSET(reg_FDEFN)
386 lwz reg_CODE,CLOSURE_FUN_OFFSET(reg_LEXENV)
387 la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE)
391 SET_SIZE(xclosure_tramp)
393 GFUNCDEF(fun_end_breakpoint_trap)
395 SET_SIZE(fun_end_breakpoint_trap)
397 GFUNCDEF(fun_end_breakpoint)
399 SET_SIZE(fun_end_breakpoint)
401 GFUNCDEF(fun_end_breakpoint_guts)
403 SET_SIZE(fun_end_breakpoint_guts)
405 GFUNCDEF(fun_end_breakpoint_end)
407 SET_SIZE(fun_end_breakpoint_end)
410 GFUNCDEF(ppc_flush_cache_line)
417 SET_SIZE(ppc_flush_cache_line)