1 #define LANGUAGE_ASSEMBLY
7 #include "genesis/simple-fun.h"
8 #include "genesis/fdefn.h"
9 #include "genesis/closure.h"
10 #include "genesis/static-symbols.h"
13 #define CSYMBOL(x) _ ## x
19 #define FUNCDEF(x) .text @ \
23 #define GFUNCDEF(x) .globl _/**/x @ \
26 #define FUNCDEF(x) .text ; \
31 #define GFUNCDEF(x) .globl x ; \
38 #define SET_SIZE(x) .size x,.-x
41 /* Load a register from a global, using the register as an intermediary */
42 /* The register will be a fixnum for one instruction, so this is gc-safe */
45 #define load(reg,global) \
46 lis reg,ha16(global) @ \
47 lwz reg,lo16(global)(reg) ; Comment
48 #define store(reg,temp,global) \
49 lis temp,ha16(global) @\
50 stw reg,lo16(global)(temp) ; Comment
52 #define load(reg,global) \
53 lis reg,global@ha; lwz reg,global@l(reg)
54 #define store(reg,temp,global) \
55 lis temp,global@ha; stw reg,global@l(temp)
58 #define FIRST_SAVE_FPR 14 /* lowest-numbered non-volatile FPR */
60 #define FIRST_SAVE_GPR 13 /* lowest-numbered non-volatile GPR */
61 #define NGPR_SAVE_BYTES(n) ((32-(n))*4)
62 #define FRAME_ARG_BYTES(n) (((((n)+6)*4)+15)&~15)
64 #define FIRST_SAVE_GPR 14 /* lowest-numbered non-volatile GPR */
65 #define NGPR_SAVE_BYTES(n) ((32-(~1&((n)+1)))*4)
66 #define FRAME_ARG_BYTES(n) (((((n)+2)*4)+15)&~15)
68 #define NFPR_SAVE_BYTES(n) ((32-(n))*8)
71 #define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \
72 (NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words))
73 #define SAVE_FPR(n) stfd f##n,-8*(32- n)(r11)
74 #define SAVE_GPR(n) stw r##n,-4*(32- n)(r11)
75 #define FULL_FRAME_SIZE FRAME_SIZE(FIRST_SAVE_GPR,FIRST_SAVE_FPR,8,1)
76 #define RESTORE_FPR(n) lfd f##n,-8*(32- n)(r11)
77 #define RESTORE_GPR(n) lwz r##n,-4*(32- n)(r11)
79 #define FRAME_SIZE(first_g,first_f,out_arg_words,savecr) \
80 (NFPR_SAVE_BYTES(first_f)+ NGPR_SAVE_BYTES(first_g)+ FRAME_ARG_BYTES(out_arg_words+savecr))
81 #define SAVE_FPR(n) stfd n,-8*(32-(n))(11)
82 #define SAVE_GPR(n) stw n,-4*(32-(n))(11)
83 #define FULL_FRAME_SIZE FRAME_SIZE(FIRST_SAVE_GPR,FIRST_SAVE_FPR,0,1)
85 #define RESTORE_FPR(n) lfd n,-8*(32-(n))(11)
86 #define RESTORE_GPR(n) lwz n,-4*(32-(n))(11)
90 #define C_FULL_PROLOG \
94 stw REG(0),4(REG(1)) @ \
96 stw REG(0),8(REG(1)) @ \
98 stwu REG(1),-FULL_FRAME_SIZE(REG(1)) @ \
117 la REG(11),-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(11)) @ \
139 #define C_FULL_EPILOG \
140 la REG(11),FULL_FRAME_SIZE-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(1)) @ \
160 la REG(11),NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(REG(11)) @ \
179 lwz REG(1),0(REG(1)) @ \
180 lwz REG(0),4(REG(1)) @ \
182 lwz REG(0),8(REG(1)) @ \
187 #define C_FULL_PROLOG \
191 stwu 1,-FULL_FRAME_SIZE(1) ; \
210 la 11,-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \
232 #define C_FULL_EPILOG \
235 la 11,FULL_FRAME_SIZE-NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(1) ; \
254 la 11,NFPR_SAVE_BYTES(FIRST_SAVE_FPR)(11) ; \
282 * Function to transfer control into lisp. The lisp object to invoke is
283 * passed as the first argument, which puts it in NL0
286 GFUNCDEF(call_into_lisp)
288 /* store(reg_POLL,11,saver2) */
289 /* Initialize tagged registers */
306 lis reg_NULL,hi16(NIL)
307 ori reg_NULL,reg_NULL,lo16(NIL)
310 ori reg_NULL,reg_NULL,NIL@l
312 /* Turn on pseudo-atomic */
316 store(reg_ZERO,reg_NL4,CSYMBOL(foreign_function_call_active))
317 load(reg_NL4,CSYMBOL(dynamic_space_free_pointer))
318 add reg_ALLOC,reg_ALLOC,reg_NL4
319 load(reg_BSP,CSYMBOL(current_binding_stack_pointer))
320 load(reg_CSP,CSYMBOL(current_control_stack_pointer))
321 load(reg_OCFP,CSYMBOL(current_control_frame_pointer))
323 /* No longer atomic, and check for interrupt */
324 add reg_ALLOC,reg_ALLOC,reg_NL3
327 /* Pass in the arguments */
330 mr reg_LEXENV,reg_NL0
331 lwz reg_A0,0(reg_CFP)
332 lwz reg_A1,4(reg_CFP)
333 lwz reg_A2,8(reg_CFP)
334 lwz reg_A3,12(reg_CFP)
338 lis reg_LRA,ha16(lra)
339 addi reg_LRA,reg_LRA,lo16(lra)
342 addi reg_LRA,reg_LRA,lra@l
344 addi reg_LRA,reg_LRA,OTHER_POINTER_LOWTAG
346 /* Function is an indirect closure */
347 lwz reg_CODE,SIMPLE_FUN_SELF_OFFSET(reg_LEXENV)
348 addi reg_LIP,reg_CODE,6*4-FUN_POINTER_LOWTAG
350 slwi reg_NARGS,reg_NL2,2
355 .long RETURN_PC_HEADER_WIDETAG
357 /* Blow off any extra values. */
361 /* Return the one value. */
365 /* Turn on pseudo-atomic */
367 la reg_ALLOC,4(reg_ALLOC)
369 /* Store lisp state */
370 clrrwi reg_NL1,reg_ALLOC,3
371 store(reg_NL1,reg_NL2,CSYMBOL(dynamic_space_free_pointer))
372 /* store(reg_POLL,reg_NL2,poll_flag) */
373 /* load(reg_NL2,current_thread) */
374 store(reg_BSP,reg_NL2,CSYMBOL(current_binding_stack_pointer))
375 store(reg_CSP,reg_NL2,CSYMBOL(current_control_stack_pointer))
376 store(reg_CFP,reg_NL2,CSYMBOL(current_control_frame_pointer))
377 /* load(reg_POLL,saver2) */
379 /* No longer in Lisp. */
380 store(reg_NL1,reg_NL2,CSYMBOL(foreign_function_call_active))
382 /* Check for interrupt */
383 add reg_ALLOC,reg_ALLOC,reg_NL3
389 SET_SIZE(call_into_lisp)
392 GFUNCDEF(call_into_c)
393 /* We're kind of low on unboxed, non-dedicated registers here:
394 most of the unboxed registers may have outgoing C args in them.
395 CFUNC is going to have to go in the CTR in a moment, anyway
396 so we'll free it up soon. reg_NFP is preserved by lisp if it
397 has a meaningful value in it, so we can use it. reg_NARGS is
398 free when it's not holding a copy of the "real" reg_NL3, which
399 gets tied up by the pseudo-atomic mechanism */
402 /* Build a lisp stack frame */
405 la reg_CSP,32(reg_CSP)
406 stw reg_OCFP,0(reg_CFP)
407 stw reg_CODE,8(reg_CFP)
408 /* The pseudo-atomic mechanism wants to use reg_NL3, but that
409 may be an outgoing C argument. Copy reg_NL3 to something that's
410 unboxed and -not- one of the C argument registers */
413 /* Turn on pseudo-atomic */
415 la reg_ALLOC,4(reg_ALLOC)
417 /* Convert the return address to an offset and save it on the stack. */
418 sub reg_NFP,reg_LIP,reg_CODE
419 la reg_NFP,OTHER_POINTER_LOWTAG(reg_NFP)
420 stw reg_NFP,4(reg_CFP)
422 /* Store Lisp state */
423 clrrwi reg_NFP,reg_ALLOC,3
424 store(reg_NFP,reg_CFUNC,CSYMBOL(dynamic_space_free_pointer))
425 /* load(reg_CFUNC,current_thread) */
427 store(reg_BSP,reg_CFUNC,CSYMBOL(current_binding_stack_pointer))
428 store(reg_CSP,reg_CFUNC,CSYMBOL(current_control_stack_pointer))
429 store(reg_CFP,reg_CFUNC,CSYMBOL(current_control_frame_pointer))
431 /* No longer in Lisp */
432 store(reg_CSP,reg_CFUNC,CSYMBOL(foreign_function_call_active))
433 /* load(reg_POLL,saver2) */
434 /* Disable pseudo-atomic; check pending interrupt */
435 add reg_ALLOC,reg_ALLOC,reg_NL3
440 /* PowerOpen (i.e. OS X) requires the callee address in r12
441 (a.k.a. CFUNC), so move it back there, too. */
447 /* Re-establish NIL */
449 lis reg_NULL,hi16(NIL)
450 ori reg_NULL,reg_NULL,lo16(NIL)
453 ori reg_NULL,reg_NULL,NIL@l
458 /* If we GC'ed during the FF code (as the result of a callback ?)
459 the tagged lisp registers may now contain garbage (since the
460 registers were saved by C and not seen by the GC.) Put something
461 harmless in all such registers before allowing an interrupt */
465 /* reg_OCFP was pointing to a control stack frame & was preserved by C */
480 /* No long in foreign function call. */
481 store(reg_ZERO,reg_NL2,CSYMBOL(foreign_function_call_active))
483 /* The free pointer may have moved */
484 load(reg_NL4,CSYMBOL(dynamic_space_free_pointer))
485 add reg_ALLOC,reg_ALLOC,reg_NL4
487 /* The BSP wasn't preserved by C, so load it */
488 load(reg_BSP,CSYMBOL(current_binding_stack_pointer))
490 /* Other lisp stack/frame pointers were preserved by C.
491 I can't imagine why they'd have moved */
493 /* Get the return address back. */
494 lwz reg_LIP,4(reg_CFP)
495 lwz reg_CODE,8(reg_CFP)
496 add reg_LIP,reg_CODE,reg_LIP
497 la reg_LIP,-OTHER_POINTER_LOWTAG(reg_LIP)
499 /* No longer atomic */
500 add reg_ALLOC,reg_ALLOC,reg_NL3
504 /* Reset the lisp stack. */
508 /* And back into Lisp. */
511 SET_SIZE(call_into_c)
513 GFUNCDEF(xundefined_tramp)
514 .globl CSYMBOL(undefined_tramp)
515 .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG
517 CSYMBOL(undefined_tramp):
519 .long CSYMBOL(undefined_tramp)
524 twllei reg_ZERO,trap_Cerror
526 .byte UNDEFINED_FUN_ERROR
527 .byte 254, sc_DescriptorReg+0x40, 1 /* 140? sparc says sc_descriptorReg */
529 1: lwz reg_CODE,FDEFN_RAW_ADDR_OFFSET(reg_FDEFN)
530 la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE)
534 SET_SIZE(xundefined_tramp)
536 GFUNCDEF(xclosure_tramp)
537 .globl CSYMBOL(closure_tramp)
538 .byte 0,0,0,SIMPLE_FUN_HEADER_WIDETAG
540 CSYMBOL(closure_tramp):
542 .long CSYMBOL(closure_tramp)
547 lwz reg_LEXENV,FDEFN_FUN_OFFSET(reg_FDEFN)
548 lwz reg_CODE,CLOSURE_FUN_OFFSET(reg_LEXENV)
549 la reg_LIP,SIMPLE_FUN_CODE_OFFSET(reg_CODE)
553 SET_SIZE(xclosure_tramp)
555 GFUNCDEF(fun_end_breakpoint_trap)
557 SET_SIZE(fun_end_breakpoint_trap)
559 GFUNCDEF(fun_end_breakpoint)
561 SET_SIZE(fun_end_breakpoint)
563 GFUNCDEF(fun_end_breakpoint_guts)
565 SET_SIZE(fun_end_breakpoint_guts)
567 GFUNCDEF(fun_end_breakpoint_end)
569 SET_SIZE(fun_end_breakpoint_end)
572 GFUNCDEF(ppc_flush_cache_line)
579 SET_SIZE(ppc_flush_cache_line)